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