s3:utils: Fix 'Usage:' for 'net ads enctypes'
[samba4-gss.git] / source3 / rpc_server / rpc_worker.c
blob9533c5598635dfee83c43cbdee998449f1a51667
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 "lib/util/util_file.h"
28 #include "rpc_server.h"
29 #include "rpc_pipes.h"
30 #include "source3/smbd/proto.h"
31 #include "source3/lib/smbd_shim.h"
32 #include "source3/lib/global_contexts.h"
33 #include "source3/lib/util_procid.h"
34 #include "lib/tsocket/tsocket.h"
35 #include "libcli/named_pipe_auth/npa_tstream.h"
36 #include "libcli/smb/smb_constants.h"
37 #include "lib/param/param.h"
38 #include "lib/util/idtree_random.h"
39 #include "lib/util/tevent_unix.h"
40 #include "lib/async_req/async_sock.h"
41 #include "lib/util/dlinklist.h"
42 #include "source3/include/auth.h"
43 #include "nsswitch/winbind_client.h"
44 #include "source3/include/messages.h"
45 #include "libcli/security/security_token.h"
46 #include "libcli/security/dom_sid.h"
47 #include "source3/include/proto.h"
50 * This is the generic code that becomes the
51 * template that all rpcd_* instances that
52 * serve DCERPC can use to provide services to samba-dcerpcd.
54 * The external entry point is:
55 * rpc_worker_main() which takes an argc/argv list
56 * and two functions:
58 * get_interfaces() - List all interfaces that this server provides
59 * get_servers() - Provide the RPC server implementations
61 * Each rpcd_* service needs only to provide
62 * the implementations of get_interfaces() and get_servers()
63 * and call rpc_worker_main() from their main() function
64 * to provide services that can be connected to from samba-dcerpcd.
67 struct rpc_worker {
68 struct dcerpc_ncacn_conn *conns;
69 struct server_id rpc_host_pid;
70 struct messaging_context *msg_ctx;
71 struct dcesrv_context *dce_ctx;
73 struct dcesrv_context_callbacks cb;
75 struct rpc_worker_status status;
77 bool done;
80 static void rpc_worker_print_interface(
81 FILE *f, const struct ndr_interface_table *t)
83 const struct ndr_interface_string_array *endpoints = t->endpoints;
84 uint32_t i;
85 struct ndr_syntax_id_buf id_buf;
87 fprintf(f,
88 "%s %s\n",
89 ndr_syntax_id_buf_string(&t->syntax_id, &id_buf),
90 t->name);
92 for (i=0; i<endpoints->count; i++) {
93 fprintf(f, " %s\n", endpoints->names[i]);
97 static NTSTATUS rpc_worker_report_status(struct rpc_worker *worker)
99 uint8_t buf[16];
100 DATA_BLOB blob = { .data = buf, .length = sizeof(buf), };
101 enum ndr_err_code ndr_err;
102 NTSTATUS status;
104 worker->status.num_association_groups = worker->dce_ctx->assoc_groups_num;
106 if (DEBUGLEVEL >= 10) {
107 NDR_PRINT_DEBUG(rpc_worker_status, &worker->status);
110 ndr_err = ndr_push_struct_into_fixed_blob(
111 &blob,
112 &worker->status,
113 (ndr_push_flags_fn_t)ndr_push_rpc_worker_status);
114 SMB_ASSERT(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
116 status = messaging_send(
117 worker->msg_ctx,
118 worker->rpc_host_pid,
119 MSG_RPC_WORKER_STATUS,
120 &blob);
121 return status;
124 static void rpc_worker_connection_terminated(
125 struct dcesrv_connection *conn, void *private_data)
127 struct rpc_worker *worker = talloc_get_type_abort(
128 private_data, struct rpc_worker);
129 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
130 conn->transport.private_data, struct dcerpc_ncacn_conn);
131 struct dcerpc_ncacn_conn *w = NULL;
132 NTSTATUS status;
133 bool found = false;
136 * We need to drop the association group reference
137 * explicitly here in order to avoid the order given
138 * by the destructors. rpc_worker_report_status() below,
139 * expects worker->dce_ctx->assoc_groups_num to be updated
140 * already.
142 if (conn->assoc_group != NULL) {
143 talloc_unlink(conn, conn->assoc_group);
144 conn->assoc_group = NULL;
147 SMB_ASSERT(worker->status.num_connections > 0);
149 for (w = worker->conns; w != NULL; w = w->next) {
150 if (w == ncacn_conn) {
151 found = true;
152 break;
155 SMB_ASSERT(found);
157 DLIST_REMOVE(worker->conns, ncacn_conn);
159 worker->status.num_connections -= 1;
161 status = rpc_worker_report_status(worker);
162 if (!NT_STATUS_IS_OK(status)) {
163 DBG_DEBUG("rpc_worker_report_status returned %s\n",
164 nt_errstr(status));
168 static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
170 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
171 conn->transport.private_data,
172 struct dcerpc_ncacn_conn);
174 if (ncacn_conn->termination_fn != NULL) {
175 ncacn_conn->termination_fn(conn, ncacn_conn->termination_data);
178 return 0;
182 * A new client has been passed to us from samba-dcerpcd.
184 static void rpc_worker_new_client(
185 struct rpc_worker *worker,
186 struct rpc_host_client *client,
187 int sock)
189 struct dcesrv_context *dce_ctx = worker->dce_ctx;
190 struct named_pipe_auth_req_info8 *info8 = client->npa_info8;
191 struct tsocket_address *remote_client_addr = NULL;
192 struct tsocket_address *local_server_addr = NULL;
193 struct dcerpc_binding *b = NULL;
194 enum dcerpc_transport_t transport;
195 struct dcesrv_endpoint *ep = NULL;
196 struct tstream_context *tstream = NULL;
197 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
198 struct dcesrv_connection *dcesrv_conn = NULL;
199 DATA_BLOB buffer = { .data = NULL };
200 struct ncacn_packet *pkt = NULL;
201 struct security_token *token = NULL;
202 uint32_t npa_flags, state_flags;
203 bool found_npa_flags;
204 NTSTATUS status;
205 int ret;
207 DBG_DEBUG("Got new conn sock %d for binding %s\n",
208 sock,
209 client->binding);
211 status = dcerpc_parse_binding(client, client->binding, &b);
212 if (!NT_STATUS_IS_OK(status)) {
213 DBG_DEBUG("dcerpc_parse_binding(%s) failed: %s\n",
214 client->binding,
215 nt_errstr(status));
216 goto fail;
218 transport = dcerpc_binding_get_transport(b);
220 status = dcesrv_find_endpoint(dce_ctx, b, &ep);
222 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) &&
223 ((transport == NCACN_IP_TCP) || (transport == NCALRPC)) &&
224 (dcerpc_binding_get_string_option(b, "endpoint") != NULL)) {
226 * We have two kinds of servers: Those who explicitly
227 * bind to a port (e.g. 135 for epmapper) and those
228 * who just specify a transport. The client specified
229 * a port (or socket name), but we did not find this
230 * in the list of servers having specified a
231 * port. Retry just matching for the transport,
232 * catching the servers that did not explicitly
233 * specify a port.
235 * This is not fully correct, what we should do is
236 * that once the port the server listens on has been
237 * finalized we should mark this in the server list,
238 * but for now it works. We don't have the same RPC
239 * interface listening twice on different ports.
241 struct dcerpc_binding *b_without_port = dcerpc_binding_dup(
242 client, b);
243 if (b_without_port == NULL) {
244 status = NT_STATUS_NO_MEMORY;
245 goto fail;
248 status = dcerpc_binding_set_string_option(
249 b_without_port, "endpoint", NULL);
250 if (!NT_STATUS_IS_OK(status)) {
251 DBG_DEBUG("Could not delete endpoint: %s\n",
252 nt_errstr(status));
253 TALLOC_FREE(b_without_port);
254 goto fail;
257 status = dcesrv_find_endpoint(dce_ctx, b_without_port, &ep);
259 TALLOC_FREE(b_without_port);
262 if (!NT_STATUS_IS_OK(status)) {
263 DBG_DEBUG("Could not find endpoint for %s: %s\n",
264 client->binding,
265 nt_errstr(status));
266 goto fail;
269 ncacn_conn = talloc(dce_ctx, struct dcerpc_ncacn_conn);
270 if (ncacn_conn == NULL) {
271 DBG_DEBUG("talloc failed\n");
272 goto fail;
274 *ncacn_conn = (struct dcerpc_ncacn_conn) {
275 .endpoint = ep,
276 .sock = sock,
277 .termination_fn = rpc_worker_connection_terminated,
278 .termination_data = worker,
281 if (transport == NCALRPC) {
282 ret = tsocket_address_unix_from_path(ncacn_conn,
283 info8->remote_client_addr,
284 &remote_client_addr);
285 if (ret == -1) {
286 DBG_DEBUG("tsocket_address_unix_from_path"
287 "(%s) failed: %s\n",
288 info8->remote_client_addr,
289 strerror(errno));
290 goto fail;
293 ncacn_conn->remote_client_name =
294 talloc_strdup(ncacn_conn, info8->remote_client_name);
295 if (ncacn_conn->remote_client_name == NULL) {
296 DBG_DEBUG("talloc_strdup(%s) failed\n",
297 info8->remote_client_name);
298 goto fail;
301 ret = tsocket_address_unix_from_path(ncacn_conn,
302 info8->local_server_addr,
303 &local_server_addr);
304 if (ret == -1) {
305 DBG_DEBUG("tsocket_address_unix_from_path"
306 "(%s) failed: %s\n",
307 info8->local_server_addr,
308 strerror(errno));
309 goto fail;
312 ncacn_conn->local_server_name =
313 talloc_strdup(ncacn_conn, info8->local_server_name);
314 if (ncacn_conn->local_server_name == NULL) {
315 DBG_DEBUG("talloc_strdup(%s) failed\n",
316 info8->local_server_name);
317 goto fail;
319 } else {
320 ret = tsocket_address_inet_from_strings(
321 ncacn_conn,
322 "ip",
323 info8->remote_client_addr,
324 info8->remote_client_port,
325 &remote_client_addr);
326 if (ret == -1) {
327 DBG_DEBUG("tsocket_address_inet_from_strings"
328 "(%s, %" PRIu16 ") failed: %s\n",
329 info8->remote_client_addr,
330 info8->remote_client_port,
331 strerror(errno));
332 goto fail;
334 ncacn_conn->remote_client_name =
335 talloc_strdup(ncacn_conn, info8->remote_client_name);
336 if (ncacn_conn->remote_client_name == NULL) {
337 DBG_DEBUG("talloc_strdup(%s) failed\n",
338 info8->remote_client_name);
339 goto fail;
342 ret = tsocket_address_inet_from_strings(
343 ncacn_conn,
344 "ip",
345 info8->local_server_addr,
346 info8->local_server_port,
347 &local_server_addr);
348 if (ret == -1) {
349 DBG_DEBUG("tsocket_address_inet_from_strings"
350 "(%s, %" PRIu16 ") failed: %s\n",
351 info8->local_server_addr,
352 info8->local_server_port,
353 strerror(errno));
354 goto fail;
356 ncacn_conn->local_server_name =
357 talloc_strdup(ncacn_conn, info8->local_server_name);
358 if (ncacn_conn->local_server_name == NULL) {
359 DBG_DEBUG("talloc_strdup(%s) failed\n",
360 info8->local_server_name);
361 goto fail;
365 if (transport == NCACN_NP) {
366 ret = tstream_npa_existing_socket(
367 ncacn_conn,
368 sock,
369 FILE_TYPE_MESSAGE_MODE_PIPE,
370 &tstream);
371 if (ret == -1) {
372 DBG_DEBUG("tstream_npa_existing_socket failed: %s\n",
373 strerror(errno));
374 goto fail;
378 * "transport" so far is implicitly assigned by the
379 * socket that the client connected to, passed in from
380 * samba-dcerpcd via the binding. For NCACN_NP (root
381 * only by unix permissions) we got a
382 * named_pipe_auth_req_info8 where the transport can
383 * be overridden.
385 transport = info8->transport;
386 } else {
387 ret = tstream_bsd_existing_socket(
388 ncacn_conn, sock, &tstream);
389 if (ret == -1) {
390 DBG_DEBUG("tstream_bsd_existing_socket failed: %s\n",
391 strerror(errno));
392 goto fail;
394 /* as server we want to fail early */
395 tstream_bsd_fail_readv_first_error(tstream, true);
397 sock = -1;
399 token = info8->session_info->session_info->security_token;
401 if (security_token_is_system(token) && (transport != NCALRPC)) {
402 DBG_DEBUG("System token only allowed on NCALRPC\n");
403 goto fail;
406 state_flags = DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
408 found_npa_flags = security_token_find_npa_flags(token, &npa_flags);
409 if (found_npa_flags) {
410 if (npa_flags & SAMBA_NPA_FLAGS_WINBIND_OFF) {
411 state_flags |=
412 DCESRV_CALL_STATE_FLAG_WINBIND_OFF;
416 * Delete the flags so that we don't bail in
417 * local_np_connect_send() on subsequent
418 * connects. Once we connect to another RPC service, a
419 * new flags sid will be added if required.
421 security_token_del_npa_flags(token);
424 ncacn_conn->p.msg_ctx = global_messaging_context();
425 ncacn_conn->p.transport = transport;
427 status = dcesrv_endpoint_connect(dce_ctx,
428 ncacn_conn,
430 info8->session_info->session_info,
431 global_event_context(),
432 state_flags,
433 &dcesrv_conn);
434 if (!NT_STATUS_IS_OK(status)) {
435 DBG_DEBUG("Failed to connect to endpoint: %s\n",
436 nt_errstr(status));
437 goto fail;
440 talloc_set_destructor(dcesrv_conn, dcesrv_connection_destructor);
442 dcesrv_conn->transport.private_data = ncacn_conn;
443 dcesrv_conn->transport.report_output_data =
444 dcesrv_sock_report_output_data;
445 dcesrv_conn->transport.terminate_connection =
446 dcesrv_transport_terminate_connection;
448 dcesrv_conn->send_queue = tevent_queue_create(
449 dcesrv_conn, "dcesrv send queue");
450 if (dcesrv_conn->send_queue == NULL) {
451 DBG_DEBUG("tevent_queue_create failed\n");
452 goto fail;
455 dcesrv_conn->stream = talloc_move(dcesrv_conn, &tstream);
456 dcesrv_conn->local_address =
457 talloc_move(dcesrv_conn, &local_server_addr);
458 dcesrv_conn->remote_address =
459 talloc_move(dcesrv_conn, &remote_client_addr);
461 if (client->bind_packet.length == 0) {
462 DBG_DEBUG("Expected bind packet\n");
463 goto fail;
466 buffer = (DATA_BLOB) {
467 .data = talloc_move(dcesrv_conn, &client->bind_packet.data),
468 .length = client->bind_packet.length,
471 pkt = talloc(dcesrv_conn, struct ncacn_packet);
472 if (pkt == NULL) {
473 DBG_DEBUG("talloc failed\n");
474 goto fail;
477 status = dcerpc_pull_ncacn_packet(pkt, &buffer, pkt);
478 if (!NT_STATUS_IS_OK(status)) {
479 DBG_DEBUG("dcerpc_pull_ncacn_packet failed: %s\n",
480 nt_errstr(status));
481 goto fail;
484 TALLOC_FREE(client);
486 DLIST_ADD(worker->conns, ncacn_conn);
487 worker->status.num_connections += 1;
489 dcesrv_loop_next_packet(dcesrv_conn, pkt, buffer);
491 return;
492 fail:
493 TALLOC_FREE(ncacn_conn);
494 TALLOC_FREE(dcesrv_conn);
495 TALLOC_FREE(client);
496 if (sock != -1) {
497 close(sock);
501 * Parent thinks it successfully sent us a client. Tell it
502 * that we declined.
504 status = rpc_worker_report_status(worker);
505 if (!NT_STATUS_IS_OK(status)) {
506 DBG_DEBUG("rpc_worker_report_status returned %s\n",
507 nt_errstr(status));
512 * New client message processing.
514 static bool rpc_worker_new_client_filter(
515 struct messaging_rec *rec, void *private_data)
517 struct rpc_worker *worker = talloc_get_type_abort(
518 private_data, struct rpc_worker);
519 struct dcesrv_context *dce_ctx = worker->dce_ctx;
520 struct rpc_host_client *client = NULL;
521 enum ndr_err_code ndr_err;
522 int sock;
524 if (rec->msg_type != MSG_RPC_HOST_NEW_CLIENT) {
525 return false;
528 if (rec->num_fds != 1) {
529 DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
530 return false;
533 client = talloc(dce_ctx, struct rpc_host_client);
534 if (client == NULL) {
535 DBG_DEBUG("talloc failed\n");
536 return false;
539 ndr_err = ndr_pull_struct_blob_all(
540 &rec->buf,
541 client,
542 client,
543 (ndr_pull_flags_fn_t)ndr_pull_rpc_host_client);
544 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
545 DBG_DEBUG("ndr_pull_rpc_host_client failed: %s\n",
546 ndr_errstr(ndr_err));
547 TALLOC_FREE(client);
548 return false;
551 if (DEBUGLEVEL >= 10) {
552 NDR_PRINT_DEBUG(rpc_host_client, client);
555 sock = rec->fds[0];
556 rec->fds[0] = -1;
558 rpc_worker_new_client(worker, client, sock);
560 return false;
564 * Return your status message processing.
566 static bool rpc_worker_status_filter(
567 struct messaging_rec *rec, void *private_data)
569 struct rpc_worker *worker = talloc_get_type_abort(
570 private_data, struct rpc_worker);
571 struct dcerpc_ncacn_conn *conn = NULL;
572 FILE *f = NULL;
574 if (rec->msg_type != MSG_RPC_DUMP_STATUS) {
575 return false;
578 if (rec->num_fds != 1) {
579 DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
580 return false;
583 f = fdopen_keepfd(rec->fds[0], "w");
584 if (f == NULL) {
585 DBG_DEBUG("fdopen_keepfd failed: %s\n", strerror(errno));
586 return false;
589 for (conn = worker->conns; conn != NULL; conn = conn->next) {
590 char *endpoint = NULL;
592 endpoint = dcerpc_binding_string(
593 conn, conn->endpoint->ep_description);
595 fprintf(f,
596 "endpoint=%s client=%s server=%s\n",
597 endpoint ? endpoint : "UNKNOWN",
598 conn->remote_client_name,
599 conn->local_server_name);
600 TALLOC_FREE(endpoint);
603 fclose(f);
605 return false;
609 take a reference to an existing association group
611 static struct dcesrv_assoc_group *rpc_worker_assoc_group_reference(
612 struct dcesrv_connection *conn,
613 uint32_t id)
615 const struct dcesrv_endpoint *endpoint = conn->endpoint;
616 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
617 endpoint->ep_description);
618 struct dcesrv_assoc_group *assoc_group = NULL;
619 void *id_ptr = NULL;
621 /* find an association group given a assoc_group_id */
622 id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, id & UINT16_MAX);
623 if (id_ptr == NULL) {
624 DBG_NOTICE("Failed to find assoc_group 0x%08x\n", id);
625 return NULL;
627 assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
629 if (assoc_group->transport != transport) {
630 const char *at = derpc_transport_string_by_transport(
631 assoc_group->transport);
632 const char *ct = derpc_transport_string_by_transport(
633 transport);
635 DBG_NOTICE("assoc_group 0x%08x (transport %s) "
636 "is not available on transport %s\n",
637 id, at, ct);
638 return NULL;
642 * Yes, this is a talloc_reference: The assoc group must be
643 * removed when all connections go. This should be replaced by
644 * adding a linked list of dcesrv_connection structs to the
645 * assoc group.
647 return talloc_reference(conn, assoc_group);
650 static int rpc_worker_assoc_group_destructor(
651 struct dcesrv_assoc_group *assoc_group)
653 int ret;
655 dcesrv_assoc_group_common_destructor(assoc_group);
657 ret = idr_remove(
658 assoc_group->dce_ctx->assoc_groups_idr,
659 assoc_group->id & UINT16_MAX);
660 if (ret != 0) {
661 DBG_WARNING("Failed to remove assoc_group 0x%08x\n",
662 assoc_group->id);
665 SMB_ASSERT(assoc_group->dce_ctx->assoc_groups_num > 0);
666 assoc_group->dce_ctx->assoc_groups_num -= 1;
667 return 0;
671 allocate a new association group
673 static struct dcesrv_assoc_group *rpc_worker_assoc_group_new(
674 struct dcesrv_connection *conn, uint16_t worker_index)
676 struct dcesrv_context *dce_ctx = conn->dce_ctx;
677 const struct dcesrv_endpoint *endpoint = conn->endpoint;
678 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
679 endpoint->ep_description);
680 struct dcesrv_assoc_group *assoc_group = NULL;
681 int id;
683 assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
684 if (assoc_group == NULL) {
685 return NULL;
689 * We use 16-bit to encode the worker index,
690 * have 16-bits left within the worker to form a
691 * 32-bit association group id.
693 id = idr_get_new_random(
694 dce_ctx->assoc_groups_idr, assoc_group, 1, UINT16_MAX);
695 if (id == -1) {
696 talloc_free(assoc_group);
697 DBG_WARNING("Out of association groups!\n");
698 return NULL;
700 assoc_group->id = (((uint32_t)worker_index) << 16) | id;
701 assoc_group->transport = transport;
702 assoc_group->dce_ctx = dce_ctx;
704 talloc_set_destructor(assoc_group, rpc_worker_assoc_group_destructor);
706 SMB_ASSERT(dce_ctx->assoc_groups_num < UINT16_MAX);
707 dce_ctx->assoc_groups_num += 1;
709 return assoc_group;
712 static NTSTATUS rpc_worker_assoc_group_find(
713 struct dcesrv_call_state *call,
714 void *private_data)
716 struct rpc_worker *w = talloc_get_type_abort(
717 private_data, struct rpc_worker);
718 uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
720 if (assoc_group_id != 0) {
721 uint16_t worker_index = (assoc_group_id & 0xffff0000) >> 16;
722 if (worker_index != w->status.worker_index) {
723 DBG_DEBUG("Wrong worker id %"PRIu16", "
724 "expected %"PRIu32"\n",
725 worker_index,
726 w->status.worker_index);
727 return NT_STATUS_NOT_FOUND;
729 call->conn->assoc_group = rpc_worker_assoc_group_reference(
730 call->conn, assoc_group_id);
731 } else {
732 call->conn->assoc_group = rpc_worker_assoc_group_new(
733 call->conn, w->status.worker_index);
736 if (call->conn->assoc_group == NULL) {
737 /* TODO Return correct status */
738 return NT_STATUS_UNSUCCESSFUL;
741 return NT_STATUS_OK;
744 static struct rpc_worker *rpc_worker_new(
745 TALLOC_CTX *mem_ctx,
746 struct messaging_context *msg_ctx)
748 struct rpc_worker *worker = NULL;
750 worker = talloc_zero(mem_ctx, struct rpc_worker);
751 if (worker == NULL) {
752 return NULL;
755 worker->rpc_host_pid = (struct server_id) { .pid = 0 };
756 worker->msg_ctx = msg_ctx;
758 worker->cb = (struct dcesrv_context_callbacks) {
759 .log.successful_authz = dcesrv_log_successful_authz,
760 .auth.gensec_prepare = dcesrv_auth_gensec_prepare,
761 .auth.become_root = become_root,
762 .auth.unbecome_root = unbecome_root,
763 .assoc_group.find = rpc_worker_assoc_group_find,
764 .assoc_group.private_data = worker,
767 worker->dce_ctx = global_dcesrv_context();
768 if (worker->dce_ctx == NULL) {
769 goto fail;
771 dcesrv_context_set_callbacks(worker->dce_ctx, &worker->cb);
773 return worker;
774 fail:
775 TALLOC_FREE(worker);
776 return NULL;
779 static struct dcesrv_context *rpc_worker_dce_ctx(struct rpc_worker *w)
781 return w->dce_ctx;
784 struct rpc_worker_state {
785 struct tevent_context *ev;
786 struct rpc_worker *w;
787 struct tevent_req *new_client_req;
788 struct tevent_req *status_req;
789 struct tevent_req *finish_req;
792 static void rpc_worker_done(struct tevent_req *subreq);
793 static void rpc_worker_shutdown(
794 struct messaging_context *msg,
795 void *private_data,
796 uint32_t msg_type,
797 struct server_id server_id,
798 DATA_BLOB *data);
800 static struct tevent_req *rpc_worker_send(
801 TALLOC_CTX *mem_ctx,
802 struct tevent_context *ev,
803 struct rpc_worker *w,
804 pid_t rpc_host_pid,
805 int server_index,
806 int worker_index)
808 struct tevent_req *req = NULL;
809 struct rpc_worker_state *state = NULL;
810 NTSTATUS status;
812 req = tevent_req_create(mem_ctx, &state, struct rpc_worker_state);
813 if (req == NULL) {
814 return NULL;
816 state->ev = ev;
817 state->w = w;
819 if ((server_index < 0) || ((unsigned)server_index > UINT32_MAX)) {
820 DBG_ERR("Invalid server index %d\n", server_index);
821 tevent_req_error(req, EINVAL);
822 return tevent_req_post(req, ev);
824 if ((worker_index < 0) || ((unsigned)worker_index > UINT16_MAX)) {
825 DBG_ERR("Invalid worker index %d\n", worker_index);
826 tevent_req_error(req, EINVAL);
827 return tevent_req_post(req, ev);
829 w->rpc_host_pid = pid_to_procid(rpc_host_pid);
831 w->status = (struct rpc_worker_status) {
832 .server_index = server_index,
833 .worker_index = worker_index,
836 /* Wait for new client messages. */
837 state->new_client_req = messaging_filtered_read_send(
839 messaging_tevent_context(w->msg_ctx),
840 w->msg_ctx,
841 rpc_worker_new_client_filter,
843 if (tevent_req_nomem(state->new_client_req, req)) {
844 return tevent_req_post(req, ev);
847 /* Wait for report your status messages. */
848 state->status_req = messaging_filtered_read_send(
850 messaging_tevent_context(w->msg_ctx),
851 w->msg_ctx,
852 rpc_worker_status_filter,
854 if (tevent_req_nomem(state->status_req, req)) {
855 return tevent_req_post(req, ev);
858 /* Wait for shutdown messages. */
859 status = messaging_register(
860 w->msg_ctx, req, MSG_SHUTDOWN, rpc_worker_shutdown);
861 if (!NT_STATUS_IS_OK(status)) {
862 DBG_DEBUG("messaging_register failed: %s\n",
863 nt_errstr(status));
864 tevent_req_error(req, map_errno_from_nt_status(status));
865 return tevent_req_post(req, ev);
868 state->finish_req = wait_for_read_send(state, ev, 0, false);
869 if (tevent_req_nomem(state->finish_req, req)) {
870 return tevent_req_post(req, ev);
872 tevent_req_set_callback(state->finish_req, rpc_worker_done, req);
874 rpc_worker_report_status(w);
876 return req;
879 static void rpc_worker_done(struct tevent_req *subreq)
881 struct tevent_req *req = tevent_req_callback_data(
882 subreq, struct tevent_req);
883 int err = 0;
884 bool ok;
886 ok = wait_for_read_recv(subreq, &err);
887 TALLOC_FREE(subreq);
888 if (!ok) {
889 tevent_req_error(req, err);
890 return;
892 tevent_req_done(req);
895 static void rpc_worker_shutdown(
896 struct messaging_context *msg,
897 void *private_data,
898 uint32_t msg_type,
899 struct server_id server_id,
900 DATA_BLOB *data)
902 struct tevent_req *req = talloc_get_type_abort(
903 private_data, struct tevent_req);
904 tevent_req_done(req);
907 static int rpc_worker_recv(struct tevent_req *req)
909 return tevent_req_simple_recv_unix(req);
912 static void sig_term_handler(
913 struct tevent_context *ev,
914 struct tevent_signal *se,
915 int signum,
916 int count,
917 void *siginfo,
918 void *private_data)
920 exit(0);
923 static void sig_hup_handler(
924 struct tevent_context *ev,
925 struct tevent_signal *se,
926 int signum,
927 int count,
928 void *siginfo,
929 void *private_data)
931 change_to_root_user();
932 lp_load_with_shares(get_dyn_CONFIGFILE());
935 static NTSTATUS register_ep_server(
936 struct dcesrv_context *dce_ctx,
937 const struct dcesrv_endpoint_server *ep_server)
939 NTSTATUS status;
941 DBG_DEBUG("Registering server %s\n", ep_server->name);
943 status = dcerpc_register_ep_server(ep_server);
944 if (!NT_STATUS_IS_OK(status) &&
945 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
946 DBG_ERR("Failed to register '%s' endpoint server: %s\n",
947 ep_server->name,
948 nt_errstr(status));
949 return status;
952 status = dcesrv_init_ep_server(dce_ctx, ep_server->name);
953 if (!NT_STATUS_IS_OK(status)) {
954 DBG_ERR("dcesrv_init_ep_server(%s) failed: %s\n",
955 ep_server->name,
956 nt_errstr(status));
957 return status;
960 return NT_STATUS_OK;
964 * @brief Main function for RPC server implementations
966 * This function provides all that is necessary to run a RPC server
967 * inside the samba-dcerpcd framework. Just pass argv and argc on to
968 * this function.
970 * The get_interfaces() callback provides the information that is
971 * passed to samba-dcerpcd via --list-interfaces, it should not do any
972 * real RPC server initialization work. Quickly after this function is
973 * called by rpc_worker_main, the process exits again. It should
974 * return the number of interfaces provided.
976 * get_servers() is called when the process is about to do the real
977 * work. So more heavy-weight initialization should happen here. It
978 * should return NT_STATUS_OK and the number of server implementations provided.
980 * @param[in] argc argc from main()
981 * @param[in] argv argv from main()
982 * @param[in] get_interfaces List all interfaces that this server provides
983 * @param[in] get_servers Provide the RPC server implementations
984 * @param[in] private_data Passed to the callback functions
985 * @return 0 It should never return except on successful process exit
988 int rpc_worker_main(
989 int argc,
990 const char *argv[],
991 const char *daemon_config_name,
992 int num_workers,
993 int idle_seconds,
994 size_t (*get_interfaces)(
995 const struct ndr_interface_table ***ifaces,
996 void *private_data),
997 NTSTATUS (*get_servers)(
998 struct dcesrv_context *dce_ctx,
999 const struct dcesrv_endpoint_server ***ep_servers,
1000 size_t *num_ep_servers,
1001 void *private_data),
1002 void *private_data)
1004 const struct loadparm_substitution *lp_sub =
1005 loadparm_s3_global_substitution();
1006 const char *progname = getprogname();
1007 TALLOC_CTX *frame = NULL;
1008 struct tevent_context *ev_ctx = NULL;
1009 struct tevent_req *req = NULL;
1010 struct messaging_context *msg_ctx = NULL;
1011 struct dcesrv_context *dce_ctx = NULL;
1012 struct tevent_signal *se = NULL;
1013 poptContext pc;
1014 int opt;
1015 NTSTATUS status;
1016 int ret;
1017 int worker_group = -1;
1018 int worker_index = -1;
1019 bool log_stdout;
1020 int list_interfaces = 0;
1021 struct rpc_worker *worker = NULL;
1022 const struct dcesrv_endpoint_server **ep_servers;
1023 size_t i, num_servers;
1024 bool ok;
1026 struct poptOption long_options[] = {
1027 POPT_AUTOHELP
1029 .longName = "list-interfaces",
1030 .argInfo = POPT_ARG_NONE,
1031 .arg = &list_interfaces,
1032 .descrip = "List the interfaces provided",
1035 .longName = "worker-group",
1036 .argInfo = POPT_ARG_INT,
1037 .arg = &worker_group,
1038 .descrip = "Group index in status message",
1041 .longName = "worker-index",
1042 .argInfo = POPT_ARG_INT,
1043 .arg = &worker_index,
1044 .descrip = "Worker index in status message",
1046 POPT_COMMON_SAMBA
1047 POPT_TABLEEND
1049 static const struct smbd_shim smbd_shim_fns = {
1050 .become_authenticated_pipe_user =
1051 smbd_become_authenticated_pipe_user,
1052 .unbecome_authenticated_pipe_user =
1053 smbd_unbecome_authenticated_pipe_user,
1054 .become_root = smbd_become_root,
1055 .unbecome_root = smbd_unbecome_root,
1058 closefrom(3);
1059 talloc_enable_null_tracking();
1060 frame = talloc_stackframe();
1061 umask(0);
1062 smb_init_locale();
1064 ok = samba_cmdline_init(frame,
1065 SAMBA_CMDLINE_CONFIG_SERVER,
1066 true /* require_smbconf */);
1067 if (!ok) {
1068 DBG_ERR("Failed to init cmdline parser!\n");
1069 TALLOC_FREE(frame);
1070 exit(ENOMEM);
1073 pc = samba_popt_get_context(progname, argc, argv, long_options, 0);
1074 if (pc == NULL) {
1075 DBG_ERR("Failed to setup popt context!\n");
1076 TALLOC_FREE(frame);
1077 exit(1);
1080 while ((opt = poptGetNextOpt(pc)) != -1) {
1081 d_fprintf(stderr,
1082 "\nInvalid option %s: %s\n\n",
1083 poptBadOption(pc, 0),
1084 poptStrerror(opt));
1085 poptPrintUsage(pc, stderr, 0);
1086 TALLOC_FREE(frame);
1087 exit(1);
1089 poptFreeContext(pc);
1091 if (list_interfaces != 0) {
1092 const struct ndr_interface_table **ifaces = NULL;
1093 size_t num_ifaces;
1095 num_workers = lp_parm_int(
1096 -1, daemon_config_name, "num_workers", num_workers);
1097 idle_seconds = lp_parm_int(
1098 -1, daemon_config_name, "idle_seconds", idle_seconds);
1100 DBG_DEBUG("daemon=%s, num_workers=%d, idle_seconds=%d\n",
1101 daemon_config_name,
1102 num_workers,
1103 idle_seconds);
1105 fprintf(stdout, "%d\n%d\n", num_workers, idle_seconds);
1107 num_ifaces = get_interfaces(&ifaces, private_data);
1109 for (i=0; i<num_ifaces; i++) {
1110 rpc_worker_print_interface(stdout, ifaces[i]);
1113 TALLOC_FREE(frame);
1114 exit(0);
1117 log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
1118 if (log_stdout != 0) {
1119 setup_logging(argv[0], DEBUG_STDOUT);
1120 } else {
1121 setup_logging(argv[0], DEBUG_FILE);
1124 set_smbd_shim(&smbd_shim_fns);
1126 dump_core_setup(progname, lp_logfile(talloc_tos(), lp_sub));
1128 /* POSIX demands that signals are inherited. If the invoking
1129 * process has these signals masked, we will have problems, as
1130 * we won't receive them. */
1131 BlockSignals(False, SIGHUP);
1132 BlockSignals(False, SIGUSR1);
1133 BlockSignals(False, SIGTERM);
1135 #if defined(SIGFPE)
1136 /* we are never interested in SIGFPE */
1137 BlockSignals(True,SIGFPE);
1138 #endif
1139 /* We no longer use USR2... */
1140 #if defined(SIGUSR2)
1141 BlockSignals(True, SIGUSR2);
1142 #endif
1143 /* Ignore children - no zombies. */
1144 CatchChild();
1146 reopen_logs();
1148 DBG_STARTUP_NOTICE("%s version %s started.\n%s\n",
1149 progname,
1150 samba_version_string(),
1151 samba_copyright_string());
1153 msg_ctx = global_messaging_context();
1154 if (msg_ctx == NULL) {
1155 DBG_ERR("global_messaging_context() failed\n");
1156 TALLOC_FREE(frame);
1157 exit(1);
1159 ev_ctx = messaging_tevent_context(msg_ctx);
1161 worker = rpc_worker_new(ev_ctx, msg_ctx);
1162 if (worker == NULL) {
1163 DBG_ERR("rpc_worker_new failed\n");
1164 global_messaging_context_free();
1165 TALLOC_FREE(frame);
1166 exit(1);
1168 dce_ctx = rpc_worker_dce_ctx(worker);
1170 se = tevent_add_signal(
1171 ev_ctx, ev_ctx, SIGTERM, 0, sig_term_handler, NULL);
1172 if (se == NULL) {
1173 DBG_ERR("tevent_add_signal failed\n");
1174 global_messaging_context_free();
1175 TALLOC_FREE(frame);
1176 exit(1);
1178 BlockSignals(false, SIGTERM);
1180 se = tevent_add_signal(
1181 ev_ctx, ev_ctx, SIGHUP, 0, sig_hup_handler, NULL);
1182 if (se == NULL) {
1183 DBG_ERR("tevent_add_signal failed\n");
1184 global_messaging_context_free();
1185 TALLOC_FREE(frame);
1186 exit(1);
1188 BlockSignals(false, SIGHUP);
1190 (void)winbind_off();
1191 ok = init_guest_session_info(NULL);
1192 (void)winbind_on();
1193 if (!ok) {
1194 DBG_WARNING("init_guest_session_info failed\n");
1195 global_messaging_context_free();
1196 TALLOC_FREE(frame);
1197 exit(1);
1200 status = init_system_session_info(NULL);
1201 if (!NT_STATUS_IS_OK(status)) {
1202 DBG_WARNING("init_system_session_info failed: %s\n",
1203 nt_errstr(status));
1204 global_messaging_context_free();
1205 TALLOC_FREE(frame);
1206 exit(1);
1209 DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
1211 status = get_servers(dce_ctx,
1212 &ep_servers,
1213 &num_servers,
1214 private_data);
1215 if (!NT_STATUS_IS_OK(status)) {
1216 DBG_ERR("get_servers failed: %s\n", nt_errstr(status));
1217 global_messaging_context_free();
1218 TALLOC_FREE(frame);
1219 exit(1);
1222 DBG_DEBUG("get_servers() returned %zu servers\n", num_servers);
1224 for (i=0; i<num_servers; i++) {
1225 status = register_ep_server(dce_ctx, ep_servers[i]);
1226 if (!NT_STATUS_IS_OK(status)) {
1227 DBG_ERR("register_ep_server failed: %s\n",
1228 nt_errstr(status));
1229 global_messaging_context_free();
1230 TALLOC_FREE(frame);
1231 exit(1);
1235 req = rpc_worker_send(
1236 ev_ctx, ev_ctx, worker, getppid(), worker_group, worker_index);
1237 if (req == NULL) {
1238 DBG_ERR("rpc_worker_send failed\n");
1239 global_messaging_context_free();
1240 TALLOC_FREE(frame);
1241 exit(1);
1244 DBG_DEBUG("%s worker running\n", progname);
1246 while (tevent_req_is_in_progress(req)) {
1247 TALLOC_CTX *loop_frame = NULL;
1249 loop_frame = talloc_stackframe();
1251 ret = tevent_loop_once(ev_ctx);
1253 TALLOC_FREE(loop_frame);
1255 if (ret != 0) {
1256 DBG_WARNING("tevent_req_once() failed: %s\n",
1257 strerror(errno));
1258 global_messaging_context_free();
1259 TALLOC_FREE(frame);
1260 exit(1);
1264 status = dcesrv_shutdown_registered_ep_servers(dce_ctx);
1265 if (!NT_STATUS_IS_OK(status)) {
1266 DBG_DEBUG("Shutdown failed with: %s\n",
1267 nt_errstr(status));
1270 ret = rpc_worker_recv(req);
1271 if (ret != 0) {
1272 DBG_DEBUG("rpc_worker_recv returned %s\n", strerror(ret));
1273 global_messaging_context_free();
1274 TALLOC_FREE(frame);
1275 exit(1);
1278 TALLOC_FREE(frame);
1279 return 0;