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