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