s4:rpc_server: fix crash bugs in 26200f4fb1db81be7a9da51f317e46405351b170
[kai/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 /*
293   destroy a link to an endpoint
294 */
295 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
296 {
297         while (p->contexts) {
298                 struct dcesrv_connection_context *c = p->contexts;
299
300                 DLIST_REMOVE(p->contexts, c);
301
302                 if (c->iface) {
303                         c->iface->unbind(c, c->iface);
304                 }
305         }
306
307         return 0;
308 }
309
310
311 /*
312   connect to a dcerpc endpoint
313 */
314 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
315                                  TALLOC_CTX *mem_ctx,
316                                  const struct dcesrv_endpoint *ep,
317                                  struct auth_session_info *session_info,
318                                  struct event_context *event_ctx,
319                                  struct messaging_context *msg_ctx,
320                                  struct server_id server_id,
321                                  uint32_t state_flags,
322                                  struct dcesrv_connection **_p)
323 {
324         struct dcesrv_connection *p;
325
326         if (!session_info) {
327                 return NT_STATUS_ACCESS_DENIED;
328         }
329
330         p = talloc(mem_ctx, struct dcesrv_connection);
331         NT_STATUS_HAVE_NO_MEMORY(p);
332
333         if (!talloc_reference(p, session_info)) {
334                 talloc_free(p);
335                 return NT_STATUS_NO_MEMORY;
336         }
337
338         p->dce_ctx = dce_ctx;
339         p->endpoint = ep;
340         p->contexts = NULL;
341         p->call_list = NULL;
342         p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx);
343         p->incoming_fragmented_call_list = NULL;
344         p->pending_call_list = NULL;
345         p->cli_max_recv_frag = 0;
346         p->partial_input = data_blob(NULL, 0);
347         p->auth_state.auth_info = NULL;
348         p->auth_state.gensec_security = NULL;
349         p->auth_state.session_info = session_info;
350         p->auth_state.session_key = dcesrv_generic_session_key;
351         p->event_ctx = event_ctx;
352         p->msg_ctx = msg_ctx;
353         p->server_id = server_id;
354         p->processing = false;
355         p->state_flags = state_flags;
356         ZERO_STRUCT(p->transport);
357
358         talloc_set_destructor(p, dcesrv_endpoint_destructor);
359
360         *_p = p;
361         return NT_STATUS_OK;
362 }
363
364 /*
365   search and connect to a dcerpc endpoint
366 */
367 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
368                                         TALLOC_CTX *mem_ctx,
369                                         const struct dcerpc_binding *ep_description,
370                                         struct auth_session_info *session_info,
371                                         struct event_context *event_ctx,
372                                         struct messaging_context *msg_ctx,
373                                         struct server_id server_id,
374                                         uint32_t state_flags,
375                                         struct dcesrv_connection **dce_conn_p)
376 {
377         NTSTATUS status;
378         const struct dcesrv_endpoint *ep;
379
380         /* make sure this endpoint exists */
381         ep = find_endpoint(dce_ctx, ep_description);
382         if (!ep) {
383                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
384         }
385
386         status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
387                                          event_ctx, msg_ctx, server_id,
388                                          state_flags, dce_conn_p);
389         NT_STATUS_NOT_OK_RETURN(status);
390
391         (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
392
393         /* TODO: check security descriptor of the endpoint here 
394          *       if it's a smb named pipe
395          *       if it's failed free dce_conn_p
396          */
397
398         return NT_STATUS_OK;
399 }
400
401
402 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
403 {
404         pkt->rpc_vers = 5;
405         pkt->rpc_vers_minor = 0;
406         if (bigendian) {
407                 pkt->drep[0] = 0;
408         } else {
409                 pkt->drep[0] = DCERPC_DREP_LE;
410         }
411         pkt->drep[1] = 0;
412         pkt->drep[2] = 0;
413         pkt->drep[3] = 0;
414 }
415
416 /*
417   move a call from an existing linked list to the specified list. This
418   prevents bugs where we forget to remove the call from a previous
419   list when moving it.
420  */
421 static void dcesrv_call_set_list(struct dcesrv_call_state *call, 
422                                  enum dcesrv_call_list list)
423 {
424         switch (call->list) {
425         case DCESRV_LIST_NONE:
426                 break;
427         case DCESRV_LIST_CALL_LIST:
428                 DLIST_REMOVE(call->conn->call_list, call);
429                 break;
430         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
431                 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
432                 break;
433         case DCESRV_LIST_PENDING_CALL_LIST:
434                 DLIST_REMOVE(call->conn->pending_call_list, call);
435                 break;
436         }
437         call->list = list;
438         switch (list) {
439         case DCESRV_LIST_NONE:
440                 break;
441         case DCESRV_LIST_CALL_LIST:
442                 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
443                 break;
444         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
445                 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
446                 break;
447         case DCESRV_LIST_PENDING_CALL_LIST:
448                 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
449                 break;
450         }
451 }
452
453 /*
454   return a dcerpc fault
455 */
456 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
457 {
458         struct ncacn_packet pkt;
459         struct data_blob_list_item *rep;
460         uint8_t zeros[4];
461         NTSTATUS status;
462
463         /* setup a bind_ack */
464         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
465         pkt.auth_length = 0;
466         pkt.call_id = call->pkt.call_id;
467         pkt.ptype = DCERPC_PKT_FAULT;
468         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
469         pkt.u.fault.alloc_hint = 0;
470         pkt.u.fault.context_id = 0;
471         pkt.u.fault.cancel_count = 0;
472         pkt.u.fault.status = fault_code;
473
474         ZERO_STRUCT(zeros);
475         pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
476
477         rep = talloc(call, struct data_blob_list_item);
478         if (!rep) {
479                 return NT_STATUS_NO_MEMORY;
480         }
481
482         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
483         if (!NT_STATUS_IS_OK(status)) {
484                 return status;
485         }
486
487         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
488
489         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
490         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
491
492         return NT_STATUS_OK;    
493 }
494
495
496 /*
497   return a dcerpc bind_nak
498 */
499 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
500 {
501         struct ncacn_packet pkt;
502         struct data_blob_list_item *rep;
503         NTSTATUS status;
504
505         /* setup a bind_nak */
506         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
507         pkt.auth_length = 0;
508         pkt.call_id = call->pkt.call_id;
509         pkt.ptype = DCERPC_PKT_BIND_NAK;
510         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
511         pkt.u.bind_nak.reject_reason = reason;
512         if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
513                 pkt.u.bind_nak.versions.v.num_versions = 0;
514         }
515
516         rep = talloc(call, struct data_blob_list_item);
517         if (!rep) {
518                 return NT_STATUS_NO_MEMORY;
519         }
520
521         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
522         if (!NT_STATUS_IS_OK(status)) {
523                 return status;
524         }
525
526         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
527
528         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
529         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
530
531         return NT_STATUS_OK;    
532 }
533
534
535 /*
536   handle a bind request
537 */
538 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
539 {
540         uint32_t if_version, transfer_syntax_version;
541         struct GUID uuid, *transfer_syntax_uuid;
542         struct ncacn_packet pkt;
543         struct data_blob_list_item *rep;
544         NTSTATUS status;
545         uint32_t result=0, reason=0;
546         uint32_t context_id;
547         const struct dcesrv_interface *iface;
548         uint32_t extra_flags = 0;
549
550         /*
551          * Association groups allow policy handles to be shared across
552          * multiple client connections.  We don't implement this yet.
553          *
554          * So we just allow 0 if the client wants to create a new
555          * association group.
556          *
557          * And we allow the 0x12345678 value, we give away as
558          * assoc_group_id back to the clients
559          */
560         if (call->pkt.u.bind.assoc_group_id != 0 &&
561             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
562             call->pkt.u.bind.assoc_group_id != SAMBA_ASSOC_GROUP) {
563                 return dcesrv_bind_nak(call, 0);        
564         }
565
566         if (call->pkt.u.bind.num_contexts < 1 ||
567             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
568                 return dcesrv_bind_nak(call, 0);
569         }
570
571         context_id = call->pkt.u.bind.ctx_list[0].context_id;
572
573         /* you can't bind twice on one context */
574         if (dcesrv_find_context(call->conn, context_id) != NULL) {
575                 return dcesrv_bind_nak(call, 0);
576         }
577
578         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
579         uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
580
581         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
582         transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
583         if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
584             ndr_transfer_syntax.if_version != transfer_syntax_version) {
585                 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
586                 /* we only do NDR encoded dcerpc */
587                 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
588                 talloc_free(uuid_str);
589                 return dcesrv_bind_nak(call, 0);
590         }
591
592         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
593         if (iface == NULL) {
594                 char *uuid_str = GUID_string(call, &uuid);
595                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
596                 talloc_free(uuid_str);
597
598                 /* we don't know about that interface */
599                 result = DCERPC_BIND_PROVIDER_REJECT;
600                 reason = DCERPC_BIND_REASON_ASYNTAX;            
601         }
602
603         if (iface) {
604                 /* add this context to the list of available context_ids */
605                 struct dcesrv_connection_context *context = talloc(call->conn, 
606                                                                    struct dcesrv_connection_context);
607                 if (context == NULL) {
608                         return dcesrv_bind_nak(call, 0);
609                 }
610                 context->conn = call->conn;
611                 context->iface = iface;
612                 context->context_id = context_id;
613                 /*
614                  * we need to send a non zero assoc_group_id here to make longhorn happy,
615                  * it also matches samba3
616                  */
617                 context->assoc_group_id = SAMBA_ASSOC_GROUP;
618                 context->private = NULL;
619                 context->handles = NULL;
620                 DLIST_ADD(call->conn->contexts, context);
621                 call->context = context;
622         }
623
624         if (call->conn->cli_max_recv_frag == 0) {
625                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
626         }
627
628         if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
629             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
630                 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
631                 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
632         }
633
634         /* handle any authentication that is being requested */
635         if (!dcesrv_auth_bind(call)) {
636                 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
637         }
638
639         /* setup a bind_ack */
640         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
641         pkt.auth_length = 0;
642         pkt.call_id = call->pkt.call_id;
643         pkt.ptype = DCERPC_PKT_BIND_ACK;
644         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
645         pkt.u.bind_ack.max_xmit_frag = 0x2000;
646         pkt.u.bind_ack.max_recv_frag = 0x2000;
647         pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
648         if (iface) {
649                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
650                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
651         } else {
652                 pkt.u.bind_ack.secondary_address = "";
653         }
654         pkt.u.bind_ack.num_results = 1;
655         pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
656         if (!pkt.u.bind_ack.ctx_list) {
657                 return NT_STATUS_NO_MEMORY;
658         }
659         pkt.u.bind_ack.ctx_list[0].result = result;
660         pkt.u.bind_ack.ctx_list[0].reason = reason;
661         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
662         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
663
664         status = dcesrv_auth_bind_ack(call, &pkt);
665         if (!NT_STATUS_IS_OK(status)) {
666                 return dcesrv_bind_nak(call, 0);
667         }
668
669         if (iface) {
670                 status = iface->bind(call, iface);
671                 if (!NT_STATUS_IS_OK(status)) {
672                         char *uuid_str = GUID_string(call, &uuid);
673                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", 
674                                  uuid_str, if_version, nt_errstr(status)));
675                         talloc_free(uuid_str);
676                         return dcesrv_bind_nak(call, 0);
677                 }
678         }
679
680         /* the iface->bind() might change the assoc_group_id */
681         pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
682
683         rep = talloc(call, struct data_blob_list_item);
684         if (!rep) {
685                 return NT_STATUS_NO_MEMORY;
686         }
687
688         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
689         if (!NT_STATUS_IS_OK(status)) {
690                 return status;
691         }
692
693         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
694
695         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
696         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
697
698         return NT_STATUS_OK;
699 }
700
701
702 /*
703   handle a auth3 request
704 */
705 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
706 {
707         /* handle the auth3 in the auth code */
708         if (!dcesrv_auth_auth3(call)) {
709                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
710         }
711
712         talloc_free(call);
713
714         /* we don't send a reply to a auth3 request, except by a
715            fault */
716         return NT_STATUS_OK;
717 }
718
719
720 /*
721   handle a bind request
722 */
723 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
724 {
725         uint32_t if_version, transfer_syntax_version;
726         struct dcesrv_connection_context *context;
727         const struct dcesrv_interface *iface;
728         struct GUID uuid, *transfer_syntax_uuid;
729         NTSTATUS status;
730
731         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
732         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
733
734         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
735         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
736         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
737             ndr_transfer_syntax.if_version != transfer_syntax_version) {
738                 /* we only do NDR encoded dcerpc */
739                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
740         }
741
742         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
743         if (iface == NULL) {
744                 char *uuid_str = GUID_string(call, &uuid);
745                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
746                 talloc_free(uuid_str);
747                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
748         }
749
750         /* add this context to the list of available context_ids */
751         context = talloc(call->conn, struct dcesrv_connection_context);
752         if (context == NULL) {
753                 return NT_STATUS_NO_MEMORY;
754         }
755         context->conn = call->conn;
756         context->iface = iface;
757         context->context_id = context_id;
758         context->assoc_group_id = SAMBA_ASSOC_GROUP;
759         context->private = NULL;
760         context->handles = NULL;
761         DLIST_ADD(call->conn->contexts, context);
762         call->context = context;
763
764         if (iface) {
765                 status = iface->bind(call, iface);
766                 if (!NT_STATUS_IS_OK(status)) {
767                         return status;
768                 }
769         }
770
771         return NT_STATUS_OK;
772 }
773
774
775 /*
776   handle a alter context request
777 */
778 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
779 {
780         struct ncacn_packet pkt;
781         struct data_blob_list_item *rep;
782         NTSTATUS status;
783         uint32_t result=0, reason=0;
784         uint32_t context_id;
785
786         /* handle any authentication that is being requested */
787         if (!dcesrv_auth_alter(call)) {
788                 /* TODO: work out the right reject code */
789                 result = DCERPC_BIND_PROVIDER_REJECT;
790                 reason = DCERPC_BIND_REASON_ASYNTAX;            
791         }
792
793         context_id = call->pkt.u.alter.ctx_list[0].context_id;
794
795         /* see if they are asking for a new interface */
796         if (result == 0) {
797                 call->context = dcesrv_find_context(call->conn, context_id);
798                 if (!call->context) {
799                         status = dcesrv_alter_new_context(call, context_id);
800                         if (!NT_STATUS_IS_OK(status)) {
801                                 result = DCERPC_BIND_PROVIDER_REJECT;
802                                 reason = DCERPC_BIND_REASON_ASYNTAX;
803                         }
804                 }
805         }
806
807         if (result == 0 &&
808             call->pkt.u.alter.assoc_group_id != 0 &&
809             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
810             call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
811                 /* TODO: work out what to return here */
812                 result = DCERPC_BIND_PROVIDER_REJECT;
813                 reason = DCERPC_BIND_REASON_ASYNTAX;
814         }
815
816         /* setup a alter_resp */
817         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
818         pkt.auth_length = 0;
819         pkt.call_id = call->pkt.call_id;
820         pkt.ptype = DCERPC_PKT_ALTER_RESP;
821         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
822         pkt.u.alter_resp.max_xmit_frag = 0x2000;
823         pkt.u.alter_resp.max_recv_frag = 0x2000;
824         if (result == 0) {
825                 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
826         } else {
827                 pkt.u.alter_resp.assoc_group_id = 0;
828         }
829         pkt.u.alter_resp.num_results = 1;
830         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
831         if (!pkt.u.alter_resp.ctx_list) {
832                 return NT_STATUS_NO_MEMORY;
833         }
834         pkt.u.alter_resp.ctx_list[0].result = result;
835         pkt.u.alter_resp.ctx_list[0].reason = reason;
836         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
837         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
838         pkt.u.alter_resp.secondary_address = "";
839
840         status = dcesrv_auth_alter_ack(call, &pkt);
841         if (!NT_STATUS_IS_OK(status)) {
842                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
843                     || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
844                     || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
845                     || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
846                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
847                 }
848                 return dcesrv_fault(call, 0);
849         }
850
851         rep = talloc(call, struct data_blob_list_item);
852         if (!rep) {
853                 return NT_STATUS_NO_MEMORY;
854         }
855
856         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
857         if (!NT_STATUS_IS_OK(status)) {
858                 return status;
859         }
860
861         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
862
863         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
864         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
865
866         return NT_STATUS_OK;
867 }
868
869 /*
870   handle a dcerpc request packet
871 */
872 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
873 {
874         struct ndr_pull *pull;
875         NTSTATUS status;
876         struct dcesrv_connection_context *context;
877
878         /* if authenticated, and the mech we use can't do async replies, don't use them... */
879         if (call->conn->auth_state.gensec_security && 
880             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
881                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
882         }
883
884         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
885         if (context == NULL) {
886                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
887         }
888
889         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
890                                   lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
891         NT_STATUS_HAVE_NO_MEMORY(pull);
892
893         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
894
895         call->context   = context;
896         call->ndr_pull  = pull;
897
898         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
899                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
900         }
901
902         /* unravel the NDR for the packet */
903         status = context->iface->ndr_pull(call, call, pull, &call->r);
904         if (!NT_STATUS_IS_OK(status)) {
905                 return dcesrv_fault(call, call->fault_code);
906         }
907
908         if (pull->offset != pull->data_size) {
909                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
910                          pull->data_size - pull->offset));
911                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
912         }
913
914         /* call the dispatch function */
915         status = context->iface->dispatch(call, call, call->r);
916         if (!NT_STATUS_IS_OK(status)) {
917                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
918                          context->iface->name, 
919                          call->pkt.u.request.opnum,
920                          dcerpc_errstr(pull, call->fault_code)));
921                 return dcesrv_fault(call, call->fault_code);
922         }
923
924         /* add the call to the pending list */
925         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
926
927         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
928                 return NT_STATUS_OK;
929         }
930
931         return dcesrv_reply(call);
932 }
933
934 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
935 {
936         struct ndr_push *push;
937         NTSTATUS status;
938         DATA_BLOB stub;
939         uint32_t total_length, chunk_size;
940         struct dcesrv_connection_context *context = call->context;
941         size_t sig_size = 0;
942
943         /* call the reply function */
944         status = context->iface->reply(call, call, call->r);
945         if (!NT_STATUS_IS_OK(status)) {
946                 return dcesrv_fault(call, call->fault_code);
947         }
948
949         /* form the reply NDR */
950         push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
951         NT_STATUS_HAVE_NO_MEMORY(push);
952
953         /* carry over the pointer count to the reply in case we are
954            using full pointer. See NDR specification for full
955            pointers */
956         push->ptr_count = call->ndr_pull->ptr_count;
957
958         if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
959                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
960         }
961
962         status = context->iface->ndr_push(call, call, push, call->r);
963         if (!NT_STATUS_IS_OK(status)) {
964                 return dcesrv_fault(call, call->fault_code);
965         }
966
967         stub = ndr_push_blob(push);
968
969         total_length = stub.length;
970
971         /* we can write a full max_recv_frag size, minus the dcerpc
972            request header size */
973         chunk_size = call->conn->cli_max_recv_frag;
974         chunk_size -= DCERPC_REQUEST_LENGTH;
975         if (call->conn->auth_state.auth_info &&
976             call->conn->auth_state.gensec_security) {
977                 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
978                                            call->conn->cli_max_recv_frag);
979                 if (sig_size) {
980                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
981                         chunk_size -= sig_size;
982                 }
983         }
984         chunk_size -= (chunk_size % 16);
985
986         do {
987                 uint32_t length;
988                 struct data_blob_list_item *rep;
989                 struct ncacn_packet pkt;
990
991                 rep = talloc(call, struct data_blob_list_item);
992                 NT_STATUS_HAVE_NO_MEMORY(rep);
993
994                 length = MIN(chunk_size, stub.length);
995
996                 /* form the dcerpc response packet */
997                 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
998                 pkt.auth_length = 0;
999                 pkt.call_id = call->pkt.call_id;
1000                 pkt.ptype = DCERPC_PKT_RESPONSE;
1001                 pkt.pfc_flags = 0;
1002                 if (stub.length == total_length) {
1003                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1004                 }
1005                 if (length == stub.length) {
1006                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1007                 }
1008                 pkt.u.response.alloc_hint = stub.length;
1009                 pkt.u.response.context_id = call->pkt.u.request.context_id;
1010                 pkt.u.response.cancel_count = 0;
1011                 pkt.u.response.stub_and_verifier.data = stub.data;
1012                 pkt.u.response.stub_and_verifier.length = length;
1013
1014                 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1015                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
1016                 }
1017
1018                 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1019
1020                 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1021                 
1022                 stub.data += length;
1023                 stub.length -= length;
1024         } while (stub.length != 0);
1025
1026         /* move the call from the pending to the finished calls list */
1027         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1028
1029         if (call->conn->call_list && call->conn->call_list->replies) {
1030                 if (call->conn->transport.report_output_data) {
1031                         call->conn->transport.report_output_data(call->conn);
1032                 }
1033         }
1034
1035         return NT_STATUS_OK;
1036 }
1037
1038 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1039 {
1040         if (!conn->transport.get_my_addr) {
1041                 return NULL;
1042         }
1043
1044         return conn->transport.get_my_addr(conn, mem_ctx);
1045 }
1046
1047 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1048 {
1049         if (!conn->transport.get_peer_addr) {
1050                 return NULL;
1051         }
1052
1053         return conn->transport.get_peer_addr(conn, mem_ctx);
1054 }
1055
1056 /*
1057   work out if we have a full packet yet
1058 */
1059 static bool dce_full_packet(const DATA_BLOB *data)
1060 {
1061         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1062                 return false;
1063         }
1064         if (dcerpc_get_frag_length(data) > data->length) {
1065                 return false;
1066         }
1067         return true;
1068 }
1069
1070 /*
1071   we might have consumed only part of our input - advance past that part
1072 */
1073 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1074 {
1075         DATA_BLOB blob;
1076
1077         if (dce_conn->partial_input.length == offset) {
1078                 data_blob_free(&dce_conn->partial_input);
1079                 return;
1080         }
1081
1082         blob = dce_conn->partial_input;
1083         dce_conn->partial_input = data_blob(blob.data + offset,
1084                                             blob.length - offset);
1085         data_blob_free(&blob);
1086 }
1087
1088 /*
1089   remove the call from the right list when freed
1090  */
1091 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1092 {
1093         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1094         return 0;
1095 }
1096
1097 /*
1098   process some input to a dcerpc endpoint server.
1099 */
1100 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1101 {
1102         struct ndr_pull *ndr;
1103         enum ndr_err_code ndr_err;
1104         NTSTATUS status;
1105         struct dcesrv_call_state *call;
1106         DATA_BLOB blob;
1107
1108         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1109         if (!call) {
1110                 talloc_free(dce_conn->partial_input.data);
1111                 return NT_STATUS_NO_MEMORY;
1112         }
1113         call->conn              = dce_conn;
1114         call->event_ctx         = dce_conn->event_ctx;
1115         call->msg_ctx           = dce_conn->msg_ctx;
1116         call->state_flags       = call->conn->state_flags;
1117         call->time              = timeval_current();
1118         call->list              = DCESRV_LIST_NONE;
1119
1120         talloc_set_destructor(call, dcesrv_call_dequeue);
1121
1122         blob = dce_conn->partial_input;
1123         blob.length = dcerpc_get_frag_length(&blob);
1124
1125         ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1126         if (!ndr) {
1127                 talloc_free(dce_conn->partial_input.data);
1128                 talloc_free(call);
1129                 return NT_STATUS_NO_MEMORY;
1130         }
1131
1132         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1133                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1134         }
1135
1136         if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
1137                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
1138         }
1139
1140         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1141         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1142                 talloc_free(dce_conn->partial_input.data);
1143                 talloc_free(call);
1144                 return ndr_map_error2ntstatus(ndr_err);
1145         }
1146
1147         /* we have to check the signing here, before combining the
1148            pdus */
1149         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1150             !dcesrv_auth_request(call, &blob)) {
1151                 dce_partial_advance(dce_conn, blob.length);
1152                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1153         }
1154
1155         dce_partial_advance(dce_conn, blob.length);
1156
1157         /* see if this is a continued packet */
1158         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1159             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1160                 struct dcesrv_call_state *call2 = call;
1161                 uint32_t alloc_size;
1162
1163                 /* we only allow fragmented requests, no other packet types */
1164                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1165                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1166                 }
1167
1168                 /* this is a continuation of an existing call - find the call then
1169                    tack it on the end */
1170                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1171                 if (!call) {
1172                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1173                 }
1174
1175                 if (call->pkt.ptype != call2->pkt.ptype) {
1176                         /* trying to play silly buggers are we? */
1177                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1178                 }
1179
1180                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1181                         call2->pkt.u.request.stub_and_verifier.length;
1182                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1183                         alloc_size = call->pkt.u.request.alloc_hint;
1184                 }
1185
1186                 call->pkt.u.request.stub_and_verifier.data = 
1187                         talloc_realloc(call, 
1188                                        call->pkt.u.request.stub_and_verifier.data, 
1189                                        uint8_t, alloc_size);
1190                 if (!call->pkt.u.request.stub_and_verifier.data) {
1191                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1192                 }
1193                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1194                        call->pkt.u.request.stub_and_verifier.length,
1195                        call2->pkt.u.request.stub_and_verifier.data,
1196                        call2->pkt.u.request.stub_and_verifier.length);
1197                 call->pkt.u.request.stub_and_verifier.length += 
1198                         call2->pkt.u.request.stub_and_verifier.length;
1199
1200                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1201
1202                 talloc_free(call2);
1203         }
1204
1205         /* this may not be the last pdu in the chain - if its isn't then
1206            just put it on the incoming_fragmented_call_list and wait for the rest */
1207         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1208             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1209                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1210                 return NT_STATUS_OK;
1211         } 
1212         
1213         /* This removes any fragments we may have had stashed away */
1214         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1215
1216         switch (call->pkt.ptype) {
1217         case DCERPC_PKT_BIND:
1218                 status = dcesrv_bind(call);
1219                 break;
1220         case DCERPC_PKT_AUTH3:
1221                 status = dcesrv_auth3(call);
1222                 break;
1223         case DCERPC_PKT_ALTER:
1224                 status = dcesrv_alter(call);
1225                 break;
1226         case DCERPC_PKT_REQUEST:
1227                 status = dcesrv_request(call);
1228                 break;
1229         default:
1230                 status = NT_STATUS_INVALID_PARAMETER;
1231                 break;
1232         }
1233
1234         /* if we are going to be sending a reply then add
1235            it to the list of pending calls. We add it to the end to keep the call
1236            list in the order we will answer */
1237         if (!NT_STATUS_IS_OK(status)) {
1238                 talloc_free(call);
1239         }
1240
1241         return status;
1242 }
1243
1244
1245 /*
1246   provide some input to a dcerpc endpoint server. This passes data
1247   from a dcerpc client into the server
1248 */
1249 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1250 {
1251         NTSTATUS status;
1252
1253         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1254                                                       dce_conn->partial_input.data,
1255                                                       uint8_t,
1256                                                       dce_conn->partial_input.length + data->length);
1257         if (!dce_conn->partial_input.data) {
1258                 return NT_STATUS_NO_MEMORY;
1259         }
1260         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1261                data->data, data->length);
1262         dce_conn->partial_input.length += data->length;
1263
1264         while (dce_full_packet(&dce_conn->partial_input)) {
1265                 status = dcesrv_input_process(dce_conn);
1266                 if (!NT_STATUS_IS_OK(status)) {
1267                         return status;
1268                 }
1269         }
1270
1271         return NT_STATUS_OK;
1272 }
1273
1274 /*
1275   retrieve some output from a dcerpc server
1276   The caller supplies a function that will be called to do the
1277   actual output. 
1278
1279   The first argument to write_fn() will be 'private', the second will
1280   be a pointer to a buffer containing the data to be sent and the 3rd
1281   will be a pointer to a size_t variable that will be set to the
1282   number of bytes that are consumed from the output.
1283
1284   from the current fragment
1285 */
1286 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1287                        void *private_data,
1288                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1289 {
1290         NTSTATUS status;
1291         struct dcesrv_call_state *call;
1292         struct data_blob_list_item *rep;
1293         size_t nwritten;
1294
1295         call = dce_conn->call_list;
1296         if (!call || !call->replies) {
1297                 if (dce_conn->pending_call_list) {
1298                         /* TODO: we need to say act async here
1299                          *       as we know we have pending requests
1300                          *       which will be finished at a time
1301                          */
1302                         return NT_STATUS_FOOBAR;
1303                 }
1304                 return NT_STATUS_FOOBAR;
1305         }
1306         rep = call->replies;
1307
1308         status = write_fn(private_data, &rep->blob, &nwritten);
1309         NT_STATUS_IS_ERR_RETURN(status);
1310
1311         rep->blob.length -= nwritten;
1312         rep->blob.data += nwritten;
1313
1314         if (rep->blob.length == 0) {
1315                 /* we're done with this section of the call */
1316                 DLIST_REMOVE(call->replies, rep);
1317         }
1318
1319         if (call->replies == NULL) {
1320                 /* we're done with the whole call */
1321                 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1322                 talloc_free(call);
1323         }
1324
1325         return status;
1326 }
1327
1328 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
1329                                       struct loadparm_context *lp_ctx,
1330                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1331 {
1332         NTSTATUS status;
1333         struct dcesrv_context *dce_ctx;
1334         int i;
1335
1336         if (!endpoint_servers) {
1337                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1338                 return NT_STATUS_INTERNAL_ERROR;
1339         }
1340
1341         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1342         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1343         dce_ctx->endpoint_list  = NULL;
1344         dce_ctx->lp_ctx = lp_ctx;
1345
1346         for (i=0;endpoint_servers[i];i++) {
1347                 const struct dcesrv_endpoint_server *ep_server;
1348
1349                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1350                 if (!ep_server) {
1351                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1352                         return NT_STATUS_INTERNAL_ERROR;
1353                 }
1354
1355                 status = ep_server->init_server(dce_ctx, ep_server);
1356                 if (!NT_STATUS_IS_OK(status)) {
1357                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1358                                 nt_errstr(status)));
1359                         return status;
1360                 }
1361         }
1362
1363         *_dce_ctx = dce_ctx;
1364         return NT_STATUS_OK;
1365 }
1366
1367 /* the list of currently registered DCERPC endpoint servers.
1368  */
1369 static struct ep_server {
1370         struct dcesrv_endpoint_server *ep_server;
1371 } *ep_servers = NULL;
1372 static int num_ep_servers;
1373
1374 /*
1375   register a DCERPC endpoint server. 
1376
1377   The 'name' can be later used by other backends to find the operations
1378   structure for this backend.  
1379
1380   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1381 */
1382 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1383 {
1384         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1385         
1386         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1387                 /* its already registered! */
1388                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1389                          ep_server->name));
1390                 return NT_STATUS_OBJECT_NAME_COLLISION;
1391         }
1392
1393         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1394         if (!ep_servers) {
1395                 smb_panic("out of memory in dcerpc_register");
1396         }
1397
1398         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1399         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1400
1401         num_ep_servers++;
1402
1403         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1404                  ep_server->name));
1405
1406         return NT_STATUS_OK;
1407 }
1408
1409 /*
1410   return the operations structure for a named backend of the specified type
1411 */
1412 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1413 {
1414         int i;
1415
1416         for (i=0;i<num_ep_servers;i++) {
1417                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1418                         return ep_servers[i].ep_server;
1419                 }
1420         }
1421
1422         return NULL;
1423 }
1424
1425 /*
1426   return the DCERPC module version, and the size of some critical types
1427   This can be used by endpoint server modules to either detect compilation errors, or provide
1428   multiple implementations for different smbd compilation options in one module
1429 */
1430 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1431 {
1432         static const struct dcesrv_critical_sizes critical_sizes = {
1433                 DCERPC_MODULE_VERSION,
1434                 sizeof(struct dcesrv_context),
1435                 sizeof(struct dcesrv_endpoint),
1436                 sizeof(struct dcesrv_endpoint_server),
1437                 sizeof(struct dcesrv_interface),
1438                 sizeof(struct dcesrv_if_list),
1439                 sizeof(struct dcesrv_connection),
1440                 sizeof(struct dcesrv_call_state),
1441                 sizeof(struct dcesrv_auth),
1442                 sizeof(struct dcesrv_handle)
1443         };
1444
1445         return &critical_sizes;
1446 }
1447
1448 /*
1449   initialise the dcerpc server context for ncacn_np based services
1450 */
1451 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1452                                           struct dcesrv_context **_dce_ctx)
1453 {
1454         NTSTATUS status;
1455         struct dcesrv_context *dce_ctx;
1456
1457         status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1458         NT_STATUS_NOT_OK_RETURN(status);
1459
1460         *_dce_ctx = dce_ctx;
1461         return NT_STATUS_OK;
1462 }
1463
1464