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