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