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