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