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