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