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