Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-gmake3
[abartlet/samba.git/.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         NTSTATUS status;
449
450         /* setup a bind_ack */
451         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
452         pkt.auth_length = 0;
453         pkt.call_id = call->pkt.call_id;
454         pkt.ptype = DCERPC_PKT_FAULT;
455         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
456         pkt.u.fault.alloc_hint = 0;
457         pkt.u.fault.context_id = 0;
458         pkt.u.fault.cancel_count = 0;
459         pkt.u.fault.status = fault_code;
460
461         rep = talloc(call, struct data_blob_list_item);
462         if (!rep) {
463                 return NT_STATUS_NO_MEMORY;
464         }
465
466         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
467         if (!NT_STATUS_IS_OK(status)) {
468                 return status;
469         }
470
471         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
472
473         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
474         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
475
476         return NT_STATUS_OK;    
477 }
478
479
480 /*
481   return a dcerpc bind_nak
482 */
483 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
484 {
485         struct ncacn_packet pkt;
486         struct data_blob_list_item *rep;
487         NTSTATUS status;
488
489         /* setup a bind_nak */
490         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
491         pkt.auth_length = 0;
492         pkt.call_id = call->pkt.call_id;
493         pkt.ptype = DCERPC_PKT_BIND_NAK;
494         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
495         pkt.u.bind_nak.reject_reason = reason;
496         if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
497                 pkt.u.bind_nak.versions.v.num_versions = 0;
498         }
499
500         rep = talloc(call, struct data_blob_list_item);
501         if (!rep) {
502                 return NT_STATUS_NO_MEMORY;
503         }
504
505         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
506         if (!NT_STATUS_IS_OK(status)) {
507                 return status;
508         }
509
510         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
511
512         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
513         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
514
515         return NT_STATUS_OK;    
516 }
517
518
519 /*
520   handle a bind request
521 */
522 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
523 {
524         uint32_t if_version, transfer_syntax_version;
525         struct GUID uuid, *transfer_syntax_uuid;
526         struct ncacn_packet pkt;
527         struct data_blob_list_item *rep;
528         NTSTATUS status;
529         uint32_t result=0, reason=0;
530         uint32_t context_id;
531         const struct dcesrv_interface *iface;
532
533         if (call->pkt.u.bind.assoc_group_id != 0) {
534                 return dcesrv_bind_nak(call, 0);        
535         }
536
537         if (call->pkt.u.bind.num_contexts < 1 ||
538             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
539                 return dcesrv_bind_nak(call, 0);
540         }
541
542         context_id = call->pkt.u.bind.ctx_list[0].context_id;
543
544         /* you can't bind twice on one context */
545         if (dcesrv_find_context(call->conn, context_id) != NULL) {
546                 return dcesrv_bind_nak(call, 0);
547         }
548
549         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
550         uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
551
552         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
553         transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
554         if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
555             ndr_transfer_syntax.if_version != transfer_syntax_version) {
556                 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
557                 /* we only do NDR encoded dcerpc */
558                 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
559                 talloc_free(uuid_str);
560                 return dcesrv_bind_nak(call, 0);
561         }
562
563         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
564         if (iface == NULL) {
565                 char *uuid_str = GUID_string(call, &uuid);
566                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
567                 talloc_free(uuid_str);
568
569                 /* we don't know about that interface */
570                 result = DCERPC_BIND_PROVIDER_REJECT;
571                 reason = DCERPC_BIND_REASON_ASYNTAX;            
572         }
573
574         if (iface) {
575                 /* add this context to the list of available context_ids */
576                 struct dcesrv_connection_context *context = talloc(call->conn, 
577                                                                    struct dcesrv_connection_context);
578                 if (context == NULL) {
579                         return dcesrv_bind_nak(call, 0);
580                 }
581                 context->conn = call->conn;
582                 context->iface = iface;
583                 context->context_id = context_id;
584                 context->private = NULL;
585                 context->handles = NULL;
586                 DLIST_ADD(call->conn->contexts, context);
587                 call->context = context;
588         }
589
590         if (call->conn->cli_max_recv_frag == 0) {
591                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
592         }
593
594         /* handle any authentication that is being requested */
595         if (!dcesrv_auth_bind(call)) {
596                 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
597         }
598
599         /* setup a bind_ack */
600         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
601         pkt.auth_length = 0;
602         pkt.call_id = call->pkt.call_id;
603         pkt.ptype = DCERPC_PKT_BIND_ACK;
604         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
605         pkt.u.bind_ack.max_xmit_frag = 0x2000;
606         pkt.u.bind_ack.max_recv_frag = 0x2000;
607         /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
608         pkt.u.bind_ack.assoc_group_id = 0x12345678;
609         if (iface) {
610                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
611                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
612         } else {
613                 pkt.u.bind_ack.secondary_address = "";
614         }
615         pkt.u.bind_ack.num_results = 1;
616         pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
617         if (!pkt.u.bind_ack.ctx_list) {
618                 return NT_STATUS_NO_MEMORY;
619         }
620         pkt.u.bind_ack.ctx_list[0].result = result;
621         pkt.u.bind_ack.ctx_list[0].reason = reason;
622         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
623         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
624
625         status = dcesrv_auth_bind_ack(call, &pkt);
626         if (!NT_STATUS_IS_OK(status)) {
627                 return dcesrv_bind_nak(call, 0);
628         }
629
630         if (iface) {
631                 status = iface->bind(call, iface);
632                 if (!NT_STATUS_IS_OK(status)) {
633                         char *uuid_str = GUID_string(call, &uuid);
634                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", 
635                                  uuid_str, if_version, nt_errstr(status)));
636                         talloc_free(uuid_str);
637                         return dcesrv_bind_nak(call, 0);
638                 }
639         }
640
641         rep = talloc(call, struct data_blob_list_item);
642         if (!rep) {
643                 return NT_STATUS_NO_MEMORY;
644         }
645
646         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
647         if (!NT_STATUS_IS_OK(status)) {
648                 return status;
649         }
650
651         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
652
653         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
654         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
655
656         return NT_STATUS_OK;
657 }
658
659
660 /*
661   handle a auth3 request
662 */
663 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
664 {
665         /* handle the auth3 in the auth code */
666         if (!dcesrv_auth_auth3(call)) {
667                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
668         }
669
670         talloc_free(call);
671
672         /* we don't send a reply to a auth3 request, except by a
673            fault */
674         return NT_STATUS_OK;
675 }
676
677
678 /*
679   handle a bind request
680 */
681 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
682 {
683         uint32_t if_version, transfer_syntax_version;
684         struct dcesrv_connection_context *context;
685         const struct dcesrv_interface *iface;
686         struct GUID uuid, *transfer_syntax_uuid;
687
688         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
689         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
690
691         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
692         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
693         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
694             ndr_transfer_syntax.if_version != transfer_syntax_version) {
695                 /* we only do NDR encoded dcerpc */
696                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
697         }
698
699         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
700         if (iface == NULL) {
701                 char *uuid_str = GUID_string(call, &uuid);
702                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
703                 talloc_free(uuid_str);
704                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
705         }
706
707         /* add this context to the list of available context_ids */
708         context = talloc(call->conn, struct dcesrv_connection_context);
709         if (context == NULL) {
710                 return NT_STATUS_NO_MEMORY;
711         }
712         context->conn = call->conn;
713         context->iface = iface;
714         context->context_id = context_id;
715         context->private = NULL;
716         context->handles = NULL;
717         DLIST_ADD(call->conn->contexts, context);
718         call->context = context;
719
720         return NT_STATUS_OK;
721 }
722
723
724 /*
725   handle a alter context request
726 */
727 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
728 {
729         struct ncacn_packet pkt;
730         struct data_blob_list_item *rep;
731         NTSTATUS status;
732         uint32_t result=0, reason=0;
733         uint32_t context_id;
734
735         /* handle any authentication that is being requested */
736         if (!dcesrv_auth_alter(call)) {
737                 /* TODO: work out the right reject code */
738                 result = DCERPC_BIND_PROVIDER_REJECT;
739                 reason = DCERPC_BIND_REASON_ASYNTAX;            
740         }
741
742         context_id = call->pkt.u.alter.ctx_list[0].context_id;
743
744         /* see if they are asking for a new interface */
745         if (result == 0 &&
746             dcesrv_find_context(call->conn, context_id) == NULL) {
747                 status = dcesrv_alter_new_context(call, context_id);
748                 if (!NT_STATUS_IS_OK(status)) {
749                         result = DCERPC_BIND_PROVIDER_REJECT;
750                         reason = DCERPC_BIND_REASON_ASYNTAX;            
751                 }
752         }
753
754         /* setup a alter_resp */
755         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
756         pkt.auth_length = 0;
757         pkt.call_id = call->pkt.call_id;
758         pkt.ptype = DCERPC_PKT_ALTER_RESP;
759         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
760         pkt.u.alter_resp.max_xmit_frag = 0x2000;
761         pkt.u.alter_resp.max_recv_frag = 0x2000;
762         pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
763         pkt.u.alter_resp.num_results = 1;
764         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
765         if (!pkt.u.alter_resp.ctx_list) {
766                 return NT_STATUS_NO_MEMORY;
767         }
768         pkt.u.alter_resp.ctx_list[0].result = result;
769         pkt.u.alter_resp.ctx_list[0].reason = reason;
770         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
771         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
772         pkt.u.alter_resp.secondary_address = "";
773
774         status = dcesrv_auth_alter_ack(call, &pkt);
775         if (!NT_STATUS_IS_OK(status)) {
776                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
777                     || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
778                     || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
779                     || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
780                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
781                 }
782                 return dcesrv_fault(call, 0);
783         }
784
785         rep = talloc(call, struct data_blob_list_item);
786         if (!rep) {
787                 return NT_STATUS_NO_MEMORY;
788         }
789
790         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
791         if (!NT_STATUS_IS_OK(status)) {
792                 return status;
793         }
794
795         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
796
797         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
798         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
799
800         return NT_STATUS_OK;
801 }
802
803 /*
804   handle a dcerpc request packet
805 */
806 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
807 {
808         struct ndr_pull *pull;
809         NTSTATUS status;
810         struct dcesrv_connection_context *context;
811
812         /* if authenticated, and the mech we use can't do async replies, don't use them... */
813         if (call->conn->auth_state.gensec_security && 
814             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
815                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
816         }
817
818         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
819         if (context == NULL) {
820                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
821         }
822
823         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
824                                   lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
825         NT_STATUS_HAVE_NO_MEMORY(pull);
826
827         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
828
829         call->context   = context;
830         call->ndr_pull  = pull;
831
832         if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
833                 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
834         }
835
836         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
837                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
838         }
839
840         /* unravel the NDR for the packet */
841         status = context->iface->ndr_pull(call, call, pull, &call->r);
842         if (!NT_STATUS_IS_OK(status)) {
843                 return dcesrv_fault(call, call->fault_code);
844         }
845
846         if (pull->offset != pull->data_size) {
847                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
848                          pull->data_size - pull->offset));
849                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
850         }
851
852         /* call the dispatch function */
853         status = context->iface->dispatch(call, call, call->r);
854         if (!NT_STATUS_IS_OK(status)) {
855                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
856                          context->iface->name, 
857                          call->pkt.u.request.opnum,
858                          dcerpc_errstr(pull, call->fault_code)));
859                 return dcesrv_fault(call, call->fault_code);
860         }
861
862         /* add the call to the pending list */
863         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
864
865         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
866                 return NT_STATUS_OK;
867         }
868
869         return dcesrv_reply(call);
870 }
871
872 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
873 {
874         struct ndr_push *push;
875         NTSTATUS status;
876         DATA_BLOB stub;
877         uint32_t total_length;
878         struct dcesrv_connection_context *context = call->context;
879
880         /* call the reply function */
881         status = context->iface->reply(call, call, call->r);
882         if (!NT_STATUS_IS_OK(status)) {
883                 return dcesrv_fault(call, call->fault_code);
884         }
885
886         /* form the reply NDR */
887         push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
888         NT_STATUS_HAVE_NO_MEMORY(push);
889
890         /* carry over the pointer count to the reply in case we are
891            using full pointer. See NDR specification for full
892            pointers */
893         push->ptr_count = call->ndr_pull->ptr_count;
894
895         if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
896                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
897         }
898
899         status = context->iface->ndr_push(call, call, push, call->r);
900         if (!NT_STATUS_IS_OK(status)) {
901                 return dcesrv_fault(call, call->fault_code);
902         }
903
904         stub = ndr_push_blob(push);
905
906         total_length = stub.length;
907
908         do {
909                 uint32_t length;
910                 struct data_blob_list_item *rep;
911                 struct ncacn_packet pkt;
912
913                 rep = talloc(call, struct data_blob_list_item);
914                 NT_STATUS_HAVE_NO_MEMORY(rep);
915
916                 length = stub.length;
917                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
918                         /* the 32 is to cope with signing data */
919                         length = call->conn->cli_max_recv_frag - 
920                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
921                 }
922
923                 /* form the dcerpc response packet */
924                 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
925                 pkt.auth_length = 0;
926                 pkt.call_id = call->pkt.call_id;
927                 pkt.ptype = DCERPC_PKT_RESPONSE;
928                 pkt.pfc_flags = 0;
929                 if (stub.length == total_length) {
930                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
931                 }
932                 if (length == stub.length) {
933                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
934                 }
935                 pkt.u.response.alloc_hint = stub.length;
936                 pkt.u.response.context_id = call->pkt.u.request.context_id;
937                 pkt.u.response.cancel_count = 0;
938                 pkt.u.response.stub_and_verifier.data = stub.data;
939                 pkt.u.response.stub_and_verifier.length = length;
940
941                 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
942                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
943                 }
944
945                 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
946
947                 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
948                 
949                 stub.data += length;
950                 stub.length -= length;
951         } while (stub.length != 0);
952
953         /* move the call from the pending to the finished calls list */
954         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
955
956         if (call->conn->call_list && call->conn->call_list->replies) {
957                 if (call->conn->transport.report_output_data) {
958                         call->conn->transport.report_output_data(call->conn);
959                 }
960         }
961
962         return NT_STATUS_OK;
963 }
964
965 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
966 {
967         if (!conn->transport.get_my_addr) {
968                 return NULL;
969         }
970
971         return conn->transport.get_my_addr(conn, mem_ctx);
972 }
973
974 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
975 {
976         if (!conn->transport.get_peer_addr) {
977                 return NULL;
978         }
979
980         return conn->transport.get_peer_addr(conn, mem_ctx);
981 }
982
983 /*
984   work out if we have a full packet yet
985 */
986 static bool dce_full_packet(const DATA_BLOB *data)
987 {
988         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
989                 return false;
990         }
991         if (dcerpc_get_frag_length(data) > data->length) {
992                 return false;
993         }
994         return true;
995 }
996
997 /*
998   we might have consumed only part of our input - advance past that part
999 */
1000 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1001 {
1002         DATA_BLOB blob;
1003
1004         if (dce_conn->partial_input.length == offset) {
1005                 data_blob_free(&dce_conn->partial_input);
1006                 return;
1007         }
1008
1009         blob = dce_conn->partial_input;
1010         dce_conn->partial_input = data_blob(blob.data + offset,
1011                                             blob.length - offset);
1012         data_blob_free(&blob);
1013 }
1014
1015 /*
1016   remove the call from the right list when freed
1017  */
1018 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1019 {
1020         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1021         return 0;
1022 }
1023
1024 /*
1025   process some input to a dcerpc endpoint server.
1026 */
1027 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1028 {
1029         struct ndr_pull *ndr;
1030         enum ndr_err_code ndr_err;
1031         NTSTATUS status;
1032         struct dcesrv_call_state *call;
1033         DATA_BLOB blob;
1034
1035         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1036         if (!call) {
1037                 talloc_free(dce_conn->partial_input.data);
1038                 return NT_STATUS_NO_MEMORY;
1039         }
1040         call->conn              = dce_conn;
1041         call->event_ctx         = dce_conn->event_ctx;
1042         call->msg_ctx           = dce_conn->msg_ctx;
1043         call->state_flags       = call->conn->state_flags;
1044         call->time              = timeval_current();
1045         call->list              = DCESRV_LIST_NONE;
1046
1047         talloc_set_destructor(call, dcesrv_call_dequeue);
1048
1049         blob = dce_conn->partial_input;
1050         blob.length = dcerpc_get_frag_length(&blob);
1051
1052         ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1053         if (!ndr) {
1054                 talloc_free(dce_conn->partial_input.data);
1055                 talloc_free(call);
1056                 return NT_STATUS_NO_MEMORY;
1057         }
1058
1059         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1060                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1061         }
1062
1063         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1064         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1065                 talloc_free(dce_conn->partial_input.data);
1066                 talloc_free(call);
1067                 return ndr_map_error2ntstatus(ndr_err);
1068         }
1069
1070         /* we have to check the signing here, before combining the
1071            pdus */
1072         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1073             !dcesrv_auth_request(call, &blob)) {
1074                 dce_partial_advance(dce_conn, blob.length);
1075                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1076         }
1077
1078         dce_partial_advance(dce_conn, blob.length);
1079
1080         /* see if this is a continued packet */
1081         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1082             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1083                 struct dcesrv_call_state *call2 = call;
1084                 uint32_t alloc_size;
1085
1086                 /* we only allow fragmented requests, no other packet types */
1087                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1088                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1089                 }
1090
1091                 /* this is a continuation of an existing call - find the call then
1092                    tack it on the end */
1093                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1094                 if (!call) {
1095                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1096                 }
1097
1098                 if (call->pkt.ptype != call2->pkt.ptype) {
1099                         /* trying to play silly buggers are we? */
1100                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1101                 }
1102
1103                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1104                         call2->pkt.u.request.stub_and_verifier.length;
1105                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1106                         alloc_size = call->pkt.u.request.alloc_hint;
1107                 }
1108
1109                 call->pkt.u.request.stub_and_verifier.data = 
1110                         talloc_realloc(call, 
1111                                        call->pkt.u.request.stub_and_verifier.data, 
1112                                        uint8_t, alloc_size);
1113                 if (!call->pkt.u.request.stub_and_verifier.data) {
1114                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1115                 }
1116                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1117                        call->pkt.u.request.stub_and_verifier.length,
1118                        call2->pkt.u.request.stub_and_verifier.data,
1119                        call2->pkt.u.request.stub_and_verifier.length);
1120                 call->pkt.u.request.stub_and_verifier.length += 
1121                         call2->pkt.u.request.stub_and_verifier.length;
1122
1123                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1124
1125                 talloc_free(call2);
1126         }
1127
1128         /* this may not be the last pdu in the chain - if its isn't then
1129            just put it on the incoming_fragmented_call_list and wait for the rest */
1130         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1131             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1132                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1133                 return NT_STATUS_OK;
1134         } 
1135         
1136         /* This removes any fragments we may have had stashed away */
1137         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1138
1139         switch (call->pkt.ptype) {
1140         case DCERPC_PKT_BIND:
1141                 status = dcesrv_bind(call);
1142                 break;
1143         case DCERPC_PKT_AUTH3:
1144                 status = dcesrv_auth3(call);
1145                 break;
1146         case DCERPC_PKT_ALTER:
1147                 status = dcesrv_alter(call);
1148                 break;
1149         case DCERPC_PKT_REQUEST:
1150                 status = dcesrv_request(call);
1151                 break;
1152         default:
1153                 status = NT_STATUS_INVALID_PARAMETER;
1154                 break;
1155         }
1156
1157         /* if we are going to be sending a reply then add
1158            it to the list of pending calls. We add it to the end to keep the call
1159            list in the order we will answer */
1160         if (!NT_STATUS_IS_OK(status)) {
1161                 talloc_free(call);
1162         }
1163
1164         return status;
1165 }
1166
1167
1168 /*
1169   provide some input to a dcerpc endpoint server. This passes data
1170   from a dcerpc client into the server
1171 */
1172 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1173 {
1174         NTSTATUS status;
1175
1176         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1177                                                       dce_conn->partial_input.data,
1178                                                       uint8_t,
1179                                                       dce_conn->partial_input.length + data->length);
1180         if (!dce_conn->partial_input.data) {
1181                 return NT_STATUS_NO_MEMORY;
1182         }
1183         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1184                data->data, data->length);
1185         dce_conn->partial_input.length += data->length;
1186
1187         while (dce_full_packet(&dce_conn->partial_input)) {
1188                 status = dcesrv_input_process(dce_conn);
1189                 if (!NT_STATUS_IS_OK(status)) {
1190                         return status;
1191                 }
1192         }
1193
1194         return NT_STATUS_OK;
1195 }
1196
1197 /*
1198   retrieve some output from a dcerpc server
1199   The caller supplies a function that will be called to do the
1200   actual output. 
1201
1202   The first argument to write_fn() will be 'private', the second will
1203   be a pointer to a buffer containing the data to be sent and the 3rd
1204   will be a pointer to a size_t variable that will be set to the
1205   number of bytes that are consumed from the output.
1206
1207   from the current fragment
1208 */
1209 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1210                        void *private_data,
1211                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1212 {
1213         NTSTATUS status;
1214         struct dcesrv_call_state *call;
1215         struct data_blob_list_item *rep;
1216         size_t nwritten;
1217
1218         call = dce_conn->call_list;
1219         if (!call || !call->replies) {
1220                 if (dce_conn->pending_call_list) {
1221                         /* TODO: we need to say act async here
1222                          *       as we know we have pending requests
1223                          *       which will be finished at a time
1224                          */
1225                         return NT_STATUS_FOOBAR;
1226                 }
1227                 return NT_STATUS_FOOBAR;
1228         }
1229         rep = call->replies;
1230
1231         status = write_fn(private_data, &rep->blob, &nwritten);
1232         NT_STATUS_IS_ERR_RETURN(status);
1233
1234         rep->blob.length -= nwritten;
1235         rep->blob.data += nwritten;
1236
1237         if (rep->blob.length == 0) {
1238                 /* we're done with this section of the call */
1239                 DLIST_REMOVE(call->replies, rep);
1240         }
1241
1242         if (call->replies == NULL) {
1243                 /* we're done with the whole call */
1244                 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1245                 talloc_free(call);
1246         }
1247
1248         return status;
1249 }
1250
1251 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1252                                       struct loadparm_context *lp_ctx,
1253                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1254 {
1255         NTSTATUS status;
1256         struct dcesrv_context *dce_ctx;
1257         int i;
1258
1259         if (!endpoint_servers) {
1260                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1261                 return NT_STATUS_INTERNAL_ERROR;
1262         }
1263
1264         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1265         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1266         dce_ctx->endpoint_list  = NULL;
1267         dce_ctx->lp_ctx = lp_ctx;
1268
1269         for (i=0;endpoint_servers[i];i++) {
1270                 const struct dcesrv_endpoint_server *ep_server;
1271
1272                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1273                 if (!ep_server) {
1274                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1275                         return NT_STATUS_INTERNAL_ERROR;
1276                 }
1277
1278                 status = ep_server->init_server(dce_ctx, ep_server);
1279                 if (!NT_STATUS_IS_OK(status)) {
1280                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1281                                 nt_errstr(status)));
1282                         return status;
1283                 }
1284         }
1285
1286         *_dce_ctx = dce_ctx;
1287         return NT_STATUS_OK;
1288 }
1289
1290 /* the list of currently registered DCERPC endpoint servers.
1291  */
1292 static struct ep_server {
1293         struct dcesrv_endpoint_server *ep_server;
1294 } *ep_servers = NULL;
1295 static int num_ep_servers;
1296
1297 /*
1298   register a DCERPC endpoint server. 
1299
1300   The 'name' can be later used by other backends to find the operations
1301   structure for this backend.  
1302
1303   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1304 */
1305 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1306 {
1307         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1308         
1309         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1310                 /* its already registered! */
1311                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1312                          ep_server->name));
1313                 return NT_STATUS_OBJECT_NAME_COLLISION;
1314         }
1315
1316         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1317         if (!ep_servers) {
1318                 smb_panic("out of memory in dcerpc_register");
1319         }
1320
1321         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1322         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1323
1324         num_ep_servers++;
1325
1326         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1327                  ep_server->name));
1328
1329         return NT_STATUS_OK;
1330 }
1331
1332 /*
1333   return the operations structure for a named backend of the specified type
1334 */
1335 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1336 {
1337         int i;
1338
1339         for (i=0;i<num_ep_servers;i++) {
1340                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1341                         return ep_servers[i].ep_server;
1342                 }
1343         }
1344
1345         return NULL;
1346 }
1347
1348 /*
1349   return the DCERPC module version, and the size of some critical types
1350   This can be used by endpoint server modules to either detect compilation errors, or provide
1351   multiple implementations for different smbd compilation options in one module
1352 */
1353 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1354 {
1355         static const struct dcesrv_critical_sizes critical_sizes = {
1356                 DCERPC_MODULE_VERSION,
1357                 sizeof(struct dcesrv_context),
1358                 sizeof(struct dcesrv_endpoint),
1359                 sizeof(struct dcesrv_endpoint_server),
1360                 sizeof(struct dcesrv_interface),
1361                 sizeof(struct dcesrv_if_list),
1362                 sizeof(struct dcesrv_connection),
1363                 sizeof(struct dcesrv_call_state),
1364                 sizeof(struct dcesrv_auth),
1365                 sizeof(struct dcesrv_handle)
1366         };
1367
1368         return &critical_sizes;
1369 }
1370
1371 /*
1372   initialise the dcerpc server context for ncacn_np based services
1373 */
1374 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1375                                           struct dcesrv_context **_dce_ctx)
1376 {
1377         NTSTATUS status;
1378         struct dcesrv_context *dce_ctx;
1379
1380         status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1381         NT_STATUS_NOT_OK_RETURN(status);
1382
1383         *_dce_ctx = dce_ctx;
1384         return NT_STATUS_OK;
1385 }
1386
1387