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