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