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