r3165: Support local connections in Gtk+ tools
[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
7    Copyright (C) Stefan (metze) Metzmacher 2004
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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 /*
27   see if two endpoints match
28 */
29 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
30                             const struct dcerpc_binding *ep2)
31 {
32         if (ep1->transport != ep2->transport) {
33                 return False;
34         }
35
36         if (!ep1->options || !ep2->options) {
37                 return ep1->options == ep2->options;
38         }
39
40         if (!ep1->options[0] || !ep2->options[0]) {
41                 return ep1->options[0] == ep2->options[0];
42         }
43
44         if (strcasecmp(ep1->options[0], ep2->options[0]) != 0) 
45                 return False;
46
47         return True;
48 }
49
50 /*
51   find an endpoint in the dcesrv_context
52 */
53 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
54                                              const struct dcerpc_binding *ep_description)
55 {
56         struct dcesrv_endpoint *ep;
57         for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
58                 if (endpoints_match(&ep->ep_description, ep_description)) {
59                         return ep;
60                 }
61         }
62         return NULL;
63 }
64
65 /*
66   see if a uuid and if_version match to an interface
67 */
68 static BOOL interface_match(const struct dcesrv_interface *if1,
69                                                         const struct dcesrv_interface *if2)
70 {
71         if (if1->ndr->if_version != if2->ndr->if_version) {
72                 return False;
73         }
74
75         if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
76                 return True;
77         }                       
78
79         return False;
80 }
81
82 /*
83   find the interface operations on an endpoint
84 */
85 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
86                                                        const struct dcesrv_interface *iface)
87 {
88         struct dcesrv_if_list *ifl;
89         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
90                 if (interface_match(&(ifl->iface), iface)) {
91                         return &(ifl->iface);
92                 }
93         }
94         return NULL;
95 }
96
97 /*
98   see if a uuid and if_version match to an interface
99 */
100 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
101                                     const char *uuid, uint32_t if_version)
102 {
103         if (iface->ndr->if_version != if_version) {
104                 return False;
105         }
106
107         if (strcmp(iface->ndr->uuid, uuid)==0) {
108                 return True;
109         }                       
110
111         return False;
112 }
113
114 /*
115   find the interface operations on an endpoint by uuid
116 */
117 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
118                                                              const char *uuid, uint32_t if_version)
119 {
120         struct dcesrv_if_list *ifl;
121         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
122                 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
123                         return &(ifl->iface);
124                 }
125         }
126         return NULL;
127 }
128
129 /*
130   find a call that is pending in our call list
131 */
132 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
133 {
134         struct dcesrv_call_state *c;
135         for (c=dce_conn->call_list;c;c=c->next) {
136                 if (c->pkt.call_id == call_id) {
137                         return c;
138                 }
139         }
140         return NULL;
141 }
142
143 /*
144   register an interface on an endpoint
145 */
146 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
147                                    const char *ep_name,
148                                    const struct dcesrv_interface *iface,
149                                    const struct security_descriptor *sd)
150 {
151         struct dcesrv_endpoint *ep;
152         struct dcesrv_if_list *ifl;
153         struct dcerpc_binding binding;
154         BOOL add_ep = False;
155         NTSTATUS status;
156         
157         status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
158
159         if (NT_STATUS_IS_ERR(status)) {
160                 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
161                 return status;
162         }
163
164         /* check if this endpoint exists
165          */
166         if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
167                 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
168                 if (!ep) {
169                         return NT_STATUS_NO_MEMORY;
170                 }
171                 ZERO_STRUCTP(ep);
172                 ep->ep_description = binding;
173                 add_ep = True;
174         }
175
176         /* see if the interface is already registered on te endpoint */
177         if (find_interface(ep, iface)!=NULL) {
178                 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
179                         iface->ndr->name, ep_name));
180                 return NT_STATUS_OBJECT_NAME_COLLISION;
181         }
182
183         /* talloc a new interface list element */
184         ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
185         if (!ifl) {
186                 return NT_STATUS_NO_MEMORY;
187         }
188
189         /* copy the given interface struct to the one on the endpoints interface list */
190         memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
191
192         /* if we have a security descriptor given,
193          * we should see if we can set it up on the endpoint
194          */
195         if (sd != NULL) {
196                 /* if there's currently no security descriptor given on the endpoint
197                  * we try to set it
198                  */
199                 if (ep->sd == NULL) {
200                         ep->sd = copy_security_descriptor(dce_ctx, sd);
201                 }
202
203                 /* if now there's no security descriptor given on the endpoint
204                  * something goes wrong, either we failed to copy the security descriptor
205                  * or there was already one on the endpoint
206                  */
207                 if (ep->sd != NULL) {
208                         DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
209                                  "                           on endpoint '%s'\n",
210                                 iface->ndr->name, ep_name));
211                         if (add_ep) free(ep);
212                         free(ifl);
213                         return NT_STATUS_OBJECT_NAME_COLLISION;
214                 }
215         }
216
217         /* finally add the interface on the endpoint */
218         DLIST_ADD(ep->interface_list, ifl);
219
220         /* if it's a new endpoint add it to the dcesrv_context */
221         if (add_ep) {
222                 DLIST_ADD(dce_ctx->endpoint_list, ep);
223         }
224
225         DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
226                 iface->ndr->name, ep_name));
227
228         return NT_STATUS_OK;
229 }
230
231 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
232                                               DATA_BLOB *session_key)
233 {
234         if (p->auth_state.session_info->session_key.length) {
235                 *session_key = p->auth_state.session_info->session_key;
236                 return NT_STATUS_OK;
237         }
238         return NT_STATUS_NO_USER_SESSION_KEY;
239 }
240
241 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
242                                     DATA_BLOB *session_key)
243 {
244         /* this took quite a few CPU cycles to find ... */
245         session_key->data = "SystemLibraryDTC";
246         session_key->length = 16;
247         return NT_STATUS_OK;
248 }
249
250 /*
251   fetch the user session key - may be default (above) or the SMB session key
252 */
253 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
254                                   DATA_BLOB *session_key)
255 {
256         return p->auth_state.session_key(p, session_key);
257 }
258
259
260 /*
261   destroy a link to an endpoint
262 */
263 static int dcesrv_endpoint_destructor(void *ptr)
264 {
265         struct dcesrv_connection *p = ptr;
266         if (p->iface) {
267                 p->iface->unbind(p, p->iface);
268         }
269
270         /* destroy any handles */
271         while (p->handles) {
272                 dcesrv_handle_destroy(p, p->handles);
273         }
274
275         if (p->auth_state.gensec_security) {
276                 gensec_end(&p->auth_state.gensec_security);
277         }
278
279         return 0;
280 }
281
282
283 /*
284   connect to a dcerpc endpoint
285 */
286 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
287                                  const struct dcesrv_endpoint *ep,
288                                  struct dcesrv_connection **p)
289 {
290         *p = talloc_p(dce_ctx, struct dcesrv_connection);
291         if (! *p) {
292                 return NT_STATUS_NO_MEMORY;
293         }
294
295         (*p)->dce_ctx = dce_ctx;
296         (*p)->endpoint = ep;
297         (*p)->iface = NULL;
298         (*p)->private = NULL;
299         (*p)->call_list = NULL;
300         (*p)->cli_max_recv_frag = 0;
301         (*p)->handles = NULL;
302         (*p)->partial_input = data_blob(NULL, 0);
303         (*p)->auth_state.auth_info = NULL;
304         (*p)->auth_state.gensec_security = NULL;
305         (*p)->auth_state.session_info = NULL;
306         (*p)->auth_state.session_key = dcesrv_generic_session_key;
307         (*p)->srv_conn = NULL;
308
309         talloc_set_destructor(*p, dcesrv_endpoint_destructor);
310
311         return NT_STATUS_OK;
312 }
313
314 /*
315   search and connect to a dcerpc endpoint
316 */
317 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
318                                         const struct dcerpc_binding *ep_description,
319                                         struct auth_session_info *session_info,
320                                         struct dcesrv_connection **dce_conn_p)
321 {
322         NTSTATUS status;
323         const struct dcesrv_endpoint *ep;
324
325         /* make sure this endpoint exists */
326         ep = find_endpoint(dce_ctx, ep_description);
327         if (!ep) {
328                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
329         }
330
331         status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
332         if (!NT_STATUS_IS_OK(status)) {
333                 return status;
334         }
335
336         session_info->refcount++;
337         (*dce_conn_p)->auth_state.session_info = session_info;
338         (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
339
340         /* TODO: check security descriptor of the endpoint here 
341          *       if it's a smb named pipe
342          *       if it's failed free dce_conn_p
343          */
344
345         return NT_STATUS_OK;
346 }
347
348
349 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
350 {
351         pkt->rpc_vers = 5;
352         pkt->rpc_vers_minor = 0;
353         if (lp_rpc_big_endian()) {
354                 pkt->drep[0] = 0;
355         } else {
356                 pkt->drep[0] = DCERPC_DREP_LE;
357         }
358         pkt->drep[1] = 0;
359         pkt->drep[2] = 0;
360         pkt->drep[3] = 0;
361 }
362
363 /*
364   return a dcerpc fault
365 */
366 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
367 {
368         struct dcerpc_packet pkt;
369         struct dcesrv_call_reply *rep;
370         NTSTATUS status;
371
372         /* setup a bind_ack */
373         dcesrv_init_hdr(&pkt);
374         pkt.auth_length = 0;
375         pkt.call_id = call->pkt.call_id;
376         pkt.ptype = DCERPC_PKT_FAULT;
377         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
378         pkt.u.fault.alloc_hint = 0;
379         pkt.u.fault.context_id = 0;
380         pkt.u.fault.cancel_count = 0;
381         pkt.u.fault.status = fault_code;
382
383         rep = talloc_p(call, struct dcesrv_call_reply);
384         if (!rep) {
385                 return NT_STATUS_NO_MEMORY;
386         }
387
388         status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
389         if (!NT_STATUS_IS_OK(status)) {
390                 return status;
391         }
392
393         dcerpc_set_frag_length(&rep->data, rep->data.length);
394
395         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
396         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
397
398         return NT_STATUS_OK;    
399 }
400
401
402 /*
403   return a dcerpc bind_nak
404 */
405 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
406 {
407         struct dcerpc_packet pkt;
408         struct dcesrv_call_reply *rep;
409         NTSTATUS status;
410
411         /* setup a bind_nak */
412         dcesrv_init_hdr(&pkt);
413         pkt.auth_length = 0;
414         pkt.call_id = call->pkt.call_id;
415         pkt.ptype = DCERPC_PKT_BIND_NAK;
416         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
417         pkt.u.bind_nak.reject_reason = reason;
418         pkt.u.bind_nak.num_versions = 0;
419
420         rep = talloc_p(call, struct dcesrv_call_reply);
421         if (!rep) {
422                 return NT_STATUS_NO_MEMORY;
423         }
424
425         status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
426         if (!NT_STATUS_IS_OK(status)) {
427                 return status;
428         }
429
430         dcerpc_set_frag_length(&rep->data, rep->data.length);
431
432         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
433         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
434
435         return NT_STATUS_OK;    
436 }
437
438
439 /*
440   handle a bind request
441 */
442 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
443 {
444         const char *uuid, *transfer_syntax;
445         uint32_t if_version, transfer_syntax_version;
446         struct dcerpc_packet pkt;
447         struct dcesrv_call_reply *rep;
448         NTSTATUS status;
449         uint32_t result=0, reason=0;
450
451         if (call->pkt.u.bind.num_contexts != 1 ||
452             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
453                 return dcesrv_bind_nak(call, 0);
454         }
455
456         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
457         uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
458         if (!uuid) {
459                 return dcesrv_bind_nak(call, 0);
460         }
461
462         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
463         transfer_syntax = GUID_string(call, 
464                                       &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
465         if (!transfer_syntax ||
466             strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
467             NDR_GUID_VERSION != transfer_syntax_version) {
468                 /* we only do NDR encoded dcerpc */
469                 return dcesrv_bind_nak(call, 0);
470         }
471
472         call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
473         if (!call->conn->iface) {
474                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
475                 /* we don't know about that interface */
476                 result = DCERPC_BIND_PROVIDER_REJECT;
477                 reason = DCERPC_BIND_REASON_ASYNTAX;            
478         }
479
480         if (call->conn->cli_max_recv_frag == 0) {
481                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
482         }
483
484         /* handle any authentication that is being requested */
485         if (!dcesrv_auth_bind(call)) {
486                 /* TODO: work out the right reject code */
487                 return dcesrv_bind_nak(call, 0);
488         }
489
490         /* setup a bind_ack */
491         dcesrv_init_hdr(&pkt);
492         pkt.auth_length = 0;
493         pkt.call_id = call->pkt.call_id;
494         pkt.ptype = DCERPC_PKT_BIND_ACK;
495         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
496         pkt.u.bind_ack.max_xmit_frag = 0x2000;
497         pkt.u.bind_ack.max_recv_frag = 0x2000;
498         pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
499         if (call->conn->iface && call->conn->iface->ndr) {
500                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
501                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", 
502                                                                    call->conn->iface->ndr->name);
503         } else {
504                 pkt.u.bind_ack.secondary_address = "";
505         }
506         pkt.u.bind_ack.num_results = 1;
507         pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
508         if (!pkt.u.bind_ack.ctx_list) {
509                 return NT_STATUS_NO_MEMORY;
510         }
511         pkt.u.bind_ack.ctx_list[0].result = result;
512         pkt.u.bind_ack.ctx_list[0].reason = reason;
513         GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
514         pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
515         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
516
517         if (!dcesrv_auth_bind_ack(call, &pkt)) {
518                 return dcesrv_bind_nak(call, 0);
519         }
520
521         if (call->conn->iface) {
522                 status = call->conn->iface->bind(call, call->conn->iface);
523                 if (!NT_STATUS_IS_OK(status)) {
524                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", uuid, if_version, nt_errstr(status)));
525                         return dcesrv_bind_nak(call, 0);
526                 }
527         }
528
529         rep = talloc_p(call, struct dcesrv_call_reply);
530         if (!rep) {
531                 return NT_STATUS_NO_MEMORY;
532         }
533
534         status = dcerpc_push_auth(&rep->data, call, &pkt, 
535                                   call->conn->auth_state.auth_info);
536         if (!NT_STATUS_IS_OK(status)) {
537                 return status;
538         }
539
540         dcerpc_set_frag_length(&rep->data, rep->data.length);
541
542         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
543         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
544
545         return NT_STATUS_OK;
546 }
547
548
549 /*
550   handle a auth3 request
551 */
552 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
553 {
554         /* handle the auth3 in the auth code */
555         if (!dcesrv_auth_auth3(call)) {
556                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
557         }
558
559         talloc_free(call);
560
561         /* we don't send a reply to a auth3 request, except by a
562            fault */
563         return NT_STATUS_OK;
564 }
565
566
567 /*
568   handle a dcerpc request packet
569 */
570 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
571 {
572         struct ndr_pull *pull;
573         struct ndr_push *push;
574         uint16_t opnum;
575         void *r;
576         NTSTATUS status;
577         DATA_BLOB stub;
578         uint32_t total_length;
579
580
581         if (!call->conn->iface) {
582                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
583         }
584
585         opnum = call->pkt.u.request.opnum;
586
587         if (opnum >= call->conn->iface->ndr->num_calls) {
588                 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
589         }
590
591         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
592         if (!pull) {
593                 return NT_STATUS_NO_MEMORY;
594         }
595
596         r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
597         if (!r) {
598                 return NT_STATUS_NO_MEMORY;
599         }
600
601         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
602                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
603         }
604
605         /* unravel the NDR for the packet */
606         status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
607         if (!NT_STATUS_IS_OK(status)) {
608                 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN, 
609                                   &call->pkt.u.request.stub_and_verifier);
610                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
611         }
612
613         if (pull->offset != pull->data_size) {
614                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
615                          pull->data_size - pull->offset));
616                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
617         }
618
619         call->fault_code = 0;
620
621         /* call the dispatch function */
622         status = call->conn->iface->dispatch(call, call, r);
623         if (!NT_STATUS_IS_OK(status)) {
624                 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN, 
625                                   &call->pkt.u.request.stub_and_verifier);
626                 return dcesrv_fault(call, call->fault_code);
627         }
628
629         /* form the reply NDR */
630         push = ndr_push_init_ctx(call);
631         if (!push) {
632                 return NT_STATUS_NO_MEMORY;
633         }
634
635         /* carry over the pointer count to the reply in case we are
636            using full pointer. See NDR specification for full
637            pointers */
638         push->ptr_count = pull->ptr_count;
639
640         if (lp_rpc_big_endian()) {
641                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
642         }
643
644         status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
645         if (!NT_STATUS_IS_OK(status)) {
646                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
647         }
648
649         stub = ndr_push_blob(push);
650
651         total_length = stub.length;
652
653         do {
654                 uint32_t length;
655                 struct dcesrv_call_reply *rep;
656                 struct dcerpc_packet pkt;
657
658                 rep = talloc_p(call, struct dcesrv_call_reply);
659                 if (!rep) {
660                         return NT_STATUS_NO_MEMORY;
661                 }
662
663                 length = stub.length;
664                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
665                         /* the 32 is to cope with signing data */
666                         length = call->conn->cli_max_recv_frag - 
667                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
668                 }
669
670                 /* form the dcerpc response packet */
671                 dcesrv_init_hdr(&pkt);
672                 pkt.auth_length = 0;
673                 pkt.call_id = call->pkt.call_id;
674                 pkt.ptype = DCERPC_PKT_RESPONSE;
675                 pkt.pfc_flags = 0;
676                 if (stub.length == total_length) {
677                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
678                 }
679                 if (length == stub.length) {
680                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
681                 }
682                 pkt.u.response.alloc_hint = stub.length;
683                 pkt.u.response.context_id = call->pkt.u.request.context_id;
684                 pkt.u.response.cancel_count = 0;
685                 pkt.u.response.stub_and_verifier.data = stub.data;
686                 pkt.u.response.stub_and_verifier.length = length;
687
688                 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
689                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
690                 }
691
692                 dcerpc_set_frag_length(&rep->data, rep->data.length);
693
694                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
695                 
696                 stub.data += length;
697                 stub.length -= length;
698         } while (stub.length != 0);
699
700         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
701
702         return NT_STATUS_OK;
703 }
704
705
706 /*
707   work out if we have a full packet yet
708 */
709 static BOOL dce_full_packet(const DATA_BLOB *data)
710 {
711         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
712                 return False;
713         }
714         if (dcerpc_get_frag_length(data) > data->length) {
715                 return False;
716         }
717         return True;
718 }
719
720 /*
721   we might have consumed only part of our input - advance past that part
722 */
723 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
724 {
725         DATA_BLOB blob;
726
727         if (dce_conn->partial_input.length == offset) {
728                 data_blob_free(&dce_conn->partial_input);
729                 return;
730         }
731
732         blob = dce_conn->partial_input;
733         dce_conn->partial_input = data_blob(blob.data + offset,
734                                             blob.length - offset);
735         data_blob_free(&blob);
736 }
737
738 /*
739   process some input to a dcerpc endpoint server.
740 */
741 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
742 {
743         struct ndr_pull *ndr;
744         NTSTATUS status;
745         struct dcesrv_call_state *call;
746         DATA_BLOB blob;
747
748         call = talloc_p(dce_conn, struct dcesrv_call_state);
749         if (!call) {
750                 talloc_free(dce_conn->partial_input.data);
751                 return NT_STATUS_NO_MEMORY;
752         }
753         call->conn = dce_conn;
754         call->replies = NULL;
755
756         blob = dce_conn->partial_input;
757         blob.length = dcerpc_get_frag_length(&blob);
758
759         ndr = ndr_pull_init_blob(&blob, call);
760         if (!ndr) {
761                 talloc_free(dce_conn->partial_input.data);
762                 talloc_free(call);
763                 return NT_STATUS_NO_MEMORY;
764         }
765
766         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
767                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
768         }
769
770         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
771         if (!NT_STATUS_IS_OK(status)) {
772                 talloc_free(dce_conn->partial_input.data);
773                 talloc_free(call);
774                 return status;
775         }
776
777         /* we have to check the signing here, before combining the
778            pdus */
779         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
780             !dcesrv_auth_request(call, &blob)) {
781                 dce_partial_advance(dce_conn, blob.length);
782                 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);          
783         }
784
785         dce_partial_advance(dce_conn, blob.length);
786
787         /* see if this is a continued packet */
788         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
789                 struct dcesrv_call_state *call2 = call;
790                 uint32_t alloc_size;
791
792                 /* we only allow fragmented requests, no other packet types */
793                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
794                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
795                 }
796
797                 /* this is a continuation of an existing call - find the call then
798                    tack it on the end */
799                 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
800                 if (!call) {
801                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
802                 }
803
804                 if (call->pkt.ptype != call2->pkt.ptype) {
805                         /* trying to play silly buggers are we? */
806                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
807                 }
808
809                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
810                         call2->pkt.u.request.stub_and_verifier.length;
811                 if (call->pkt.u.request.alloc_hint > alloc_size) {
812                         alloc_size = call->pkt.u.request.alloc_hint;
813                 }
814
815                 call->pkt.u.request.stub_and_verifier.data = 
816                         talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
817                 if (!call->pkt.u.request.stub_and_verifier.data) {
818                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
819                 }
820                 memcpy(call->pkt.u.request.stub_and_verifier.data +
821                        call->pkt.u.request.stub_and_verifier.length,
822                        call2->pkt.u.request.stub_and_verifier.data,
823                        call2->pkt.u.request.stub_and_verifier.length);
824                 call->pkt.u.request.stub_and_verifier.length += 
825                         call2->pkt.u.request.stub_and_verifier.length;
826
827                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
828
829                 talloc_free(call2);
830         }
831
832         /* this may not be the last pdu in the chain - if its isn't then
833            just put it on the call_list and wait for the rest */
834         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
835                 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
836                 return NT_STATUS_OK;
837         }
838
839         switch (call->pkt.ptype) {
840         case DCERPC_PKT_BIND:
841                 status = dcesrv_bind(call);
842                 break;
843         case DCERPC_PKT_AUTH3:
844                 status = dcesrv_auth3(call);
845                 break;
846         case DCERPC_PKT_REQUEST:
847                 status = dcesrv_request(call);
848                 break;
849         default:
850                 status = NT_STATUS_INVALID_PARAMETER;
851                 break;
852         }
853
854         /* if we are going to be sending a reply then add
855            it to the list of pending calls. We add it to the end to keep the call
856            list in the order we will answer */
857         if (!NT_STATUS_IS_OK(status)) {
858                 talloc_free(call);
859         }
860
861         return status;
862 }
863
864
865 /*
866   provide some input to a dcerpc endpoint server. This passes data
867   from a dcerpc client into the server
868 */
869 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
870 {
871         NTSTATUS status;
872
873         dce_conn->partial_input.data = talloc_realloc(dce_conn,
874                                                       dce_conn->partial_input.data,
875                                                       dce_conn->partial_input.length + data->length);
876         if (!dce_conn->partial_input.data) {
877                 return NT_STATUS_NO_MEMORY;
878         }
879         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
880                data->data, data->length);
881         dce_conn->partial_input.length += data->length;
882
883         while (dce_full_packet(&dce_conn->partial_input)) {
884                 status = dcesrv_input_process(dce_conn);
885                 if (!NT_STATUS_IS_OK(status)) {
886                         return status;
887                 }
888         }
889
890         return NT_STATUS_OK;
891 }
892
893 /*
894   retrieve some output from a dcerpc server
895   The caller supplies a function that will be called to do the
896   actual output. 
897
898   The first argument to write_fn() will be 'private', the second will
899   be a pointer to a buffer containing the data to be sent and the 3rd
900   will be the number of bytes to be sent.
901
902   write_fn() should return the number of bytes successfully written.
903
904   this will return STATUS_BUFFER_OVERFLOW if there is more to be read
905   from the current fragment
906 */
907 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
908                        void *private,
909                        ssize_t (*write_fn)(void *, DATA_BLOB *))
910 {
911         struct dcesrv_call_state *call;
912         struct dcesrv_call_reply *rep;
913         ssize_t nwritten;
914         NTSTATUS status = NT_STATUS_OK;
915
916         call = dce_conn->call_list;
917         if (!call || !call->replies) {
918                 return NT_STATUS_FOOBAR;
919         }
920         rep = call->replies;
921
922         nwritten = write_fn(private, &rep->data);
923         if (nwritten == -1) {
924                 /* TODO: hmm, how do we cope with this? destroy the
925                    connection perhaps? */
926                 return NT_STATUS_UNSUCCESSFUL;
927         }
928
929         rep->data.length -= nwritten;
930         rep->data.data += nwritten;
931
932         if (rep->data.length == 0) {
933                 /* we're done with this section of the call */
934                 DLIST_REMOVE(call->replies, rep);
935         } else {
936                 status = STATUS_BUFFER_OVERFLOW;
937         }
938
939         if (call->replies == NULL) {
940                 /* we're done with the whole call */
941                 DLIST_REMOVE(dce_conn->call_list, call);
942                 talloc_free(call);
943         }
944
945         return status;
946 }
947
948
949 /*
950   write_fn() for dcesrv_output_blob()
951 */
952 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
953 {
954         DATA_BLOB *blob = private;
955         if (out->length < blob->length) {
956                 blob->length = out->length;
957         }
958         memcpy(blob->data, out->data, blob->length);
959         return blob->length;
960 }
961
962 /*
963   a simple wrapper for dcesrv_output() for when we want to output
964   into a data blob
965 */
966 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn, 
967                             DATA_BLOB *blob)
968 {
969         return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
970 }
971
972 /*
973   initialise the dcerpc server context
974 */
975 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
976 {
977         int i;
978         const char **endpoint_servers = lp_dcerpc_endpoint_servers();
979
980         (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
981         if (! *dce_ctx) {
982                 return NT_STATUS_NO_MEMORY;
983         }
984
985         (*dce_ctx)->endpoint_list = NULL;
986
987         if (!endpoint_servers) {
988                 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
989                 return NT_STATUS_OK;
990         }
991
992         for (i=0;endpoint_servers[i];i++) {
993                 NTSTATUS ret;
994                 const struct dcesrv_endpoint_server *ep_server;
995                 
996                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
997                 if (!ep_server) {
998                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
999                         return NT_STATUS_UNSUCCESSFUL;
1000                 }
1001
1002                 ret = ep_server->init_server(*dce_ctx, ep_server);
1003                 if (!NT_STATUS_IS_OK(ret)) {
1004                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1005                         return ret;
1006                 }
1007         }
1008
1009         return NT_STATUS_OK;
1010 }
1011
1012 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1013 {
1014         struct dcesrv_context *dce_ctx;
1015         int i;
1016         const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1017
1018         DEBUG(1,("dcesrv_init\n"));
1019
1020         if (!endpoint_servers) {
1021                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1022                 return;
1023         }
1024
1025         dce_ctx = talloc_p(service, struct dcesrv_context);
1026         if (!dce_ctx) {
1027                 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1028                 return;
1029         }
1030
1031         ZERO_STRUCTP(dce_ctx);
1032         dce_ctx->endpoint_list  = NULL;
1033
1034         for (i=0;endpoint_servers[i];i++) {
1035                 NTSTATUS ret;
1036                 const struct dcesrv_endpoint_server *ep_server;
1037                 
1038                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1039                 if (!ep_server) {
1040                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1041                         return;
1042                 }
1043
1044                 ret = ep_server->init_server(dce_ctx, ep_server);
1045                 if (!NT_STATUS_IS_OK(ret)) {
1046                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1047                         return;
1048                 }
1049         }
1050
1051         dcesrv_sock_init(service, model_ops, dce_ctx);
1052
1053         return; 
1054 }
1055
1056 static void dcesrv_accept(struct server_connection *srv_conn)
1057 {
1058         dcesrv_sock_accept(srv_conn);
1059 }
1060
1061 static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
1062 {
1063         dcesrv_sock_recv(srv_conn, t, flags);
1064 }
1065
1066 static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
1067 {
1068         dcesrv_sock_send(srv_conn, t, flags);
1069 }
1070
1071 static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
1072 {
1073         dcesrv_sock_idle(srv_conn, t);
1074 }
1075
1076 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1077 {
1078         dcesrv_sock_close(srv_conn, reason);
1079         return; 
1080 }
1081
1082 static void dcesrv_exit(struct server_service *service, const char *reason)
1083 {
1084         dcesrv_sock_exit(service, reason);
1085         return; 
1086 }
1087
1088 /* the list of currently registered DCERPC endpoint servers.
1089  */
1090 static struct {
1091         struct dcesrv_endpoint_server *ep_server;
1092 } *ep_servers = NULL;
1093 static int num_ep_servers;
1094
1095 /*
1096   register a DCERPC endpoint server. 
1097
1098   The 'name' can be later used by other backends to find the operations
1099   structure for this backend.  
1100
1101   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1102 */
1103 static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1104 {
1105         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1106         
1107         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1108                 /* its already registered! */
1109                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1110                          ep_server->name));
1111                 return NT_STATUS_OBJECT_NAME_COLLISION;
1112         }
1113
1114         ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1115         if (!ep_servers) {
1116                 smb_panic("out of memory in dcerpc_register");
1117         }
1118
1119         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1120         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1121
1122         num_ep_servers++;
1123
1124         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1125                  ep_server->name));
1126
1127         return NT_STATUS_OK;
1128 }
1129
1130 /*
1131   return the operations structure for a named backend of the specified type
1132 */
1133 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1134 {
1135         int i;
1136
1137         for (i=0;i<num_ep_servers;i++) {
1138                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1139                         return ep_servers[i].ep_server;
1140                 }
1141         }
1142
1143         return NULL;
1144 }
1145
1146 /*
1147   return the DCERPC module version, and the size of some critical types
1148   This can be used by endpoint server modules to either detect compilation errors, or provide
1149   multiple implementations for different smbd compilation options in one module
1150 */
1151 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1152 {
1153         static const struct dcesrv_critical_sizes critical_sizes = {
1154                 DCERPC_MODULE_VERSION,
1155                 sizeof(struct dcesrv_context),
1156                 sizeof(struct dcesrv_endpoint),
1157                 sizeof(struct dcesrv_endpoint_server),
1158                 sizeof(struct dcesrv_interface),
1159                 sizeof(struct dcesrv_if_list),
1160                 sizeof(struct dcesrv_connection),
1161                 sizeof(struct dcesrv_call_state),
1162                 sizeof(struct dcesrv_auth),
1163                 sizeof(struct dcesrv_handle)
1164         };
1165
1166         return &critical_sizes;
1167 }
1168
1169 /*
1170   initialise the DCERPC subsystem
1171 */
1172 BOOL subsystem_dcerpc_init(void)
1173 {
1174         NTSTATUS status;
1175
1176         status = register_subsystem("dcerpc", dcerpc_register_ep_server); 
1177         if (!NT_STATUS_IS_OK(status)) {
1178                 return False;
1179         }
1180
1181         /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPPER, fails to initialise? */
1182         static_init_dcerpc;
1183
1184         DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1185         return True;
1186 }
1187
1188 static const struct server_service_ops dcesrv_ops = {
1189         .name                   = "rpc",
1190         .service_init           = dcesrv_init,
1191         .accept_connection      = dcesrv_accept,
1192         .recv_handler           = dcesrv_recv,
1193         .send_handler           = dcesrv_send,
1194         .idle_handler           = dcesrv_idle,
1195         .close_connection       = dcesrv_close,
1196         .service_exit           = dcesrv_exit,  
1197 };
1198
1199 const struct server_service_ops *dcesrv_get_ops(void)
1200 {
1201         return &dcesrv_ops;
1202 }
1203
1204 NTSTATUS server_service_rpc_init(void)
1205 {
1206         return NT_STATUS_OK;    
1207 }