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