s4-rpc_server: Get the real initial uid for selftest
[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(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(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(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
412         *_p = p;
413         return NT_STATUS_OK;
414 }
415
416 /*
417   move a call from an existing linked list to the specified list. This
418   prevents bugs where we forget to remove the call from a previous
419   list when moving it.
420  */
421 static void dcesrv_call_set_list(struct dcesrv_call_state *call, 
422                                  enum dcesrv_call_list list)
423 {
424         switch (call->list) {
425         case DCESRV_LIST_NONE:
426                 break;
427         case DCESRV_LIST_CALL_LIST:
428                 DLIST_REMOVE(call->conn->call_list, call);
429                 break;
430         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
431                 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
432                 break;
433         case DCESRV_LIST_PENDING_CALL_LIST:
434                 DLIST_REMOVE(call->conn->pending_call_list, call);
435                 break;
436         }
437         call->list = list;
438         switch (list) {
439         case DCESRV_LIST_NONE:
440                 break;
441         case DCESRV_LIST_CALL_LIST:
442                 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
443                 break;
444         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
445                 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
446                 break;
447         case DCESRV_LIST_PENDING_CALL_LIST:
448                 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
449                 break;
450         }
451 }
452
453
454 /*
455   return a dcerpc bind_nak
456 */
457 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
458 {
459         struct ncacn_packet pkt;
460         struct dcerpc_bind_nak_version version;
461         struct data_blob_list_item *rep;
462         NTSTATUS status;
463
464         /* setup a bind_nak */
465         dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
466         pkt.auth_length = 0;
467         pkt.call_id = call->pkt.call_id;
468         pkt.ptype = DCERPC_PKT_BIND_NAK;
469         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
470         pkt.u.bind_nak.reject_reason = reason;
471         version.rpc_vers = 5;
472         version.rpc_vers_minor = 0;
473         pkt.u.bind_nak.num_versions = 1;
474         pkt.u.bind_nak.versions = &version;
475         pkt.u.bind_nak._pad = data_blob_null;
476
477         rep = talloc(call, struct data_blob_list_item);
478         if (!rep) {
479                 return NT_STATUS_NO_MEMORY;
480         }
481
482         status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
483         if (!NT_STATUS_IS_OK(status)) {
484                 return status;
485         }
486
487         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
488
489         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
490         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
491
492         if (call->conn->call_list && call->conn->call_list->replies) {
493                 if (call->conn->transport.report_output_data) {
494                         call->conn->transport.report_output_data(call->conn);
495                 }
496         }
497
498         return NT_STATUS_OK;    
499 }
500
501 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
502 {
503         DLIST_REMOVE(c->conn->contexts, c);
504
505         if (c->iface && c->iface->unbind) {
506                 c->iface->unbind(c, c->iface);
507                 c->iface = NULL;
508         }
509
510         return 0;
511 }
512
513 /*
514   handle a bind request
515 */
516 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
517 {
518         uint32_t if_version, transfer_syntax_version;
519         struct GUID uuid, *transfer_syntax_uuid;
520         struct ncacn_packet pkt;
521         struct data_blob_list_item *rep;
522         NTSTATUS status;
523         uint32_t result=0, reason=0;
524         uint32_t context_id;
525         const struct dcesrv_interface *iface;
526         uint32_t extra_flags = 0;
527
528         /*
529           if provided, check the assoc_group is valid
530          */
531         if (call->pkt.u.bind.assoc_group_id != 0 &&
532             lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
533             dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
534                 return dcesrv_bind_nak(call, 0);        
535         }
536
537         if (call->pkt.u.bind.num_contexts < 1 ||
538             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
539                 return dcesrv_bind_nak(call, 0);
540         }
541
542         context_id = call->pkt.u.bind.ctx_list[0].context_id;
543
544         /* you can't bind twice on one context */
545         if (dcesrv_find_context(call->conn, context_id) != NULL) {
546                 return dcesrv_bind_nak(call, 0);
547         }
548
549         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
550         uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
551
552         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
553         transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
554         if (!GUID_equal(&ndr_transfer_syntax_ndr.uuid, transfer_syntax_uuid) != 0 ||
555             ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
556                 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
557                 /* we only do NDR encoded dcerpc */
558                 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
559                 talloc_free(uuid_str);
560                 return dcesrv_bind_nak(call, 0);
561         }
562
563         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
564         if (iface == NULL) {
565                 char *uuid_str = GUID_string(call, &uuid);
566                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
567                 talloc_free(uuid_str);
568
569                 /* we don't know about that interface */
570                 result = DCERPC_BIND_PROVIDER_REJECT;
571                 reason = DCERPC_BIND_REASON_ASYNTAX;            
572         }
573
574         if (iface) {
575                 /* add this context to the list of available context_ids */
576                 struct dcesrv_connection_context *context = talloc(call->conn, 
577                                                                    struct dcesrv_connection_context);
578                 if (context == NULL) {
579                         return dcesrv_bind_nak(call, 0);
580                 }
581                 context->conn = call->conn;
582                 context->iface = iface;
583                 context->context_id = context_id;
584                 if (call->pkt.u.bind.assoc_group_id != 0) {
585                         context->assoc_group = dcesrv_assoc_group_reference(context,
586                                                                             call->conn->dce_ctx, 
587                                                                             call->pkt.u.bind.assoc_group_id);
588                 } else {
589                         context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
590                 }
591                 if (context->assoc_group == NULL) {
592                         talloc_free(context);
593                         return dcesrv_bind_nak(call, 0);
594                 }
595                 context->private_data = NULL;
596                 DLIST_ADD(call->conn->contexts, context);
597                 call->context = context;
598                 talloc_set_destructor(context, dcesrv_connection_context_destructor);
599
600                 status = iface->bind(call, iface, if_version);
601                 if (!NT_STATUS_IS_OK(status)) {
602                         char *uuid_str = GUID_string(call, &uuid);
603                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
604                                  uuid_str, if_version, nt_errstr(status)));
605                         talloc_free(uuid_str);
606                         /* we don't want to trigger the iface->unbind() hook */
607                         context->iface = NULL;
608                         talloc_free(call->context);
609                         call->context = NULL;
610                         return dcesrv_bind_nak(call, 0);
611                 }
612         }
613
614         if (call->conn->cli_max_recv_frag == 0) {
615                 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
616         }
617
618         if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
619             (call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
620                 call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
621                 extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
622         }
623
624         if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
625                 call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
626         }
627
628         /* handle any authentication that is being requested */
629         if (!dcesrv_auth_bind(call)) {
630                 talloc_free(call->context);
631                 call->context = NULL;
632                 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
633         }
634
635         /* setup a bind_ack */
636         dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
637         pkt.auth_length = 0;
638         pkt.call_id = call->pkt.call_id;
639         pkt.ptype = DCERPC_PKT_BIND_ACK;
640         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
641         pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
642         pkt.u.bind_ack.max_recv_frag = 0x2000;
643
644         /*
645           make it possible for iface->bind() to specify the assoc_group_id
646           This helps the openchange mapiproxy plugin to work correctly.
647           
648           metze
649         */
650         if (call->context) {
651                 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
652         } else {
653                 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
654         }
655
656         if (iface) {
657                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
658                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
659         } else {
660                 pkt.u.bind_ack.secondary_address = "";
661         }
662         pkt.u.bind_ack.num_results = 1;
663         pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
664         if (!pkt.u.bind_ack.ctx_list) {
665                 talloc_free(call->context);
666                 call->context = NULL;
667                 return NT_STATUS_NO_MEMORY;
668         }
669         pkt.u.bind_ack.ctx_list[0].result = result;
670         pkt.u.bind_ack.ctx_list[0].reason.value = reason;
671         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
672         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
673
674         status = dcesrv_auth_bind_ack(call, &pkt);
675         if (!NT_STATUS_IS_OK(status)) {
676                 talloc_free(call->context);
677                 call->context = NULL;
678                 return dcesrv_bind_nak(call, 0);
679         }
680
681         rep = talloc(call, struct data_blob_list_item);
682         if (!rep) {
683                 talloc_free(call->context);
684                 call->context = NULL;
685                 return NT_STATUS_NO_MEMORY;
686         }
687
688         status = ncacn_push_auth(&rep->blob, call, &pkt,
689                                                          call->conn->auth_state.auth_info);
690         if (!NT_STATUS_IS_OK(status)) {
691                 talloc_free(call->context);
692                 call->context = NULL;
693                 return status;
694         }
695
696         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
697
698         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
699         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
700
701         if (call->conn->call_list && call->conn->call_list->replies) {
702                 if (call->conn->transport.report_output_data) {
703                         call->conn->transport.report_output_data(call->conn);
704                 }
705         }
706
707         return NT_STATUS_OK;
708 }
709
710
711 /*
712   handle a auth3 request
713 */
714 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
715 {
716         /* handle the auth3 in the auth code */
717         if (!dcesrv_auth_auth3(call)) {
718                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
719         }
720
721         talloc_free(call);
722
723         /* we don't send a reply to a auth3 request, except by a
724            fault */
725         return NT_STATUS_OK;
726 }
727
728
729 /*
730   handle a bind request
731 */
732 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
733 {
734         uint32_t if_version, transfer_syntax_version;
735         struct dcesrv_connection_context *context;
736         const struct dcesrv_interface *iface;
737         struct GUID uuid, *transfer_syntax_uuid;
738         NTSTATUS status;
739
740         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
741         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
742
743         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
744         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
745         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax_ndr.uuid) ||
746             ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
747                 /* we only do NDR encoded dcerpc */
748                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
749         }
750
751         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
752         if (iface == NULL) {
753                 char *uuid_str = GUID_string(call, &uuid);
754                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
755                 talloc_free(uuid_str);
756                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
757         }
758
759         /* add this context to the list of available context_ids */
760         context = talloc(call->conn, struct dcesrv_connection_context);
761         if (context == NULL) {
762                 return NT_STATUS_NO_MEMORY;
763         }
764         context->conn = call->conn;
765         context->iface = iface;
766         context->context_id = context_id;
767         if (call->pkt.u.alter.assoc_group_id != 0) {
768                 context->assoc_group = dcesrv_assoc_group_reference(context,
769                                                                     call->conn->dce_ctx, 
770                                                                     call->pkt.u.alter.assoc_group_id);
771         } else {
772                 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
773         }
774         if (context->assoc_group == NULL) {
775                 talloc_free(context);
776                 call->context = NULL;
777                 return NT_STATUS_NO_MEMORY;
778         }
779         context->private_data = NULL;
780         DLIST_ADD(call->conn->contexts, context);
781         call->context = context;
782         talloc_set_destructor(context, dcesrv_connection_context_destructor);
783
784         status = iface->bind(call, iface, if_version);
785         if (!NT_STATUS_IS_OK(status)) {
786                 /* we don't want to trigger the iface->unbind() hook */
787                 context->iface = NULL;
788                 talloc_free(context);
789                 call->context = NULL;
790                 return status;
791         }
792
793         return NT_STATUS_OK;
794 }
795
796 /* setup and send an alter_resp */
797 static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call,
798                                 uint32_t result,
799                                 uint32_t reason)
800 {
801         struct ncacn_packet pkt;
802         uint32_t extra_flags = 0;
803         struct data_blob_list_item *rep = NULL;
804         NTSTATUS status;
805
806         dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
807         pkt.auth_length = 0;
808         pkt.call_id = call->pkt.call_id;
809         pkt.ptype = DCERPC_PKT_ALTER_RESP;
810         if (result == 0) {
811                 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
812                                 call->context->conn->state_flags &
813                                         DCESRV_CALL_STATE_FLAG_MULTIPLEXED) {
814                         extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
815                 }
816                 if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
817                         call->context->conn->state_flags |=
818                                 DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
819                 }
820         }
821         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
822         pkt.u.alter_resp.max_xmit_frag = 0x2000;
823         pkt.u.alter_resp.max_recv_frag = 0x2000;
824         if (result == 0) {
825                 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
826         } else {
827                 pkt.u.alter_resp.assoc_group_id = 0;
828         }
829         pkt.u.alter_resp.num_results = 1;
830         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
831         if (!pkt.u.alter_resp.ctx_list) {
832                 return NT_STATUS_NO_MEMORY;
833         }
834         pkt.u.alter_resp.ctx_list[0].result = result;
835         pkt.u.alter_resp.ctx_list[0].reason.value = reason;
836         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
837         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
838         pkt.u.alter_resp.secondary_address = "";
839
840         status = dcesrv_auth_alter_ack(call, &pkt);
841         if (!NT_STATUS_IS_OK(status)) {
842                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
843                     || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
844                     || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
845                     || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
846                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
847                 }
848                 return dcesrv_fault(call, 0);
849         }
850
851         rep = talloc(call, struct data_blob_list_item);
852         if (!rep) {
853                 return NT_STATUS_NO_MEMORY;
854         }
855
856         status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
857         if (!NT_STATUS_IS_OK(status)) {
858                 return status;
859         }
860
861         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
862
863         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
864         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
865
866         if (call->conn->call_list && call->conn->call_list->replies) {
867                 if (call->conn->transport.report_output_data) {
868                         call->conn->transport.report_output_data(call->conn);
869                 }
870         }
871
872         return NT_STATUS_OK;
873 }
874
875 /*
876   handle a alter context request
877 */
878 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
879 {
880         NTSTATUS status;
881         uint32_t context_id;
882
883         /* handle any authentication that is being requested */
884         if (!dcesrv_auth_alter(call)) {
885                 /* TODO: work out the right reject code */
886                 return dcesrv_alter_resp(call,
887                                 DCERPC_BIND_PROVIDER_REJECT,
888                                 DCERPC_BIND_REASON_ASYNTAX);
889         }
890
891         context_id = call->pkt.u.alter.ctx_list[0].context_id;
892
893         /* see if they are asking for a new interface */
894         call->context = dcesrv_find_context(call->conn, context_id);
895         if (!call->context) {
896                 status = dcesrv_alter_new_context(call, context_id);
897                 if (!NT_STATUS_IS_OK(status)) {
898                         return dcesrv_alter_resp(call,
899                                 DCERPC_BIND_PROVIDER_REJECT,
900                                 DCERPC_BIND_REASON_ASYNTAX);
901                 }
902         }
903
904         if (call->pkt.u.alter.assoc_group_id != 0 &&
905             lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
906             call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
907                 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
908                          call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
909                 /* TODO: can they ask for a new association group? */
910                 return dcesrv_alter_resp(call,
911                                 DCERPC_BIND_PROVIDER_REJECT,
912                                 DCERPC_BIND_REASON_ASYNTAX);
913         }
914
915         return dcesrv_alter_resp(call,
916                                 DCERPC_BIND_ACK_RESULT_ACCEPTANCE,
917                                 DCERPC_BIND_ACK_REASON_NOT_SPECIFIED);
918 }
919
920 /*
921   possibly save the call for inspection with ndrdump
922  */
923 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
924 {
925 #ifdef DEVELOPER
926         char *fname;
927         const char *dump_dir;
928         dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
929         if (!dump_dir) {
930                 return;
931         }
932         fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
933                                 dump_dir,
934                                 call->context->iface->name,
935                                 call->pkt.u.request.opnum,
936                                 why);
937         if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
938                 DEBUG(0,("RPC SAVED %s\n", fname));
939         }
940         talloc_free(fname);
941 #endif
942 }
943
944 static NTSTATUS dcesrv_check_verification_trailer(struct dcesrv_call_state *call)
945 {
946         TALLOC_CTX *frame = talloc_stackframe();
947         const uint32_t bitmask1 = call->conn->auth_state.client_hdr_signing ?
948                 DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING : 0;
949         const struct dcerpc_sec_vt_pcontext pcontext = {
950                 .abstract_syntax = call->context->iface->syntax_id,
951                 .transfer_syntax = ndr_transfer_syntax_ndr,
952         };
953         const struct dcerpc_sec_vt_header2 header2 =
954                 dcerpc_sec_vt_header2_from_ncacn_packet(&call->pkt);
955         enum ndr_err_code ndr_err;
956         struct dcerpc_sec_verification_trailer *vt = NULL;
957         NTSTATUS status = NT_STATUS_OK;
958         bool ok;
959
960         SMB_ASSERT(call->pkt.ptype == DCERPC_PKT_REQUEST);
961
962         ndr_err = ndr_pop_dcerpc_sec_verification_trailer(call->ndr_pull,
963                                                           frame, &vt);
964         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
965                 status = ndr_map_error2ntstatus(ndr_err);
966                 goto done;
967         }
968
969         ok = dcerpc_sec_verification_trailer_check(vt, &bitmask1,
970                                                    &pcontext, &header2);
971         if (!ok) {
972                 status = NT_STATUS_ACCESS_DENIED;
973                 goto done;
974         }
975 done:
976         TALLOC_FREE(frame);
977         return status;
978 }
979
980 /*
981   handle a dcerpc request packet
982 */
983 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
984 {
985         struct ndr_pull *pull;
986         NTSTATUS status;
987         struct dcesrv_connection_context *context;
988
989         /* if authenticated, and the mech we use can't do async replies, don't use them... */
990         if (call->conn->auth_state.gensec_security && 
991             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
992                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
993         }
994
995         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
996         if (context == NULL) {
997                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
998         }
999
1000         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
1001         NT_STATUS_HAVE_NO_MEMORY(pull);
1002
1003         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1004
1005         call->context   = context;
1006         call->ndr_pull  = pull;
1007
1008         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
1009                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1010         }
1011
1012         status = dcesrv_check_verification_trailer(call);
1013         if (!NT_STATUS_IS_OK(status)) {
1014                 uint32_t faultcode = DCERPC_FAULT_OTHER;
1015                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1016                         faultcode = DCERPC_FAULT_ACCESS_DENIED;
1017                 }
1018                 DEBUG(10, ("dcesrv_check_verification_trailer failed: %s\n",
1019                            nt_errstr(status)));
1020                 return dcesrv_fault(call, faultcode);
1021         }
1022
1023         /* unravel the NDR for the packet */
1024         status = context->iface->ndr_pull(call, call, pull, &call->r);
1025         if (!NT_STATUS_IS_OK(status)) {
1026                 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
1027                         /* we got an unknown call */
1028                         DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
1029                                  call->pkt.u.request.opnum, context->iface->name));
1030                         dcesrv_save_call(call, "unknown");
1031                 } else {
1032                         dcesrv_save_call(call, "pullfail");
1033                 }
1034                 return dcesrv_fault(call, call->fault_code);
1035         }
1036
1037         if (pull->offset != pull->data_size) {
1038                 dcesrv_save_call(call, "extrabytes");
1039                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
1040                          pull->data_size - pull->offset));
1041         }
1042
1043         /* call the dispatch function */
1044         status = context->iface->dispatch(call, call, call->r);
1045         if (!NT_STATUS_IS_OK(status)) {
1046                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1047                          context->iface->name, 
1048                          call->pkt.u.request.opnum,
1049                          dcerpc_errstr(pull, call->fault_code)));
1050                 return dcesrv_fault(call, call->fault_code);
1051         }
1052
1053         /* add the call to the pending list */
1054         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1055
1056         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1057                 return NT_STATUS_OK;
1058         }
1059
1060         return dcesrv_reply(call);
1061 }
1062
1063
1064 /*
1065   remove the call from the right list when freed
1066  */
1067 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1068 {
1069         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1070         return 0;
1071 }
1072
1073 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1074 {
1075         return conn->local_address;
1076 }
1077
1078 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1079 {
1080         return conn->remote_address;
1081 }
1082
1083 /*
1084   process some input to a dcerpc endpoint server.
1085 */
1086 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1087                                      struct ncacn_packet *pkt,
1088                                      DATA_BLOB blob)
1089 {
1090         NTSTATUS status;
1091         struct dcesrv_call_state *call;
1092
1093         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1094         if (!call) {
1095                 data_blob_free(&blob);
1096                 talloc_free(pkt);
1097                 return NT_STATUS_NO_MEMORY;
1098         }
1099         call->conn              = dce_conn;
1100         call->event_ctx         = dce_conn->event_ctx;
1101         call->msg_ctx           = dce_conn->msg_ctx;
1102         call->state_flags       = call->conn->state_flags;
1103         call->time              = timeval_current();
1104         call->list              = DCESRV_LIST_NONE;
1105
1106         talloc_steal(call, pkt);
1107         talloc_steal(call, blob.data);
1108         call->pkt = *pkt;
1109
1110         talloc_set_destructor(call, dcesrv_call_dequeue);
1111
1112         /* we have to check the signing here, before combining the
1113            pdus */
1114         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1115             !dcesrv_auth_request(call, &blob)) {
1116                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1117         }
1118
1119         /* see if this is a continued packet */
1120         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1121             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1122                 struct dcesrv_call_state *call2 = call;
1123                 uint32_t alloc_size;
1124
1125                 /* we only allow fragmented requests, no other packet types */
1126                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1127                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1128                 }
1129
1130                 /* this is a continuation of an existing call - find the call
1131                    then tack it on the end */
1132                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1133                 if (!call) {
1134                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1135                 }
1136
1137                 if (call->pkt.ptype != call2->pkt.ptype) {
1138                         /* trying to play silly buggers are we? */
1139                         return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1140                 }
1141                 if (memcmp(call->pkt.drep, call2->pkt.drep, sizeof(pkt->drep)) != 0) {
1142                         return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1143                 }
1144                 if (call->pkt.call_id != call2->pkt.call_id) {
1145                         return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1146                 }
1147                 if (call->pkt.u.request.context_id != call2->pkt.u.request.context_id)  {
1148                         return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1149                 }
1150                 if (call->pkt.u.request.opnum != call2->pkt.u.request.opnum)  {
1151                         return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1152                 }
1153
1154                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1155                         call2->pkt.u.request.stub_and_verifier.length;
1156                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1157                         alloc_size = call->pkt.u.request.alloc_hint;
1158                 }
1159
1160                 call->pkt.u.request.stub_and_verifier.data = 
1161                         talloc_realloc(call, 
1162                                        call->pkt.u.request.stub_and_verifier.data, 
1163                                        uint8_t, alloc_size);
1164                 if (!call->pkt.u.request.stub_and_verifier.data) {
1165                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1166                 }
1167                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1168                        call->pkt.u.request.stub_and_verifier.length,
1169                        call2->pkt.u.request.stub_and_verifier.data,
1170                        call2->pkt.u.request.stub_and_verifier.length);
1171                 call->pkt.u.request.stub_and_verifier.length += 
1172                         call2->pkt.u.request.stub_and_verifier.length;
1173
1174                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1175
1176                 talloc_free(call2);
1177         }
1178
1179         /* this may not be the last pdu in the chain - if its isn't then
1180            just put it on the incoming_fragmented_call_list and wait for the rest */
1181         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1182             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1183                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1184                 return NT_STATUS_OK;
1185         } 
1186         
1187         /* This removes any fragments we may have had stashed away */
1188         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1189
1190         switch (call->pkt.ptype) {
1191         case DCERPC_PKT_BIND:
1192                 status = dcesrv_bind(call);
1193                 break;
1194         case DCERPC_PKT_AUTH3:
1195                 status = dcesrv_auth3(call);
1196                 break;
1197         case DCERPC_PKT_ALTER:
1198                 status = dcesrv_alter(call);
1199                 break;
1200         case DCERPC_PKT_REQUEST:
1201                 status = dcesrv_request(call);
1202                 break;
1203         default:
1204                 status = NT_STATUS_INVALID_PARAMETER;
1205                 break;
1206         }
1207
1208         /* if we are going to be sending a reply then add
1209            it to the list of pending calls. We add it to the end to keep the call
1210            list in the order we will answer */
1211         if (!NT_STATUS_IS_OK(status)) {
1212                 talloc_free(call);
1213         }
1214
1215         return status;
1216 }
1217
1218 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1219                                       struct loadparm_context *lp_ctx,
1220                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1221 {
1222         NTSTATUS status;
1223         struct dcesrv_context *dce_ctx;
1224         int i;
1225
1226         if (!endpoint_servers) {
1227                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1228                 return NT_STATUS_INTERNAL_ERROR;
1229         }
1230
1231         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1232         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1233
1234         if (uid_wrapper_enabled()) {
1235                 setenv("UID_WRAPPER_MYUID", "1", 1);
1236         }
1237         dce_ctx->initial_euid = geteuid();
1238         if (uid_wrapper_enabled()) {
1239                 unsetenv("UID_WRAPPER_MYUID");
1240         }
1241
1242         dce_ctx->endpoint_list  = NULL;
1243         dce_ctx->lp_ctx = lp_ctx;
1244         dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1245         NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1246         dce_ctx->broken_connections = NULL;
1247
1248         for (i=0;endpoint_servers[i];i++) {
1249                 const struct dcesrv_endpoint_server *ep_server;
1250
1251                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1252                 if (!ep_server) {
1253                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1254                         return NT_STATUS_INTERNAL_ERROR;
1255                 }
1256
1257                 status = ep_server->init_server(dce_ctx, ep_server);
1258                 if (!NT_STATUS_IS_OK(status)) {
1259                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1260                                 nt_errstr(status)));
1261                         return status;
1262                 }
1263         }
1264
1265         *_dce_ctx = dce_ctx;
1266         return NT_STATUS_OK;
1267 }
1268
1269 /* the list of currently registered DCERPC endpoint servers.
1270  */
1271 static struct ep_server {
1272         struct dcesrv_endpoint_server *ep_server;
1273 } *ep_servers = NULL;
1274 static int num_ep_servers;
1275
1276 /*
1277   register a DCERPC endpoint server. 
1278
1279   The 'name' can be later used by other backends to find the operations
1280   structure for this backend.  
1281
1282   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1283 */
1284 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1285 {
1286         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1287         
1288         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1289                 /* its already registered! */
1290                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1291                          ep_server->name));
1292                 return NT_STATUS_OBJECT_NAME_COLLISION;
1293         }
1294
1295         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1296         if (!ep_servers) {
1297                 smb_panic("out of memory in dcerpc_register");
1298         }
1299
1300         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1301         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1302
1303         num_ep_servers++;
1304
1305         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1306                  ep_server->name));
1307
1308         return NT_STATUS_OK;
1309 }
1310
1311 /*
1312   return the operations structure for a named backend of the specified type
1313 */
1314 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1315 {
1316         int i;
1317
1318         for (i=0;i<num_ep_servers;i++) {
1319                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1320                         return ep_servers[i].ep_server;
1321                 }
1322         }
1323
1324         return NULL;
1325 }
1326
1327 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1328 {
1329         static bool initialized;
1330 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1331         STATIC_dcerpc_server_MODULES_PROTO;
1332         init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1333         init_module_fn *shared_init;
1334
1335         if (initialized) {
1336                 return;
1337         }
1338         initialized = true;
1339
1340         shared_init = load_samba_modules(NULL, "dcerpc_server");
1341
1342         run_init_functions(static_init);
1343         run_init_functions(shared_init);
1344
1345         talloc_free(shared_init);
1346 }
1347
1348 /*
1349   return the DCERPC module version, and the size of some critical types
1350   This can be used by endpoint server modules to either detect compilation errors, or provide
1351   multiple implementations for different smbd compilation options in one module
1352 */
1353 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1354 {
1355         static const struct dcesrv_critical_sizes critical_sizes = {
1356                 DCERPC_MODULE_VERSION,
1357                 sizeof(struct dcesrv_context),
1358                 sizeof(struct dcesrv_endpoint),
1359                 sizeof(struct dcesrv_endpoint_server),
1360                 sizeof(struct dcesrv_interface),
1361                 sizeof(struct dcesrv_if_list),
1362                 sizeof(struct dcesrv_connection),
1363                 sizeof(struct dcesrv_call_state),
1364                 sizeof(struct dcesrv_auth),
1365                 sizeof(struct dcesrv_handle)
1366         };
1367
1368         return &critical_sizes;
1369 }
1370
1371 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1372 {
1373         struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1374         struct stream_connection *srv_conn;
1375         srv_conn = talloc_get_type(dce_conn->transport.private_data,
1376                                    struct stream_connection);
1377
1378         if (dce_conn->pending_call_list == NULL) {
1379                 char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
1380
1381                 DLIST_REMOVE(dce_ctx->broken_connections, dce_conn);
1382                 stream_terminate_connection(srv_conn, full_reason ? full_reason : reason);
1383                 return;
1384         }
1385
1386         if (dce_conn->terminate != NULL) {
1387                 return;
1388         }
1389
1390         DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1391                  reason));
1392         dce_conn->terminate = talloc_strdup(dce_conn, reason);
1393         if (dce_conn->terminate == NULL) {
1394                 dce_conn->terminate = "dcesrv: defered terminating connection - no memory";
1395         }
1396         DLIST_ADD_END(dce_ctx->broken_connections, dce_conn, NULL);
1397 }
1398
1399 static void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx)
1400 {
1401         struct dcesrv_connection *cur, *next;
1402
1403         next = dce_ctx->broken_connections;
1404         while (next != NULL) {
1405                 cur = next;
1406                 next = cur->next;
1407
1408                 if (cur->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
1409                         struct dcesrv_connection_context *context_cur, *context_next;
1410
1411                         context_next = cur->contexts;
1412                         while (context_next != NULL) {
1413                                 context_cur = context_next;
1414                                 context_next = context_cur->next;
1415
1416                                 dcesrv_connection_context_destructor(context_cur);
1417                         }
1418                 }
1419
1420                 dcesrv_terminate_connection(cur, cur->terminate);
1421         }
1422 }
1423
1424 /* We need this include to be able to compile on some plateforms
1425  * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1426  * correctly.
1427  * It has to be that deep because otherwise we have a conflict on
1428  * const struct dcesrv_interface declaration.
1429  * This is mostly due to socket_wrapper defining #define bind swrap_bind
1430  * which conflict with the bind used before.
1431  */
1432 #include "system/network.h"
1433
1434 struct dcesrv_sock_reply_state {
1435         struct dcesrv_connection *dce_conn;
1436         struct dcesrv_call_state *call;
1437         struct iovec iov;
1438 };
1439
1440 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1441
1442 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1443 {
1444         struct dcesrv_call_state *call;
1445
1446         call = dce_conn->call_list;
1447         if (!call || !call->replies) {
1448                 return;
1449         }
1450
1451         while (call->replies) {
1452                 struct data_blob_list_item *rep = call->replies;
1453                 struct dcesrv_sock_reply_state *substate;
1454                 struct tevent_req *subreq;
1455
1456                 substate = talloc(call, struct dcesrv_sock_reply_state);
1457                 if (!substate) {
1458                         dcesrv_terminate_connection(dce_conn, "no memory");
1459                         return;
1460                 }
1461
1462                 substate->dce_conn = dce_conn;
1463                 substate->call = NULL;
1464
1465                 DLIST_REMOVE(call->replies, rep);
1466
1467                 if (call->replies == NULL) {
1468                         substate->call = call;
1469                 }
1470
1471                 substate->iov.iov_base = (void *) rep->blob.data;
1472                 substate->iov.iov_len = rep->blob.length;
1473
1474                 subreq = tstream_writev_queue_send(substate,
1475                                                    dce_conn->event_ctx,
1476                                                    dce_conn->stream,
1477                                                    dce_conn->send_queue,
1478                                                    &substate->iov, 1);
1479                 if (!subreq) {
1480                         dcesrv_terminate_connection(dce_conn, "no memory");
1481                         return;
1482                 }
1483                 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1484                                         substate);
1485         }
1486
1487         DLIST_REMOVE(call->conn->call_list, call);
1488         call->list = DCESRV_LIST_NONE;
1489 }
1490
1491 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1492 {
1493         struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1494                                                 struct dcesrv_sock_reply_state);
1495         int ret;
1496         int sys_errno;
1497         NTSTATUS status;
1498         struct dcesrv_call_state *call = substate->call;
1499
1500         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1501         TALLOC_FREE(subreq);
1502         if (ret == -1) {
1503                 status = map_nt_error_from_unix_common(sys_errno);
1504                 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1505                 return;
1506         }
1507
1508         talloc_free(substate);
1509         if (call) {
1510                 talloc_free(call);
1511         }
1512 }
1513
1514
1515
1516
1517 struct dcesrv_socket_context {
1518         const struct dcesrv_endpoint *endpoint;
1519         struct dcesrv_context *dcesrv_ctx;
1520 };
1521
1522
1523 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1524
1525 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1526 {
1527         NTSTATUS status;
1528         struct dcesrv_socket_context *dcesrv_sock = 
1529                 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1530         enum dcerpc_transport_t transport =
1531                 dcerpc_binding_get_transport(dcesrv_sock->endpoint->ep_description);
1532         struct dcesrv_connection *dcesrv_conn = NULL;
1533         int ret;
1534         struct tevent_req *subreq;
1535         struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1536
1537         dcesrv_cleanup_broken_connections(dcesrv_sock->dcesrv_ctx);
1538
1539         if (!srv_conn->session_info) {
1540                 status = auth_anonymous_session_info(srv_conn,
1541                                                      lp_ctx,
1542                                                      &srv_conn->session_info);
1543                 if (!NT_STATUS_IS_OK(status)) {
1544                         DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1545                                 nt_errstr(status)));
1546                         stream_terminate_connection(srv_conn, nt_errstr(status));
1547                         return;
1548                 }
1549         }
1550
1551         status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1552                                          srv_conn,
1553                                          dcesrv_sock->endpoint,
1554                                          srv_conn->session_info,
1555                                          srv_conn->event.ctx,
1556                                          srv_conn->msg_ctx,
1557                                          srv_conn->server_id,
1558                                          DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1559                                          &dcesrv_conn);
1560         if (!NT_STATUS_IS_OK(status)) {
1561                 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", 
1562                         nt_errstr(status)));
1563                 stream_terminate_connection(srv_conn, nt_errstr(status));
1564                 return;
1565         }
1566
1567         dcesrv_conn->transport.private_data             = srv_conn;
1568         dcesrv_conn->transport.report_output_data       = dcesrv_sock_report_output_data;
1569
1570         TALLOC_FREE(srv_conn->event.fde);
1571
1572         dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1573         if (!dcesrv_conn->send_queue) {
1574                 status = NT_STATUS_NO_MEMORY;
1575                 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1576                         nt_errstr(status)));
1577                 stream_terminate_connection(srv_conn, nt_errstr(status));
1578                 return;
1579         }
1580
1581         if (transport == NCACN_NP) {
1582                 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1583                 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1584                                                   &srv_conn->tstream);
1585         } else {
1586                 ret = tstream_bsd_existing_socket(dcesrv_conn,
1587                                                   socket_get_fd(srv_conn->socket),
1588                                                   &dcesrv_conn->stream);
1589                 if (ret == -1) {
1590                         status = map_nt_error_from_unix_common(errno);
1591                         DEBUG(0, ("dcesrv_sock_accept: "
1592                                   "failed to setup tstream: %s\n",
1593                                   nt_errstr(status)));
1594                         stream_terminate_connection(srv_conn, nt_errstr(status));
1595                         return;
1596                 }
1597                 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1598         }
1599
1600         dcesrv_conn->local_address = srv_conn->local_address;
1601         dcesrv_conn->remote_address = srv_conn->remote_address;
1602
1603         if (transport == NCALRPC) {
1604                 uid_t uid;
1605                 gid_t gid;
1606
1607                 ret = getpeereid(socket_get_fd(srv_conn->socket), &uid, &gid);
1608                 if (ret == -1) {
1609                         status = map_nt_error_from_unix_common(errno);
1610                         DEBUG(0, ("dcesrv_sock_accept: "
1611                                   "getpeereid() failed for NCALRPC: %s\n",
1612                                   nt_errstr(status)));
1613                         stream_terminate_connection(srv_conn, nt_errstr(status));
1614                         return;
1615                 }
1616                 if (uid == dcesrv_conn->dce_ctx->initial_euid) {
1617                         struct tsocket_address *r = NULL;
1618
1619                         ret = tsocket_address_unix_from_path(dcesrv_conn,
1620                                                              "/root/ncalrpc_as_system",
1621                                                              &r);
1622                         if (ret == -1) {
1623                                 status = map_nt_error_from_unix_common(errno);
1624                                 DEBUG(0, ("dcesrv_sock_accept: "
1625                                           "tsocket_address_unix_from_path() failed for NCALRPC: %s\n",
1626                                           nt_errstr(status)));
1627                                 stream_terminate_connection(srv_conn, nt_errstr(status));
1628                                 return;
1629                         }
1630                         dcesrv_conn->remote_address = r;
1631                 }
1632         }
1633
1634         srv_conn->private_data = dcesrv_conn;
1635
1636         irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1637
1638         subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1639                                                dcesrv_conn->event_ctx,
1640                                                dcesrv_conn->stream);
1641         if (!subreq) {
1642                 status = NT_STATUS_NO_MEMORY;
1643                 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1644                         nt_errstr(status)));
1645                 stream_terminate_connection(srv_conn, nt_errstr(status));
1646                 return;
1647         }
1648         tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1649
1650         return;
1651 }
1652
1653 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1654 {
1655         struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1656                                              struct dcesrv_connection);
1657         struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1658         struct ncacn_packet *pkt;
1659         DATA_BLOB buffer;
1660         NTSTATUS status;
1661
1662         if (dce_conn->terminate) {
1663                 /*
1664                  * if the current connection is broken
1665                  * we need to clean it up before any other connection
1666                  */
1667                 dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
1668                 dcesrv_cleanup_broken_connections(dce_ctx);
1669                 return;
1670         }
1671
1672         dcesrv_cleanup_broken_connections(dce_ctx);
1673
1674         status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1675                                                &pkt, &buffer);
1676         TALLOC_FREE(subreq);
1677         if (!NT_STATUS_IS_OK(status)) {
1678                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1679                 return;
1680         }
1681
1682         status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1683         if (!NT_STATUS_IS_OK(status)) {
1684                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1685                 return;
1686         }
1687
1688         subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1689                                                dce_conn->event_ctx,
1690                                                dce_conn->stream);
1691         if (!subreq) {
1692                 status = NT_STATUS_NO_MEMORY;
1693                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1694                 return;
1695         }
1696         tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1697 }
1698
1699 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1700 {
1701         struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1702                                              struct dcesrv_connection);
1703         dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1704 }
1705
1706 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1707 {
1708         struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1709                                              struct dcesrv_connection);
1710         dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1711 }
1712
1713
1714 static const struct stream_server_ops dcesrv_stream_ops = {
1715         .name                   = "rpc",
1716         .accept_connection      = dcesrv_sock_accept,
1717         .recv_handler           = dcesrv_sock_recv,
1718         .send_handler           = dcesrv_sock_send,
1719 };
1720
1721 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, 
1722                                    struct loadparm_context *lp_ctx,
1723                                    struct dcesrv_endpoint *e,
1724                             struct tevent_context *event_ctx, const struct model_ops *model_ops)
1725 {
1726         struct dcesrv_socket_context *dcesrv_sock;
1727         uint16_t port = 1;
1728         NTSTATUS status;
1729         const char *endpoint;
1730
1731         dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1732         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1733
1734         /* remember the endpoint of this socket */
1735         dcesrv_sock->endpoint           = e;
1736         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
1737
1738         endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1739
1740         status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1741                                      model_ops, &dcesrv_stream_ops, 
1742                                      "unix", endpoint, &port,
1743                                      lpcfg_socket_options(lp_ctx),
1744                                      dcesrv_sock);
1745         if (!NT_STATUS_IS_OK(status)) {
1746                 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1747                          endpoint, nt_errstr(status)));
1748         }
1749
1750         return status;
1751 }
1752
1753 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, 
1754                                       struct loadparm_context *lp_ctx,
1755                                       struct dcesrv_endpoint *e,
1756                                       struct tevent_context *event_ctx, const struct model_ops *model_ops)
1757 {
1758         struct dcesrv_socket_context *dcesrv_sock;
1759         uint16_t port = 1;
1760         char *full_path;
1761         NTSTATUS status;
1762         const char *endpoint;
1763
1764         endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1765
1766         if (endpoint == NULL) {
1767                 /*
1768                  * No identifier specified: use DEFAULT.
1769                  *
1770                  * TODO: DO NOT hardcode this value anywhere else. Rather, specify
1771                  * no endpoint and let the epmapper worry about it.
1772                  */
1773                 endpoint = "DEFAULT";
1774                 status = dcerpc_binding_set_string_option(e->ep_description,
1775                                                           "endpoint",
1776                                                           endpoint);
1777                 if (!NT_STATUS_IS_OK(status)) {
1778                         DEBUG(0,("dcerpc_binding_set_string_option() failed - %s\n",
1779                                   nt_errstr(status)));
1780                         return status;
1781                 }
1782         }
1783
1784         full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1785                                     endpoint);
1786
1787         dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1788         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1789
1790         /* remember the endpoint of this socket */
1791         dcesrv_sock->endpoint           = e;
1792         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
1793
1794         status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1795                                      model_ops, &dcesrv_stream_ops, 
1796                                      "unix", full_path, &port, 
1797                                      lpcfg_socket_options(lp_ctx),
1798                                      dcesrv_sock);
1799         if (!NT_STATUS_IS_OK(status)) {
1800                 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1801                          endpoint, full_path, nt_errstr(status)));
1802         }
1803         return status;
1804 }
1805
1806 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1807                                  struct loadparm_context *lp_ctx,
1808                                  struct dcesrv_endpoint *e,
1809                                  struct tevent_context *event_ctx, const struct model_ops *model_ops)
1810 {
1811         struct dcesrv_socket_context *dcesrv_sock;
1812         NTSTATUS status;
1813         const char *endpoint;
1814
1815         endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1816         if (endpoint == NULL) {
1817                 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1818                 return NT_STATUS_INVALID_PARAMETER;
1819         }
1820
1821         dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1822         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1823
1824         /* remember the endpoint of this socket */
1825         dcesrv_sock->endpoint           = e;
1826         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
1827
1828         status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
1829                                           model_ops, &dcesrv_stream_ops,
1830                                           endpoint,
1831                                           dcesrv_sock);
1832         if (!NT_STATUS_IS_OK(status)) {
1833                 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1834                          endpoint, nt_errstr(status)));
1835                 return status;
1836         }
1837
1838         return NT_STATUS_OK;
1839 }
1840
1841 /*
1842   add a socket address to the list of events, one event per dcerpc endpoint
1843 */
1844 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
1845                                          struct tevent_context *event_ctx, const struct model_ops *model_ops,
1846                                          const char *address)
1847 {
1848         struct dcesrv_socket_context *dcesrv_sock;
1849         uint16_t port = 0;
1850         NTSTATUS status;
1851         const char *endpoint;
1852         char port_str[6];
1853
1854         endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1855         if (endpoint != NULL) {
1856                 port = atoi(endpoint);
1857         }
1858
1859         dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1860         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1861
1862         /* remember the endpoint of this socket */
1863         dcesrv_sock->endpoint           = e;
1864         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
1865
1866         status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
1867                                      model_ops, &dcesrv_stream_ops, 
1868                                      "ip", address, &port,
1869                                      lpcfg_socket_options(dce_ctx->lp_ctx),
1870                                      dcesrv_sock);
1871         if (!NT_STATUS_IS_OK(status)) {
1872                 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n", 
1873                          address, port, nt_errstr(status)));
1874                 return status;
1875         }
1876
1877         snprintf(port_str, sizeof(port_str), "%u", port);
1878
1879         status = dcerpc_binding_set_string_option(e->ep_description,
1880                                                   "endpoint", port_str);
1881         if (!NT_STATUS_IS_OK(status)) {
1882                 DEBUG(0,("dcerpc_binding_set_string_option(endpoint, %s) failed - %s\n",
1883                          port_str, nt_errstr(status)));
1884                 return status;
1885         }
1886
1887         return NT_STATUS_OK;
1888 }
1889
1890 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1891
1892 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx, 
1893                                   struct loadparm_context *lp_ctx,
1894                                   struct dcesrv_endpoint *e,
1895                                   struct tevent_context *event_ctx, const struct model_ops *model_ops)
1896 {
1897         NTSTATUS status;
1898
1899         /* Add TCP/IP sockets */
1900         if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
1901                 int num_interfaces;
1902                 int i;
1903                 struct interface *ifaces;
1904
1905                 load_interface_list(dce_ctx, lp_ctx, &ifaces);
1906
1907                 num_interfaces = iface_list_count(ifaces);
1908                 for(i = 0; i < num_interfaces; i++) {
1909                         const char *address = iface_list_n_ip(ifaces, i);
1910                         status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
1911                         NT_STATUS_NOT_OK_RETURN(status);
1912                 }
1913         } else {
1914                 char **wcard;
1915                 int i;
1916                 int num_binds = 0;
1917                 wcard = iface_list_wildcard(dce_ctx);
1918                 NT_STATUS_HAVE_NO_MEMORY(wcard);
1919                 for (i=0; wcard[i]; i++) {
1920                         status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, wcard[i]);
1921                         if (NT_STATUS_IS_OK(status)) {
1922                                 num_binds++;
1923                         }
1924                 }
1925                 talloc_free(wcard);
1926                 if (num_binds == 0) {
1927                         return NT_STATUS_INVALID_PARAMETER_MIX;
1928                 }
1929         }
1930
1931         return NT_STATUS_OK;
1932 }
1933
1934 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
1935                        struct loadparm_context *lp_ctx,
1936                        struct dcesrv_endpoint *e,
1937                        struct tevent_context *event_ctx,
1938                        const struct model_ops *model_ops)
1939 {
1940         enum dcerpc_transport_t transport =
1941                 dcerpc_binding_get_transport(e->ep_description);
1942
1943         switch (transport) {
1944         case NCACN_UNIX_STREAM:
1945                 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1946
1947         case NCALRPC:
1948                 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1949
1950         case NCACN_IP_TCP:
1951                 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1952
1953         case NCACN_NP:
1954                 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1955
1956         default:
1957                 return NT_STATUS_NOT_SUPPORTED;
1958         }
1959 }
1960
1961
1962 /**
1963  * retrieve credentials from a dce_call
1964  */
1965 _PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
1966 {
1967         return dce_call->conn->auth_state.session_info->credentials;
1968 }
1969
1970 /**
1971  * returns true if this is an authenticated call
1972  */
1973 _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
1974 {
1975         enum security_user_level level;
1976         level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
1977         return level >= SECURITY_USER;
1978 }
1979
1980 /**
1981  * retrieve account_name for a dce_call
1982  */
1983 _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
1984 {
1985         return dce_call->context->conn->auth_state.session_info->info->account_name;
1986 }