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