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