s4:rpc_server: split out the parsing of the ncacn_packet from analyzing of the content
[sfrench/samba-autobuild/.git] / source4 / rpc_server / dcerpc_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc core code
5
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Stefan (metze) Metzmacher 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "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 = 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 = 0x2000;
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         NTSTATUS status;
1266
1267         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1268                                                       dce_conn->partial_input.data,
1269                                                       uint8_t,
1270                                                       dce_conn->partial_input.length + data->length);
1271         if (!dce_conn->partial_input.data) {
1272                 return NT_STATUS_NO_MEMORY;
1273         }
1274         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1275                data->data, data->length);
1276         dce_conn->partial_input.length += data->length;
1277
1278         while (dce_full_packet(&dce_conn->partial_input)) {
1279                 NTSTATUS status;
1280                 struct ndr_pull *ndr;
1281                 enum ndr_err_code ndr_err;
1282                 DATA_BLOB blob;
1283                 struct ncacn_packet *pkt;
1284
1285                 blob = dce_conn->partial_input;
1286                 blob.length = dcerpc_get_frag_length(&blob);
1287                 blob = data_blob_talloc(dce_conn, blob.data, blob.length);
1288                 if (!blob.data) {
1289                         data_blob_free(&dce_conn->partial_input);
1290                         return NT_STATUS_NO_MEMORY;
1291                 }
1292
1293                 dce_partial_advance(dce_conn, blob.length);
1294
1295                 pkt = talloc(dce_conn, struct ncacn_packet);
1296                 if (!pkt) {
1297                         data_blob_free(&blob);
1298                         return NT_STATUS_NO_MEMORY;
1299                 }
1300
1301                 ndr = ndr_pull_init_blob(&blob, pkt, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx));
1302                 if (!ndr) {
1303                         data_blob_free(&blob);
1304                         talloc_free(pkt);
1305                         return NT_STATUS_NO_MEMORY;
1306                 }
1307
1308                 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1309                         ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1310                 }
1311
1312                 if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
1313                         ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
1314                 }
1315
1316                 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
1317                 TALLOC_FREE(ndr);
1318                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1319                         data_blob_free(&blob);
1320                         talloc_free(pkt);
1321                         return ndr_map_error2ntstatus(ndr_err);
1322                 }
1323
1324                 status = dcesrv_process_ncacn_packet(dce_conn, pkt, blob);
1325                 if (!NT_STATUS_IS_OK(status)) {
1326                         return status;
1327                 }
1328         }
1329
1330         return NT_STATUS_OK;
1331 }
1332
1333 /*
1334   retrieve some output from a dcerpc server
1335   The caller supplies a function that will be called to do the
1336   actual output. 
1337
1338   The first argument to write_fn() will be 'private', the second will
1339   be a pointer to a buffer containing the data to be sent and the 3rd
1340   will be a pointer to a size_t variable that will be set to the
1341   number of bytes that are consumed from the output.
1342
1343   from the current fragment
1344 */
1345 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1346                        void *private_data,
1347                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1348 {
1349         NTSTATUS status;
1350         struct dcesrv_call_state *call;
1351         struct data_blob_list_item *rep;
1352         size_t nwritten;
1353
1354         call = dce_conn->call_list;
1355         if (!call || !call->replies) {
1356                 if (dce_conn->pending_call_list) {
1357                         /* TODO: we need to say act async here
1358                          *       as we know we have pending requests
1359                          *       which will be finished at a time
1360                          */
1361                         return NT_STATUS_FOOBAR;
1362                 }
1363                 return NT_STATUS_FOOBAR;
1364         }
1365         rep = call->replies;
1366
1367         status = write_fn(private_data, &rep->blob, &nwritten);
1368         NT_STATUS_IS_ERR_RETURN(status);
1369
1370         rep->blob.length -= nwritten;
1371         rep->blob.data += nwritten;
1372
1373         if (rep->blob.length == 0) {
1374                 /* we're done with this section of the call */
1375                 DLIST_REMOVE(call->replies, rep);
1376         }
1377
1378         if (call->replies == NULL) {
1379                 /* we're done with the whole call */
1380                 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1381                 talloc_free(call);
1382         }
1383
1384         return status;
1385 }
1386
1387 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1388                                       struct loadparm_context *lp_ctx,
1389                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1390 {
1391         NTSTATUS status;
1392         struct dcesrv_context *dce_ctx;
1393         int i;
1394
1395         if (!endpoint_servers) {
1396                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1397                 return NT_STATUS_INTERNAL_ERROR;
1398         }
1399
1400         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1401         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1402         dce_ctx->endpoint_list  = NULL;
1403         dce_ctx->lp_ctx = lp_ctx;
1404
1405         for (i=0;endpoint_servers[i];i++) {
1406                 const struct dcesrv_endpoint_server *ep_server;
1407
1408                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1409                 if (!ep_server) {
1410                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1411                         return NT_STATUS_INTERNAL_ERROR;
1412                 }
1413
1414                 status = ep_server->init_server(dce_ctx, ep_server);
1415                 if (!NT_STATUS_IS_OK(status)) {
1416                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1417                                 nt_errstr(status)));
1418                         return status;
1419                 }
1420         }
1421
1422         *_dce_ctx = dce_ctx;
1423         return NT_STATUS_OK;
1424 }
1425
1426 /* the list of currently registered DCERPC endpoint servers.
1427  */
1428 static struct ep_server {
1429         struct dcesrv_endpoint_server *ep_server;
1430 } *ep_servers = NULL;
1431 static int num_ep_servers;
1432
1433 /*
1434   register a DCERPC endpoint server. 
1435
1436   The 'name' can be later used by other backends to find the operations
1437   structure for this backend.  
1438
1439   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1440 */
1441 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1442 {
1443         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1444         
1445         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1446                 /* its already registered! */
1447                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1448                          ep_server->name));
1449                 return NT_STATUS_OBJECT_NAME_COLLISION;
1450         }
1451
1452         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1453         if (!ep_servers) {
1454                 smb_panic("out of memory in dcerpc_register");
1455         }
1456
1457         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1458         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1459
1460         num_ep_servers++;
1461
1462         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1463                  ep_server->name));
1464
1465         return NT_STATUS_OK;
1466 }
1467
1468 /*
1469   return the operations structure for a named backend of the specified type
1470 */
1471 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1472 {
1473         int i;
1474
1475         for (i=0;i<num_ep_servers;i++) {
1476                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1477                         return ep_servers[i].ep_server;
1478                 }
1479         }
1480
1481         return NULL;
1482 }
1483
1484 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1485 {
1486         static bool initialized;
1487         extern NTSTATUS dcerpc_server_wkssvc_init(void);
1488         extern NTSTATUS dcerpc_server_drsuapi_init(void);
1489         extern NTSTATUS dcerpc_server_winreg_init(void);
1490         extern NTSTATUS dcerpc_server_spoolss_init(void);
1491         extern NTSTATUS dcerpc_server_epmapper_init(void);
1492         extern NTSTATUS dcerpc_server_srvsvc_init(void);
1493         extern NTSTATUS dcerpc_server_netlogon_init(void);
1494         extern NTSTATUS dcerpc_server_rpcecho_init(void);
1495         extern NTSTATUS dcerpc_server_unixinfo_init(void);
1496         extern NTSTATUS dcerpc_server_samr_init(void);
1497         extern NTSTATUS dcerpc_server_remote_init(void);
1498         extern NTSTATUS dcerpc_server_lsa_init(void);
1499         extern NTSTATUS dcerpc_server_browser_init(void);
1500         init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1501         init_module_fn *shared_init;
1502
1503         if (initialized) {
1504                 return;
1505         }
1506         initialized = true;
1507
1508         shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1509
1510         run_init_functions(static_init);
1511         run_init_functions(shared_init);
1512
1513         talloc_free(shared_init);
1514 }
1515
1516 /*
1517   return the DCERPC module version, and the size of some critical types
1518   This can be used by endpoint server modules to either detect compilation errors, or provide
1519   multiple implementations for different smbd compilation options in one module
1520 */
1521 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1522 {
1523         static const struct dcesrv_critical_sizes critical_sizes = {
1524                 DCERPC_MODULE_VERSION,
1525                 sizeof(struct dcesrv_context),
1526                 sizeof(struct dcesrv_endpoint),
1527                 sizeof(struct dcesrv_endpoint_server),
1528                 sizeof(struct dcesrv_interface),
1529                 sizeof(struct dcesrv_if_list),
1530                 sizeof(struct dcesrv_connection),
1531                 sizeof(struct dcesrv_call_state),
1532                 sizeof(struct dcesrv_auth),
1533                 sizeof(struct dcesrv_handle)
1534         };
1535
1536         return &critical_sizes;
1537 }
1538
1539 /*
1540   initialise the dcerpc server context for ncacn_np based services
1541 */
1542 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1543                                           struct dcesrv_context **_dce_ctx)
1544 {
1545         NTSTATUS status;
1546         struct dcesrv_context *dce_ctx;
1547
1548         dcerpc_server_init(lp_ctx);
1549
1550         status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1551         NT_STATUS_NOT_OK_RETURN(status);
1552
1553         *_dce_ctx = dce_ctx;
1554         return NT_STATUS_OK;
1555 }
1556
1557