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