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