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