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