s4:lib/socket: simplify iface_list_wildcard() and its callers
[metze/samba/wip.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
44 /* this is only used when the client asks for an unknown interface */
45 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
46
47 extern const struct dcesrv_interface dcesrv_mgmt_interface;
48
49
50 /*
51   find an association group given a assoc_group_id
52  */
53 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
54                                                           uint32_t id)
55 {
56         void *id_ptr;
57
58         id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
59         if (id_ptr == NULL) {
60                 return NULL;
61         }
62         return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
63 }
64
65 /*
66   take a reference to an existing association group
67  */
68 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
69                                                                struct dcesrv_context *dce_ctx,
70                                                                uint32_t id)
71 {
72         struct dcesrv_assoc_group *assoc_group;
73
74         assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
75         if (assoc_group == NULL) {
76                 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
77                 return NULL;
78         }
79         return talloc_reference(mem_ctx, assoc_group);
80 }
81
82 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
83 {
84         int ret;
85         ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
86         if (ret != 0) {
87                 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
88                          assoc_group->id));
89         }
90         return 0;
91 }
92
93 /*
94   allocate a new association group
95  */
96 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
97                                                          struct dcesrv_context *dce_ctx)
98 {
99         struct dcesrv_assoc_group *assoc_group;
100         int id;
101
102         assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
103         if (assoc_group == NULL) {
104                 return NULL;
105         }
106         
107         id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
108         if (id == -1) {
109                 talloc_free(assoc_group);
110                 DEBUG(0,(__location__ ": Out of association groups!\n"));
111                 return NULL;
112         }
113
114         assoc_group->id = id;
115         assoc_group->dce_ctx = dce_ctx;
116
117         talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
118
119         return assoc_group;
120 }
121
122
123 /*
124   see if two endpoints match
125 */
126 static bool endpoints_match(const struct dcerpc_binding *ep1,
127                             const struct dcerpc_binding *ep2)
128 {
129         if (ep1->transport != ep2->transport) {
130                 return false;
131         }
132
133         if (!ep1->endpoint || !ep2->endpoint) {
134                 return ep1->endpoint == ep2->endpoint;
135         }
136
137         if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0) 
138                 return false;
139
140         return true;
141 }
142
143 /*
144   find an endpoint in the dcesrv_context
145 */
146 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
147                                              const struct dcerpc_binding *ep_description)
148 {
149         struct dcesrv_endpoint *ep;
150         for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
151                 if (endpoints_match(ep->ep_description, ep_description)) {
152                         return ep;
153                 }
154         }
155         return NULL;
156 }
157
158 /*
159   find a registered context_id from a bind or alter_context
160 */
161 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn, 
162                                                                    uint32_t context_id)
163 {
164         struct dcesrv_connection_context *c;
165         for (c=conn->contexts;c;c=c->next) {
166                 if (c->context_id == context_id) return c;
167         }
168         return NULL;
169 }
170
171 /*
172   see if a uuid and if_version match to an interface
173 */
174 static bool interface_match(const struct dcesrv_interface *if1,
175                                                         const struct dcesrv_interface *if2)
176 {
177         return (if1->syntax_id.if_version == if2->syntax_id.if_version && 
178                         GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
179 }
180
181 /*
182   find the interface operations on an endpoint
183 */
184 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
185                                                      const struct dcesrv_interface *iface)
186 {
187         struct dcesrv_if_list *ifl;
188         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
189                 if (interface_match(&(ifl->iface), iface)) {
190                         return &(ifl->iface);
191                 }
192         }
193         return NULL;
194 }
195
196 /*
197   see if a uuid and if_version match to an interface
198 */
199 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
200                                     const struct GUID *uuid, uint32_t if_version)
201 {
202         return (iface->syntax_id.if_version == if_version && 
203                         GUID_equal(&iface->syntax_id.uuid, uuid));
204 }
205
206 /*
207   find the interface operations on an endpoint by uuid
208 */
209 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
210                                                              const struct GUID *uuid, uint32_t if_version)
211 {
212         struct dcesrv_if_list *ifl;
213         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
214                 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
215                         return &(ifl->iface);
216                 }
217         }
218         return NULL;
219 }
220
221 /*
222   find the earlier parts of a fragmented call awaiting reassembily
223 */
224 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
225 {
226         struct dcesrv_call_state *c;
227         for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
228                 if (c->pkt.call_id == call_id) {
229                         return c;
230                 }
231         }
232         return NULL;
233 }
234
235 /*
236   register an interface on an endpoint
237 */
238 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
239                                    const char *ep_name,
240                                    const struct dcesrv_interface *iface,
241                                    const struct security_descriptor *sd)
242 {
243         struct dcesrv_endpoint *ep;
244         struct dcesrv_if_list *ifl;
245         struct dcerpc_binding *binding;
246         bool add_ep = false;
247         NTSTATUS status;
248         
249         status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
250
251         if (NT_STATUS_IS_ERR(status)) {
252                 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
253                 return status;
254         }
255
256         /* check if this endpoint exists
257          */
258         if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
259                 ep = talloc(dce_ctx, struct dcesrv_endpoint);
260                 if (!ep) {
261                         return NT_STATUS_NO_MEMORY;
262                 }
263                 ZERO_STRUCTP(ep);
264                 ep->ep_description = talloc_reference(ep, binding);
265                 add_ep = true;
266
267                 /* add mgmt interface */
268                 ifl = talloc(dce_ctx, struct dcesrv_if_list);
269                 if (!ifl) {
270                         return NT_STATUS_NO_MEMORY;
271                 }
272
273                 memcpy(&(ifl->iface), &dcesrv_mgmt_interface, 
274                            sizeof(struct dcesrv_interface));
275
276                 DLIST_ADD(ep->interface_list, ifl);
277         }
278
279         /* see if the interface is already registered on te endpoint */
280         if (find_interface(ep, iface)!=NULL) {
281                 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
282                         iface->name, ep_name));
283                 return NT_STATUS_OBJECT_NAME_COLLISION;
284         }
285
286         /* talloc a new interface list element */
287         ifl = talloc(dce_ctx, struct dcesrv_if_list);
288         if (!ifl) {
289                 return NT_STATUS_NO_MEMORY;
290         }
291
292         /* copy the given interface struct to the one on the endpoints interface list */
293         memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
294
295         /* if we have a security descriptor given,
296          * we should see if we can set it up on the endpoint
297          */
298         if (sd != NULL) {
299                 /* if there's currently no security descriptor given on the endpoint
300                  * we try to set it
301                  */
302                 if (ep->sd == NULL) {
303                         ep->sd = security_descriptor_copy(dce_ctx, sd);
304                 }
305
306                 /* if now there's no security descriptor given on the endpoint
307                  * something goes wrong, either we failed to copy the security descriptor
308                  * or there was already one on the endpoint
309                  */
310                 if (ep->sd != NULL) {
311                         DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
312                                  "                           on endpoint '%s'\n",
313                                 iface->name, ep_name));
314                         if (add_ep) free(ep);
315                         free(ifl);
316                         return NT_STATUS_OBJECT_NAME_COLLISION;
317                 }
318         }
319
320         /* finally add the interface on the endpoint */
321         DLIST_ADD(ep->interface_list, ifl);
322
323         /* if it's a new endpoint add it to the dcesrv_context */
324         if (add_ep) {
325                 DLIST_ADD(dce_ctx->endpoint_list, ep);
326         }
327
328         DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
329                 iface->name, ep_name));
330
331         return NT_STATUS_OK;
332 }
333
334 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
335                                       DATA_BLOB *session_key)
336 {
337         if (p->auth_state.session_info->session_key.length) {
338                 *session_key = p->auth_state.session_info->session_key;
339                 return NT_STATUS_OK;
340         }
341         return NT_STATUS_NO_USER_SESSION_KEY;
342 }
343
344 /*
345   fetch the user session key - may be default (above) or the SMB session key
346
347   The key is always truncated to 16 bytes 
348 */
349 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
350                                   DATA_BLOB *session_key)
351 {
352         NTSTATUS status = p->auth_state.session_key(p, session_key);
353         if (!NT_STATUS_IS_OK(status)) {
354                 return status;
355         }
356
357         session_key->length = MIN(session_key->length, 16);
358
359         return NT_STATUS_OK;
360 }
361
362 /*
363   connect to a dcerpc endpoint
364 */
365 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
366                                  TALLOC_CTX *mem_ctx,
367                                  const struct dcesrv_endpoint *ep,
368                                  struct auth_session_info *session_info,
369                                  struct tevent_context *event_ctx,
370                                  struct imessaging_context *msg_ctx,
371                                  struct server_id server_id,
372                                  uint32_t state_flags,
373                                  struct dcesrv_connection **_p)
374 {
375         struct dcesrv_connection *p;
376
377         if (!session_info) {
378                 return NT_STATUS_ACCESS_DENIED;
379         }
380
381         p = talloc(mem_ctx, struct dcesrv_connection);
382         NT_STATUS_HAVE_NO_MEMORY(p);
383
384         if (!talloc_reference(p, session_info)) {
385                 talloc_free(p);
386                 return NT_STATUS_NO_MEMORY;
387         }
388
389         p->prev = NULL;
390         p->next = NULL;
391         p->dce_ctx = dce_ctx;
392         p->endpoint = ep;
393         p->contexts = NULL;
394         p->call_list = NULL;
395         p->packet_log_dir = lpcfg_lockdir(dce_ctx->lp_ctx);
396         p->incoming_fragmented_call_list = NULL;
397         p->pending_call_list = NULL;
398         p->cli_max_recv_frag = 0;
399         p->partial_input = data_blob(NULL, 0);
400         p->auth_state.auth_info = NULL;
401         p->auth_state.gensec_security = NULL;
402         p->auth_state.session_info = session_info;
403         p->auth_state.session_key = dcesrv_generic_session_key;
404         p->event_ctx = event_ctx;
405         p->msg_ctx = msg_ctx;
406         p->server_id = server_id;
407         p->terminate = NULL;
408         p->state_flags = state_flags;
409         ZERO_STRUCT(p->transport);
410
411         *_p = p;
412         return NT_STATUS_OK;
413 }
414
415 /*
416   move a call from an existing linked list to the specified list. This
417   prevents bugs where we forget to remove the call from a previous
418   list when moving it.
419  */
420 static void dcesrv_call_set_list(struct dcesrv_call_state *call, 
421                                  enum dcesrv_call_list list)
422 {
423         switch (call->list) {
424         case DCESRV_LIST_NONE:
425                 break;
426         case DCESRV_LIST_CALL_LIST:
427                 DLIST_REMOVE(call->conn->call_list, call);
428                 break;
429         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
430                 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
431                 break;
432         case DCESRV_LIST_PENDING_CALL_LIST:
433                 DLIST_REMOVE(call->conn->pending_call_list, call);
434                 break;
435         }
436         call->list = list;
437         switch (list) {
438         case DCESRV_LIST_NONE:
439                 break;
440         case DCESRV_LIST_CALL_LIST:
441                 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
442                 break;
443         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
444                 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
445                 break;
446         case DCESRV_LIST_PENDING_CALL_LIST:
447                 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
448                 break;
449         }
450 }
451
452
453 /*
454   return a dcerpc bind_nak
455 */
456 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
457 {
458         struct ncacn_packet pkt;
459         struct data_blob_list_item *rep;
460         NTSTATUS status;
461
462         /* setup a bind_nak */
463         dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
464         pkt.auth_length = 0;
465         pkt.call_id = call->pkt.call_id;
466         pkt.ptype = DCERPC_PKT_BIND_NAK;
467         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
468         pkt.u.bind_nak.reject_reason = reason;
469         if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
470                 pkt.u.bind_nak.versions.v.num_versions = 0;
471         }
472
473         rep = talloc(call, struct data_blob_list_item);
474         if (!rep) {
475                 return NT_STATUS_NO_MEMORY;
476         }
477
478         status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
479         if (!NT_STATUS_IS_OK(status)) {
480                 return status;
481         }
482
483         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
484
485         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
486         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
487
488         if (call->conn->call_list && call->conn->call_list->replies) {
489                 if (call->conn->transport.report_output_data) {
490                         call->conn->transport.report_output_data(call->conn);
491                 }
492         }
493
494         return NT_STATUS_OK;    
495 }
496
497 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
498 {
499         DLIST_REMOVE(c->conn->contexts, c);
500
501         if (c->iface && c->iface->unbind) {
502                 c->iface->unbind(c, c->iface);
503         }
504
505         return 0;
506 }
507
508 /*
509   handle a bind request
510 */
511 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
512 {
513         uint32_t if_version, transfer_syntax_version;
514         struct GUID uuid, *transfer_syntax_uuid;
515         struct ncacn_packet pkt;
516         struct data_blob_list_item *rep;
517         NTSTATUS status;
518         uint32_t result=0, reason=0;
519         uint32_t context_id;
520         const struct dcesrv_interface *iface;
521         uint32_t extra_flags = 0;
522
523         /*
524           if provided, check the assoc_group is valid
525          */
526         if (call->pkt.u.bind.assoc_group_id != 0 &&
527             lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
528             dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
529                 return dcesrv_bind_nak(call, 0);        
530         }
531
532         if (call->pkt.u.bind.num_contexts < 1 ||
533             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
534                 return dcesrv_bind_nak(call, 0);
535         }
536
537         context_id = call->pkt.u.bind.ctx_list[0].context_id;
538
539         /* you can't bind twice on one context */
540         if (dcesrv_find_context(call->conn, context_id) != NULL) {
541                 return dcesrv_bind_nak(call, 0);
542         }
543
544         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
545         uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
546
547         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
548         transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
549         if (!GUID_equal(&ndr_transfer_syntax_ndr.uuid, transfer_syntax_uuid) != 0 ||
550             ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
551                 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
552                 /* we only do NDR encoded dcerpc */
553                 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
554                 talloc_free(uuid_str);
555                 return dcesrv_bind_nak(call, 0);
556         }
557
558         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
559         if (iface == NULL) {
560                 char *uuid_str = GUID_string(call, &uuid);
561                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
562                 talloc_free(uuid_str);
563
564                 /* we don't know about that interface */
565                 result = DCERPC_BIND_PROVIDER_REJECT;
566                 reason = DCERPC_BIND_REASON_ASYNTAX;            
567         }
568
569         if (iface) {
570                 /* add this context to the list of available context_ids */
571                 struct dcesrv_connection_context *context = talloc(call->conn, 
572                                                                    struct dcesrv_connection_context);
573                 if (context == NULL) {
574                         return dcesrv_bind_nak(call, 0);
575                 }
576                 context->conn = call->conn;
577                 context->iface = iface;
578                 context->context_id = context_id;
579                 if (call->pkt.u.bind.assoc_group_id != 0) {
580                         context->assoc_group = dcesrv_assoc_group_reference(context,
581                                                                             call->conn->dce_ctx, 
582                                                                             call->pkt.u.bind.assoc_group_id);
583                 } else {
584                         context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
585                 }
586                 if (context->assoc_group == NULL) {
587                         talloc_free(context);
588                         return dcesrv_bind_nak(call, 0);
589                 }
590                 context->private_data = NULL;
591                 DLIST_ADD(call->conn->contexts, context);
592                 call->context = context;
593                 talloc_set_destructor(context, dcesrv_connection_context_destructor);
594
595                 status = iface->bind(call, iface, if_version);
596                 if (!NT_STATUS_IS_OK(status)) {
597                         char *uuid_str = GUID_string(call, &uuid);
598                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
599                                  uuid_str, if_version, nt_errstr(status)));
600                         talloc_free(uuid_str);
601                         /* we don't want to trigger the iface->unbind() hook */
602                         context->iface = NULL;
603                         talloc_free(call->context);
604                         call->context = NULL;
605                         return dcesrv_bind_nak(call, 0);
606                 }
607         }
608
609         if (call->conn->cli_max_recv_frag == 0) {
610                 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
611         }
612
613         if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
614             lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
615                 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
616                 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
617         }
618
619         /* handle any authentication that is being requested */
620         if (!dcesrv_auth_bind(call)) {
621                 talloc_free(call->context);
622                 call->context = NULL;
623                 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
624         }
625
626         /* setup a bind_ack */
627         dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
628         pkt.auth_length = 0;
629         pkt.call_id = call->pkt.call_id;
630         pkt.ptype = DCERPC_PKT_BIND_ACK;
631         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
632         pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
633         pkt.u.bind_ack.max_recv_frag = 0x2000;
634
635         /*
636           make it possible for iface->bind() to specify the assoc_group_id
637           This helps the openchange mapiproxy plugin to work correctly.
638           
639           metze
640         */
641         if (call->context) {
642                 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
643         } else {
644                 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
645         }
646
647         if (iface) {
648                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
649                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
650         } else {
651                 pkt.u.bind_ack.secondary_address = "";
652         }
653         pkt.u.bind_ack.num_results = 1;
654         pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
655         if (!pkt.u.bind_ack.ctx_list) {
656                 talloc_free(call->context);
657                 call->context = NULL;
658                 return NT_STATUS_NO_MEMORY;
659         }
660         pkt.u.bind_ack.ctx_list[0].result = result;
661         pkt.u.bind_ack.ctx_list[0].reason = reason;
662         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
663         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
664
665         status = dcesrv_auth_bind_ack(call, &pkt);
666         if (!NT_STATUS_IS_OK(status)) {
667                 talloc_free(call->context);
668                 call->context = NULL;
669                 return dcesrv_bind_nak(call, 0);
670         }
671
672         rep = talloc(call, struct data_blob_list_item);
673         if (!rep) {
674                 talloc_free(call->context);
675                 call->context = NULL;
676                 return NT_STATUS_NO_MEMORY;
677         }
678
679         status = ncacn_push_auth(&rep->blob, call, &pkt,
680                                                          call->conn->auth_state.auth_info);
681         if (!NT_STATUS_IS_OK(status)) {
682                 talloc_free(call->context);
683                 call->context = NULL;
684                 return status;
685         }
686
687         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
688
689         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
690         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
691
692         if (call->conn->call_list && call->conn->call_list->replies) {
693                 if (call->conn->transport.report_output_data) {
694                         call->conn->transport.report_output_data(call->conn);
695                 }
696         }
697
698         return NT_STATUS_OK;
699 }
700
701
702 /*
703   handle a auth3 request
704 */
705 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
706 {
707         /* handle the auth3 in the auth code */
708         if (!dcesrv_auth_auth3(call)) {
709                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
710         }
711
712         talloc_free(call);
713
714         /* we don't send a reply to a auth3 request, except by a
715            fault */
716         return NT_STATUS_OK;
717 }
718
719
720 /*
721   handle a bind request
722 */
723 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
724 {
725         uint32_t if_version, transfer_syntax_version;
726         struct dcesrv_connection_context *context;
727         const struct dcesrv_interface *iface;
728         struct GUID uuid, *transfer_syntax_uuid;
729         NTSTATUS status;
730
731         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
732         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
733
734         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
735         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
736         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax_ndr.uuid) ||
737             ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
738                 /* we only do NDR encoded dcerpc */
739                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
740         }
741
742         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
743         if (iface == NULL) {
744                 char *uuid_str = GUID_string(call, &uuid);
745                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
746                 talloc_free(uuid_str);
747                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
748         }
749
750         /* add this context to the list of available context_ids */
751         context = talloc(call->conn, struct dcesrv_connection_context);
752         if (context == NULL) {
753                 return NT_STATUS_NO_MEMORY;
754         }
755         context->conn = call->conn;
756         context->iface = iface;
757         context->context_id = context_id;
758         if (call->pkt.u.alter.assoc_group_id != 0) {
759                 context->assoc_group = dcesrv_assoc_group_reference(context,
760                                                                     call->conn->dce_ctx, 
761                                                                     call->pkt.u.alter.assoc_group_id);
762         } else {
763                 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
764         }
765         if (context->assoc_group == NULL) {
766                 talloc_free(context);
767                 call->context = NULL;
768                 return NT_STATUS_NO_MEMORY;
769         }
770         context->private_data = NULL;
771         DLIST_ADD(call->conn->contexts, context);
772         call->context = context;
773         talloc_set_destructor(context, dcesrv_connection_context_destructor);
774
775         status = iface->bind(call, iface, if_version);
776         if (!NT_STATUS_IS_OK(status)) {
777                 /* we don't want to trigger the iface->unbind() hook */
778                 context->iface = NULL;
779                 talloc_free(context);
780                 call->context = NULL;
781                 return status;
782         }
783
784         return NT_STATUS_OK;
785 }
786
787
788 /*
789   handle a alter context request
790 */
791 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
792 {
793         struct ncacn_packet pkt;
794         struct data_blob_list_item *rep;
795         NTSTATUS status;
796         uint32_t result=0, reason=0;
797         uint32_t context_id;
798
799         /* handle any authentication that is being requested */
800         if (!dcesrv_auth_alter(call)) {
801                 /* TODO: work out the right reject code */
802                 result = DCERPC_BIND_PROVIDER_REJECT;
803                 reason = DCERPC_BIND_REASON_ASYNTAX;            
804         }
805
806         context_id = call->pkt.u.alter.ctx_list[0].context_id;
807
808         /* see if they are asking for a new interface */
809         if (result == 0) {
810                 call->context = dcesrv_find_context(call->conn, context_id);
811                 if (!call->context) {
812                         status = dcesrv_alter_new_context(call, context_id);
813                         if (!NT_STATUS_IS_OK(status)) {
814                                 result = DCERPC_BIND_PROVIDER_REJECT;
815                                 reason = DCERPC_BIND_REASON_ASYNTAX;
816                         }
817                 }
818         }
819
820         if (result == 0 &&
821             call->pkt.u.alter.assoc_group_id != 0 &&
822             lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
823             call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
824                 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
825                          call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
826                 /* TODO: can they ask for a new association group? */
827                 result = DCERPC_BIND_PROVIDER_REJECT;
828                 reason = DCERPC_BIND_REASON_ASYNTAX;
829         }
830
831         /* setup a alter_resp */
832         dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
833         pkt.auth_length = 0;
834         pkt.call_id = call->pkt.call_id;
835         pkt.ptype = DCERPC_PKT_ALTER_RESP;
836         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
837         pkt.u.alter_resp.max_xmit_frag = 0x2000;
838         pkt.u.alter_resp.max_recv_frag = 0x2000;
839         if (result == 0) {
840                 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
841         } else {
842                 pkt.u.alter_resp.assoc_group_id = 0;
843         }
844         pkt.u.alter_resp.num_results = 1;
845         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
846         if (!pkt.u.alter_resp.ctx_list) {
847                 return NT_STATUS_NO_MEMORY;
848         }
849         pkt.u.alter_resp.ctx_list[0].result = result;
850         pkt.u.alter_resp.ctx_list[0].reason = reason;
851         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
852         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
853         pkt.u.alter_resp.secondary_address = "";
854
855         status = dcesrv_auth_alter_ack(call, &pkt);
856         if (!NT_STATUS_IS_OK(status)) {
857                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
858                     || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
859                     || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
860                     || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
861                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
862                 }
863                 return dcesrv_fault(call, 0);
864         }
865
866         rep = talloc(call, struct data_blob_list_item);
867         if (!rep) {
868                 return NT_STATUS_NO_MEMORY;
869         }
870
871         status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
872         if (!NT_STATUS_IS_OK(status)) {
873                 return status;
874         }
875
876         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
877
878         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
879         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
880
881         if (call->conn->call_list && call->conn->call_list->replies) {
882                 if (call->conn->transport.report_output_data) {
883                         call->conn->transport.report_output_data(call->conn);
884                 }
885         }
886
887         return NT_STATUS_OK;
888 }
889
890 /*
891   possibly save the call for inspection with ndrdump
892  */
893 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
894 {
895 #ifdef DEVELOPER
896         char *fname;
897         const char *dump_dir;
898         dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
899         if (!dump_dir) {
900                 return;
901         }
902         fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
903                                 dump_dir,
904                                 call->context->iface->name,
905                                 call->pkt.u.request.opnum,
906                                 why);
907         if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
908                 DEBUG(0,("RPC SAVED %s\n", fname));
909         }
910         talloc_free(fname);
911 #endif
912 }
913
914 /*
915   handle a dcerpc request packet
916 */
917 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
918 {
919         struct ndr_pull *pull;
920         NTSTATUS status;
921         struct dcesrv_connection_context *context;
922
923         /* if authenticated, and the mech we use can't do async replies, don't use them... */
924         if (call->conn->auth_state.gensec_security && 
925             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
926                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
927         }
928
929         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
930         if (context == NULL) {
931                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
932         }
933
934         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
935         NT_STATUS_HAVE_NO_MEMORY(pull);
936
937         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
938
939         call->context   = context;
940         call->ndr_pull  = pull;
941
942         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
943                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
944         }
945
946         /* unravel the NDR for the packet */
947         status = context->iface->ndr_pull(call, call, pull, &call->r);
948         if (!NT_STATUS_IS_OK(status)) {
949                 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
950                         /* we got an unknown call */
951                         DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
952                                  call->pkt.u.request.opnum, context->iface->name));
953                         dcesrv_save_call(call, "unknown");
954                 } else {
955                         dcesrv_save_call(call, "pullfail");
956                 }
957                 return dcesrv_fault(call, call->fault_code);
958         }
959
960         if (pull->offset != pull->data_size) {
961                 dcesrv_save_call(call, "extrabytes");
962                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
963                          pull->data_size - pull->offset));
964         }
965
966         /* call the dispatch function */
967         status = context->iface->dispatch(call, call, call->r);
968         if (!NT_STATUS_IS_OK(status)) {
969                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
970                          context->iface->name, 
971                          call->pkt.u.request.opnum,
972                          dcerpc_errstr(pull, call->fault_code)));
973                 return dcesrv_fault(call, call->fault_code);
974         }
975
976         /* add the call to the pending list */
977         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
978
979         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
980                 return NT_STATUS_OK;
981         }
982
983         return dcesrv_reply(call);
984 }
985
986
987 /*
988   remove the call from the right list when freed
989  */
990 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
991 {
992         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
993         return 0;
994 }
995
996 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
997 {
998         return conn->local_address;
999 }
1000
1001 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1002 {
1003         return conn->remote_address;
1004 }
1005
1006 /*
1007   process some input to a dcerpc endpoint server.
1008 */
1009 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1010                                      struct ncacn_packet *pkt,
1011                                      DATA_BLOB blob)
1012 {
1013         NTSTATUS status;
1014         struct dcesrv_call_state *call;
1015
1016         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1017         if (!call) {
1018                 data_blob_free(&blob);
1019                 talloc_free(pkt);
1020                 return NT_STATUS_NO_MEMORY;
1021         }
1022         call->conn              = dce_conn;
1023         call->event_ctx         = dce_conn->event_ctx;
1024         call->msg_ctx           = dce_conn->msg_ctx;
1025         call->state_flags       = call->conn->state_flags;
1026         call->time              = timeval_current();
1027         call->list              = DCESRV_LIST_NONE;
1028
1029         talloc_steal(call, pkt);
1030         talloc_steal(call, blob.data);
1031         call->pkt = *pkt;
1032
1033         talloc_set_destructor(call, dcesrv_call_dequeue);
1034
1035         /* we have to check the signing here, before combining the
1036            pdus */
1037         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1038             !dcesrv_auth_request(call, &blob)) {
1039                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1040         }
1041
1042         /* see if this is a continued packet */
1043         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1044             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1045                 struct dcesrv_call_state *call2 = call;
1046                 uint32_t alloc_size;
1047
1048                 /* we only allow fragmented requests, no other packet types */
1049                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1050                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1051                 }
1052
1053                 /* this is a continuation of an existing call - find the call
1054                    then tack it on the end */
1055                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1056                 if (!call) {
1057                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1058                 }
1059
1060                 if (call->pkt.ptype != call2->pkt.ptype) {
1061                         /* trying to play silly buggers are we? */
1062                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1063                 }
1064
1065                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1066                         call2->pkt.u.request.stub_and_verifier.length;
1067                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1068                         alloc_size = call->pkt.u.request.alloc_hint;
1069                 }
1070
1071                 call->pkt.u.request.stub_and_verifier.data = 
1072                         talloc_realloc(call, 
1073                                        call->pkt.u.request.stub_and_verifier.data, 
1074                                        uint8_t, alloc_size);
1075                 if (!call->pkt.u.request.stub_and_verifier.data) {
1076                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1077                 }
1078                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1079                        call->pkt.u.request.stub_and_verifier.length,
1080                        call2->pkt.u.request.stub_and_verifier.data,
1081                        call2->pkt.u.request.stub_and_verifier.length);
1082                 call->pkt.u.request.stub_and_verifier.length += 
1083                         call2->pkt.u.request.stub_and_verifier.length;
1084
1085                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1086
1087                 talloc_free(call2);
1088         }
1089
1090         /* this may not be the last pdu in the chain - if its isn't then
1091            just put it on the incoming_fragmented_call_list and wait for the rest */
1092         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1093             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1094                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1095                 return NT_STATUS_OK;
1096         } 
1097         
1098         /* This removes any fragments we may have had stashed away */
1099         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1100
1101         switch (call->pkt.ptype) {
1102         case DCERPC_PKT_BIND:
1103                 status = dcesrv_bind(call);
1104                 break;
1105         case DCERPC_PKT_AUTH3:
1106                 status = dcesrv_auth3(call);
1107                 break;
1108         case DCERPC_PKT_ALTER:
1109                 status = dcesrv_alter(call);
1110                 break;
1111         case DCERPC_PKT_REQUEST:
1112                 status = dcesrv_request(call);
1113                 break;
1114         default:
1115                 status = NT_STATUS_INVALID_PARAMETER;
1116                 break;
1117         }
1118
1119         /* if we are going to be sending a reply then add
1120            it to the list of pending calls. We add it to the end to keep the call
1121            list in the order we will answer */
1122         if (!NT_STATUS_IS_OK(status)) {
1123                 talloc_free(call);
1124         }
1125
1126         return status;
1127 }
1128
1129 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1130                                       struct loadparm_context *lp_ctx,
1131                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1132 {
1133         NTSTATUS status;
1134         struct dcesrv_context *dce_ctx;
1135         int i;
1136
1137         if (!endpoint_servers) {
1138                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1139                 return NT_STATUS_INTERNAL_ERROR;
1140         }
1141
1142         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1143         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1144         dce_ctx->endpoint_list  = NULL;
1145         dce_ctx->lp_ctx = lp_ctx;
1146         dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1147         NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1148         dce_ctx->broken_connections = NULL;
1149
1150         for (i=0;endpoint_servers[i];i++) {
1151                 const struct dcesrv_endpoint_server *ep_server;
1152
1153                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1154                 if (!ep_server) {
1155                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1156                         return NT_STATUS_INTERNAL_ERROR;
1157                 }
1158
1159                 status = ep_server->init_server(dce_ctx, ep_server);
1160                 if (!NT_STATUS_IS_OK(status)) {
1161                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1162                                 nt_errstr(status)));
1163                         return status;
1164                 }
1165         }
1166
1167         *_dce_ctx = dce_ctx;
1168         return NT_STATUS_OK;
1169 }
1170
1171 /* the list of currently registered DCERPC endpoint servers.
1172  */
1173 static struct ep_server {
1174         struct dcesrv_endpoint_server *ep_server;
1175 } *ep_servers = NULL;
1176 static int num_ep_servers;
1177
1178 /*
1179   register a DCERPC endpoint server. 
1180
1181   The 'name' can be later used by other backends to find the operations
1182   structure for this backend.  
1183
1184   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1185 */
1186 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1187 {
1188         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1189         
1190         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1191                 /* its already registered! */
1192                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1193                          ep_server->name));
1194                 return NT_STATUS_OBJECT_NAME_COLLISION;
1195         }
1196
1197         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1198         if (!ep_servers) {
1199                 smb_panic("out of memory in dcerpc_register");
1200         }
1201
1202         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1203         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1204
1205         num_ep_servers++;
1206
1207         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1208                  ep_server->name));
1209
1210         return NT_STATUS_OK;
1211 }
1212
1213 /*
1214   return the operations structure for a named backend of the specified type
1215 */
1216 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1217 {
1218         int i;
1219
1220         for (i=0;i<num_ep_servers;i++) {
1221                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1222                         return ep_servers[i].ep_server;
1223                 }
1224         }
1225
1226         return NULL;
1227 }
1228
1229 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1230 {
1231         static bool initialized;
1232 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1233         STATIC_dcerpc_server_MODULES_PROTO;
1234         init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1235         init_module_fn *shared_init;
1236
1237         if (initialized) {
1238                 return;
1239         }
1240         initialized = true;
1241
1242         shared_init = load_samba_modules(NULL, "dcerpc_server");
1243
1244         run_init_functions(static_init);
1245         run_init_functions(shared_init);
1246
1247         talloc_free(shared_init);
1248 }
1249
1250 /*
1251   return the DCERPC module version, and the size of some critical types
1252   This can be used by endpoint server modules to either detect compilation errors, or provide
1253   multiple implementations for different smbd compilation options in one module
1254 */
1255 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1256 {
1257         static const struct dcesrv_critical_sizes critical_sizes = {
1258                 DCERPC_MODULE_VERSION,
1259                 sizeof(struct dcesrv_context),
1260                 sizeof(struct dcesrv_endpoint),
1261                 sizeof(struct dcesrv_endpoint_server),
1262                 sizeof(struct dcesrv_interface),
1263                 sizeof(struct dcesrv_if_list),
1264                 sizeof(struct dcesrv_connection),
1265                 sizeof(struct dcesrv_call_state),
1266                 sizeof(struct dcesrv_auth),
1267                 sizeof(struct dcesrv_handle)
1268         };
1269
1270         return &critical_sizes;
1271 }
1272
1273 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1274 {
1275         struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1276         struct stream_connection *srv_conn;
1277         srv_conn = talloc_get_type(dce_conn->transport.private_data,
1278                                    struct stream_connection);
1279
1280         if (dce_conn->pending_call_list == NULL) {
1281                 char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
1282
1283                 DLIST_REMOVE(dce_ctx->broken_connections, dce_conn);
1284                 stream_terminate_connection(srv_conn, full_reason ? full_reason : reason);
1285                 return;
1286         }
1287
1288         if (dce_conn->terminate != NULL) {
1289                 return;
1290         }
1291
1292         DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1293                  reason));
1294         dce_conn->terminate = talloc_strdup(dce_conn, reason);
1295         if (dce_conn->terminate == NULL) {
1296                 dce_conn->terminate = "dcesrv: defered terminating connection - no memory";
1297         }
1298         DLIST_ADD_END(dce_ctx->broken_connections, dce_conn, NULL);
1299 }
1300
1301 static void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx)
1302 {
1303         struct dcesrv_connection *cur, *next;
1304
1305         next = dce_ctx->broken_connections;
1306         while (next != NULL) {
1307                 cur = next;
1308                 next = cur->next;
1309
1310                 dcesrv_terminate_connection(cur, cur->terminate);
1311         }
1312 }
1313
1314 /* We need this include to be able to compile on some plateforms
1315  * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1316  * correctly.
1317  * It has to be that deep because otherwise we have a conflict on
1318  * const struct dcesrv_interface declaration.
1319  * This is mostly due to socket_wrapper defining #define bind swrap_bind
1320  * which conflict with the bind used before.
1321  */
1322 #include "system/network.h"
1323
1324 struct dcesrv_sock_reply_state {
1325         struct dcesrv_connection *dce_conn;
1326         struct dcesrv_call_state *call;
1327         struct iovec iov;
1328 };
1329
1330 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1331
1332 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1333 {
1334         struct dcesrv_call_state *call;
1335
1336         call = dce_conn->call_list;
1337         if (!call || !call->replies) {
1338                 return;
1339         }
1340
1341         while (call->replies) {
1342                 struct data_blob_list_item *rep = call->replies;
1343                 struct dcesrv_sock_reply_state *substate;
1344                 struct tevent_req *subreq;
1345
1346                 substate = talloc(call, struct dcesrv_sock_reply_state);
1347                 if (!substate) {
1348                         dcesrv_terminate_connection(dce_conn, "no memory");
1349                         return;
1350                 }
1351
1352                 substate->dce_conn = dce_conn;
1353                 substate->call = NULL;
1354
1355                 DLIST_REMOVE(call->replies, rep);
1356
1357                 if (call->replies == NULL) {
1358                         substate->call = call;
1359                 }
1360
1361                 substate->iov.iov_base = (void *) rep->blob.data;
1362                 substate->iov.iov_len = rep->blob.length;
1363
1364                 subreq = tstream_writev_queue_send(substate,
1365                                                    dce_conn->event_ctx,
1366                                                    dce_conn->stream,
1367                                                    dce_conn->send_queue,
1368                                                    &substate->iov, 1);
1369                 if (!subreq) {
1370                         dcesrv_terminate_connection(dce_conn, "no memory");
1371                         return;
1372                 }
1373                 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1374                                         substate);
1375         }
1376
1377         DLIST_REMOVE(call->conn->call_list, call);
1378         call->list = DCESRV_LIST_NONE;
1379 }
1380
1381 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1382 {
1383         struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1384                                                 struct dcesrv_sock_reply_state);
1385         int ret;
1386         int sys_errno;
1387         NTSTATUS status;
1388         struct dcesrv_call_state *call = substate->call;
1389
1390         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1391         TALLOC_FREE(subreq);
1392         if (ret == -1) {
1393                 status = map_nt_error_from_unix_common(sys_errno);
1394                 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1395                 return;
1396         }
1397
1398         talloc_free(substate);
1399         if (call) {
1400                 talloc_free(call);
1401         }
1402 }
1403
1404
1405
1406
1407 struct dcesrv_socket_context {
1408         const struct dcesrv_endpoint *endpoint;
1409         struct dcesrv_context *dcesrv_ctx;
1410 };
1411
1412
1413 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1414
1415 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1416 {
1417         NTSTATUS status;
1418         struct dcesrv_socket_context *dcesrv_sock = 
1419                 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1420         struct dcesrv_connection *dcesrv_conn = NULL;
1421         int ret;
1422         struct tevent_req *subreq;
1423         struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1424
1425         dcesrv_cleanup_broken_connections(dcesrv_sock->dcesrv_ctx);
1426
1427         if (!srv_conn->session_info) {
1428                 status = auth_anonymous_session_info(srv_conn,
1429                                                      lp_ctx,
1430                                                      &srv_conn->session_info);
1431                 if (!NT_STATUS_IS_OK(status)) {
1432                         DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1433                                 nt_errstr(status)));
1434                         stream_terminate_connection(srv_conn, nt_errstr(status));
1435                         return;
1436                 }
1437         }
1438
1439         status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1440                                          srv_conn,
1441                                          dcesrv_sock->endpoint,
1442                                          srv_conn->session_info,
1443                                          srv_conn->event.ctx,
1444                                          srv_conn->msg_ctx,
1445                                          srv_conn->server_id,
1446                                          DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1447                                          &dcesrv_conn);
1448         if (!NT_STATUS_IS_OK(status)) {
1449                 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", 
1450                         nt_errstr(status)));
1451                 stream_terminate_connection(srv_conn, nt_errstr(status));
1452                 return;
1453         }
1454
1455         dcesrv_conn->transport.private_data             = srv_conn;
1456         dcesrv_conn->transport.report_output_data       = dcesrv_sock_report_output_data;
1457
1458         TALLOC_FREE(srv_conn->event.fde);
1459
1460         dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1461         if (!dcesrv_conn->send_queue) {
1462                 status = NT_STATUS_NO_MEMORY;
1463                 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1464                         nt_errstr(status)));
1465                 stream_terminate_connection(srv_conn, nt_errstr(status));
1466                 return;
1467         }
1468
1469         if (dcesrv_sock->endpoint->ep_description->transport == NCACN_NP) {
1470                 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1471                 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1472                                                   &srv_conn->tstream);
1473         } else {
1474                 ret = tstream_bsd_existing_socket(dcesrv_conn,
1475                                                   socket_get_fd(srv_conn->socket),
1476                                                   &dcesrv_conn->stream);
1477                 if (ret == -1) {
1478                         status = map_nt_error_from_unix_common(errno);
1479                         DEBUG(0, ("dcesrv_sock_accept: "
1480                                   "failed to setup tstream: %s\n",
1481                                   nt_errstr(status)));
1482                         stream_terminate_connection(srv_conn, nt_errstr(status));
1483                         return;
1484                 }
1485                 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1486         }
1487
1488         dcesrv_conn->local_address = srv_conn->local_address;
1489         dcesrv_conn->remote_address = srv_conn->remote_address;
1490
1491         srv_conn->private_data = dcesrv_conn;
1492
1493         irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1494
1495         subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1496                                                dcesrv_conn->event_ctx,
1497                                                dcesrv_conn->stream);
1498         if (!subreq) {
1499                 status = NT_STATUS_NO_MEMORY;
1500                 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1501                         nt_errstr(status)));
1502                 stream_terminate_connection(srv_conn, nt_errstr(status));
1503                 return;
1504         }
1505         tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1506
1507         return;
1508 }
1509
1510 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1511 {
1512         struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1513                                              struct dcesrv_connection);
1514         struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1515         struct ncacn_packet *pkt;
1516         DATA_BLOB buffer;
1517         NTSTATUS status;
1518
1519         if (dce_conn->terminate) {
1520                 /*
1521                  * if the current connection is broken
1522                  * we need to clean it up before any other connection
1523                  */
1524                 dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
1525                 dcesrv_cleanup_broken_connections(dce_ctx);
1526                 return;
1527         }
1528
1529         dcesrv_cleanup_broken_connections(dce_ctx);
1530
1531         status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1532                                                &pkt, &buffer);
1533         TALLOC_FREE(subreq);
1534         if (!NT_STATUS_IS_OK(status)) {
1535                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1536                 return;
1537         }
1538
1539         status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1540         if (!NT_STATUS_IS_OK(status)) {
1541                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1542                 return;
1543         }
1544
1545         subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1546                                                dce_conn->event_ctx,
1547                                                dce_conn->stream);
1548         if (!subreq) {
1549                 status = NT_STATUS_NO_MEMORY;
1550                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1551                 return;
1552         }
1553         tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1554 }
1555
1556 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1557 {
1558         struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1559                                              struct dcesrv_connection);
1560         dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1561 }
1562
1563 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1564 {
1565         struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1566                                              struct dcesrv_connection);
1567         dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1568 }
1569
1570
1571 static const struct stream_server_ops dcesrv_stream_ops = {
1572         .name                   = "rpc",
1573         .accept_connection      = dcesrv_sock_accept,
1574         .recv_handler           = dcesrv_sock_recv,
1575         .send_handler           = dcesrv_sock_send,
1576 };
1577
1578 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, 
1579                                    struct loadparm_context *lp_ctx,
1580                                    struct dcesrv_endpoint *e,
1581                             struct tevent_context *event_ctx, const struct model_ops *model_ops)
1582 {
1583         struct dcesrv_socket_context *dcesrv_sock;
1584         uint16_t port = 1;
1585         NTSTATUS status;
1586
1587         dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1588         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1589
1590         /* remember the endpoint of this socket */
1591         dcesrv_sock->endpoint           = e;
1592         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
1593
1594         status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1595                                      model_ops, &dcesrv_stream_ops, 
1596                                      "unix", e->ep_description->endpoint, &port, 
1597                                      lpcfg_socket_options(lp_ctx),
1598                                      dcesrv_sock);
1599         if (!NT_STATUS_IS_OK(status)) {
1600                 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1601                          e->ep_description->endpoint, nt_errstr(status)));
1602         }
1603
1604         return status;
1605 }
1606
1607 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, 
1608                                       struct loadparm_context *lp_ctx,
1609                                       struct dcesrv_endpoint *e,
1610                                       struct tevent_context *event_ctx, const struct model_ops *model_ops)
1611 {
1612         struct dcesrv_socket_context *dcesrv_sock;
1613         uint16_t port = 1;
1614         char *full_path;
1615         NTSTATUS status;
1616
1617         if (!e->ep_description->endpoint) {
1618                 /* No identifier specified: use DEFAULT. 
1619                  * DO NOT hardcode this value anywhere else. Rather, specify 
1620                  * no endpoint and let the epmapper worry about it. */
1621                 e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT");
1622         }
1623
1624         full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1625                                     e->ep_description->endpoint);
1626
1627         dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1628         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1629
1630         /* remember the endpoint of this socket */
1631         dcesrv_sock->endpoint           = e;
1632         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
1633
1634         status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1635                                      model_ops, &dcesrv_stream_ops, 
1636                                      "unix", full_path, &port, 
1637                                      lpcfg_socket_options(lp_ctx),
1638                                      dcesrv_sock);
1639         if (!NT_STATUS_IS_OK(status)) {
1640                 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1641                          e->ep_description->endpoint, full_path, nt_errstr(status)));
1642         }
1643         return status;
1644 }
1645
1646 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1647                                  struct loadparm_context *lp_ctx,
1648                                  struct dcesrv_endpoint *e,
1649                                  struct tevent_context *event_ctx, const struct model_ops *model_ops)
1650 {
1651         struct dcesrv_socket_context *dcesrv_sock;
1652         NTSTATUS status;
1653                         
1654         if (e->ep_description->endpoint == NULL) {
1655                 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1656                 return NT_STATUS_INVALID_PARAMETER;
1657         }
1658
1659         dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1660         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1661
1662         /* remember the endpoint of this socket */
1663         dcesrv_sock->endpoint           = e;
1664         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
1665
1666         status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
1667                                           model_ops, &dcesrv_stream_ops,
1668                                           e->ep_description->endpoint,
1669                                           dcesrv_sock);
1670         if (!NT_STATUS_IS_OK(status)) {
1671                 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1672                          e->ep_description->endpoint, nt_errstr(status)));
1673                 return status;
1674         }
1675
1676         return NT_STATUS_OK;
1677 }
1678
1679 /*
1680   add a socket address to the list of events, one event per dcerpc endpoint
1681 */
1682 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
1683                                          struct tevent_context *event_ctx, const struct model_ops *model_ops,
1684                                          const char *address)
1685 {
1686         struct dcesrv_socket_context *dcesrv_sock;
1687         uint16_t port = 0;
1688         NTSTATUS status;
1689                         
1690         if (e->ep_description->endpoint) {
1691                 port = atoi(e->ep_description->endpoint);
1692         }
1693
1694         dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1695         NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1696
1697         /* remember the endpoint of this socket */
1698         dcesrv_sock->endpoint           = e;
1699         dcesrv_sock->dcesrv_ctx         = talloc_reference(dcesrv_sock, dce_ctx);
1700
1701         status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
1702                                      model_ops, &dcesrv_stream_ops, 
1703                                      "ip", address, &port,
1704                                      lpcfg_socket_options(dce_ctx->lp_ctx),
1705                                      dcesrv_sock);
1706         if (!NT_STATUS_IS_OK(status)) {
1707                 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n", 
1708                          address, port, nt_errstr(status)));
1709         }
1710
1711         if (e->ep_description->endpoint == NULL) {
1712                 e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port);
1713         }
1714
1715         return status;
1716 }
1717
1718 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1719
1720 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx, 
1721                                   struct loadparm_context *lp_ctx,
1722                                   struct dcesrv_endpoint *e,
1723                                   struct tevent_context *event_ctx, const struct model_ops *model_ops)
1724 {
1725         NTSTATUS status;
1726
1727         /* Add TCP/IP sockets */
1728         if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
1729                 int num_interfaces;
1730                 int i;
1731                 struct interface *ifaces;
1732
1733                 load_interface_list(dce_ctx, lp_ctx, &ifaces);
1734
1735                 num_interfaces = iface_list_count(ifaces);
1736                 for(i = 0; i < num_interfaces; i++) {
1737                         const char *address = iface_list_n_ip(ifaces, i);
1738                         status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
1739                         NT_STATUS_NOT_OK_RETURN(status);
1740                 }
1741         } else {
1742                 char **wcard;
1743                 int i;
1744                 wcard = iface_list_wildcard(dce_ctx);
1745                 NT_STATUS_HAVE_NO_MEMORY(wcard);
1746                 for (i=0; wcard[i]; i++) {
1747                         status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, wcard[i]);
1748                         NT_STATUS_NOT_OK_RETURN(status);
1749                 }
1750                 talloc_free(wcard);
1751         }
1752
1753         return NT_STATUS_OK;
1754 }
1755
1756 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
1757                        struct loadparm_context *lp_ctx,
1758                        struct dcesrv_endpoint *e,
1759                        struct tevent_context *event_ctx,
1760                        const struct model_ops *model_ops)
1761 {
1762         switch (e->ep_description->transport) {
1763         case NCACN_UNIX_STREAM:
1764                 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1765
1766         case NCALRPC:
1767                 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1768
1769         case NCACN_IP_TCP:
1770                 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1771
1772         case NCACN_NP:
1773                 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1774
1775         default:
1776                 return NT_STATUS_NOT_SUPPORTED;
1777         }
1778 }
1779
1780
1781 /**
1782  * retrieve credentials from a dce_call
1783  */
1784 _PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
1785 {
1786         return dce_call->conn->auth_state.session_info->credentials;
1787 }
1788
1789 /**
1790  * returns true if this is an authenticated call
1791  */
1792 _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
1793 {
1794         enum security_user_level level;
1795         level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
1796         return level >= SECURITY_USER;
1797 }
1798
1799 /**
1800  * retrieve account_name for a dce_call
1801  */
1802 _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
1803 {
1804         return dce_call->context->conn->auth_state.session_info->info->account_name;
1805 }