r995: - renamed many of our crypto routines to use the industry standard
[samba.git] / source / 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 dcesrv_ep_description *ep1,
30                                                         const struct dcesrv_ep_description *ep2)
31 {
32         if (ep1->type != ep2->type) {
33                 return False;
34         }
35
36         switch (ep1->type) {
37                 case ENDPOINT_SMB:
38                         if (strcasecmp(ep1->info.smb_pipe,ep2->info.smb_pipe)==0) {
39                                 return True;
40                         }                       
41                         break;
42                 case ENDPOINT_TCP:
43                         if (ep1->info.tcp_port == ep2->info.tcp_port) {
44                                 return True;
45                         }
46                         break;
47         }
48
49         return False;
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 dcesrv_ep_description *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_ep_description ep_description;
154         struct dcesrv_endpoint *ep;
155         struct dcesrv_if_list *ifl;
156         BOOL tcp;
157         BOOL add_ep = False;
158
159         tcp = (strncasecmp(ep_name, "TCP-", 4) == 0);
160
161         if (tcp) {
162                 ep_description.type = ENDPOINT_TCP;
163                 ep_description.info.tcp_port = atoi(ep_name+4);
164         } else {
165                 ep_description.type = ENDPOINT_SMB;
166                 ep_description.info.smb_pipe = ep_name;
167         }
168
169         /* check if this endpoint exists
170          */
171         if ((ep=find_endpoint(dce_ctx, &ep_description))==NULL) {
172                 ep = talloc(dce_ctx->mem_ctx, sizeof(*ep));
173                 if (!ep) {
174                         return NT_STATUS_NO_MEMORY;
175                 }
176                 ZERO_STRUCTP(ep);
177                 if (tcp) {
178                         ep->ep_description.type = ENDPOINT_TCP;
179                         ep->ep_description.info.tcp_port = atoi(ep_name+4);
180                 } else {
181                         ep->ep_description.type = ENDPOINT_SMB;
182                         ep->ep_description.info.smb_pipe = smb_xstrdup(ep_name);
183                 }
184                 add_ep = True;
185         }
186
187         /* see if the interface is already registered on te endpoint */
188         if (find_interface(ep, iface)!=NULL) {
189                 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
190                         iface->ndr->name, ep_name));
191                 return NT_STATUS_OBJECT_NAME_COLLISION;
192         }
193
194         /* talloc a new interface list element */
195         ifl = talloc(dce_ctx->mem_ctx, sizeof(*ifl));
196         if (!ifl) {
197                 return NT_STATUS_NO_MEMORY;
198         }
199
200         /* copy the given interface struct to the one on the endpoints interface list */
201         memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
202
203         /* if we have a security descriptor given,
204          * we should see if we can set it up on the endpoint
205          */
206         if (sd != NULL) {
207                 /* if there's currently no security descriptor given on the endpoint
208                  * we try to set it
209                  */
210                 if (ep->sd == NULL) {
211                         ep->sd = copy_security_descriptor(dce_ctx->mem_ctx, sd);
212                 }
213
214                 /* if now there's no security descriptor given on the endpoint
215                  * something goes wrong, either we failed to copy the security descriptor
216                  * or there was already one on the endpoint
217                  */
218                 if (ep->sd != NULL) {
219                         DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
220                                  "                           on endpoint '%s'\n",
221                                 iface->ndr->name, ep_name));
222                         if (add_ep) free(ep);
223                         free(ifl);
224                         return NT_STATUS_OBJECT_NAME_COLLISION;
225                 }
226         }
227
228         /* finally add the interface on the endpoint */
229         DLIST_ADD(ep->interface_list, ifl);
230
231         /* if it's a new endpoint add it to the dcesrv_context */
232         if (add_ep) {
233                 DLIST_ADD(dce_ctx->endpoint_list, ep);
234         }
235
236         DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
237                 iface->ndr->name, ep_name));
238
239         return NT_STATUS_OK;
240 }
241
242 /*
243   connect to a dcerpc endpoint
244 */
245 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
246                                  const struct dcesrv_endpoint *ep,
247                                  struct dcesrv_connection **p)
248 {
249         TALLOC_CTX *mem_ctx;
250
251         mem_ctx = talloc_init("dcesrv_endpoint_connect");
252         if (!mem_ctx) {
253                 return NT_STATUS_NO_MEMORY;
254         }
255
256         *p = talloc_p(mem_ctx, struct dcesrv_connection);
257         if (! *p) {
258                 talloc_destroy(mem_ctx);
259                 return NT_STATUS_NO_MEMORY;
260         }
261
262         (*p)->dce_ctx = dce_ctx;
263         (*p)->mem_ctx = mem_ctx;
264         (*p)->endpoint = ep;
265         (*p)->iface = NULL;
266         (*p)->private = NULL;
267         (*p)->call_list = NULL;
268         (*p)->cli_max_recv_frag = 0;
269         (*p)->handles = NULL;
270         (*p)->partial_input = data_blob(NULL, 0);
271         (*p)->auth_state.crypto_state = NULL;
272         (*p)->auth_state.auth_info = NULL;
273         (*p)->session_key = data_blob(NULL, 0);
274
275         return NT_STATUS_OK;
276 }
277
278 /*
279   set the transport level session key
280 */
281 void dcesrv_set_session_key(struct dcesrv_connection *p, DATA_BLOB key)
282 {
283         p->session_key = data_blob_talloc(p->mem_ctx, key.data, key.length);
284 }
285
286 /*
287   search and connect to a dcerpc endpoint
288 */
289 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
290                                         const struct dcesrv_ep_description *ep_description,
291                                         struct dcesrv_connection **dce_conn_p)
292 {
293         NTSTATUS status;
294         const struct dcesrv_endpoint *ep;
295
296         /* make sure this endpoint exists */
297         ep = find_endpoint(dce_ctx, ep_description);
298         if (!ep) {
299                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
300         }
301
302         status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
303         if (!NT_STATUS_IS_OK(status)) {
304                 return status;
305         }
306
307         /* TODO: check security descriptor of the endpoint here 
308          *       if it's a smb named pipe
309          *       if it's failed free dce_conn_p
310          */
311
312         return NT_STATUS_OK;
313 }
314
315
316 /*
317   disconnect a link to an endpoint
318 */
319 void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
320 {
321         if (p->iface) {
322                 p->iface->unbind(p, p->iface);
323         }
324
325         /* destroy any handles */
326         while (p->handles) {
327                 dcesrv_handle_destroy(p, p->handles);
328         }
329         
330         talloc_destroy(p->mem_ctx);
331 }
332
333 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
334 {
335         pkt->rpc_vers = 5;
336         pkt->rpc_vers_minor = 0;
337         if (lp_rpc_big_endian()) {
338                 pkt->drep[0] = 0;
339         } else {
340                 pkt->drep[0] = DCERPC_DREP_LE;
341         }
342         pkt->drep[1] = 0;
343         pkt->drep[2] = 0;
344         pkt->drep[3] = 0;
345 }
346
347 /*
348   return a dcerpc fault
349 */
350 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
351 {
352         struct dcerpc_packet pkt;
353         struct dcesrv_call_reply *rep;
354         NTSTATUS status;
355
356         /* setup a bind_ack */
357         dcesrv_init_hdr(&pkt);
358         pkt.auth_length = 0;
359         pkt.call_id = call->pkt.call_id;
360         pkt.ptype = DCERPC_PKT_FAULT;
361         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
362         pkt.u.fault.alloc_hint = 0;
363         pkt.u.fault.context_id = 0;
364         pkt.u.fault.cancel_count = 0;
365         pkt.u.fault.status = fault_code;
366
367         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
368         if (!rep) {
369                 return NT_STATUS_NO_MEMORY;
370         }
371
372         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
373         if (!NT_STATUS_IS_OK(status)) {
374                 return status;
375         }
376
377         dcerpc_set_frag_length(&rep->data, rep->data.length);
378
379         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
380         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
381
382         return NT_STATUS_OK;    
383 }
384
385
386 /*
387   return a dcerpc bind_nak
388 */
389 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
390 {
391         struct dcerpc_packet pkt;
392         struct dcesrv_call_reply *rep;
393         NTSTATUS status;
394
395         /* setup a bind_nak */
396         dcesrv_init_hdr(&pkt);
397         pkt.auth_length = 0;
398         pkt.call_id = call->pkt.call_id;
399         pkt.ptype = DCERPC_PKT_BIND_NAK;
400         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
401         pkt.u.bind_nak.reject_reason = reason;
402         pkt.u.bind_nak.num_versions = 0;
403
404         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
405         if (!rep) {
406                 return NT_STATUS_NO_MEMORY;
407         }
408
409         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
410         if (!NT_STATUS_IS_OK(status)) {
411                 return status;
412         }
413
414         dcerpc_set_frag_length(&rep->data, rep->data.length);
415
416         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
417         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
418
419         return NT_STATUS_OK;    
420 }
421
422
423 /*
424   handle a bind request
425 */
426 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
427 {
428         const char *uuid, *transfer_syntax;
429         uint32_t if_version, transfer_syntax_version;
430         struct dcerpc_packet pkt;
431         struct dcesrv_call_reply *rep;
432         NTSTATUS status;
433         uint32_t result=0, reason=0;
434
435         if (call->pkt.u.bind.num_contexts != 1 ||
436             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
437                 return dcesrv_bind_nak(call, 0);
438         }
439
440         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
441         uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
442         if (!uuid) {
443                 return dcesrv_bind_nak(call, 0);
444         }
445
446         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
447         transfer_syntax = GUID_string(call->mem_ctx, 
448                                       &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
449         if (!transfer_syntax ||
450             strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
451             NDR_GUID_VERSION != transfer_syntax_version) {
452                 /* we only do NDR encoded dcerpc */
453                 return dcesrv_bind_nak(call, 0);
454         }
455
456         call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
457         if (!call->conn->iface) {
458                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
459                 /* we don't know about that interface */
460                 result = DCERPC_BIND_PROVIDER_REJECT;
461                 reason = DCERPC_BIND_REASON_ASYNTAX;            
462         }
463
464         if (call->conn->cli_max_recv_frag == 0) {
465                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
466         }
467
468         /* handle any authentication that is being requested */
469         if (!dcesrv_auth_bind(call)) {
470                 /* TODO: work out the right reject code */
471                 return dcesrv_bind_nak(call, 0);
472         }
473
474         /* setup a bind_ack */
475         dcesrv_init_hdr(&pkt);
476         pkt.auth_length = 0;
477         pkt.call_id = call->pkt.call_id;
478         pkt.ptype = DCERPC_PKT_BIND_ACK;
479         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
480         pkt.u.bind_ack.max_xmit_frag = 0x2000;
481         pkt.u.bind_ack.max_recv_frag = 0x2000;
482         pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
483         if (call->conn->iface && call->conn->iface->ndr) {
484                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s", 
485                                                                    call->conn->iface->ndr->name);
486         } else {
487                 pkt.u.bind_ack.secondary_address = "";
488         }
489         pkt.u.bind_ack.num_results = 1;
490         pkt.u.bind_ack.ctx_list = talloc_p(call->mem_ctx, struct dcerpc_ack_ctx);
491         if (!pkt.u.bind_ack.ctx_list) {
492                 return NT_STATUS_NO_MEMORY;
493         }
494         pkt.u.bind_ack.ctx_list[0].result = result;
495         pkt.u.bind_ack.ctx_list[0].reason = reason;
496         GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
497         pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
498         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
499
500         if (!dcesrv_auth_bind_ack(call, &pkt)) {
501                 return dcesrv_bind_nak(call, 0);
502         }
503
504         if (call->conn->iface) {
505                 status = call->conn->iface->bind(call, call->conn->iface);
506                 if (!NT_STATUS_IS_OK(status)) {
507                         DEBUG(2,("Request for dcerpc interface %s/%d rejected\n", uuid, if_version));
508                         return status;
509                 }
510         }
511
512         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
513         if (!rep) {
514                 return NT_STATUS_NO_MEMORY;
515         }
516
517         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, 
518                                   call->conn->auth_state.auth_info);
519         if (!NT_STATUS_IS_OK(status)) {
520                 return status;
521         }
522
523         dcerpc_set_frag_length(&rep->data, rep->data.length);
524
525         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
526         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
527
528         return NT_STATUS_OK;
529 }
530
531
532 /*
533   handle a auth3 request
534 */
535 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
536 {
537         /* handle the auth3 in the auth code */
538         if (!dcesrv_auth_auth3(call)) {
539                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
540         }
541
542         talloc_destroy(call->mem_ctx);
543
544         /* we don't send a reply to a auth3 request, except by a
545            fault */
546         return NT_STATUS_OK;
547 }
548
549
550 /*
551   handle a dcerpc request packet
552 */
553 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
554 {
555         struct ndr_pull *pull;
556         struct ndr_push *push;
557         uint16_t opnum;
558         void *r;
559         NTSTATUS status;
560         DATA_BLOB stub;
561         uint32_t total_length;
562
563
564         if (!call->conn->iface) {
565                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
566         }
567
568         opnum = call->pkt.u.request.opnum;
569
570         if (opnum >= call->conn->iface->ndr->num_calls) {
571                 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
572         }
573
574         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call->mem_ctx);
575         if (!pull) {
576                 return NT_STATUS_NO_MEMORY;
577         }
578
579         r = talloc(call->mem_ctx, call->conn->iface->ndr->calls[opnum].struct_size);
580         if (!r) {
581                 return NT_STATUS_NO_MEMORY;
582         }
583
584         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
585                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
586         }
587
588         /* unravel the NDR for the packet */
589         status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
590         if (!NT_STATUS_IS_OK(status)) {
591                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
592         }
593
594         call->fault_code = 0;
595
596         /* call the dispatch function */
597         status = call->conn->iface->dispatch(call, call->mem_ctx, r);
598         if (!NT_STATUS_IS_OK(status)) {
599                 return dcesrv_fault(call, call->fault_code);
600         }
601
602         /* form the reply NDR */
603         push = ndr_push_init_ctx(call->mem_ctx);
604         if (!push) {
605                 return NT_STATUS_NO_MEMORY;
606         }
607
608         if (lp_rpc_big_endian()) {
609                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
610         }
611
612         status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
613         if (!NT_STATUS_IS_OK(status)) {
614                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
615         }
616
617         stub = ndr_push_blob(push);
618
619         total_length = stub.length;
620
621         do {
622                 uint32_t length;
623                 struct dcesrv_call_reply *rep;
624                 struct dcerpc_packet pkt;
625
626                 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
627                 if (!rep) {
628                         return NT_STATUS_NO_MEMORY;
629                 }
630
631                 length = stub.length;
632                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
633                         /* the 32 is to cope with signing data */
634                         length = call->conn->cli_max_recv_frag - 
635                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
636                 }
637
638                 /* form the dcerpc response packet */
639                 dcesrv_init_hdr(&pkt);
640                 pkt.auth_length = 0;
641                 pkt.call_id = call->pkt.call_id;
642                 pkt.ptype = DCERPC_PKT_RESPONSE;
643                 pkt.pfc_flags = 0;
644                 if (stub.length == total_length) {
645                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
646                 }
647                 if (length == stub.length) {
648                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
649                 }
650                 pkt.u.response.alloc_hint = stub.length;
651                 pkt.u.response.context_id = call->pkt.u.request.context_id;
652                 pkt.u.response.cancel_count = 0;
653                 pkt.u.response.stub_and_verifier.data = stub.data;
654                 pkt.u.response.stub_and_verifier.length = length;
655
656                 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
657                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
658                 }
659
660                 dcerpc_set_frag_length(&rep->data, rep->data.length);
661
662                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
663                 
664                 stub.data += length;
665                 stub.length -= length;
666         } while (stub.length != 0);
667
668         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
669
670         return NT_STATUS_OK;
671 }
672
673
674 /*
675   work out if we have a full packet yet
676 */
677 static BOOL dce_full_packet(const DATA_BLOB *data)
678 {
679         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
680                 return False;
681         }
682         if (dcerpc_get_frag_length(data) > data->length) {
683                 return False;
684         }
685         return True;
686 }
687
688 /*
689   we might have consumed only part of our input - advance past that part
690 */
691 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
692 {
693         DATA_BLOB blob;
694
695         if (dce_conn->partial_input.length == offset) {
696                 data_blob_free(&dce_conn->partial_input);
697                 return;
698         }
699
700         blob = dce_conn->partial_input;
701         dce_conn->partial_input = data_blob(blob.data + offset,
702                                             blob.length - offset);
703         data_blob_free(&blob);
704 }
705
706 /*
707   process some input to a dcerpc endpoint server.
708 */
709 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
710 {
711         struct ndr_pull *ndr;
712         TALLOC_CTX *mem_ctx;
713         NTSTATUS status;
714         struct dcesrv_call_state *call;
715         DATA_BLOB blob;
716
717         mem_ctx = talloc_init("dcesrv_input");
718         if (!mem_ctx) {
719                 return NT_STATUS_NO_MEMORY;
720         }
721         call = talloc_p(mem_ctx, struct dcesrv_call_state);
722         if (!call) {
723                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
724                 talloc_destroy(mem_ctx);
725                 return NT_STATUS_NO_MEMORY;
726         }
727         call->mem_ctx = mem_ctx;
728         call->conn = dce_conn;
729         call->replies = NULL;
730
731         blob = dce_conn->partial_input;
732         blob.length = dcerpc_get_frag_length(&blob);
733
734         ndr = ndr_pull_init_blob(&blob, mem_ctx);
735         if (!ndr) {
736                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
737                 talloc_destroy(mem_ctx);
738                 return NT_STATUS_NO_MEMORY;
739         }
740
741         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
742                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
743         }
744
745         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
746         if (!NT_STATUS_IS_OK(status)) {
747                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
748                 talloc_destroy(mem_ctx);
749                 return status;
750         }
751
752         dce_partial_advance(dce_conn, blob.length);
753
754         /* we have to check the signing here, before combining the
755            pdus */
756         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
757             !dcesrv_auth_request(call)) {
758                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
759         }
760
761         /* see if this is a continued packet */
762         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
763                 struct dcesrv_call_state *call2 = call;
764                 uint32_t alloc_size;
765
766                 /* we only allow fragmented requests, no other packet types */
767                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
768                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
769                 }
770
771                 /* this is a continuation of an existing call - find the call then
772                    tack it on the end */
773                 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
774                 if (!call) {
775                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
776                 }
777
778                 if (call->pkt.ptype != call2->pkt.ptype) {
779                         /* trying to play silly buggers are we? */
780                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
781                 }
782
783                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
784                         call2->pkt.u.request.stub_and_verifier.length;
785                 if (call->pkt.u.request.alloc_hint > alloc_size) {
786                         alloc_size = call->pkt.u.request.alloc_hint;
787                 }
788
789                 call->pkt.u.request.stub_and_verifier.data = 
790                         talloc_realloc(call->mem_ctx,
791                                        call->pkt.u.request.stub_and_verifier.data, alloc_size);
792                 if (!call->pkt.u.request.stub_and_verifier.data) {
793                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
794                 }
795                 memcpy(call->pkt.u.request.stub_and_verifier.data +
796                        call->pkt.u.request.stub_and_verifier.length,
797                        call2->pkt.u.request.stub_and_verifier.data,
798                        call2->pkt.u.request.stub_and_verifier.length);
799                 call->pkt.u.request.stub_and_verifier.length += 
800                         call2->pkt.u.request.stub_and_verifier.length;
801
802                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
803         }
804
805         /* this may not be the last pdu in the chain - if its isn't then
806            just put it on the call_list and wait for the rest */
807         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
808                 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
809                 return NT_STATUS_OK;
810         }
811
812         switch (call->pkt.ptype) {
813         case DCERPC_PKT_BIND:
814                 status = dcesrv_bind(call);
815                 break;
816         case DCERPC_PKT_AUTH3:
817                 status = dcesrv_auth3(call);
818                 break;
819         case DCERPC_PKT_REQUEST:
820                 status = dcesrv_request(call);
821                 break;
822         default:
823                 status = NT_STATUS_INVALID_PARAMETER;
824                 break;
825         }
826
827         /* if we are going to be sending a reply then add
828            it to the list of pending calls. We add it to the end to keep the call
829            list in the order we will answer */
830         if (!NT_STATUS_IS_OK(status)) {
831                 talloc_destroy(mem_ctx);
832         }
833
834         return status;
835 }
836
837
838 /*
839   provide some input to a dcerpc endpoint server. This passes data
840   from a dcerpc client into the server
841 */
842 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
843 {
844         NTSTATUS status;
845
846         /* handle the very common case that the input contains a full packet and there
847            is no partial packet pending. In this case we can avoid a copy of the
848            data */
849         if (dce_conn->partial_input.length == 0) {
850                 dce_conn->partial_input = *data;
851                 /* make sure that dce_partial_advance doesn't free this data */
852                 dce_conn->partial_input.free = NULL;
853                 while (dce_full_packet(&dce_conn->partial_input)) {
854                         status = dcesrv_input_process(dce_conn);
855                         if (!NT_STATUS_IS_OK(status)) {
856                                 return status;
857                         }
858                 }
859                 if (dce_conn->partial_input.length) {
860                         /* there was some data left over. We have to copy this
861                            as the caller may free the data */
862                         dce_conn->partial_input = 
863                                 data_blob(dce_conn->partial_input.data,
864                                           dce_conn->partial_input.length);
865                         if (!dce_conn->partial_input.data) {
866                                 return NT_STATUS_NO_MEMORY;
867                         }
868                 }
869                 return NT_STATUS_OK;
870         }
871
872         dce_conn->partial_input.data = Realloc(dce_conn->partial_input.data,
873                                           dce_conn->partial_input.length + data->length);
874         if (!dce_conn->partial_input.data) {
875                 return NT_STATUS_NO_MEMORY;
876         }
877         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
878                data->data, data->length);
879         dce_conn->partial_input.length += data->length;
880
881         while (dce_full_packet(&dce_conn->partial_input)) {
882                 status = dcesrv_input_process(dce_conn);
883                 if (!NT_STATUS_IS_OK(status)) {
884                         return status;
885                 }
886         }
887
888         return NT_STATUS_OK;
889 }
890
891 /*
892   retrieve some output from a dcerpc server
893   The caller supplies a function that will be called to do the
894   actual output. 
895
896   The first argument to write_fn() will be 'private', the second will
897   be a pointer to a buffer containing the data to be sent and the 3rd
898   will be the number of bytes to be sent.
899
900   write_fn() should return the number of bytes successfully written.
901 */
902 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
903                        void *private,
904                        ssize_t (*write_fn)(void *, const void *, size_t))
905 {
906         struct dcesrv_call_state *call;
907         struct dcesrv_call_reply *rep;
908         ssize_t nwritten;
909
910         call = dce_conn->call_list;
911         if (!call || !call->replies) {
912                 return NT_STATUS_FOOBAR;
913         }
914         rep = call->replies;
915
916         nwritten = write_fn(private, rep->data.data, rep->data.length);
917         if (nwritten == -1) {
918                 /* TODO: hmm, how do we cope with this? destroy the
919                    connection perhaps? */
920                 return NT_STATUS_UNSUCCESSFUL;
921         }
922
923         rep->data.length -= nwritten;
924         rep->data.data += nwritten;
925
926         if (rep->data.length == 0) {
927                 /* we're done with this section of the call */
928                 DLIST_REMOVE(call->replies, rep);
929         }
930
931         if (call->replies == NULL) {
932                 /* we're done with the whole call */
933                 DLIST_REMOVE(dce_conn->call_list, call);
934                 talloc_destroy(call->mem_ctx);
935         }
936
937         return NT_STATUS_OK;
938 }
939
940
941 /*
942   write_fn() for dcesrv_output_blob()
943 */
944 static ssize_t dcesrv_output_blob_write_fn(void *private, const void *buf, size_t count)
945 {
946         DATA_BLOB *blob = private;
947         if (count < blob->length) {
948                 blob->length = count;
949         }
950         memcpy(blob->data, buf, blob->length);
951         return blob->length;
952 }
953
954 /*
955   a simple wrapper for dcesrv_output() for when we want to output
956   into a data blob
957 */
958 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn, 
959                             DATA_BLOB *blob)
960 {
961         return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
962 }
963
964 /*
965   initialise the dcerpc server context
966 */
967 NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
968 {
969         int i;
970         const char **endpoint_servers = lp_dcerpc_endpoint_servers();
971
972         dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
973         if (!dce_ctx->mem_ctx) {
974                 DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
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 /* the list of currently registered DCERPC endpoint servers.
1006  */
1007 static struct {
1008         struct dcesrv_endpoint_server *ep_server;
1009 } *ep_servers = NULL;
1010 static int num_ep_servers;
1011
1012 /*
1013   register a DCERPC endpoint server. 
1014
1015   The 'name' can be later used by other backends to find the operations
1016   structure for this backend.  
1017
1018   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1019 */
1020 static NTSTATUS decrpc_register_ep_server(void *_ep_server)
1021 {
1022         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1023         
1024         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1025                 /* its already registered! */
1026                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1027                          ep_server->name));
1028                 return NT_STATUS_OBJECT_NAME_COLLISION;
1029         }
1030
1031         ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1032         if (!ep_servers) {
1033                 smb_panic("out of memory in decrpc_register");
1034         }
1035
1036         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1037         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1038
1039         num_ep_servers++;
1040
1041         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1042                  ep_server->name));
1043
1044         return NT_STATUS_OK;
1045 }
1046
1047 /*
1048   return the operations structure for a named backend of the specified type
1049 */
1050 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1051 {
1052         int i;
1053
1054         for (i=0;i<num_ep_servers;i++) {
1055                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1056                         return ep_servers[i].ep_server;
1057                 }
1058         }
1059
1060         return NULL;
1061 }
1062
1063 /*
1064   return the DCERPC module version, and the size of some critical types
1065   This can be used by endpoint server modules to either detect compilation errors, or provide
1066   multiple implementations for different smbd compilation options in one module
1067 */
1068 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1069 {
1070         static const struct dcesrv_critical_sizes critical_sizes = {
1071                 DCERPC_MODULE_VERSION,
1072                 sizeof(struct dcesrv_context),
1073                 sizeof(struct dcesrv_endpoint),
1074                 sizeof(struct dcesrv_endpoint_server),
1075                 sizeof(struct dcesrv_ep_description),
1076                 sizeof(struct dcesrv_interface),
1077                 sizeof(struct dcesrv_if_list),
1078                 sizeof(struct dcesrv_connection),
1079                 sizeof(struct dcesrv_call_state),
1080                 sizeof(struct dcesrv_auth),
1081                 sizeof(struct dcesrv_handle)
1082         };
1083
1084         return &critical_sizes;
1085 }
1086
1087 /*
1088   initialise the DCERPC subsystem
1089 */
1090 BOOL dcesrv_init(void)
1091 {
1092         NTSTATUS status;
1093
1094         status = register_subsystem("dcerpc", decrpc_register_ep_server); 
1095         if (!NT_STATUS_IS_OK(status)) {
1096                 return False;
1097         }
1098
1099         /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1100         static_init_dcerpc;
1101
1102         DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1103         return True;
1104 }