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