This patch adds remaining padding bytes to the dcerpc_fault IDL structure and adds...
[kai/samba-autobuild/.git] / source4 / rpc_server / dcerpc_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc core code
5
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Stefan (metze) Metzmacher 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "librpc/gen_ndr/ndr_dcerpc.h"
25 #include "auth/auth.h"
26 #include "auth/gensec/gensec.h"
27 #include "lib/util/dlinklist.h"
28 #include "rpc_server/dcerpc_server.h"
29 #include "rpc_server/dcerpc_server_proto.h"
30 #include "librpc/rpc/dcerpc_proto.h"
31 #include "lib/events/events.h"
32 #include "smbd/service_task.h"
33 #include "smbd/service_stream.h"
34 #include "smbd/service.h"
35 #include "system/filesys.h"
36 #include "libcli/security/security.h"
37 #include "param/param.h"
38
39 extern const struct dcesrv_interface dcesrv_mgmt_interface;
40
41 /*
42   see if two endpoints match
43 */
44 static bool endpoints_match(const struct dcerpc_binding *ep1,
45                             const struct dcerpc_binding *ep2)
46 {
47         if (ep1->transport != ep2->transport) {
48                 return false;
49         }
50
51         if (!ep1->endpoint || !ep2->endpoint) {
52                 return ep1->endpoint == ep2->endpoint;
53         }
54
55         if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0) 
56                 return false;
57
58         return true;
59 }
60
61 /*
62   find an endpoint in the dcesrv_context
63 */
64 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
65                                              const struct dcerpc_binding *ep_description)
66 {
67         struct dcesrv_endpoint *ep;
68         for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
69                 if (endpoints_match(ep->ep_description, ep_description)) {
70                         return ep;
71                 }
72         }
73         return NULL;
74 }
75
76 /*
77   find a registered context_id from a bind or alter_context
78 */
79 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn, 
80                                                                    uint32_t context_id)
81 {
82         struct dcesrv_connection_context *c;
83         for (c=conn->contexts;c;c=c->next) {
84                 if (c->context_id == context_id) return c;
85         }
86         return NULL;
87 }
88
89 /*
90   see if a uuid and if_version match to an interface
91 */
92 static bool interface_match(const struct dcesrv_interface *if1,
93                                                         const struct dcesrv_interface *if2)
94 {
95         return (if1->syntax_id.if_version == if2->syntax_id.if_version && 
96                         GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
97 }
98
99 /*
100   find the interface operations on an endpoint
101 */
102 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
103                                                      const struct dcesrv_interface *iface)
104 {
105         struct dcesrv_if_list *ifl;
106         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
107                 if (interface_match(&(ifl->iface), iface)) {
108                         return &(ifl->iface);
109                 }
110         }
111         return NULL;
112 }
113
114 /*
115   see if a uuid and if_version match to an interface
116 */
117 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
118                                     const struct GUID *uuid, uint32_t if_version)
119 {
120         return (iface->syntax_id.if_version == if_version && 
121                         GUID_equal(&iface->syntax_id.uuid, uuid));
122 }
123
124 /*
125   find the interface operations on an endpoint by uuid
126 */
127 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
128                                                              const struct GUID *uuid, uint32_t if_version)
129 {
130         struct dcesrv_if_list *ifl;
131         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
132                 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
133                         return &(ifl->iface);
134                 }
135         }
136         return NULL;
137 }
138
139 /*
140   find the earlier parts of a fragmented call awaiting reassembily
141 */
142 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
143 {
144         struct dcesrv_call_state *c;
145         for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
146                 if (c->pkt.call_id == call_id) {
147                         return c;
148                 }
149         }
150         return NULL;
151 }
152
153 /*
154   register an interface on an endpoint
155 */
156 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
157                                    const char *ep_name,
158                                    const struct dcesrv_interface *iface,
159                                    const struct security_descriptor *sd)
160 {
161         struct dcesrv_endpoint *ep;
162         struct dcesrv_if_list *ifl;
163         struct dcerpc_binding *binding;
164         bool add_ep = false;
165         NTSTATUS status;
166         
167         status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
168
169         if (NT_STATUS_IS_ERR(status)) {
170                 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
171                 return status;
172         }
173
174         /* check if this endpoint exists
175          */
176         if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
177                 ep = talloc(dce_ctx, struct dcesrv_endpoint);
178                 if (!ep) {
179                         return NT_STATUS_NO_MEMORY;
180                 }
181                 ZERO_STRUCTP(ep);
182                 ep->ep_description = talloc_reference(ep, binding);
183                 add_ep = true;
184
185                 /* add mgmt interface */
186                 ifl = talloc(dce_ctx, struct dcesrv_if_list);
187                 if (!ifl) {
188                         return NT_STATUS_NO_MEMORY;
189                 }
190
191                 memcpy(&(ifl->iface), &dcesrv_mgmt_interface, 
192                            sizeof(struct dcesrv_interface));
193
194                 DLIST_ADD(ep->interface_list, ifl);
195         }
196
197         /* see if the interface is already registered on te endpoint */
198         if (find_interface(ep, iface)!=NULL) {
199                 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
200                         iface->name, ep_name));
201                 return NT_STATUS_OBJECT_NAME_COLLISION;
202         }
203
204         /* talloc a new interface list element */
205         ifl = talloc(dce_ctx, struct dcesrv_if_list);
206         if (!ifl) {
207                 return NT_STATUS_NO_MEMORY;
208         }
209
210         /* copy the given interface struct to the one on the endpoints interface list */
211         memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
212
213         /* if we have a security descriptor given,
214          * we should see if we can set it up on the endpoint
215          */
216         if (sd != NULL) {
217                 /* if there's currently no security descriptor given on the endpoint
218                  * we try to set it
219                  */
220                 if (ep->sd == NULL) {
221                         ep->sd = security_descriptor_copy(dce_ctx, sd);
222                 }
223
224                 /* if now there's no security descriptor given on the endpoint
225                  * something goes wrong, either we failed to copy the security descriptor
226                  * or there was already one on the endpoint
227                  */
228                 if (ep->sd != NULL) {
229                         DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
230                                  "                           on endpoint '%s'\n",
231                                 iface->name, ep_name));
232                         if (add_ep) free(ep);
233                         free(ifl);
234                         return NT_STATUS_OBJECT_NAME_COLLISION;
235                 }
236         }
237
238         /* finally add the interface on the endpoint */
239         DLIST_ADD(ep->interface_list, ifl);
240
241         /* if it's a new endpoint add it to the dcesrv_context */
242         if (add_ep) {
243                 DLIST_ADD(dce_ctx->endpoint_list, ep);
244         }
245
246         DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
247                 iface->name, ep_name));
248
249         return NT_STATUS_OK;
250 }
251
252 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
253                                               DATA_BLOB *session_key)
254 {
255         if (p->auth_state.session_info->session_key.length) {
256                 *session_key = p->auth_state.session_info->session_key;
257                 return NT_STATUS_OK;
258         }
259         return NT_STATUS_NO_USER_SESSION_KEY;
260 }
261
262 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
263                                     DATA_BLOB *session_key)
264 {
265         /* this took quite a few CPU cycles to find ... */
266         session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
267         session_key->length = 16;
268         return NT_STATUS_OK;
269 }
270
271 /*
272   fetch the user session key - may be default (above) or the SMB session key
273 */
274 _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
692         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
693         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
694
695         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
696         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
697         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
698             ndr_transfer_syntax.if_version != transfer_syntax_version) {
699                 /* we only do NDR encoded dcerpc */
700                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
701         }
702
703         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
704         if (iface == NULL) {
705                 char *uuid_str = GUID_string(call, &uuid);
706                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
707                 talloc_free(uuid_str);
708                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
709         }
710
711         /* add this context to the list of available context_ids */
712         context = talloc(call->conn, struct dcesrv_connection_context);
713         if (context == NULL) {
714                 return NT_STATUS_NO_MEMORY;
715         }
716         context->conn = call->conn;
717         context->iface = iface;
718         context->context_id = context_id;
719         context->private = NULL;
720         context->handles = NULL;
721         DLIST_ADD(call->conn->contexts, context);
722         call->context = context;
723
724         return NT_STATUS_OK;
725 }
726
727
728 /*
729   handle a alter context request
730 */
731 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
732 {
733         struct ncacn_packet pkt;
734         struct data_blob_list_item *rep;
735         NTSTATUS status;
736         uint32_t result=0, reason=0;
737         uint32_t context_id;
738
739         /* handle any authentication that is being requested */
740         if (!dcesrv_auth_alter(call)) {
741                 /* TODO: work out the right reject code */
742                 result = DCERPC_BIND_PROVIDER_REJECT;
743                 reason = DCERPC_BIND_REASON_ASYNTAX;            
744         }
745
746         context_id = call->pkt.u.alter.ctx_list[0].context_id;
747
748         /* see if they are asking for a new interface */
749         if (result == 0 &&
750             dcesrv_find_context(call->conn, context_id) == NULL) {
751                 status = dcesrv_alter_new_context(call, context_id);
752                 if (!NT_STATUS_IS_OK(status)) {
753                         result = DCERPC_BIND_PROVIDER_REJECT;
754                         reason = DCERPC_BIND_REASON_ASYNTAX;            
755                 }
756         }
757
758         /* setup a alter_resp */
759         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
760         pkt.auth_length = 0;
761         pkt.call_id = call->pkt.call_id;
762         pkt.ptype = DCERPC_PKT_ALTER_RESP;
763         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
764         pkt.u.alter_resp.max_xmit_frag = 0x2000;
765         pkt.u.alter_resp.max_recv_frag = 0x2000;
766         pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
767         pkt.u.alter_resp.num_results = 1;
768         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
769         if (!pkt.u.alter_resp.ctx_list) {
770                 return NT_STATUS_NO_MEMORY;
771         }
772         pkt.u.alter_resp.ctx_list[0].result = result;
773         pkt.u.alter_resp.ctx_list[0].reason = reason;
774         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
775         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
776         pkt.u.alter_resp.secondary_address = "";
777
778         status = dcesrv_auth_alter_ack(call, &pkt);
779         if (!NT_STATUS_IS_OK(status)) {
780                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
781                     || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
782                     || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
783                     || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
784                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
785                 }
786                 return dcesrv_fault(call, 0);
787         }
788
789         rep = talloc(call, struct data_blob_list_item);
790         if (!rep) {
791                 return NT_STATUS_NO_MEMORY;
792         }
793
794         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
795         if (!NT_STATUS_IS_OK(status)) {
796                 return status;
797         }
798
799         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
800
801         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
802         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
803
804         return NT_STATUS_OK;
805 }
806
807 /*
808   handle a dcerpc request packet
809 */
810 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
811 {
812         struct ndr_pull *pull;
813         NTSTATUS status;
814         struct dcesrv_connection_context *context;
815
816         /* if authenticated, and the mech we use can't do async replies, don't use them... */
817         if (call->conn->auth_state.gensec_security && 
818             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
819                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
820         }
821
822         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
823         if (context == NULL) {
824                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
825         }
826
827         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
828                                   lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
829         NT_STATUS_HAVE_NO_MEMORY(pull);
830
831         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
832
833         call->context   = context;
834         call->ndr_pull  = pull;
835
836         if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
837                 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
838         }
839
840         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
841                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
842         }
843
844         /* unravel the NDR for the packet */
845         status = context->iface->ndr_pull(call, call, pull, &call->r);
846         if (!NT_STATUS_IS_OK(status)) {
847                 return dcesrv_fault(call, call->fault_code);
848         }
849
850         if (pull->offset != pull->data_size) {
851                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
852                          pull->data_size - pull->offset));
853                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
854         }
855
856         /* call the dispatch function */
857         status = context->iface->dispatch(call, call, call->r);
858         if (!NT_STATUS_IS_OK(status)) {
859                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
860                          context->iface->name, 
861                          call->pkt.u.request.opnum,
862                          dcerpc_errstr(pull, call->fault_code)));
863                 return dcesrv_fault(call, call->fault_code);
864         }
865
866         /* add the call to the pending list */
867         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
868
869         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
870                 return NT_STATUS_OK;
871         }
872
873         return dcesrv_reply(call);
874 }
875
876 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
877 {
878         struct ndr_push *push;
879         NTSTATUS status;
880         DATA_BLOB stub;
881         uint32_t total_length;
882         struct dcesrv_connection_context *context = call->context;
883
884         /* call the reply function */
885         status = context->iface->reply(call, call, call->r);
886         if (!NT_STATUS_IS_OK(status)) {
887                 return dcesrv_fault(call, call->fault_code);
888         }
889
890         /* form the reply NDR */
891         push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
892         NT_STATUS_HAVE_NO_MEMORY(push);
893
894         /* carry over the pointer count to the reply in case we are
895            using full pointer. See NDR specification for full
896            pointers */
897         push->ptr_count = call->ndr_pull->ptr_count;
898
899         if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
900                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
901         }
902
903         status = context->iface->ndr_push(call, call, push, call->r);
904         if (!NT_STATUS_IS_OK(status)) {
905                 return dcesrv_fault(call, call->fault_code);
906         }
907
908         stub = ndr_push_blob(push);
909
910         total_length = stub.length;
911
912         do {
913                 uint32_t length;
914                 struct data_blob_list_item *rep;
915                 struct ncacn_packet pkt;
916
917                 rep = talloc(call, struct data_blob_list_item);
918                 NT_STATUS_HAVE_NO_MEMORY(rep);
919
920                 length = stub.length;
921                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
922                         /* the 32 is to cope with signing data */
923                         length = call->conn->cli_max_recv_frag - 
924                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
925                 }
926
927                 /* form the dcerpc response packet */
928                 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
929                 pkt.auth_length = 0;
930                 pkt.call_id = call->pkt.call_id;
931                 pkt.ptype = DCERPC_PKT_RESPONSE;
932                 pkt.pfc_flags = 0;
933                 if (stub.length == total_length) {
934                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
935                 }
936                 if (length == stub.length) {
937                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
938                 }
939                 pkt.u.response.alloc_hint = stub.length;
940                 pkt.u.response.context_id = call->pkt.u.request.context_id;
941                 pkt.u.response.cancel_count = 0;
942                 pkt.u.response.stub_and_verifier.data = stub.data;
943                 pkt.u.response.stub_and_verifier.length = length;
944
945                 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
946                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
947                 }
948
949                 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
950
951                 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
952                 
953                 stub.data += length;
954                 stub.length -= length;
955         } while (stub.length != 0);
956
957         /* move the call from the pending to the finished calls list */
958         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
959
960         if (call->conn->call_list && call->conn->call_list->replies) {
961                 if (call->conn->transport.report_output_data) {
962                         call->conn->transport.report_output_data(call->conn);
963                 }
964         }
965
966         return NT_STATUS_OK;
967 }
968
969 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
970 {
971         if (!conn->transport.get_my_addr) {
972                 return NULL;
973         }
974
975         return conn->transport.get_my_addr(conn, mem_ctx);
976 }
977
978 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
979 {
980         if (!conn->transport.get_peer_addr) {
981                 return NULL;
982         }
983
984         return conn->transport.get_peer_addr(conn, mem_ctx);
985 }
986
987 /*
988   work out if we have a full packet yet
989 */
990 static bool dce_full_packet(const DATA_BLOB *data)
991 {
992         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
993                 return false;
994         }
995         if (dcerpc_get_frag_length(data) > data->length) {
996                 return false;
997         }
998         return true;
999 }
1000
1001 /*
1002   we might have consumed only part of our input - advance past that part
1003 */
1004 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1005 {
1006         DATA_BLOB blob;
1007
1008         if (dce_conn->partial_input.length == offset) {
1009                 data_blob_free(&dce_conn->partial_input);
1010                 return;
1011         }
1012
1013         blob = dce_conn->partial_input;
1014         dce_conn->partial_input = data_blob(blob.data + offset,
1015                                             blob.length - offset);
1016         data_blob_free(&blob);
1017 }
1018
1019 /*
1020   remove the call from the right list when freed
1021  */
1022 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1023 {
1024         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1025         return 0;
1026 }
1027
1028 /*
1029   process some input to a dcerpc endpoint server.
1030 */
1031 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1032 {
1033         struct ndr_pull *ndr;
1034         enum ndr_err_code ndr_err;
1035         NTSTATUS status;
1036         struct dcesrv_call_state *call;
1037         DATA_BLOB blob;
1038
1039         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1040         if (!call) {
1041                 talloc_free(dce_conn->partial_input.data);
1042                 return NT_STATUS_NO_MEMORY;
1043         }
1044         call->conn              = dce_conn;
1045         call->event_ctx         = dce_conn->event_ctx;
1046         call->msg_ctx           = dce_conn->msg_ctx;
1047         call->state_flags       = call->conn->state_flags;
1048         call->time              = timeval_current();
1049         call->list              = DCESRV_LIST_NONE;
1050
1051         talloc_set_destructor(call, dcesrv_call_dequeue);
1052
1053         blob = dce_conn->partial_input;
1054         blob.length = dcerpc_get_frag_length(&blob);
1055
1056         ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1057         if (!ndr) {
1058                 talloc_free(dce_conn->partial_input.data);
1059                 talloc_free(call);
1060                 return NT_STATUS_NO_MEMORY;
1061         }
1062
1063         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1064                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1065         }
1066
1067         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1068         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1069                 talloc_free(dce_conn->partial_input.data);
1070                 talloc_free(call);
1071                 return ndr_map_error2ntstatus(ndr_err);
1072         }
1073
1074         /* we have to check the signing here, before combining the
1075            pdus */
1076         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1077             !dcesrv_auth_request(call, &blob)) {
1078                 dce_partial_advance(dce_conn, blob.length);
1079                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1080         }
1081
1082         dce_partial_advance(dce_conn, blob.length);
1083
1084         /* see if this is a continued packet */
1085         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1086             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1087                 struct dcesrv_call_state *call2 = call;
1088                 uint32_t alloc_size;
1089
1090                 /* we only allow fragmented requests, no other packet types */
1091                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1092                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1093                 }
1094
1095                 /* this is a continuation of an existing call - find the call then
1096                    tack it on the end */
1097                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1098                 if (!call) {
1099                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1100                 }
1101
1102                 if (call->pkt.ptype != call2->pkt.ptype) {
1103                         /* trying to play silly buggers are we? */
1104                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1105                 }
1106
1107                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1108                         call2->pkt.u.request.stub_and_verifier.length;
1109                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1110                         alloc_size = call->pkt.u.request.alloc_hint;
1111                 }
1112
1113                 call->pkt.u.request.stub_and_verifier.data = 
1114                         talloc_realloc(call, 
1115                                        call->pkt.u.request.stub_and_verifier.data, 
1116                                        uint8_t, alloc_size);
1117                 if (!call->pkt.u.request.stub_and_verifier.data) {
1118                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1119                 }
1120                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1121                        call->pkt.u.request.stub_and_verifier.length,
1122                        call2->pkt.u.request.stub_and_verifier.data,
1123                        call2->pkt.u.request.stub_and_verifier.length);
1124                 call->pkt.u.request.stub_and_verifier.length += 
1125                         call2->pkt.u.request.stub_and_verifier.length;
1126
1127                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1128
1129                 talloc_free(call2);
1130         }
1131
1132         /* this may not be the last pdu in the chain - if its isn't then
1133            just put it on the incoming_fragmented_call_list and wait for the rest */
1134         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1135             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1136                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1137                 return NT_STATUS_OK;
1138         } 
1139         
1140         /* This removes any fragments we may have had stashed away */
1141         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1142
1143         switch (call->pkt.ptype) {
1144         case DCERPC_PKT_BIND:
1145                 status = dcesrv_bind(call);
1146                 break;
1147         case DCERPC_PKT_AUTH3:
1148                 status = dcesrv_auth3(call);
1149                 break;
1150         case DCERPC_PKT_ALTER:
1151                 status = dcesrv_alter(call);
1152                 break;
1153         case DCERPC_PKT_REQUEST:
1154                 status = dcesrv_request(call);
1155                 break;
1156         default:
1157                 status = NT_STATUS_INVALID_PARAMETER;
1158                 break;
1159         }
1160
1161         /* if we are going to be sending a reply then add
1162            it to the list of pending calls. We add it to the end to keep the call
1163            list in the order we will answer */
1164         if (!NT_STATUS_IS_OK(status)) {
1165                 talloc_free(call);
1166         }
1167
1168         return status;
1169 }
1170
1171
1172 /*
1173   provide some input to a dcerpc endpoint server. This passes data
1174   from a dcerpc client into the server
1175 */
1176 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1177 {
1178         NTSTATUS status;
1179
1180         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1181                                                       dce_conn->partial_input.data,
1182                                                       uint8_t,
1183                                                       dce_conn->partial_input.length + data->length);
1184         if (!dce_conn->partial_input.data) {
1185                 return NT_STATUS_NO_MEMORY;
1186         }
1187         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1188                data->data, data->length);
1189         dce_conn->partial_input.length += data->length;
1190
1191         while (dce_full_packet(&dce_conn->partial_input)) {
1192                 status = dcesrv_input_process(dce_conn);
1193                 if (!NT_STATUS_IS_OK(status)) {
1194                         return status;
1195                 }
1196         }
1197
1198         return NT_STATUS_OK;
1199 }
1200
1201 /*
1202   retrieve some output from a dcerpc server
1203   The caller supplies a function that will be called to do the
1204   actual output. 
1205
1206   The first argument to write_fn() will be 'private', the second will
1207   be a pointer to a buffer containing the data to be sent and the 3rd
1208   will be a pointer to a size_t variable that will be set to the
1209   number of bytes that are consumed from the output.
1210
1211   from the current fragment
1212 */
1213 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1214                        void *private_data,
1215                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1216 {
1217         NTSTATUS status;
1218         struct dcesrv_call_state *call;
1219         struct data_blob_list_item *rep;
1220         size_t nwritten;
1221
1222         call = dce_conn->call_list;
1223         if (!call || !call->replies) {
1224                 if (dce_conn->pending_call_list) {
1225                         /* TODO: we need to say act async here
1226                          *       as we know we have pending requests
1227                          *       which will be finished at a time
1228                          */
1229                         return NT_STATUS_FOOBAR;
1230                 }
1231                 return NT_STATUS_FOOBAR;
1232         }
1233         rep = call->replies;
1234
1235         status = write_fn(private_data, &rep->blob, &nwritten);
1236         NT_STATUS_IS_ERR_RETURN(status);
1237
1238         rep->blob.length -= nwritten;
1239         rep->blob.data += nwritten;
1240
1241         if (rep->blob.length == 0) {
1242                 /* we're done with this section of the call */
1243                 DLIST_REMOVE(call->replies, rep);
1244         }
1245
1246         if (call->replies == NULL) {
1247                 /* we're done with the whole call */
1248                 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1249                 talloc_free(call);
1250         }
1251
1252         return status;
1253 }
1254
1255 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1256                                       struct loadparm_context *lp_ctx,
1257                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1258 {
1259         NTSTATUS status;
1260         struct dcesrv_context *dce_ctx;
1261         int i;
1262
1263         if (!endpoint_servers) {
1264                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1265                 return NT_STATUS_INTERNAL_ERROR;
1266         }
1267
1268         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1269         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1270         dce_ctx->endpoint_list  = NULL;
1271         dce_ctx->lp_ctx = lp_ctx;
1272
1273         for (i=0;endpoint_servers[i];i++) {
1274                 const struct dcesrv_endpoint_server *ep_server;
1275
1276                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1277                 if (!ep_server) {
1278                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1279                         return NT_STATUS_INTERNAL_ERROR;
1280                 }
1281
1282                 status = ep_server->init_server(dce_ctx, ep_server);
1283                 if (!NT_STATUS_IS_OK(status)) {
1284                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1285                                 nt_errstr(status)));
1286                         return status;
1287                 }
1288         }
1289
1290         *_dce_ctx = dce_ctx;
1291         return NT_STATUS_OK;
1292 }
1293
1294 /* the list of currently registered DCERPC endpoint servers.
1295  */
1296 static struct ep_server {
1297         struct dcesrv_endpoint_server *ep_server;
1298 } *ep_servers = NULL;
1299 static int num_ep_servers;
1300
1301 /*
1302   register a DCERPC endpoint server. 
1303
1304   The 'name' can be later used by other backends to find the operations
1305   structure for this backend.  
1306
1307   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1308 */
1309 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1310 {
1311         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1312         
1313         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1314                 /* its already registered! */
1315                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1316                          ep_server->name));
1317                 return NT_STATUS_OBJECT_NAME_COLLISION;
1318         }
1319
1320         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1321         if (!ep_servers) {
1322                 smb_panic("out of memory in dcerpc_register");
1323         }
1324
1325         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1326         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1327
1328         num_ep_servers++;
1329
1330         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1331                  ep_server->name));
1332
1333         return NT_STATUS_OK;
1334 }
1335
1336 /*
1337   return the operations structure for a named backend of the specified type
1338 */
1339 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1340 {
1341         int i;
1342
1343         for (i=0;i<num_ep_servers;i++) {
1344                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1345                         return ep_servers[i].ep_server;
1346                 }
1347         }
1348
1349         return NULL;
1350 }
1351
1352 /*
1353   return the DCERPC module version, and the size of some critical types
1354   This can be used by endpoint server modules to either detect compilation errors, or provide
1355   multiple implementations for different smbd compilation options in one module
1356 */
1357 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1358 {
1359         static const struct dcesrv_critical_sizes critical_sizes = {
1360                 DCERPC_MODULE_VERSION,
1361                 sizeof(struct dcesrv_context),
1362                 sizeof(struct dcesrv_endpoint),
1363                 sizeof(struct dcesrv_endpoint_server),
1364                 sizeof(struct dcesrv_interface),
1365                 sizeof(struct dcesrv_if_list),
1366                 sizeof(struct dcesrv_connection),
1367                 sizeof(struct dcesrv_call_state),
1368                 sizeof(struct dcesrv_auth),
1369                 sizeof(struct dcesrv_handle)
1370         };
1371
1372         return &critical_sizes;
1373 }
1374
1375 /*
1376   initialise the dcerpc server context for ncacn_np based services
1377 */
1378 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1379                                           struct dcesrv_context **_dce_ctx)
1380 {
1381         NTSTATUS status;
1382         struct dcesrv_context *dce_ctx;
1383
1384         status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1385         NT_STATUS_NOT_OK_RETURN(status);
1386
1387         *_dce_ctx = dce_ctx;
1388         return NT_STATUS_OK;
1389 }
1390
1391