s3:rpc_server: Activate samba-dcerpcd
[samba.git] / source3 / rpc_server / rpc_server.c
1 /*
2    Unix SMB/Netbios implementation.
3    Generic infrstructure for RPC Daemons
4    Copyright (C) Simo Sorce 2010
5    Copyright (C) Andrew Bartlett 2011
6    Copyright (C) Andreas Schneider 2011
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "librpc/rpc/dcesrv_core.h"
24 #include "rpc_server/rpc_pipes.h"
25 #include "rpc_server/rpc_server.h"
26 #include "rpc_server/rpc_config.h"
27 #include "rpc_dce.h"
28 #include "librpc/gen_ndr/netlogon.h"
29 #include "librpc/gen_ndr/auth.h"
30 #include "lib/tsocket/tsocket.h"
31 #include "libcli/named_pipe_auth/npa_tstream.h"
32 #include "../auth/auth_sam_reply.h"
33 #include "auth.h"
34 #include "rpc_server/rpc_ncacn_np.h"
35 #include "rpc_server/srv_pipe_hnd.h"
36
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_RPC_SRV
39
40 /* Start listening on the appropriate unix socket and setup all is needed to
41  * dispatch requests to the pipes rpc implementation */
42
43 struct dcerpc_ncacn_listen_state {
44         int fd;
45
46         struct tevent_context *ev_ctx;
47         struct messaging_context *msg_ctx;
48         struct dcesrv_context *dce_ctx;
49         struct dcesrv_endpoint *endpoint;
50         dcerpc_ncacn_termination_fn termination_fn;
51         void *termination_data;
52 };
53
54 #if 0
55 static void dcesrv_ncacn_listener(
56         struct tevent_context *ev,
57         struct tevent_fd *fde,
58         uint16_t flags,
59         void *private_data);
60
61 int dcesrv_setup_ncacn_listener(
62         TALLOC_CTX *mem_ctx,
63         struct dcesrv_context *dce_ctx,
64         struct tevent_context *ev_ctx,
65         struct messaging_context *msg_ctx,
66         struct dcesrv_endpoint *e,
67         int *fd,
68         dcerpc_ncacn_termination_fn term_fn,
69         void *termination_data,
70         struct dcerpc_ncacn_listen_state **listen_state)
71 {
72         struct dcerpc_ncacn_listen_state *state = NULL;
73         struct tevent_fd *fde = NULL;
74         int rc, err = ENOMEM;
75
76         state = talloc_zero(mem_ctx, struct dcerpc_ncacn_listen_state);
77         if (state == NULL) {
78                 DBG_ERR("Out of memory\n");
79                 return ENOMEM;
80         }
81
82         state->fd = *fd;
83         state->ev_ctx = ev_ctx;
84         state->msg_ctx = msg_ctx;
85         state->dce_ctx = dce_ctx;
86         state->endpoint = e;
87         state->termination_fn = term_fn;
88         state->termination_data = termination_data;
89
90         rc = listen(state->fd, SMBD_LISTEN_BACKLOG);
91         if (rc < 0) {
92                 err = errno;
93                 DBG_ERR("listen(%d) failed: %s\n",
94                         state->fd,
95                         strerror(err));
96                 goto fail;
97         }
98
99         /* Set server socket to non-blocking for the accept. */
100         rc = set_blocking(state->fd, false);
101         if (rc < 0) {
102                 err = errno;
103                 goto fail;
104         }
105
106         fde = tevent_add_fd(
107                 state->ev_ctx,
108                 state,
109                 state->fd,
110                 TEVENT_FD_READ,
111                 dcesrv_ncacn_listener,
112                 state);
113         if (fde == NULL) {
114                 err = errno;
115                 DBG_ERR("tevent_add_fd for %d failed: %s\n",
116                         state->fd,
117                         strerror(err));
118                 goto fail;
119         }
120         tevent_fd_set_auto_close(fde);
121         *fd = -1;
122
123         *listen_state = state;
124
125         return 0;
126
127 fail:
128         TALLOC_FREE(state);
129         return err;
130 }
131
132 static void dcesrv_ncacn_listener(
133         struct tevent_context *ev,
134         struct tevent_fd *fde,
135         uint16_t flags,
136         void *private_data)
137 {
138         struct dcerpc_ncacn_listen_state *state = talloc_get_type_abort(
139                 private_data, struct dcerpc_ncacn_listen_state);
140         struct tsocket_address *cli_addr = NULL, *srv_addr = NULL;
141         struct samba_sockaddr addr = {
142                 .sa_socklen = sizeof(struct samba_sockaddr),
143         };
144         int sd = -1;
145         int rc;
146
147         sd = accept(state->fd, &addr.u.sa, &addr.sa_socklen);
148         if (sd == -1) {
149                 if (errno != EINTR) {
150                         DBG_ERR("Failed to accept: %s\n", strerror(errno));
151                 }
152                 return;
153         }
154         smb_set_close_on_exec(sd);
155
156         rc = tsocket_address_bsd_from_samba_sockaddr(state, &addr, &cli_addr);
157         if (rc < 0) {
158                 goto fail;
159         }
160
161         rc = getsockname(sd, &addr.u.sa, &addr.sa_socklen);
162         if (rc < 0) {
163                 goto fail;
164         }
165
166         rc = tsocket_address_bsd_from_samba_sockaddr(state, &addr, &srv_addr);
167         if (rc < 0) {
168                 goto fail;
169         }
170
171         dcerpc_ncacn_accept(
172                 state->ev_ctx,
173                 state->msg_ctx,
174                 state->dce_ctx,
175                 state->endpoint,
176                 &cli_addr,
177                 &srv_addr,
178                 sd,
179                 state->termination_fn,
180                 state->termination_data);
181         return;
182
183 fail:
184         TALLOC_FREE(cli_addr);
185         TALLOC_FREE(srv_addr);
186         if (sd != -1) {
187                 close(sd);
188         }
189 }
190
191 static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
192 {
193         struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
194                         conn->transport.private_data,
195                         struct dcerpc_ncacn_conn);
196
197         if (ncacn_conn->termination_fn != NULL) {
198                 ncacn_conn->termination_fn(conn, ncacn_conn->termination_data);
199         }
200
201         return 0;
202 }
203 #endif
204
205 NTSTATUS dcerpc_ncacn_conn_init(TALLOC_CTX *mem_ctx,
206                                 struct tevent_context *ev_ctx,
207                                 struct messaging_context *msg_ctx,
208                                 struct dcesrv_context *dce_ctx,
209                                 struct dcesrv_endpoint *endpoint,
210                                 dcerpc_ncacn_termination_fn term_fn,
211                                 void *termination_data,
212                                 struct dcerpc_ncacn_conn **out)
213 {
214         struct dcerpc_ncacn_conn *ncacn_conn = NULL;
215
216         ncacn_conn = talloc_zero(mem_ctx, struct dcerpc_ncacn_conn);
217         if (ncacn_conn == NULL) {
218                 return NT_STATUS_NO_MEMORY;
219         }
220
221         ncacn_conn->ev_ctx = ev_ctx;
222         ncacn_conn->msg_ctx = msg_ctx;
223         ncacn_conn->dce_ctx = dce_ctx;
224         ncacn_conn->endpoint = endpoint;
225         ncacn_conn->sock = -1;
226         ncacn_conn->termination_fn = term_fn;
227         ncacn_conn->termination_data = termination_data;
228
229         *out = ncacn_conn;
230
231         return NT_STATUS_OK;
232 }
233
234 #if 0
235 static void dcesrv_ncacn_np_accept_done(struct tevent_req *subreq);
236 static void dcesrv_ncacn_accept_step2(struct dcerpc_ncacn_conn *ncacn_conn);
237 #endif
238
239 static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
240                                        const char *reason);
241
242 #if 0
243 void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
244                          struct messaging_context *msg_ctx,
245                          struct dcesrv_context *dce_ctx,
246                          struct dcesrv_endpoint *e,
247                          struct tsocket_address **cli_addr,
248                          struct tsocket_address **srv_addr,
249                          int s,
250                          dcerpc_ncacn_termination_fn termination_fn,
251                          void *termination_data)
252 {
253         enum dcerpc_transport_t transport =
254                 dcerpc_binding_get_transport(e->ep_description);
255         struct dcerpc_ncacn_conn *ncacn_conn;
256         NTSTATUS status;
257         int rc;
258
259         DBG_DEBUG("dcerpc_ncacn_accept\n");
260
261         status = dcerpc_ncacn_conn_init(ev_ctx,
262                                         ev_ctx,
263                                         msg_ctx,
264                                         dce_ctx,
265                                         e,
266                                         termination_fn,
267                                         termination_data,
268                                         &ncacn_conn);
269         if (!NT_STATUS_IS_OK(status)) {
270                 DBG_ERR("Failed to initialize dcerpc_ncacn_connection: %s\n",
271                         nt_errstr(status));
272                 close(s);
273                 return;
274         }
275
276         ncacn_conn->sock = s;
277
278         if ((cli_addr != NULL) && (*cli_addr != NULL)) {
279                 ncacn_conn->remote_client_addr = talloc_move(
280                         ncacn_conn, cli_addr);
281
282                 if (tsocket_address_is_inet(ncacn_conn->remote_client_addr, "ip")) {
283                         ncacn_conn->remote_client_name =
284                                 tsocket_address_inet_addr_string(ncacn_conn->remote_client_addr,
285                                                                  ncacn_conn);
286                 } else {
287                         ncacn_conn->remote_client_name =
288                                 tsocket_address_unix_path(ncacn_conn->remote_client_addr,
289                                                           ncacn_conn);
290                 }
291
292                 if (ncacn_conn->remote_client_name == NULL) {
293                         DBG_ERR("Out of memory obtaining remote socket address as a string!\n");
294                         ncacn_terminate_connection(ncacn_conn, "No memory");
295                         close(s);
296                         return;
297                 }
298         }
299
300         if ((srv_addr != NULL) && (*srv_addr != NULL))  {
301                 ncacn_conn->local_server_addr = talloc_move(
302                         ncacn_conn, srv_addr);
303
304                 if (tsocket_address_is_inet(ncacn_conn->local_server_addr, "ip")) {
305                         ncacn_conn->local_server_name =
306                                 tsocket_address_inet_addr_string(ncacn_conn->local_server_addr,
307                                                                  ncacn_conn);
308                 } else {
309                         ncacn_conn->local_server_name =
310                                 tsocket_address_unix_path(ncacn_conn->local_server_addr,
311                                                           ncacn_conn);
312                 }
313                 if (ncacn_conn->local_server_name == NULL) {
314                         DBG_ERR("No memory\n");
315                         ncacn_terminate_connection(ncacn_conn, "No memory");
316                         close(s);
317                         return;
318                 }
319         }
320
321         rc = set_blocking(s, false);
322         if (rc < 0) {
323                 DBG_WARNING("Failed to set dcerpc socket to non-blocking\n");
324                 ncacn_terminate_connection(ncacn_conn, strerror(errno));
325                 close(s);
326                 return;
327         }
328
329         /*
330          * As soon as we have tstream_bsd_existing_socket set up it will
331          * take care of closing the socket.
332          */
333         rc = tstream_bsd_existing_socket(ncacn_conn, s, &ncacn_conn->tstream);
334         if (rc < 0) {
335                 DBG_WARNING("Failed to create tstream socket for dcerpc\n");
336                 ncacn_terminate_connection(ncacn_conn, "No memory");
337                 close(s);
338                 return;
339         }
340
341         if (transport == NCACN_NP) {
342                 struct tevent_req *subreq = NULL;
343                 uint64_t allocation_size = 4096;
344                 uint16_t device_state = 0xff | 0x0400 | 0x0100;
345                 uint16_t file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
346
347                 subreq = tstream_npa_accept_existing_send(ncacn_conn,
348                                                           ncacn_conn->ev_ctx,
349                                                           ncacn_conn->tstream,
350                                                           file_type,
351                                                           device_state,
352                                                           allocation_size);
353                 if (subreq == NULL) {
354                         ncacn_terminate_connection(ncacn_conn, "No memory");
355                         return;
356                 }
357                 tevent_req_set_callback(subreq, dcesrv_ncacn_np_accept_done,
358                                         ncacn_conn);
359                 return;
360         }
361
362         dcesrv_ncacn_accept_step2(ncacn_conn);
363 }
364
365 static void dcesrv_ncacn_np_accept_done(struct tevent_req *subreq)
366 {
367         struct dcerpc_ncacn_conn *ncacn_conn = tevent_req_callback_data(
368                 subreq, struct dcerpc_ncacn_conn);
369         struct auth_session_info_transport *session_info_transport = NULL;
370         enum dcerpc_transport_t transport;
371         int error;
372         int ret;
373
374         ret = tstream_npa_accept_existing_recv(subreq, &error, ncacn_conn,
375                                                &ncacn_conn->tstream,
376                                                NULL,
377                                                &transport,
378                                                &ncacn_conn->remote_client_addr,
379                                                &ncacn_conn->remote_client_name,
380                                                &ncacn_conn->local_server_addr,
381                                                &ncacn_conn->local_server_name,
382                                                &session_info_transport);
383         ncacn_conn->session_info = talloc_move(ncacn_conn,
384                         &session_info_transport->session_info);
385
386         if (transport != NCACN_NP) {
387                 ncacn_terminate_connection(
388                         ncacn_conn,
389                         "Only allow NCACN_NP transport on named pipes\n");
390                 return;
391         }
392
393         if (security_token_is_system(
394                     ncacn_conn->session_info->security_token)) {
395                 ncacn_terminate_connection(
396                         ncacn_conn,
397                         "No system token via NCACN_NP allowed\n");
398                 return;
399         }
400
401         TALLOC_FREE(subreq);
402         if (ret != 0) {
403                 DBG_ERR("Failed to accept named pipe connection: %s\n",
404                         strerror(error));
405                 ncacn_terminate_connection(ncacn_conn, strerror(errno));
406                 return;
407         }
408
409         dcesrv_ncacn_accept_step2(ncacn_conn);
410 }
411
412 static void dcesrv_ncacn_accept_step2(struct dcerpc_ncacn_conn *ncacn_conn)
413 {
414         char *pipe_name = NULL;
415         uid_t uid;
416         gid_t gid;
417         int rc;
418         enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
419                         ncacn_conn->endpoint->ep_description);
420         const char *endpoint = dcerpc_binding_get_string_option(
421                         ncacn_conn->endpoint->ep_description, "endpoint");
422         struct dcesrv_connection *dcesrv_conn = NULL;
423         NTSTATUS status;
424
425         switch (transport) {
426                 case NCACN_IP_TCP:
427                         pipe_name = tsocket_address_string(ncacn_conn->remote_client_addr,
428                                                            ncacn_conn);
429                         if (pipe_name == NULL) {
430                                 DBG_ERR("No memory\n");
431                                 ncacn_terminate_connection(ncacn_conn, "No memory");
432                                 return;
433                         }
434
435                         break;
436                 case NCALRPC:
437                         rc = getpeereid(ncacn_conn->sock, &uid, &gid);
438                         if (rc < 0) {
439                                 DEBUG(2, ("Failed to get ncalrpc connecting "
440                                           "uid - %s!\n", strerror(errno)));
441                         } else {
442                                 if (uid == sec_initial_uid()) {
443                                         TALLOC_FREE(ncacn_conn->remote_client_addr);
444
445                                         rc = tsocket_address_unix_from_path(ncacn_conn,
446                                                                             AS_SYSTEM_MAGIC_PATH_TOKEN,
447                                                                             &ncacn_conn->remote_client_addr);
448                                         if (rc < 0) {
449                                                 DBG_ERR("No memory\n");
450                                                 ncacn_terminate_connection(ncacn_conn, "No memory");
451                                                 return;
452                                         }
453
454                                         TALLOC_FREE(ncacn_conn->remote_client_name);
455                                         ncacn_conn->remote_client_name
456                                                 = tsocket_address_unix_path(ncacn_conn->remote_client_addr,
457                                                                             ncacn_conn);
458                                         if (ncacn_conn->remote_client_name == NULL) {
459                                                 DBG_ERR("No memory\n");
460                                                 ncacn_terminate_connection(ncacn_conn, "No memory");
461                                                 return;
462                                         }
463                                 }
464                         }
465
466                         FALL_THROUGH;
467                 case NCACN_NP:
468                         pipe_name = talloc_strdup(ncacn_conn, endpoint);
469                         if (pipe_name == NULL) {
470                                 DBG_ERR("No memory\n");
471                                 ncacn_terminate_connection(ncacn_conn, "No memory");
472                                 return;
473                         }
474                         break;
475                 default:
476                         DBG_ERR("unknown dcerpc transport: %u!\n", transport);
477                         ncacn_terminate_connection(ncacn_conn,
478                                         "Unknown DCE/RPC transport");
479                         return;
480         }
481
482         if (ncacn_conn->session_info == NULL) {
483                 status = make_session_info_anonymous(ncacn_conn,
484                                                      &ncacn_conn->session_info);
485                 if (!NT_STATUS_IS_OK(status)) {
486                         DBG_ERR("Failed to create anonymous session info: "
487                                 "%s\n", nt_errstr(status));
488                         ncacn_terminate_connection(ncacn_conn,
489                                 nt_errstr(status));
490                         return;
491                 }
492         }
493
494         rc = make_base_pipes_struct(ncacn_conn,
495                                     ncacn_conn->msg_ctx,
496                                     pipe_name,
497                                     transport,
498                                     ncacn_conn->remote_client_addr,
499                                     ncacn_conn->local_server_addr,
500                                     &ncacn_conn->p);
501         if (rc != 0) {
502                 const char *errstr = strerror(rc);
503                 DBG_ERR("Failed to create pipe struct: %s\n", errstr);
504                 ncacn_terminate_connection(ncacn_conn, errstr);
505                 return;
506         }
507
508         /*
509          * This fills in dcesrv_conn->endpoint with the endpoint
510          * associated with the socket.  From this point on we know
511          * which (group of) services we are handling, but not the
512          * specific interface.
513          */
514         status = dcesrv_endpoint_connect(ncacn_conn->dce_ctx,
515                                          ncacn_conn,
516                                          ncacn_conn->endpoint,
517                                          ncacn_conn->session_info,
518                                          ncacn_conn->ev_ctx,
519                                          DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
520                                          &dcesrv_conn);
521         if (!NT_STATUS_IS_OK(status)) {
522                 DBG_ERR("Failed to connect to endpoint: %s\n",
523                         nt_errstr(status));
524                 ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
525                 return;
526         }
527         talloc_set_destructor(dcesrv_conn, dcesrv_connection_destructor);
528
529         dcesrv_conn->transport.private_data = ncacn_conn;
530         dcesrv_conn->transport.report_output_data =
531                 dcesrv_sock_report_output_data;
532         dcesrv_conn->transport.terminate_connection =
533                 dcesrv_transport_terminate_connection;
534         dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn,
535                                                       "dcesrv send queue");
536         if (dcesrv_conn->send_queue == NULL) {
537                 status = NT_STATUS_NO_MEMORY;
538                 DBG_ERR("Failed to create send queue: %s\n",
539                         nt_errstr(status));
540                 ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
541                 return;
542         }
543
544         dcesrv_conn->stream = talloc_move(dcesrv_conn, &ncacn_conn->tstream);
545         dcesrv_conn->local_address = ncacn_conn->local_server_addr;
546         dcesrv_conn->remote_address = ncacn_conn->remote_client_addr;
547         status = dcesrv_connection_loop_start(dcesrv_conn);
548         if (!NT_STATUS_IS_OK(status)) {
549                 DBG_ERR("Failed to start dcesrv_connection loop: %s\n",
550                                 nt_errstr(status));
551                 ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
552         }
553         DBG_DEBUG("dcerpc_ncacn_accept done\n");
554
555         return;
556 }
557 #endif
558
559 NTSTATUS dcesrv_auth_gensec_prepare(
560         TALLOC_CTX *mem_ctx,
561         struct dcesrv_call_state *call,
562         struct gensec_security **out,
563         void *private_data)
564 {
565         struct gensec_security *gensec = NULL;
566         NTSTATUS status;
567
568         if (out == NULL) {
569                 return NT_STATUS_INVALID_PARAMETER;
570         }
571
572         status = auth_generic_prepare(mem_ctx,
573                                       call->conn->remote_address,
574                                       call->conn->local_address,
575                                       "DCE/RPC",
576                                       &gensec);
577         if (!NT_STATUS_IS_OK(status)) {
578                 DBG_ERR("Failed to prepare gensec: %s\n", nt_errstr(status));
579                 return status;
580         }
581
582         *out = gensec;
583
584         return NT_STATUS_OK;
585 }
586
587 void dcesrv_log_successful_authz(
588         struct dcesrv_call_state *call,
589         void *private_data)
590 {
591         TALLOC_CTX *frame = talloc_stackframe();
592         struct auth4_context *auth4_context = NULL;
593         struct dcesrv_auth *auth = call->auth_state;
594         enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
595                         call->conn->endpoint->ep_description);
596         const char *auth_type = derpc_transport_string_by_transport(transport);
597         const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
598         NTSTATUS status;
599
600         if (frame == NULL) {
601                 DBG_ERR("No memory");
602                 return;
603         }
604
605         if (transport == NCACN_NP) {
606                 transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
607         }
608
609         become_root();
610         status = make_auth4_context(frame, &auth4_context);
611         unbecome_root();
612         if (!NT_STATUS_IS_OK(status)) {
613                 DBG_ERR("Unable to make auth context for authz log.\n");
614                 TALLOC_FREE(frame);
615                 return;
616         }
617
618         /*
619          * Log the authorization to this RPC interface.  This
620          * covered ncacn_np pass-through auth, and anonymous
621          * DCE/RPC (eg epmapper, netlogon etc)
622          */
623         log_successful_authz_event(auth4_context->msg_ctx,
624                                    auth4_context->lp_ctx,
625                                    call->conn->remote_address,
626                                    call->conn->local_address,
627                                    "DCE/RPC",
628                                    auth_type,
629                                    transport_protection,
630                                    auth->session_info);
631
632         auth->auth_audited = true;
633
634         TALLOC_FREE(frame);
635 }
636
637 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
638 {
639         int ret;
640         ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr,
641                          assoc_group->id);
642         if (ret != 0) {
643                 DBG_ERR("Failed to remove assoc_group 0x%08x\n",
644                         assoc_group->id);
645         }
646         return 0;
647 }
648
649 static NTSTATUS dcesrv_assoc_group_new(struct dcesrv_call_state *call)
650 {
651         struct dcesrv_connection *conn = call->conn;
652         struct dcesrv_context *dce_ctx = conn->dce_ctx;
653         const struct dcesrv_endpoint *endpoint = conn->endpoint;
654         enum dcerpc_transport_t transport =
655                 dcerpc_binding_get_transport(endpoint->ep_description);
656         struct dcesrv_assoc_group *assoc_group = NULL;
657         int id;
658
659         assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
660         if (assoc_group == NULL) {
661                 return NT_STATUS_NO_MEMORY;
662         }
663
664         id = idr_get_new_random(dce_ctx->assoc_groups_idr,
665                                 assoc_group,
666                                 UINT16_MAX);
667         if (id == -1) {
668                 TALLOC_FREE(assoc_group);
669                 DBG_ERR("Out of association groups!\n");
670                 return NT_STATUS_RPC_OUT_OF_RESOURCES;
671         }
672
673         assoc_group->transport = transport;
674         assoc_group->id = id;
675         assoc_group->dce_ctx = dce_ctx;
676
677         call->conn->assoc_group = assoc_group;
678
679         talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
680
681         return NT_STATUS_OK;
682 }
683
684 static NTSTATUS dcesrv_assoc_group_reference(struct dcesrv_call_state *call,
685                                              uint32_t assoc_group_id)
686 {
687         struct dcesrv_connection *conn = call->conn;
688         const struct dcesrv_endpoint *endpoint = conn->endpoint;
689         enum dcerpc_transport_t transport =
690                 dcerpc_binding_get_transport(endpoint->ep_description);
691         struct dcesrv_assoc_group *assoc_group = NULL;
692         void *id_ptr = NULL;
693
694         /* find an association group given a assoc_group_id */
695         id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, assoc_group_id);
696         if (id_ptr == NULL) {
697                 /*
698                  * FIXME If the association group is not found it has
699                  * been created in other process (preforking daemons).
700                  * Until this is properly fixed we just create a new
701                  * association group in this process
702                  */
703                 DBG_NOTICE("Failed to find assoc_group 0x%08x in this "
704                            "server process, creating a new one\n",
705                            assoc_group_id);
706                 return dcesrv_assoc_group_new(call);
707         }
708         assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
709
710         if (assoc_group->transport != transport) {
711                 const char *at =
712                         derpc_transport_string_by_transport(
713                                 assoc_group->transport);
714                 const char *ct =
715                         derpc_transport_string_by_transport(
716                                 transport);
717
718                 DBG_NOTICE("assoc_group 0x%08x (transport %s) "
719                            "is not available on transport %s",
720                            assoc_group_id, at, ct);
721                 return NT_STATUS_UNSUCCESSFUL;
722         }
723
724         conn->assoc_group = talloc_reference(conn, assoc_group);
725         return NT_STATUS_OK;
726 }
727
728 NTSTATUS dcesrv_assoc_group_find(
729         struct dcesrv_call_state *call,
730         void *private_data)
731 {
732         uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
733
734         if (assoc_group_id != 0) {
735                 return dcesrv_assoc_group_reference(call, assoc_group_id);
736         }
737
738         /* If not requested by client create a new association group */
739         return dcesrv_assoc_group_new(call);
740 }
741
742 void dcesrv_transport_terminate_connection(struct dcesrv_connection *dce_conn,
743                                            const char *reason)
744 {
745        struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
746                        dce_conn->transport.private_data,
747                        struct dcerpc_ncacn_conn);
748
749        ncacn_terminate_connection(ncacn_conn, reason);
750 }
751
752 static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
753                                        const char *reason)
754 {
755        if (reason == NULL) {
756                reason = "Unknown reason";
757        }
758
759        DBG_NOTICE("Terminating connection - '%s'\n", reason);
760
761        talloc_free(conn);
762 }
763
764 NTSTATUS dcesrv_endpoint_by_ncacn_np_name(struct dcesrv_context *dce_ctx,
765                                           const char *pipe_name,
766                                           struct dcesrv_endpoint **out)
767 {
768         struct dcesrv_endpoint *e = NULL;
769
770         for (e = dce_ctx->endpoint_list; e; e = e->next) {
771                 enum dcerpc_transport_t transport =
772                         dcerpc_binding_get_transport(e->ep_description);
773                 const char *endpoint = NULL;
774
775                 if (transport != NCACN_NP) {
776                         continue;
777                 }
778
779                 endpoint = dcerpc_binding_get_string_option(e->ep_description,
780                                                             "endpoint");
781                 if (endpoint == NULL) {
782                         continue;
783                 }
784
785                 if (strncmp(endpoint, "\\pipe\\", 6) == 0) {
786                         endpoint += 6;
787                 }
788
789                 if (strequal(endpoint, pipe_name)) {
790                         *out = e;
791                         return NT_STATUS_OK;
792                 }
793         }
794
795         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
796 }
797
798 struct pipes_struct *dcesrv_get_pipes_struct(struct dcesrv_connection *conn)
799 {
800         struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
801                         conn->transport.private_data,
802                         struct dcerpc_ncacn_conn);
803
804         return ncacn_conn->p;
805 }
806
807 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */