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