s3:rpc_server: call reopen_logs before we print the copyright notice
[Samba.git] / source3 / rpc_server / rpc_worker.c
blob2ef90547dd6661cbac53bce83b6ef70d11ad9b5c
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"
45 #include "libcli/security/dom_sid.h"
46 #include "source3/include/proto.h"
49 * This is the generic code that becomes the
50 * template that all rpcd_* instances that
51 * serve DCERPC can use to provide services to samba-dcerpcd.
53 * The external entry point is:
54 * rpc_worker_main() which takes an argc/argv list
55 * and two functions:
57 * get_interfaces() - List all interfaces that this server provides
58 * get_servers() - Provide the RPC server implementations
60 * Each rpcd_* service needs only to provide
61 * the implementations of get_interfaces() and get_servers()
62 * and call rpc_worker_main() from their main() function
63 * to provide services that can be connected to from samba-dcerpcd.
66 struct rpc_worker {
67 struct dcerpc_ncacn_conn *conns;
68 struct server_id rpc_host_pid;
69 struct messaging_context *msg_ctx;
70 struct dcesrv_context *dce_ctx;
72 struct dcesrv_context_callbacks cb;
74 struct rpc_worker_status status;
76 bool done;
79 static void rpc_worker_print_interface(
80 FILE *f, const struct ndr_interface_table *t)
82 const struct ndr_interface_string_array *endpoints = t->endpoints;
83 uint32_t i;
84 struct ndr_syntax_id_buf id_buf;
86 fprintf(f,
87 "%s %s\n",
88 ndr_syntax_id_buf_string(&t->syntax_id, &id_buf),
89 t->name);
91 for (i=0; i<endpoints->count; i++) {
92 fprintf(f, " %s\n", endpoints->names[i]);
96 static NTSTATUS rpc_worker_report_status(struct rpc_worker *worker)
98 uint8_t buf[9];
99 DATA_BLOB blob = { .data = buf, .length = sizeof(buf), };
100 enum ndr_err_code ndr_err;
101 NTSTATUS status;
103 if (DEBUGLEVEL >= 10) {
104 NDR_PRINT_DEBUG(rpc_worker_status, &worker->status);
107 ndr_err = ndr_push_struct_into_fixed_blob(
108 &blob,
109 &worker->status,
110 (ndr_push_flags_fn_t)ndr_push_rpc_worker_status);
111 SMB_ASSERT(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
113 status = messaging_send(
114 worker->msg_ctx,
115 worker->rpc_host_pid,
116 MSG_RPC_WORKER_STATUS,
117 &blob);
118 return status;
121 static void rpc_worker_connection_terminated(
122 struct dcesrv_connection *conn, void *private_data)
124 struct rpc_worker *worker = talloc_get_type_abort(
125 private_data, struct rpc_worker);
126 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
127 conn->transport.private_data, struct dcerpc_ncacn_conn);
128 struct dcerpc_ncacn_conn *w = NULL;
129 NTSTATUS status;
130 bool found = false;
132 SMB_ASSERT(worker->status.num_clients > 0);
134 for (w = worker->conns; w != NULL; w = w->next) {
135 if (w == ncacn_conn) {
136 found = true;
137 break;
140 SMB_ASSERT(found);
142 DLIST_REMOVE(worker->conns, ncacn_conn);
144 worker->status.num_clients -= 1;
146 status = rpc_worker_report_status(worker);
147 if (!NT_STATUS_IS_OK(status)) {
148 DBG_DEBUG("rpc_worker_report_status returned %s\n",
149 nt_errstr(status));
153 static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
155 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
156 conn->transport.private_data,
157 struct dcerpc_ncacn_conn);
159 if (ncacn_conn->termination_fn != NULL) {
160 ncacn_conn->termination_fn(conn, ncacn_conn->termination_data);
163 return 0;
167 * A new client has been passed to us from samba-dcerpcd.
169 static void rpc_worker_new_client(
170 struct rpc_worker *worker,
171 struct rpc_host_client *client,
172 int sock)
174 struct dcesrv_context *dce_ctx = worker->dce_ctx;
175 struct named_pipe_auth_req_info7 *info7 = client->npa_info7;
176 struct tsocket_address *remote_client_addr = NULL;
177 struct tsocket_address *local_server_addr = NULL;
178 struct dcerpc_binding *b = NULL;
179 enum dcerpc_transport_t transport;
180 struct dcesrv_endpoint *ep = NULL;
181 struct tstream_context *tstream = NULL;
182 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
183 struct dcesrv_connection *dcesrv_conn = NULL;
184 DATA_BLOB buffer = { .data = NULL };
185 struct ncacn_packet *pkt = NULL;
186 struct security_token *token = NULL;
187 uint32_t npa_flags, state_flags;
188 bool found_npa_flags;
189 NTSTATUS status;
190 int ret;
192 DBG_DEBUG("Got new conn sock %d for binding %s\n",
193 sock,
194 client->binding);
196 status = dcerpc_parse_binding(client, client->binding, &b);
197 if (!NT_STATUS_IS_OK(status)) {
198 DBG_DEBUG("dcerpc_parse_binding(%s) failed: %s\n",
199 client->binding,
200 nt_errstr(status));
201 goto fail;
203 transport = dcerpc_binding_get_transport(b);
205 status = dcesrv_find_endpoint(dce_ctx, b, &ep);
207 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) &&
208 ((transport == NCACN_IP_TCP) || (transport == NCALRPC)) &&
209 (dcerpc_binding_get_string_option(b, "endpoint") != NULL)) {
211 * We have two kinds of servers: Those who explicitly
212 * bind to a port (e.g. 135 for epmapper) and those
213 * who just specify a transport. The client specified
214 * a port (or socket name), but we did not find this
215 * in the list of servers having specified a
216 * port. Retry just matching for the transport,
217 * catching the servers that did not explicitly
218 * specify a port.
220 * This is not fully correct, what we should do is
221 * that once the port the server listens on has been
222 * finalized we should mark this in the server list,
223 * but for now it works. We don't have the same RPC
224 * interface listening twice on different ports.
226 struct dcerpc_binding *b_without_port = dcerpc_binding_dup(
227 client, b);
228 if (b_without_port == NULL) {
229 status = NT_STATUS_NO_MEMORY;
230 goto fail;
233 status = dcerpc_binding_set_string_option(
234 b_without_port, "endpoint", NULL);
235 if (!NT_STATUS_IS_OK(status)) {
236 DBG_DEBUG("Could not delete endpoint: %s\n",
237 nt_errstr(status));
238 TALLOC_FREE(b_without_port);
239 goto fail;
242 status = dcesrv_find_endpoint(dce_ctx, b_without_port, &ep);
244 TALLOC_FREE(b_without_port);
247 if (!NT_STATUS_IS_OK(status)) {
248 DBG_DEBUG("Could not find endpoint for %s: %s\n",
249 client->binding,
250 nt_errstr(status));
251 goto fail;
254 ncacn_conn = talloc(dce_ctx, struct dcerpc_ncacn_conn);
255 if (ncacn_conn == NULL) {
256 DBG_DEBUG("talloc failed\n");
257 goto fail;
259 *ncacn_conn = (struct dcerpc_ncacn_conn) {
260 .endpoint = ep,
261 .sock = sock,
262 .termination_fn = rpc_worker_connection_terminated,
263 .termination_data = worker,
266 if (transport == NCALRPC) {
267 ret = tsocket_address_unix_from_path(ncacn_conn,
268 info7->remote_client_addr,
269 &remote_client_addr);
270 if (ret == -1) {
271 DBG_DEBUG("tsocket_address_unix_from_path"
272 "(%s) failed: %s\n",
273 info7->remote_client_addr,
274 strerror(errno));
275 goto fail;
278 ncacn_conn->remote_client_name =
279 talloc_strdup(ncacn_conn, info7->remote_client_name);
280 if (ncacn_conn->remote_client_name == NULL) {
281 DBG_DEBUG("talloc_strdup(%s) failed\n",
282 info7->remote_client_name);
283 goto fail;
286 ret = tsocket_address_unix_from_path(ncacn_conn,
287 info7->local_server_addr,
288 &local_server_addr);
289 if (ret == -1) {
290 DBG_DEBUG("tsocket_address_unix_from_path"
291 "(%s) failed: %s\n",
292 info7->local_server_addr,
293 strerror(errno));
294 goto fail;
297 ncacn_conn->local_server_name =
298 talloc_strdup(ncacn_conn, info7->local_server_name);
299 if (ncacn_conn->local_server_name == NULL) {
300 DBG_DEBUG("talloc_strdup(%s) failed\n",
301 info7->local_server_name);
302 goto fail;
304 } else {
305 ret = tsocket_address_inet_from_strings(
306 ncacn_conn,
307 "ip",
308 info7->remote_client_addr,
309 info7->remote_client_port,
310 &remote_client_addr);
311 if (ret == -1) {
312 DBG_DEBUG("tsocket_address_inet_from_strings"
313 "(%s, %" PRIu16 ") failed: %s\n",
314 info7->remote_client_addr,
315 info7->remote_client_port,
316 strerror(errno));
317 goto fail;
319 ncacn_conn->remote_client_name =
320 talloc_strdup(ncacn_conn, info7->remote_client_name);
321 if (ncacn_conn->remote_client_name == NULL) {
322 DBG_DEBUG("talloc_strdup(%s) failed\n",
323 info7->remote_client_name);
324 goto fail;
327 ret = tsocket_address_inet_from_strings(
328 ncacn_conn,
329 "ip",
330 info7->local_server_addr,
331 info7->local_server_port,
332 &local_server_addr);
333 if (ret == -1) {
334 DBG_DEBUG("tsocket_address_inet_from_strings"
335 "(%s, %" PRIu16 ") failed: %s\n",
336 info7->local_server_addr,
337 info7->local_server_port,
338 strerror(errno));
339 goto fail;
341 ncacn_conn->local_server_name =
342 talloc_strdup(ncacn_conn, info7->local_server_name);
343 if (ncacn_conn->local_server_name == NULL) {
344 DBG_DEBUG("talloc_strdup(%s) failed\n",
345 info7->local_server_name);
346 goto fail;
350 if (transport == NCACN_NP) {
351 ret = tstream_npa_existing_socket(
352 ncacn_conn,
353 sock,
354 FILE_TYPE_MESSAGE_MODE_PIPE,
355 &tstream);
356 if (ret == -1) {
357 DBG_DEBUG("tstream_npa_existing_socket failed: %s\n",
358 strerror(errno));
359 goto fail;
363 * "transport" so far is implicitly assigned by the
364 * socket that the client connected to, passed in from
365 * samba-dcerpcd via the binding. For NCACN_NP (root
366 * only by unix permissions) we got a
367 * named_pipe_auth_req_info7 where the transport can
368 * be overridden.
370 transport = info7->transport;
371 } else {
372 ret = tstream_bsd_existing_socket(
373 ncacn_conn, sock, &tstream);
374 if (ret == -1) {
375 DBG_DEBUG("tstream_bsd_existing_socket failed: %s\n",
376 strerror(errno));
377 goto fail;
380 sock = -1;
382 token = info7->session_info->session_info->security_token;
384 if (security_token_is_system(token) && (transport != NCALRPC)) {
385 DBG_DEBUG("System token only allowed on NCALRPC\n");
386 goto fail;
389 state_flags = DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
391 found_npa_flags = security_token_find_npa_flags(token, &npa_flags);
392 if (found_npa_flags) {
393 if (npa_flags & SAMBA_NPA_FLAGS_WINBIND_OFF) {
394 state_flags |=
395 DCESRV_CALL_STATE_FLAG_WINBIND_OFF;
399 * Delete the flags so that we don't bail in
400 * local_np_connect_send() on subsequent
401 * connects. Once we connect to another RPC service, a
402 * new flags sid will be added if required.
404 security_token_del_npa_flags(token);
407 ncacn_conn->p.msg_ctx = global_messaging_context();
408 ncacn_conn->p.transport = transport;
410 status = dcesrv_endpoint_connect(dce_ctx,
411 ncacn_conn,
413 info7->session_info->session_info,
414 global_event_context(),
415 state_flags,
416 &dcesrv_conn);
417 if (!NT_STATUS_IS_OK(status)) {
418 DBG_DEBUG("Failed to connect to endpoint: %s\n",
419 nt_errstr(status));
420 goto fail;
423 talloc_set_destructor(dcesrv_conn, dcesrv_connection_destructor);
425 dcesrv_conn->transport.private_data = ncacn_conn;
426 dcesrv_conn->transport.report_output_data =
427 dcesrv_sock_report_output_data;
428 dcesrv_conn->transport.terminate_connection =
429 dcesrv_transport_terminate_connection;
431 dcesrv_conn->send_queue = tevent_queue_create(
432 dcesrv_conn, "dcesrv send queue");
433 if (dcesrv_conn->send_queue == NULL) {
434 DBG_DEBUG("tevent_queue_create failed\n");
435 goto fail;
438 dcesrv_conn->stream = talloc_move(dcesrv_conn, &tstream);
439 dcesrv_conn->local_address =
440 talloc_move(dcesrv_conn, &local_server_addr);
441 dcesrv_conn->remote_address =
442 talloc_move(dcesrv_conn, &remote_client_addr);
444 if (client->bind_packet.length == 0) {
445 DBG_DEBUG("Expected bind packet\n");
446 goto fail;
449 buffer = (DATA_BLOB) {
450 .data = talloc_move(dcesrv_conn, &client->bind_packet.data),
451 .length = client->bind_packet.length,
454 pkt = talloc(dcesrv_conn, struct ncacn_packet);
455 if (pkt == NULL) {
456 DBG_DEBUG("talloc failed\n");
457 goto fail;
460 status = dcerpc_pull_ncacn_packet(pkt, &buffer, pkt);
461 if (!NT_STATUS_IS_OK(status)) {
462 DBG_DEBUG("dcerpc_pull_ncacn_packet failed: %s\n",
463 nt_errstr(status));
464 goto fail;
467 TALLOC_FREE(client);
469 DLIST_ADD(worker->conns, ncacn_conn);
470 worker->status.num_clients += 1;
472 dcesrv_loop_next_packet(dcesrv_conn, pkt, buffer);
474 return;
475 fail:
476 TALLOC_FREE(ncacn_conn);
477 TALLOC_FREE(dcesrv_conn);
478 TALLOC_FREE(client);
479 if (sock != -1) {
480 close(sock);
484 * Parent thinks it successfully sent us a client. Tell it
485 * that we declined.
487 status = rpc_worker_report_status(worker);
488 if (!NT_STATUS_IS_OK(status)) {
489 DBG_DEBUG("rpc_worker_report_status returned %s\n",
490 nt_errstr(status));
495 * New client message processing.
497 static bool rpc_worker_new_client_filter(
498 struct messaging_rec *rec, void *private_data)
500 struct rpc_worker *worker = talloc_get_type_abort(
501 private_data, struct rpc_worker);
502 struct dcesrv_context *dce_ctx = worker->dce_ctx;
503 struct rpc_host_client *client = NULL;
504 enum ndr_err_code ndr_err;
505 int sock;
507 if (rec->msg_type != MSG_RPC_HOST_NEW_CLIENT) {
508 return false;
511 if (rec->num_fds != 1) {
512 DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
513 return false;
516 client = talloc(dce_ctx, struct rpc_host_client);
517 if (client == NULL) {
518 DBG_DEBUG("talloc failed\n");
519 return false;
522 ndr_err = ndr_pull_struct_blob_all(
523 &rec->buf,
524 client,
525 client,
526 (ndr_pull_flags_fn_t)ndr_pull_rpc_host_client);
527 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
528 DBG_DEBUG("ndr_pull_rpc_host_client failed: %s\n",
529 ndr_errstr(ndr_err));
530 TALLOC_FREE(client);
531 return false;
534 if (DEBUGLEVEL >= 10) {
535 NDR_PRINT_DEBUG(rpc_host_client, client);
538 sock = rec->fds[0];
539 rec->fds[0] = -1;
541 rpc_worker_new_client(worker, client, sock);
543 return false;
547 * Return your status message processing.
549 static bool rpc_worker_status_filter(
550 struct messaging_rec *rec, void *private_data)
552 struct rpc_worker *worker = talloc_get_type_abort(
553 private_data, struct rpc_worker);
554 struct dcerpc_ncacn_conn *conn = NULL;
555 FILE *f = NULL;
556 int fd;
558 if (rec->msg_type != MSG_RPC_DUMP_STATUS) {
559 return false;
562 if (rec->num_fds != 1) {
563 DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
564 return false;
567 fd = dup(rec->fds[0]);
568 if (fd == -1) {
569 DBG_DEBUG("dup(%"PRIi64") failed: %s\n",
570 rec->fds[0],
571 strerror(errno));
572 return false;
575 f = fdopen(fd, "w");
576 if (f == NULL) {
577 DBG_DEBUG("fdopen failed: %s\n", strerror(errno));
578 close(fd);
579 return false;
582 for (conn = worker->conns; conn != NULL; conn = conn->next) {
583 char *endpoint = NULL;
585 endpoint = dcerpc_binding_string(
586 conn, conn->endpoint->ep_description);
588 fprintf(f,
589 "endpoint=%s client=%s server=%s\n",
590 endpoint ? endpoint : "UNKNOWN",
591 conn->remote_client_name,
592 conn->local_server_name);
593 TALLOC_FREE(endpoint);
596 fclose(f);
598 return false;
602 take a reference to an existing association group
604 static struct dcesrv_assoc_group *rpc_worker_assoc_group_reference(
605 struct dcesrv_connection *conn,
606 uint32_t id)
608 const struct dcesrv_endpoint *endpoint = conn->endpoint;
609 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
610 endpoint->ep_description);
611 struct dcesrv_assoc_group *assoc_group = NULL;
612 void *id_ptr = NULL;
614 /* find an association group given a assoc_group_id */
615 id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, id & 0xffffff);
616 if (id_ptr == NULL) {
617 DBG_NOTICE("Failed to find assoc_group 0x%08x\n", id);
618 return NULL;
620 assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
622 if (assoc_group->transport != transport) {
623 const char *at = derpc_transport_string_by_transport(
624 assoc_group->transport);
625 const char *ct = derpc_transport_string_by_transport(
626 transport);
628 DBG_NOTICE("assoc_group 0x%08x (transport %s) "
629 "is not available on transport %s",
630 id, at, ct);
631 return NULL;
635 * Yes, this is a talloc_reference: The assoc group must be
636 * removed when all connections go. This should be replaced by
637 * adding a linked list of dcesrv_connection structs to the
638 * assoc group.
640 return talloc_reference(conn, assoc_group);
643 static int rpc_worker_assoc_group_destructor(
644 struct dcesrv_assoc_group *assoc_group)
646 int ret;
648 ret = idr_remove(
649 assoc_group->dce_ctx->assoc_groups_idr,
650 assoc_group->id & 0xffffff);
651 if (ret != 0) {
652 DBG_WARNING("Failed to remove assoc_group 0x%08x\n",
653 assoc_group->id);
655 return 0;
659 allocate a new association group
661 static struct dcesrv_assoc_group *rpc_worker_assoc_group_new(
662 struct dcesrv_connection *conn, uint8_t worker_index)
664 struct dcesrv_context *dce_ctx = conn->dce_ctx;
665 const struct dcesrv_endpoint *endpoint = conn->endpoint;
666 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
667 endpoint->ep_description);
668 struct dcesrv_assoc_group *assoc_group = NULL;
669 int id;
671 assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
672 if (assoc_group == NULL) {
673 return NULL;
676 id = idr_get_new_random(
677 dce_ctx->assoc_groups_idr, assoc_group, 1, UINT16_MAX);
678 if (id == -1) {
679 talloc_free(assoc_group);
680 DBG_WARNING("Out of association groups!\n");
681 return NULL;
683 assoc_group->id = (worker_index << 24) + id;
684 assoc_group->transport = transport;
685 assoc_group->dce_ctx = dce_ctx;
687 talloc_set_destructor(assoc_group, rpc_worker_assoc_group_destructor);
689 return assoc_group;
692 static NTSTATUS rpc_worker_assoc_group_find(
693 struct dcesrv_call_state *call,
694 void *private_data)
696 struct rpc_worker *w = talloc_get_type_abort(
697 private_data, struct rpc_worker);
698 uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
700 if (assoc_group_id != 0) {
701 uint8_t worker_index = (assoc_group_id & 0xff000000) >> 24;
702 if (worker_index != w->status.worker_index) {
703 DBG_DEBUG("Wrong worker id %"PRIu8", "
704 "expected %"PRIu8"\n",
705 worker_index,
706 w->status.worker_index);
707 return NT_STATUS_NOT_FOUND;
709 call->conn->assoc_group = rpc_worker_assoc_group_reference(
710 call->conn, assoc_group_id);
711 } else {
712 call->conn->assoc_group = rpc_worker_assoc_group_new(
713 call->conn, w->status.worker_index);
716 if (call->conn->assoc_group == NULL) {
717 /* TODO Return correct status */
718 return NT_STATUS_UNSUCCESSFUL;
721 return NT_STATUS_OK;
724 static struct rpc_worker *rpc_worker_new(
725 TALLOC_CTX *mem_ctx,
726 struct messaging_context *msg_ctx)
728 struct rpc_worker *worker = NULL;
730 worker = talloc_zero(mem_ctx, struct rpc_worker);
731 if (worker == NULL) {
732 return NULL;
735 worker->rpc_host_pid = (struct server_id) { .pid = 0 };
736 worker->msg_ctx = msg_ctx;
738 worker->cb = (struct dcesrv_context_callbacks) {
739 .log.successful_authz = dcesrv_log_successful_authz,
740 .auth.gensec_prepare = dcesrv_auth_gensec_prepare,
741 .auth.become_root = become_root,
742 .auth.unbecome_root = unbecome_root,
743 .assoc_group.find = rpc_worker_assoc_group_find,
744 .assoc_group.private_data = worker,
747 worker->dce_ctx = global_dcesrv_context();
748 if (worker->dce_ctx == NULL) {
749 goto fail;
751 dcesrv_context_set_callbacks(worker->dce_ctx, &worker->cb);
753 return worker;
754 fail:
755 TALLOC_FREE(worker);
756 return NULL;
759 static struct dcesrv_context *rpc_worker_dce_ctx(struct rpc_worker *w)
761 return w->dce_ctx;
764 struct rpc_worker_state {
765 struct tevent_context *ev;
766 struct rpc_worker *w;
767 struct tevent_req *new_client_req;
768 struct tevent_req *status_req;
769 struct tevent_req *finish_req;
772 static void rpc_worker_done(struct tevent_req *subreq);
773 static void rpc_worker_shutdown(
774 struct messaging_context *msg,
775 void *private_data,
776 uint32_t msg_type,
777 struct server_id server_id,
778 DATA_BLOB *data);
780 static struct tevent_req *rpc_worker_send(
781 TALLOC_CTX *mem_ctx,
782 struct tevent_context *ev,
783 struct rpc_worker *w,
784 pid_t rpc_host_pid,
785 int server_index,
786 int worker_index)
788 struct tevent_req *req = NULL;
789 struct rpc_worker_state *state = NULL;
790 NTSTATUS status;
792 req = tevent_req_create(mem_ctx, &state, struct rpc_worker_state);
793 if (req == NULL) {
794 return NULL;
796 state->ev = ev;
797 state->w = w;
799 if ((server_index < 0) || ((unsigned)server_index > UINT32_MAX)) {
800 DBG_ERR("Invalid server index %d\n", server_index);
801 tevent_req_error(req, EINVAL);
802 return tevent_req_post(req, ev);
804 if ((worker_index < 0) || ((unsigned)worker_index > UINT32_MAX)) {
805 DBG_ERR("Invalid worker index %d\n", worker_index);
806 tevent_req_error(req, EINVAL);
807 return tevent_req_post(req, ev);
809 w->rpc_host_pid = pid_to_procid(rpc_host_pid);
811 w->status = (struct rpc_worker_status) {
812 .server_index = server_index,
813 .worker_index = worker_index,
816 /* Wait for new client messages. */
817 state->new_client_req = messaging_filtered_read_send(
819 messaging_tevent_context(w->msg_ctx),
820 w->msg_ctx,
821 rpc_worker_new_client_filter,
823 if (tevent_req_nomem(state->new_client_req, req)) {
824 return tevent_req_post(req, ev);
827 /* Wait for report your status messages. */
828 state->status_req = messaging_filtered_read_send(
830 messaging_tevent_context(w->msg_ctx),
831 w->msg_ctx,
832 rpc_worker_status_filter,
834 if (tevent_req_nomem(state->status_req, req)) {
835 return tevent_req_post(req, ev);
838 /* Wait for shutdown messages. */
839 status = messaging_register(
840 w->msg_ctx, req, MSG_SHUTDOWN, rpc_worker_shutdown);
841 if (!NT_STATUS_IS_OK(status)) {
842 DBG_DEBUG("messaging_register failed: %s\n",
843 nt_errstr(status));
844 tevent_req_error(req, map_errno_from_nt_status(status));
845 return tevent_req_post(req, ev);
848 state->finish_req = wait_for_read_send(state, ev, 0, false);
849 if (tevent_req_nomem(state->finish_req, req)) {
850 return tevent_req_post(req, ev);
852 tevent_req_set_callback(state->finish_req, rpc_worker_done, req);
854 rpc_worker_report_status(w);
856 return req;
859 static void rpc_worker_done(struct tevent_req *subreq)
861 struct tevent_req *req = tevent_req_callback_data(
862 subreq, struct tevent_req);
863 int err = 0;
864 bool ok;
866 ok = wait_for_read_recv(subreq, &err);
867 TALLOC_FREE(subreq);
868 if (!ok) {
869 tevent_req_error(req, err);
870 return;
872 tevent_req_done(req);
875 static void rpc_worker_shutdown(
876 struct messaging_context *msg,
877 void *private_data,
878 uint32_t msg_type,
879 struct server_id server_id,
880 DATA_BLOB *data)
882 struct tevent_req *req = talloc_get_type_abort(
883 private_data, struct tevent_req);
884 tevent_req_done(req);
887 static int rpc_worker_recv(struct tevent_req *req)
889 return tevent_req_simple_recv_unix(req);
892 static void sig_term_handler(
893 struct tevent_context *ev,
894 struct tevent_signal *se,
895 int signum,
896 int count,
897 void *siginfo,
898 void *private_data)
900 exit(0);
903 static void sig_hup_handler(
904 struct tevent_context *ev,
905 struct tevent_signal *se,
906 int signum,
907 int count,
908 void *siginfo,
909 void *private_data)
911 change_to_root_user();
912 lp_load_with_shares(get_dyn_CONFIGFILE());
915 static NTSTATUS register_ep_server(
916 struct dcesrv_context *dce_ctx,
917 const struct dcesrv_endpoint_server *ep_server)
919 NTSTATUS status;
921 DBG_DEBUG("Registering server %s\n", ep_server->name);
923 status = dcerpc_register_ep_server(ep_server);
924 if (!NT_STATUS_IS_OK(status) &&
925 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
926 DBG_ERR("Failed to register '%s' endpoint server: %s\n",
927 ep_server->name,
928 nt_errstr(status));
929 return status;
932 status = dcesrv_init_ep_server(dce_ctx, ep_server->name);
933 if (!NT_STATUS_IS_OK(status)) {
934 DBG_ERR("dcesrv_init_ep_server(%s) failed: %s\n",
935 ep_server->name,
936 nt_errstr(status));
937 return status;
940 return NT_STATUS_OK;
944 * @brief Main function for RPC server implementations
946 * This function provides all that is necessary to run a RPC server
947 * inside the samba-dcerpcd framework. Just pass argv and argc on to
948 * this function.
950 * The get_interfaces() callback provides the information that is
951 * passed to samba-dcerpcd via --list-interfaces, it should not do any
952 * real RPC server initialization work. Quickly after this function is
953 * called by rpc_worker_main, the process exits again. It should
954 * return the number of interfaces provided.
956 * get_servers() is called when the process is about to do the real
957 * work. So more heavy-weight initialization should happen here. It
958 * should return the number of server implementations provided.
960 * @param[in] argc argc from main()
961 * @param[in] argv argv from main()
962 * @param[in] get_interfaces List all interfaces that this server provides
963 * @param[in] get_servers Provide the RPC server implementations
964 * @param[in] private_data Passed to the callback functions
965 * @return 0 It should never return except on successful process exit
968 int rpc_worker_main(
969 int argc,
970 const char *argv[],
971 const char *daemon_config_name,
972 int num_workers,
973 int idle_seconds,
974 size_t (*get_interfaces)(
975 const struct ndr_interface_table ***ifaces,
976 void *private_data),
977 size_t (*get_servers)(
978 struct dcesrv_context *dce_ctx,
979 const struct dcesrv_endpoint_server ***ep_servers,
980 void *private_data),
981 void *private_data)
983 const struct loadparm_substitution *lp_sub =
984 loadparm_s3_global_substitution();
985 const char *progname = getprogname();
986 TALLOC_CTX *frame = NULL;
987 struct tevent_context *ev_ctx = NULL;
988 struct tevent_req *req = NULL;
989 struct messaging_context *msg_ctx = NULL;
990 struct dcesrv_context *dce_ctx = NULL;
991 struct tevent_signal *se = NULL;
992 poptContext pc;
993 int opt;
994 NTSTATUS status;
995 int ret;
996 int worker_group = -1;
997 int worker_index = -1;
998 bool log_stdout;
999 int list_interfaces = 0;
1000 struct rpc_worker *worker = NULL;
1001 const struct dcesrv_endpoint_server **ep_servers;
1002 size_t i, num_servers;
1003 bool ok;
1005 struct poptOption long_options[] = {
1006 POPT_AUTOHELP
1008 .longName = "list-interfaces",
1009 .argInfo = POPT_ARG_NONE,
1010 .arg = &list_interfaces,
1011 .descrip = "List the interfaces provided",
1014 .longName = "worker-group",
1015 .argInfo = POPT_ARG_INT,
1016 .arg = &worker_group,
1017 .descrip = "Group index in status message",
1020 .longName = "worker-index",
1021 .argInfo = POPT_ARG_INT,
1022 .arg = &worker_index,
1023 .descrip = "Worker index in status message",
1025 POPT_COMMON_SAMBA
1026 POPT_TABLEEND
1028 static const struct smbd_shim smbd_shim_fns = {
1029 .become_authenticated_pipe_user =
1030 smbd_become_authenticated_pipe_user,
1031 .unbecome_authenticated_pipe_user =
1032 smbd_unbecome_authenticated_pipe_user,
1033 .become_root = smbd_become_root,
1034 .unbecome_root = smbd_unbecome_root,
1037 closefrom(3);
1038 talloc_enable_null_tracking();
1039 frame = talloc_stackframe();
1040 umask(0);
1041 smb_init_locale();
1043 ok = samba_cmdline_init(frame,
1044 SAMBA_CMDLINE_CONFIG_SERVER,
1045 true /* require_smbconf */);
1046 if (!ok) {
1047 DBG_ERR("Failed to init cmdline parser!\n");
1048 TALLOC_FREE(frame);
1049 exit(ENOMEM);
1052 pc = samba_popt_get_context(progname, argc, argv, long_options, 0);
1053 if (pc == NULL) {
1054 DBG_ERR("Failed to setup popt context!\n");
1055 TALLOC_FREE(frame);
1056 exit(1);
1059 while ((opt = poptGetNextOpt(pc)) != -1) {
1060 d_fprintf(stderr,
1061 "\nInvalid option %s: %s\n\n",
1062 poptBadOption(pc, 0),
1063 poptStrerror(opt));
1064 poptPrintUsage(pc, stderr, 0);
1065 TALLOC_FREE(frame);
1066 exit(1);
1068 poptFreeContext(pc);
1070 if (list_interfaces != 0) {
1071 const struct ndr_interface_table **ifaces = NULL;
1072 size_t num_ifaces;
1074 num_workers = lp_parm_int(
1075 -1, daemon_config_name, "num_workers", num_workers);
1076 idle_seconds = lp_parm_int(
1077 -1, daemon_config_name, "idle_seconds", idle_seconds);
1079 DBG_DEBUG("daemon=%s, num_workers=%d, idle_seconds=%d\n",
1080 daemon_config_name,
1081 num_workers,
1082 idle_seconds);
1084 fprintf(stdout, "%d\n%d\n", num_workers, idle_seconds);
1086 num_ifaces = get_interfaces(&ifaces, private_data);
1088 for (i=0; i<num_ifaces; i++) {
1089 rpc_worker_print_interface(stdout, ifaces[i]);
1092 TALLOC_FREE(frame);
1093 exit(0);
1096 log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
1097 if (log_stdout != 0) {
1098 setup_logging(argv[0], DEBUG_STDOUT);
1099 } else {
1100 setup_logging(argv[0], DEBUG_FILE);
1103 set_smbd_shim(&smbd_shim_fns);
1105 dump_core_setup(progname, lp_logfile(talloc_tos(), lp_sub));
1107 /* POSIX demands that signals are inherited. If the invoking
1108 * process has these signals masked, we will have problems, as
1109 * we won't receive them. */
1110 BlockSignals(False, SIGHUP);
1111 BlockSignals(False, SIGUSR1);
1112 BlockSignals(False, SIGTERM);
1114 #if defined(SIGFPE)
1115 /* we are never interested in SIGFPE */
1116 BlockSignals(True,SIGFPE);
1117 #endif
1118 /* We no longer use USR2... */
1119 #if defined(SIGUSR2)
1120 BlockSignals(True, SIGUSR2);
1121 #endif
1122 /* Ignore children - no zombies. */
1123 CatchChild();
1125 reopen_logs();
1127 DEBUG(0, ("%s version %s started.\n",
1128 progname,
1129 samba_version_string()));
1130 DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
1132 msg_ctx = global_messaging_context();
1133 if (msg_ctx == NULL) {
1134 DBG_ERR("global_messaging_context() failed\n");
1135 TALLOC_FREE(frame);
1136 exit(1);
1138 ev_ctx = messaging_tevent_context(msg_ctx);
1140 worker = rpc_worker_new(ev_ctx, msg_ctx);
1141 if (worker == NULL) {
1142 DBG_ERR("rpc_worker_new failed\n");
1143 global_messaging_context_free();
1144 TALLOC_FREE(frame);
1145 exit(1);
1147 dce_ctx = rpc_worker_dce_ctx(worker);
1149 se = tevent_add_signal(
1150 ev_ctx, ev_ctx, SIGTERM, 0, sig_term_handler, NULL);
1151 if (se == NULL) {
1152 DBG_ERR("tevent_add_signal failed\n");
1153 global_messaging_context_free();
1154 TALLOC_FREE(frame);
1155 exit(1);
1157 BlockSignals(false, SIGTERM);
1159 se = tevent_add_signal(
1160 ev_ctx, ev_ctx, SIGHUP, 0, sig_hup_handler, NULL);
1161 if (se == NULL) {
1162 DBG_ERR("tevent_add_signal failed\n");
1163 global_messaging_context_free();
1164 TALLOC_FREE(frame);
1165 exit(1);
1167 BlockSignals(false, SIGHUP);
1169 (void)winbind_off();
1170 ok = init_guest_session_info(NULL);
1171 (void)winbind_on();
1172 if (!ok) {
1173 DBG_WARNING("init_guest_session_info failed\n");
1174 global_messaging_context_free();
1175 TALLOC_FREE(frame);
1176 exit(1);
1179 status = init_system_session_info(NULL);
1180 if (!NT_STATUS_IS_OK(status)) {
1181 DBG_WARNING("init_system_session_info failed: %s\n",
1182 nt_errstr(status));
1183 global_messaging_context_free();
1184 TALLOC_FREE(frame);
1185 exit(1);
1188 DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
1190 num_servers = get_servers(dce_ctx, &ep_servers, private_data);
1192 DBG_DEBUG("get_servers() returned %zu servers\n", num_servers);
1194 for (i=0; i<num_servers; i++) {
1195 status = register_ep_server(dce_ctx, ep_servers[i]);
1196 if (!NT_STATUS_IS_OK(status)) {
1197 DBG_DEBUG("register_ep_server failed: %s\n",
1198 nt_errstr(status));
1199 global_messaging_context_free();
1200 TALLOC_FREE(frame);
1201 exit(1);
1205 req = rpc_worker_send(
1206 ev_ctx, ev_ctx, worker, getppid(), worker_group, worker_index);
1207 if (req == NULL) {
1208 DBG_ERR("rpc_worker_send failed\n");
1209 global_messaging_context_free();
1210 TALLOC_FREE(frame);
1211 exit(1);
1214 DBG_DEBUG("%s worker running\n", progname);
1216 while (tevent_req_is_in_progress(req)) {
1217 TALLOC_CTX *loop_frame = NULL;
1219 loop_frame = talloc_stackframe();
1221 ret = tevent_loop_once(ev_ctx);
1223 TALLOC_FREE(loop_frame);
1225 if (ret != 0) {
1226 DBG_WARNING("tevent_req_once() failed: %s\n",
1227 strerror(errno));
1228 global_messaging_context_free();
1229 TALLOC_FREE(frame);
1230 exit(1);
1234 status = dcesrv_shutdown_registered_ep_servers(dce_ctx);
1235 if (!NT_STATUS_IS_OK(status)) {
1236 DBG_DEBUG("Shutdown failed with: %s\n",
1237 nt_errstr(status));
1240 ret = rpc_worker_recv(req);
1241 if (ret != 0) {
1242 DBG_DEBUG("rpc_worker_recv returned %s\n", strerror(ret));
1243 global_messaging_context_free();
1244 TALLOC_FREE(frame);
1245 exit(1);
1248 TALLOC_FREE(frame);
1249 return 0;