r1294: A nice, large, commit...
[samba.git] / source4 / rpc_server / dcerpc_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc core code
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Stefan (metze) Metzmacher 2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 /*
27   see if two endpoints match
28 */
29 static BOOL endpoints_match(const struct 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.gensec_security = NULL;
273         (*p)->auth_state.session_info = NULL;
274
275         return NT_STATUS_OK;
276 }
277
278 /*
279   search and connect to a dcerpc endpoint
280 */
281 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
282                                         const struct dcesrv_ep_description *ep_description,
283                                         struct auth_session_info *session_info,
284                                         struct dcesrv_connection **dce_conn_p)
285 {
286         NTSTATUS status;
287         const struct dcesrv_endpoint *ep;
288
289         /* make sure this endpoint exists */
290         ep = find_endpoint(dce_ctx, ep_description);
291         if (!ep) {
292                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
293         }
294
295         status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
296         if (!NT_STATUS_IS_OK(status)) {
297                 return status;
298         }
299
300         session_info->refcount++;
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.gensec_security) {
327                 gensec_end(&p->auth_state.gensec_security);
328         }
329
330         if (p->auth_state.session_info) {
331                 free_session_info(&p->auth_state.session_info);
332         }
333
334         talloc_destroy(p->mem_ctx);
335 }
336
337 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
338 {
339         pkt->rpc_vers = 5;
340         pkt->rpc_vers_minor = 0;
341         if (lp_rpc_big_endian()) {
342                 pkt->drep[0] = 0;
343         } else {
344                 pkt->drep[0] = DCERPC_DREP_LE;
345         }
346         pkt->drep[1] = 0;
347         pkt->drep[2] = 0;
348         pkt->drep[3] = 0;
349 }
350
351 /*
352   return a dcerpc fault
353 */
354 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
355 {
356         struct dcerpc_packet pkt;
357         struct dcesrv_call_reply *rep;
358         NTSTATUS status;
359
360         /* setup a bind_ack */
361         dcesrv_init_hdr(&pkt);
362         pkt.auth_length = 0;
363         pkt.call_id = call->pkt.call_id;
364         pkt.ptype = DCERPC_PKT_FAULT;
365         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
366         pkt.u.fault.alloc_hint = 0;
367         pkt.u.fault.context_id = 0;
368         pkt.u.fault.cancel_count = 0;
369         pkt.u.fault.status = fault_code;
370
371         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
372         if (!rep) {
373                 return NT_STATUS_NO_MEMORY;
374         }
375
376         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
377         if (!NT_STATUS_IS_OK(status)) {
378                 return status;
379         }
380
381         dcerpc_set_frag_length(&rep->data, rep->data.length);
382
383         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
384         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
385
386         return NT_STATUS_OK;    
387 }
388
389
390 /*
391   return a dcerpc bind_nak
392 */
393 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
394 {
395         struct dcerpc_packet pkt;
396         struct dcesrv_call_reply *rep;
397         NTSTATUS status;
398
399         /* setup a bind_nak */
400         dcesrv_init_hdr(&pkt);
401         pkt.auth_length = 0;
402         pkt.call_id = call->pkt.call_id;
403         pkt.ptype = DCERPC_PKT_BIND_NAK;
404         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
405         pkt.u.bind_nak.reject_reason = reason;
406         pkt.u.bind_nak.num_versions = 0;
407
408         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
409         if (!rep) {
410                 return NT_STATUS_NO_MEMORY;
411         }
412
413         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
414         if (!NT_STATUS_IS_OK(status)) {
415                 return status;
416         }
417
418         dcerpc_set_frag_length(&rep->data, rep->data.length);
419
420         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
421         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
422
423         return NT_STATUS_OK;    
424 }
425
426
427 /*
428   handle a bind request
429 */
430 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
431 {
432         const char *uuid, *transfer_syntax;
433         uint32_t if_version, transfer_syntax_version;
434         struct dcerpc_packet pkt;
435         struct dcesrv_call_reply *rep;
436         NTSTATUS status;
437         uint32_t result=0, reason=0;
438
439         if (call->pkt.u.bind.num_contexts != 1 ||
440             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
441                 return dcesrv_bind_nak(call, 0);
442         }
443
444         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
445         uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
446         if (!uuid) {
447                 return dcesrv_bind_nak(call, 0);
448         }
449
450         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
451         transfer_syntax = GUID_string(call->mem_ctx, 
452                                       &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
453         if (!transfer_syntax ||
454             strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
455             NDR_GUID_VERSION != transfer_syntax_version) {
456                 /* we only do NDR encoded dcerpc */
457                 return dcesrv_bind_nak(call, 0);
458         }
459
460         call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
461         if (!call->conn->iface) {
462                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
463                 /* we don't know about that interface */
464                 result = DCERPC_BIND_PROVIDER_REJECT;
465                 reason = DCERPC_BIND_REASON_ASYNTAX;            
466         }
467
468         if (call->conn->cli_max_recv_frag == 0) {
469                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
470         }
471
472         /* handle any authentication that is being requested */
473         if (!dcesrv_auth_bind(call)) {
474                 /* TODO: work out the right reject code */
475                 return dcesrv_bind_nak(call, 0);
476         }
477
478         /* setup a bind_ack */
479         dcesrv_init_hdr(&pkt);
480         pkt.auth_length = 0;
481         pkt.call_id = call->pkt.call_id;
482         pkt.ptype = DCERPC_PKT_BIND_ACK;
483         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
484         pkt.u.bind_ack.max_xmit_frag = 0x2000;
485         pkt.u.bind_ack.max_recv_frag = 0x2000;
486         pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
487         if (call->conn->iface && call->conn->iface->ndr) {
488                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s", 
489                                                                    call->conn->iface->ndr->name);
490         } else {
491                 pkt.u.bind_ack.secondary_address = "";
492         }
493         pkt.u.bind_ack.num_results = 1;
494         pkt.u.bind_ack.ctx_list = talloc_p(call->mem_ctx, struct dcerpc_ack_ctx);
495         if (!pkt.u.bind_ack.ctx_list) {
496                 return NT_STATUS_NO_MEMORY;
497         }
498         pkt.u.bind_ack.ctx_list[0].result = result;
499         pkt.u.bind_ack.ctx_list[0].reason = reason;
500         GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
501         pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
502         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
503
504         if (!dcesrv_auth_bind_ack(call, &pkt)) {
505                 return dcesrv_bind_nak(call, 0);
506         }
507
508         if (call->conn->iface) {
509                 status = call->conn->iface->bind(call, call->conn->iface);
510                 if (!NT_STATUS_IS_OK(status)) {
511                         DEBUG(2,("Request for dcerpc interface %s/%d rejected\n", uuid, if_version));
512                         return status;
513                 }
514         }
515
516         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
517         if (!rep) {
518                 return NT_STATUS_NO_MEMORY;
519         }
520
521         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, 
522                                   call->conn->auth_state.auth_info);
523         if (!NT_STATUS_IS_OK(status)) {
524                 return status;
525         }
526
527         dcerpc_set_frag_length(&rep->data, rep->data.length);
528
529         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
530         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
531
532         return NT_STATUS_OK;
533 }
534
535
536 /*
537   handle a auth3 request
538 */
539 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
540 {
541         /* handle the auth3 in the auth code */
542         if (!dcesrv_auth_auth3(call)) {
543                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
544         }
545
546         talloc_destroy(call->mem_ctx);
547
548         /* we don't send a reply to a auth3 request, except by a
549            fault */
550         return NT_STATUS_OK;
551 }
552
553
554 /*
555   handle a dcerpc request packet
556 */
557 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
558 {
559         struct ndr_pull *pull;
560         struct ndr_push *push;
561         uint16_t opnum;
562         void *r;
563         NTSTATUS status;
564         DATA_BLOB stub;
565         uint32_t total_length;
566
567
568         if (!call->conn->iface) {
569                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
570         }
571
572         opnum = call->pkt.u.request.opnum;
573
574         if (opnum >= call->conn->iface->ndr->num_calls) {
575                 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
576         }
577
578         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call->mem_ctx);
579         if (!pull) {
580                 return NT_STATUS_NO_MEMORY;
581         }
582
583         r = talloc(call->mem_ctx, call->conn->iface->ndr->calls[opnum].struct_size);
584         if (!r) {
585                 return NT_STATUS_NO_MEMORY;
586         }
587
588         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
589                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
590         }
591
592         /* unravel the NDR for the packet */
593         status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
594         if (!NT_STATUS_IS_OK(status)) {
595                 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN, 
596                                   &call->pkt.u.request.stub_and_verifier);
597                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
598         }
599
600         call->fault_code = 0;
601
602         /* call the dispatch function */
603         status = call->conn->iface->dispatch(call, call->mem_ctx, r);
604         if (!NT_STATUS_IS_OK(status)) {
605                 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN, 
606                                   &call->pkt.u.request.stub_and_verifier);
607                 return dcesrv_fault(call, call->fault_code);
608         }
609
610         /* form the reply NDR */
611         push = ndr_push_init_ctx(call->mem_ctx);
612         if (!push) {
613                 return NT_STATUS_NO_MEMORY;
614         }
615
616         if (lp_rpc_big_endian()) {
617                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
618         }
619
620         status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
621         if (!NT_STATUS_IS_OK(status)) {
622                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
623         }
624
625         stub = ndr_push_blob(push);
626
627         total_length = stub.length;
628
629         do {
630                 uint32_t length;
631                 struct dcesrv_call_reply *rep;
632                 struct dcerpc_packet pkt;
633
634                 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
635                 if (!rep) {
636                         return NT_STATUS_NO_MEMORY;
637                 }
638
639                 length = stub.length;
640                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
641                         /* the 32 is to cope with signing data */
642                         length = call->conn->cli_max_recv_frag - 
643                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
644                 }
645
646                 /* form the dcerpc response packet */
647                 dcesrv_init_hdr(&pkt);
648                 pkt.auth_length = 0;
649                 pkt.call_id = call->pkt.call_id;
650                 pkt.ptype = DCERPC_PKT_RESPONSE;
651                 pkt.pfc_flags = 0;
652                 if (stub.length == total_length) {
653                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
654                 }
655                 if (length == stub.length) {
656                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
657                 }
658                 pkt.u.response.alloc_hint = stub.length;
659                 pkt.u.response.context_id = call->pkt.u.request.context_id;
660                 pkt.u.response.cancel_count = 0;
661                 pkt.u.response.stub_and_verifier.data = stub.data;
662                 pkt.u.response.stub_and_verifier.length = length;
663
664                 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
665                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
666                 }
667
668                 dcerpc_set_frag_length(&rep->data, rep->data.length);
669
670                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
671                 
672                 stub.data += length;
673                 stub.length -= length;
674         } while (stub.length != 0);
675
676         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
677
678         return NT_STATUS_OK;
679 }
680
681
682 /*
683   work out if we have a full packet yet
684 */
685 static BOOL dce_full_packet(const DATA_BLOB *data)
686 {
687         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
688                 return False;
689         }
690         if (dcerpc_get_frag_length(data) > data->length) {
691                 return False;
692         }
693         return True;
694 }
695
696 /*
697   we might have consumed only part of our input - advance past that part
698 */
699 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
700 {
701         DATA_BLOB blob;
702
703         if (dce_conn->partial_input.length == offset) {
704                 data_blob_free(&dce_conn->partial_input);
705                 return;
706         }
707
708         blob = dce_conn->partial_input;
709         dce_conn->partial_input = data_blob(blob.data + offset,
710                                             blob.length - offset);
711         data_blob_free(&blob);
712 }
713
714 /*
715   process some input to a dcerpc endpoint server.
716 */
717 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
718 {
719         struct ndr_pull *ndr;
720         TALLOC_CTX *mem_ctx;
721         NTSTATUS status;
722         struct dcesrv_call_state *call;
723         DATA_BLOB blob;
724
725         mem_ctx = talloc_init("dcesrv_input");
726         if (!mem_ctx) {
727                 return NT_STATUS_NO_MEMORY;
728         }
729         call = talloc_p(mem_ctx, struct dcesrv_call_state);
730         if (!call) {
731                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
732                 talloc_destroy(mem_ctx);
733                 return NT_STATUS_NO_MEMORY;
734         }
735         call->mem_ctx = mem_ctx;
736         call->conn = dce_conn;
737         call->replies = NULL;
738
739         blob = dce_conn->partial_input;
740         blob.length = dcerpc_get_frag_length(&blob);
741
742         ndr = ndr_pull_init_blob(&blob, mem_ctx);
743         if (!ndr) {
744                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
745                 talloc_destroy(mem_ctx);
746                 return NT_STATUS_NO_MEMORY;
747         }
748
749         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
750                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
751         }
752
753         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
754         if (!NT_STATUS_IS_OK(status)) {
755                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
756                 talloc_destroy(mem_ctx);
757                 return status;
758         }
759
760         dce_partial_advance(dce_conn, blob.length);
761
762         /* we have to check the signing here, before combining the
763            pdus */
764         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
765             !dcesrv_auth_request(call)) {
766                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
767         }
768
769         /* see if this is a continued packet */
770         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
771                 struct dcesrv_call_state *call2 = call;
772                 uint32_t alloc_size;
773
774                 /* we only allow fragmented requests, no other packet types */
775                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
776                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
777                 }
778
779                 /* this is a continuation of an existing call - find the call then
780                    tack it on the end */
781                 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
782                 if (!call) {
783                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
784                 }
785
786                 if (call->pkt.ptype != call2->pkt.ptype) {
787                         /* trying to play silly buggers are we? */
788                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
789                 }
790
791                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
792                         call2->pkt.u.request.stub_and_verifier.length;
793                 if (call->pkt.u.request.alloc_hint > alloc_size) {
794                         alloc_size = call->pkt.u.request.alloc_hint;
795                 }
796
797                 call->pkt.u.request.stub_and_verifier.data = 
798                         talloc_realloc(call->mem_ctx,
799                                        call->pkt.u.request.stub_and_verifier.data, alloc_size);
800                 if (!call->pkt.u.request.stub_and_verifier.data) {
801                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
802                 }
803                 memcpy(call->pkt.u.request.stub_and_verifier.data +
804                        call->pkt.u.request.stub_and_verifier.length,
805                        call2->pkt.u.request.stub_and_verifier.data,
806                        call2->pkt.u.request.stub_and_verifier.length);
807                 call->pkt.u.request.stub_and_verifier.length += 
808                         call2->pkt.u.request.stub_and_verifier.length;
809
810                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
811         }
812
813         /* this may not be the last pdu in the chain - if its isn't then
814            just put it on the call_list and wait for the rest */
815         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
816                 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
817                 return NT_STATUS_OK;
818         }
819
820         switch (call->pkt.ptype) {
821         case DCERPC_PKT_BIND:
822                 status = dcesrv_bind(call);
823                 break;
824         case DCERPC_PKT_AUTH3:
825                 status = dcesrv_auth3(call);
826                 break;
827         case DCERPC_PKT_REQUEST:
828                 status = dcesrv_request(call);
829                 break;
830         default:
831                 status = NT_STATUS_INVALID_PARAMETER;
832                 break;
833         }
834
835         /* if we are going to be sending a reply then add
836            it to the list of pending calls. We add it to the end to keep the call
837            list in the order we will answer */
838         if (!NT_STATUS_IS_OK(status)) {
839                 talloc_destroy(mem_ctx);
840         }
841
842         return status;
843 }
844
845
846 /*
847   provide some input to a dcerpc endpoint server. This passes data
848   from a dcerpc client into the server
849 */
850 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
851 {
852         NTSTATUS status;
853
854         /* handle the very common case that the input contains a full packet and there
855            is no partial packet pending. In this case we can avoid a copy of the
856            data */
857         if (dce_conn->partial_input.length == 0) {
858                 dce_conn->partial_input = *data;
859                 /* make sure that dce_partial_advance doesn't free this data */
860                 dce_conn->partial_input.free = NULL;
861                 while (dce_full_packet(&dce_conn->partial_input)) {
862                         status = dcesrv_input_process(dce_conn);
863                         if (!NT_STATUS_IS_OK(status)) {
864                                 return status;
865                         }
866                 }
867                 if (dce_conn->partial_input.length) {
868                         /* there was some data left over. We have to copy this
869                            as the caller may free the data */
870                         dce_conn->partial_input = 
871                                 data_blob(dce_conn->partial_input.data,
872                                           dce_conn->partial_input.length);
873                         if (!dce_conn->partial_input.data) {
874                                 return NT_STATUS_NO_MEMORY;
875                         }
876                 }
877                 return NT_STATUS_OK;
878         }
879
880         dce_conn->partial_input.data = Realloc(dce_conn->partial_input.data,
881                                           dce_conn->partial_input.length + data->length);
882         if (!dce_conn->partial_input.data) {
883                 return NT_STATUS_NO_MEMORY;
884         }
885         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
886                data->data, data->length);
887         dce_conn->partial_input.length += data->length;
888
889         while (dce_full_packet(&dce_conn->partial_input)) {
890                 status = dcesrv_input_process(dce_conn);
891                 if (!NT_STATUS_IS_OK(status)) {
892                         return status;
893                 }
894         }
895
896         return NT_STATUS_OK;
897 }
898
899 /*
900   retrieve some output from a dcerpc server
901   The caller supplies a function that will be called to do the
902   actual output. 
903
904   The first argument to write_fn() will be 'private', the second will
905   be a pointer to a buffer containing the data to be sent and the 3rd
906   will be the number of bytes to be sent.
907
908   write_fn() should return the number of bytes successfully written.
909
910   this will return STATUS_BUFFER_OVERFLOW if there is more to be read
911   from the current fragment
912 */
913 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
914                        void *private,
915                        ssize_t (*write_fn)(void *, const void *, size_t))
916 {
917         struct dcesrv_call_state *call;
918         struct dcesrv_call_reply *rep;
919         ssize_t nwritten;
920         NTSTATUS status = NT_STATUS_OK;
921
922         call = dce_conn->call_list;
923         if (!call || !call->replies) {
924                 return NT_STATUS_FOOBAR;
925         }
926         rep = call->replies;
927
928         nwritten = write_fn(private, rep->data.data, rep->data.length);
929         if (nwritten == -1) {
930                 /* TODO: hmm, how do we cope with this? destroy the
931                    connection perhaps? */
932                 return NT_STATUS_UNSUCCESSFUL;
933         }
934
935         rep->data.length -= nwritten;
936         rep->data.data += nwritten;
937
938         if (rep->data.length == 0) {
939                 /* we're done with this section of the call */
940                 DLIST_REMOVE(call->replies, rep);
941         } else {
942                 status = STATUS_BUFFER_OVERFLOW;
943         }
944
945         if (call->replies == NULL) {
946                 /* we're done with the whole call */
947                 DLIST_REMOVE(dce_conn->call_list, call);
948                 talloc_destroy(call->mem_ctx);
949         }
950
951         return status;
952 }
953
954
955 /*
956   write_fn() for dcesrv_output_blob()
957 */
958 static ssize_t dcesrv_output_blob_write_fn(void *private, const void *buf, size_t count)
959 {
960         DATA_BLOB *blob = private;
961         if (count < blob->length) {
962                 blob->length = count;
963         }
964         memcpy(blob->data, buf, blob->length);
965         return blob->length;
966 }
967
968 /*
969   a simple wrapper for dcesrv_output() for when we want to output
970   into a data blob
971 */
972 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn, 
973                             DATA_BLOB *blob)
974 {
975         return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
976 }
977
978 /*
979   initialise the dcerpc server context
980 */
981 NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
982 {
983         int i;
984         const char **endpoint_servers = lp_dcerpc_endpoint_servers();
985
986         dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
987         if (!dce_ctx->mem_ctx) {
988                 DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
989                 return NT_STATUS_NO_MEMORY;
990         }
991
992         dce_ctx->endpoint_list = NULL;
993
994         if (!endpoint_servers) {
995                 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
996                 return NT_STATUS_OK;
997         }
998
999         for (i=0;endpoint_servers[i];i++) {
1000                 NTSTATUS ret;
1001                 const struct dcesrv_endpoint_server *ep_server;
1002                 
1003                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1004                 if (!ep_server) {
1005                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1006                         return NT_STATUS_UNSUCCESSFUL;
1007                 }
1008
1009                 ret = ep_server->init_server(dce_ctx, ep_server);
1010                 if (!NT_STATUS_IS_OK(ret)) {
1011                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1012                         return ret;
1013                 }
1014         }
1015
1016         return NT_STATUS_OK;
1017 }
1018
1019 /* the list of currently registered DCERPC endpoint servers.
1020  */
1021 static struct {
1022         struct dcesrv_endpoint_server *ep_server;
1023 } *ep_servers = NULL;
1024 static int num_ep_servers;
1025
1026 /*
1027   register a DCERPC endpoint server. 
1028
1029   The 'name' can be later used by other backends to find the operations
1030   structure for this backend.  
1031
1032   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1033 */
1034 static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1035 {
1036         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1037         
1038         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1039                 /* its already registered! */
1040                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1041                          ep_server->name));
1042                 return NT_STATUS_OBJECT_NAME_COLLISION;
1043         }
1044
1045         ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1046         if (!ep_servers) {
1047                 smb_panic("out of memory in dcerpc_register");
1048         }
1049
1050         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1051         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1052
1053         num_ep_servers++;
1054
1055         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1056                  ep_server->name));
1057
1058         return NT_STATUS_OK;
1059 }
1060
1061 /*
1062   return the operations structure for a named backend of the specified type
1063 */
1064 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1065 {
1066         int i;
1067
1068         for (i=0;i<num_ep_servers;i++) {
1069                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1070                         return ep_servers[i].ep_server;
1071                 }
1072         }
1073
1074         return NULL;
1075 }
1076
1077 /*
1078   return the DCERPC module version, and the size of some critical types
1079   This can be used by endpoint server modules to either detect compilation errors, or provide
1080   multiple implementations for different smbd compilation options in one module
1081 */
1082 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1083 {
1084         static const struct dcesrv_critical_sizes critical_sizes = {
1085                 DCERPC_MODULE_VERSION,
1086                 sizeof(struct dcesrv_context),
1087                 sizeof(struct dcesrv_endpoint),
1088                 sizeof(struct dcesrv_endpoint_server),
1089                 sizeof(struct dcesrv_ep_description),
1090                 sizeof(struct dcesrv_interface),
1091                 sizeof(struct dcesrv_if_list),
1092                 sizeof(struct dcesrv_connection),
1093                 sizeof(struct dcesrv_call_state),
1094                 sizeof(struct dcesrv_auth),
1095                 sizeof(struct dcesrv_handle)
1096         };
1097
1098         return &critical_sizes;
1099 }
1100
1101 /*
1102   initialise the DCERPC subsystem
1103 */
1104 BOOL dcesrv_init(void)
1105 {
1106         NTSTATUS status;
1107
1108         status = register_subsystem("dcerpc", dcerpc_register_ep_server); 
1109         if (!NT_STATUS_IS_OK(status)) {
1110                 return False;
1111         }
1112
1113         /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1114         static_init_dcerpc;
1115
1116         DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1117         return True;
1118 }