s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_CLOSE test to smb2.compound_async.
[Samba.git] / source3 / rpc_server / rpc_worker.c
blob2d2bb35af0f189d56b2a1a73397ef8e840e3d09e
1 /*
2 * Unix SMB/CIFS implementation.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "source3/include/includes.h"
19 #include "lib/cmdline/cmdline.h"
20 #include "rpc_worker.h"
21 #include "rpc_config.h"
22 #include "librpc/rpc/dcesrv_core.h"
23 #include "librpc/rpc/dcerpc_util.h"
24 #include "source3/librpc/gen_ndr/ndr_rpc_host.h"
25 #include "lib/util/debug.h"
26 #include "lib/util/fault.h"
27 #include "rpc_server.h"
28 #include "rpc_pipes.h"
29 #include "source3/smbd/proto.h"
30 #include "source3/lib/smbd_shim.h"
31 #include "source3/lib/global_contexts.h"
32 #include "source3/lib/util_procid.h"
33 #include "lib/tsocket/tsocket.h"
34 #include "libcli/named_pipe_auth/npa_tstream.h"
35 #include "libcli/smb/smb_constants.h"
36 #include "lib/param/param.h"
37 #include "lib/util/idtree_random.h"
38 #include "lib/util/tevent_unix.h"
39 #include "lib/async_req/async_sock.h"
40 #include "lib/util/dlinklist.h"
41 #include "source3/include/auth.h"
42 #include "nsswitch/winbind_client.h"
43 #include "source3/include/messages.h"
44 #include "libcli/security/security_token.h"
47 * This is the generic code that becomes the
48 * template that all rpcd_* instances that
49 * serve DCERPC can use to provide services to samba-dcerpcd.
51 * The external entry point is:
52 * rpc_worker_main() which takes an argc/argv list
53 * and two functions:
55 * get_interfaces() - List all interfaces that this server provides
56 * get_servers() - Provide the RPC server implementations
58 * Each rpcd_* service needs only to provide
59 * the implementations of get_interfaces() and get_servers()
60 * and call rpc_worker_main() from their main() function
61 * to provide services that can be connected to from samba-dcerpcd.
64 struct rpc_worker {
65 struct dcerpc_ncacn_conn *conns;
66 struct server_id rpc_host_pid;
67 struct messaging_context *msg_ctx;
68 struct dcesrv_context *dce_ctx;
70 struct dcesrv_context_callbacks cb;
72 struct rpc_worker_status status;
74 bool done;
77 static void rpc_worker_print_interface(
78 FILE *f, const struct ndr_interface_table *t)
80 const struct ndr_interface_string_array *endpoints = t->endpoints;
81 uint32_t i;
82 struct ndr_syntax_id_buf id_buf;
84 fprintf(f,
85 "%s %s\n",
86 ndr_syntax_id_buf_string(&t->syntax_id, &id_buf),
87 t->name);
89 for (i=0; i<endpoints->count; i++) {
90 fprintf(f, " %s\n", endpoints->names[i]);
94 static NTSTATUS rpc_worker_report_status(struct rpc_worker *worker)
96 uint8_t buf[6];
97 DATA_BLOB blob = { .data = buf, .length = sizeof(buf), };
98 enum ndr_err_code ndr_err;
99 NTSTATUS status;
101 if (DEBUGLEVEL >= 10) {
102 NDR_PRINT_DEBUG(rpc_worker_status, &worker->status);
105 ndr_err = ndr_push_struct_into_fixed_blob(
106 &blob,
107 &worker->status,
108 (ndr_push_flags_fn_t)ndr_push_rpc_worker_status);
109 SMB_ASSERT(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
111 status = messaging_send(
112 worker->msg_ctx,
113 worker->rpc_host_pid,
114 MSG_RPC_WORKER_STATUS,
115 &blob);
116 return status;
119 static void rpc_worker_connection_terminated(
120 struct dcesrv_connection *conn, void *private_data)
122 struct rpc_worker *worker = talloc_get_type_abort(
123 private_data, struct rpc_worker);
124 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
125 conn->transport.private_data, struct dcerpc_ncacn_conn);
126 struct dcerpc_ncacn_conn *w = NULL;
127 NTSTATUS status;
128 bool found = false;
130 SMB_ASSERT(worker->status.num_clients > 0);
132 for (w = worker->conns; w != NULL; w = w->next) {
133 if (w == ncacn_conn) {
134 found = true;
135 break;
138 SMB_ASSERT(found);
140 DLIST_REMOVE(worker->conns, ncacn_conn);
142 worker->status.num_clients -= 1;
144 status = rpc_worker_report_status(worker);
145 if (!NT_STATUS_IS_OK(status)) {
146 DBG_DEBUG("rpc_worker_report_status returned %s\n",
147 nt_errstr(status));
151 static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
153 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
154 conn->transport.private_data,
155 struct dcerpc_ncacn_conn);
157 if (ncacn_conn->termination_fn != NULL) {
158 ncacn_conn->termination_fn(conn, ncacn_conn->termination_data);
161 return 0;
165 * A new client has been passed to us from samba-dcerpcd.
167 static void rpc_worker_new_client(
168 struct rpc_worker *worker,
169 struct rpc_host_client *client,
170 int sock)
172 struct dcesrv_context *dce_ctx = worker->dce_ctx;
173 struct named_pipe_auth_req_info5 *info5 = client->npa_info5;
174 struct tsocket_address *remote_client_addr = NULL;
175 struct tsocket_address *local_server_addr = NULL;
176 struct dcerpc_binding *b = NULL;
177 enum dcerpc_transport_t transport;
178 struct dcesrv_endpoint *ep = NULL;
179 struct tstream_context *tstream = NULL;
180 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
181 struct dcesrv_connection *dcesrv_conn = NULL;
182 DATA_BLOB buffer = { .data = NULL };
183 struct ncacn_packet *pkt = NULL;
184 NTSTATUS status;
185 int ret;
187 DBG_DEBUG("Got new conn sock %d for binding %s\n",
188 sock,
189 client->binding);
191 status = dcerpc_parse_binding(client, client->binding, &b);
192 if (!NT_STATUS_IS_OK(status)) {
193 DBG_DEBUG("dcerpc_parse_binding(%s) failed: %s\n",
194 client->binding,
195 nt_errstr(status));
196 goto fail;
198 transport = dcerpc_binding_get_transport(b);
200 status = dcesrv_find_endpoint(dce_ctx, b, &ep);
202 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) &&
203 ((transport == NCACN_IP_TCP) || (transport == NCALRPC)) &&
204 (dcerpc_binding_get_string_option(b, "endpoint") != NULL)) {
206 * We have two kinds of servers: Those who explicitly
207 * bind to a port (e.g. 135 for epmapper) and those
208 * who just specify a transport. The client specified
209 * a port (or socket name), but we did not find this
210 * in the list of servers having specified a
211 * port. Retry just matching for the transport,
212 * catching the servers that did not explicitly
213 * specify a port.
215 * This is not fully correct, what we should do is
216 * that once the port the server listens on has been
217 * finalized we should mark this in the server list,
218 * but for now it works. We don't have the same RPC
219 * interface listening twice on different ports.
221 struct dcerpc_binding *b_without_port = dcerpc_binding_dup(
222 client, b);
223 if (b_without_port == NULL) {
224 status = NT_STATUS_NO_MEMORY;
225 goto fail;
228 status = dcerpc_binding_set_string_option(
229 b_without_port, "endpoint", NULL);
230 if (!NT_STATUS_IS_OK(status)) {
231 DBG_DEBUG("Could not delete endpoint: %s\n",
232 nt_errstr(status));
233 TALLOC_FREE(b_without_port);
234 goto fail;
237 status = dcesrv_find_endpoint(dce_ctx, b_without_port, &ep);
239 TALLOC_FREE(b_without_port);
242 if (!NT_STATUS_IS_OK(status)) {
243 DBG_DEBUG("Could not find endpoint for %s: %s\n",
244 client->binding,
245 nt_errstr(status));
246 goto fail;
249 ncacn_conn = talloc(dce_ctx, struct dcerpc_ncacn_conn);
250 if (ncacn_conn == NULL) {
251 DBG_DEBUG("talloc failed\n");
252 goto fail;
254 *ncacn_conn = (struct dcerpc_ncacn_conn) {
255 .endpoint = ep,
256 .sock = sock,
257 .termination_fn = rpc_worker_connection_terminated,
258 .termination_data = worker,
261 if (transport == NCALRPC) {
262 ret = tsocket_address_unix_from_path(
263 ncacn_conn,
264 info5->remote_client_addr,
265 &remote_client_addr);
266 if (ret == -1) {
267 DBG_DEBUG("tsocket_address_unix_from_path"
268 "(%s) failed: %s\n",
269 info5->remote_client_addr,
270 strerror(errno));
271 goto fail;
274 ncacn_conn->remote_client_name = talloc_strdup(
275 ncacn_conn, info5->remote_client_name);
276 if (ncacn_conn->remote_client_name == NULL) {
277 DBG_DEBUG("talloc_strdup(%s) failed\n",
278 info5->remote_client_name);
279 goto fail;
282 ret = tsocket_address_unix_from_path(
283 ncacn_conn,
284 info5->local_server_addr,
285 &local_server_addr);
286 if (ret == -1) {
287 DBG_DEBUG("tsocket_address_unix_from_path"
288 "(%s) failed: %s\n",
289 info5->local_server_addr,
290 strerror(errno));
291 goto fail;
294 ncacn_conn->local_server_name = talloc_strdup(
295 ncacn_conn, info5->local_server_name);
296 if (ncacn_conn->local_server_name == NULL) {
297 DBG_DEBUG("talloc_strdup(%s) failed\n",
298 info5->local_server_name);
299 goto fail;
301 } else {
302 ret = tsocket_address_inet_from_strings(
303 ncacn_conn,
304 "ip",
305 info5->remote_client_addr,
306 info5->remote_client_port,
307 &remote_client_addr);
308 if (ret == -1) {
309 DBG_DEBUG("tsocket_address_inet_from_strings"
310 "(%s, %"PRIu16") failed: %s\n",
311 info5->remote_client_addr,
312 info5->remote_client_port,
313 strerror(errno));
314 goto fail;
316 ncacn_conn->remote_client_name = talloc_strdup(
317 ncacn_conn, info5->remote_client_name);
318 if (ncacn_conn->remote_client_name == NULL) {
319 DBG_DEBUG("talloc_strdup(%s) failed\n",
320 info5->remote_client_name);
321 goto fail;
324 ret = tsocket_address_inet_from_strings(
325 ncacn_conn,
326 "ip",
327 info5->local_server_addr,
328 info5->local_server_port,
329 &local_server_addr);
330 if (ret == -1) {
331 DBG_DEBUG("tsocket_address_inet_from_strings"
332 "(%s, %"PRIu16") failed: %s\n",
333 info5->local_server_addr,
334 info5->local_server_port,
335 strerror(errno));
336 goto fail;
338 ncacn_conn->local_server_name = talloc_strdup(
339 ncacn_conn, info5->local_server_name);
340 if (ncacn_conn->local_server_name == NULL) {
341 DBG_DEBUG("talloc_strdup(%s) failed\n",
342 info5->local_server_name);
343 goto fail;
347 if (transport == NCACN_NP) {
348 ret = tstream_npa_existing_socket(
349 ncacn_conn,
350 sock,
351 FILE_TYPE_MESSAGE_MODE_PIPE,
352 &tstream);
353 if (ret == -1) {
354 DBG_DEBUG("tstream_npa_existing_socket failed: %s\n",
355 strerror(errno));
356 goto fail;
360 * "transport" so far is implicitly assigned by the
361 * socket that the client connected to, passed in from
362 * samba-dcerpcd via the binding. For NCACN_NP (root
363 * only by unix permissions) we got a
364 * named_pipe_auth_req_info5 where the transport can
365 * be overridden.
367 transport = info5->transport;
368 } else {
369 ret = tstream_bsd_existing_socket(
370 ncacn_conn, sock, &tstream);
371 if (ret == -1) {
372 DBG_DEBUG("tstream_bsd_existing_socket failed: %s\n",
373 strerror(errno));
374 goto fail;
377 sock = -1;
379 if (security_token_is_system(
380 info5->session_info->session_info->security_token) &&
381 (transport != NCALRPC)) {
382 DBG_DEBUG("System token only allowed on NCALRPC\n");
383 goto fail;
386 ncacn_conn->p.msg_ctx = global_messaging_context();
387 ncacn_conn->p.transport = transport;
389 status = dcesrv_endpoint_connect(
390 dce_ctx,
391 ncacn_conn,
393 info5->session_info->session_info,
394 global_event_context(),
395 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
396 &dcesrv_conn);
397 if (!NT_STATUS_IS_OK(status)) {
398 DBG_DEBUG("Failed to connect to endpoint: %s\n",
399 nt_errstr(status));
400 goto fail;
403 talloc_set_destructor(dcesrv_conn, dcesrv_connection_destructor);
405 dcesrv_conn->transport.private_data = ncacn_conn;
406 dcesrv_conn->transport.report_output_data =
407 dcesrv_sock_report_output_data;
408 dcesrv_conn->transport.terminate_connection =
409 dcesrv_transport_terminate_connection;
411 dcesrv_conn->send_queue = tevent_queue_create(
412 dcesrv_conn, "dcesrv send queue");
413 if (dcesrv_conn->send_queue == NULL) {
414 DBG_DEBUG("tevent_queue_create failed\n");
415 goto fail;
418 dcesrv_conn->stream = talloc_move(dcesrv_conn, &tstream);
419 dcesrv_conn->local_address =
420 talloc_move(dcesrv_conn, &local_server_addr);
421 dcesrv_conn->remote_address =
422 talloc_move(dcesrv_conn, &remote_client_addr);
424 if (client->bind_packet.length == 0) {
425 DBG_DEBUG("Expected bind packet\n");
426 goto fail;
429 buffer = (DATA_BLOB) {
430 .data = talloc_move(dcesrv_conn, &client->bind_packet.data),
431 .length = client->bind_packet.length,
434 pkt = talloc(dcesrv_conn, struct ncacn_packet);
435 if (pkt == NULL) {
436 DBG_DEBUG("talloc failed\n");
437 goto fail;
440 status = dcerpc_pull_ncacn_packet(pkt, &buffer, pkt);
441 if (!NT_STATUS_IS_OK(status)) {
442 DBG_DEBUG("dcerpc_pull_ncacn_packet failed: %s\n",
443 nt_errstr(status));
444 goto fail;
447 TALLOC_FREE(client);
449 DLIST_ADD(worker->conns, ncacn_conn);
450 worker->status.num_clients += 1;
452 dcesrv_loop_next_packet(dcesrv_conn, pkt, buffer);
454 return;
455 fail:
456 TALLOC_FREE(ncacn_conn);
457 TALLOC_FREE(dcesrv_conn);
458 TALLOC_FREE(client);
459 if (sock != -1) {
460 close(sock);
464 * Parent thinks it successfully sent us a client. Tell it
465 * that we declined.
467 status = rpc_worker_report_status(worker);
468 if (!NT_STATUS_IS_OK(status)) {
469 DBG_DEBUG("rpc_worker_report_status returned %s\n",
470 nt_errstr(status));
475 * New client message processing.
477 static bool rpc_worker_new_client_filter(
478 struct messaging_rec *rec, void *private_data)
480 struct rpc_worker *worker = talloc_get_type_abort(
481 private_data, struct rpc_worker);
482 struct dcesrv_context *dce_ctx = worker->dce_ctx;
483 struct rpc_host_client *client = NULL;
484 enum ndr_err_code ndr_err;
485 int sock;
487 if (rec->msg_type != MSG_RPC_HOST_NEW_CLIENT) {
488 return false;
491 if (rec->num_fds != 1) {
492 DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
493 return false;
496 client = talloc(dce_ctx, struct rpc_host_client);
497 if (client == NULL) {
498 DBG_DEBUG("talloc failed\n");
499 return false;
502 ndr_err = ndr_pull_struct_blob_all(
503 &rec->buf,
504 client,
505 client,
506 (ndr_pull_flags_fn_t)ndr_pull_rpc_host_client);
507 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
508 DBG_DEBUG("ndr_pull_rpc_host_client failed: %s\n",
509 ndr_errstr(ndr_err));
510 TALLOC_FREE(client);
511 return false;
514 if (DEBUGLEVEL >= 10) {
515 NDR_PRINT_DEBUG(rpc_host_client, client);
518 sock = rec->fds[0];
519 rec->fds[0] = -1;
521 rpc_worker_new_client(worker, client, sock);
523 return false;
527 * Return your status message processing.
529 static bool rpc_worker_status_filter(
530 struct messaging_rec *rec, void *private_data)
532 struct rpc_worker *worker = talloc_get_type_abort(
533 private_data, struct rpc_worker);
534 struct dcerpc_ncacn_conn *conn = NULL;
535 FILE *f = NULL;
536 int fd;
538 if (rec->msg_type != MSG_RPC_DUMP_STATUS) {
539 return false;
542 if (rec->num_fds != 1) {
543 DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
544 return false;
547 fd = dup(rec->fds[0]);
548 if (fd == -1) {
549 DBG_DEBUG("dup(%"PRIi64") failed: %s\n",
550 rec->fds[0],
551 strerror(errno));
552 return false;
555 f = fdopen(fd, "w");
556 if (f == NULL) {
557 DBG_DEBUG("fdopen failed: %s\n", strerror(errno));
558 close(fd);
559 return false;
562 for (conn = worker->conns; conn != NULL; conn = conn->next) {
563 char *endpoint = NULL;
565 endpoint = dcerpc_binding_string(
566 conn, conn->endpoint->ep_description);
568 fprintf(f,
569 "endpoint=%s client=%s server=%s\n",
570 endpoint ? endpoint : "UNKNOWN",
571 conn->remote_client_name,
572 conn->local_server_name);
573 TALLOC_FREE(endpoint);
576 fclose(f);
578 return false;
582 take a reference to an existing association group
584 static struct dcesrv_assoc_group *rpc_worker_assoc_group_reference(
585 struct dcesrv_connection *conn,
586 uint32_t id)
588 const struct dcesrv_endpoint *endpoint = conn->endpoint;
589 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
590 endpoint->ep_description);
591 struct dcesrv_assoc_group *assoc_group = NULL;
592 void *id_ptr = NULL;
594 /* find an association group given a assoc_group_id */
595 id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, id & 0xffffff);
596 if (id_ptr == NULL) {
597 DBG_NOTICE("Failed to find assoc_group 0x%08x\n", id);
598 return NULL;
600 assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
602 if (assoc_group->transport != transport) {
603 const char *at = derpc_transport_string_by_transport(
604 assoc_group->transport);
605 const char *ct = derpc_transport_string_by_transport(
606 transport);
608 DBG_NOTICE("assoc_group 0x%08x (transport %s) "
609 "is not available on transport %s",
610 id, at, ct);
611 return NULL;
615 * Yes, this is a talloc_reference: The assoc group must be
616 * removed when all connections go. This should be replaced by
617 * adding a linked list of dcesrv_connection structs to the
618 * assoc group.
620 return talloc_reference(conn, assoc_group);
623 static int rpc_worker_assoc_group_destructor(
624 struct dcesrv_assoc_group *assoc_group)
626 int ret;
628 ret = idr_remove(
629 assoc_group->dce_ctx->assoc_groups_idr,
630 assoc_group->id & 0xffffff);
631 if (ret != 0) {
632 DBG_WARNING("Failed to remove assoc_group 0x%08x\n",
633 assoc_group->id);
635 return 0;
639 allocate a new association group
641 static struct dcesrv_assoc_group *rpc_worker_assoc_group_new(
642 struct dcesrv_connection *conn, uint8_t worker_index)
644 struct dcesrv_context *dce_ctx = conn->dce_ctx;
645 const struct dcesrv_endpoint *endpoint = conn->endpoint;
646 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
647 endpoint->ep_description);
648 struct dcesrv_assoc_group *assoc_group = NULL;
649 int id;
651 assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
652 if (assoc_group == NULL) {
653 return NULL;
656 id = idr_get_new_random(
657 dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
658 if (id == -1) {
659 talloc_free(assoc_group);
660 DBG_WARNING("Out of association groups!\n");
661 return NULL;
663 assoc_group->id = (worker_index << 24) + id;
664 assoc_group->transport = transport;
665 assoc_group->dce_ctx = dce_ctx;
667 talloc_set_destructor(assoc_group, rpc_worker_assoc_group_destructor);
669 return assoc_group;
672 static NTSTATUS rpc_worker_assoc_group_find(
673 struct dcesrv_call_state *call,
674 void *private_data)
676 struct rpc_worker *w = talloc_get_type_abort(
677 private_data, struct rpc_worker);
678 uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
680 if (assoc_group_id != 0) {
681 uint8_t worker_index = (assoc_group_id & 0xff000000) >> 24;
682 if (worker_index != w->status.worker_index) {
683 DBG_DEBUG("Wrong worker id %"PRIu8", "
684 "expected %"PRIu8"\n",
685 worker_index,
686 w->status.worker_index);
687 return NT_STATUS_NOT_FOUND;
689 call->conn->assoc_group = rpc_worker_assoc_group_reference(
690 call->conn, assoc_group_id);
691 } else {
692 call->conn->assoc_group = rpc_worker_assoc_group_new(
693 call->conn, w->status.worker_index);
696 if (call->conn->assoc_group == NULL) {
697 /* TODO Return correct status */
698 return NT_STATUS_UNSUCCESSFUL;
701 return NT_STATUS_OK;
704 static struct rpc_worker *rpc_worker_new(
705 TALLOC_CTX *mem_ctx,
706 struct messaging_context *msg_ctx)
708 struct rpc_worker *worker = NULL;
710 worker = talloc_zero(mem_ctx, struct rpc_worker);
711 if (worker == NULL) {
712 return NULL;
715 worker->rpc_host_pid = (struct server_id) { .pid = 0 };
716 worker->msg_ctx = msg_ctx;
718 worker->cb = (struct dcesrv_context_callbacks) {
719 .log.successful_authz = dcesrv_log_successful_authz,
720 .auth.gensec_prepare = dcesrv_auth_gensec_prepare,
721 .auth.become_root = become_root,
722 .auth.unbecome_root = unbecome_root,
723 .assoc_group.find = rpc_worker_assoc_group_find,
724 .assoc_group.private_data = worker,
727 worker->dce_ctx = global_dcesrv_context();
728 if (worker->dce_ctx == NULL) {
729 goto fail;
731 dcesrv_context_set_callbacks(worker->dce_ctx, &worker->cb);
733 return worker;
734 fail:
735 TALLOC_FREE(worker);
736 return NULL;
739 static struct dcesrv_context *rpc_worker_dce_ctx(struct rpc_worker *w)
741 return w->dce_ctx;
744 struct rpc_worker_state {
745 struct tevent_context *ev;
746 struct rpc_worker *w;
747 struct tevent_req *new_client_req;
748 struct tevent_req *status_req;
749 struct tevent_req *finish_req;
752 static void rpc_worker_done(struct tevent_req *subreq);
753 static void rpc_worker_shutdown(
754 struct messaging_context *msg,
755 void *private_data,
756 uint32_t msg_type,
757 struct server_id server_id,
758 DATA_BLOB *data);
760 static struct tevent_req *rpc_worker_send(
761 TALLOC_CTX *mem_ctx,
762 struct tevent_context *ev,
763 struct rpc_worker *w,
764 pid_t rpc_host_pid,
765 int server_index,
766 int worker_index)
768 struct tevent_req *req = NULL;
769 struct rpc_worker_state *state = NULL;
770 NTSTATUS status;
772 req = tevent_req_create(mem_ctx, &state, struct rpc_worker_state);
773 if (req == NULL) {
774 return NULL;
776 state->ev = ev;
777 state->w = w;
779 if ((server_index < 0) || ((unsigned)server_index > UINT32_MAX)) {
780 DBG_ERR("Invalid server index %d\n", server_index);
781 tevent_req_error(req, EINVAL);
782 return tevent_req_post(req, ev);
784 if ((worker_index < 0) || ((unsigned)worker_index > UINT32_MAX)) {
785 DBG_ERR("Invalid worker index %d\n", worker_index);
786 tevent_req_error(req, EINVAL);
787 return tevent_req_post(req, ev);
789 w->rpc_host_pid = pid_to_procid(rpc_host_pid);
791 w->status = (struct rpc_worker_status) {
792 .server_index = server_index,
793 .worker_index = worker_index,
796 /* Wait for new client messages. */
797 state->new_client_req = messaging_filtered_read_send(
799 messaging_tevent_context(w->msg_ctx),
800 w->msg_ctx,
801 rpc_worker_new_client_filter,
803 if (tevent_req_nomem(state->new_client_req, req)) {
804 return tevent_req_post(req, ev);
807 /* Wait for report your status messages. */
808 state->status_req = messaging_filtered_read_send(
810 messaging_tevent_context(w->msg_ctx),
811 w->msg_ctx,
812 rpc_worker_status_filter,
814 if (tevent_req_nomem(state->status_req, req)) {
815 return tevent_req_post(req, ev);
818 /* Wait for shutdown messages. */
819 status = messaging_register(
820 w->msg_ctx, req, MSG_SHUTDOWN, rpc_worker_shutdown);
821 if (!NT_STATUS_IS_OK(status)) {
822 DBG_DEBUG("messaging_register failed: %s\n",
823 nt_errstr(status));
824 tevent_req_error(req, map_errno_from_nt_status(status));
825 return tevent_req_post(req, ev);
828 state->finish_req = wait_for_read_send(state, ev, 0, false);
829 if (tevent_req_nomem(state->finish_req, req)) {
830 return tevent_req_post(req, ev);
832 tevent_req_set_callback(state->finish_req, rpc_worker_done, req);
834 rpc_worker_report_status(w);
836 return req;
839 static void rpc_worker_done(struct tevent_req *subreq)
841 struct tevent_req *req = tevent_req_callback_data(
842 subreq, struct tevent_req);
843 int err = 0;
844 bool ok;
846 ok = wait_for_read_recv(subreq, &err);
847 TALLOC_FREE(subreq);
848 if (!ok) {
849 tevent_req_error(req, err);
850 return;
852 tevent_req_done(req);
855 static void rpc_worker_shutdown(
856 struct messaging_context *msg,
857 void *private_data,
858 uint32_t msg_type,
859 struct server_id server_id,
860 DATA_BLOB *data)
862 struct tevent_req *req = talloc_get_type_abort(
863 private_data, struct tevent_req);
864 tevent_req_done(req);
867 static int rpc_worker_recv(struct tevent_req *req)
869 return tevent_req_simple_recv_unix(req);
872 static void sig_term_handler(
873 struct tevent_context *ev,
874 struct tevent_signal *se,
875 int signum,
876 int count,
877 void *siginfo,
878 void *private_data)
880 exit(0);
883 static void sig_hup_handler(
884 struct tevent_context *ev,
885 struct tevent_signal *se,
886 int signum,
887 int count,
888 void *siginfo,
889 void *private_data)
891 change_to_root_user();
892 lp_load_with_shares(get_dyn_CONFIGFILE());
895 static NTSTATUS register_ep_server(
896 struct dcesrv_context *dce_ctx,
897 const struct dcesrv_endpoint_server *ep_server)
899 NTSTATUS status;
901 DBG_DEBUG("Registering server %s\n", ep_server->name);
903 status = dcerpc_register_ep_server(ep_server);
904 if (!NT_STATUS_IS_OK(status) &&
905 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
906 DBG_ERR("Failed to register '%s' endpoint server: %s\n",
907 ep_server->name,
908 nt_errstr(status));
909 return status;
912 status = dcesrv_init_ep_server(dce_ctx, ep_server->name);
913 if (!NT_STATUS_IS_OK(status)) {
914 DBG_ERR("dcesrv_init_ep_server(%s) failed: %s\n",
915 ep_server->name,
916 nt_errstr(status));
917 return status;
920 return NT_STATUS_OK;
924 * @brief Main function for RPC server implementations
926 * This function provides all that is necessary to run a RPC server
927 * inside the samba-dcerpcd framework. Just pass argv and argc on to
928 * this function.
930 * The get_interfaces() callback provides the information that is
931 * passed to samba-dcerpcd via --list-interfaces, it should not do any
932 * real RPC server initialization work. Quickly after this function is
933 * called by rpc_worker_main, the process exits again. It should
934 * return the number of interfaces provided.
936 * get_servers() is called when the process is about to do the real
937 * work. So more heavy-weight initialization should happen here. It
938 * should return the number of server implementations provided.
940 * @param[in] argc argc from main()
941 * @param[in] argv argv from main()
942 * @param[in] get_interfaces List all interfaces that this server provides
943 * @param[in] get_servers Provide the RPC server implementations
944 * @param[in] private_data Passed to the callback functions
945 * @return 0 It should never return except on successful process exit
948 int rpc_worker_main(
949 int argc,
950 const char *argv[],
951 const char *daemon_config_name,
952 int num_workers,
953 int idle_seconds,
954 size_t (*get_interfaces)(
955 const struct ndr_interface_table ***ifaces,
956 void *private_data),
957 size_t (*get_servers)(
958 struct dcesrv_context *dce_ctx,
959 const struct dcesrv_endpoint_server ***ep_servers,
960 void *private_data),
961 void *private_data)
963 const struct loadparm_substitution *lp_sub =
964 loadparm_s3_global_substitution();
965 const char *progname = getprogname();
966 TALLOC_CTX *frame = NULL;
967 struct tevent_context *ev_ctx = NULL;
968 struct tevent_req *req = NULL;
969 struct messaging_context *msg_ctx = NULL;
970 struct dcesrv_context *dce_ctx = NULL;
971 struct tevent_signal *se = NULL;
972 poptContext pc;
973 int opt;
974 NTSTATUS status;
975 int ret;
976 int worker_group = -1;
977 int worker_index = -1;
978 bool log_stdout;
979 int list_interfaces = 0;
980 struct rpc_worker *worker = NULL;
981 const struct dcesrv_endpoint_server **ep_servers;
982 size_t i, num_servers;
983 bool ok;
985 struct poptOption long_options[] = {
986 POPT_AUTOHELP
988 .longName = "list-interfaces",
989 .argInfo = POPT_ARG_NONE,
990 .arg = &list_interfaces,
991 .descrip = "List the interfaces provided",
994 .longName = "worker-group",
995 .argInfo = POPT_ARG_INT,
996 .arg = &worker_group,
997 .descrip = "Group index in status message",
1000 .longName = "worker-index",
1001 .argInfo = POPT_ARG_INT,
1002 .arg = &worker_index,
1003 .descrip = "Worker index in status message",
1005 POPT_COMMON_SAMBA
1006 POPT_TABLEEND
1008 static const struct smbd_shim smbd_shim_fns = {
1009 .become_authenticated_pipe_user =
1010 smbd_become_authenticated_pipe_user,
1011 .unbecome_authenticated_pipe_user =
1012 smbd_unbecome_authenticated_pipe_user,
1013 .become_root = smbd_become_root,
1014 .unbecome_root = smbd_unbecome_root,
1017 closefrom(3);
1018 talloc_enable_null_tracking();
1019 frame = talloc_stackframe();
1020 umask(0);
1021 smb_init_locale();
1023 ok = samba_cmdline_init(frame,
1024 SAMBA_CMDLINE_CONFIG_SERVER,
1025 true /* require_smbconf */);
1026 if (!ok) {
1027 DBG_ERR("Failed to init cmdline parser!\n");
1028 TALLOC_FREE(frame);
1029 exit(ENOMEM);
1032 pc = samba_popt_get_context(progname, argc, argv, long_options, 0);
1033 if (pc == NULL) {
1034 DBG_ERR("Failed to setup popt context!\n");
1035 TALLOC_FREE(frame);
1036 exit(1);
1039 while ((opt = poptGetNextOpt(pc)) != -1) {
1040 d_fprintf(stderr,
1041 "\nInvalid option %s: %s\n\n",
1042 poptBadOption(pc, 0),
1043 poptStrerror(opt));
1044 poptPrintUsage(pc, stderr, 0);
1045 TALLOC_FREE(frame);
1046 exit(1);
1048 poptFreeContext(pc);
1050 if (list_interfaces != 0) {
1051 const struct ndr_interface_table **ifaces = NULL;
1052 size_t num_ifaces;
1054 num_workers = lp_parm_int(
1055 -1, daemon_config_name, "num_workers", num_workers);
1056 idle_seconds = lp_parm_int(
1057 -1, daemon_config_name, "idle_seconds", idle_seconds);
1059 DBG_DEBUG("daemon=%s, num_workers=%d, idle_seconds=%d\n",
1060 daemon_config_name,
1061 num_workers,
1062 idle_seconds);
1064 fprintf(stdout, "%d\n%d\n", num_workers, idle_seconds);
1066 num_ifaces = get_interfaces(&ifaces, private_data);
1068 for (i=0; i<num_ifaces; i++) {
1069 rpc_worker_print_interface(stdout, ifaces[i]);
1072 TALLOC_FREE(frame);
1073 exit(0);
1076 log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
1077 if (log_stdout != 0) {
1078 setup_logging(argv[0], DEBUG_STDOUT);
1079 } else {
1080 setup_logging(argv[0], DEBUG_FILE);
1083 set_smbd_shim(&smbd_shim_fns);
1085 dump_core_setup(progname, lp_logfile(talloc_tos(), lp_sub));
1087 /* POSIX demands that signals are inherited. If the invoking
1088 * process has these signals masked, we will have problems, as
1089 * we won't receive them. */
1090 BlockSignals(False, SIGHUP);
1091 BlockSignals(False, SIGUSR1);
1092 BlockSignals(False, SIGTERM);
1094 #if defined(SIGFPE)
1095 /* we are never interested in SIGFPE */
1096 BlockSignals(True,SIGFPE);
1097 #endif
1098 /* We no longer use USR2... */
1099 #if defined(SIGUSR2)
1100 BlockSignals(True, SIGUSR2);
1101 #endif
1102 /* Ignore children - no zombies. */
1103 CatchChild();
1105 DEBUG(0, ("%s version %s started.\n",
1106 progname,
1107 samba_version_string()));
1108 DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
1110 msg_ctx = global_messaging_context();
1111 if (msg_ctx == NULL) {
1112 DBG_ERR("global_messaging_context() failed\n");
1113 TALLOC_FREE(frame);
1114 exit(1);
1116 ev_ctx = messaging_tevent_context(msg_ctx);
1118 worker = rpc_worker_new(ev_ctx, msg_ctx);
1119 if (worker == NULL) {
1120 DBG_ERR("rpc_worker_new failed\n");
1121 global_messaging_context_free();
1122 TALLOC_FREE(frame);
1123 exit(1);
1125 dce_ctx = rpc_worker_dce_ctx(worker);
1127 se = tevent_add_signal(
1128 ev_ctx, ev_ctx, SIGTERM, 0, sig_term_handler, NULL);
1129 if (se == NULL) {
1130 DBG_ERR("tevent_add_signal failed\n");
1131 global_messaging_context_free();
1132 TALLOC_FREE(frame);
1133 exit(1);
1135 BlockSignals(false, SIGTERM);
1137 se = tevent_add_signal(
1138 ev_ctx, ev_ctx, SIGHUP, 0, sig_hup_handler, NULL);
1139 if (se == NULL) {
1140 DBG_ERR("tevent_add_signal failed\n");
1141 global_messaging_context_free();
1142 TALLOC_FREE(frame);
1143 exit(1);
1145 BlockSignals(false, SIGHUP);
1147 (void)winbind_off();
1148 ok = init_guest_session_info(NULL);
1149 (void)winbind_on();
1150 if (!ok) {
1151 DBG_WARNING("init_guest_session_info failed\n");
1152 global_messaging_context_free();
1153 TALLOC_FREE(frame);
1154 exit(1);
1157 status = init_system_session_info(NULL);
1158 if (!NT_STATUS_IS_OK(status)) {
1159 DBG_WARNING("init_system_session_info failed: %s\n",
1160 nt_errstr(status));
1161 global_messaging_context_free();
1162 TALLOC_FREE(frame);
1163 exit(1);
1166 DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
1168 num_servers = get_servers(dce_ctx, &ep_servers, private_data);
1170 DBG_DEBUG("get_servers() returned %zu servers\n", num_servers);
1172 for (i=0; i<num_servers; i++) {
1173 status = register_ep_server(dce_ctx, ep_servers[i]);
1174 if (!NT_STATUS_IS_OK(status)) {
1175 DBG_DEBUG("register_ep_server failed: %s\n",
1176 nt_errstr(status));
1177 global_messaging_context_free();
1178 TALLOC_FREE(frame);
1179 exit(1);
1183 req = rpc_worker_send(
1184 ev_ctx, ev_ctx, worker, getppid(), worker_group, worker_index);
1185 if (req == NULL) {
1186 DBG_ERR("rpc_worker_send failed\n");
1187 global_messaging_context_free();
1188 TALLOC_FREE(frame);
1189 exit(1);
1192 DBG_DEBUG("%s worker running\n", progname);
1194 while (tevent_req_is_in_progress(req)) {
1195 TALLOC_CTX *loop_frame = NULL;
1197 loop_frame = talloc_stackframe();
1199 ret = tevent_loop_once(ev_ctx);
1201 TALLOC_FREE(loop_frame);
1203 if (ret != 0) {
1204 DBG_WARNING("tevent_req_once() failed: %s\n",
1205 strerror(errno));
1206 global_messaging_context_free();
1207 TALLOC_FREE(frame);
1208 exit(1);
1212 status = dcesrv_shutdown_registered_ep_servers(dce_ctx);
1213 if (!NT_STATUS_IS_OK(status)) {
1214 DBG_DEBUG("Shutdown failed with: %s\n",
1215 nt_errstr(status));
1218 ret = rpc_worker_recv(req);
1219 if (ret != 0) {
1220 DBG_DEBUG("rpc_worker_recv returned %s\n", strerror(ret));
1221 global_messaging_context_free();
1222 TALLOC_FREE(frame);
1223 exit(1);
1226 TALLOC_FREE(frame);
1227 return 0;