r21835: fixed a rpc server bug where we failed to remove a call from one
[kai/samba-autobuild/.git] / source4 / rpc_server / dcerpc_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc core code
5
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Stefan (metze) Metzmacher 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_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         pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
607         if (iface) {
608                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
609                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
610         } else {
611                 pkt.u.bind_ack.secondary_address = "";
612         }
613         pkt.u.bind_ack.num_results = 1;
614         pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
615         if (!pkt.u.bind_ack.ctx_list) {
616                 return NT_STATUS_NO_MEMORY;
617         }
618         pkt.u.bind_ack.ctx_list[0].result = result;
619         pkt.u.bind_ack.ctx_list[0].reason = reason;
620         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
621         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
622
623         if (!dcesrv_auth_bind_ack(call, &pkt)) {
624                 return dcesrv_bind_nak(call, 0);
625         }
626
627         if (iface) {
628                 status = iface->bind(call, iface);
629                 if (!NT_STATUS_IS_OK(status)) {
630                         char *uuid_str = GUID_string(call, &uuid);
631                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", 
632                                  uuid_str, if_version, nt_errstr(status)));
633                         talloc_free(uuid_str);
634                         return dcesrv_bind_nak(call, 0);
635                 }
636         }
637
638         rep = talloc(call, struct data_blob_list_item);
639         if (!rep) {
640                 return NT_STATUS_NO_MEMORY;
641         }
642
643         status = ncacn_push_auth(&rep->blob, call, &pkt, 
644                                   call->conn->auth_state.auth_info);
645         if (!NT_STATUS_IS_OK(status)) {
646                 return status;
647         }
648
649         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
650
651         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
652         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
653
654         return NT_STATUS_OK;
655 }
656
657
658 /*
659   handle a auth3 request
660 */
661 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
662 {
663         /* handle the auth3 in the auth code */
664         if (!dcesrv_auth_auth3(call)) {
665                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
666         }
667
668         talloc_free(call);
669
670         /* we don't send a reply to a auth3 request, except by a
671            fault */
672         return NT_STATUS_OK;
673 }
674
675
676 /*
677   handle a bind request
678 */
679 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
680 {
681         uint32_t if_version, transfer_syntax_version;
682         struct dcesrv_connection_context *context;
683         const struct dcesrv_interface *iface;
684         struct GUID uuid, *transfer_syntax_uuid;
685
686         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
687         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
688
689         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
690         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
691         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
692             ndr_transfer_syntax.if_version != transfer_syntax_version) {
693                 /* we only do NDR encoded dcerpc */
694                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
695         }
696
697         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
698         if (iface == NULL) {
699                 char *uuid_str = GUID_string(call, &uuid);
700                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
701                 talloc_free(uuid_str);
702                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
703         }
704
705         /* add this context to the list of available context_ids */
706         context = talloc(call->conn, struct dcesrv_connection_context);
707         if (context == NULL) {
708                 return NT_STATUS_NO_MEMORY;
709         }
710         context->conn = call->conn;
711         context->iface = iface;
712         context->context_id = context_id;
713         context->private = NULL;
714         context->handles = NULL;
715         DLIST_ADD(call->conn->contexts, context);
716         call->context = context;
717
718         return NT_STATUS_OK;
719 }
720
721
722 /*
723   handle a alter context request
724 */
725 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
726 {
727         struct ncacn_packet pkt;
728         struct data_blob_list_item *rep;
729         NTSTATUS status;
730         uint32_t result=0, reason=0;
731         uint32_t context_id;
732
733         /* handle any authentication that is being requested */
734         if (!dcesrv_auth_alter(call)) {
735                 /* TODO: work out the right reject code */
736                 result = DCERPC_BIND_PROVIDER_REJECT;
737                 reason = DCERPC_BIND_REASON_ASYNTAX;            
738         }
739
740         context_id = call->pkt.u.alter.ctx_list[0].context_id;
741
742         /* see if they are asking for a new interface */
743         if (result == 0 &&
744             dcesrv_find_context(call->conn, context_id) == NULL) {
745                 status = dcesrv_alter_new_context(call, context_id);
746                 if (!NT_STATUS_IS_OK(status)) {
747                         result = DCERPC_BIND_PROVIDER_REJECT;
748                         reason = DCERPC_BIND_REASON_ASYNTAX;            
749                 }
750         }
751
752         /* setup a alter_resp */
753         dcesrv_init_hdr(&pkt);
754         pkt.auth_length = 0;
755         pkt.call_id = call->pkt.call_id;
756         pkt.ptype = DCERPC_PKT_ALTER_RESP;
757         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
758         pkt.u.alter_resp.max_xmit_frag = 0x2000;
759         pkt.u.alter_resp.max_recv_frag = 0x2000;
760         pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
761         pkt.u.alter_resp.num_results = 1;
762         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
763         if (!pkt.u.alter_resp.ctx_list) {
764                 return NT_STATUS_NO_MEMORY;
765         }
766         pkt.u.alter_resp.ctx_list[0].result = result;
767         pkt.u.alter_resp.ctx_list[0].reason = reason;
768         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
769         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
770         pkt.u.alter_resp.secondary_address = "";
771
772         if (!dcesrv_auth_alter_ack(call, &pkt)) {
773                 return dcesrv_bind_nak(call, 0);
774         }
775
776         rep = talloc(call, struct data_blob_list_item);
777         if (!rep) {
778                 return NT_STATUS_NO_MEMORY;
779         }
780
781         status = ncacn_push_auth(&rep->blob, call, &pkt, 
782                                   call->conn->auth_state.auth_info);
783         if (!NT_STATUS_IS_OK(status)) {
784                 return status;
785         }
786
787         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
788
789         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
790         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
791
792         return NT_STATUS_OK;
793 }
794
795 /*
796   handle a dcerpc request packet
797 */
798 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
799 {
800         struct ndr_pull *pull;
801         NTSTATUS status;
802         struct dcesrv_connection_context *context;
803
804         /* if authenticated, and the mech we use can't do async replies, don't use them... */
805         if (call->conn->auth_state.gensec_security && 
806             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
807                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
808         }
809
810         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
811         if (context == NULL) {
812                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
813         }
814
815         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
816         NT_STATUS_HAVE_NO_MEMORY(pull);
817
818         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
819
820         call->context   = context;
821         call->ndr_pull  = pull;
822
823         if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
824                 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
825         }
826
827         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
828                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
829         }
830
831         /* unravel the NDR for the packet */
832         status = context->iface->ndr_pull(call, call, pull, &call->r);
833         if (!NT_STATUS_IS_OK(status)) {
834                 return dcesrv_fault(call, call->fault_code);
835         }
836
837         if (pull->offset != pull->data_size) {
838                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
839                          pull->data_size - pull->offset));
840                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
841         }
842
843         /* call the dispatch function */
844         status = context->iface->dispatch(call, call, call->r);
845         if (!NT_STATUS_IS_OK(status)) {
846                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
847                          context->iface->name, 
848                          call->pkt.u.request.opnum,
849                          dcerpc_errstr(pull, call->fault_code)));
850                 return dcesrv_fault(call, call->fault_code);
851         }
852
853         /* add the call to the pending list */
854         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
855
856         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
857                 return NT_STATUS_OK;
858         }
859
860         return dcesrv_reply(call);
861 }
862
863 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
864 {
865         struct ndr_push *push;
866         NTSTATUS status;
867         DATA_BLOB stub;
868         uint32_t total_length;
869         struct dcesrv_connection_context *context = call->context;
870
871         /* call the reply function */
872         status = context->iface->reply(call, call, call->r);
873         if (!NT_STATUS_IS_OK(status)) {
874                 return dcesrv_fault(call, call->fault_code);
875         }
876
877         /* form the reply NDR */
878         push = ndr_push_init_ctx(call);
879         NT_STATUS_HAVE_NO_MEMORY(push);
880
881         /* carry over the pointer count to the reply in case we are
882            using full pointer. See NDR specification for full
883            pointers */
884         push->ptr_count = call->ndr_pull->ptr_count;
885
886         if (lp_rpc_big_endian()) {
887                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
888         }
889
890         status = context->iface->ndr_push(call, call, push, call->r);
891         if (!NT_STATUS_IS_OK(status)) {
892                 return dcesrv_fault(call, call->fault_code);
893         }
894
895         stub = ndr_push_blob(push);
896
897         total_length = stub.length;
898
899         do {
900                 uint32_t length;
901                 struct data_blob_list_item *rep;
902                 struct ncacn_packet pkt;
903
904                 rep = talloc(call, struct data_blob_list_item);
905                 NT_STATUS_HAVE_NO_MEMORY(rep);
906
907                 length = stub.length;
908                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
909                         /* the 32 is to cope with signing data */
910                         length = call->conn->cli_max_recv_frag - 
911                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
912                 }
913
914                 /* form the dcerpc response packet */
915                 dcesrv_init_hdr(&pkt);
916                 pkt.auth_length = 0;
917                 pkt.call_id = call->pkt.call_id;
918                 pkt.ptype = DCERPC_PKT_RESPONSE;
919                 pkt.pfc_flags = 0;
920                 if (stub.length == total_length) {
921                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
922                 }
923                 if (length == stub.length) {
924                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
925                 }
926                 pkt.u.response.alloc_hint = stub.length;
927                 pkt.u.response.context_id = call->pkt.u.request.context_id;
928                 pkt.u.response.cancel_count = 0;
929                 pkt.u.response.stub_and_verifier.data = stub.data;
930                 pkt.u.response.stub_and_verifier.length = length;
931
932                 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
933                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
934                 }
935
936                 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
937
938                 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
939                 
940                 stub.data += length;
941                 stub.length -= length;
942         } while (stub.length != 0);
943
944         /* move the call from the pending to the finished calls list */
945         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
946
947         if (call->conn->call_list && call->conn->call_list->replies) {
948                 if (call->conn->transport.report_output_data) {
949                         call->conn->transport.report_output_data(call->conn);
950                 }
951         }
952
953         return NT_STATUS_OK;
954 }
955
956 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
957 {
958         if (!conn->transport.get_my_addr) {
959                 return NULL;
960         }
961
962         return conn->transport.get_my_addr(conn, mem_ctx);
963 }
964
965 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
966 {
967         if (!conn->transport.get_peer_addr) {
968                 return NULL;
969         }
970
971         return conn->transport.get_peer_addr(conn, mem_ctx);
972 }
973
974 /*
975   work out if we have a full packet yet
976 */
977 static BOOL dce_full_packet(const DATA_BLOB *data)
978 {
979         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
980                 return False;
981         }
982         if (dcerpc_get_frag_length(data) > data->length) {
983                 return False;
984         }
985         return True;
986 }
987
988 /*
989   we might have consumed only part of our input - advance past that part
990 */
991 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
992 {
993         DATA_BLOB blob;
994
995         if (dce_conn->partial_input.length == offset) {
996                 data_blob_free(&dce_conn->partial_input);
997                 return;
998         }
999
1000         blob = dce_conn->partial_input;
1001         dce_conn->partial_input = data_blob(blob.data + offset,
1002                                             blob.length - offset);
1003         data_blob_free(&blob);
1004 }
1005
1006 /*
1007   remove the call from the right list when freed
1008  */
1009 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1010 {
1011         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1012         return 0;
1013 }
1014
1015 /*
1016   process some input to a dcerpc endpoint server.
1017 */
1018 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1019 {
1020         struct ndr_pull *ndr;
1021         NTSTATUS status;
1022         struct dcesrv_call_state *call;
1023         DATA_BLOB blob;
1024
1025         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1026         if (!call) {
1027                 talloc_free(dce_conn->partial_input.data);
1028                 return NT_STATUS_NO_MEMORY;
1029         }
1030         call->conn              = dce_conn;
1031         call->event_ctx         = dce_conn->event_ctx;
1032         call->msg_ctx           = dce_conn->msg_ctx;
1033         call->state_flags       = call->conn->state_flags;
1034         call->time              = timeval_current();
1035         call->list              = DCESRV_LIST_NONE;
1036
1037         talloc_set_destructor(call, dcesrv_call_dequeue);
1038
1039         blob = dce_conn->partial_input;
1040         blob.length = dcerpc_get_frag_length(&blob);
1041
1042         ndr = ndr_pull_init_blob(&blob, call);
1043         if (!ndr) {
1044                 talloc_free(dce_conn->partial_input.data);
1045                 talloc_free(call);
1046                 return NT_STATUS_NO_MEMORY;
1047         }
1048
1049         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1050                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1051         }
1052
1053         status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1054         if (!NT_STATUS_IS_OK(status)) {
1055                 talloc_free(dce_conn->partial_input.data);
1056                 talloc_free(call);
1057                 return status;
1058         }
1059
1060         /* we have to check the signing here, before combining the
1061            pdus */
1062         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1063             !dcesrv_auth_request(call, &blob)) {
1064                 dce_partial_advance(dce_conn, blob.length);
1065                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1066         }
1067
1068         dce_partial_advance(dce_conn, blob.length);
1069
1070         /* see if this is a continued packet */
1071         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1072             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1073                 struct dcesrv_call_state *call2 = call;
1074                 uint32_t alloc_size;
1075
1076                 /* we only allow fragmented requests, no other packet types */
1077                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1078                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1079                 }
1080
1081                 /* this is a continuation of an existing call - find the call then
1082                    tack it on the end */
1083                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1084                 if (!call) {
1085                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1086                 }
1087
1088                 if (call->pkt.ptype != call2->pkt.ptype) {
1089                         /* trying to play silly buggers are we? */
1090                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1091                 }
1092
1093                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1094                         call2->pkt.u.request.stub_and_verifier.length;
1095                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1096                         alloc_size = call->pkt.u.request.alloc_hint;
1097                 }
1098
1099                 call->pkt.u.request.stub_and_verifier.data = 
1100                         talloc_realloc(call, 
1101                                        call->pkt.u.request.stub_and_verifier.data, 
1102                                        uint8_t, alloc_size);
1103                 if (!call->pkt.u.request.stub_and_verifier.data) {
1104                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1105                 }
1106                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1107                        call->pkt.u.request.stub_and_verifier.length,
1108                        call2->pkt.u.request.stub_and_verifier.data,
1109                        call2->pkt.u.request.stub_and_verifier.length);
1110                 call->pkt.u.request.stub_and_verifier.length += 
1111                         call2->pkt.u.request.stub_and_verifier.length;
1112
1113                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1114
1115                 talloc_free(call2);
1116         }
1117
1118         /* this may not be the last pdu in the chain - if its isn't then
1119            just put it on the incoming_fragmented_call_list and wait for the rest */
1120         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1121             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1122                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1123                 return NT_STATUS_OK;
1124         } 
1125         
1126         /* This removes any fragments we may have had stashed away */
1127         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1128
1129         switch (call->pkt.ptype) {
1130         case DCERPC_PKT_BIND:
1131                 status = dcesrv_bind(call);
1132                 break;
1133         case DCERPC_PKT_AUTH3:
1134                 status = dcesrv_auth3(call);
1135                 break;
1136         case DCERPC_PKT_ALTER:
1137                 status = dcesrv_alter(call);
1138                 break;
1139         case DCERPC_PKT_REQUEST:
1140                 status = dcesrv_request(call);
1141                 break;
1142         default:
1143                 status = NT_STATUS_INVALID_PARAMETER;
1144                 break;
1145         }
1146
1147         /* if we are going to be sending a reply then add
1148            it to the list of pending calls. We add it to the end to keep the call
1149            list in the order we will answer */
1150         if (!NT_STATUS_IS_OK(status)) {
1151                 talloc_free(call);
1152         }
1153
1154         return status;
1155 }
1156
1157
1158 /*
1159   provide some input to a dcerpc endpoint server. This passes data
1160   from a dcerpc client into the server
1161 */
1162 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1163 {
1164         NTSTATUS status;
1165
1166         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1167                                                       dce_conn->partial_input.data,
1168                                                       uint8_t,
1169                                                       dce_conn->partial_input.length + data->length);
1170         if (!dce_conn->partial_input.data) {
1171                 return NT_STATUS_NO_MEMORY;
1172         }
1173         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1174                data->data, data->length);
1175         dce_conn->partial_input.length += data->length;
1176
1177         while (dce_full_packet(&dce_conn->partial_input)) {
1178                 status = dcesrv_input_process(dce_conn);
1179                 if (!NT_STATUS_IS_OK(status)) {
1180                         return status;
1181                 }
1182         }
1183
1184         return NT_STATUS_OK;
1185 }
1186
1187 /*
1188   retrieve some output from a dcerpc server
1189   The caller supplies a function that will be called to do the
1190   actual output. 
1191
1192   The first argument to write_fn() will be 'private', the second will
1193   be a pointer to a buffer containing the data to be sent and the 3rd
1194   will be a pointer to a size_t variable that will be set to the
1195   number of bytes that are consumed from the output.
1196
1197   from the current fragment
1198 */
1199 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1200                        void *private_data,
1201                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1202 {
1203         NTSTATUS status;
1204         struct dcesrv_call_state *call;
1205         struct data_blob_list_item *rep;
1206         size_t nwritten;
1207
1208         call = dce_conn->call_list;
1209         if (!call || !call->replies) {
1210                 if (dce_conn->pending_call_list) {
1211                         /* TODO: we need to say act async here
1212                          *       as we know we have pending requests
1213                          *       which will be finished at a time
1214                          */
1215                         return NT_STATUS_FOOBAR;
1216                 }
1217                 return NT_STATUS_FOOBAR;
1218         }
1219         rep = call->replies;
1220
1221         status = write_fn(private_data, &rep->blob, &nwritten);
1222         NT_STATUS_IS_ERR_RETURN(status);
1223
1224         rep->blob.length -= nwritten;
1225         rep->blob.data += nwritten;
1226
1227         if (rep->blob.length == 0) {
1228                 /* we're done with this section of the call */
1229                 DLIST_REMOVE(call->replies, rep);
1230         }
1231
1232         if (call->replies == NULL) {
1233                 /* we're done with the whole call */
1234                 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1235                 talloc_free(call);
1236         }
1237
1238         return status;
1239 }
1240
1241 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1242 {
1243         NTSTATUS status;
1244         struct dcesrv_context *dce_ctx;
1245         int i;
1246
1247         if (!endpoint_servers) {
1248                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1249                 return NT_STATUS_INTERNAL_ERROR;
1250         }
1251
1252         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1253         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1254         dce_ctx->endpoint_list  = NULL;
1255
1256         for (i=0;endpoint_servers[i];i++) {
1257                 const struct dcesrv_endpoint_server *ep_server;
1258
1259                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1260                 if (!ep_server) {
1261                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1262                         return NT_STATUS_INTERNAL_ERROR;
1263                 }
1264
1265                 status = ep_server->init_server(dce_ctx, ep_server);
1266                 if (!NT_STATUS_IS_OK(status)) {
1267                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1268                                 nt_errstr(status)));
1269                         return status;
1270                 }
1271         }
1272
1273         *_dce_ctx = dce_ctx;
1274         return NT_STATUS_OK;
1275 }
1276
1277 /*
1278   initialise the dcerpc server context for ncacn_np based services
1279 */
1280 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1281 {
1282         NTSTATUS status;
1283         struct dcesrv_context *dce_ctx;
1284
1285         status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1286         NT_STATUS_NOT_OK_RETURN(status);
1287
1288         *_dce_ctx = dce_ctx;
1289         return NT_STATUS_OK;
1290 }
1291
1292 /* the list of currently registered DCERPC endpoint servers.
1293  */
1294 static struct ep_server {
1295         struct dcesrv_endpoint_server *ep_server;
1296 } *ep_servers = NULL;
1297 static int num_ep_servers;
1298
1299 /*
1300   register a DCERPC endpoint server. 
1301
1302   The 'name' can be later used by other backends to find the operations
1303   structure for this backend.  
1304
1305   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1306 */
1307 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1308 {
1309         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1310         
1311         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1312                 /* its already registered! */
1313                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1314                          ep_server->name));
1315                 return NT_STATUS_OBJECT_NAME_COLLISION;
1316         }
1317
1318         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1319         if (!ep_servers) {
1320                 smb_panic("out of memory in dcerpc_register");
1321         }
1322
1323         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1324         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1325
1326         num_ep_servers++;
1327
1328         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1329                  ep_server->name));
1330
1331         return NT_STATUS_OK;
1332 }
1333
1334 /*
1335   return the operations structure for a named backend of the specified type
1336 */
1337 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1338 {
1339         int i;
1340
1341         for (i=0;i<num_ep_servers;i++) {
1342                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1343                         return ep_servers[i].ep_server;
1344                 }
1345         }
1346
1347         return NULL;
1348 }
1349
1350 /*
1351   return the DCERPC module version, and the size of some critical types
1352   This can be used by endpoint server modules to either detect compilation errors, or provide
1353   multiple implementations for different smbd compilation options in one module
1354 */
1355 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1356 {
1357         static const struct dcesrv_critical_sizes critical_sizes = {
1358                 DCERPC_MODULE_VERSION,
1359                 sizeof(struct dcesrv_context),
1360                 sizeof(struct dcesrv_endpoint),
1361                 sizeof(struct dcesrv_endpoint_server),
1362                 sizeof(struct dcesrv_interface),
1363                 sizeof(struct dcesrv_if_list),
1364                 sizeof(struct dcesrv_connection),
1365                 sizeof(struct dcesrv_call_state),
1366                 sizeof(struct dcesrv_auth),
1367                 sizeof(struct dcesrv_handle)
1368         };
1369
1370         return &critical_sizes;
1371 }
1372
1373 /*
1374   open the dcerpc server sockets
1375 */
1376 static void dcesrv_task_init(struct task_server *task)
1377 {
1378         NTSTATUS status;
1379         struct dcesrv_context *dce_ctx;
1380         struct dcesrv_endpoint *e;
1381
1382         task_server_set_title(task, "task[dcesrv]");
1383
1384         status = dcesrv_init_context(task->event_ctx,
1385                                      lp_dcerpc_endpoint_servers(),
1386                                      &dce_ctx);
1387         if (!NT_STATUS_IS_OK(status)) goto failed;
1388
1389         /* Make sure the directory for NCALRPC exists */
1390         if (!directory_exist(lp_ncalrpc_dir())) {
1391                 mkdir(lp_ncalrpc_dir(), 0755);
1392         }
1393
1394         for (e=dce_ctx->endpoint_list;e;e=e->next) {
1395                 switch (e->ep_description->transport) {
1396                 case NCACN_UNIX_STREAM:
1397                         status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1398                         if (!NT_STATUS_IS_OK(status)) goto failed;
1399                         break;
1400                 
1401                 case NCALRPC:
1402                         status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1403                         if (!NT_STATUS_IS_OK(status)) goto failed;
1404                         break;
1405
1406                 case NCACN_IP_TCP:
1407                         status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1408                         if (!NT_STATUS_IS_OK(status)) goto failed;
1409                         break;
1410                         
1411                 case NCACN_NP:
1412 /*                      FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1413                         if (!NT_STATUS_IS_OK(status)) goto failed;
1414 */                      break;
1415
1416                 default:
1417                         status = NT_STATUS_NOT_SUPPORTED;
1418                         if (!NT_STATUS_IS_OK(status)) goto failed;
1419                 }
1420         }
1421
1422         return;
1423 failed:
1424         task_server_terminate(task, "Failed to startup dcerpc server task");    
1425 }
1426
1427 /*
1428   called on startup of the smb server service It's job is to start
1429   listening on all configured sockets
1430 */
1431 static NTSTATUS dcesrv_init(struct event_context *event_context, 
1432                             const struct model_ops *model_ops)
1433 {       
1434         return task_server_startup(event_context, model_ops, dcesrv_task_init);
1435 }
1436
1437 NTSTATUS server_service_rpc_init(void)
1438 {
1439         init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1440         init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1441
1442         run_init_functions(static_init);
1443         run_init_functions(shared_init);
1444
1445         talloc_free(shared_init);
1446         
1447         return register_server_service("rpc", dcesrv_init);
1448 }