Merge branch 'master' of ssh://git.samba.org/data/git/samba into abartlet-devel
[tprouty/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 event_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 event_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         return NT_STATUS_OK;    
471 }
472
473
474 /*
475   return a dcerpc bind_nak
476 */
477 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
478 {
479         struct ncacn_packet pkt;
480         struct data_blob_list_item *rep;
481         NTSTATUS status;
482
483         /* setup a bind_nak */
484         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
485         pkt.auth_length = 0;
486         pkt.call_id = call->pkt.call_id;
487         pkt.ptype = DCERPC_PKT_BIND_NAK;
488         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
489         pkt.u.bind_nak.reject_reason = reason;
490         if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
491                 pkt.u.bind_nak.versions.v.num_versions = 0;
492         }
493
494         rep = talloc(call, struct data_blob_list_item);
495         if (!rep) {
496                 return NT_STATUS_NO_MEMORY;
497         }
498
499         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
500         if (!NT_STATUS_IS_OK(status)) {
501                 return status;
502         }
503
504         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
505
506         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
507         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
508
509         return NT_STATUS_OK;    
510 }
511
512 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
513 {
514         DLIST_REMOVE(c->conn->contexts, c);
515
516         if (c->iface) {
517                 c->iface->unbind(c, c->iface);
518         }
519
520         return 0;
521 }
522
523 /*
524   handle a bind request
525 */
526 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
527 {
528         uint32_t if_version, transfer_syntax_version;
529         struct GUID uuid, *transfer_syntax_uuid;
530         struct ncacn_packet pkt;
531         struct data_blob_list_item *rep;
532         NTSTATUS status;
533         uint32_t result=0, reason=0;
534         uint32_t context_id;
535         const struct dcesrv_interface *iface;
536         uint32_t extra_flags = 0;
537
538         /*
539          * Association groups allow policy handles to be shared across
540          * multiple client connections.  We don't implement this yet.
541          *
542          * So we just allow 0 if the client wants to create a new
543          * association group.
544          *
545          * And we allow the 0x12345678 value, we give away as
546          * assoc_group_id back to the clients
547          */
548         if (call->pkt.u.bind.assoc_group_id != 0 &&
549             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
550             call->pkt.u.bind.assoc_group_id != SAMBA_ASSOC_GROUP) {
551                 return dcesrv_bind_nak(call, 0);        
552         }
553
554         if (call->pkt.u.bind.num_contexts < 1 ||
555             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
556                 return dcesrv_bind_nak(call, 0);
557         }
558
559         context_id = call->pkt.u.bind.ctx_list[0].context_id;
560
561         /* you can't bind twice on one context */
562         if (dcesrv_find_context(call->conn, context_id) != NULL) {
563                 return dcesrv_bind_nak(call, 0);
564         }
565
566         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
567         uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
568
569         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
570         transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
571         if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
572             ndr_transfer_syntax.if_version != transfer_syntax_version) {
573                 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
574                 /* we only do NDR encoded dcerpc */
575                 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
576                 talloc_free(uuid_str);
577                 return dcesrv_bind_nak(call, 0);
578         }
579
580         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
581         if (iface == NULL) {
582                 char *uuid_str = GUID_string(call, &uuid);
583                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
584                 talloc_free(uuid_str);
585
586                 /* we don't know about that interface */
587                 result = DCERPC_BIND_PROVIDER_REJECT;
588                 reason = DCERPC_BIND_REASON_ASYNTAX;            
589         }
590
591         if (iface) {
592                 /* add this context to the list of available context_ids */
593                 struct dcesrv_connection_context *context = talloc(call->conn, 
594                                                                    struct dcesrv_connection_context);
595                 if (context == NULL) {
596                         return dcesrv_bind_nak(call, 0);
597                 }
598                 context->conn = call->conn;
599                 context->iface = iface;
600                 context->context_id = context_id;
601                 /*
602                  * we need to send a non zero assoc_group_id here to make longhorn happy,
603                  * it also matches samba3
604                  */
605                 context->assoc_group_id = SAMBA_ASSOC_GROUP;
606                 context->private = NULL;
607                 context->handles = NULL;
608                 DLIST_ADD(call->conn->contexts, context);
609                 call->context = context;
610                 talloc_set_destructor(context, dcesrv_connection_context_destructor);
611
612                 status = iface->bind(call, iface);
613                 if (!NT_STATUS_IS_OK(status)) {
614                         char *uuid_str = GUID_string(call, &uuid);
615                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
616                                  uuid_str, if_version, nt_errstr(status)));
617                         talloc_free(uuid_str);
618                         /* we don't want to trigger the iface->unbind() hook */
619                         context->iface = NULL;
620                         talloc_free(call->context);
621                         call->context = NULL;
622                         return dcesrv_bind_nak(call, 0);
623                 }
624         }
625
626         if (call->conn->cli_max_recv_frag == 0) {
627                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
628         }
629
630         if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
631             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
632                 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
633                 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
634         }
635
636         /* handle any authentication that is being requested */
637         if (!dcesrv_auth_bind(call)) {
638                 talloc_free(call->context);
639                 call->context = NULL;
640                 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
641         }
642
643         /* setup a bind_ack */
644         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
645         pkt.auth_length = 0;
646         pkt.call_id = call->pkt.call_id;
647         pkt.ptype = DCERPC_PKT_BIND_ACK;
648         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
649         pkt.u.bind_ack.max_xmit_frag = 0x2000;
650         pkt.u.bind_ack.max_recv_frag = 0x2000;
651
652         /*
653           make it possible for iface->bind() to specify the assoc_group_id
654           This helps the openchange mapiproxy plugin to work correctly.
655           
656           metze
657         */
658         if (call->context) {
659                 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
660         } else {
661                 /* we better pick something - this chosen so as to send a non zero assoc_group_id (matching windows), it also matches samba3 */
662                 pkt.u.bind_ack.assoc_group_id = SAMBA_ASSOC_GROUP;
663         }
664
665         if (iface) {
666                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
667                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
668         } else {
669                 pkt.u.bind_ack.secondary_address = "";
670         }
671         pkt.u.bind_ack.num_results = 1;
672         pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
673         if (!pkt.u.bind_ack.ctx_list) {
674                 talloc_free(call->context);
675                 call->context = NULL;
676                 return NT_STATUS_NO_MEMORY;
677         }
678         pkt.u.bind_ack.ctx_list[0].result = result;
679         pkt.u.bind_ack.ctx_list[0].reason = reason;
680         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
681         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
682
683         status = dcesrv_auth_bind_ack(call, &pkt);
684         if (!NT_STATUS_IS_OK(status)) {
685                 talloc_free(call->context);
686                 call->context = NULL;
687                 return dcesrv_bind_nak(call, 0);
688         }
689
690         rep = talloc(call, struct data_blob_list_item);
691         if (!rep) {
692                 talloc_free(call->context);
693                 call->context = NULL;
694                 return NT_STATUS_NO_MEMORY;
695         }
696
697         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
698         if (!NT_STATUS_IS_OK(status)) {
699                 talloc_free(call->context);
700                 call->context = NULL;
701                 return status;
702         }
703
704         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
705
706         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
707         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
708
709         return NT_STATUS_OK;
710 }
711
712
713 /*
714   handle a auth3 request
715 */
716 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
717 {
718         /* handle the auth3 in the auth code */
719         if (!dcesrv_auth_auth3(call)) {
720                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
721         }
722
723         talloc_free(call);
724
725         /* we don't send a reply to a auth3 request, except by a
726            fault */
727         return NT_STATUS_OK;
728 }
729
730
731 /*
732   handle a bind request
733 */
734 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
735 {
736         uint32_t if_version, transfer_syntax_version;
737         struct dcesrv_connection_context *context;
738         const struct dcesrv_interface *iface;
739         struct GUID uuid, *transfer_syntax_uuid;
740         NTSTATUS status;
741
742         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
743         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
744
745         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
746         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
747         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
748             ndr_transfer_syntax.if_version != transfer_syntax_version) {
749                 /* we only do NDR encoded dcerpc */
750                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
751         }
752
753         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
754         if (iface == NULL) {
755                 char *uuid_str = GUID_string(call, &uuid);
756                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
757                 talloc_free(uuid_str);
758                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
759         }
760
761         /* add this context to the list of available context_ids */
762         context = talloc(call->conn, struct dcesrv_connection_context);
763         if (context == NULL) {
764                 return NT_STATUS_NO_MEMORY;
765         }
766         context->conn = call->conn;
767         context->iface = iface;
768         context->context_id = context_id;
769         context->assoc_group_id = SAMBA_ASSOC_GROUP;
770         context->private = NULL;
771         context->handles = NULL;
772         DLIST_ADD(call->conn->contexts, context);
773         call->context = context;
774         talloc_set_destructor(context, dcesrv_connection_context_destructor);
775
776         status = iface->bind(call, iface);
777         if (!NT_STATUS_IS_OK(status)) {
778                 /* we don't want to trigger the iface->unbind() hook */
779                 context->iface = NULL;
780                 talloc_free(context);
781                 call->context = NULL;
782                 return status;
783         }
784
785         return NT_STATUS_OK;
786 }
787
788
789 /*
790   handle a alter context request
791 */
792 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
793 {
794         struct ncacn_packet pkt;
795         struct data_blob_list_item *rep;
796         NTSTATUS status;
797         uint32_t result=0, reason=0;
798         uint32_t context_id;
799
800         /* handle any authentication that is being requested */
801         if (!dcesrv_auth_alter(call)) {
802                 /* TODO: work out the right reject code */
803                 result = DCERPC_BIND_PROVIDER_REJECT;
804                 reason = DCERPC_BIND_REASON_ASYNTAX;            
805         }
806
807         context_id = call->pkt.u.alter.ctx_list[0].context_id;
808
809         /* see if they are asking for a new interface */
810         if (result == 0) {
811                 call->context = dcesrv_find_context(call->conn, context_id);
812                 if (!call->context) {
813                         status = dcesrv_alter_new_context(call, context_id);
814                         if (!NT_STATUS_IS_OK(status)) {
815                                 result = DCERPC_BIND_PROVIDER_REJECT;
816                                 reason = DCERPC_BIND_REASON_ASYNTAX;
817                         }
818                 }
819         }
820
821         if (result == 0 &&
822             call->pkt.u.alter.assoc_group_id != 0 &&
823             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
824             call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
825                 /* TODO: work out what to return here */
826                 result = DCERPC_BIND_PROVIDER_REJECT;
827                 reason = DCERPC_BIND_REASON_ASYNTAX;
828         }
829
830         /* setup a alter_resp */
831         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
832         pkt.auth_length = 0;
833         pkt.call_id = call->pkt.call_id;
834         pkt.ptype = DCERPC_PKT_ALTER_RESP;
835         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
836         pkt.u.alter_resp.max_xmit_frag = 0x2000;
837         pkt.u.alter_resp.max_recv_frag = 0x2000;
838         if (result == 0) {
839                 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
840         } else {
841                 pkt.u.alter_resp.assoc_group_id = 0;
842         }
843         pkt.u.alter_resp.num_results = 1;
844         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
845         if (!pkt.u.alter_resp.ctx_list) {
846                 return NT_STATUS_NO_MEMORY;
847         }
848         pkt.u.alter_resp.ctx_list[0].result = result;
849         pkt.u.alter_resp.ctx_list[0].reason = reason;
850         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
851         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
852         pkt.u.alter_resp.secondary_address = "";
853
854         status = dcesrv_auth_alter_ack(call, &pkt);
855         if (!NT_STATUS_IS_OK(status)) {
856                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
857                     || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
858                     || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
859                     || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
860                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
861                 }
862                 return dcesrv_fault(call, 0);
863         }
864
865         rep = talloc(call, struct data_blob_list_item);
866         if (!rep) {
867                 return NT_STATUS_NO_MEMORY;
868         }
869
870         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
871         if (!NT_STATUS_IS_OK(status)) {
872                 return status;
873         }
874
875         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
876
877         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
878         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
879
880         return NT_STATUS_OK;
881 }
882
883 /*
884   handle a dcerpc request packet
885 */
886 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
887 {
888         struct ndr_pull *pull;
889         NTSTATUS status;
890         struct dcesrv_connection_context *context;
891
892         /* if authenticated, and the mech we use can't do async replies, don't use them... */
893         if (call->conn->auth_state.gensec_security && 
894             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
895                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
896         }
897
898         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
899         if (context == NULL) {
900                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
901         }
902
903         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
904                                   lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
905         NT_STATUS_HAVE_NO_MEMORY(pull);
906
907         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
908
909         call->context   = context;
910         call->ndr_pull  = pull;
911
912         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
913                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
914         }
915
916         /* unravel the NDR for the packet */
917         status = context->iface->ndr_pull(call, call, pull, &call->r);
918         if (!NT_STATUS_IS_OK(status)) {
919                 return dcesrv_fault(call, call->fault_code);
920         }
921
922         if (pull->offset != pull->data_size) {
923                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
924                          pull->data_size - pull->offset));
925                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
926         }
927
928         /* call the dispatch function */
929         status = context->iface->dispatch(call, call, call->r);
930         if (!NT_STATUS_IS_OK(status)) {
931                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
932                          context->iface->name, 
933                          call->pkt.u.request.opnum,
934                          dcerpc_errstr(pull, call->fault_code)));
935                 return dcesrv_fault(call, call->fault_code);
936         }
937
938         /* add the call to the pending list */
939         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
940
941         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
942                 return NT_STATUS_OK;
943         }
944
945         return dcesrv_reply(call);
946 }
947
948 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
949 {
950         struct ndr_push *push;
951         NTSTATUS status;
952         DATA_BLOB stub;
953         uint32_t total_length, chunk_size;
954         struct dcesrv_connection_context *context = call->context;
955         size_t sig_size = 0;
956
957         /* call the reply function */
958         status = context->iface->reply(call, call, call->r);
959         if (!NT_STATUS_IS_OK(status)) {
960                 return dcesrv_fault(call, call->fault_code);
961         }
962
963         /* form the reply NDR */
964         push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
965         NT_STATUS_HAVE_NO_MEMORY(push);
966
967         /* carry over the pointer count to the reply in case we are
968            using full pointer. See NDR specification for full
969            pointers */
970         push->ptr_count = call->ndr_pull->ptr_count;
971
972         if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
973                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
974         }
975
976         status = context->iface->ndr_push(call, call, push, call->r);
977         if (!NT_STATUS_IS_OK(status)) {
978                 return dcesrv_fault(call, call->fault_code);
979         }
980
981         stub = ndr_push_blob(push);
982
983         total_length = stub.length;
984
985         /* we can write a full max_recv_frag size, minus the dcerpc
986            request header size */
987         chunk_size = call->conn->cli_max_recv_frag;
988         chunk_size -= DCERPC_REQUEST_LENGTH;
989         if (call->conn->auth_state.auth_info &&
990             call->conn->auth_state.gensec_security) {
991                 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
992                                            call->conn->cli_max_recv_frag);
993                 if (sig_size) {
994                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
995                         chunk_size -= sig_size;
996                 }
997         }
998         chunk_size -= (chunk_size % 16);
999
1000         do {
1001                 uint32_t length;
1002                 struct data_blob_list_item *rep;
1003                 struct ncacn_packet pkt;
1004
1005                 rep = talloc(call, struct data_blob_list_item);
1006                 NT_STATUS_HAVE_NO_MEMORY(rep);
1007
1008                 length = MIN(chunk_size, stub.length);
1009
1010                 /* form the dcerpc response packet */
1011                 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1012                 pkt.auth_length = 0;
1013                 pkt.call_id = call->pkt.call_id;
1014                 pkt.ptype = DCERPC_PKT_RESPONSE;
1015                 pkt.pfc_flags = 0;
1016                 if (stub.length == total_length) {
1017                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1018                 }
1019                 if (length == stub.length) {
1020                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1021                 }
1022                 pkt.u.response.alloc_hint = stub.length;
1023                 pkt.u.response.context_id = call->pkt.u.request.context_id;
1024                 pkt.u.response.cancel_count = 0;
1025                 pkt.u.response.stub_and_verifier.data = stub.data;
1026                 pkt.u.response.stub_and_verifier.length = length;
1027
1028                 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1029                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
1030                 }
1031
1032                 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1033
1034                 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1035                 
1036                 stub.data += length;
1037                 stub.length -= length;
1038         } while (stub.length != 0);
1039
1040         /* move the call from the pending to the finished calls list */
1041         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1042
1043         if (call->conn->call_list && call->conn->call_list->replies) {
1044                 if (call->conn->transport.report_output_data) {
1045                         call->conn->transport.report_output_data(call->conn);
1046                 }
1047         }
1048
1049         return NT_STATUS_OK;
1050 }
1051
1052 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1053 {
1054         if (!conn->transport.get_my_addr) {
1055                 return NULL;
1056         }
1057
1058         return conn->transport.get_my_addr(conn, mem_ctx);
1059 }
1060
1061 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1062 {
1063         if (!conn->transport.get_peer_addr) {
1064                 return NULL;
1065         }
1066
1067         return conn->transport.get_peer_addr(conn, mem_ctx);
1068 }
1069
1070 /*
1071   work out if we have a full packet yet
1072 */
1073 static bool dce_full_packet(const DATA_BLOB *data)
1074 {
1075         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1076                 return false;
1077         }
1078         if (dcerpc_get_frag_length(data) > data->length) {
1079                 return false;
1080         }
1081         return true;
1082 }
1083
1084 /*
1085   we might have consumed only part of our input - advance past that part
1086 */
1087 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1088 {
1089         DATA_BLOB blob;
1090
1091         if (dce_conn->partial_input.length == offset) {
1092                 data_blob_free(&dce_conn->partial_input);
1093                 return;
1094         }
1095
1096         blob = dce_conn->partial_input;
1097         dce_conn->partial_input = data_blob(blob.data + offset,
1098                                             blob.length - offset);
1099         data_blob_free(&blob);
1100 }
1101
1102 /*
1103   remove the call from the right list when freed
1104  */
1105 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1106 {
1107         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1108         return 0;
1109 }
1110
1111 /*
1112   process some input to a dcerpc endpoint server.
1113 */
1114 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1115 {
1116         struct ndr_pull *ndr;
1117         enum ndr_err_code ndr_err;
1118         NTSTATUS status;
1119         struct dcesrv_call_state *call;
1120         DATA_BLOB blob;
1121
1122         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1123         if (!call) {
1124                 talloc_free(dce_conn->partial_input.data);
1125                 return NT_STATUS_NO_MEMORY;
1126         }
1127         call->conn              = dce_conn;
1128         call->event_ctx         = dce_conn->event_ctx;
1129         call->msg_ctx           = dce_conn->msg_ctx;
1130         call->state_flags       = call->conn->state_flags;
1131         call->time              = timeval_current();
1132         call->list              = DCESRV_LIST_NONE;
1133
1134         talloc_set_destructor(call, dcesrv_call_dequeue);
1135
1136         blob = dce_conn->partial_input;
1137         blob.length = dcerpc_get_frag_length(&blob);
1138
1139         ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1140         if (!ndr) {
1141                 talloc_free(dce_conn->partial_input.data);
1142                 talloc_free(call);
1143                 return NT_STATUS_NO_MEMORY;
1144         }
1145
1146         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1147                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1148         }
1149
1150         if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
1151                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
1152         }
1153
1154         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1155         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1156                 talloc_free(dce_conn->partial_input.data);
1157                 talloc_free(call);
1158                 return ndr_map_error2ntstatus(ndr_err);
1159         }
1160
1161         /* we have to check the signing here, before combining the
1162            pdus */
1163         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1164             !dcesrv_auth_request(call, &blob)) {
1165                 dce_partial_advance(dce_conn, blob.length);
1166                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1167         }
1168
1169         dce_partial_advance(dce_conn, blob.length);
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                 status = dcesrv_input_process(dce_conn);
1280                 if (!NT_STATUS_IS_OK(status)) {
1281                         return status;
1282                 }
1283         }
1284
1285         return NT_STATUS_OK;
1286 }
1287
1288 /*
1289   retrieve some output from a dcerpc server
1290   The caller supplies a function that will be called to do the
1291   actual output. 
1292
1293   The first argument to write_fn() will be 'private', the second will
1294   be a pointer to a buffer containing the data to be sent and the 3rd
1295   will be a pointer to a size_t variable that will be set to the
1296   number of bytes that are consumed from the output.
1297
1298   from the current fragment
1299 */
1300 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1301                        void *private_data,
1302                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1303 {
1304         NTSTATUS status;
1305         struct dcesrv_call_state *call;
1306         struct data_blob_list_item *rep;
1307         size_t nwritten;
1308
1309         call = dce_conn->call_list;
1310         if (!call || !call->replies) {
1311                 if (dce_conn->pending_call_list) {
1312                         /* TODO: we need to say act async here
1313                          *       as we know we have pending requests
1314                          *       which will be finished at a time
1315                          */
1316                         return NT_STATUS_FOOBAR;
1317                 }
1318                 return NT_STATUS_FOOBAR;
1319         }
1320         rep = call->replies;
1321
1322         status = write_fn(private_data, &rep->blob, &nwritten);
1323         NT_STATUS_IS_ERR_RETURN(status);
1324
1325         rep->blob.length -= nwritten;
1326         rep->blob.data += nwritten;
1327
1328         if (rep->blob.length == 0) {
1329                 /* we're done with this section of the call */
1330                 DLIST_REMOVE(call->replies, rep);
1331         }
1332
1333         if (call->replies == NULL) {
1334                 /* we're done with the whole call */
1335                 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1336                 talloc_free(call);
1337         }
1338
1339         return status;
1340 }
1341
1342 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1343                                       struct loadparm_context *lp_ctx,
1344                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1345 {
1346         NTSTATUS status;
1347         struct dcesrv_context *dce_ctx;
1348         int i;
1349
1350         if (!endpoint_servers) {
1351                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1352                 return NT_STATUS_INTERNAL_ERROR;
1353         }
1354
1355         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1356         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1357         dce_ctx->endpoint_list  = NULL;
1358         dce_ctx->lp_ctx = lp_ctx;
1359
1360         for (i=0;endpoint_servers[i];i++) {
1361                 const struct dcesrv_endpoint_server *ep_server;
1362
1363                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1364                 if (!ep_server) {
1365                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1366                         return NT_STATUS_INTERNAL_ERROR;
1367                 }
1368
1369                 status = ep_server->init_server(dce_ctx, ep_server);
1370                 if (!NT_STATUS_IS_OK(status)) {
1371                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1372                                 nt_errstr(status)));
1373                         return status;
1374                 }
1375         }
1376
1377         *_dce_ctx = dce_ctx;
1378         return NT_STATUS_OK;
1379 }
1380
1381 /* the list of currently registered DCERPC endpoint servers.
1382  */
1383 static struct ep_server {
1384         struct dcesrv_endpoint_server *ep_server;
1385 } *ep_servers = NULL;
1386 static int num_ep_servers;
1387
1388 /*
1389   register a DCERPC endpoint server. 
1390
1391   The 'name' can be later used by other backends to find the operations
1392   structure for this backend.  
1393
1394   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1395 */
1396 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1397 {
1398         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1399         
1400         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1401                 /* its already registered! */
1402                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1403                          ep_server->name));
1404                 return NT_STATUS_OBJECT_NAME_COLLISION;
1405         }
1406
1407         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1408         if (!ep_servers) {
1409                 smb_panic("out of memory in dcerpc_register");
1410         }
1411
1412         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1413         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1414
1415         num_ep_servers++;
1416
1417         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1418                  ep_server->name));
1419
1420         return NT_STATUS_OK;
1421 }
1422
1423 /*
1424   return the operations structure for a named backend of the specified type
1425 */
1426 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1427 {
1428         int i;
1429
1430         for (i=0;i<num_ep_servers;i++) {
1431                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1432                         return ep_servers[i].ep_server;
1433                 }
1434         }
1435
1436         return NULL;
1437 }
1438
1439 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1440 {
1441         static bool initialized;
1442         extern NTSTATUS dcerpc_server_wkssvc_init(void);
1443         extern NTSTATUS dcerpc_server_drsuapi_init(void);
1444         extern NTSTATUS dcerpc_server_winreg_init(void);
1445         extern NTSTATUS dcerpc_server_spoolss_init(void);
1446         extern NTSTATUS dcerpc_server_epmapper_init(void);
1447         extern NTSTATUS dcerpc_server_srvsvc_init(void);
1448         extern NTSTATUS dcerpc_server_netlogon_init(void);
1449         extern NTSTATUS dcerpc_server_rpcecho_init(void);
1450         extern NTSTATUS dcerpc_server_unixinfo_init(void);
1451         extern NTSTATUS dcerpc_server_samr_init(void);
1452         extern NTSTATUS dcerpc_server_remote_init(void);
1453         extern NTSTATUS dcerpc_server_lsa_init(void);
1454         extern NTSTATUS dcerpc_server_browser_init(void);
1455         init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1456         init_module_fn *shared_init;
1457
1458         if (initialized) {
1459                 return;
1460         }
1461         initialized = true;
1462
1463         shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1464
1465         run_init_functions(static_init);
1466         run_init_functions(shared_init);
1467
1468         talloc_free(shared_init);
1469 }
1470
1471 /*
1472   return the DCERPC module version, and the size of some critical types
1473   This can be used by endpoint server modules to either detect compilation errors, or provide
1474   multiple implementations for different smbd compilation options in one module
1475 */
1476 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1477 {
1478         static const struct dcesrv_critical_sizes critical_sizes = {
1479                 DCERPC_MODULE_VERSION,
1480                 sizeof(struct dcesrv_context),
1481                 sizeof(struct dcesrv_endpoint),
1482                 sizeof(struct dcesrv_endpoint_server),
1483                 sizeof(struct dcesrv_interface),
1484                 sizeof(struct dcesrv_if_list),
1485                 sizeof(struct dcesrv_connection),
1486                 sizeof(struct dcesrv_call_state),
1487                 sizeof(struct dcesrv_auth),
1488                 sizeof(struct dcesrv_handle)
1489         };
1490
1491         return &critical_sizes;
1492 }
1493
1494 /*
1495   initialise the dcerpc server context for ncacn_np based services
1496 */
1497 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1498                                           struct dcesrv_context **_dce_ctx)
1499 {
1500         NTSTATUS status;
1501         struct dcesrv_context *dce_ctx;
1502
1503         dcerpc_server_init(lp_ctx);
1504
1505         status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1506         NT_STATUS_NOT_OK_RETURN(status);
1507
1508         *_dce_ctx = dce_ctx;
1509         return NT_STATUS_OK;
1510 }
1511
1512