3afe5f1dc5449c6ac22c36f5b5acebf6f73ce608
[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 = security_descriptor_copy(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(uint8_t, "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   handle a bind request
569 */
570 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
571 {
572         struct dcerpc_packet pkt;
573         struct dcesrv_call_reply *rep;
574         NTSTATUS status;
575         uint32_t result=0, reason=0;
576
577         /* handle any authentication that is being requested */
578         if (!dcesrv_auth_alter(call)) {
579                 /* TODO: work out the right reject code */
580                 return dcesrv_bind_nak(call, 0);
581         }
582
583         /* setup a alter_ack */
584         dcesrv_init_hdr(&pkt);
585         pkt.auth_length = 0;
586         pkt.call_id = call->pkt.call_id;
587         pkt.ptype = DCERPC_PKT_ALTER_ACK;
588         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
589         pkt.u.alter_ack.max_xmit_frag = 0x2000;
590         pkt.u.alter_ack.max_recv_frag = 0x2000;
591         pkt.u.alter_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
592         pkt.u.alter_ack.secondary_address = NULL;
593         pkt.u.alter_ack.num_results = 1;
594         pkt.u.alter_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
595         if (!pkt.u.alter_ack.ctx_list) {
596                 return NT_STATUS_NO_MEMORY;
597         }
598         pkt.u.alter_ack.ctx_list[0].result = result;
599         pkt.u.alter_ack.ctx_list[0].reason = reason;
600         GUID_from_string(NDR_GUID, &pkt.u.alter_ack.ctx_list[0].syntax.uuid);
601         pkt.u.alter_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
602         pkt.u.alter_ack.auth_info = data_blob(NULL, 0);
603
604         if (!dcesrv_auth_alter_ack(call, &pkt)) {
605                 return dcesrv_bind_nak(call, 0);
606         }
607
608         rep = talloc_p(call, struct dcesrv_call_reply);
609         if (!rep) {
610                 return NT_STATUS_NO_MEMORY;
611         }
612
613         status = dcerpc_push_auth(&rep->data, call, &pkt, 
614                                   call->conn->auth_state.auth_info);
615         if (!NT_STATUS_IS_OK(status)) {
616                 return status;
617         }
618
619         dcerpc_set_frag_length(&rep->data, rep->data.length);
620
621         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
622         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
623
624         return NT_STATUS_OK;
625 }
626
627 /*
628   handle a dcerpc request packet
629 */
630 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
631 {
632         struct ndr_pull *pull;
633         struct ndr_push *push;
634         uint16_t opnum;
635         void *r;
636         NTSTATUS status;
637         DATA_BLOB stub;
638         uint32_t total_length;
639
640
641         if (!call->conn->iface) {
642                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
643         }
644
645         opnum = call->pkt.u.request.opnum;
646
647         if (opnum >= call->conn->iface->ndr->num_calls) {
648                 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
649         }
650
651         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
652         if (!pull) {
653                 return NT_STATUS_NO_MEMORY;
654         }
655
656         if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
657                 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
658         }
659
660         r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
661         if (!r) {
662                 return NT_STATUS_NO_MEMORY;
663         }
664
665         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
666                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
667         }
668
669         /* unravel the NDR for the packet */
670         status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
671         if (!NT_STATUS_IS_OK(status)) {
672                 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN, 
673                                   &call->pkt.u.request.stub_and_verifier);
674                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
675         }
676
677         if (pull->offset != pull->data_size) {
678                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
679                          pull->data_size - pull->offset));
680                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
681         }
682
683         call->fault_code = 0;
684
685         /* call the dispatch function */
686         status = call->conn->iface->dispatch(call, call, r);
687         if (!NT_STATUS_IS_OK(status)) {
688                 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN, 
689                                   &call->pkt.u.request.stub_and_verifier);
690                 return dcesrv_fault(call, call->fault_code);
691         }
692
693         /* form the reply NDR */
694         push = ndr_push_init_ctx(call);
695         if (!push) {
696                 return NT_STATUS_NO_MEMORY;
697         }
698
699         /* carry over the pointer count to the reply in case we are
700            using full pointer. See NDR specification for full
701            pointers */
702         push->ptr_count = pull->ptr_count;
703
704         if (lp_rpc_big_endian()) {
705                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
706         }
707
708         status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
709         if (!NT_STATUS_IS_OK(status)) {
710                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
711         }
712
713         stub = ndr_push_blob(push);
714
715         total_length = stub.length;
716
717         do {
718                 uint32_t length;
719                 struct dcesrv_call_reply *rep;
720                 struct dcerpc_packet pkt;
721
722                 rep = talloc_p(call, struct dcesrv_call_reply);
723                 if (!rep) {
724                         return NT_STATUS_NO_MEMORY;
725                 }
726
727                 length = stub.length;
728                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
729                         /* the 32 is to cope with signing data */
730                         length = call->conn->cli_max_recv_frag - 
731                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
732                 }
733
734                 /* form the dcerpc response packet */
735                 dcesrv_init_hdr(&pkt);
736                 pkt.auth_length = 0;
737                 pkt.call_id = call->pkt.call_id;
738                 pkt.ptype = DCERPC_PKT_RESPONSE;
739                 pkt.pfc_flags = 0;
740                 if (stub.length == total_length) {
741                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
742                 }
743                 if (length == stub.length) {
744                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
745                 }
746                 pkt.u.response.alloc_hint = stub.length;
747                 pkt.u.response.context_id = call->pkt.u.request.context_id;
748                 pkt.u.response.cancel_count = 0;
749                 pkt.u.response.stub_and_verifier.data = stub.data;
750                 pkt.u.response.stub_and_verifier.length = length;
751
752                 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
753                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
754                 }
755
756                 dcerpc_set_frag_length(&rep->data, rep->data.length);
757
758                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
759                 
760                 stub.data += length;
761                 stub.length -= length;
762         } while (stub.length != 0);
763
764         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
765
766         return NT_STATUS_OK;
767 }
768
769
770 /*
771   work out if we have a full packet yet
772 */
773 static BOOL dce_full_packet(const DATA_BLOB *data)
774 {
775         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
776                 return False;
777         }
778         if (dcerpc_get_frag_length(data) > data->length) {
779                 return False;
780         }
781         return True;
782 }
783
784 /*
785   we might have consumed only part of our input - advance past that part
786 */
787 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
788 {
789         DATA_BLOB blob;
790
791         if (dce_conn->partial_input.length == offset) {
792                 data_blob_free(&dce_conn->partial_input);
793                 return;
794         }
795
796         blob = dce_conn->partial_input;
797         dce_conn->partial_input = data_blob(blob.data + offset,
798                                             blob.length - offset);
799         data_blob_free(&blob);
800 }
801
802 /*
803   process some input to a dcerpc endpoint server.
804 */
805 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
806 {
807         struct ndr_pull *ndr;
808         NTSTATUS status;
809         struct dcesrv_call_state *call;
810         DATA_BLOB blob;
811
812         call = talloc_p(dce_conn, struct dcesrv_call_state);
813         if (!call) {
814                 talloc_free(dce_conn->partial_input.data);
815                 return NT_STATUS_NO_MEMORY;
816         }
817         call->conn = dce_conn;
818         call->replies = NULL;
819
820         blob = dce_conn->partial_input;
821         blob.length = dcerpc_get_frag_length(&blob);
822
823         ndr = ndr_pull_init_blob(&blob, call);
824         if (!ndr) {
825                 talloc_free(dce_conn->partial_input.data);
826                 talloc_free(call);
827                 return NT_STATUS_NO_MEMORY;
828         }
829
830         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
831                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
832         }
833
834         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
835         if (!NT_STATUS_IS_OK(status)) {
836                 talloc_free(dce_conn->partial_input.data);
837                 talloc_free(call);
838                 return status;
839         }
840
841         /* we have to check the signing here, before combining the
842            pdus */
843         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
844             !dcesrv_auth_request(call, &blob)) {
845                 dce_partial_advance(dce_conn, blob.length);
846                 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);          
847         }
848
849         dce_partial_advance(dce_conn, blob.length);
850
851         /* see if this is a continued packet */
852         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
853                 struct dcesrv_call_state *call2 = call;
854                 uint32_t alloc_size;
855
856                 /* we only allow fragmented requests, no other packet types */
857                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
858                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
859                 }
860
861                 /* this is a continuation of an existing call - find the call then
862                    tack it on the end */
863                 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
864                 if (!call) {
865                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
866                 }
867
868                 if (call->pkt.ptype != call2->pkt.ptype) {
869                         /* trying to play silly buggers are we? */
870                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
871                 }
872
873                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
874                         call2->pkt.u.request.stub_and_verifier.length;
875                 if (call->pkt.u.request.alloc_hint > alloc_size) {
876                         alloc_size = call->pkt.u.request.alloc_hint;
877                 }
878
879                 call->pkt.u.request.stub_and_verifier.data = 
880                         talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
881                 if (!call->pkt.u.request.stub_and_verifier.data) {
882                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
883                 }
884                 memcpy(call->pkt.u.request.stub_and_verifier.data +
885                        call->pkt.u.request.stub_and_verifier.length,
886                        call2->pkt.u.request.stub_and_verifier.data,
887                        call2->pkt.u.request.stub_and_verifier.length);
888                 call->pkt.u.request.stub_and_verifier.length += 
889                         call2->pkt.u.request.stub_and_verifier.length;
890
891                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
892
893                 talloc_free(call2);
894         }
895
896         /* this may not be the last pdu in the chain - if its isn't then
897            just put it on the call_list and wait for the rest */
898         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
899                 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
900                 return NT_STATUS_OK;
901         }
902
903         switch (call->pkt.ptype) {
904         case DCERPC_PKT_BIND:
905                 status = dcesrv_bind(call);
906                 break;
907         case DCERPC_PKT_AUTH3:
908                 status = dcesrv_auth3(call);
909                 break;
910         case DCERPC_PKT_ALTER:
911                 status = dcesrv_alter(call);
912                 break;
913         case DCERPC_PKT_REQUEST:
914                 status = dcesrv_request(call);
915                 break;
916         default:
917                 status = NT_STATUS_INVALID_PARAMETER;
918                 break;
919         }
920
921         /* if we are going to be sending a reply then add
922            it to the list of pending calls. We add it to the end to keep the call
923            list in the order we will answer */
924         if (!NT_STATUS_IS_OK(status)) {
925                 talloc_free(call);
926         }
927
928         return status;
929 }
930
931
932 /*
933   provide some input to a dcerpc endpoint server. This passes data
934   from a dcerpc client into the server
935 */
936 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
937 {
938         NTSTATUS status;
939
940         dce_conn->partial_input.data = talloc_realloc(dce_conn,
941                                                       dce_conn->partial_input.data,
942                                                       dce_conn->partial_input.length + data->length);
943         if (!dce_conn->partial_input.data) {
944                 return NT_STATUS_NO_MEMORY;
945         }
946         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
947                data->data, data->length);
948         dce_conn->partial_input.length += data->length;
949
950         while (dce_full_packet(&dce_conn->partial_input)) {
951                 status = dcesrv_input_process(dce_conn);
952                 if (!NT_STATUS_IS_OK(status)) {
953                         return status;
954                 }
955         }
956
957         return NT_STATUS_OK;
958 }
959
960 /*
961   retrieve some output from a dcerpc server
962   The caller supplies a function that will be called to do the
963   actual output. 
964
965   The first argument to write_fn() will be 'private', the second will
966   be a pointer to a buffer containing the data to be sent and the 3rd
967   will be the number of bytes to be sent.
968
969   write_fn() should return the number of bytes successfully written.
970
971   this will return STATUS_BUFFER_OVERFLOW if there is more to be read
972   from the current fragment
973 */
974 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
975                        void *private,
976                        ssize_t (*write_fn)(void *, DATA_BLOB *))
977 {
978         struct dcesrv_call_state *call;
979         struct dcesrv_call_reply *rep;
980         ssize_t nwritten;
981
982         call = dce_conn->call_list;
983         if (!call || !call->replies) {
984                 return NT_STATUS_FOOBAR;
985         }
986         rep = call->replies;
987
988         nwritten = write_fn(private, &rep->data);
989         if (nwritten == -1) {
990                 /* TODO: hmm, how do we cope with this? destroy the
991                    connection perhaps? */
992                 return NT_STATUS_UNSUCCESSFUL;
993         }
994
995         rep->data.length -= nwritten;
996         rep->data.data += nwritten;
997
998         if (rep->data.length == 0) {
999                 /* we're done with this section of the call */
1000                 DLIST_REMOVE(call->replies, rep);
1001         }
1002
1003         if (call->replies == NULL) {
1004                 /* we're done with the whole call */
1005                 DLIST_REMOVE(dce_conn->call_list, call);
1006                 talloc_free(call);
1007         }
1008
1009         return NT_STATUS_OK;
1010 }
1011
1012
1013 /*
1014   write_fn() for dcesrv_output_blob()
1015 */
1016 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1017 {
1018         DATA_BLOB *blob = private;
1019         if (out->length < blob->length) {
1020                 blob->length = out->length;
1021         }
1022         memcpy(blob->data, out->data, blob->length);
1023         return blob->length;
1024 }
1025
1026 /*
1027   a simple wrapper for dcesrv_output() for when we want to output
1028   into a data blob
1029 */
1030 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn, 
1031                             DATA_BLOB *blob)
1032 {
1033         return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1034 }
1035
1036 /*
1037   initialise the dcerpc server context
1038 */
1039 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
1040 {
1041         int i;
1042         const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1043
1044         (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
1045         if (! *dce_ctx) {
1046                 return NT_STATUS_NO_MEMORY;
1047         }
1048
1049         (*dce_ctx)->endpoint_list = NULL;
1050
1051         if (!endpoint_servers) {
1052                 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
1053                 return NT_STATUS_OK;
1054         }
1055
1056         for (i=0;endpoint_servers[i];i++) {
1057                 NTSTATUS ret;
1058                 const struct dcesrv_endpoint_server *ep_server;
1059                 
1060                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1061                 if (!ep_server) {
1062                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1063                         return NT_STATUS_UNSUCCESSFUL;
1064                 }
1065
1066                 ret = ep_server->init_server(*dce_ctx, ep_server);
1067                 if (!NT_STATUS_IS_OK(ret)) {
1068                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1069                         return ret;
1070                 }
1071         }
1072
1073         return NT_STATUS_OK;
1074 }
1075
1076 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1077 {
1078         struct dcesrv_context *dce_ctx;
1079         int i;
1080         const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1081
1082         DEBUG(1,("dcesrv_init\n"));
1083
1084         if (!endpoint_servers) {
1085                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1086                 return;
1087         }
1088
1089         dce_ctx = talloc_p(service, struct dcesrv_context);
1090         if (!dce_ctx) {
1091                 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1092                 return;
1093         }
1094
1095         ZERO_STRUCTP(dce_ctx);
1096         dce_ctx->endpoint_list  = NULL;
1097
1098         for (i=0;endpoint_servers[i];i++) {
1099                 NTSTATUS ret;
1100                 const struct dcesrv_endpoint_server *ep_server;
1101                 
1102                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1103                 if (!ep_server) {
1104                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1105                         return;
1106                 }
1107
1108                 ret = ep_server->init_server(dce_ctx, ep_server);
1109                 if (!NT_STATUS_IS_OK(ret)) {
1110                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1111                         return;
1112                 }
1113         }
1114
1115         dcesrv_sock_init(service, model_ops, dce_ctx);
1116
1117         return; 
1118 }
1119
1120 static void dcesrv_accept(struct server_connection *srv_conn)
1121 {
1122         dcesrv_sock_accept(srv_conn);
1123 }
1124
1125 static void dcesrv_recv(struct server_connection *srv_conn, 
1126                         struct timeval t, uint16_t flags)
1127 {
1128         dcesrv_sock_recv(srv_conn, t, flags);
1129 }
1130
1131 static void dcesrv_send(struct server_connection *srv_conn, 
1132                         struct timeval t, uint16_t flags)
1133 {
1134         dcesrv_sock_send(srv_conn, t, flags);
1135 }
1136
1137 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1138 {
1139         dcesrv_sock_close(srv_conn, reason);
1140         return; 
1141 }
1142
1143 static void dcesrv_exit(struct server_service *service, const char *reason)
1144 {
1145         dcesrv_sock_exit(service, reason);
1146         return; 
1147 }
1148
1149 /* the list of currently registered DCERPC endpoint servers.
1150  */
1151 static struct ep_server {
1152         struct dcesrv_endpoint_server *ep_server;
1153 } *ep_servers = NULL;
1154 static int num_ep_servers;
1155
1156 /*
1157   register a DCERPC endpoint server. 
1158
1159   The 'name' can be later used by other backends to find the operations
1160   structure for this backend.  
1161
1162   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1163 */
1164 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1165 {
1166         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1167         
1168         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1169                 /* its already registered! */
1170                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1171                          ep_server->name));
1172                 return NT_STATUS_OBJECT_NAME_COLLISION;
1173         }
1174
1175         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1176         if (!ep_servers) {
1177                 smb_panic("out of memory in dcerpc_register");
1178         }
1179
1180         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1181         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1182
1183         num_ep_servers++;
1184
1185         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1186                  ep_server->name));
1187
1188         return NT_STATUS_OK;
1189 }
1190
1191 /*
1192   return the operations structure for a named backend of the specified type
1193 */
1194 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1195 {
1196         int i;
1197
1198         for (i=0;i<num_ep_servers;i++) {
1199                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1200                         return ep_servers[i].ep_server;
1201                 }
1202         }
1203
1204         return NULL;
1205 }
1206
1207 /*
1208   return the DCERPC module version, and the size of some critical types
1209   This can be used by endpoint server modules to either detect compilation errors, or provide
1210   multiple implementations for different smbd compilation options in one module
1211 */
1212 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1213 {
1214         static const struct dcesrv_critical_sizes critical_sizes = {
1215                 DCERPC_MODULE_VERSION,
1216                 sizeof(struct dcesrv_context),
1217                 sizeof(struct dcesrv_endpoint),
1218                 sizeof(struct dcesrv_endpoint_server),
1219                 sizeof(struct dcesrv_interface),
1220                 sizeof(struct dcesrv_if_list),
1221                 sizeof(struct dcesrv_connection),
1222                 sizeof(struct dcesrv_call_state),
1223                 sizeof(struct dcesrv_auth),
1224                 sizeof(struct dcesrv_handle)
1225         };
1226
1227         return &critical_sizes;
1228 }
1229
1230 static const struct server_service_ops dcesrv_ops = {
1231         .name                   = "rpc",
1232         .service_init           = dcesrv_init,
1233         .accept_connection      = dcesrv_accept,
1234         .recv_handler           = dcesrv_recv,
1235         .send_handler           = dcesrv_send,
1236         .idle_handler           = NULL,
1237         .close_connection       = dcesrv_close,
1238         .service_exit           = dcesrv_exit,  
1239 };
1240
1241 const struct server_service_ops *dcesrv_get_ops(void)
1242 {
1243         return &dcesrv_ops;
1244 }
1245
1246 NTSTATUS server_service_rpc_init(void)
1247 {
1248         return NT_STATUS_OK;    
1249 }