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