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