Remove the 'accoc_group_id' check in the RPC server.
[ira/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 "librpc/gen_ndr/ndr_dcerpc.h"
25 #include "auth/auth.h"
26 #include "auth/gensec/gensec.h"
27 #include "lib/util/dlinklist.h"
28 #include "rpc_server/dcerpc_server.h"
29 #include "rpc_server/dcerpc_server_proto.h"
30 #include "librpc/rpc/dcerpc_proto.h"
31 #include "lib/events/events.h"
32 #include "smbd/service_task.h"
33 #include "smbd/service_stream.h"
34 #include "smbd/service.h"
35 #include "system/filesys.h"
36 #include "libcli/security/security.h"
37 #include "param/param.h"
38
39 extern const struct dcesrv_interface dcesrv_mgmt_interface;
40
41 /*
42   see if two endpoints match
43 */
44 static bool endpoints_match(const struct dcerpc_binding *ep1,
45                             const struct dcerpc_binding *ep2)
46 {
47         if (ep1->transport != ep2->transport) {
48                 return false;
49         }
50
51         if (!ep1->endpoint || !ep2->endpoint) {
52                 return ep1->endpoint == ep2->endpoint;
53         }
54
55         if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0) 
56                 return false;
57
58         return true;
59 }
60
61 /*
62   find an endpoint in the dcesrv_context
63 */
64 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
65                                              const struct dcerpc_binding *ep_description)
66 {
67         struct dcesrv_endpoint *ep;
68         for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
69                 if (endpoints_match(ep->ep_description, ep_description)) {
70                         return ep;
71                 }
72         }
73         return NULL;
74 }
75
76 /*
77   find a registered context_id from a bind or alter_context
78 */
79 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn, 
80                                                                    uint32_t context_id)
81 {
82         struct dcesrv_connection_context *c;
83         for (c=conn->contexts;c;c=c->next) {
84                 if (c->context_id == context_id) return c;
85         }
86         return NULL;
87 }
88
89 /*
90   see if a uuid and if_version match to an interface
91 */
92 static bool interface_match(const struct dcesrv_interface *if1,
93                                                         const struct dcesrv_interface *if2)
94 {
95         return (if1->syntax_id.if_version == if2->syntax_id.if_version && 
96                         GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
97 }
98
99 /*
100   find the interface operations on an endpoint
101 */
102 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
103                                                      const struct dcesrv_interface *iface)
104 {
105         struct dcesrv_if_list *ifl;
106         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
107                 if (interface_match(&(ifl->iface), iface)) {
108                         return &(ifl->iface);
109                 }
110         }
111         return NULL;
112 }
113
114 /*
115   see if a uuid and if_version match to an interface
116 */
117 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
118                                     const struct GUID *uuid, uint32_t if_version)
119 {
120         return (iface->syntax_id.if_version == if_version && 
121                         GUID_equal(&iface->syntax_id.uuid, uuid));
122 }
123
124 /*
125   find the interface operations on an endpoint by uuid
126 */
127 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
128                                                              const struct GUID *uuid, uint32_t if_version)
129 {
130         struct dcesrv_if_list *ifl;
131         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
132                 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
133                         return &(ifl->iface);
134                 }
135         }
136         return NULL;
137 }
138
139 /*
140   find the earlier parts of a fragmented call awaiting reassembily
141 */
142 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
143 {
144         struct dcesrv_call_state *c;
145         for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
146                 if (c->pkt.call_id == call_id) {
147                         return c;
148                 }
149         }
150         return NULL;
151 }
152
153 /*
154   register an interface on an endpoint
155 */
156 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
157                                    const char *ep_name,
158                                    const struct dcesrv_interface *iface,
159                                    const struct security_descriptor *sd)
160 {
161         struct dcesrv_endpoint *ep;
162         struct dcesrv_if_list *ifl;
163         struct dcerpc_binding *binding;
164         bool add_ep = false;
165         NTSTATUS status;
166         
167         status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
168
169         if (NT_STATUS_IS_ERR(status)) {
170                 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
171                 return status;
172         }
173
174         /* check if this endpoint exists
175          */
176         if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
177                 ep = talloc(dce_ctx, struct dcesrv_endpoint);
178                 if (!ep) {
179                         return NT_STATUS_NO_MEMORY;
180                 }
181                 ZERO_STRUCTP(ep);
182                 ep->ep_description = talloc_reference(ep, binding);
183                 add_ep = true;
184
185                 /* add mgmt interface */
186                 ifl = talloc(dce_ctx, struct dcesrv_if_list);
187                 if (!ifl) {
188                         return NT_STATUS_NO_MEMORY;
189                 }
190
191                 memcpy(&(ifl->iface), &dcesrv_mgmt_interface, 
192                            sizeof(struct dcesrv_interface));
193
194                 DLIST_ADD(ep->interface_list, ifl);
195         }
196
197         /* see if the interface is already registered on te endpoint */
198         if (find_interface(ep, iface)!=NULL) {
199                 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
200                         iface->name, ep_name));
201                 return NT_STATUS_OBJECT_NAME_COLLISION;
202         }
203
204         /* talloc a new interface list element */
205         ifl = talloc(dce_ctx, struct dcesrv_if_list);
206         if (!ifl) {
207                 return NT_STATUS_NO_MEMORY;
208         }
209
210         /* copy the given interface struct to the one on the endpoints interface list */
211         memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
212
213         /* if we have a security descriptor given,
214          * we should see if we can set it up on the endpoint
215          */
216         if (sd != NULL) {
217                 /* if there's currently no security descriptor given on the endpoint
218                  * we try to set it
219                  */
220                 if (ep->sd == NULL) {
221                         ep->sd = security_descriptor_copy(dce_ctx, sd);
222                 }
223
224                 /* if now there's no security descriptor given on the endpoint
225                  * something goes wrong, either we failed to copy the security descriptor
226                  * or there was already one on the endpoint
227                  */
228                 if (ep->sd != NULL) {
229                         DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
230                                  "                           on endpoint '%s'\n",
231                                 iface->name, ep_name));
232                         if (add_ep) free(ep);
233                         free(ifl);
234                         return NT_STATUS_OBJECT_NAME_COLLISION;
235                 }
236         }
237
238         /* finally add the interface on the endpoint */
239         DLIST_ADD(ep->interface_list, ifl);
240
241         /* if it's a new endpoint add it to the dcesrv_context */
242         if (add_ep) {
243                 DLIST_ADD(dce_ctx->endpoint_list, ep);
244         }
245
246         DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
247                 iface->name, ep_name));
248
249         return NT_STATUS_OK;
250 }
251
252 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
253                                               DATA_BLOB *session_key)
254 {
255         if (p->auth_state.session_info->session_key.length) {
256                 *session_key = p->auth_state.session_info->session_key;
257                 return NT_STATUS_OK;
258         }
259         return NT_STATUS_NO_USER_SESSION_KEY;
260 }
261
262 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
263                                     DATA_BLOB *session_key)
264 {
265         /* this took quite a few CPU cycles to find ... */
266         session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
267         session_key->length = 16;
268         return NT_STATUS_OK;
269 }
270
271 /*
272   fetch the user session key - may be default (above) or the SMB session key
273 */
274 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
275                                   DATA_BLOB *session_key)
276 {
277         return p->auth_state.session_key(p, session_key);
278 }
279
280
281 /*
282   destroy a link to an endpoint
283 */
284 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
285 {
286         while (p->contexts) {
287                 struct dcesrv_connection_context *c = p->contexts;
288
289                 DLIST_REMOVE(p->contexts, c);
290
291                 if (c->iface) {
292                         c->iface->unbind(c, c->iface);
293                 }
294         }
295
296         return 0;
297 }
298
299
300 /*
301   connect to a dcerpc endpoint
302 */
303 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
304                                  TALLOC_CTX *mem_ctx,
305                                  const struct dcesrv_endpoint *ep,
306                                  struct auth_session_info *session_info,
307                                  struct event_context *event_ctx,
308                                  struct messaging_context *msg_ctx,
309                                  struct server_id server_id,
310                                  uint32_t state_flags,
311                                  struct dcesrv_connection **_p)
312 {
313         struct dcesrv_connection *p;
314
315         if (!session_info) {
316                 return NT_STATUS_ACCESS_DENIED;
317         }
318
319         p = talloc(mem_ctx, struct dcesrv_connection);
320         NT_STATUS_HAVE_NO_MEMORY(p);
321
322         if (!talloc_reference(p, session_info)) {
323                 talloc_free(p);
324                 return NT_STATUS_NO_MEMORY;
325         }
326
327         p->dce_ctx = dce_ctx;
328         p->endpoint = ep;
329         p->contexts = NULL;
330         p->call_list = NULL;
331         p->incoming_fragmented_call_list = NULL;
332         p->pending_call_list = NULL;
333         p->cli_max_recv_frag = 0;
334         p->partial_input = data_blob(NULL, 0);
335         p->auth_state.auth_info = NULL;
336         p->auth_state.gensec_security = NULL;
337         p->auth_state.session_info = session_info;
338         p->auth_state.session_key = dcesrv_generic_session_key;
339         p->event_ctx = event_ctx;
340         p->msg_ctx = msg_ctx;
341         p->server_id = server_id;
342         p->processing = false;
343         p->state_flags = state_flags;
344         ZERO_STRUCT(p->transport);
345
346         talloc_set_destructor(p, dcesrv_endpoint_destructor);
347
348         *_p = p;
349         return NT_STATUS_OK;
350 }
351
352 /*
353   search and connect to a dcerpc endpoint
354 */
355 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
356                                         TALLOC_CTX *mem_ctx,
357                                         const struct dcerpc_binding *ep_description,
358                                         struct auth_session_info *session_info,
359                                         struct event_context *event_ctx,
360                                         struct messaging_context *msg_ctx,
361                                         struct server_id server_id,
362                                         uint32_t state_flags,
363                                         struct dcesrv_connection **dce_conn_p)
364 {
365         NTSTATUS status;
366         const struct dcesrv_endpoint *ep;
367
368         /* make sure this endpoint exists */
369         ep = find_endpoint(dce_ctx, ep_description);
370         if (!ep) {
371                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
372         }
373
374         status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
375                                          event_ctx, msg_ctx, server_id,
376                                          state_flags, dce_conn_p);
377         NT_STATUS_NOT_OK_RETURN(status);
378
379         (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
380
381         /* TODO: check security descriptor of the endpoint here 
382          *       if it's a smb named pipe
383          *       if it's failed free dce_conn_p
384          */
385
386         return NT_STATUS_OK;
387 }
388
389
390 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
391 {
392         pkt->rpc_vers = 5;
393         pkt->rpc_vers_minor = 0;
394         if (bigendian) {
395                 pkt->drep[0] = 0;
396         } else {
397                 pkt->drep[0] = DCERPC_DREP_LE;
398         }
399         pkt->drep[1] = 0;
400         pkt->drep[2] = 0;
401         pkt->drep[3] = 0;
402 }
403
404 /*
405   move a call from an existing linked list to the specified list. This
406   prevents bugs where we forget to remove the call from a previous
407   list when moving it.
408  */
409 static void dcesrv_call_set_list(struct dcesrv_call_state *call, 
410                                  enum dcesrv_call_list list)
411 {
412         switch (call->list) {
413         case DCESRV_LIST_NONE:
414                 break;
415         case DCESRV_LIST_CALL_LIST:
416                 DLIST_REMOVE(call->conn->call_list, call);
417                 break;
418         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
419                 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
420                 break;
421         case DCESRV_LIST_PENDING_CALL_LIST:
422                 DLIST_REMOVE(call->conn->pending_call_list, call);
423                 break;
424         }
425         call->list = list;
426         switch (list) {
427         case DCESRV_LIST_NONE:
428                 break;
429         case DCESRV_LIST_CALL_LIST:
430                 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
431                 break;
432         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
433                 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
434                 break;
435         case DCESRV_LIST_PENDING_CALL_LIST:
436                 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
437                 break;
438         }
439 }
440
441 /*
442   return a dcerpc fault
443 */
444 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
445 {
446         struct ncacn_packet pkt;
447         struct data_blob_list_item *rep;
448         uint8_t zeros[4];
449         NTSTATUS status;
450
451         /* setup a bind_ack */
452         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
453         pkt.auth_length = 0;
454         pkt.call_id = call->pkt.call_id;
455         pkt.ptype = DCERPC_PKT_FAULT;
456         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
457         pkt.u.fault.alloc_hint = 0;
458         pkt.u.fault.context_id = 0;
459         pkt.u.fault.cancel_count = 0;
460         pkt.u.fault.status = fault_code;
461
462         ZERO_STRUCT(zeros);
463         pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
464
465         rep = talloc(call, struct data_blob_list_item);
466         if (!rep) {
467                 return NT_STATUS_NO_MEMORY;
468         }
469
470         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
471         if (!NT_STATUS_IS_OK(status)) {
472                 return status;
473         }
474
475         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
476
477         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
478         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
479
480         return NT_STATUS_OK;    
481 }
482
483
484 /*
485   return a dcerpc bind_nak
486 */
487 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
488 {
489         struct ncacn_packet pkt;
490         struct data_blob_list_item *rep;
491         NTSTATUS status;
492
493         /* setup a bind_nak */
494         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
495         pkt.auth_length = 0;
496         pkt.call_id = call->pkt.call_id;
497         pkt.ptype = DCERPC_PKT_BIND_NAK;
498         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
499         pkt.u.bind_nak.reject_reason = reason;
500         if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
501                 pkt.u.bind_nak.versions.v.num_versions = 0;
502         }
503
504         rep = talloc(call, struct data_blob_list_item);
505         if (!rep) {
506                 return NT_STATUS_NO_MEMORY;
507         }
508
509         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
510         if (!NT_STATUS_IS_OK(status)) {
511                 return status;
512         }
513
514         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
515
516         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
517         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
518
519         return NT_STATUS_OK;    
520 }
521
522
523 /*
524   handle a bind request
525 */
526 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
527 {
528         uint32_t if_version, transfer_syntax_version;
529         struct GUID uuid, *transfer_syntax_uuid;
530         struct ncacn_packet pkt;
531         struct data_blob_list_item *rep;
532         NTSTATUS status;
533         uint32_t result=0, reason=0;
534         uint32_t context_id;
535         const struct dcesrv_interface *iface;
536
537 #if 0
538         /* It is not safe to enable this check - windows clients
539          * (WinXP in particular) will use it for NETLOGON calls, for
540          * the subsequent SCHANNEL bind.  It turns out that NETLOGON
541          * calls include no policy handles, so it is safe there.  Let
542          * the failure occour on the attempt to reuse a poilcy handle,
543          * rather than here */
544
545         /* Association groups allow policy handles to be shared across
546          * multiple client connections.  We don't implement this yet. */
547         if (call->pkt.u.bind.assoc_group_id != 0) {
548                 return dcesrv_bind_nak(call, 0);        
549         }
550 #endif
551
552         if (call->pkt.u.bind.num_contexts < 1 ||
553             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
554                 return dcesrv_bind_nak(call, 0);
555         }
556
557         context_id = call->pkt.u.bind.ctx_list[0].context_id;
558
559         /* you can't bind twice on one context */
560         if (dcesrv_find_context(call->conn, context_id) != NULL) {
561                 return dcesrv_bind_nak(call, 0);
562         }
563
564         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
565         uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
566
567         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
568         transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
569         if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
570             ndr_transfer_syntax.if_version != transfer_syntax_version) {
571                 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
572                 /* we only do NDR encoded dcerpc */
573                 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
574                 talloc_free(uuid_str);
575                 return dcesrv_bind_nak(call, 0);
576         }
577
578         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
579         if (iface == NULL) {
580                 char *uuid_str = GUID_string(call, &uuid);
581                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
582                 talloc_free(uuid_str);
583
584                 /* we don't know about that interface */
585                 result = DCERPC_BIND_PROVIDER_REJECT;
586                 reason = DCERPC_BIND_REASON_ASYNTAX;            
587         }
588
589         if (iface) {
590                 /* add this context to the list of available context_ids */
591                 struct dcesrv_connection_context *context = talloc(call->conn, 
592                                                                    struct dcesrv_connection_context);
593                 if (context == NULL) {
594                         return dcesrv_bind_nak(call, 0);
595                 }
596                 context->conn = call->conn;
597                 context->iface = iface;
598                 context->context_id = context_id;
599                 context->private = NULL;
600                 context->handles = NULL;
601                 DLIST_ADD(call->conn->contexts, context);
602                 call->context = context;
603         }
604
605         if (call->conn->cli_max_recv_frag == 0) {
606                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
607         }
608
609         /* handle any authentication that is being requested */
610         if (!dcesrv_auth_bind(call)) {
611                 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
612         }
613
614         /* setup a bind_ack */
615         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
616         pkt.auth_length = 0;
617         pkt.call_id = call->pkt.call_id;
618         pkt.ptype = DCERPC_PKT_BIND_ACK;
619         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
620         pkt.u.bind_ack.max_xmit_frag = 0x2000;
621         pkt.u.bind_ack.max_recv_frag = 0x2000;
622         /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
623         pkt.u.bind_ack.assoc_group_id = 0x12345678;
624         if (iface) {
625                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
626                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
627         } else {
628                 pkt.u.bind_ack.secondary_address = "";
629         }
630         pkt.u.bind_ack.num_results = 1;
631         pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
632         if (!pkt.u.bind_ack.ctx_list) {
633                 return NT_STATUS_NO_MEMORY;
634         }
635         pkt.u.bind_ack.ctx_list[0].result = result;
636         pkt.u.bind_ack.ctx_list[0].reason = reason;
637         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
638         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
639
640         status = dcesrv_auth_bind_ack(call, &pkt);
641         if (!NT_STATUS_IS_OK(status)) {
642                 return dcesrv_bind_nak(call, 0);
643         }
644
645         if (iface) {
646                 status = iface->bind(call, iface);
647                 if (!NT_STATUS_IS_OK(status)) {
648                         char *uuid_str = GUID_string(call, &uuid);
649                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", 
650                                  uuid_str, if_version, nt_errstr(status)));
651                         talloc_free(uuid_str);
652                         return dcesrv_bind_nak(call, 0);
653                 }
654         }
655
656         rep = talloc(call, struct data_blob_list_item);
657         if (!rep) {
658                 return NT_STATUS_NO_MEMORY;
659         }
660
661         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
662         if (!NT_STATUS_IS_OK(status)) {
663                 return status;
664         }
665
666         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
667
668         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
669         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
670
671         return NT_STATUS_OK;
672 }
673
674
675 /*
676   handle a auth3 request
677 */
678 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
679 {
680         /* handle the auth3 in the auth code */
681         if (!dcesrv_auth_auth3(call)) {
682                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
683         }
684
685         talloc_free(call);
686
687         /* we don't send a reply to a auth3 request, except by a
688            fault */
689         return NT_STATUS_OK;
690 }
691
692
693 /*
694   handle a bind request
695 */
696 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
697 {
698         uint32_t if_version, transfer_syntax_version;
699         struct dcesrv_connection_context *context;
700         const struct dcesrv_interface *iface;
701         struct GUID uuid, *transfer_syntax_uuid;
702         NTSTATUS status;
703
704         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
705         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
706
707         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
708         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
709         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
710             ndr_transfer_syntax.if_version != transfer_syntax_version) {
711                 /* we only do NDR encoded dcerpc */
712                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
713         }
714
715         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
716         if (iface == NULL) {
717                 char *uuid_str = GUID_string(call, &uuid);
718                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
719                 talloc_free(uuid_str);
720                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
721         }
722
723         /* add this context to the list of available context_ids */
724         context = talloc(call->conn, struct dcesrv_connection_context);
725         if (context == NULL) {
726                 return NT_STATUS_NO_MEMORY;
727         }
728         context->conn = call->conn;
729         context->iface = iface;
730         context->context_id = context_id;
731         context->private = NULL;
732         context->handles = NULL;
733         DLIST_ADD(call->conn->contexts, context);
734         call->context = context;
735
736         if (iface) {
737                 status = iface->bind(call, iface);
738                 if (!NT_STATUS_IS_OK(status)) {
739                         return status;
740                 }
741         }
742
743         return NT_STATUS_OK;
744 }
745
746
747 /*
748   handle a alter context request
749 */
750 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
751 {
752         struct ncacn_packet pkt;
753         struct data_blob_list_item *rep;
754         NTSTATUS status;
755         uint32_t result=0, reason=0;
756         uint32_t context_id;
757
758         /* handle any authentication that is being requested */
759         if (!dcesrv_auth_alter(call)) {
760                 /* TODO: work out the right reject code */
761                 result = DCERPC_BIND_PROVIDER_REJECT;
762                 reason = DCERPC_BIND_REASON_ASYNTAX;            
763         }
764
765         context_id = call->pkt.u.alter.ctx_list[0].context_id;
766
767         /* see if they are asking for a new interface */
768         if (result == 0 &&
769             dcesrv_find_context(call->conn, context_id) == NULL) {
770                 status = dcesrv_alter_new_context(call, context_id);
771                 if (!NT_STATUS_IS_OK(status)) {
772                         result = DCERPC_BIND_PROVIDER_REJECT;
773                         reason = DCERPC_BIND_REASON_ASYNTAX;            
774                 }
775         }
776
777         /* setup a alter_resp */
778         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
779         pkt.auth_length = 0;
780         pkt.call_id = call->pkt.call_id;
781         pkt.ptype = DCERPC_PKT_ALTER_RESP;
782         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
783         pkt.u.alter_resp.max_xmit_frag = 0x2000;
784         pkt.u.alter_resp.max_recv_frag = 0x2000;
785         pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
786         pkt.u.alter_resp.num_results = 1;
787         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
788         if (!pkt.u.alter_resp.ctx_list) {
789                 return NT_STATUS_NO_MEMORY;
790         }
791         pkt.u.alter_resp.ctx_list[0].result = result;
792         pkt.u.alter_resp.ctx_list[0].reason = reason;
793         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
794         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
795         pkt.u.alter_resp.secondary_address = "";
796
797         status = dcesrv_auth_alter_ack(call, &pkt);
798         if (!NT_STATUS_IS_OK(status)) {
799                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
800                     || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
801                     || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
802                     || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
803                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
804                 }
805                 return dcesrv_fault(call, 0);
806         }
807
808         rep = talloc(call, struct data_blob_list_item);
809         if (!rep) {
810                 return NT_STATUS_NO_MEMORY;
811         }
812
813         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
814         if (!NT_STATUS_IS_OK(status)) {
815                 return status;
816         }
817
818         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
819
820         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
821         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
822
823         return NT_STATUS_OK;
824 }
825
826 /*
827   handle a dcerpc request packet
828 */
829 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
830 {
831         struct ndr_pull *pull;
832         NTSTATUS status;
833         struct dcesrv_connection_context *context;
834
835         /* if authenticated, and the mech we use can't do async replies, don't use them... */
836         if (call->conn->auth_state.gensec_security && 
837             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
838                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
839         }
840
841         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
842         if (context == NULL) {
843                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
844         }
845
846         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
847                                   lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
848         NT_STATUS_HAVE_NO_MEMORY(pull);
849
850         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
851
852         call->context   = context;
853         call->ndr_pull  = pull;
854
855         if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
856                 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
857         }
858
859         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
860                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
861         }
862
863         /* unravel the NDR for the packet */
864         status = context->iface->ndr_pull(call, call, pull, &call->r);
865         if (!NT_STATUS_IS_OK(status)) {
866                 return dcesrv_fault(call, call->fault_code);
867         }
868
869         if (pull->offset != pull->data_size) {
870                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
871                          pull->data_size - pull->offset));
872                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
873         }
874
875         /* call the dispatch function */
876         status = context->iface->dispatch(call, call, call->r);
877         if (!NT_STATUS_IS_OK(status)) {
878                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
879                          context->iface->name, 
880                          call->pkt.u.request.opnum,
881                          dcerpc_errstr(pull, call->fault_code)));
882                 return dcesrv_fault(call, call->fault_code);
883         }
884
885         /* add the call to the pending list */
886         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
887
888         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
889                 return NT_STATUS_OK;
890         }
891
892         return dcesrv_reply(call);
893 }
894
895 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
896 {
897         struct ndr_push *push;
898         NTSTATUS status;
899         DATA_BLOB stub;
900         uint32_t total_length, chunk_size;
901         struct dcesrv_connection_context *context = call->context;
902
903         /* call the reply function */
904         status = context->iface->reply(call, call, call->r);
905         if (!NT_STATUS_IS_OK(status)) {
906                 return dcesrv_fault(call, call->fault_code);
907         }
908
909         /* form the reply NDR */
910         push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
911         NT_STATUS_HAVE_NO_MEMORY(push);
912
913         /* carry over the pointer count to the reply in case we are
914            using full pointer. See NDR specification for full
915            pointers */
916         push->ptr_count = call->ndr_pull->ptr_count;
917
918         if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
919                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
920         }
921
922         status = context->iface->ndr_push(call, call, push, call->r);
923         if (!NT_STATUS_IS_OK(status)) {
924                 return dcesrv_fault(call, call->fault_code);
925         }
926
927         stub = ndr_push_blob(push);
928
929         total_length = stub.length;
930
931         /* we can write a full max_recv_frag size, minus the dcerpc
932            request header size */
933         chunk_size = call->conn->cli_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
934
935         do {
936                 uint32_t length;
937                 struct data_blob_list_item *rep;
938                 struct ncacn_packet pkt;
939                 const uint32_t overhead = (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
940
941                 rep = talloc(call, struct data_blob_list_item);
942                 NT_STATUS_HAVE_NO_MEMORY(rep);
943
944                 length = MIN(chunk_size, stub.length);
945
946                 /* form the dcerpc response packet */
947                 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
948                 pkt.auth_length = 0;
949                 pkt.call_id = call->pkt.call_id;
950                 pkt.ptype = DCERPC_PKT_RESPONSE;
951                 pkt.pfc_flags = 0;
952                 if (stub.length == total_length) {
953                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
954                 }
955                 if (length == stub.length) {
956                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
957                 }
958                 pkt.u.response.alloc_hint = stub.length;
959                 pkt.u.response.context_id = call->pkt.u.request.context_id;
960                 pkt.u.response.cancel_count = 0;
961                 pkt.u.response.stub_and_verifier.data = stub.data;
962                 pkt.u.response.stub_and_verifier.length = length;
963
964                 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
965                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
966                 }
967
968                 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
969
970                 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
971                 
972                 stub.data += length;
973                 stub.length -= length;
974         } while (stub.length != 0);
975
976         /* move the call from the pending to the finished calls list */
977         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
978
979         if (call->conn->call_list && call->conn->call_list->replies) {
980                 if (call->conn->transport.report_output_data) {
981                         call->conn->transport.report_output_data(call->conn);
982                 }
983         }
984
985         return NT_STATUS_OK;
986 }
987
988 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
989 {
990         if (!conn->transport.get_my_addr) {
991                 return NULL;
992         }
993
994         return conn->transport.get_my_addr(conn, mem_ctx);
995 }
996
997 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
998 {
999         if (!conn->transport.get_peer_addr) {
1000                 return NULL;
1001         }
1002
1003         return conn->transport.get_peer_addr(conn, mem_ctx);
1004 }
1005
1006 /*
1007   work out if we have a full packet yet
1008 */
1009 static bool dce_full_packet(const DATA_BLOB *data)
1010 {
1011         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1012                 return false;
1013         }
1014         if (dcerpc_get_frag_length(data) > data->length) {
1015                 return false;
1016         }
1017         return true;
1018 }
1019
1020 /*
1021   we might have consumed only part of our input - advance past that part
1022 */
1023 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1024 {
1025         DATA_BLOB blob;
1026
1027         if (dce_conn->partial_input.length == offset) {
1028                 data_blob_free(&dce_conn->partial_input);
1029                 return;
1030         }
1031
1032         blob = dce_conn->partial_input;
1033         dce_conn->partial_input = data_blob(blob.data + offset,
1034                                             blob.length - offset);
1035         data_blob_free(&blob);
1036 }
1037
1038 /*
1039   remove the call from the right list when freed
1040  */
1041 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1042 {
1043         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1044         return 0;
1045 }
1046
1047 /*
1048   process some input to a dcerpc endpoint server.
1049 */
1050 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1051 {
1052         struct ndr_pull *ndr;
1053         enum ndr_err_code ndr_err;
1054         NTSTATUS status;
1055         struct dcesrv_call_state *call;
1056         DATA_BLOB blob;
1057
1058         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1059         if (!call) {
1060                 talloc_free(dce_conn->partial_input.data);
1061                 return NT_STATUS_NO_MEMORY;
1062         }
1063         call->conn              = dce_conn;
1064         call->event_ctx         = dce_conn->event_ctx;
1065         call->msg_ctx           = dce_conn->msg_ctx;
1066         call->state_flags       = call->conn->state_flags;
1067         call->time              = timeval_current();
1068         call->list              = DCESRV_LIST_NONE;
1069
1070         talloc_set_destructor(call, dcesrv_call_dequeue);
1071
1072         blob = dce_conn->partial_input;
1073         blob.length = dcerpc_get_frag_length(&blob);
1074
1075         ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1076         if (!ndr) {
1077                 talloc_free(dce_conn->partial_input.data);
1078                 talloc_free(call);
1079                 return NT_STATUS_NO_MEMORY;
1080         }
1081
1082         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1083                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1084         }
1085
1086         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1087         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1088                 talloc_free(dce_conn->partial_input.data);
1089                 talloc_free(call);
1090                 return ndr_map_error2ntstatus(ndr_err);
1091         }
1092
1093         /* we have to check the signing here, before combining the
1094            pdus */
1095         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1096             !dcesrv_auth_request(call, &blob)) {
1097                 dce_partial_advance(dce_conn, blob.length);
1098                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1099         }
1100
1101         dce_partial_advance(dce_conn, blob.length);
1102
1103         /* see if this is a continued packet */
1104         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1105             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1106                 struct dcesrv_call_state *call2 = call;
1107                 uint32_t alloc_size;
1108
1109                 /* we only allow fragmented requests, no other packet types */
1110                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1111                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1112                 }
1113
1114                 /* this is a continuation of an existing call - find the call then
1115                    tack it on the end */
1116                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1117                 if (!call) {
1118                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1119                 }
1120
1121                 if (call->pkt.ptype != call2->pkt.ptype) {
1122                         /* trying to play silly buggers are we? */
1123                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1124                 }
1125
1126                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1127                         call2->pkt.u.request.stub_and_verifier.length;
1128                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1129                         alloc_size = call->pkt.u.request.alloc_hint;
1130                 }
1131
1132                 call->pkt.u.request.stub_and_verifier.data = 
1133                         talloc_realloc(call, 
1134                                        call->pkt.u.request.stub_and_verifier.data, 
1135                                        uint8_t, alloc_size);
1136                 if (!call->pkt.u.request.stub_and_verifier.data) {
1137                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1138                 }
1139                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1140                        call->pkt.u.request.stub_and_verifier.length,
1141                        call2->pkt.u.request.stub_and_verifier.data,
1142                        call2->pkt.u.request.stub_and_verifier.length);
1143                 call->pkt.u.request.stub_and_verifier.length += 
1144                         call2->pkt.u.request.stub_and_verifier.length;
1145
1146                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1147
1148                 talloc_free(call2);
1149         }
1150
1151         /* this may not be the last pdu in the chain - if its isn't then
1152            just put it on the incoming_fragmented_call_list and wait for the rest */
1153         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1154             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1155                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1156                 return NT_STATUS_OK;
1157         } 
1158         
1159         /* This removes any fragments we may have had stashed away */
1160         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1161
1162         switch (call->pkt.ptype) {
1163         case DCERPC_PKT_BIND:
1164                 status = dcesrv_bind(call);
1165                 break;
1166         case DCERPC_PKT_AUTH3:
1167                 status = dcesrv_auth3(call);
1168                 break;
1169         case DCERPC_PKT_ALTER:
1170                 status = dcesrv_alter(call);
1171                 break;
1172         case DCERPC_PKT_REQUEST:
1173                 status = dcesrv_request(call);
1174                 break;
1175         default:
1176                 status = NT_STATUS_INVALID_PARAMETER;
1177                 break;
1178         }
1179
1180         /* if we are going to be sending a reply then add
1181            it to the list of pending calls. We add it to the end to keep the call
1182            list in the order we will answer */
1183         if (!NT_STATUS_IS_OK(status)) {
1184                 talloc_free(call);
1185         }
1186
1187         return status;
1188 }
1189
1190
1191 /*
1192   provide some input to a dcerpc endpoint server. This passes data
1193   from a dcerpc client into the server
1194 */
1195 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1196 {
1197         NTSTATUS status;
1198
1199         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1200                                                       dce_conn->partial_input.data,
1201                                                       uint8_t,
1202                                                       dce_conn->partial_input.length + data->length);
1203         if (!dce_conn->partial_input.data) {
1204                 return NT_STATUS_NO_MEMORY;
1205         }
1206         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1207                data->data, data->length);
1208         dce_conn->partial_input.length += data->length;
1209
1210         while (dce_full_packet(&dce_conn->partial_input)) {
1211                 status = dcesrv_input_process(dce_conn);
1212                 if (!NT_STATUS_IS_OK(status)) {
1213                         return status;
1214                 }
1215         }
1216
1217         return NT_STATUS_OK;
1218 }
1219
1220 /*
1221   retrieve some output from a dcerpc server
1222   The caller supplies a function that will be called to do the
1223   actual output. 
1224
1225   The first argument to write_fn() will be 'private', the second will
1226   be a pointer to a buffer containing the data to be sent and the 3rd
1227   will be a pointer to a size_t variable that will be set to the
1228   number of bytes that are consumed from the output.
1229
1230   from the current fragment
1231 */
1232 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1233                        void *private_data,
1234                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1235 {
1236         NTSTATUS status;
1237         struct dcesrv_call_state *call;
1238         struct data_blob_list_item *rep;
1239         size_t nwritten;
1240
1241         call = dce_conn->call_list;
1242         if (!call || !call->replies) {
1243                 if (dce_conn->pending_call_list) {
1244                         /* TODO: we need to say act async here
1245                          *       as we know we have pending requests
1246                          *       which will be finished at a time
1247                          */
1248                         return NT_STATUS_FOOBAR;
1249                 }
1250                 return NT_STATUS_FOOBAR;
1251         }
1252         rep = call->replies;
1253
1254         status = write_fn(private_data, &rep->blob, &nwritten);
1255         NT_STATUS_IS_ERR_RETURN(status);
1256
1257         rep->blob.length -= nwritten;
1258         rep->blob.data += nwritten;
1259
1260         if (rep->blob.length == 0) {
1261                 /* we're done with this section of the call */
1262                 DLIST_REMOVE(call->replies, rep);
1263         }
1264
1265         if (call->replies == NULL) {
1266                 /* we're done with the whole call */
1267                 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1268                 talloc_free(call);
1269         }
1270
1271         return status;
1272 }
1273
1274 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1275                                       struct loadparm_context *lp_ctx,
1276                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1277 {
1278         NTSTATUS status;
1279         struct dcesrv_context *dce_ctx;
1280         int i;
1281
1282         if (!endpoint_servers) {
1283                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1284                 return NT_STATUS_INTERNAL_ERROR;
1285         }
1286
1287         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1288         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1289         dce_ctx->endpoint_list  = NULL;
1290         dce_ctx->lp_ctx = lp_ctx;
1291
1292         for (i=0;endpoint_servers[i];i++) {
1293                 const struct dcesrv_endpoint_server *ep_server;
1294
1295                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1296                 if (!ep_server) {
1297                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1298                         return NT_STATUS_INTERNAL_ERROR;
1299                 }
1300
1301                 status = ep_server->init_server(dce_ctx, ep_server);
1302                 if (!NT_STATUS_IS_OK(status)) {
1303                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1304                                 nt_errstr(status)));
1305                         return status;
1306                 }
1307         }
1308
1309         *_dce_ctx = dce_ctx;
1310         return NT_STATUS_OK;
1311 }
1312
1313 /* the list of currently registered DCERPC endpoint servers.
1314  */
1315 static struct ep_server {
1316         struct dcesrv_endpoint_server *ep_server;
1317 } *ep_servers = NULL;
1318 static int num_ep_servers;
1319
1320 /*
1321   register a DCERPC endpoint server. 
1322
1323   The 'name' can be later used by other backends to find the operations
1324   structure for this backend.  
1325
1326   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1327 */
1328 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1329 {
1330         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1331         
1332         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1333                 /* its already registered! */
1334                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1335                          ep_server->name));
1336                 return NT_STATUS_OBJECT_NAME_COLLISION;
1337         }
1338
1339         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1340         if (!ep_servers) {
1341                 smb_panic("out of memory in dcerpc_register");
1342         }
1343
1344         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1345         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1346
1347         num_ep_servers++;
1348
1349         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1350                  ep_server->name));
1351
1352         return NT_STATUS_OK;
1353 }
1354
1355 /*
1356   return the operations structure for a named backend of the specified type
1357 */
1358 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1359 {
1360         int i;
1361
1362         for (i=0;i<num_ep_servers;i++) {
1363                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1364                         return ep_servers[i].ep_server;
1365                 }
1366         }
1367
1368         return NULL;
1369 }
1370
1371 /*
1372   return the DCERPC module version, and the size of some critical types
1373   This can be used by endpoint server modules to either detect compilation errors, or provide
1374   multiple implementations for different smbd compilation options in one module
1375 */
1376 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1377 {
1378         static const struct dcesrv_critical_sizes critical_sizes = {
1379                 DCERPC_MODULE_VERSION,
1380                 sizeof(struct dcesrv_context),
1381                 sizeof(struct dcesrv_endpoint),
1382                 sizeof(struct dcesrv_endpoint_server),
1383                 sizeof(struct dcesrv_interface),
1384                 sizeof(struct dcesrv_if_list),
1385                 sizeof(struct dcesrv_connection),
1386                 sizeof(struct dcesrv_call_state),
1387                 sizeof(struct dcesrv_auth),
1388                 sizeof(struct dcesrv_handle)
1389         };
1390
1391         return &critical_sizes;
1392 }
1393
1394 /*
1395   initialise the dcerpc server context for ncacn_np based services
1396 */
1397 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1398                                           struct dcesrv_context **_dce_ctx)
1399 {
1400         NTSTATUS status;
1401         struct dcesrv_context *dce_ctx;
1402
1403         status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1404         NT_STATUS_NOT_OK_RETURN(status);
1405
1406         *_dce_ctx = dce_ctx;
1407         return NT_STATUS_OK;
1408 }
1409
1410