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