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