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