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