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