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