Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
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.
8 : *
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.
13 : *
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/>.
16 : */
17 :
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"
47 :
48 : /*
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.
52 : *
53 : * The external entry point is:
54 : * rpc_worker_main() which takes an argc/argv list
55 : * and two functions:
56 : *
57 : * get_interfaces() - List all interfaces that this server provides
58 : * get_servers() - Provide the RPC server implementations
59 : *
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.
64 : */
65 :
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;
71 :
72 : struct dcesrv_context_callbacks cb;
73 :
74 : struct rpc_worker_status status;
75 :
76 : bool done;
77 : };
78 :
79 1430 : static void rpc_worker_print_interface(
80 : FILE *f, const struct ndr_interface_table *t)
81 : {
82 1430 : const struct ndr_interface_string_array *endpoints = t->endpoints;
83 : uint32_t i;
84 : struct ndr_syntax_id_buf id_buf;
85 :
86 1430 : fprintf(f,
87 : "%s %s\n",
88 : ndr_syntax_id_buf_string(&t->syntax_id, &id_buf),
89 1430 : t->name);
90 :
91 5031 : for (i=0; i<endpoints->count; i++) {
92 3601 : fprintf(f, " %s\n", endpoints->names[i]);
93 : }
94 1430 : }
95 :
96 36694 : static NTSTATUS rpc_worker_report_status(struct rpc_worker *worker)
97 : {
98 : uint8_t buf[16];
99 36694 : DATA_BLOB blob = { .data = buf, .length = sizeof(buf), };
100 : enum ndr_err_code ndr_err;
101 : NTSTATUS status;
102 :
103 36694 : worker->status.num_association_groups = worker->dce_ctx->assoc_groups_num;
104 :
105 36694 : if (DEBUGLEVEL >= 10) {
106 0 : NDR_PRINT_DEBUG(rpc_worker_status, &worker->status);
107 : }
108 :
109 36694 : ndr_err = ndr_push_struct_into_fixed_blob(
110 : &blob,
111 36694 : &worker->status,
112 : (ndr_push_flags_fn_t)ndr_push_rpc_worker_status);
113 36694 : SMB_ASSERT(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
114 :
115 36694 : status = messaging_send(
116 : worker->msg_ctx,
117 : worker->rpc_host_pid,
118 : MSG_RPC_WORKER_STATUS,
119 : &blob);
120 36694 : return status;
121 : }
122 :
123 36123 : static void rpc_worker_connection_terminated(
124 : struct dcesrv_connection *conn, void *private_data)
125 : {
126 36123 : struct rpc_worker *worker = talloc_get_type_abort(
127 : private_data, struct rpc_worker);
128 36123 : struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
129 : conn->transport.private_data, struct dcerpc_ncacn_conn);
130 36123 : struct dcerpc_ncacn_conn *w = NULL;
131 : NTSTATUS status;
132 36123 : bool found = false;
133 :
134 : /*
135 : * We need to drop the association group reference
136 : * explicitly here in order to avoid the order given
137 : * by the destructors. rpc_worker_report_status() below,
138 : * expects worker->dce_ctx->assoc_groups_num to be updated
139 : * already.
140 : */
141 36123 : if (conn->assoc_group != NULL) {
142 36115 : talloc_unlink(conn, conn->assoc_group);
143 36115 : conn->assoc_group = NULL;
144 : }
145 :
146 36123 : SMB_ASSERT(worker->status.num_connections > 0);
147 :
148 36323 : for (w = worker->conns; w != NULL; w = w->next) {
149 36323 : if (w == ncacn_conn) {
150 36123 : found = true;
151 36123 : break;
152 : }
153 : }
154 36123 : SMB_ASSERT(found);
155 :
156 36123 : DLIST_REMOVE(worker->conns, ncacn_conn);
157 :
158 36123 : worker->status.num_connections -= 1;
159 :
160 36123 : status = rpc_worker_report_status(worker);
161 36123 : if (!NT_STATUS_IS_OK(status)) {
162 0 : DBG_DEBUG("rpc_worker_report_status returned %s\n",
163 : nt_errstr(status));
164 : }
165 36123 : }
166 :
167 36123 : static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
168 : {
169 36123 : struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
170 : conn->transport.private_data,
171 : struct dcerpc_ncacn_conn);
172 :
173 36123 : if (ncacn_conn->termination_fn != NULL) {
174 36123 : ncacn_conn->termination_fn(conn, ncacn_conn->termination_data);
175 : }
176 :
177 36123 : return 0;
178 : }
179 :
180 : /*
181 : * A new client has been passed to us from samba-dcerpcd.
182 : */
183 36127 : static void rpc_worker_new_client(
184 : struct rpc_worker *worker,
185 : struct rpc_host_client *client,
186 : int sock)
187 : {
188 36127 : struct dcesrv_context *dce_ctx = worker->dce_ctx;
189 36127 : struct named_pipe_auth_req_info8 *info8 = client->npa_info8;
190 36127 : struct tsocket_address *remote_client_addr = NULL;
191 36127 : struct tsocket_address *local_server_addr = NULL;
192 36127 : struct dcerpc_binding *b = NULL;
193 : enum dcerpc_transport_t transport;
194 36127 : struct dcesrv_endpoint *ep = NULL;
195 36127 : struct tstream_context *tstream = NULL;
196 36127 : struct dcerpc_ncacn_conn *ncacn_conn = NULL;
197 36127 : struct dcesrv_connection *dcesrv_conn = NULL;
198 36127 : DATA_BLOB buffer = { .data = NULL };
199 36127 : struct ncacn_packet *pkt = NULL;
200 36127 : struct security_token *token = NULL;
201 : uint32_t npa_flags, state_flags;
202 : bool found_npa_flags;
203 : NTSTATUS status;
204 : int ret;
205 :
206 36127 : DBG_DEBUG("Got new conn sock %d for binding %s\n",
207 : sock,
208 : client->binding);
209 :
210 36127 : status = dcerpc_parse_binding(client, client->binding, &b);
211 36127 : if (!NT_STATUS_IS_OK(status)) {
212 0 : DBG_DEBUG("dcerpc_parse_binding(%s) failed: %s\n",
213 : client->binding,
214 : nt_errstr(status));
215 0 : goto fail;
216 : }
217 36127 : transport = dcerpc_binding_get_transport(b);
218 :
219 36127 : status = dcesrv_find_endpoint(dce_ctx, b, &ep);
220 :
221 36127 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) &&
222 150 : ((transport == NCACN_IP_TCP) || (transport == NCALRPC)) &&
223 150 : (dcerpc_binding_get_string_option(b, "endpoint") != NULL)) {
224 : /*
225 : * We have two kinds of servers: Those who explicitly
226 : * bind to a port (e.g. 135 for epmapper) and those
227 : * who just specify a transport. The client specified
228 : * a port (or socket name), but we did not find this
229 : * in the list of servers having specified a
230 : * port. Retry just matching for the transport,
231 : * catching the servers that did not explicitly
232 : * specify a port.
233 : *
234 : * This is not fully correct, what we should do is
235 : * that once the port the server listens on has been
236 : * finalized we should mark this in the server list,
237 : * but for now it works. We don't have the same RPC
238 : * interface listening twice on different ports.
239 : */
240 150 : struct dcerpc_binding *b_without_port = dcerpc_binding_dup(
241 : client, b);
242 150 : if (b_without_port == NULL) {
243 0 : status = NT_STATUS_NO_MEMORY;
244 0 : goto fail;
245 : }
246 :
247 150 : status = dcerpc_binding_set_string_option(
248 : b_without_port, "endpoint", NULL);
249 150 : if (!NT_STATUS_IS_OK(status)) {
250 0 : DBG_DEBUG("Could not delete endpoint: %s\n",
251 : nt_errstr(status));
252 0 : TALLOC_FREE(b_without_port);
253 0 : goto fail;
254 : }
255 :
256 150 : status = dcesrv_find_endpoint(dce_ctx, b_without_port, &ep);
257 :
258 150 : TALLOC_FREE(b_without_port);
259 : }
260 :
261 36127 : if (!NT_STATUS_IS_OK(status)) {
262 0 : DBG_DEBUG("Could not find endpoint for %s: %s\n",
263 : client->binding,
264 : nt_errstr(status));
265 0 : goto fail;
266 : }
267 :
268 36127 : ncacn_conn = talloc(dce_ctx, struct dcerpc_ncacn_conn);
269 36127 : if (ncacn_conn == NULL) {
270 0 : DBG_DEBUG("talloc failed\n");
271 0 : goto fail;
272 : }
273 36127 : *ncacn_conn = (struct dcerpc_ncacn_conn) {
274 : .endpoint = ep,
275 : .sock = sock,
276 : .termination_fn = rpc_worker_connection_terminated,
277 : .termination_data = worker,
278 : };
279 :
280 36127 : if (transport == NCALRPC) {
281 134 : ret = tsocket_address_unix_from_path(ncacn_conn,
282 : info8->remote_client_addr,
283 : &remote_client_addr);
284 134 : if (ret == -1) {
285 0 : DBG_DEBUG("tsocket_address_unix_from_path"
286 : "(%s) failed: %s\n",
287 : info8->remote_client_addr,
288 : strerror(errno));
289 0 : goto fail;
290 : }
291 :
292 134 : ncacn_conn->remote_client_name =
293 134 : talloc_strdup(ncacn_conn, info8->remote_client_name);
294 134 : if (ncacn_conn->remote_client_name == NULL) {
295 0 : DBG_DEBUG("talloc_strdup(%s) failed\n",
296 : info8->remote_client_name);
297 0 : goto fail;
298 : }
299 :
300 134 : ret = tsocket_address_unix_from_path(ncacn_conn,
301 : info8->local_server_addr,
302 : &local_server_addr);
303 134 : if (ret == -1) {
304 0 : DBG_DEBUG("tsocket_address_unix_from_path"
305 : "(%s) failed: %s\n",
306 : info8->local_server_addr,
307 : strerror(errno));
308 0 : goto fail;
309 : }
310 :
311 134 : ncacn_conn->local_server_name =
312 134 : talloc_strdup(ncacn_conn, info8->local_server_name);
313 134 : if (ncacn_conn->local_server_name == NULL) {
314 0 : DBG_DEBUG("talloc_strdup(%s) failed\n",
315 : info8->local_server_name);
316 0 : goto fail;
317 : }
318 : } else {
319 35993 : ret = tsocket_address_inet_from_strings(
320 : ncacn_conn,
321 : "ip",
322 : info8->remote_client_addr,
323 : info8->remote_client_port,
324 : &remote_client_addr);
325 35993 : if (ret == -1) {
326 0 : DBG_DEBUG("tsocket_address_inet_from_strings"
327 : "(%s, %" PRIu16 ") failed: %s\n",
328 : info8->remote_client_addr,
329 : info8->remote_client_port,
330 : strerror(errno));
331 0 : goto fail;
332 : }
333 35993 : ncacn_conn->remote_client_name =
334 35993 : talloc_strdup(ncacn_conn, info8->remote_client_name);
335 35993 : if (ncacn_conn->remote_client_name == NULL) {
336 0 : DBG_DEBUG("talloc_strdup(%s) failed\n",
337 : info8->remote_client_name);
338 0 : goto fail;
339 : }
340 :
341 35993 : ret = tsocket_address_inet_from_strings(
342 : ncacn_conn,
343 : "ip",
344 : info8->local_server_addr,
345 : info8->local_server_port,
346 : &local_server_addr);
347 35993 : if (ret == -1) {
348 0 : DBG_DEBUG("tsocket_address_inet_from_strings"
349 : "(%s, %" PRIu16 ") failed: %s\n",
350 : info8->local_server_addr,
351 : info8->local_server_port,
352 : strerror(errno));
353 0 : goto fail;
354 : }
355 35993 : ncacn_conn->local_server_name =
356 35993 : talloc_strdup(ncacn_conn, info8->local_server_name);
357 35993 : if (ncacn_conn->local_server_name == NULL) {
358 0 : DBG_DEBUG("talloc_strdup(%s) failed\n",
359 : info8->local_server_name);
360 0 : goto fail;
361 : }
362 : }
363 :
364 36127 : if (transport == NCACN_NP) {
365 35217 : ret = tstream_npa_existing_socket(
366 : ncacn_conn,
367 : sock,
368 : FILE_TYPE_MESSAGE_MODE_PIPE,
369 : &tstream);
370 35217 : if (ret == -1) {
371 0 : DBG_DEBUG("tstream_npa_existing_socket failed: %s\n",
372 : strerror(errno));
373 0 : goto fail;
374 : }
375 :
376 : /*
377 : * "transport" so far is implicitly assigned by the
378 : * socket that the client connected to, passed in from
379 : * samba-dcerpcd via the binding. For NCACN_NP (root
380 : * only by unix permissions) we got a
381 : * named_pipe_auth_req_info8 where the transport can
382 : * be overridden.
383 : */
384 35217 : transport = info8->transport;
385 : } else {
386 910 : ret = tstream_bsd_existing_socket(
387 : ncacn_conn, sock, &tstream);
388 910 : if (ret == -1) {
389 0 : DBG_DEBUG("tstream_bsd_existing_socket failed: %s\n",
390 : strerror(errno));
391 0 : goto fail;
392 : }
393 : /* as server we want to fail early */
394 910 : tstream_bsd_fail_readv_first_error(tstream, true);
395 : }
396 36127 : sock = -1;
397 :
398 36127 : token = info8->session_info->session_info->security_token;
399 :
400 36127 : if (security_token_is_system(token) && (transport != NCALRPC)) {
401 0 : DBG_DEBUG("System token only allowed on NCALRPC\n");
402 0 : goto fail;
403 : }
404 :
405 36127 : state_flags = DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
406 :
407 36127 : found_npa_flags = security_token_find_npa_flags(token, &npa_flags);
408 36127 : if (found_npa_flags) {
409 35217 : if (npa_flags & SAMBA_NPA_FLAGS_WINBIND_OFF) {
410 268 : state_flags |=
411 : DCESRV_CALL_STATE_FLAG_WINBIND_OFF;
412 : }
413 :
414 : /*
415 : * Delete the flags so that we don't bail in
416 : * local_np_connect_send() on subsequent
417 : * connects. Once we connect to another RPC service, a
418 : * new flags sid will be added if required.
419 : */
420 35217 : security_token_del_npa_flags(token);
421 : }
422 :
423 36127 : ncacn_conn->p.msg_ctx = global_messaging_context();
424 36127 : ncacn_conn->p.transport = transport;
425 :
426 36127 : status = dcesrv_endpoint_connect(dce_ctx,
427 : ncacn_conn,
428 : ep,
429 36127 : info8->session_info->session_info,
430 : global_event_context(),
431 : state_flags,
432 : &dcesrv_conn);
433 36127 : if (!NT_STATUS_IS_OK(status)) {
434 0 : DBG_DEBUG("Failed to connect to endpoint: %s\n",
435 : nt_errstr(status));
436 0 : goto fail;
437 : }
438 :
439 36127 : talloc_set_destructor(dcesrv_conn, dcesrv_connection_destructor);
440 :
441 36127 : dcesrv_conn->transport.private_data = ncacn_conn;
442 36127 : dcesrv_conn->transport.report_output_data =
443 : dcesrv_sock_report_output_data;
444 36127 : dcesrv_conn->transport.terminate_connection =
445 : dcesrv_transport_terminate_connection;
446 :
447 36127 : dcesrv_conn->send_queue = tevent_queue_create(
448 : dcesrv_conn, "dcesrv send queue");
449 36127 : if (dcesrv_conn->send_queue == NULL) {
450 0 : DBG_DEBUG("tevent_queue_create failed\n");
451 0 : goto fail;
452 : }
453 :
454 36127 : dcesrv_conn->stream = talloc_move(dcesrv_conn, &tstream);
455 72254 : dcesrv_conn->local_address =
456 36127 : talloc_move(dcesrv_conn, &local_server_addr);
457 72254 : dcesrv_conn->remote_address =
458 36127 : talloc_move(dcesrv_conn, &remote_client_addr);
459 :
460 36127 : if (client->bind_packet.length == 0) {
461 0 : DBG_DEBUG("Expected bind packet\n");
462 0 : goto fail;
463 : }
464 :
465 36127 : buffer = (DATA_BLOB) {
466 36127 : .data = talloc_move(dcesrv_conn, &client->bind_packet.data),
467 36127 : .length = client->bind_packet.length,
468 : };
469 :
470 36127 : pkt = talloc(dcesrv_conn, struct ncacn_packet);
471 36127 : if (pkt == NULL) {
472 0 : DBG_DEBUG("talloc failed\n");
473 0 : goto fail;
474 : }
475 :
476 36127 : status = dcerpc_pull_ncacn_packet(pkt, &buffer, pkt);
477 36127 : if (!NT_STATUS_IS_OK(status)) {
478 0 : DBG_DEBUG("dcerpc_pull_ncacn_packet failed: %s\n",
479 : nt_errstr(status));
480 0 : goto fail;
481 : }
482 :
483 36127 : TALLOC_FREE(client);
484 :
485 36127 : DLIST_ADD(worker->conns, ncacn_conn);
486 36127 : worker->status.num_connections += 1;
487 :
488 36127 : dcesrv_loop_next_packet(dcesrv_conn, pkt, buffer);
489 :
490 36127 : return;
491 0 : fail:
492 0 : TALLOC_FREE(ncacn_conn);
493 0 : TALLOC_FREE(dcesrv_conn);
494 0 : TALLOC_FREE(client);
495 0 : if (sock != -1) {
496 0 : close(sock);
497 : }
498 :
499 : /*
500 : * Parent thinks it successfully sent us a client. Tell it
501 : * that we declined.
502 : */
503 0 : status = rpc_worker_report_status(worker);
504 0 : if (!NT_STATUS_IS_OK(status)) {
505 0 : DBG_DEBUG("rpc_worker_report_status returned %s\n",
506 : nt_errstr(status));
507 : }
508 : }
509 :
510 : /*
511 : * New client message processing.
512 : */
513 40092 : static bool rpc_worker_new_client_filter(
514 : struct messaging_rec *rec, void *private_data)
515 : {
516 40092 : struct rpc_worker *worker = talloc_get_type_abort(
517 : private_data, struct rpc_worker);
518 40092 : struct dcesrv_context *dce_ctx = worker->dce_ctx;
519 40092 : struct rpc_host_client *client = NULL;
520 : enum ndr_err_code ndr_err;
521 : int sock;
522 :
523 40092 : if (rec->msg_type != MSG_RPC_HOST_NEW_CLIENT) {
524 3965 : return false;
525 : }
526 :
527 36127 : if (rec->num_fds != 1) {
528 0 : DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
529 0 : return false;
530 : }
531 :
532 36127 : client = talloc(dce_ctx, struct rpc_host_client);
533 36127 : if (client == NULL) {
534 0 : DBG_DEBUG("talloc failed\n");
535 0 : return false;
536 : }
537 :
538 36127 : ndr_err = ndr_pull_struct_blob_all(
539 36127 : &rec->buf,
540 : client,
541 : client,
542 : (ndr_pull_flags_fn_t)ndr_pull_rpc_host_client);
543 36127 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
544 0 : DBG_DEBUG("ndr_pull_rpc_host_client failed: %s\n",
545 : ndr_errstr(ndr_err));
546 0 : TALLOC_FREE(client);
547 0 : return false;
548 : }
549 :
550 36127 : if (DEBUGLEVEL >= 10) {
551 0 : NDR_PRINT_DEBUG(rpc_host_client, client);
552 : }
553 :
554 36127 : sock = rec->fds[0];
555 36127 : rec->fds[0] = -1;
556 :
557 36127 : rpc_worker_new_client(worker, client, sock);
558 :
559 36127 : return false;
560 : }
561 :
562 : /*
563 : * Return your status message processing.
564 : */
565 40092 : static bool rpc_worker_status_filter(
566 : struct messaging_rec *rec, void *private_data)
567 : {
568 40092 : struct rpc_worker *worker = talloc_get_type_abort(
569 : private_data, struct rpc_worker);
570 40092 : struct dcerpc_ncacn_conn *conn = NULL;
571 40092 : FILE *f = NULL;
572 : int fd;
573 :
574 40092 : if (rec->msg_type != MSG_RPC_DUMP_STATUS) {
575 40092 : return false;
576 : }
577 :
578 0 : if (rec->num_fds != 1) {
579 0 : DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
580 0 : return false;
581 : }
582 :
583 0 : fd = dup(rec->fds[0]);
584 0 : if (fd == -1) {
585 0 : DBG_DEBUG("dup(%"PRIi64") failed: %s\n",
586 : rec->fds[0],
587 : strerror(errno));
588 0 : return false;
589 : }
590 :
591 0 : f = fdopen(fd, "w");
592 0 : if (f == NULL) {
593 0 : DBG_DEBUG("fdopen failed: %s\n", strerror(errno));
594 0 : close(fd);
595 0 : return false;
596 : }
597 :
598 0 : for (conn = worker->conns; conn != NULL; conn = conn->next) {
599 0 : char *endpoint = NULL;
600 :
601 0 : endpoint = dcerpc_binding_string(
602 0 : conn, conn->endpoint->ep_description);
603 :
604 0 : fprintf(f,
605 : "endpoint=%s client=%s server=%s\n",
606 : endpoint ? endpoint : "UNKNOWN",
607 : conn->remote_client_name,
608 : conn->local_server_name);
609 0 : TALLOC_FREE(endpoint);
610 : }
611 :
612 0 : fclose(f);
613 :
614 0 : return false;
615 : }
616 :
617 : /*
618 : take a reference to an existing association group
619 : */
620 26 : static struct dcesrv_assoc_group *rpc_worker_assoc_group_reference(
621 : struct dcesrv_connection *conn,
622 : uint32_t id)
623 : {
624 26 : const struct dcesrv_endpoint *endpoint = conn->endpoint;
625 26 : enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
626 26 : endpoint->ep_description);
627 26 : struct dcesrv_assoc_group *assoc_group = NULL;
628 26 : void *id_ptr = NULL;
629 :
630 : /* find an association group given a assoc_group_id */
631 26 : id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, id & UINT16_MAX);
632 26 : if (id_ptr == NULL) {
633 6 : DBG_NOTICE("Failed to find assoc_group 0x%08x\n", id);
634 6 : return NULL;
635 : }
636 20 : assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
637 :
638 20 : if (assoc_group->transport != transport) {
639 0 : const char *at = derpc_transport_string_by_transport(
640 : assoc_group->transport);
641 0 : const char *ct = derpc_transport_string_by_transport(
642 : transport);
643 :
644 0 : DBG_NOTICE("assoc_group 0x%08x (transport %s) "
645 : "is not available on transport %s\n",
646 : id, at, ct);
647 0 : return NULL;
648 : }
649 :
650 : /*
651 : * Yes, this is a talloc_reference: The assoc group must be
652 : * removed when all connections go. This should be replaced by
653 : * adding a linked list of dcesrv_connection structs to the
654 : * assoc group.
655 : */
656 20 : return talloc_reference(conn, assoc_group);
657 : }
658 :
659 36095 : static int rpc_worker_assoc_group_destructor(
660 : struct dcesrv_assoc_group *assoc_group)
661 : {
662 : int ret;
663 :
664 36095 : ret = idr_remove(
665 36095 : assoc_group->dce_ctx->assoc_groups_idr,
666 36095 : assoc_group->id & UINT16_MAX);
667 36095 : if (ret != 0) {
668 0 : DBG_WARNING("Failed to remove assoc_group 0x%08x\n",
669 : assoc_group->id);
670 : }
671 :
672 36095 : SMB_ASSERT(assoc_group->dce_ctx->assoc_groups_num > 0);
673 36095 : assoc_group->dce_ctx->assoc_groups_num -= 1;
674 36095 : return 0;
675 : }
676 :
677 : /*
678 : allocate a new association group
679 : */
680 36099 : static struct dcesrv_assoc_group *rpc_worker_assoc_group_new(
681 : struct dcesrv_connection *conn, uint16_t worker_index)
682 : {
683 36099 : struct dcesrv_context *dce_ctx = conn->dce_ctx;
684 36099 : const struct dcesrv_endpoint *endpoint = conn->endpoint;
685 36099 : enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
686 36099 : endpoint->ep_description);
687 36099 : struct dcesrv_assoc_group *assoc_group = NULL;
688 : int id;
689 :
690 36099 : assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
691 36099 : if (assoc_group == NULL) {
692 0 : return NULL;
693 : }
694 :
695 : /*
696 : * We use 16-bit to encode the worker index,
697 : * have 16-bits left within the worker to form a
698 : * 32-bit association group id.
699 : */
700 36099 : id = idr_get_new_random(
701 : dce_ctx->assoc_groups_idr, assoc_group, 1, UINT16_MAX);
702 36099 : if (id == -1) {
703 0 : talloc_free(assoc_group);
704 0 : DBG_WARNING("Out of association groups!\n");
705 0 : return NULL;
706 : }
707 36099 : assoc_group->id = (((uint32_t)worker_index) << 16) | id;
708 36099 : assoc_group->transport = transport;
709 36099 : assoc_group->dce_ctx = dce_ctx;
710 :
711 36099 : talloc_set_destructor(assoc_group, rpc_worker_assoc_group_destructor);
712 :
713 36099 : SMB_ASSERT(dce_ctx->assoc_groups_num < UINT16_MAX);
714 36099 : dce_ctx->assoc_groups_num += 1;
715 :
716 36099 : return assoc_group;
717 : }
718 :
719 36125 : static NTSTATUS rpc_worker_assoc_group_find(
720 : struct dcesrv_call_state *call,
721 : void *private_data)
722 : {
723 36125 : struct rpc_worker *w = talloc_get_type_abort(
724 : private_data, struct rpc_worker);
725 36125 : uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
726 :
727 36125 : if (assoc_group_id != 0) {
728 26 : uint16_t worker_index = (assoc_group_id & 0xffff0000) >> 16;
729 26 : if (worker_index != w->status.worker_index) {
730 0 : DBG_DEBUG("Wrong worker id %"PRIu16", "
731 : "expected %"PRIu32"\n",
732 : worker_index,
733 : w->status.worker_index);
734 0 : return NT_STATUS_NOT_FOUND;
735 : }
736 26 : call->conn->assoc_group = rpc_worker_assoc_group_reference(
737 : call->conn, assoc_group_id);
738 : } else {
739 36099 : call->conn->assoc_group = rpc_worker_assoc_group_new(
740 36099 : call->conn, w->status.worker_index);
741 : }
742 :
743 36125 : if (call->conn->assoc_group == NULL) {
744 : /* TODO Return correct status */
745 6 : return NT_STATUS_UNSUCCESSFUL;
746 : }
747 :
748 36119 : return NT_STATUS_OK;
749 : }
750 :
751 571 : static struct rpc_worker *rpc_worker_new(
752 : TALLOC_CTX *mem_ctx,
753 : struct messaging_context *msg_ctx)
754 : {
755 571 : struct rpc_worker *worker = NULL;
756 :
757 571 : worker = talloc_zero(mem_ctx, struct rpc_worker);
758 571 : if (worker == NULL) {
759 0 : return NULL;
760 : }
761 :
762 571 : worker->rpc_host_pid = (struct server_id) { .pid = 0 };
763 571 : worker->msg_ctx = msg_ctx;
764 :
765 571 : worker->cb = (struct dcesrv_context_callbacks) {
766 : .log.successful_authz = dcesrv_log_successful_authz,
767 : .auth.gensec_prepare = dcesrv_auth_gensec_prepare,
768 : .auth.become_root = become_root,
769 : .auth.unbecome_root = unbecome_root,
770 : .assoc_group.find = rpc_worker_assoc_group_find,
771 : .assoc_group.private_data = worker,
772 : };
773 :
774 571 : worker->dce_ctx = global_dcesrv_context();
775 571 : if (worker->dce_ctx == NULL) {
776 0 : goto fail;
777 : }
778 571 : dcesrv_context_set_callbacks(worker->dce_ctx, &worker->cb);
779 :
780 571 : return worker;
781 0 : fail:
782 0 : TALLOC_FREE(worker);
783 0 : return NULL;
784 : }
785 :
786 571 : static struct dcesrv_context *rpc_worker_dce_ctx(struct rpc_worker *w)
787 : {
788 571 : return w->dce_ctx;
789 : }
790 :
791 : struct rpc_worker_state {
792 : struct tevent_context *ev;
793 : struct rpc_worker *w;
794 : struct tevent_req *new_client_req;
795 : struct tevent_req *status_req;
796 : struct tevent_req *finish_req;
797 : };
798 :
799 : static void rpc_worker_done(struct tevent_req *subreq);
800 : static void rpc_worker_shutdown(
801 : struct messaging_context *msg,
802 : void *private_data,
803 : uint32_t msg_type,
804 : struct server_id server_id,
805 : DATA_BLOB *data);
806 :
807 571 : static struct tevent_req *rpc_worker_send(
808 : TALLOC_CTX *mem_ctx,
809 : struct tevent_context *ev,
810 : struct rpc_worker *w,
811 : pid_t rpc_host_pid,
812 : int server_index,
813 : int worker_index)
814 : {
815 571 : struct tevent_req *req = NULL;
816 571 : struct rpc_worker_state *state = NULL;
817 : NTSTATUS status;
818 :
819 571 : req = tevent_req_create(mem_ctx, &state, struct rpc_worker_state);
820 571 : if (req == NULL) {
821 0 : return NULL;
822 : }
823 571 : state->ev = ev;
824 571 : state->w = w;
825 :
826 571 : if ((server_index < 0) || ((unsigned)server_index > UINT32_MAX)) {
827 0 : DBG_ERR("Invalid server index %d\n", server_index);
828 0 : tevent_req_error(req, EINVAL);
829 0 : return tevent_req_post(req, ev);
830 : }
831 571 : if ((worker_index < 0) || ((unsigned)worker_index > UINT16_MAX)) {
832 0 : DBG_ERR("Invalid worker index %d\n", worker_index);
833 0 : tevent_req_error(req, EINVAL);
834 0 : return tevent_req_post(req, ev);
835 : }
836 571 : w->rpc_host_pid = pid_to_procid(rpc_host_pid);
837 :
838 571 : w->status = (struct rpc_worker_status) {
839 : .server_index = server_index,
840 : .worker_index = worker_index,
841 : };
842 :
843 : /* Wait for new client messages. */
844 571 : state->new_client_req = messaging_filtered_read_send(
845 : w,
846 : messaging_tevent_context(w->msg_ctx),
847 : w->msg_ctx,
848 : rpc_worker_new_client_filter,
849 : w);
850 571 : if (tevent_req_nomem(state->new_client_req, req)) {
851 0 : return tevent_req_post(req, ev);
852 : }
853 :
854 : /* Wait for report your status messages. */
855 571 : state->status_req = messaging_filtered_read_send(
856 : w,
857 : messaging_tevent_context(w->msg_ctx),
858 : w->msg_ctx,
859 : rpc_worker_status_filter,
860 : w);
861 571 : if (tevent_req_nomem(state->status_req, req)) {
862 0 : return tevent_req_post(req, ev);
863 : }
864 :
865 : /* Wait for shutdown messages. */
866 571 : status = messaging_register(
867 : w->msg_ctx, req, MSG_SHUTDOWN, rpc_worker_shutdown);
868 571 : if (!NT_STATUS_IS_OK(status)) {
869 0 : DBG_DEBUG("messaging_register failed: %s\n",
870 : nt_errstr(status));
871 0 : tevent_req_error(req, map_errno_from_nt_status(status));
872 0 : return tevent_req_post(req, ev);
873 : }
874 :
875 571 : state->finish_req = wait_for_read_send(state, ev, 0, false);
876 571 : if (tevent_req_nomem(state->finish_req, req)) {
877 0 : return tevent_req_post(req, ev);
878 : }
879 571 : tevent_req_set_callback(state->finish_req, rpc_worker_done, req);
880 :
881 571 : rpc_worker_report_status(w);
882 :
883 571 : return req;
884 : }
885 :
886 52 : static void rpc_worker_done(struct tevent_req *subreq)
887 : {
888 52 : struct tevent_req *req = tevent_req_callback_data(
889 : subreq, struct tevent_req);
890 52 : int err = 0;
891 : bool ok;
892 :
893 52 : ok = wait_for_read_recv(subreq, &err);
894 52 : TALLOC_FREE(subreq);
895 52 : if (!ok) {
896 0 : tevent_req_error(req, err);
897 0 : return;
898 : }
899 52 : tevent_req_done(req);
900 : }
901 :
902 519 : static void rpc_worker_shutdown(
903 : struct messaging_context *msg,
904 : void *private_data,
905 : uint32_t msg_type,
906 : struct server_id server_id,
907 : DATA_BLOB *data)
908 : {
909 519 : struct tevent_req *req = talloc_get_type_abort(
910 : private_data, struct tevent_req);
911 519 : tevent_req_done(req);
912 519 : }
913 :
914 571 : static int rpc_worker_recv(struct tevent_req *req)
915 : {
916 571 : return tevent_req_simple_recv_unix(req);
917 : }
918 :
919 0 : static void sig_term_handler(
920 : struct tevent_context *ev,
921 : struct tevent_signal *se,
922 : int signum,
923 : int count,
924 : void *siginfo,
925 : void *private_data)
926 : {
927 0 : exit(0);
928 : }
929 :
930 0 : static void sig_hup_handler(
931 : struct tevent_context *ev,
932 : struct tevent_signal *se,
933 : int signum,
934 : int count,
935 : void *siginfo,
936 : void *private_data)
937 : {
938 0 : change_to_root_user();
939 0 : lp_load_with_shares(get_dyn_CONFIGFILE());
940 0 : }
941 :
942 1813 : static NTSTATUS register_ep_server(
943 : struct dcesrv_context *dce_ctx,
944 : const struct dcesrv_endpoint_server *ep_server)
945 : {
946 : NTSTATUS status;
947 :
948 1813 : DBG_DEBUG("Registering server %s\n", ep_server->name);
949 :
950 1813 : status = dcerpc_register_ep_server(ep_server);
951 1813 : if (!NT_STATUS_IS_OK(status) &&
952 0 : !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
953 0 : DBG_ERR("Failed to register '%s' endpoint server: %s\n",
954 : ep_server->name,
955 : nt_errstr(status));
956 0 : return status;
957 : }
958 :
959 1813 : status = dcesrv_init_ep_server(dce_ctx, ep_server->name);
960 1813 : if (!NT_STATUS_IS_OK(status)) {
961 0 : DBG_ERR("dcesrv_init_ep_server(%s) failed: %s\n",
962 : ep_server->name,
963 : nt_errstr(status));
964 0 : return status;
965 : }
966 :
967 1813 : return NT_STATUS_OK;
968 : }
969 :
970 : /**
971 : * @brief Main function for RPC server implementations
972 : *
973 : * This function provides all that is necessary to run a RPC server
974 : * inside the samba-dcerpcd framework. Just pass argv and argc on to
975 : * this function.
976 : *
977 : * The get_interfaces() callback provides the information that is
978 : * passed to samba-dcerpcd via --list-interfaces, it should not do any
979 : * real RPC server initialization work. Quickly after this function is
980 : * called by rpc_worker_main, the process exits again. It should
981 : * return the number of interfaces provided.
982 : *
983 : * get_servers() is called when the process is about to do the real
984 : * work. So more heavy-weight initialization should happen here. It
985 : * should return NT_STATUS_OK and the number of server implementations provided.
986 : *
987 : * @param[in] argc argc from main()
988 : * @param[in] argv argv from main()
989 : * @param[in] get_interfaces List all interfaces that this server provides
990 : * @param[in] get_servers Provide the RPC server implementations
991 : * @param[in] private_data Passed to the callback functions
992 : * @return 0 It should never return except on successful process exit
993 : */
994 :
995 1339 : int rpc_worker_main(
996 : int argc,
997 : const char *argv[],
998 : const char *daemon_config_name,
999 : int num_workers,
1000 : int idle_seconds,
1001 : size_t (*get_interfaces)(
1002 : const struct ndr_interface_table ***ifaces,
1003 : void *private_data),
1004 : NTSTATUS (*get_servers)(
1005 : struct dcesrv_context *dce_ctx,
1006 : const struct dcesrv_endpoint_server ***ep_servers,
1007 : size_t *num_ep_servers,
1008 : void *private_data),
1009 : void *private_data)
1010 : {
1011 : const struct loadparm_substitution *lp_sub =
1012 1339 : loadparm_s3_global_substitution();
1013 1339 : const char *progname = getprogname();
1014 1339 : TALLOC_CTX *frame = NULL;
1015 1339 : struct tevent_context *ev_ctx = NULL;
1016 1339 : struct tevent_req *req = NULL;
1017 1339 : struct messaging_context *msg_ctx = NULL;
1018 1339 : struct dcesrv_context *dce_ctx = NULL;
1019 1339 : struct tevent_signal *se = NULL;
1020 : poptContext pc;
1021 : int opt;
1022 : NTSTATUS status;
1023 : int ret;
1024 1339 : int worker_group = -1;
1025 1339 : int worker_index = -1;
1026 : bool log_stdout;
1027 1339 : int list_interfaces = 0;
1028 1339 : struct rpc_worker *worker = NULL;
1029 : const struct dcesrv_endpoint_server **ep_servers;
1030 : size_t i, num_servers;
1031 : bool ok;
1032 :
1033 2678 : struct poptOption long_options[] = {
1034 : POPT_AUTOHELP
1035 : {
1036 : .longName = "list-interfaces",
1037 : .argInfo = POPT_ARG_NONE,
1038 : .arg = &list_interfaces,
1039 : .descrip = "List the interfaces provided",
1040 : },
1041 : {
1042 : .longName = "worker-group",
1043 : .argInfo = POPT_ARG_INT,
1044 : .arg = &worker_group,
1045 : .descrip = "Group index in status message",
1046 : },
1047 : {
1048 : .longName = "worker-index",
1049 : .argInfo = POPT_ARG_INT,
1050 : .arg = &worker_index,
1051 : .descrip = "Worker index in status message",
1052 : },
1053 1339 : POPT_COMMON_SAMBA
1054 : POPT_TABLEEND
1055 : };
1056 : static const struct smbd_shim smbd_shim_fns = {
1057 : .become_authenticated_pipe_user =
1058 : smbd_become_authenticated_pipe_user,
1059 : .unbecome_authenticated_pipe_user =
1060 : smbd_unbecome_authenticated_pipe_user,
1061 : .become_root = smbd_become_root,
1062 : .unbecome_root = smbd_unbecome_root,
1063 : };
1064 :
1065 1339 : closefrom(3);
1066 1339 : talloc_enable_null_tracking();
1067 1339 : frame = talloc_stackframe();
1068 1339 : umask(0);
1069 1339 : smb_init_locale();
1070 :
1071 1339 : ok = samba_cmdline_init(frame,
1072 : SAMBA_CMDLINE_CONFIG_SERVER,
1073 : true /* require_smbconf */);
1074 1339 : if (!ok) {
1075 0 : DBG_ERR("Failed to init cmdline parser!\n");
1076 0 : TALLOC_FREE(frame);
1077 0 : exit(ENOMEM);
1078 : }
1079 :
1080 1339 : pc = samba_popt_get_context(progname, argc, argv, long_options, 0);
1081 1339 : if (pc == NULL) {
1082 0 : DBG_ERR("Failed to setup popt context!\n");
1083 0 : TALLOC_FREE(frame);
1084 0 : exit(1);
1085 : }
1086 :
1087 1339 : while ((opt = poptGetNextOpt(pc)) != -1) {
1088 0 : d_fprintf(stderr,
1089 : "\nInvalid option %s: %s\n\n",
1090 : poptBadOption(pc, 0),
1091 : poptStrerror(opt));
1092 0 : poptPrintUsage(pc, stderr, 0);
1093 0 : TALLOC_FREE(frame);
1094 0 : exit(1);
1095 : };
1096 1339 : poptFreeContext(pc);
1097 :
1098 1339 : if (list_interfaces != 0) {
1099 768 : const struct ndr_interface_table **ifaces = NULL;
1100 : size_t num_ifaces;
1101 :
1102 768 : num_workers = lp_parm_int(
1103 : -1, daemon_config_name, "num_workers", num_workers);
1104 768 : idle_seconds = lp_parm_int(
1105 : -1, daemon_config_name, "idle_seconds", idle_seconds);
1106 :
1107 768 : DBG_DEBUG("daemon=%s, num_workers=%d, idle_seconds=%d\n",
1108 : daemon_config_name,
1109 : num_workers,
1110 : idle_seconds);
1111 :
1112 768 : fprintf(stdout, "%d\n%d\n", num_workers, idle_seconds);
1113 :
1114 768 : num_ifaces = get_interfaces(&ifaces, private_data);
1115 :
1116 2198 : for (i=0; i<num_ifaces; i++) {
1117 1430 : rpc_worker_print_interface(stdout, ifaces[i]);
1118 : }
1119 :
1120 768 : TALLOC_FREE(frame);
1121 768 : exit(0);
1122 : }
1123 :
1124 571 : log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
1125 571 : if (log_stdout != 0) {
1126 0 : setup_logging(argv[0], DEBUG_STDOUT);
1127 : } else {
1128 571 : setup_logging(argv[0], DEBUG_FILE);
1129 : }
1130 :
1131 571 : set_smbd_shim(&smbd_shim_fns);
1132 :
1133 571 : dump_core_setup(progname, lp_logfile(talloc_tos(), lp_sub));
1134 :
1135 : /* POSIX demands that signals are inherited. If the invoking
1136 : * process has these signals masked, we will have problems, as
1137 : * we won't receive them. */
1138 571 : BlockSignals(False, SIGHUP);
1139 571 : BlockSignals(False, SIGUSR1);
1140 571 : BlockSignals(False, SIGTERM);
1141 :
1142 : #if defined(SIGFPE)
1143 : /* we are never interested in SIGFPE */
1144 571 : BlockSignals(True,SIGFPE);
1145 : #endif
1146 : /* We no longer use USR2... */
1147 : #if defined(SIGUSR2)
1148 571 : BlockSignals(True, SIGUSR2);
1149 : #endif
1150 : /* Ignore children - no zombies. */
1151 571 : CatchChild();
1152 :
1153 571 : reopen_logs();
1154 :
1155 571 : DBG_STARTUP_NOTICE("%s version %s started.\n%s\n",
1156 : progname,
1157 : samba_version_string(),
1158 : samba_copyright_string());
1159 :
1160 571 : msg_ctx = global_messaging_context();
1161 571 : if (msg_ctx == NULL) {
1162 0 : DBG_ERR("global_messaging_context() failed\n");
1163 0 : TALLOC_FREE(frame);
1164 0 : exit(1);
1165 : }
1166 571 : ev_ctx = messaging_tevent_context(msg_ctx);
1167 :
1168 571 : worker = rpc_worker_new(ev_ctx, msg_ctx);
1169 571 : if (worker == NULL) {
1170 0 : DBG_ERR("rpc_worker_new failed\n");
1171 0 : global_messaging_context_free();
1172 0 : TALLOC_FREE(frame);
1173 0 : exit(1);
1174 : }
1175 571 : dce_ctx = rpc_worker_dce_ctx(worker);
1176 :
1177 571 : se = tevent_add_signal(
1178 : ev_ctx, ev_ctx, SIGTERM, 0, sig_term_handler, NULL);
1179 571 : if (se == NULL) {
1180 0 : DBG_ERR("tevent_add_signal failed\n");
1181 0 : global_messaging_context_free();
1182 0 : TALLOC_FREE(frame);
1183 0 : exit(1);
1184 : }
1185 571 : BlockSignals(false, SIGTERM);
1186 :
1187 571 : se = tevent_add_signal(
1188 : ev_ctx, ev_ctx, SIGHUP, 0, sig_hup_handler, NULL);
1189 571 : if (se == NULL) {
1190 0 : DBG_ERR("tevent_add_signal failed\n");
1191 0 : global_messaging_context_free();
1192 0 : TALLOC_FREE(frame);
1193 0 : exit(1);
1194 : }
1195 571 : BlockSignals(false, SIGHUP);
1196 :
1197 571 : (void)winbind_off();
1198 571 : ok = init_guest_session_info(NULL);
1199 571 : (void)winbind_on();
1200 571 : if (!ok) {
1201 0 : DBG_WARNING("init_guest_session_info failed\n");
1202 0 : global_messaging_context_free();
1203 0 : TALLOC_FREE(frame);
1204 0 : exit(1);
1205 : }
1206 :
1207 571 : status = init_system_session_info(NULL);
1208 571 : if (!NT_STATUS_IS_OK(status)) {
1209 0 : DBG_WARNING("init_system_session_info failed: %s\n",
1210 : nt_errstr(status));
1211 0 : global_messaging_context_free();
1212 0 : TALLOC_FREE(frame);
1213 0 : exit(1);
1214 : }
1215 :
1216 571 : DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
1217 :
1218 571 : status = get_servers(dce_ctx,
1219 : &ep_servers,
1220 : &num_servers,
1221 : private_data);
1222 571 : if (!NT_STATUS_IS_OK(status)) {
1223 0 : DBG_ERR("get_servers failed: %s\n", nt_errstr(status));
1224 0 : global_messaging_context_free();
1225 0 : TALLOC_FREE(frame);
1226 0 : exit(1);
1227 : }
1228 :
1229 571 : DBG_DEBUG("get_servers() returned %zu servers\n", num_servers);
1230 :
1231 2384 : for (i=0; i<num_servers; i++) {
1232 1813 : status = register_ep_server(dce_ctx, ep_servers[i]);
1233 1813 : if (!NT_STATUS_IS_OK(status)) {
1234 0 : DBG_ERR("register_ep_server failed: %s\n",
1235 : nt_errstr(status));
1236 0 : global_messaging_context_free();
1237 0 : TALLOC_FREE(frame);
1238 0 : exit(1);
1239 : }
1240 : }
1241 :
1242 571 : req = rpc_worker_send(
1243 : ev_ctx, ev_ctx, worker, getppid(), worker_group, worker_index);
1244 571 : if (req == NULL) {
1245 0 : DBG_ERR("rpc_worker_send failed\n");
1246 0 : global_messaging_context_free();
1247 0 : TALLOC_FREE(frame);
1248 0 : exit(1);
1249 : }
1250 :
1251 571 : DBG_DEBUG("%s worker running\n", progname);
1252 :
1253 2708078 : while (tevent_req_is_in_progress(req)) {
1254 2707507 : TALLOC_CTX *loop_frame = NULL;
1255 :
1256 2707507 : loop_frame = talloc_stackframe();
1257 :
1258 2707507 : ret = tevent_loop_once(ev_ctx);
1259 :
1260 2707507 : TALLOC_FREE(loop_frame);
1261 :
1262 2707507 : if (ret != 0) {
1263 0 : DBG_WARNING("tevent_req_once() failed: %s\n",
1264 : strerror(errno));
1265 0 : global_messaging_context_free();
1266 0 : TALLOC_FREE(frame);
1267 0 : exit(1);
1268 : }
1269 : }
1270 :
1271 571 : status = dcesrv_shutdown_registered_ep_servers(dce_ctx);
1272 571 : if (!NT_STATUS_IS_OK(status)) {
1273 0 : DBG_DEBUG("Shutdown failed with: %s\n",
1274 : nt_errstr(status));
1275 : }
1276 :
1277 571 : ret = rpc_worker_recv(req);
1278 571 : if (ret != 0) {
1279 0 : DBG_DEBUG("rpc_worker_recv returned %s\n", strerror(ret));
1280 0 : global_messaging_context_free();
1281 0 : TALLOC_FREE(frame);
1282 0 : exit(1);
1283 : }
1284 :
1285 571 : TALLOC_FREE(frame);
1286 571 : return 0;
1287 : }
|