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