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