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