s4:rpc_server Add a 'if_version' parameter to the bind operation.
[abartlet/samba.git/.git] / source4 / rpc_server / dcerpc_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc core code
5
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Stefan (metze) Metzmacher 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "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, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &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, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &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, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
736         if (!NT_STATUS_IS_OK(status)) {
737                 talloc_free(call->context);
738                 call->context = NULL;
739                 return status;
740         }
741
742         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
743
744         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
745         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
746
747         if (call->conn->call_list && call->conn->call_list->replies) {
748                 if (call->conn->transport.report_output_data) {
749                         call->conn->transport.report_output_data(call->conn);
750                 }
751         }
752
753         return NT_STATUS_OK;
754 }
755
756
757 /*
758   handle a auth3 request
759 */
760 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
761 {
762         /* handle the auth3 in the auth code */
763         if (!dcesrv_auth_auth3(call)) {
764                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
765         }
766
767         talloc_free(call);
768
769         /* we don't send a reply to a auth3 request, except by a
770            fault */
771         return NT_STATUS_OK;
772 }
773
774
775 /*
776   handle a bind request
777 */
778 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
779 {
780         uint32_t if_version, transfer_syntax_version;
781         struct dcesrv_connection_context *context;
782         const struct dcesrv_interface *iface;
783         struct GUID uuid, *transfer_syntax_uuid;
784         NTSTATUS status;
785
786         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
787         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
788
789         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
790         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
791         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
792             ndr_transfer_syntax.if_version != transfer_syntax_version) {
793                 /* we only do NDR encoded dcerpc */
794                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
795         }
796
797         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
798         if (iface == NULL) {
799                 char *uuid_str = GUID_string(call, &uuid);
800                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
801                 talloc_free(uuid_str);
802                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
803         }
804
805         /* add this context to the list of available context_ids */
806         context = talloc(call->conn, struct dcesrv_connection_context);
807         if (context == NULL) {
808                 return NT_STATUS_NO_MEMORY;
809         }
810         context->conn = call->conn;
811         context->iface = iface;
812         context->context_id = context_id;
813         if (call->pkt.u.alter.assoc_group_id != 0) {
814                 context->assoc_group = dcesrv_assoc_group_reference(context,
815                                                                     call->conn->dce_ctx, 
816                                                                     call->pkt.u.alter.assoc_group_id);
817         } else {
818                 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
819         }
820         if (context->assoc_group == NULL) {
821                 talloc_free(context);
822                 call->context = NULL;
823                 return NT_STATUS_NO_MEMORY;
824         }
825         context->private_data = NULL;
826         DLIST_ADD(call->conn->contexts, context);
827         call->context = context;
828         talloc_set_destructor(context, dcesrv_connection_context_destructor);
829
830         status = iface->bind(call, iface, if_version);
831         if (!NT_STATUS_IS_OK(status)) {
832                 /* we don't want to trigger the iface->unbind() hook */
833                 context->iface = NULL;
834                 talloc_free(context);
835                 call->context = NULL;
836                 return status;
837         }
838
839         return NT_STATUS_OK;
840 }
841
842
843 /*
844   handle a alter context request
845 */
846 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
847 {
848         struct ncacn_packet pkt;
849         struct data_blob_list_item *rep;
850         NTSTATUS status;
851         uint32_t result=0, reason=0;
852         uint32_t context_id;
853
854         /* handle any authentication that is being requested */
855         if (!dcesrv_auth_alter(call)) {
856                 /* TODO: work out the right reject code */
857                 result = DCERPC_BIND_PROVIDER_REJECT;
858                 reason = DCERPC_BIND_REASON_ASYNTAX;            
859         }
860
861         context_id = call->pkt.u.alter.ctx_list[0].context_id;
862
863         /* see if they are asking for a new interface */
864         if (result == 0) {
865                 call->context = dcesrv_find_context(call->conn, context_id);
866                 if (!call->context) {
867                         status = dcesrv_alter_new_context(call, context_id);
868                         if (!NT_STATUS_IS_OK(status)) {
869                                 result = DCERPC_BIND_PROVIDER_REJECT;
870                                 reason = DCERPC_BIND_REASON_ASYNTAX;
871                         }
872                 }
873         }
874
875         if (result == 0 &&
876             call->pkt.u.alter.assoc_group_id != 0 &&
877             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
878             call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
879                 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
880                          call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
881                 /* TODO: can they ask for a new association group? */
882                 result = DCERPC_BIND_PROVIDER_REJECT;
883                 reason = DCERPC_BIND_REASON_ASYNTAX;
884         }
885
886         /* setup a alter_resp */
887         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
888         pkt.auth_length = 0;
889         pkt.call_id = call->pkt.call_id;
890         pkt.ptype = DCERPC_PKT_ALTER_RESP;
891         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
892         pkt.u.alter_resp.max_xmit_frag = 0x2000;
893         pkt.u.alter_resp.max_recv_frag = 0x2000;
894         if (result == 0) {
895                 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
896         } else {
897                 pkt.u.alter_resp.assoc_group_id = 0;
898         }
899         pkt.u.alter_resp.num_results = 1;
900         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
901         if (!pkt.u.alter_resp.ctx_list) {
902                 return NT_STATUS_NO_MEMORY;
903         }
904         pkt.u.alter_resp.ctx_list[0].result = result;
905         pkt.u.alter_resp.ctx_list[0].reason = reason;
906         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
907         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
908         pkt.u.alter_resp.secondary_address = "";
909
910         status = dcesrv_auth_alter_ack(call, &pkt);
911         if (!NT_STATUS_IS_OK(status)) {
912                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
913                     || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
914                     || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
915                     || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
916                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
917                 }
918                 return dcesrv_fault(call, 0);
919         }
920
921         rep = talloc(call, struct data_blob_list_item);
922         if (!rep) {
923                 return NT_STATUS_NO_MEMORY;
924         }
925
926         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
927         if (!NT_STATUS_IS_OK(status)) {
928                 return status;
929         }
930
931         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
932
933         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
934         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
935
936         if (call->conn->call_list && call->conn->call_list->replies) {
937                 if (call->conn->transport.report_output_data) {
938                         call->conn->transport.report_output_data(call->conn);
939                 }
940         }
941
942         return NT_STATUS_OK;
943 }
944
945 /*
946   handle a dcerpc request packet
947 */
948 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
949 {
950         struct ndr_pull *pull;
951         NTSTATUS status;
952         struct dcesrv_connection_context *context;
953
954         /* if authenticated, and the mech we use can't do async replies, don't use them... */
955         if (call->conn->auth_state.gensec_security && 
956             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
957                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
958         }
959
960         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
961         if (context == NULL) {
962                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
963         }
964
965         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
966                                   lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
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, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
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 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1115 {
1116         if (!conn->transport.get_my_addr) {
1117                 return NULL;
1118         }
1119
1120         return conn->transport.get_my_addr(conn, mem_ctx);
1121 }
1122
1123 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1124 {
1125         if (!conn->transport.get_peer_addr) {
1126                 return NULL;
1127         }
1128
1129         return conn->transport.get_peer_addr(conn, mem_ctx);
1130 }
1131
1132
1133 /*
1134   remove the call from the right list when freed
1135  */
1136 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1137 {
1138         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1139         return 0;
1140 }
1141
1142 /*
1143   process some input to a dcerpc endpoint server.
1144 */
1145 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1146                                      struct ncacn_packet *pkt,
1147                                      DATA_BLOB blob)
1148 {
1149         NTSTATUS status;
1150         struct dcesrv_call_state *call;
1151
1152         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1153         if (!call) {
1154                 data_blob_free(&blob);
1155                 talloc_free(pkt);
1156                 return NT_STATUS_NO_MEMORY;
1157         }
1158         call->conn              = dce_conn;
1159         call->event_ctx         = dce_conn->event_ctx;
1160         call->msg_ctx           = dce_conn->msg_ctx;
1161         call->state_flags       = call->conn->state_flags;
1162         call->time              = timeval_current();
1163         call->list              = DCESRV_LIST_NONE;
1164
1165         talloc_steal(call, pkt);
1166         talloc_steal(call, blob.data);
1167         call->pkt = *pkt;
1168
1169         talloc_set_destructor(call, dcesrv_call_dequeue);
1170
1171         /* we have to check the signing here, before combining the
1172            pdus */
1173         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1174             !dcesrv_auth_request(call, &blob)) {
1175                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1176         }
1177
1178         /* see if this is a continued packet */
1179         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1180             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1181                 struct dcesrv_call_state *call2 = call;
1182                 uint32_t alloc_size;
1183
1184                 /* we only allow fragmented requests, no other packet types */
1185                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1186                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1187                 }
1188
1189                 /* this is a continuation of an existing call - find the call then
1190                    tack it on the end */
1191                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1192                 if (!call) {
1193                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1194                 }
1195
1196                 if (call->pkt.ptype != call2->pkt.ptype) {
1197                         /* trying to play silly buggers are we? */
1198                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1199                 }
1200
1201                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1202                         call2->pkt.u.request.stub_and_verifier.length;
1203                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1204                         alloc_size = call->pkt.u.request.alloc_hint;
1205                 }
1206
1207                 call->pkt.u.request.stub_and_verifier.data = 
1208                         talloc_realloc(call, 
1209                                        call->pkt.u.request.stub_and_verifier.data, 
1210                                        uint8_t, alloc_size);
1211                 if (!call->pkt.u.request.stub_and_verifier.data) {
1212                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1213                 }
1214                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1215                        call->pkt.u.request.stub_and_verifier.length,
1216                        call2->pkt.u.request.stub_and_verifier.data,
1217                        call2->pkt.u.request.stub_and_verifier.length);
1218                 call->pkt.u.request.stub_and_verifier.length += 
1219                         call2->pkt.u.request.stub_and_verifier.length;
1220
1221                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1222
1223                 talloc_free(call2);
1224         }
1225
1226         /* this may not be the last pdu in the chain - if its isn't then
1227            just put it on the incoming_fragmented_call_list and wait for the rest */
1228         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1229             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1230                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1231                 return NT_STATUS_OK;
1232         } 
1233         
1234         /* This removes any fragments we may have had stashed away */
1235         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1236
1237         switch (call->pkt.ptype) {
1238         case DCERPC_PKT_BIND:
1239                 status = dcesrv_bind(call);
1240                 break;
1241         case DCERPC_PKT_AUTH3:
1242                 status = dcesrv_auth3(call);
1243                 break;
1244         case DCERPC_PKT_ALTER:
1245                 status = dcesrv_alter(call);
1246                 break;
1247         case DCERPC_PKT_REQUEST:
1248                 status = dcesrv_request(call);
1249                 break;
1250         default:
1251                 status = NT_STATUS_INVALID_PARAMETER;
1252                 break;
1253         }
1254
1255         /* if we are going to be sending a reply then add
1256            it to the list of pending calls. We add it to the end to keep the call
1257            list in the order we will answer */
1258         if (!NT_STATUS_IS_OK(status)) {
1259                 talloc_free(call);
1260         }
1261
1262         return status;
1263 }
1264
1265 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1266                                       struct loadparm_context *lp_ctx,
1267                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1268 {
1269         NTSTATUS status;
1270         struct dcesrv_context *dce_ctx;
1271         int i;
1272
1273         if (!endpoint_servers) {
1274                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1275                 return NT_STATUS_INTERNAL_ERROR;
1276         }
1277
1278         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1279         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1280         dce_ctx->endpoint_list  = NULL;
1281         dce_ctx->lp_ctx = lp_ctx;
1282         dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1283         NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1284
1285         for (i=0;endpoint_servers[i];i++) {
1286                 const struct dcesrv_endpoint_server *ep_server;
1287
1288                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1289                 if (!ep_server) {
1290                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1291                         return NT_STATUS_INTERNAL_ERROR;
1292                 }
1293
1294                 status = ep_server->init_server(dce_ctx, ep_server);
1295                 if (!NT_STATUS_IS_OK(status)) {
1296                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1297                                 nt_errstr(status)));
1298                         return status;
1299                 }
1300         }
1301
1302         *_dce_ctx = dce_ctx;
1303         return NT_STATUS_OK;
1304 }
1305
1306 /* the list of currently registered DCERPC endpoint servers.
1307  */
1308 static struct ep_server {
1309         struct dcesrv_endpoint_server *ep_server;
1310 } *ep_servers = NULL;
1311 static int num_ep_servers;
1312
1313 /*
1314   register a DCERPC endpoint server. 
1315
1316   The 'name' can be later used by other backends to find the operations
1317   structure for this backend.  
1318
1319   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1320 */
1321 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1322 {
1323         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1324         
1325         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1326                 /* its already registered! */
1327                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1328                          ep_server->name));
1329                 return NT_STATUS_OBJECT_NAME_COLLISION;
1330         }
1331
1332         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1333         if (!ep_servers) {
1334                 smb_panic("out of memory in dcerpc_register");
1335         }
1336
1337         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1338         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1339
1340         num_ep_servers++;
1341
1342         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1343                  ep_server->name));
1344
1345         return NT_STATUS_OK;
1346 }
1347
1348 /*
1349   return the operations structure for a named backend of the specified type
1350 */
1351 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1352 {
1353         int i;
1354
1355         for (i=0;i<num_ep_servers;i++) {
1356                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1357                         return ep_servers[i].ep_server;
1358                 }
1359         }
1360
1361         return NULL;
1362 }
1363
1364 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1365 {
1366         static bool initialized;
1367         extern NTSTATUS dcerpc_server_wkssvc_init(void);
1368         extern NTSTATUS dcerpc_server_drsuapi_init(void);
1369         extern NTSTATUS dcerpc_server_winreg_init(void);
1370         extern NTSTATUS dcerpc_server_spoolss_init(void);
1371         extern NTSTATUS dcerpc_server_epmapper_init(void);
1372         extern NTSTATUS dcerpc_server_srvsvc_init(void);
1373         extern NTSTATUS dcerpc_server_netlogon_init(void);
1374         extern NTSTATUS dcerpc_server_rpcecho_init(void);
1375         extern NTSTATUS dcerpc_server_unixinfo_init(void);
1376         extern NTSTATUS dcerpc_server_samr_init(void);
1377         extern NTSTATUS dcerpc_server_remote_init(void);
1378         extern NTSTATUS dcerpc_server_lsa_init(void);
1379         extern NTSTATUS dcerpc_server_browser_init(void);
1380         init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1381         init_module_fn *shared_init;
1382
1383         if (initialized) {
1384                 return;
1385         }
1386         initialized = true;
1387
1388         shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1389
1390         run_init_functions(static_init);
1391         run_init_functions(shared_init);
1392
1393         talloc_free(shared_init);
1394 }
1395
1396 /*
1397   return the DCERPC module version, and the size of some critical types
1398   This can be used by endpoint server modules to either detect compilation errors, or provide
1399   multiple implementations for different smbd compilation options in one module
1400 */
1401 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1402 {
1403         static const struct dcesrv_critical_sizes critical_sizes = {
1404                 DCERPC_MODULE_VERSION,
1405                 sizeof(struct dcesrv_context),
1406                 sizeof(struct dcesrv_endpoint),
1407                 sizeof(struct dcesrv_endpoint_server),
1408                 sizeof(struct dcesrv_interface),
1409                 sizeof(struct dcesrv_if_list),
1410                 sizeof(struct dcesrv_connection),
1411                 sizeof(struct dcesrv_call_state),
1412                 sizeof(struct dcesrv_auth),
1413                 sizeof(struct dcesrv_handle)
1414         };
1415
1416         return &critical_sizes;
1417 }
1418