s4:rpc_server/dcerpc_server.c - fix a "const" warning
[samba.git] / source4 / rpc_server / dcerpc_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc core code
5
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Stefan (metze) Metzmacher 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "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 = lpcfg_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, lpcfg_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, lpcfg_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 && c->iface->unbind) {
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             lpcfg_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             lpcfg_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, lpcfg_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             lpcfg_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, lpcfg_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   possibly save the call for inspection with ndrdump
948  */
949 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
950 {
951 #ifdef DEVELOPER
952         char *fname;
953         const char *dump_dir;
954         dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
955         if (!dump_dir) {
956                 return;
957         }
958         fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
959                                 dump_dir,
960                                 call->context->iface->name,
961                                 call->pkt.u.request.opnum,
962                                 why);
963         if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
964                 DEBUG(0,("RPC SAVED %s\n", fname));
965         }
966         talloc_free(fname);
967 #endif
968 }
969
970 /*
971   handle a dcerpc request packet
972 */
973 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
974 {
975         struct ndr_pull *pull;
976         NTSTATUS status;
977         struct dcesrv_connection_context *context;
978
979         /* if authenticated, and the mech we use can't do async replies, don't use them... */
980         if (call->conn->auth_state.gensec_security && 
981             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
982                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
983         }
984
985         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
986         if (context == NULL) {
987                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
988         }
989
990         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
991         NT_STATUS_HAVE_NO_MEMORY(pull);
992
993         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
994
995         call->context   = context;
996         call->ndr_pull  = pull;
997
998         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
999                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1000         }
1001
1002         /* unravel the NDR for the packet */
1003         status = context->iface->ndr_pull(call, call, pull, &call->r);
1004         if (!NT_STATUS_IS_OK(status)) {
1005                 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
1006                         /* we got an unknown call */
1007                         DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
1008                                  call->pkt.u.request.opnum, context->iface->name));
1009                         dcesrv_save_call(call, "unknown");
1010                 } else {
1011                         dcesrv_save_call(call, "pullfail");
1012                 }
1013                 return dcesrv_fault(call, call->fault_code);
1014         }
1015
1016         if (pull->offset != pull->data_size) {
1017                 dcesrv_save_call(call, "extrabytes");
1018                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
1019                          pull->data_size - pull->offset));
1020         }
1021
1022         /* call the dispatch function */
1023         status = context->iface->dispatch(call, call, call->r);
1024         if (!NT_STATUS_IS_OK(status)) {
1025                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1026                          context->iface->name, 
1027                          call->pkt.u.request.opnum,
1028                          dcerpc_errstr(pull, call->fault_code)));
1029                 return dcesrv_fault(call, call->fault_code);
1030         }
1031
1032         /* add the call to the pending list */
1033         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1034
1035         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1036                 return NT_STATUS_OK;
1037         }
1038
1039         return dcesrv_reply(call);
1040 }
1041
1042 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
1043 {
1044         struct ndr_push *push;
1045         NTSTATUS status;
1046         DATA_BLOB stub;
1047         uint32_t total_length, chunk_size;
1048         struct dcesrv_connection_context *context = call->context;
1049         size_t sig_size = 0;
1050
1051         /* call the reply function */
1052         status = context->iface->reply(call, call, call->r);
1053         if (!NT_STATUS_IS_OK(status)) {
1054                 return dcesrv_fault(call, call->fault_code);
1055         }
1056
1057         /* form the reply NDR */
1058         push = ndr_push_init_ctx(call);
1059         NT_STATUS_HAVE_NO_MEMORY(push);
1060
1061         /* carry over the pointer count to the reply in case we are
1062            using full pointer. See NDR specification for full
1063            pointers */
1064         push->ptr_count = call->ndr_pull->ptr_count;
1065
1066         if (lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
1067                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1068         }
1069
1070         status = context->iface->ndr_push(call, call, push, call->r);
1071         if (!NT_STATUS_IS_OK(status)) {
1072                 return dcesrv_fault(call, call->fault_code);
1073         }
1074
1075         stub = ndr_push_blob(push);
1076
1077         total_length = stub.length;
1078
1079         /* we can write a full max_recv_frag size, minus the dcerpc
1080            request header size */
1081         chunk_size = call->conn->cli_max_recv_frag;
1082         chunk_size -= DCERPC_REQUEST_LENGTH;
1083         if (call->conn->auth_state.auth_info &&
1084             call->conn->auth_state.gensec_security) {
1085                 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
1086                                            call->conn->cli_max_recv_frag);
1087                 if (sig_size) {
1088                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1089                         chunk_size -= sig_size;
1090                 }
1091         }
1092         chunk_size -= (chunk_size % 16);
1093
1094         do {
1095                 uint32_t length;
1096                 struct data_blob_list_item *rep;
1097                 struct ncacn_packet pkt;
1098
1099                 rep = talloc(call, struct data_blob_list_item);
1100                 NT_STATUS_HAVE_NO_MEMORY(rep);
1101
1102                 length = MIN(chunk_size, stub.length);
1103
1104                 /* form the dcerpc response packet */
1105                 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1106                 pkt.auth_length = 0;
1107                 pkt.call_id = call->pkt.call_id;
1108                 pkt.ptype = DCERPC_PKT_RESPONSE;
1109                 pkt.pfc_flags = 0;
1110                 if (stub.length == total_length) {
1111                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1112                 }
1113                 if (length == stub.length) {
1114                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1115                 }
1116                 pkt.u.response.alloc_hint = stub.length;
1117                 pkt.u.response.context_id = call->pkt.u.request.context_id;
1118                 pkt.u.response.cancel_count = 0;
1119                 pkt.u.response.stub_and_verifier.data = stub.data;
1120                 pkt.u.response.stub_and_verifier.length = length;
1121
1122                 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1123                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
1124                 }
1125
1126                 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1127
1128                 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1129                 
1130                 stub.data += length;
1131                 stub.length -= length;
1132         } while (stub.length != 0);
1133
1134         /* move the call from the pending to the finished calls list */
1135         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1136
1137         if (call->conn->call_list && call->conn->call_list->replies) {
1138                 if (call->conn->transport.report_output_data) {
1139                         call->conn->transport.report_output_data(call->conn);
1140                 }
1141         }
1142
1143         return NT_STATUS_OK;
1144 }
1145
1146 /*
1147   remove the call from the right list when freed
1148  */
1149 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1150 {
1151         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1152         return 0;
1153 }
1154
1155 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1156 {
1157         return conn->local_address;
1158 }
1159
1160 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1161 {
1162         return conn->remote_address;
1163 }
1164
1165 /*
1166   process some input to a dcerpc endpoint server.
1167 */
1168 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1169                                      struct ncacn_packet *pkt,
1170                                      DATA_BLOB blob)
1171 {
1172         NTSTATUS status;
1173         struct dcesrv_call_state *call;
1174
1175         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1176         if (!call) {
1177                 data_blob_free(&blob);
1178                 talloc_free(pkt);
1179                 return NT_STATUS_NO_MEMORY;
1180         }
1181         call->conn              = dce_conn;
1182         call->event_ctx         = dce_conn->event_ctx;
1183         call->msg_ctx           = dce_conn->msg_ctx;
1184         call->state_flags       = call->conn->state_flags;
1185         call->time              = timeval_current();
1186         call->list              = DCESRV_LIST_NONE;
1187
1188         talloc_steal(call, pkt);
1189         talloc_steal(call, blob.data);
1190         call->pkt = *pkt;
1191
1192         talloc_set_destructor(call, dcesrv_call_dequeue);
1193
1194         /* we have to check the signing here, before combining the
1195            pdus */
1196         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1197             !dcesrv_auth_request(call, &blob)) {
1198                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1199         }
1200
1201         /* see if this is a continued packet */
1202         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1203             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1204                 struct dcesrv_call_state *call2 = call;
1205                 uint32_t alloc_size;
1206
1207                 /* we only allow fragmented requests, no other packet types */
1208                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1209                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1210                 }
1211
1212                 /* this is a continuation of an existing call - find the call then
1213                    tack it on the end */
1214                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1215                 if (!call) {
1216                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1217                 }
1218
1219                 if (call->pkt.ptype != call2->pkt.ptype) {
1220                         /* trying to play silly buggers are we? */
1221                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1222                 }
1223
1224                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1225                         call2->pkt.u.request.stub_and_verifier.length;
1226                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1227                         alloc_size = call->pkt.u.request.alloc_hint;
1228                 }
1229
1230                 call->pkt.u.request.stub_and_verifier.data = 
1231                         talloc_realloc(call, 
1232                                        call->pkt.u.request.stub_and_verifier.data, 
1233                                        uint8_t, alloc_size);
1234                 if (!call->pkt.u.request.stub_and_verifier.data) {
1235                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1236                 }
1237                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1238                        call->pkt.u.request.stub_and_verifier.length,
1239                        call2->pkt.u.request.stub_and_verifier.data,
1240                        call2->pkt.u.request.stub_and_verifier.length);
1241                 call->pkt.u.request.stub_and_verifier.length += 
1242                         call2->pkt.u.request.stub_and_verifier.length;
1243
1244                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1245
1246                 talloc_free(call2);
1247         }
1248
1249         /* this may not be the last pdu in the chain - if its isn't then
1250            just put it on the incoming_fragmented_call_list and wait for the rest */
1251         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1252             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1253                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1254                 return NT_STATUS_OK;
1255         } 
1256         
1257         /* This removes any fragments we may have had stashed away */
1258         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1259
1260         switch (call->pkt.ptype) {
1261         case DCERPC_PKT_BIND:
1262                 status = dcesrv_bind(call);
1263                 break;
1264         case DCERPC_PKT_AUTH3:
1265                 status = dcesrv_auth3(call);
1266                 break;
1267         case DCERPC_PKT_ALTER:
1268                 status = dcesrv_alter(call);
1269                 break;
1270         case DCERPC_PKT_REQUEST:
1271                 status = dcesrv_request(call);
1272                 break;
1273         default:
1274                 status = NT_STATUS_INVALID_PARAMETER;
1275                 break;
1276         }
1277
1278         /* if we are going to be sending a reply then add
1279            it to the list of pending calls. We add it to the end to keep the call
1280            list in the order we will answer */
1281         if (!NT_STATUS_IS_OK(status)) {
1282                 talloc_free(call);
1283         }
1284
1285         return status;
1286 }
1287
1288 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1289                                       struct loadparm_context *lp_ctx,
1290                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1291 {
1292         NTSTATUS status;
1293         struct dcesrv_context *dce_ctx;
1294         int i;
1295
1296         if (!endpoint_servers) {
1297                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1298                 return NT_STATUS_INTERNAL_ERROR;
1299         }
1300
1301         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1302         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1303         dce_ctx->endpoint_list  = NULL;
1304         dce_ctx->lp_ctx = lp_ctx;
1305         dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1306         NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1307
1308         for (i=0;endpoint_servers[i];i++) {
1309                 const struct dcesrv_endpoint_server *ep_server;
1310
1311                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1312                 if (!ep_server) {
1313                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1314                         return NT_STATUS_INTERNAL_ERROR;
1315                 }
1316
1317                 status = ep_server->init_server(dce_ctx, ep_server);
1318                 if (!NT_STATUS_IS_OK(status)) {
1319                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1320                                 nt_errstr(status)));
1321                         return status;
1322                 }
1323         }
1324
1325         *_dce_ctx = dce_ctx;
1326         return NT_STATUS_OK;
1327 }
1328
1329 /* the list of currently registered DCERPC endpoint servers.
1330  */
1331 static struct ep_server {
1332         struct dcesrv_endpoint_server *ep_server;
1333 } *ep_servers = NULL;
1334 static int num_ep_servers;
1335
1336 /*
1337   register a DCERPC endpoint server. 
1338
1339   The 'name' can be later used by other backends to find the operations
1340   structure for this backend.  
1341
1342   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1343 */
1344 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1345 {
1346         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1347         
1348         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1349                 /* its already registered! */
1350                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1351                          ep_server->name));
1352                 return NT_STATUS_OBJECT_NAME_COLLISION;
1353         }
1354
1355         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1356         if (!ep_servers) {
1357                 smb_panic("out of memory in dcerpc_register");
1358         }
1359
1360         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1361         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1362
1363         num_ep_servers++;
1364
1365         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1366                  ep_server->name));
1367
1368         return NT_STATUS_OK;
1369 }
1370
1371 /*
1372   return the operations structure for a named backend of the specified type
1373 */
1374 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1375 {
1376         int i;
1377
1378         for (i=0;i<num_ep_servers;i++) {
1379                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1380                         return ep_servers[i].ep_server;
1381                 }
1382         }
1383
1384         return NULL;
1385 }
1386
1387 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1388 {
1389         static bool initialized;
1390         extern NTSTATUS dcerpc_server_wkssvc_init(void);
1391         extern NTSTATUS dcerpc_server_drsuapi_init(void);
1392         extern NTSTATUS dcerpc_server_winreg_init(void);
1393         extern NTSTATUS dcerpc_server_spoolss_init(void);
1394         extern NTSTATUS dcerpc_server_epmapper_init(void);
1395         extern NTSTATUS dcerpc_server_srvsvc_init(void);
1396         extern NTSTATUS dcerpc_server_netlogon_init(void);
1397         extern NTSTATUS dcerpc_server_rpcecho_init(void);
1398         extern NTSTATUS dcerpc_server_unixinfo_init(void);
1399         extern NTSTATUS dcerpc_server_samr_init(void);
1400         extern NTSTATUS dcerpc_server_remote_init(void);
1401         extern NTSTATUS dcerpc_server_lsa_init(void);
1402         extern NTSTATUS dcerpc_server_browser_init(void);
1403         extern NTSTATUS dcerpc_server_eventlog6_init(void);
1404         init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1405         init_module_fn *shared_init;
1406
1407         if (initialized) {
1408                 return;
1409         }
1410         initialized = true;
1411
1412         shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1413
1414         run_init_functions(static_init);
1415         run_init_functions(shared_init);
1416
1417         talloc_free(shared_init);
1418 }
1419
1420 /*
1421   return the DCERPC module version, and the size of some critical types
1422   This can be used by endpoint server modules to either detect compilation errors, or provide
1423   multiple implementations for different smbd compilation options in one module
1424 */
1425 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1426 {
1427         static const struct dcesrv_critical_sizes critical_sizes = {
1428                 DCERPC_MODULE_VERSION,
1429                 sizeof(struct dcesrv_context),
1430                 sizeof(struct dcesrv_endpoint),
1431                 sizeof(struct dcesrv_endpoint_server),
1432                 sizeof(struct dcesrv_interface),
1433                 sizeof(struct dcesrv_if_list),
1434                 sizeof(struct dcesrv_connection),
1435                 sizeof(struct dcesrv_call_state),
1436                 sizeof(struct dcesrv_auth),
1437                 sizeof(struct dcesrv_handle)
1438         };
1439
1440         return &critical_sizes;
1441 }
1442