r1165: fixed handling of SMBtrans replies that should return STATUS_BUFFER_OVERFLOW...
[abartlet/samba.git/.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 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.auth_info = NULL;
272         (*p)->auth_state.crypto_ctx.private_data = NULL;
273         (*p)->auth_state.crypto_ctx.ops = NULL;
274         (*p)->auth_state.session_info = NULL;
275
276         return NT_STATUS_OK;
277 }
278
279 /*
280   search and connect to a dcerpc endpoint
281 */
282 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
283                                         const struct dcesrv_ep_description *ep_description,
284                                         struct auth_session_info *session_info,
285                                         struct dcesrv_connection **dce_conn_p)
286 {
287         NTSTATUS status;
288         const struct dcesrv_endpoint *ep;
289
290         /* make sure this endpoint exists */
291         ep = find_endpoint(dce_ctx, ep_description);
292         if (!ep) {
293                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
294         }
295
296         status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
297         if (!NT_STATUS_IS_OK(status)) {
298                 return status;
299         }
300
301         (*dce_conn_p)->auth_state.session_info = session_info;
302
303         /* TODO: check security descriptor of the endpoint here 
304          *       if it's a smb named pipe
305          *       if it's failed free dce_conn_p
306          */
307
308         return NT_STATUS_OK;
309 }
310
311
312 /*
313   disconnect a link to an endpoint
314 */
315 void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
316 {
317         if (p->iface) {
318                 p->iface->unbind(p, p->iface);
319         }
320
321         /* destroy any handles */
322         while (p->handles) {
323                 dcesrv_handle_destroy(p, p->handles);
324         }
325
326         if (p->auth_state.crypto_ctx.ops) {
327                 p->auth_state.crypto_ctx.ops->end(&p->auth_state);
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                 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN, 
592                                   &call->pkt.u.request.stub_and_verifier);
593                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
594         }
595
596         call->fault_code = 0;
597
598         /* call the dispatch function */
599         status = call->conn->iface->dispatch(call, call->mem_ctx, r);
600         if (!NT_STATUS_IS_OK(status)) {
601                 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN, 
602                                   &call->pkt.u.request.stub_and_verifier);
603                 return dcesrv_fault(call, call->fault_code);
604         }
605
606         /* form the reply NDR */
607         push = ndr_push_init_ctx(call->mem_ctx);
608         if (!push) {
609                 return NT_STATUS_NO_MEMORY;
610         }
611
612         if (lp_rpc_big_endian()) {
613                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
614         }
615
616         status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
617         if (!NT_STATUS_IS_OK(status)) {
618                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
619         }
620
621         stub = ndr_push_blob(push);
622
623         total_length = stub.length;
624
625         do {
626                 uint32_t length;
627                 struct dcesrv_call_reply *rep;
628                 struct dcerpc_packet pkt;
629
630                 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
631                 if (!rep) {
632                         return NT_STATUS_NO_MEMORY;
633                 }
634
635                 length = stub.length;
636                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
637                         /* the 32 is to cope with signing data */
638                         length = call->conn->cli_max_recv_frag - 
639                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
640                 }
641
642                 /* form the dcerpc response packet */
643                 dcesrv_init_hdr(&pkt);
644                 pkt.auth_length = 0;
645                 pkt.call_id = call->pkt.call_id;
646                 pkt.ptype = DCERPC_PKT_RESPONSE;
647                 pkt.pfc_flags = 0;
648                 if (stub.length == total_length) {
649                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
650                 }
651                 if (length == stub.length) {
652                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
653                 }
654                 pkt.u.response.alloc_hint = stub.length;
655                 pkt.u.response.context_id = call->pkt.u.request.context_id;
656                 pkt.u.response.cancel_count = 0;
657                 pkt.u.response.stub_and_verifier.data = stub.data;
658                 pkt.u.response.stub_and_verifier.length = length;
659
660                 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
661                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
662                 }
663
664                 dcerpc_set_frag_length(&rep->data, rep->data.length);
665
666                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
667                 
668                 stub.data += length;
669                 stub.length -= length;
670         } while (stub.length != 0);
671
672         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
673
674         return NT_STATUS_OK;
675 }
676
677
678 /*
679   work out if we have a full packet yet
680 */
681 static BOOL dce_full_packet(const DATA_BLOB *data)
682 {
683         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
684                 return False;
685         }
686         if (dcerpc_get_frag_length(data) > data->length) {
687                 return False;
688         }
689         return True;
690 }
691
692 /*
693   we might have consumed only part of our input - advance past that part
694 */
695 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
696 {
697         DATA_BLOB blob;
698
699         if (dce_conn->partial_input.length == offset) {
700                 data_blob_free(&dce_conn->partial_input);
701                 return;
702         }
703
704         blob = dce_conn->partial_input;
705         dce_conn->partial_input = data_blob(blob.data + offset,
706                                             blob.length - offset);
707         data_blob_free(&blob);
708 }
709
710 /*
711   process some input to a dcerpc endpoint server.
712 */
713 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
714 {
715         struct ndr_pull *ndr;
716         TALLOC_CTX *mem_ctx;
717         NTSTATUS status;
718         struct dcesrv_call_state *call;
719         DATA_BLOB blob;
720
721         mem_ctx = talloc_init("dcesrv_input");
722         if (!mem_ctx) {
723                 return NT_STATUS_NO_MEMORY;
724         }
725         call = talloc_p(mem_ctx, struct dcesrv_call_state);
726         if (!call) {
727                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
728                 talloc_destroy(mem_ctx);
729                 return NT_STATUS_NO_MEMORY;
730         }
731         call->mem_ctx = mem_ctx;
732         call->conn = dce_conn;
733         call->replies = NULL;
734
735         blob = dce_conn->partial_input;
736         blob.length = dcerpc_get_frag_length(&blob);
737
738         ndr = ndr_pull_init_blob(&blob, mem_ctx);
739         if (!ndr) {
740                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
741                 talloc_destroy(mem_ctx);
742                 return NT_STATUS_NO_MEMORY;
743         }
744
745         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
746                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
747         }
748
749         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
750         if (!NT_STATUS_IS_OK(status)) {
751                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
752                 talloc_destroy(mem_ctx);
753                 return status;
754         }
755
756         dce_partial_advance(dce_conn, blob.length);
757
758         /* we have to check the signing here, before combining the
759            pdus */
760         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
761             !dcesrv_auth_request(call)) {
762                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
763         }
764
765         /* see if this is a continued packet */
766         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
767                 struct dcesrv_call_state *call2 = call;
768                 uint32_t alloc_size;
769
770                 /* we only allow fragmented requests, no other packet types */
771                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
772                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
773                 }
774
775                 /* this is a continuation of an existing call - find the call then
776                    tack it on the end */
777                 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
778                 if (!call) {
779                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
780                 }
781
782                 if (call->pkt.ptype != call2->pkt.ptype) {
783                         /* trying to play silly buggers are we? */
784                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
785                 }
786
787                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
788                         call2->pkt.u.request.stub_and_verifier.length;
789                 if (call->pkt.u.request.alloc_hint > alloc_size) {
790                         alloc_size = call->pkt.u.request.alloc_hint;
791                 }
792
793                 call->pkt.u.request.stub_and_verifier.data = 
794                         talloc_realloc(call->mem_ctx,
795                                        call->pkt.u.request.stub_and_verifier.data, alloc_size);
796                 if (!call->pkt.u.request.stub_and_verifier.data) {
797                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
798                 }
799                 memcpy(call->pkt.u.request.stub_and_verifier.data +
800                        call->pkt.u.request.stub_and_verifier.length,
801                        call2->pkt.u.request.stub_and_verifier.data,
802                        call2->pkt.u.request.stub_and_verifier.length);
803                 call->pkt.u.request.stub_and_verifier.length += 
804                         call2->pkt.u.request.stub_and_verifier.length;
805
806                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
807         }
808
809         /* this may not be the last pdu in the chain - if its isn't then
810            just put it on the call_list and wait for the rest */
811         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
812                 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
813                 return NT_STATUS_OK;
814         }
815
816         switch (call->pkt.ptype) {
817         case DCERPC_PKT_BIND:
818                 status = dcesrv_bind(call);
819                 break;
820         case DCERPC_PKT_AUTH3:
821                 status = dcesrv_auth3(call);
822                 break;
823         case DCERPC_PKT_REQUEST:
824                 status = dcesrv_request(call);
825                 break;
826         default:
827                 status = NT_STATUS_INVALID_PARAMETER;
828                 break;
829         }
830
831         /* if we are going to be sending a reply then add
832            it to the list of pending calls. We add it to the end to keep the call
833            list in the order we will answer */
834         if (!NT_STATUS_IS_OK(status)) {
835                 talloc_destroy(mem_ctx);
836         }
837
838         return status;
839 }
840
841
842 /*
843   provide some input to a dcerpc endpoint server. This passes data
844   from a dcerpc client into the server
845 */
846 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
847 {
848         NTSTATUS status;
849
850         /* handle the very common case that the input contains a full packet and there
851            is no partial packet pending. In this case we can avoid a copy of the
852            data */
853         if (dce_conn->partial_input.length == 0) {
854                 dce_conn->partial_input = *data;
855                 /* make sure that dce_partial_advance doesn't free this data */
856                 dce_conn->partial_input.free = NULL;
857                 while (dce_full_packet(&dce_conn->partial_input)) {
858                         status = dcesrv_input_process(dce_conn);
859                         if (!NT_STATUS_IS_OK(status)) {
860                                 return status;
861                         }
862                 }
863                 if (dce_conn->partial_input.length) {
864                         /* there was some data left over. We have to copy this
865                            as the caller may free the data */
866                         dce_conn->partial_input = 
867                                 data_blob(dce_conn->partial_input.data,
868                                           dce_conn->partial_input.length);
869                         if (!dce_conn->partial_input.data) {
870                                 return NT_STATUS_NO_MEMORY;
871                         }
872                 }
873                 return NT_STATUS_OK;
874         }
875
876         dce_conn->partial_input.data = Realloc(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 *, const void *, size_t))
912 {
913         struct dcesrv_call_state *call;
914         struct dcesrv_call_reply *rep;
915         ssize_t nwritten;
916         NTSTATUS status = NT_STATUS_OK;
917
918         call = dce_conn->call_list;
919         if (!call || !call->replies) {
920                 return NT_STATUS_FOOBAR;
921         }
922         rep = call->replies;
923
924         nwritten = write_fn(private, rep->data.data, rep->data.length);
925         if (nwritten == -1) {
926                 /* TODO: hmm, how do we cope with this? destroy the
927                    connection perhaps? */
928                 return NT_STATUS_UNSUCCESSFUL;
929         }
930
931         rep->data.length -= nwritten;
932         rep->data.data += nwritten;
933
934         if (rep->data.length == 0) {
935                 /* we're done with this section of the call */
936                 DLIST_REMOVE(call->replies, rep);
937         } else {
938                 status = STATUS_BUFFER_OVERFLOW;
939         }
940
941         if (call->replies == NULL) {
942                 /* we're done with the whole call */
943                 DLIST_REMOVE(dce_conn->call_list, call);
944                 talloc_destroy(call->mem_ctx);
945         }
946
947         return status;
948 }
949
950
951 /*
952   write_fn() for dcesrv_output_blob()
953 */
954 static ssize_t dcesrv_output_blob_write_fn(void *private, const void *buf, size_t count)
955 {
956         DATA_BLOB *blob = private;
957         if (count < blob->length) {
958                 blob->length = count;
959         }
960         memcpy(blob->data, buf, blob->length);
961         return blob->length;
962 }
963
964 /*
965   a simple wrapper for dcesrv_output() for when we want to output
966   into a data blob
967 */
968 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn, 
969                             DATA_BLOB *blob)
970 {
971         return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
972 }
973
974 /*
975   initialise the dcerpc server context
976 */
977 NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
978 {
979         int i;
980         const char **endpoint_servers = lp_dcerpc_endpoint_servers();
981
982         dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
983         if (!dce_ctx->mem_ctx) {
984                 DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
985                 return NT_STATUS_NO_MEMORY;
986         }
987
988         dce_ctx->endpoint_list = NULL;
989
990         if (!endpoint_servers) {
991                 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
992                 return NT_STATUS_OK;
993         }
994
995         for (i=0;endpoint_servers[i];i++) {
996                 NTSTATUS ret;
997                 const struct dcesrv_endpoint_server *ep_server;
998                 
999                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1000                 if (!ep_server) {
1001                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1002                         return NT_STATUS_UNSUCCESSFUL;
1003                 }
1004
1005                 ret = ep_server->init_server(dce_ctx, ep_server);
1006                 if (!NT_STATUS_IS_OK(ret)) {
1007                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1008                         return ret;
1009                 }
1010         }
1011
1012         return NT_STATUS_OK;
1013 }
1014
1015 /* the list of currently registered DCERPC endpoint servers.
1016  */
1017 static struct {
1018         struct dcesrv_endpoint_server *ep_server;
1019 } *ep_servers = NULL;
1020 static int num_ep_servers;
1021
1022 /*
1023   register a DCERPC endpoint server. 
1024
1025   The 'name' can be later used by other backends to find the operations
1026   structure for this backend.  
1027
1028   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1029 */
1030 static NTSTATUS decrpc_register_ep_server(void *_ep_server)
1031 {
1032         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1033         
1034         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1035                 /* its already registered! */
1036                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1037                          ep_server->name));
1038                 return NT_STATUS_OBJECT_NAME_COLLISION;
1039         }
1040
1041         ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1042         if (!ep_servers) {
1043                 smb_panic("out of memory in decrpc_register");
1044         }
1045
1046         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1047         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1048
1049         num_ep_servers++;
1050
1051         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1052                  ep_server->name));
1053
1054         return NT_STATUS_OK;
1055 }
1056
1057 /*
1058   return the operations structure for a named backend of the specified type
1059 */
1060 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1061 {
1062         int i;
1063
1064         for (i=0;i<num_ep_servers;i++) {
1065                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1066                         return ep_servers[i].ep_server;
1067                 }
1068         }
1069
1070         return NULL;
1071 }
1072
1073 /*
1074   return the DCERPC module version, and the size of some critical types
1075   This can be used by endpoint server modules to either detect compilation errors, or provide
1076   multiple implementations for different smbd compilation options in one module
1077 */
1078 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1079 {
1080         static const struct dcesrv_critical_sizes critical_sizes = {
1081                 DCERPC_MODULE_VERSION,
1082                 sizeof(struct dcesrv_context),
1083                 sizeof(struct dcesrv_endpoint),
1084                 sizeof(struct dcesrv_endpoint_server),
1085                 sizeof(struct dcesrv_ep_description),
1086                 sizeof(struct dcesrv_interface),
1087                 sizeof(struct dcesrv_if_list),
1088                 sizeof(struct dcesrv_connection),
1089                 sizeof(struct dcesrv_call_state),
1090                 sizeof(struct dcesrv_auth),
1091                 sizeof(struct dcesrv_handle)
1092         };
1093
1094         return &critical_sizes;
1095 }
1096
1097 /*
1098   initialise the DCERPC subsystem
1099 */
1100 BOOL dcesrv_init(void)
1101 {
1102         NTSTATUS status;
1103
1104         status = register_subsystem("dcerpc", decrpc_register_ep_server); 
1105         if (!NT_STATUS_IS_OK(status)) {
1106                 return False;
1107         }
1108
1109         /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1110         static_init_dcerpc;
1111
1112         DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1113         return True;
1114 }