CVE-2015-5370: s4:rpc_server: disconnect after a failing dcesrv_auth_request()
[samba.git] / source4 / rpc_server / dcerpc_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc core code
5
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Stefan (metze) Metzmacher 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "auth/auth.h"
25 #include "auth/gensec/gensec.h"
26 #include "../lib/util/dlinklist.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/dcerpc_server_proto.h"
29 #include "rpc_server/common/proto.h"
30 #include "librpc/rpc/dcerpc_proto.h"
31 #include "system/filesys.h"
32 #include "libcli/security/security.h"
33 #include "param/param.h"
34 #include "../lib/tsocket/tsocket.h"
35 #include "../libcli/named_pipe_auth/npa_tstream.h"
36 #include "smbd/service_stream.h"
37 #include "../lib/tsocket/tsocket.h"
38 #include "lib/socket/socket.h"
39 #include "smbd/process_model.h"
40 #include "lib/messaging/irpc.h"
41 #include "librpc/rpc/rpc_common.h"
42 #include "lib/util/samba_modules.h"
43 #include "librpc/gen_ndr/ndr_dcerpc.h"
44
45 /* this is only used when the client asks for an unknown interface */
46 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
47
48 extern const struct dcesrv_interface dcesrv_mgmt_interface;
49
50
51 /*
52   find an association group given a assoc_group_id
53  */
54 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
55                                                           uint32_t id)
56 {
57         void *id_ptr;
58
59         id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
60         if (id_ptr == NULL) {
61                 return NULL;
62         }
63         return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
64 }
65
66 /*
67   take a reference to an existing association group
68  */
69 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
70                                                                struct dcesrv_context *dce_ctx,
71                                                                uint32_t id)
72 {
73         struct dcesrv_assoc_group *assoc_group;
74
75         assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
76         if (assoc_group == NULL) {
77                 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
78                 return NULL;
79         }
80         return talloc_reference(mem_ctx, assoc_group);
81 }
82
83 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
84 {
85         int ret;
86         ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
87         if (ret != 0) {
88                 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
89                          assoc_group->id));
90         }
91         return 0;
92 }
93
94 /*
95   allocate a new association group
96  */
97 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
98                                                          struct dcesrv_context *dce_ctx)
99 {
100         struct dcesrv_assoc_group *assoc_group;
101         int id;
102
103         assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
104         if (assoc_group == NULL) {
105                 return NULL;
106         }
107         
108         id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
109         if (id == -1) {
110                 talloc_free(assoc_group);
111                 DEBUG(0,(__location__ ": Out of association groups!\n"));
112                 return NULL;
113         }
114
115         assoc_group->id = id;
116         assoc_group->dce_ctx = dce_ctx;
117
118         talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
119
120         return assoc_group;
121 }
122
123
124 /*
125   see if two endpoints match
126 */
127 static bool endpoints_match(const struct dcerpc_binding *ep1,
128                             const struct dcerpc_binding *ep2)
129 {
130         enum dcerpc_transport_t t1;
131         enum dcerpc_transport_t t2;
132         const char *e1;
133         const char *e2;
134
135         t1 = dcerpc_binding_get_transport(ep1);
136         t2 = dcerpc_binding_get_transport(ep2);
137
138         e1 = dcerpc_binding_get_string_option(ep1, "endpoint");
139         e2 = dcerpc_binding_get_string_option(ep2, "endpoint");
140
141         if (t1 != t2) {
142                 return false;
143         }
144
145         if (!e1 || !e2) {
146                 return e1 == e2;
147         }
148
149         if (strcasecmp(e1, e2) != 0) {
150                 return false;
151         }
152
153         return true;
154 }
155
156 /*
157   find an endpoint in the dcesrv_context
158 */
159 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
160                                              const struct dcerpc_binding *ep_description)
161 {
162         struct dcesrv_endpoint *ep;
163         for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
164                 if (endpoints_match(ep->ep_description, ep_description)) {
165                         return ep;
166                 }
167         }
168         return NULL;
169 }
170
171 /*
172   find a registered context_id from a bind or alter_context
173 */
174 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn, 
175                                                                    uint32_t context_id)
176 {
177         struct dcesrv_connection_context *c;
178         for (c=conn->contexts;c;c=c->next) {
179                 if (c->context_id == context_id) return c;
180         }
181         return NULL;
182 }
183
184 /*
185   see if a uuid and if_version match to an interface
186 */
187 static bool interface_match(const struct dcesrv_interface *if1,
188                                                         const struct dcesrv_interface *if2)
189 {
190         return (if1->syntax_id.if_version == if2->syntax_id.if_version && 
191                         GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
192 }
193
194 /*
195   find the interface operations on an endpoint
196 */
197 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
198                                                      const struct dcesrv_interface *iface)
199 {
200         struct dcesrv_if_list *ifl;
201         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
202                 if (interface_match(&(ifl->iface), iface)) {
203                         return &(ifl->iface);
204                 }
205         }
206         return NULL;
207 }
208
209 /*
210   see if a uuid and if_version match to an interface
211 */
212 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
213                                     const struct GUID *uuid, uint32_t if_version)
214 {
215         return (iface->syntax_id.if_version == if_version && 
216                         GUID_equal(&iface->syntax_id.uuid, uuid));
217 }
218
219 /*
220   find the interface operations on an endpoint by uuid
221 */
222 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
223                                                              const struct GUID *uuid, uint32_t if_version)
224 {
225         struct dcesrv_if_list *ifl;
226         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
227                 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
228                         return &(ifl->iface);
229                 }
230         }
231         return NULL;
232 }
233
234 /*
235   find the earlier parts of a fragmented call awaiting reassembily
236 */
237 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
238 {
239         struct dcesrv_call_state *c;
240         for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
241                 if (c->pkt.call_id == call_id) {
242                         return c;
243                 }
244         }
245         return NULL;
246 }
247
248 /*
249   register an interface on an endpoint
250 */
251 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
252                                    const char *ep_name,
253                                    const struct dcesrv_interface *iface,
254                                    const struct security_descriptor *sd)
255 {
256         struct dcesrv_endpoint *ep;
257         struct dcesrv_if_list *ifl;
258         struct dcerpc_binding *binding;
259         bool add_ep = false;
260         NTSTATUS status;
261         
262         status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
263
264         if (NT_STATUS_IS_ERR(status)) {
265                 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
266                 return status;
267         }
268
269         /* check if this endpoint exists
270          */
271         if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
272                 ep = talloc_zero(dce_ctx, struct dcesrv_endpoint);
273                 if (!ep) {
274                         return NT_STATUS_NO_MEMORY;
275                 }
276                 ZERO_STRUCTP(ep);
277                 ep->ep_description = talloc_move(ep, &binding);
278                 add_ep = true;
279
280                 /* add mgmt interface */
281                 ifl = talloc_zero(ep, struct dcesrv_if_list);
282                 if (!ifl) {
283                         return NT_STATUS_NO_MEMORY;
284                 }
285
286                 memcpy(&(ifl->iface), &dcesrv_mgmt_interface, 
287                            sizeof(struct dcesrv_interface));
288
289                 DLIST_ADD(ep->interface_list, ifl);
290         }
291
292         /* see if the interface is already registered on te endpoint */
293         if (find_interface(ep, iface)!=NULL) {
294                 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
295                         iface->name, ep_name));
296                 return NT_STATUS_OBJECT_NAME_COLLISION;
297         }
298
299         /* talloc a new interface list element */
300         ifl = talloc_zero(ep, struct dcesrv_if_list);
301         if (!ifl) {
302                 return NT_STATUS_NO_MEMORY;
303         }
304
305         /* copy the given interface struct to the one on the endpoints interface list */
306         memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
307
308         /* if we have a security descriptor given,
309          * we should see if we can set it up on the endpoint
310          */
311         if (sd != NULL) {
312                 /* if there's currently no security descriptor given on the endpoint
313                  * we try to set it
314                  */
315                 if (ep->sd == NULL) {
316                         ep->sd = security_descriptor_copy(ep, sd);
317                 }
318
319                 /* if now there's no security descriptor given on the endpoint
320                  * something goes wrong, either we failed to copy the security descriptor
321                  * or there was already one on the endpoint
322                  */
323                 if (ep->sd != NULL) {
324                         DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
325                                  "                           on endpoint '%s'\n",
326                                 iface->name, ep_name));
327                         if (add_ep) free(ep);
328                         free(ifl);
329                         return NT_STATUS_OBJECT_NAME_COLLISION;
330                 }
331         }
332
333         /* finally add the interface on the endpoint */
334         DLIST_ADD(ep->interface_list, ifl);
335
336         /* if it's a new endpoint add it to the dcesrv_context */
337         if (add_ep) {
338                 DLIST_ADD(dce_ctx->endpoint_list, ep);
339         }
340
341         DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
342                 iface->name, ep_name));
343
344         return NT_STATUS_OK;
345 }
346
347 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
348                                       DATA_BLOB *session_key)
349 {
350         if (p->auth_state.session_info->session_key.length) {
351                 *session_key = p->auth_state.session_info->session_key;
352                 return NT_STATUS_OK;
353         }
354         return NT_STATUS_NO_USER_SESSION_KEY;
355 }
356
357 /*
358   fetch the user session key - may be default (above) or the SMB session key
359
360   The key is always truncated to 16 bytes 
361 */
362 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
363                                   DATA_BLOB *session_key)
364 {
365         NTSTATUS status = p->auth_state.session_key(p, session_key);
366         if (!NT_STATUS_IS_OK(status)) {
367                 return status;
368         }
369
370         session_key->length = MIN(session_key->length, 16);
371
372         return NT_STATUS_OK;
373 }
374
375 /*
376   connect to a dcerpc endpoint
377 */
378 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
379                                  TALLOC_CTX *mem_ctx,
380                                  const struct dcesrv_endpoint *ep,
381                                  struct auth_session_info *session_info,
382                                  struct tevent_context *event_ctx,
383                                  struct imessaging_context *msg_ctx,
384                                  struct server_id server_id,
385                                  uint32_t state_flags,
386                                  struct dcesrv_connection **_p)
387 {
388         struct dcesrv_connection *p;
389
390         if (!session_info) {
391                 return NT_STATUS_ACCESS_DENIED;
392         }
393
394         p = talloc_zero(mem_ctx, struct dcesrv_connection);
395         NT_STATUS_HAVE_NO_MEMORY(p);
396
397         if (!talloc_reference(p, session_info)) {
398                 talloc_free(p);
399                 return NT_STATUS_NO_MEMORY;
400         }
401
402         p->dce_ctx = dce_ctx;
403         p->endpoint = ep;
404         p->packet_log_dir = lpcfg_lock_directory(dce_ctx->lp_ctx);
405         p->auth_state.session_info = session_info;
406         p->auth_state.session_key = dcesrv_generic_session_key;
407         p->event_ctx = event_ctx;
408         p->msg_ctx = msg_ctx;
409         p->server_id = server_id;
410         p->state_flags = state_flags;
411         p->allow_bind = true;
412         p->max_recv_frag = 5840;
413         p->max_xmit_frag = 5840;
414
415         *_p = p;
416         return NT_STATUS_OK;
417 }
418
419 /*
420   move a call from an existing linked list to the specified list. This
421   prevents bugs where we forget to remove the call from a previous
422   list when moving it.
423  */
424 static void dcesrv_call_set_list(struct dcesrv_call_state *call, 
425                                  enum dcesrv_call_list list)
426 {
427         switch (call->list) {
428         case DCESRV_LIST_NONE:
429                 break;
430         case DCESRV_LIST_CALL_LIST:
431                 DLIST_REMOVE(call->conn->call_list, call);
432                 break;
433         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
434                 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
435                 break;
436         case DCESRV_LIST_PENDING_CALL_LIST:
437                 DLIST_REMOVE(call->conn->pending_call_list, call);
438                 break;
439         }
440         call->list = list;
441         switch (list) {
442         case DCESRV_LIST_NONE:
443                 break;
444         case DCESRV_LIST_CALL_LIST:
445                 DLIST_ADD_END(call->conn->call_list, call);
446                 break;
447         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
448                 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call);
449                 break;
450         case DCESRV_LIST_PENDING_CALL_LIST:
451                 DLIST_ADD_END(call->conn->pending_call_list, call);
452                 break;
453         }
454 }
455
456 static void dcesrv_call_disconnect_after(struct dcesrv_call_state *call,
457                                          const char *reason)
458 {
459         if (call->conn->terminate != NULL) {
460                 return;
461         }
462
463         call->conn->allow_bind = false;
464         call->conn->allow_alter = false;
465         call->conn->allow_auth3 = false;
466         call->conn->allow_request = false;
467
468         call->terminate_reason = talloc_strdup(call, reason);
469         if (call->terminate_reason == NULL) {
470                 call->terminate_reason = __location__;
471         }
472 }
473
474 /*
475   return a dcerpc bind_nak
476 */
477 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
478 {
479         struct ncacn_packet pkt;
480         struct dcerpc_bind_nak_version version;
481         struct data_blob_list_item *rep;
482         NTSTATUS status;
483         static const uint8_t _pad[3] = { 0, };
484
485         /*
486          * We add the call to the pending_call_list
487          * in order to defer the termination.
488          */
489         dcesrv_call_disconnect_after(call, "dcesrv_bind_nak");
490
491         /* setup a bind_nak */
492         dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
493         pkt.auth_length = 0;
494         pkt.call_id = call->pkt.call_id;
495         pkt.ptype = DCERPC_PKT_BIND_NAK;
496         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
497         pkt.u.bind_nak.reject_reason = reason;
498         version.rpc_vers = 5;
499         version.rpc_vers_minor = 0;
500         pkt.u.bind_nak.num_versions = 1;
501         pkt.u.bind_nak.versions = &version;
502         pkt.u.bind_nak._pad = data_blob_const(_pad, sizeof(_pad));
503
504         rep = talloc_zero(call, struct data_blob_list_item);
505         if (!rep) {
506                 return NT_STATUS_NO_MEMORY;
507         }
508
509         status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
510         if (!NT_STATUS_IS_OK(status)) {
511                 return status;
512         }
513
514         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
515
516         DLIST_ADD_END(call->replies, rep);
517         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
518
519         if (call->conn->call_list && call->conn->call_list->replies) {
520                 if (call->conn->transport.report_output_data) {
521                         call->conn->transport.report_output_data(call->conn);
522                 }
523         }
524
525         return NT_STATUS_OK;    
526 }
527
528 static NTSTATUS dcesrv_fault_disconnect(struct dcesrv_call_state *call,
529                                  uint32_t fault_code)
530 {
531         /*
532          * We add the call to the pending_call_list
533          * in order to defer the termination.
534          */
535         dcesrv_call_disconnect_after(call, "dcesrv_fault_disconnect");
536
537         return dcesrv_fault_with_flags(call, fault_code,
538                                        DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
539 }
540
541 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
542 {
543         DLIST_REMOVE(c->conn->contexts, c);
544
545         if (c->iface && c->iface->unbind) {
546                 c->iface->unbind(c, c->iface);
547                 c->iface = NULL;
548         }
549
550         return 0;
551 }
552
553 static void dcesrv_prepare_context_auth(struct dcesrv_call_state *dce_call)
554 {
555         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
556         const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
557         enum dcerpc_transport_t transport =
558                 dcerpc_binding_get_transport(endpoint->ep_description);
559         struct dcesrv_connection_context *context = dce_call->context;
560         const struct dcesrv_interface *iface = context->iface;
561
562         context->min_auth_level = DCERPC_AUTH_LEVEL_NONE;
563
564         if (transport == NCALRPC) {
565                 context->allow_connect = true;
566                 return;
567         }
568
569         /*
570          * allow overwrite per interface
571          * allow dcerpc auth level connect:<interface>
572          */
573         context->allow_connect = lpcfg_allow_dcerpc_auth_level_connect(lp_ctx);
574         context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
575                                         "allow dcerpc auth level connect",
576                                         iface->name,
577                                         context->allow_connect);
578 }
579
580 NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_state *dce_call,
581                                                  const struct dcesrv_interface *iface)
582 {
583         if (dce_call->context == NULL) {
584                 return NT_STATUS_INTERNAL_ERROR;
585         }
586
587         dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
588         return NT_STATUS_OK;
589 }
590
591 NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_call,
592                                                const struct dcesrv_interface *iface)
593 {
594         if (dce_call->context == NULL) {
595                 return NT_STATUS_INTERNAL_ERROR;
596         }
597
598         dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
599         return NT_STATUS_OK;
600 }
601
602 _PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_call_state *dce_call,
603                                                        const struct dcesrv_interface *iface)
604 {
605         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
606         const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
607         enum dcerpc_transport_t transport =
608                 dcerpc_binding_get_transport(endpoint->ep_description);
609         struct dcesrv_connection_context *context = dce_call->context;
610
611         if (context == NULL) {
612                 return NT_STATUS_INTERNAL_ERROR;
613         }
614
615         if (transport == NCALRPC) {
616                 context->allow_connect = true;
617                 return NT_STATUS_OK;
618         }
619
620         /*
621          * allow overwrite per interface
622          * allow dcerpc auth level connect:<interface>
623          */
624         context->allow_connect = false;
625         context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
626                                         "allow dcerpc auth level connect",
627                                         iface->name,
628                                         context->allow_connect);
629         return NT_STATUS_OK;
630 }
631
632 _PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *dce_call,
633                                                       const struct dcesrv_interface *iface)
634 {
635         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
636         const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
637         enum dcerpc_transport_t transport =
638                 dcerpc_binding_get_transport(endpoint->ep_description);
639         struct dcesrv_connection_context *context = dce_call->context;
640
641         if (context == NULL) {
642                 return NT_STATUS_INTERNAL_ERROR;
643         }
644
645         if (transport == NCALRPC) {
646                 context->allow_connect = true;
647                 return NT_STATUS_OK;
648         }
649
650         /*
651          * allow overwrite per interface
652          * allow dcerpc auth level connect:<interface>
653          */
654         context->allow_connect = true;
655         context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
656                                         "allow dcerpc auth level connect",
657                                         iface->name,
658                                         context->allow_connect);
659         return NT_STATUS_OK;
660 }
661
662 /*
663   handle a bind request
664 */
665 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
666 {
667         uint32_t if_version, transfer_syntax_version;
668         struct GUID uuid, *transfer_syntax_uuid;
669         struct ncacn_packet pkt;
670         struct data_blob_list_item *rep;
671         NTSTATUS status;
672         uint32_t result=0, reason=0;
673         uint32_t context_id;
674         const struct dcesrv_interface *iface;
675         uint32_t extra_flags = 0;
676         uint16_t max_req = 0;
677         uint16_t max_rep = 0;
678         const char *ep_prefix = "";
679         const char *endpoint = NULL;
680
681         status = dcerpc_verify_ncacn_packet_header(&call->pkt,
682                         DCERPC_PKT_BIND,
683                         call->pkt.u.bind.auth_info.length,
684                         0, /* required flags */
685                         DCERPC_PFC_FLAG_FIRST |
686                         DCERPC_PFC_FLAG_LAST |
687                         DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
688                         0x08 | /* this is not defined, but should be ignored */
689                         DCERPC_PFC_FLAG_CONC_MPX |
690                         DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
691                         DCERPC_PFC_FLAG_MAYBE |
692                         DCERPC_PFC_FLAG_OBJECT_UUID);
693         if (!NT_STATUS_IS_OK(status)) {
694                 return dcesrv_bind_nak(call,
695                         DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED);
696         }
697
698         /* max_recv_frag and max_xmit_frag result always in the same value! */
699         max_req = MIN(call->pkt.u.bind.max_xmit_frag,
700                       call->pkt.u.bind.max_recv_frag);
701         /*
702          * The values are between 2048 and 5840 tested against Windows 2012R2
703          * via ncacn_ip_tcp on port 135.
704          */
705         max_req = MAX(2048, max_req);
706         max_rep = MIN(max_req, call->conn->max_recv_frag);
707         /* They are truncated to an 8 byte boundary. */
708         max_rep &= 0xFFF8;
709
710         /* max_recv_frag and max_xmit_frag result always in the same value! */
711         call->conn->max_recv_frag = max_rep;
712         call->conn->max_xmit_frag = max_rep;
713
714         /*
715           if provided, check the assoc_group is valid
716          */
717         if (call->pkt.u.bind.assoc_group_id != 0 &&
718             lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
719             dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
720                 return dcesrv_bind_nak(call, 0);        
721         }
722
723         if (call->pkt.u.bind.num_contexts < 1 ||
724             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
725                 return dcesrv_bind_nak(call, 0);
726         }
727
728         context_id = call->pkt.u.bind.ctx_list[0].context_id;
729         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
730         uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
731
732         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
733         transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
734         if (!GUID_equal(&ndr_transfer_syntax_ndr.uuid, transfer_syntax_uuid) != 0 ||
735             ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
736                 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
737                 /* we only do NDR encoded dcerpc */
738                 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
739                 talloc_free(uuid_str);
740                 return dcesrv_bind_nak(call, 0);
741         }
742
743         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
744         if (iface == NULL) {
745                 char *uuid_str = GUID_string(call, &uuid);
746                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
747                 talloc_free(uuid_str);
748
749                 /* we don't know about that interface */
750                 result = DCERPC_BIND_PROVIDER_REJECT;
751                 reason = DCERPC_BIND_REASON_ASYNTAX;            
752         }
753
754         if (iface) {
755                 /* add this context to the list of available context_ids */
756                 struct dcesrv_connection_context *context = talloc_zero(call->conn,
757                                                                    struct dcesrv_connection_context);
758                 if (context == NULL) {
759                         return dcesrv_bind_nak(call, 0);
760                 }
761                 context->conn = call->conn;
762                 context->iface = iface;
763                 context->context_id = context_id;
764                 if (call->pkt.u.bind.assoc_group_id != 0) {
765                         context->assoc_group = dcesrv_assoc_group_reference(context,
766                                                                             call->conn->dce_ctx, 
767                                                                             call->pkt.u.bind.assoc_group_id);
768                 } else {
769                         context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
770                 }
771                 if (context->assoc_group == NULL) {
772                         talloc_free(context);
773                         return dcesrv_bind_nak(call, 0);
774                 }
775                 context->private_data = NULL;
776                 DLIST_ADD(call->conn->contexts, context);
777                 call->context = context;
778                 talloc_set_destructor(context, dcesrv_connection_context_destructor);
779
780                 dcesrv_prepare_context_auth(call);
781
782                 status = iface->bind(call, iface, if_version);
783                 if (!NT_STATUS_IS_OK(status)) {
784                         char *uuid_str = GUID_string(call, &uuid);
785                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
786                                  uuid_str, if_version, nt_errstr(status)));
787                         talloc_free(uuid_str);
788                         /* we don't want to trigger the iface->unbind() hook */
789                         context->iface = NULL;
790                         talloc_free(call->context);
791                         call->context = NULL;
792                         return dcesrv_bind_nak(call, 0);
793                 }
794         }
795
796         if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
797             (call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
798                 call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
799                 extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
800         }
801
802         if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
803                 call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
804         }
805
806         /* handle any authentication that is being requested */
807         if (!dcesrv_auth_bind(call)) {
808                 talloc_free(call->context);
809                 call->context = NULL;
810                 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
811         }
812
813         /* setup a bind_ack */
814         dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
815         pkt.auth_length = 0;
816         pkt.call_id = call->pkt.call_id;
817         pkt.ptype = DCERPC_PKT_BIND_ACK;
818         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
819         pkt.u.bind_ack.max_xmit_frag = call->conn->max_xmit_frag;
820         pkt.u.bind_ack.max_recv_frag = call->conn->max_recv_frag;
821
822         /*
823           make it possible for iface->bind() to specify the assoc_group_id
824           This helps the openchange mapiproxy plugin to work correctly.
825           
826           metze
827         */
828         if (call->context) {
829                 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
830         } else {
831                 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
832         }
833
834         if (iface) {
835                 endpoint = dcerpc_binding_get_string_option(
836                                 call->conn->endpoint->ep_description,
837                                 "endpoint");
838         }
839
840         if (endpoint == NULL) {
841                 endpoint = "";
842         }
843
844         if (strncasecmp(endpoint, "\\pipe\\", 6) == 0) {
845                 /*
846                  * TODO: check if this is really needed
847                  *
848                  * Or if we should fix this in our idl files.
849                  */
850                 ep_prefix = "\\PIPE\\";
851                 endpoint += 6;
852         }
853
854         pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "%s%s",
855                                                            ep_prefix,
856                                                            endpoint);
857         if (pkt.u.bind_ack.secondary_address == NULL) {
858                 TALLOC_FREE(call->context);
859                 return NT_STATUS_NO_MEMORY;
860         }
861         pkt.u.bind_ack.num_results = 1;
862         pkt.u.bind_ack.ctx_list = talloc_zero(call, struct dcerpc_ack_ctx);
863         if (!pkt.u.bind_ack.ctx_list) {
864                 talloc_free(call->context);
865                 call->context = NULL;
866                 return NT_STATUS_NO_MEMORY;
867         }
868         pkt.u.bind_ack.ctx_list[0].result = result;
869         pkt.u.bind_ack.ctx_list[0].reason.value = reason;
870         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
871         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
872
873         status = dcesrv_auth_bind_ack(call, &pkt);
874         if (!NT_STATUS_IS_OK(status)) {
875                 talloc_free(call->context);
876                 call->context = NULL;
877                 return dcesrv_bind_nak(call, 0);
878         }
879
880         rep = talloc_zero(call, struct data_blob_list_item);
881         if (!rep) {
882                 talloc_free(call->context);
883                 call->context = NULL;
884                 return NT_STATUS_NO_MEMORY;
885         }
886
887         status = ncacn_push_auth(&rep->blob, call, &pkt,
888                                  call->out_auth_info);
889         if (!NT_STATUS_IS_OK(status)) {
890                 talloc_free(call->context);
891                 call->context = NULL;
892                 return status;
893         }
894
895         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
896
897         DLIST_ADD_END(call->replies, rep);
898         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
899
900         if (call->conn->call_list && call->conn->call_list->replies) {
901                 if (call->conn->transport.report_output_data) {
902                         call->conn->transport.report_output_data(call->conn);
903                 }
904         }
905
906         return NT_STATUS_OK;
907 }
908
909
910 /*
911   handle a auth3 request
912 */
913 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
914 {
915         NTSTATUS status;
916
917         if (!call->conn->allow_auth3) {
918                 return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
919         }
920
921         if (call->conn->auth_state.auth_finished) {
922                 return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
923         }
924
925         status = dcerpc_verify_ncacn_packet_header(&call->pkt,
926                         DCERPC_PKT_AUTH3,
927                         call->pkt.u.auth3.auth_info.length,
928                         0, /* required flags */
929                         DCERPC_PFC_FLAG_FIRST |
930                         DCERPC_PFC_FLAG_LAST |
931                         DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
932                         0x08 | /* this is not defined, but should be ignored */
933                         DCERPC_PFC_FLAG_CONC_MPX |
934                         DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
935                         DCERPC_PFC_FLAG_MAYBE |
936                         DCERPC_PFC_FLAG_OBJECT_UUID);
937         if (!NT_STATUS_IS_OK(status)) {
938                 return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
939         }
940
941         /* handle the auth3 in the auth code */
942         if (!dcesrv_auth_auth3(call)) {
943                 call->conn->auth_state.auth_invalid = true;
944         }
945
946         talloc_free(call);
947
948         /* we don't send a reply to a auth3 request, except by a
949            fault */
950         return NT_STATUS_OK;
951 }
952
953
954 /*
955   handle a bind request
956 */
957 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
958 {
959         uint32_t if_version, transfer_syntax_version;
960         struct dcesrv_connection_context *context;
961         const struct dcesrv_interface *iface;
962         struct GUID uuid, *transfer_syntax_uuid;
963         NTSTATUS status;
964
965         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
966         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
967
968         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
969         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
970         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax_ndr.uuid) ||
971             ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
972                 /* we only do NDR encoded dcerpc */
973                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
974         }
975
976         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
977         if (iface == NULL) {
978                 char *uuid_str = GUID_string(call, &uuid);
979                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
980                 talloc_free(uuid_str);
981                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
982         }
983
984         /* add this context to the list of available context_ids */
985         context = talloc_zero(call->conn, struct dcesrv_connection_context);
986         if (context == NULL) {
987                 return NT_STATUS_NO_MEMORY;
988         }
989         context->conn = call->conn;
990         context->iface = iface;
991         context->context_id = context_id;
992         if (call->pkt.u.alter.assoc_group_id != 0) {
993                 context->assoc_group = dcesrv_assoc_group_reference(context,
994                                                                     call->conn->dce_ctx, 
995                                                                     call->pkt.u.alter.assoc_group_id);
996         } else {
997                 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
998         }
999         if (context->assoc_group == NULL) {
1000                 talloc_free(context);
1001                 call->context = NULL;
1002                 return NT_STATUS_NO_MEMORY;
1003         }
1004         context->private_data = NULL;
1005         DLIST_ADD(call->conn->contexts, context);
1006         call->context = context;
1007         talloc_set_destructor(context, dcesrv_connection_context_destructor);
1008
1009         dcesrv_prepare_context_auth(call);
1010
1011         status = iface->bind(call, iface, if_version);
1012         if (!NT_STATUS_IS_OK(status)) {
1013                 /* we don't want to trigger the iface->unbind() hook */
1014                 context->iface = NULL;
1015                 talloc_free(context);
1016                 call->context = NULL;
1017                 return status;
1018         }
1019
1020         return NT_STATUS_OK;
1021 }
1022
1023 /* setup and send an alter_resp */
1024 static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call,
1025                                 uint32_t result,
1026                                 uint32_t reason)
1027 {
1028         struct ncacn_packet pkt;
1029         uint32_t extra_flags = 0;
1030         struct data_blob_list_item *rep = NULL;
1031         NTSTATUS status;
1032
1033         dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1034         pkt.auth_length = 0;
1035         pkt.call_id = call->pkt.call_id;
1036         pkt.ptype = DCERPC_PKT_ALTER_RESP;
1037         if (result == 0) {
1038                 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
1039                                 call->context->conn->state_flags &
1040                                         DCESRV_CALL_STATE_FLAG_MULTIPLEXED) {
1041                         extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1042                 }
1043                 if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
1044                         call->context->conn->state_flags |=
1045                                 DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
1046                 }
1047         }
1048         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
1049         pkt.u.alter_resp.max_xmit_frag = call->conn->max_xmit_frag;
1050         pkt.u.alter_resp.max_recv_frag = call->conn->max_recv_frag;
1051         if (result == 0) {
1052                 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
1053         } else {
1054                 pkt.u.alter_resp.assoc_group_id = 0;
1055         }
1056         pkt.u.alter_resp.num_results = 1;
1057         pkt.u.alter_resp.ctx_list = talloc_zero(call, struct dcerpc_ack_ctx);
1058         if (!pkt.u.alter_resp.ctx_list) {
1059                 return NT_STATUS_NO_MEMORY;
1060         }
1061         pkt.u.alter_resp.ctx_list[0].result = result;
1062         pkt.u.alter_resp.ctx_list[0].reason.value = reason;
1063         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
1064         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
1065         pkt.u.alter_resp.secondary_address = "";
1066
1067         status = dcesrv_auth_alter_ack(call, &pkt);
1068         if (!NT_STATUS_IS_OK(status)) {
1069                 return dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR);
1070         }
1071
1072         rep = talloc_zero(call, struct data_blob_list_item);
1073         if (!rep) {
1074                 return NT_STATUS_NO_MEMORY;
1075         }
1076
1077         status = ncacn_push_auth(&rep->blob, call, &pkt, call->out_auth_info);
1078         if (!NT_STATUS_IS_OK(status)) {
1079                 return status;
1080         }
1081
1082         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1083
1084         DLIST_ADD_END(call->replies, rep);
1085         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1086
1087         if (call->conn->call_list && call->conn->call_list->replies) {
1088                 if (call->conn->transport.report_output_data) {
1089                         call->conn->transport.report_output_data(call->conn);
1090                 }
1091         }
1092
1093         return NT_STATUS_OK;
1094 }
1095
1096 /*
1097   handle a alter context request
1098 */
1099 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
1100 {
1101         NTSTATUS status;
1102         const struct dcerpc_ctx_list *ctx = NULL;
1103         bool auth_ok = false;
1104
1105         if (!call->conn->allow_alter) {
1106                 return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
1107         }
1108
1109         status = dcerpc_verify_ncacn_packet_header(&call->pkt,
1110                         DCERPC_PKT_ALTER,
1111                         call->pkt.u.alter.auth_info.length,
1112                         0, /* required flags */
1113                         DCERPC_PFC_FLAG_FIRST |
1114                         DCERPC_PFC_FLAG_LAST |
1115                         DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
1116                         0x08 | /* this is not defined, but should be ignored */
1117                         DCERPC_PFC_FLAG_CONC_MPX |
1118                         DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
1119                         DCERPC_PFC_FLAG_MAYBE |
1120                         DCERPC_PFC_FLAG_OBJECT_UUID);
1121         if (!NT_STATUS_IS_OK(status)) {
1122                 return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
1123         }
1124
1125         auth_ok = dcesrv_auth_alter(call);
1126         if (!auth_ok) {
1127                 if (call->in_auth_info.auth_type == DCERPC_AUTH_TYPE_NONE) {
1128                         return dcesrv_fault_disconnect(call,
1129                                         DCERPC_FAULT_ACCESS_DENIED);
1130                 }
1131         }
1132
1133         if (call->pkt.u.alter.num_contexts < 1) {
1134                 return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
1135         }
1136         ctx = &call->pkt.u.alter.ctx_list[0];
1137         if (ctx->num_transfer_syntaxes < 1) {
1138                 return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
1139         }
1140
1141         /* see if they are asking for a new interface */
1142         call->context = dcesrv_find_context(call->conn, ctx->context_id);
1143         if (!call->context) {
1144                 status = dcesrv_alter_new_context(call, ctx->context_id);
1145                 if (!NT_STATUS_IS_OK(status)) {
1146                         return dcesrv_alter_resp(call,
1147                                 DCERPC_BIND_PROVIDER_REJECT,
1148                                 DCERPC_BIND_REASON_ASYNTAX);
1149                 }
1150         } else {
1151                 bool ok;
1152
1153                 ok = ndr_syntax_id_equal(&ctx->abstract_syntax,
1154                                          &call->context->iface->syntax_id);
1155                 if (!ok) {
1156                         return dcesrv_fault_disconnect(call,
1157                                         DCERPC_NCA_S_PROTO_ERROR);
1158                 }
1159
1160                 if (ctx->num_transfer_syntaxes != 1) {
1161                         return dcesrv_fault_disconnect(call,
1162                                         DCERPC_NCA_S_PROTO_ERROR);
1163                 }
1164
1165                 ok = ndr_syntax_id_equal(&ctx->transfer_syntaxes[0],
1166                                          &ndr_transfer_syntax_ndr);
1167                 if (!ok) {
1168                         return dcesrv_fault_disconnect(call,
1169                                         DCERPC_NCA_S_PROTO_ERROR);
1170                 }
1171         }
1172
1173         if (call->pkt.u.alter.assoc_group_id != 0 &&
1174             lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
1175             call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
1176                 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
1177                          call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
1178                 /* TODO: can they ask for a new association group? */
1179                 return dcesrv_alter_resp(call,
1180                                 DCERPC_BIND_PROVIDER_REJECT,
1181                                 DCERPC_BIND_REASON_ASYNTAX);
1182         }
1183
1184         /* handle any authentication that is being requested */
1185         if (!auth_ok) {
1186                 if (call->in_auth_info.auth_type !=
1187                     call->conn->auth_state.auth_type)
1188                 {
1189                         return dcesrv_fault_disconnect(call,
1190                                         DCERPC_FAULT_SEC_PKG_ERROR);
1191                 }
1192                 return dcesrv_fault_disconnect(call, DCERPC_FAULT_ACCESS_DENIED);
1193         }
1194
1195         return dcesrv_alter_resp(call,
1196                                 DCERPC_BIND_ACK_RESULT_ACCEPTANCE,
1197                                 DCERPC_BIND_ACK_REASON_NOT_SPECIFIED);
1198 }
1199
1200 /*
1201   possibly save the call for inspection with ndrdump
1202  */
1203 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
1204 {
1205 #ifdef DEVELOPER
1206         char *fname;
1207         const char *dump_dir;
1208         dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
1209         if (!dump_dir) {
1210                 return;
1211         }
1212         fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
1213                                 dump_dir,
1214                                 call->context->iface->name,
1215                                 call->pkt.u.request.opnum,
1216                                 why);
1217         if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
1218                 DEBUG(0,("RPC SAVED %s\n", fname));
1219         }
1220         talloc_free(fname);
1221 #endif
1222 }
1223
1224 static NTSTATUS dcesrv_check_verification_trailer(struct dcesrv_call_state *call)
1225 {
1226         TALLOC_CTX *frame = talloc_stackframe();
1227         const uint32_t bitmask1 = call->conn->auth_state.client_hdr_signing ?
1228                 DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING : 0;
1229         const struct dcerpc_sec_vt_pcontext pcontext = {
1230                 .abstract_syntax = call->context->iface->syntax_id,
1231                 .transfer_syntax = ndr_transfer_syntax_ndr,
1232         };
1233         const struct dcerpc_sec_vt_header2 header2 =
1234                 dcerpc_sec_vt_header2_from_ncacn_packet(&call->pkt);
1235         enum ndr_err_code ndr_err;
1236         struct dcerpc_sec_verification_trailer *vt = NULL;
1237         NTSTATUS status = NT_STATUS_OK;
1238         bool ok;
1239
1240         SMB_ASSERT(call->pkt.ptype == DCERPC_PKT_REQUEST);
1241
1242         ndr_err = ndr_pop_dcerpc_sec_verification_trailer(call->ndr_pull,
1243                                                           frame, &vt);
1244         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1245                 status = ndr_map_error2ntstatus(ndr_err);
1246                 goto done;
1247         }
1248
1249         ok = dcerpc_sec_verification_trailer_check(vt, &bitmask1,
1250                                                    &pcontext, &header2);
1251         if (!ok) {
1252                 status = NT_STATUS_ACCESS_DENIED;
1253                 goto done;
1254         }
1255 done:
1256         TALLOC_FREE(frame);
1257         return status;
1258 }
1259
1260 /*
1261   handle a dcerpc request packet
1262 */
1263 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
1264 {
1265         const struct dcesrv_endpoint *endpoint = call->conn->endpoint;
1266         enum dcerpc_transport_t transport =
1267                 dcerpc_binding_get_transport(endpoint->ep_description);
1268         struct ndr_pull *pull;
1269         NTSTATUS status;
1270         struct dcesrv_connection_context *context;
1271
1272         if (!call->conn->allow_request) {
1273                 return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
1274         }
1275
1276         /* if authenticated, and the mech we use can't do async replies, don't use them... */
1277         if (call->conn->auth_state.gensec_security && 
1278             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
1279                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
1280         }
1281
1282         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
1283         if (context == NULL) {
1284                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
1285         }
1286
1287         switch (call->conn->auth_state.auth_level) {
1288         case DCERPC_AUTH_LEVEL_NONE:
1289         case DCERPC_AUTH_LEVEL_INTEGRITY:
1290         case DCERPC_AUTH_LEVEL_PRIVACY:
1291                 break;
1292         default:
1293                 if (!context->allow_connect) {
1294                         char *addr;
1295
1296                         addr = tsocket_address_string(call->conn->remote_address,
1297                                                       call);
1298
1299                         DEBUG(2, ("%s: restrict auth_level_connect access "
1300                                   "to [%s] with auth[type=0x%x,level=0x%x] "
1301                                   "on [%s] from [%s]\n",
1302                                   __func__, context->iface->name,
1303                                   call->conn->auth_state.auth_type,
1304                                   call->conn->auth_state.auth_level,
1305                                   derpc_transport_string_by_transport(transport),
1306                                   addr));
1307                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1308                 }
1309                 break;
1310         }
1311
1312         if (call->conn->auth_state.auth_level < context->min_auth_level) {
1313                 char *addr;
1314
1315                 addr = tsocket_address_string(call->conn->remote_address, call);
1316
1317                 DEBUG(2, ("%s: restrict access by min_auth_level[0x%x] "
1318                           "to [%s] with auth[type=0x%x,level=0x%x] "
1319                           "on [%s] from [%s]\n",
1320                           __func__,
1321                           context->min_auth_level,
1322                           context->iface->name,
1323                           call->conn->auth_state.auth_type,
1324                           call->conn->auth_state.auth_level,
1325                           derpc_transport_string_by_transport(transport),
1326                           addr));
1327                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1328         }
1329
1330         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
1331         NT_STATUS_HAVE_NO_MEMORY(pull);
1332
1333         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1334
1335         call->context   = context;
1336         call->ndr_pull  = pull;
1337
1338         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
1339                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1340         }
1341
1342         status = dcesrv_check_verification_trailer(call);
1343         if (!NT_STATUS_IS_OK(status)) {
1344                 uint32_t faultcode = DCERPC_FAULT_OTHER;
1345                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1346                         faultcode = DCERPC_FAULT_ACCESS_DENIED;
1347                 }
1348                 DEBUG(10, ("dcesrv_check_verification_trailer failed: %s\n",
1349                            nt_errstr(status)));
1350                 return dcesrv_fault(call, faultcode);
1351         }
1352
1353         /* unravel the NDR for the packet */
1354         status = context->iface->ndr_pull(call, call, pull, &call->r);
1355         if (!NT_STATUS_IS_OK(status)) {
1356                 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
1357                         /* we got an unknown call */
1358                         DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
1359                                  call->pkt.u.request.opnum, context->iface->name));
1360                         dcesrv_save_call(call, "unknown");
1361                 } else {
1362                         dcesrv_save_call(call, "pullfail");
1363                 }
1364                 return dcesrv_fault(call, call->fault_code);
1365         }
1366
1367         if (pull->offset != pull->data_size) {
1368                 dcesrv_save_call(call, "extrabytes");
1369                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
1370                          pull->data_size - pull->offset));
1371         }
1372
1373         /* call the dispatch function */
1374         status = context->iface->dispatch(call, call, call->r);
1375         if (!NT_STATUS_IS_OK(status)) {
1376                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1377                          context->iface->name, 
1378                          call->pkt.u.request.opnum,
1379                          dcerpc_errstr(pull, call->fault_code)));
1380                 return dcesrv_fault(call, call->fault_code);
1381         }
1382
1383         /* add the call to the pending list */
1384         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1385
1386         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1387                 return NT_STATUS_OK;
1388         }
1389
1390         return dcesrv_reply(call);
1391 }
1392
1393
1394 /*
1395   remove the call from the right list when freed
1396  */
1397 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1398 {
1399         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1400         return 0;
1401 }
1402
1403 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1404 {
1405         return conn->local_address;
1406 }
1407
1408 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1409 {
1410         return conn->remote_address;
1411 }
1412
1413 /*
1414   process some input to a dcerpc endpoint server.
1415 */
1416 static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1417                                             struct ncacn_packet *pkt,
1418                                             DATA_BLOB blob)
1419 {
1420         NTSTATUS status;
1421         struct dcesrv_call_state *call;
1422
1423         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1424         if (!call) {
1425                 data_blob_free(&blob);
1426                 talloc_free(pkt);
1427                 return NT_STATUS_NO_MEMORY;
1428         }
1429         call->conn              = dce_conn;
1430         call->event_ctx         = dce_conn->event_ctx;
1431         call->msg_ctx           = dce_conn->msg_ctx;
1432         call->state_flags       = call->conn->state_flags;
1433         call->time              = timeval_current();
1434         call->list              = DCESRV_LIST_NONE;
1435
1436         talloc_steal(call, pkt);
1437         talloc_steal(call, blob.data);
1438         call->pkt = *pkt;
1439
1440         talloc_set_destructor(call, dcesrv_call_dequeue);
1441
1442         if (call->conn->allow_bind) {
1443                 /*
1444                  * Only one bind is possible per connection
1445                  */
1446                 call->conn->allow_bind = false;
1447                 return dcesrv_bind(call);
1448         }
1449
1450         /* we have to check the signing here, before combining the
1451            pdus */
1452         if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
1453                 if (!call->conn->allow_request) {
1454                         return dcesrv_fault_disconnect(call,
1455                                         DCERPC_NCA_S_PROTO_ERROR);
1456                 }
1457
1458                 status = dcerpc_verify_ncacn_packet_header(&call->pkt,
1459                                 DCERPC_PKT_REQUEST,
1460                                 call->pkt.u.request.stub_and_verifier.length,
1461                                 0, /* required_flags */
1462                                 DCERPC_PFC_FLAG_FIRST |
1463                                 DCERPC_PFC_FLAG_LAST |
1464                                 DCERPC_PFC_FLAG_PENDING_CANCEL |
1465                                 0x08 | /* this is not defined, but should be ignored */
1466                                 DCERPC_PFC_FLAG_CONC_MPX |
1467                                 DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
1468                                 DCERPC_PFC_FLAG_MAYBE |
1469                                 DCERPC_PFC_FLAG_OBJECT_UUID);
1470                 if (!NT_STATUS_IS_OK(status)) {
1471                         return dcesrv_fault_disconnect(call,
1472                                         DCERPC_NCA_S_PROTO_ERROR);
1473                 }
1474
1475                 if (!dcesrv_auth_request(call, &blob)) {
1476                         /*
1477                          * We don't use dcesrv_fault_disconnect()
1478                          * here, because we don't want to set
1479                          * DCERPC_PFC_FLAG_DID_NOT_EXECUTE
1480                          */
1481                         dcesrv_call_disconnect_after(call,
1482                                                 "dcesrv_auth_request - failed");
1483                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1484                 }
1485         }
1486
1487         /* see if this is a continued packet */
1488         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1489             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1490                 struct dcesrv_call_state *call2 = call;
1491                 uint32_t alloc_size;
1492
1493                 /* this is a continuation of an existing call - find the call
1494                    then tack it on the end */
1495                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1496                 if (!call) {
1497                         return dcesrv_fault_disconnect(call2,
1498                                         DCERPC_NCA_S_PROTO_ERROR);
1499                 }
1500
1501                 if (call->pkt.ptype != call2->pkt.ptype) {
1502                         /* trying to play silly buggers are we? */
1503                         return dcesrv_fault_disconnect(call,
1504                                         DCERPC_NCA_S_PROTO_ERROR);
1505                 }
1506                 if (memcmp(call->pkt.drep, call2->pkt.drep, sizeof(pkt->drep)) != 0) {
1507                         return dcesrv_fault_disconnect(call,
1508                                         DCERPC_NCA_S_PROTO_ERROR);
1509                 }
1510                 if (call->pkt.call_id != call2->pkt.call_id) {
1511                         return dcesrv_fault_disconnect(call,
1512                                         DCERPC_NCA_S_PROTO_ERROR);
1513                 }
1514                 if (call->pkt.u.request.context_id != call2->pkt.u.request.context_id)  {
1515                         return dcesrv_fault_disconnect(call,
1516                                         DCERPC_NCA_S_PROTO_ERROR);
1517                 }
1518                 if (call->pkt.u.request.opnum != call2->pkt.u.request.opnum)  {
1519                         return dcesrv_fault_disconnect(call,
1520                                         DCERPC_NCA_S_PROTO_ERROR);
1521                 }
1522
1523                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1524                         call2->pkt.u.request.stub_and_verifier.length;
1525                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1526                         alloc_size = call->pkt.u.request.alloc_hint;
1527                 }
1528
1529                 call->pkt.u.request.stub_and_verifier.data = 
1530                         talloc_realloc(call, 
1531                                        call->pkt.u.request.stub_and_verifier.data, 
1532                                        uint8_t, alloc_size);
1533                 if (!call->pkt.u.request.stub_and_verifier.data) {
1534                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1535                 }
1536                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1537                        call->pkt.u.request.stub_and_verifier.length,
1538                        call2->pkt.u.request.stub_and_verifier.data,
1539                        call2->pkt.u.request.stub_and_verifier.length);
1540                 call->pkt.u.request.stub_and_verifier.length += 
1541                         call2->pkt.u.request.stub_and_verifier.length;
1542
1543                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1544
1545                 talloc_free(call2);
1546         }
1547
1548         /* this may not be the last pdu in the chain - if its isn't then
1549            just put it on the incoming_fragmented_call_list and wait for the rest */
1550         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1551             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1552                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1553                 return NT_STATUS_OK;
1554         } 
1555         
1556         /* This removes any fragments we may have had stashed away */
1557         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1558
1559         switch (call->pkt.ptype) {
1560         case DCERPC_PKT_BIND:
1561                 status = dcesrv_bind_nak(call,
1562                         DCERPC_BIND_NAK_REASON_NOT_SPECIFIED);
1563                 break;
1564         case DCERPC_PKT_AUTH3:
1565                 status = dcesrv_auth3(call);
1566                 break;
1567         case DCERPC_PKT_ALTER:
1568                 status = dcesrv_alter(call);
1569                 break;
1570         case DCERPC_PKT_REQUEST:
1571                 status = dcesrv_request(call);
1572                 break;
1573         default:
1574                 status = dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
1575                 break;
1576         }
1577
1578         /* if we are going to be sending a reply then add
1579            it to the list of pending calls. We add it to the end to keep the call
1580            list in the order we will answer */
1581         if (!NT_STATUS_IS_OK(status)) {
1582                 talloc_free(call);
1583         }
1584
1585         return status;
1586 }
1587
1588 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1589                                       struct loadparm_context *lp_ctx,
1590                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1591 {
1592         NTSTATUS status;
1593         struct dcesrv_context *dce_ctx;
1594         int i;
1595
1596         if (!endpoint_servers) {
1597                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1598                 return NT_STATUS_INTERNAL_ERROR;
1599         }
1600
1601         dce_ctx = talloc_zero(mem_ctx, struct dcesrv_context);
1602         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1603
1604         if (uid_wrapper_enabled()) {
1605                 setenv("UID_WRAPPER_MYUID", "1", 1);
1606         }
1607         dce_ctx->initial_euid = geteuid();
1608         if (uid_wrapper_enabled()) {
1609                 unsetenv("UID_WRAPPER_MYUID");
1610         }
1611
1612         dce_ctx->endpoint_list  = NULL;
1613         dce_ctx->lp_ctx = lp_ctx;
1614         dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1615         NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1616         dce_ctx->broken_connections = NULL;
1617
1618         for (i=0;endpoint_servers[i];i++) {
1619                 const struct dcesrv_endpoint_server *ep_server;
1620
1621                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1622                 if (!ep_server) {
1623                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1624                         return NT_STATUS_INTERNAL_ERROR;
1625                 }
1626
1627                 status = ep_server->init_server(dce_ctx, ep_server);
1628                 if (!NT_STATUS_IS_OK(status)) {
1629                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1630                                 nt_errstr(status)));
1631                         return status;
1632                 }
1633         }
1634
1635         *_dce_ctx = dce_ctx;
1636         return NT_STATUS_OK;
1637 }
1638
1639 /* the list of currently registered DCERPC endpoint servers.
1640  */
1641 static struct ep_server {
1642         struct dcesrv_endpoint_server *ep_server;
1643 } *ep_servers = NULL;
1644 static int num_ep_servers;
1645
1646 /*
1647   register a DCERPC endpoint server. 
1648
1649   The 'name' can be later used by other backends to find the operations
1650   structure for this backend.  
1651
1652   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1653 */
1654 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1655 {
1656         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1657         
1658         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1659                 /* its already registered! */
1660                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1661                          ep_server->name));
1662                 return NT_STATUS_OBJECT_NAME_COLLISION;
1663         }
1664
1665         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1666         if (!ep_servers) {
1667                 smb_panic("out of memory in dcerpc_register");
1668         }
1669
1670         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1671         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1672
1673         num_ep_servers++;
1674
1675         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1676                  ep_server->name));
1677
1678         return NT_STATUS_OK;
1679 }
1680
1681 /*
1682   return the operations structure for a named backend of the specified type
1683 */
1684 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1685 {
1686         int i;
1687
1688         for (i=0;i<num_ep_servers;i++) {
1689                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1690                         return ep_servers[i].ep_server;
1691                 }
1692         }
1693
1694         return NULL;
1695 }
1696
1697 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1698 {
1699         static bool initialized;
1700 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1701         STATIC_dcerpc_server_MODULES_PROTO;
1702         init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1703         init_module_fn *shared_init;
1704
1705         if (initialized) {
1706                 return;
1707         }
1708         initialized = true;
1709
1710         shared_init = load_samba_modules(NULL, "dcerpc_server");
1711
1712         run_init_functions(static_init);
1713         run_init_functions(shared_init);
1714
1715         talloc_free(shared_init);
1716 }
1717
1718 /*
1719   return the DCERPC module version, and the size of some critical types
1720   This can be used by endpoint server modules to either detect compilation errors, or provide
1721   multiple implementations for different smbd compilation options in one module
1722 */
1723 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1724 {
1725         static const struct dcesrv_critical_sizes critical_sizes = {
1726                 DCERPC_MODULE_VERSION,
1727                 sizeof(struct dcesrv_context),
1728                 sizeof(struct dcesrv_endpoint),
1729                 sizeof(struct dcesrv_endpoint_server),
1730                 sizeof(struct dcesrv_interface),
1731                 sizeof(struct dcesrv_if_list),
1732                 sizeof(struct dcesrv_connection),
1733                 sizeof(struct dcesrv_call_state),
1734                 sizeof(struct dcesrv_auth),
1735                 sizeof(struct dcesrv_handle)
1736         };
1737
1738         return &critical_sizes;
1739 }
1740
1741 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1742 {
1743         struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1744         struct stream_connection *srv_conn;
1745         srv_conn = talloc_get_type(dce_conn->transport.private_data,
1746                                    struct stream_connection);
1747
1748         dce_conn->allow_bind = false;
1749         dce_conn->allow_auth3 = false;
1750         dce_conn->allow_alter = false;
1751         dce_conn->allow_request = false;
1752
1753         if (dce_conn->pending_call_list == NULL) {
1754                 char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
1755
1756                 DLIST_REMOVE(dce_ctx->broken_connections, dce_conn);
1757                 stream_terminate_connection(srv_conn, full_reason ? full_reason : reason);
1758                 return;
1759         }
1760
1761         if (dce_conn->terminate != NULL) {
1762                 return;
1763         }
1764
1765         DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1766                  reason));
1767         dce_conn->terminate = talloc_strdup(dce_conn, reason);
1768         if (dce_conn->terminate == NULL) {
1769                 dce_conn->terminate = "dcesrv: defered terminating connection - no memory";
1770         }
1771         DLIST_ADD_END(dce_ctx->broken_connections, dce_conn);
1772 }
1773
1774 static void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx)
1775 {
1776         struct dcesrv_connection *cur, *next;
1777
1778         next = dce_ctx->broken_connections;
1779         while (next != NULL) {
1780                 cur = next;
1781                 next = cur->next;
1782
1783                 if (cur->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
1784                         struct dcesrv_connection_context *context_cur, *context_next;
1785
1786                         context_next = cur->contexts;
1787                         while (context_next != NULL) {
1788                                 context_cur = context_next;
1789                                 context_next = context_cur->next;
1790
1791                                 dcesrv_connection_context_destructor(context_cur);
1792                         }
1793                 }
1794
1795                 dcesrv_terminate_connection(cur, cur->terminate);
1796         }
1797 }
1798
1799 /* We need this include to be able to compile on some plateforms
1800  * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1801  * correctly.
1802  * It has to be that deep because otherwise we have a conflict on
1803  * const struct dcesrv_interface declaration.
1804  * This is mostly due to socket_wrapper defining #define bind swrap_bind
1805  * which conflict with the bind used before.
1806  */
1807 #include "system/network.h"
1808
1809 struct dcesrv_sock_reply_state {
1810         struct dcesrv_connection *dce_conn;
1811         struct dcesrv_call_state *call;
1812         struct iovec iov;
1813 };
1814
1815 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1816 static void dcesrv_call_terminate_step1(struct tevent_req *subreq);
1817
1818 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1819 {
1820         struct dcesrv_call_state *call;
1821
1822         call = dce_conn->call_list;
1823         if (!call || !call->replies) {
1824                 return;
1825         }
1826
1827         while (call->replies) {
1828                 struct data_blob_list_item *rep = call->replies;
1829                 struct dcesrv_sock_reply_state *substate;
1830                 struct tevent_req *subreq;
1831
1832                 substate = talloc_zero(call, struct dcesrv_sock_reply_state);
1833                 if (!substate) {
1834                         dcesrv_terminate_connection(dce_conn, "no memory");
1835                         return;
1836                 }
1837
1838                 substate->dce_conn = dce_conn;
1839                 substate->call = NULL;
1840
1841                 DLIST_REMOVE(call->replies, rep);
1842
1843                 if (call->replies == NULL && call->terminate_reason == NULL) {
1844                         substate->call = call;
1845                 }
1846
1847                 substate->iov.iov_base = (void *) rep->blob.data;
1848                 substate->iov.iov_len = rep->blob.length;
1849
1850                 subreq = tstream_writev_queue_send(substate,
1851                                                    dce_conn->event_ctx,
1852                                                    dce_conn->stream,
1853                                                    dce_conn->send_queue,
1854                                                    &substate->iov, 1);
1855                 if (!subreq) {
1856                         dcesrv_terminate_connection(dce_conn, "no memory");
1857                         return;
1858                 }
1859                 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1860                                         substate);
1861         }
1862
1863         if (call->terminate_reason != NULL) {
1864                 struct tevent_req *subreq;
1865
1866                 subreq = tevent_queue_wait_send(call,
1867                                                 dce_conn->event_ctx,
1868                                                 dce_conn->send_queue);
1869                 if (!subreq) {
1870                         dcesrv_terminate_connection(dce_conn, __location__);
1871                         return;
1872                 }
1873                 tevent_req_set_callback(subreq, dcesrv_call_terminate_step1,
1874                                         call);
1875         }
1876
1877         DLIST_REMOVE(call->conn->call_list, call);
1878         call->list = DCESRV_LIST_NONE;
1879 }
1880
1881 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1882 {
1883         struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1884                                                 struct dcesrv_sock_reply_state);
1885         int ret;
1886         int sys_errno;
1887         NTSTATUS status;
1888         struct dcesrv_call_state *call = substate->call;
1889
1890         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1891         TALLOC_FREE(subreq);
1892         if (ret == -1) {
1893                 status = map_nt_error_from_unix_common(sys_errno);
1894                 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1895                 return;
1896         }
1897
1898         talloc_free(substate);
1899         if (call) {
1900                 talloc_free(call);
1901         }
1902 }
1903
1904 static void dcesrv_call_terminate_step2(struct tevent_req *subreq);
1905
1906 static void dcesrv_call_terminate_step1(struct tevent_req *subreq)
1907 {
1908         struct dcesrv_call_state *call = tevent_req_callback_data(subreq,
1909                                                 struct dcesrv_call_state);
1910         bool ok;
1911         struct timeval tv;
1912
1913         /* make sure we stop send queue before removing subreq */
1914         tevent_queue_stop(call->conn->send_queue);
1915
1916         ok = tevent_queue_wait_recv(subreq);
1917         TALLOC_FREE(subreq);
1918         if (!ok) {
1919                 dcesrv_terminate_connection(call->conn, __location__);
1920                 return;
1921         }
1922
1923         /* disconnect after 200 usecs */
1924         tv = timeval_current_ofs_usec(200);
1925         subreq = tevent_wakeup_send(call, call->conn->event_ctx, tv);
1926         if (subreq == NULL) {
1927                 dcesrv_terminate_connection(call->conn, __location__);
1928                 return;
1929         }
1930         tevent_req_set_callback(subreq, dcesrv_call_terminate_step2,
1931                                 call);
1932 }
1933
1934 static void dcesrv_call_terminate_step2(struct tevent_req *subreq)
1935 {
1936         struct dcesrv_call_state *call = tevent_req_callback_data(subreq,
1937                                                 struct dcesrv_call_state);
1938         bool ok;
1939
1940         ok = tevent_wakeup_recv(subreq);
1941         TALLOC_FREE(subreq);
1942         if (!ok) {
1943                 dcesrv_terminate_connection(call->conn, __location__);
1944                 return;
1945         }
1946
1947         dcesrv_terminate_connection(call->conn, call->terminate_reason);
1948 }
1949
1950 struct dcesrv_socket_context {
1951         const struct dcesrv_endpoint *endpoint;
1952         struct dcesrv_context *dcesrv_ctx;
1953 };
1954
1955
1956 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1957
1958 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1959 {
1960         NTSTATUS status;
1961         struct dcesrv_socket_context *dcesrv_sock = 
1962                 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1963         enum dcerpc_transport_t transport =
1964                 dcerpc_binding_get_transport(dcesrv_sock->endpoint->ep_description);
1965         struct dcesrv_connection *dcesrv_conn = NULL;
1966         int ret;
1967         struct tevent_req *subreq;
1968         struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1969
1970         dcesrv_cleanup_broken_connections(dcesrv_sock->dcesrv_ctx);
1971
1972         if (!srv_conn->session_info) {
1973                 status = auth_anonymous_session_info(srv_conn,
1974                                                      lp_ctx,
1975                                                      &srv_conn->session_info);
1976                 if (!NT_STATUS_IS_OK(status)) {
1977                         DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1978                                 nt_errstr(status)));
1979                         stream_terminate_connection(srv_conn, nt_errstr(status));
1980                         return;
1981                 }
1982         }
1983
1984         status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1985                                          srv_conn,
1986                                          dcesrv_sock->endpoint,
1987                                          srv_conn->session_info,
1988                                          srv_conn->event.ctx,
1989                                          srv_conn->msg_ctx,
1990                                          srv_conn->server_id,
1991                                          DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1992                                          &dcesrv_conn);
1993         if (!NT_STATUS_IS_OK(status)) {
1994                 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", 
1995                         nt_errstr(status)));
1996                 stream_terminate_connection(srv_conn, nt_errstr(status));
1997                 return;
1998         }
1999
2000         dcesrv_conn->transport.private_data             = srv_conn;
2001         dcesrv_conn->transport.report_output_data       = dcesrv_sock_report_output_data;
2002
2003         TALLOC_FREE(srv_conn->event.fde);
2004
2005         dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
2006         if (!dcesrv_conn->send_queue) {
2007                 status = NT_STATUS_NO_MEMORY;
2008                 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
2009                         nt_errstr(status)));
2010                 stream_terminate_connection(srv_conn, nt_errstr(status));
2011                 return;
2012         }
2013
2014         if (transport == NCACN_NP) {
2015                 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
2016                 dcesrv_conn->stream = talloc_move(dcesrv_conn,
2017                                                   &srv_conn->tstream);
2018         } else {
2019                 ret = tstream_bsd_existing_socket(dcesrv_conn,
2020                                                   socket_get_fd(srv_conn->socket),
2021                                                   &dcesrv_conn->stream);
2022                 if (ret == -1) {
2023                         status = map_nt_error_from_unix_common(errno);
2024                         DEBUG(0, ("dcesrv_sock_accept: "
2025                                   "failed to setup tstream: %s\n",
2026                                   nt_errstr(status)));
2027                         stream_terminate_connection(srv_conn, nt_errstr(status));
2028                         return;
2029                 }
2030                 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
2031         }
2032
2033         dcesrv_conn->local_address = srv_conn->local_address;
2034         dcesrv_conn->remote_address = srv_conn->remote_address;
2035
2036         if (transport == NCALRPC) {
2037                 uid_t uid;
2038                 gid_t gid;
2039
2040                 ret = getpeereid(socket_get_fd(srv_conn->socket), &uid, &gid);
2041                 if (ret == -1) {
2042                         status = map_nt_error_from_unix_common(errno);
2043                         DEBUG(0, ("dcesrv_sock_accept: "
2044                                   "getpeereid() failed for NCALRPC: %s\n",
2045                                   nt_errstr(status)));
2046                         stream_terminate_connection(srv_conn, nt_errstr(status));
2047                         return;
2048                 }
2049                 if (uid == dcesrv_conn->dce_ctx->initial_euid) {
2050                         struct tsocket_address *r = NULL;
2051
2052                         ret = tsocket_address_unix_from_path(dcesrv_conn,
2053                                                              "/root/ncalrpc_as_system",
2054                                                              &r);
2055                         if (ret == -1) {
2056                                 status = map_nt_error_from_unix_common(errno);
2057                                 DEBUG(0, ("dcesrv_sock_accept: "
2058                                           "tsocket_address_unix_from_path() failed for NCALRPC: %s\n",
2059                                           nt_errstr(status)));
2060                                 stream_terminate_connection(srv_conn, nt_errstr(status));
2061                                 return;
2062                         }
2063                         dcesrv_conn->remote_address = r;
2064                 }
2065         }
2066
2067         srv_conn->private_data = dcesrv_conn;
2068
2069         irpc_add_name(srv_conn->msg_ctx, "rpc_server");
2070
2071         subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
2072                                                dcesrv_conn->event_ctx,
2073                                                dcesrv_conn->stream);
2074         if (!subreq) {
2075                 status = NT_STATUS_NO_MEMORY;
2076                 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
2077                         nt_errstr(status)));
2078                 stream_terminate_connection(srv_conn, nt_errstr(status));
2079                 return;
2080         }
2081         tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
2082
2083         return;
2084 }
2085
2086 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
2087 {
2088         struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
2089                                              struct dcesrv_connection);
2090         struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
2091         struct ncacn_packet *pkt;
2092         DATA_BLOB buffer;
2093         NTSTATUS status;
2094
2095         if (dce_conn->terminate) {
2096                 /*
2097                  * if the current connection is broken
2098                  * we need to clean it up before any other connection
2099                  */
2100                 dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
2101                 dcesrv_cleanup_broken_connections(dce_ctx);
2102                 return;
2103         }
2104
2105         dcesrv_cleanup_broken_connections(dce_ctx);
2106
2107         status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
2108                                                &pkt, &buffer);
2109         TALLOC_FREE(subreq);
2110         if (!NT_STATUS_IS_OK(status)) {
2111                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
2112                 return;
2113         }
2114
2115         status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
2116         if (!NT_STATUS_IS_OK(status)) {
2117                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
2118                 return;
2119         }
2120
2121         subreq = dcerpc_read_ncacn_packet_send(dce_conn,
2122                                                dce_conn->event_ctx,
2123                                                dce_conn->stream);
2124         if (!subreq) {
2125                 status = NT_STATUS_NO_MEMORY;
2126                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
2127                 return;
2128         }
2129         tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
2130 }
2131
2132 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
2133 {
2134         struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
2135                                              struct dcesrv_connection);
2136         dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
2137 }
2138
2139 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
2140 {
2141         struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
2142                                              struct dcesrv_connection);
2143         dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
2144 }
2145
2146
2147 static const struct stream_server_ops dcesrv_stream_ops = {
2148         .name                   = "rpc",
2149         .accept_connection      = dcesrv_sock_accept,
2150         .recv_handler           = dcesrv_sock_recv,
2151         .send_handler           = dcesrv_sock_send,
2152 };
2153
2154 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, 
2155                                    struct loadparm_context *lp_ctx,
2156                                    struct dcesrv_endpoint *e,
2157                             struct tevent_context *event_ctx, const struct model_ops *model_ops)
2158 {
2159         struct dcesrv_socket_context *dcesrv_sock;
2160         uint16_t port = 1;
2161         NTSTATUS status;
2162         const char *endpoint;
2163
2164         dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
2165         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
2166
2167         /* remember the endpoint of this socket */
2168         dcesrv_sock->endpoint           = e;
2169         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
2170
2171         endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
2172
2173         status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
2174                                      model_ops, &dcesrv_stream_ops, 
2175                                      "unix", endpoint, &port,
2176                                      lpcfg_socket_options(lp_ctx),
2177                                      dcesrv_sock);
2178         if (!NT_STATUS_IS_OK(status)) {
2179                 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
2180                          endpoint, nt_errstr(status)));
2181         }
2182
2183         return status;
2184 }
2185
2186 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, 
2187                                       struct loadparm_context *lp_ctx,
2188                                       struct dcesrv_endpoint *e,
2189                                       struct tevent_context *event_ctx, const struct model_ops *model_ops)
2190 {
2191         struct dcesrv_socket_context *dcesrv_sock;
2192         uint16_t port = 1;
2193         char *full_path;
2194         NTSTATUS status;
2195         const char *endpoint;
2196
2197         endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
2198
2199         if (endpoint == NULL) {
2200                 /*
2201                  * No identifier specified: use DEFAULT.
2202                  *
2203                  * TODO: DO NOT hardcode this value anywhere else. Rather, specify
2204                  * no endpoint and let the epmapper worry about it.
2205                  */
2206                 endpoint = "DEFAULT";
2207                 status = dcerpc_binding_set_string_option(e->ep_description,
2208                                                           "endpoint",
2209                                                           endpoint);
2210                 if (!NT_STATUS_IS_OK(status)) {
2211                         DEBUG(0,("dcerpc_binding_set_string_option() failed - %s\n",
2212                                   nt_errstr(status)));
2213                         return status;
2214                 }
2215         }
2216
2217         full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
2218                                     endpoint);
2219
2220         dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
2221         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
2222
2223         /* remember the endpoint of this socket */
2224         dcesrv_sock->endpoint           = e;
2225         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
2226
2227         status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
2228                                      model_ops, &dcesrv_stream_ops, 
2229                                      "unix", full_path, &port, 
2230                                      lpcfg_socket_options(lp_ctx),
2231                                      dcesrv_sock);
2232         if (!NT_STATUS_IS_OK(status)) {
2233                 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
2234                          endpoint, full_path, nt_errstr(status)));
2235         }
2236         return status;
2237 }
2238
2239 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
2240                                  struct loadparm_context *lp_ctx,
2241                                  struct dcesrv_endpoint *e,
2242                                  struct tevent_context *event_ctx, const struct model_ops *model_ops)
2243 {
2244         struct dcesrv_socket_context *dcesrv_sock;
2245         NTSTATUS status;
2246         const char *endpoint;
2247
2248         endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
2249         if (endpoint == NULL) {
2250                 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
2251                 return NT_STATUS_INVALID_PARAMETER;
2252         }
2253
2254         dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
2255         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
2256
2257         /* remember the endpoint of this socket */
2258         dcesrv_sock->endpoint           = e;
2259         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
2260
2261         status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
2262                                           model_ops, &dcesrv_stream_ops,
2263                                           endpoint,
2264                                           dcesrv_sock);
2265         if (!NT_STATUS_IS_OK(status)) {
2266                 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
2267                          endpoint, nt_errstr(status)));
2268                 return status;
2269         }
2270
2271         return NT_STATUS_OK;
2272 }
2273
2274 /*
2275   add a socket address to the list of events, one event per dcerpc endpoint
2276 */
2277 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
2278                                          struct tevent_context *event_ctx, const struct model_ops *model_ops,
2279                                          const char *address)
2280 {
2281         struct dcesrv_socket_context *dcesrv_sock;
2282         uint16_t port = 0;
2283         NTSTATUS status;
2284         const char *endpoint;
2285         char port_str[6];
2286
2287         endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
2288         if (endpoint != NULL) {
2289                 port = atoi(endpoint);
2290         }
2291
2292         dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
2293         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
2294
2295         /* remember the endpoint of this socket */
2296         dcesrv_sock->endpoint           = e;
2297         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
2298
2299         status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
2300                                      model_ops, &dcesrv_stream_ops, 
2301                                      "ip", address, &port,
2302                                      lpcfg_socket_options(dce_ctx->lp_ctx),
2303                                      dcesrv_sock);
2304         if (!NT_STATUS_IS_OK(status)) {
2305                 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n", 
2306                          address, port, nt_errstr(status)));
2307                 return status;
2308         }
2309
2310         snprintf(port_str, sizeof(port_str), "%u", port);
2311
2312         status = dcerpc_binding_set_string_option(e->ep_description,
2313                                                   "endpoint", port_str);
2314         if (!NT_STATUS_IS_OK(status)) {
2315                 DEBUG(0,("dcerpc_binding_set_string_option(endpoint, %s) failed - %s\n",
2316                          port_str, nt_errstr(status)));
2317                 return status;
2318         }
2319
2320         return NT_STATUS_OK;
2321 }
2322
2323 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
2324
2325 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx, 
2326                                   struct loadparm_context *lp_ctx,
2327                                   struct dcesrv_endpoint *e,
2328                                   struct tevent_context *event_ctx, const struct model_ops *model_ops)
2329 {
2330         NTSTATUS status;
2331
2332         /* Add TCP/IP sockets */
2333         if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
2334                 int num_interfaces;
2335                 int i;
2336                 struct interface *ifaces;
2337
2338                 load_interface_list(dce_ctx, lp_ctx, &ifaces);
2339
2340                 num_interfaces = iface_list_count(ifaces);
2341                 for(i = 0; i < num_interfaces; i++) {
2342                         const char *address = iface_list_n_ip(ifaces, i);
2343                         status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
2344                         NT_STATUS_NOT_OK_RETURN(status);
2345                 }
2346         } else {
2347                 char **wcard;
2348                 int i;
2349                 int num_binds = 0;
2350                 wcard = iface_list_wildcard(dce_ctx);
2351                 NT_STATUS_HAVE_NO_MEMORY(wcard);
2352                 for (i=0; wcard[i]; i++) {
2353                         status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, wcard[i]);
2354                         if (NT_STATUS_IS_OK(status)) {
2355                                 num_binds++;
2356                         }
2357                 }
2358                 talloc_free(wcard);
2359                 if (num_binds == 0) {
2360                         return NT_STATUS_INVALID_PARAMETER_MIX;
2361                 }
2362         }
2363
2364         return NT_STATUS_OK;
2365 }
2366
2367 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
2368                        struct loadparm_context *lp_ctx,
2369                        struct dcesrv_endpoint *e,
2370                        struct tevent_context *event_ctx,
2371                        const struct model_ops *model_ops)
2372 {
2373         enum dcerpc_transport_t transport =
2374                 dcerpc_binding_get_transport(e->ep_description);
2375
2376         switch (transport) {
2377         case NCACN_UNIX_STREAM:
2378                 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
2379
2380         case NCALRPC:
2381                 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
2382
2383         case NCACN_IP_TCP:
2384                 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
2385
2386         case NCACN_NP:
2387                 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
2388
2389         default:
2390                 return NT_STATUS_NOT_SUPPORTED;
2391         }
2392 }
2393
2394
2395 /**
2396  * retrieve credentials from a dce_call
2397  */
2398 _PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
2399 {
2400         return dce_call->conn->auth_state.session_info->credentials;
2401 }
2402
2403 /**
2404  * returns true if this is an authenticated call
2405  */
2406 _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
2407 {
2408         enum security_user_level level;
2409         level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
2410         return level >= SECURITY_USER;
2411 }
2412
2413 /**
2414  * retrieve account_name for a dce_call
2415  */
2416 _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
2417 {
2418         return dce_call->context->conn->auth_state.session_info->info->account_name;
2419 }