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