repack the ldb after re-indexing
[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         pkt.u.bind_ack.assoc_group_id = iface?call->context->assoc_group_id:0;
652         if (iface) {
653                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
654                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
655         } else {
656                 pkt.u.bind_ack.secondary_address = "";
657         }
658         pkt.u.bind_ack.num_results = 1;
659         pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
660         if (!pkt.u.bind_ack.ctx_list) {
661                 talloc_free(call->context);
662                 call->context = NULL;
663                 return NT_STATUS_NO_MEMORY;
664         }
665         pkt.u.bind_ack.ctx_list[0].result = result;
666         pkt.u.bind_ack.ctx_list[0].reason = reason;
667         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
668         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
669
670         status = dcesrv_auth_bind_ack(call, &pkt);
671         if (!NT_STATUS_IS_OK(status)) {
672                 talloc_free(call->context);
673                 call->context = NULL;
674                 return dcesrv_bind_nak(call, 0);
675         }
676
677         rep = talloc(call, struct data_blob_list_item);
678         if (!rep) {
679                 talloc_free(call->context);
680                 call->context = NULL;
681                 return NT_STATUS_NO_MEMORY;
682         }
683
684         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
685         if (!NT_STATUS_IS_OK(status)) {
686                 talloc_free(call->context);
687                 call->context = NULL;
688                 return status;
689         }
690
691         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
692
693         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
694         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
695
696         return NT_STATUS_OK;
697 }
698
699
700 /*
701   handle a auth3 request
702 */
703 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
704 {
705         /* handle the auth3 in the auth code */
706         if (!dcesrv_auth_auth3(call)) {
707                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
708         }
709
710         talloc_free(call);
711
712         /* we don't send a reply to a auth3 request, except by a
713            fault */
714         return NT_STATUS_OK;
715 }
716
717
718 /*
719   handle a bind request
720 */
721 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
722 {
723         uint32_t if_version, transfer_syntax_version;
724         struct dcesrv_connection_context *context;
725         const struct dcesrv_interface *iface;
726         struct GUID uuid, *transfer_syntax_uuid;
727         NTSTATUS status;
728
729         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
730         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
731
732         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
733         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
734         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
735             ndr_transfer_syntax.if_version != transfer_syntax_version) {
736                 /* we only do NDR encoded dcerpc */
737                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
738         }
739
740         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
741         if (iface == NULL) {
742                 char *uuid_str = GUID_string(call, &uuid);
743                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
744                 talloc_free(uuid_str);
745                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
746         }
747
748         /* add this context to the list of available context_ids */
749         context = talloc(call->conn, struct dcesrv_connection_context);
750         if (context == NULL) {
751                 return NT_STATUS_NO_MEMORY;
752         }
753         context->conn = call->conn;
754         context->iface = iface;
755         context->context_id = context_id;
756         context->assoc_group_id = SAMBA_ASSOC_GROUP;
757         context->private = NULL;
758         context->handles = NULL;
759         DLIST_ADD(call->conn->contexts, context);
760         call->context = context;
761         talloc_set_destructor(context, dcesrv_connection_context_destructor);
762
763         status = iface->bind(call, iface);
764         if (!NT_STATUS_IS_OK(status)) {
765                 /* we don't want to trigger the iface->unbind() hook */
766                 context->iface = NULL;
767                 talloc_free(context);
768                 call->context = NULL;
769                 return status;
770         }
771
772         return NT_STATUS_OK;
773 }
774
775
776 /*
777   handle a alter context request
778 */
779 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
780 {
781         struct ncacn_packet pkt;
782         struct data_blob_list_item *rep;
783         NTSTATUS status;
784         uint32_t result=0, reason=0;
785         uint32_t context_id;
786
787         /* handle any authentication that is being requested */
788         if (!dcesrv_auth_alter(call)) {
789                 /* TODO: work out the right reject code */
790                 result = DCERPC_BIND_PROVIDER_REJECT;
791                 reason = DCERPC_BIND_REASON_ASYNTAX;            
792         }
793
794         context_id = call->pkt.u.alter.ctx_list[0].context_id;
795
796         /* see if they are asking for a new interface */
797         if (result == 0) {
798                 call->context = dcesrv_find_context(call->conn, context_id);
799                 if (!call->context) {
800                         status = dcesrv_alter_new_context(call, context_id);
801                         if (!NT_STATUS_IS_OK(status)) {
802                                 result = DCERPC_BIND_PROVIDER_REJECT;
803                                 reason = DCERPC_BIND_REASON_ASYNTAX;
804                         }
805                 }
806         }
807
808         if (result == 0 &&
809             call->pkt.u.alter.assoc_group_id != 0 &&
810             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
811             call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
812                 /* TODO: work out what to return here */
813                 result = DCERPC_BIND_PROVIDER_REJECT;
814                 reason = DCERPC_BIND_REASON_ASYNTAX;
815         }
816
817         /* setup a alter_resp */
818         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
819         pkt.auth_length = 0;
820         pkt.call_id = call->pkt.call_id;
821         pkt.ptype = DCERPC_PKT_ALTER_RESP;
822         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
823         pkt.u.alter_resp.max_xmit_frag = 0x2000;
824         pkt.u.alter_resp.max_recv_frag = 0x2000;
825         if (result == 0) {
826                 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
827         } else {
828                 pkt.u.alter_resp.assoc_group_id = 0;
829         }
830         pkt.u.alter_resp.num_results = 1;
831         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
832         if (!pkt.u.alter_resp.ctx_list) {
833                 return NT_STATUS_NO_MEMORY;
834         }
835         pkt.u.alter_resp.ctx_list[0].result = result;
836         pkt.u.alter_resp.ctx_list[0].reason = reason;
837         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
838         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
839         pkt.u.alter_resp.secondary_address = "";
840
841         status = dcesrv_auth_alter_ack(call, &pkt);
842         if (!NT_STATUS_IS_OK(status)) {
843                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
844                     || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
845                     || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
846                     || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
847                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
848                 }
849                 return dcesrv_fault(call, 0);
850         }
851
852         rep = talloc(call, struct data_blob_list_item);
853         if (!rep) {
854                 return NT_STATUS_NO_MEMORY;
855         }
856
857         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
858         if (!NT_STATUS_IS_OK(status)) {
859                 return status;
860         }
861
862         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
863
864         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
865         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
866
867         return NT_STATUS_OK;
868 }
869
870 /*
871   handle a dcerpc request packet
872 */
873 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
874 {
875         struct ndr_pull *pull;
876         NTSTATUS status;
877         struct dcesrv_connection_context *context;
878
879         /* if authenticated, and the mech we use can't do async replies, don't use them... */
880         if (call->conn->auth_state.gensec_security && 
881             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
882                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
883         }
884
885         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
886         if (context == NULL) {
887                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
888         }
889
890         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
891                                   lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
892         NT_STATUS_HAVE_NO_MEMORY(pull);
893
894         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
895
896         call->context   = context;
897         call->ndr_pull  = pull;
898
899         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
900                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
901         }
902
903         /* unravel the NDR for the packet */
904         status = context->iface->ndr_pull(call, call, pull, &call->r);
905         if (!NT_STATUS_IS_OK(status)) {
906                 return dcesrv_fault(call, call->fault_code);
907         }
908
909         if (pull->offset != pull->data_size) {
910                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
911                          pull->data_size - pull->offset));
912                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
913         }
914
915         /* call the dispatch function */
916         status = context->iface->dispatch(call, call, call->r);
917         if (!NT_STATUS_IS_OK(status)) {
918                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
919                          context->iface->name, 
920                          call->pkt.u.request.opnum,
921                          dcerpc_errstr(pull, call->fault_code)));
922                 return dcesrv_fault(call, call->fault_code);
923         }
924
925         /* add the call to the pending list */
926         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
927
928         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
929                 return NT_STATUS_OK;
930         }
931
932         return dcesrv_reply(call);
933 }
934
935 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
936 {
937         struct ndr_push *push;
938         NTSTATUS status;
939         DATA_BLOB stub;
940         uint32_t total_length, chunk_size;
941         struct dcesrv_connection_context *context = call->context;
942         size_t sig_size = 0;
943
944         /* call the reply function */
945         status = context->iface->reply(call, call, call->r);
946         if (!NT_STATUS_IS_OK(status)) {
947                 return dcesrv_fault(call, call->fault_code);
948         }
949
950         /* form the reply NDR */
951         push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
952         NT_STATUS_HAVE_NO_MEMORY(push);
953
954         /* carry over the pointer count to the reply in case we are
955            using full pointer. See NDR specification for full
956            pointers */
957         push->ptr_count = call->ndr_pull->ptr_count;
958
959         if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
960                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
961         }
962
963         status = context->iface->ndr_push(call, call, push, call->r);
964         if (!NT_STATUS_IS_OK(status)) {
965                 return dcesrv_fault(call, call->fault_code);
966         }
967
968         stub = ndr_push_blob(push);
969
970         total_length = stub.length;
971
972         /* we can write a full max_recv_frag size, minus the dcerpc
973            request header size */
974         chunk_size = call->conn->cli_max_recv_frag;
975         chunk_size -= DCERPC_REQUEST_LENGTH;
976         if (call->conn->auth_state.auth_info &&
977             call->conn->auth_state.gensec_security) {
978                 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
979                                            call->conn->cli_max_recv_frag);
980                 if (sig_size) {
981                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
982                         chunk_size -= sig_size;
983                 }
984         }
985         chunk_size -= (chunk_size % 16);
986
987         do {
988                 uint32_t length;
989                 struct data_blob_list_item *rep;
990                 struct ncacn_packet pkt;
991
992                 rep = talloc(call, struct data_blob_list_item);
993                 NT_STATUS_HAVE_NO_MEMORY(rep);
994
995                 length = MIN(chunk_size, stub.length);
996
997                 /* form the dcerpc response packet */
998                 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
999                 pkt.auth_length = 0;
1000                 pkt.call_id = call->pkt.call_id;
1001                 pkt.ptype = DCERPC_PKT_RESPONSE;
1002                 pkt.pfc_flags = 0;
1003                 if (stub.length == total_length) {
1004                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1005                 }
1006                 if (length == stub.length) {
1007                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1008                 }
1009                 pkt.u.response.alloc_hint = stub.length;
1010                 pkt.u.response.context_id = call->pkt.u.request.context_id;
1011                 pkt.u.response.cancel_count = 0;
1012                 pkt.u.response.stub_and_verifier.data = stub.data;
1013                 pkt.u.response.stub_and_verifier.length = length;
1014
1015                 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1016                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
1017                 }
1018
1019                 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1020
1021                 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1022                 
1023                 stub.data += length;
1024                 stub.length -= length;
1025         } while (stub.length != 0);
1026
1027         /* move the call from the pending to the finished calls list */
1028         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1029
1030         if (call->conn->call_list && call->conn->call_list->replies) {
1031                 if (call->conn->transport.report_output_data) {
1032                         call->conn->transport.report_output_data(call->conn);
1033                 }
1034         }
1035
1036         return NT_STATUS_OK;
1037 }
1038
1039 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1040 {
1041         if (!conn->transport.get_my_addr) {
1042                 return NULL;
1043         }
1044
1045         return conn->transport.get_my_addr(conn, mem_ctx);
1046 }
1047
1048 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1049 {
1050         if (!conn->transport.get_peer_addr) {
1051                 return NULL;
1052         }
1053
1054         return conn->transport.get_peer_addr(conn, mem_ctx);
1055 }
1056
1057 /*
1058   work out if we have a full packet yet
1059 */
1060 static bool dce_full_packet(const DATA_BLOB *data)
1061 {
1062         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1063                 return false;
1064         }
1065         if (dcerpc_get_frag_length(data) > data->length) {
1066                 return false;
1067         }
1068         return true;
1069 }
1070
1071 /*
1072   we might have consumed only part of our input - advance past that part
1073 */
1074 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1075 {
1076         DATA_BLOB blob;
1077
1078         if (dce_conn->partial_input.length == offset) {
1079                 data_blob_free(&dce_conn->partial_input);
1080                 return;
1081         }
1082
1083         blob = dce_conn->partial_input;
1084         dce_conn->partial_input = data_blob(blob.data + offset,
1085                                             blob.length - offset);
1086         data_blob_free(&blob);
1087 }
1088
1089 /*
1090   remove the call from the right list when freed
1091  */
1092 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1093 {
1094         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1095         return 0;
1096 }
1097
1098 /*
1099   process some input to a dcerpc endpoint server.
1100 */
1101 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1102 {
1103         struct ndr_pull *ndr;
1104         enum ndr_err_code ndr_err;
1105         NTSTATUS status;
1106         struct dcesrv_call_state *call;
1107         DATA_BLOB blob;
1108
1109         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1110         if (!call) {
1111                 talloc_free(dce_conn->partial_input.data);
1112                 return NT_STATUS_NO_MEMORY;
1113         }
1114         call->conn              = dce_conn;
1115         call->event_ctx         = dce_conn->event_ctx;
1116         call->msg_ctx           = dce_conn->msg_ctx;
1117         call->state_flags       = call->conn->state_flags;
1118         call->time              = timeval_current();
1119         call->list              = DCESRV_LIST_NONE;
1120
1121         talloc_set_destructor(call, dcesrv_call_dequeue);
1122
1123         blob = dce_conn->partial_input;
1124         blob.length = dcerpc_get_frag_length(&blob);
1125
1126         ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1127         if (!ndr) {
1128                 talloc_free(dce_conn->partial_input.data);
1129                 talloc_free(call);
1130                 return NT_STATUS_NO_MEMORY;
1131         }
1132
1133         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1134                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1135         }
1136
1137         if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
1138                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
1139         }
1140
1141         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1142         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1143                 talloc_free(dce_conn->partial_input.data);
1144                 talloc_free(call);
1145                 return ndr_map_error2ntstatus(ndr_err);
1146         }
1147
1148         /* we have to check the signing here, before combining the
1149            pdus */
1150         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1151             !dcesrv_auth_request(call, &blob)) {
1152                 dce_partial_advance(dce_conn, blob.length);
1153                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1154         }
1155
1156         dce_partial_advance(dce_conn, blob.length);
1157
1158         /* see if this is a continued packet */
1159         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1160             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1161                 struct dcesrv_call_state *call2 = call;
1162                 uint32_t alloc_size;
1163
1164                 /* we only allow fragmented requests, no other packet types */
1165                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1166                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1167                 }
1168
1169                 /* this is a continuation of an existing call - find the call then
1170                    tack it on the end */
1171                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1172                 if (!call) {
1173                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1174                 }
1175
1176                 if (call->pkt.ptype != call2->pkt.ptype) {
1177                         /* trying to play silly buggers are we? */
1178                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1179                 }
1180
1181                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1182                         call2->pkt.u.request.stub_and_verifier.length;
1183                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1184                         alloc_size = call->pkt.u.request.alloc_hint;
1185                 }
1186
1187                 call->pkt.u.request.stub_and_verifier.data = 
1188                         talloc_realloc(call, 
1189                                        call->pkt.u.request.stub_and_verifier.data, 
1190                                        uint8_t, alloc_size);
1191                 if (!call->pkt.u.request.stub_and_verifier.data) {
1192                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1193                 }
1194                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1195                        call->pkt.u.request.stub_and_verifier.length,
1196                        call2->pkt.u.request.stub_and_verifier.data,
1197                        call2->pkt.u.request.stub_and_verifier.length);
1198                 call->pkt.u.request.stub_and_verifier.length += 
1199                         call2->pkt.u.request.stub_and_verifier.length;
1200
1201                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1202
1203                 talloc_free(call2);
1204         }
1205
1206         /* this may not be the last pdu in the chain - if its isn't then
1207            just put it on the incoming_fragmented_call_list and wait for the rest */
1208         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1209             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1210                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1211                 return NT_STATUS_OK;
1212         } 
1213         
1214         /* This removes any fragments we may have had stashed away */
1215         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1216
1217         switch (call->pkt.ptype) {
1218         case DCERPC_PKT_BIND:
1219                 status = dcesrv_bind(call);
1220                 break;
1221         case DCERPC_PKT_AUTH3:
1222                 status = dcesrv_auth3(call);
1223                 break;
1224         case DCERPC_PKT_ALTER:
1225                 status = dcesrv_alter(call);
1226                 break;
1227         case DCERPC_PKT_REQUEST:
1228                 status = dcesrv_request(call);
1229                 break;
1230         default:
1231                 status = NT_STATUS_INVALID_PARAMETER;
1232                 break;
1233         }
1234
1235         /* if we are going to be sending a reply then add
1236            it to the list of pending calls. We add it to the end to keep the call
1237            list in the order we will answer */
1238         if (!NT_STATUS_IS_OK(status)) {
1239                 talloc_free(call);
1240         }
1241
1242         return status;
1243 }
1244
1245
1246 /*
1247   provide some input to a dcerpc endpoint server. This passes data
1248   from a dcerpc client into the server
1249 */
1250 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1251 {
1252         NTSTATUS status;
1253
1254         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1255                                                       dce_conn->partial_input.data,
1256                                                       uint8_t,
1257                                                       dce_conn->partial_input.length + data->length);
1258         if (!dce_conn->partial_input.data) {
1259                 return NT_STATUS_NO_MEMORY;
1260         }
1261         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1262                data->data, data->length);
1263         dce_conn->partial_input.length += data->length;
1264
1265         while (dce_full_packet(&dce_conn->partial_input)) {
1266                 status = dcesrv_input_process(dce_conn);
1267                 if (!NT_STATUS_IS_OK(status)) {
1268                         return status;
1269                 }
1270         }
1271
1272         return NT_STATUS_OK;
1273 }
1274
1275 /*
1276   retrieve some output from a dcerpc server
1277   The caller supplies a function that will be called to do the
1278   actual output. 
1279
1280   The first argument to write_fn() will be 'private', the second will
1281   be a pointer to a buffer containing the data to be sent and the 3rd
1282   will be a pointer to a size_t variable that will be set to the
1283   number of bytes that are consumed from the output.
1284
1285   from the current fragment
1286 */
1287 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1288                        void *private_data,
1289                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1290 {
1291         NTSTATUS status;
1292         struct dcesrv_call_state *call;
1293         struct data_blob_list_item *rep;
1294         size_t nwritten;
1295
1296         call = dce_conn->call_list;
1297         if (!call || !call->replies) {
1298                 if (dce_conn->pending_call_list) {
1299                         /* TODO: we need to say act async here
1300                          *       as we know we have pending requests
1301                          *       which will be finished at a time
1302                          */
1303                         return NT_STATUS_FOOBAR;
1304                 }
1305                 return NT_STATUS_FOOBAR;
1306         }
1307         rep = call->replies;
1308
1309         status = write_fn(private_data, &rep->blob, &nwritten);
1310         NT_STATUS_IS_ERR_RETURN(status);
1311
1312         rep->blob.length -= nwritten;
1313         rep->blob.data += nwritten;
1314
1315         if (rep->blob.length == 0) {
1316                 /* we're done with this section of the call */
1317                 DLIST_REMOVE(call->replies, rep);
1318         }
1319
1320         if (call->replies == NULL) {
1321                 /* we're done with the whole call */
1322                 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1323                 talloc_free(call);
1324         }
1325
1326         return status;
1327 }
1328
1329 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1330                                       struct loadparm_context *lp_ctx,
1331                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1332 {
1333         NTSTATUS status;
1334         struct dcesrv_context *dce_ctx;
1335         int i;
1336
1337         if (!endpoint_servers) {
1338                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1339                 return NT_STATUS_INTERNAL_ERROR;
1340         }
1341
1342         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1343         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1344         dce_ctx->endpoint_list  = NULL;
1345         dce_ctx->lp_ctx = lp_ctx;
1346
1347         for (i=0;endpoint_servers[i];i++) {
1348                 const struct dcesrv_endpoint_server *ep_server;
1349
1350                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1351                 if (!ep_server) {
1352                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1353                         return NT_STATUS_INTERNAL_ERROR;
1354                 }
1355
1356                 status = ep_server->init_server(dce_ctx, ep_server);
1357                 if (!NT_STATUS_IS_OK(status)) {
1358                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1359                                 nt_errstr(status)));
1360                         return status;
1361                 }
1362         }
1363
1364         *_dce_ctx = dce_ctx;
1365         return NT_STATUS_OK;
1366 }
1367
1368 /* the list of currently registered DCERPC endpoint servers.
1369  */
1370 static struct ep_server {
1371         struct dcesrv_endpoint_server *ep_server;
1372 } *ep_servers = NULL;
1373 static int num_ep_servers;
1374
1375 /*
1376   register a DCERPC endpoint server. 
1377
1378   The 'name' can be later used by other backends to find the operations
1379   structure for this backend.  
1380
1381   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1382 */
1383 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1384 {
1385         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1386         
1387         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1388                 /* its already registered! */
1389                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1390                          ep_server->name));
1391                 return NT_STATUS_OBJECT_NAME_COLLISION;
1392         }
1393
1394         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1395         if (!ep_servers) {
1396                 smb_panic("out of memory in dcerpc_register");
1397         }
1398
1399         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1400         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1401
1402         num_ep_servers++;
1403
1404         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1405                  ep_server->name));
1406
1407         return NT_STATUS_OK;
1408 }
1409
1410 /*
1411   return the operations structure for a named backend of the specified type
1412 */
1413 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1414 {
1415         int i;
1416
1417         for (i=0;i<num_ep_servers;i++) {
1418                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1419                         return ep_servers[i].ep_server;
1420                 }
1421         }
1422
1423         return NULL;
1424 }
1425
1426 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1427 {
1428         static bool initialized;
1429         extern NTSTATUS dcerpc_server_wkssvc_init(void);
1430         extern NTSTATUS dcerpc_server_drsuapi_init(void);
1431         extern NTSTATUS dcerpc_server_winreg_init(void);
1432         extern NTSTATUS dcerpc_server_spoolss_init(void);
1433         extern NTSTATUS dcerpc_server_epmapper_init(void);
1434         extern NTSTATUS dcerpc_server_srvsvc_init(void);
1435         extern NTSTATUS dcerpc_server_netlogon_init(void);
1436         extern NTSTATUS dcerpc_server_rpcecho_init(void);
1437         extern NTSTATUS dcerpc_server_unixinfo_init(void);
1438         extern NTSTATUS dcerpc_server_samr_init(void);
1439         extern NTSTATUS dcerpc_server_remote_init(void);
1440         extern NTSTATUS dcerpc_server_lsa_init(void);
1441         extern NTSTATUS dcerpc_server_browser_init(void);
1442         init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1443         init_module_fn *shared_init;
1444
1445         if (initialized) {
1446                 return;
1447         }
1448         initialized = true;
1449
1450         shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1451
1452         run_init_functions(static_init);
1453         run_init_functions(shared_init);
1454
1455         talloc_free(shared_init);
1456 }
1457
1458 /*
1459   return the DCERPC module version, and the size of some critical types
1460   This can be used by endpoint server modules to either detect compilation errors, or provide
1461   multiple implementations for different smbd compilation options in one module
1462 */
1463 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1464 {
1465         static const struct dcesrv_critical_sizes critical_sizes = {
1466                 DCERPC_MODULE_VERSION,
1467                 sizeof(struct dcesrv_context),
1468                 sizeof(struct dcesrv_endpoint),
1469                 sizeof(struct dcesrv_endpoint_server),
1470                 sizeof(struct dcesrv_interface),
1471                 sizeof(struct dcesrv_if_list),
1472                 sizeof(struct dcesrv_connection),
1473                 sizeof(struct dcesrv_call_state),
1474                 sizeof(struct dcesrv_auth),
1475                 sizeof(struct dcesrv_handle)
1476         };
1477
1478         return &critical_sizes;
1479 }
1480
1481 /*
1482   initialise the dcerpc server context for ncacn_np based services
1483 */
1484 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1485                                           struct dcesrv_context **_dce_ctx)
1486 {
1487         NTSTATUS status;
1488         struct dcesrv_context *dce_ctx;
1489
1490         dcerpc_server_init(lp_ctx);
1491
1492         status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1493         NT_STATUS_NOT_OK_RETURN(status);
1494
1495         *_dce_ctx = dce_ctx;
1496         return NT_STATUS_OK;
1497 }
1498
1499