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