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