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