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