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