r21515: add some more PFC_FLAGS from the DCERPC spec, and fix some names
[ab/samba.git/.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   return a dcerpc fault
405 */
406 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
407 {
408         struct ncacn_packet pkt;
409         struct data_blob_list_item *rep;
410         NTSTATUS status;
411
412         /* setup a bind_ack */
413         dcesrv_init_hdr(&pkt);
414         pkt.auth_length = 0;
415         pkt.call_id = call->pkt.call_id;
416         pkt.ptype = DCERPC_PKT_FAULT;
417         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
418         pkt.u.fault.alloc_hint = 0;
419         pkt.u.fault.context_id = 0;
420         pkt.u.fault.cancel_count = 0;
421         pkt.u.fault.status = fault_code;
422
423         rep = talloc(call, struct data_blob_list_item);
424         if (!rep) {
425                 return NT_STATUS_NO_MEMORY;
426         }
427
428         status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
429         if (!NT_STATUS_IS_OK(status)) {
430                 return status;
431         }
432
433         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
434
435         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
436         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
437
438         return NT_STATUS_OK;    
439 }
440
441
442 /*
443   return a dcerpc bind_nak
444 */
445 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
446 {
447         struct ncacn_packet pkt;
448         struct data_blob_list_item *rep;
449         NTSTATUS status;
450
451         /* setup a bind_nak */
452         dcesrv_init_hdr(&pkt);
453         pkt.auth_length = 0;
454         pkt.call_id = call->pkt.call_id;
455         pkt.ptype = DCERPC_PKT_BIND_NAK;
456         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
457         pkt.u.bind_nak.reject_reason = reason;
458         if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
459                 pkt.u.bind_nak.versions.v.num_versions = 0;
460         }
461
462         rep = talloc(call, struct data_blob_list_item);
463         if (!rep) {
464                 return NT_STATUS_NO_MEMORY;
465         }
466
467         status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
468         if (!NT_STATUS_IS_OK(status)) {
469                 return status;
470         }
471
472         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
473
474         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
475         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
476
477         return NT_STATUS_OK;    
478 }
479
480
481 /*
482   handle a bind request
483 */
484 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
485 {
486         uint32_t if_version, transfer_syntax_version;
487         struct GUID uuid, *transfer_syntax_uuid;
488         struct ncacn_packet pkt;
489         struct data_blob_list_item *rep;
490         NTSTATUS status;
491         uint32_t result=0, reason=0;
492         uint32_t context_id;
493         const struct dcesrv_interface *iface;
494
495         if (call->pkt.u.bind.num_contexts < 1 ||
496             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
497                 return dcesrv_bind_nak(call, 0);
498         }
499
500         context_id = call->pkt.u.bind.ctx_list[0].context_id;
501
502         /* you can't bind twice on one context */
503         if (dcesrv_find_context(call->conn, context_id) != NULL) {
504                 return dcesrv_bind_nak(call, 0);
505         }
506
507         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
508         uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
509
510         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
511         transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
512         if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
513             ndr_transfer_syntax.if_version != transfer_syntax_version) {
514                 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
515                 /* we only do NDR encoded dcerpc */
516                 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
517                 talloc_free(uuid_str);
518                 return dcesrv_bind_nak(call, 0);
519         }
520
521         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
522         if (iface == NULL) {
523                 char *uuid_str = GUID_string(call, &uuid);
524                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
525                 talloc_free(uuid_str);
526
527                 /* we don't know about that interface */
528                 result = DCERPC_BIND_PROVIDER_REJECT;
529                 reason = DCERPC_BIND_REASON_ASYNTAX;            
530         }
531
532         if (iface) {
533                 /* add this context to the list of available context_ids */
534                 struct dcesrv_connection_context *context = talloc(call->conn, 
535                                                                    struct dcesrv_connection_context);
536                 if (context == NULL) {
537                         return dcesrv_bind_nak(call, 0);
538                 }
539                 context->conn = call->conn;
540                 context->iface = iface;
541                 context->context_id = context_id;
542                 context->private = NULL;
543                 context->handles = NULL;
544                 DLIST_ADD(call->conn->contexts, context);
545                 call->context = context;
546         }
547
548         if (call->conn->cli_max_recv_frag == 0) {
549                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
550         }
551
552         /* handle any authentication that is being requested */
553         if (!dcesrv_auth_bind(call)) {
554                 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
555         }
556
557         /* setup a bind_ack */
558         dcesrv_init_hdr(&pkt);
559         pkt.auth_length = 0;
560         pkt.call_id = call->pkt.call_id;
561         pkt.ptype = DCERPC_PKT_BIND_ACK;
562         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
563         pkt.u.bind_ack.max_xmit_frag = 0x2000;
564         pkt.u.bind_ack.max_recv_frag = 0x2000;
565         pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
566         if (iface) {
567                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
568                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
569         } else {
570                 pkt.u.bind_ack.secondary_address = "";
571         }
572         pkt.u.bind_ack.num_results = 1;
573         pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
574         if (!pkt.u.bind_ack.ctx_list) {
575                 return NT_STATUS_NO_MEMORY;
576         }
577         pkt.u.bind_ack.ctx_list[0].result = result;
578         pkt.u.bind_ack.ctx_list[0].reason = reason;
579         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
580         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
581
582         if (!dcesrv_auth_bind_ack(call, &pkt)) {
583                 return dcesrv_bind_nak(call, 0);
584         }
585
586         if (iface) {
587                 status = iface->bind(call, iface);
588                 if (!NT_STATUS_IS_OK(status)) {
589                         char *uuid_str = GUID_string(call, &uuid);
590                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", 
591                                  uuid_str, if_version, nt_errstr(status)));
592                         talloc_free(uuid_str);
593                         return dcesrv_bind_nak(call, 0);
594                 }
595         }
596
597         rep = talloc(call, struct data_blob_list_item);
598         if (!rep) {
599                 return NT_STATUS_NO_MEMORY;
600         }
601
602         status = ncacn_push_auth(&rep->blob, call, &pkt, 
603                                   call->conn->auth_state.auth_info);
604         if (!NT_STATUS_IS_OK(status)) {
605                 return status;
606         }
607
608         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
609
610         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
611         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
612
613         return NT_STATUS_OK;
614 }
615
616
617 /*
618   handle a auth3 request
619 */
620 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
621 {
622         /* handle the auth3 in the auth code */
623         if (!dcesrv_auth_auth3(call)) {
624                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
625         }
626
627         talloc_free(call);
628
629         /* we don't send a reply to a auth3 request, except by a
630            fault */
631         return NT_STATUS_OK;
632 }
633
634
635 /*
636   handle a bind request
637 */
638 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
639 {
640         uint32_t if_version, transfer_syntax_version;
641         struct dcesrv_connection_context *context;
642         const struct dcesrv_interface *iface;
643         struct GUID uuid, *transfer_syntax_uuid;
644
645         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
646         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
647
648         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
649         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
650         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
651             ndr_transfer_syntax.if_version != transfer_syntax_version) {
652                 /* we only do NDR encoded dcerpc */
653                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
654         }
655
656         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
657         if (iface == NULL) {
658                 char *uuid_str = GUID_string(call, &uuid);
659                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
660                 talloc_free(uuid_str);
661                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
662         }
663
664         /* add this context to the list of available context_ids */
665         context = talloc(call->conn, struct dcesrv_connection_context);
666         if (context == NULL) {
667                 return NT_STATUS_NO_MEMORY;
668         }
669         context->conn = call->conn;
670         context->iface = iface;
671         context->context_id = context_id;
672         context->private = NULL;
673         context->handles = NULL;
674         DLIST_ADD(call->conn->contexts, context);
675         call->context = context;
676
677         return NT_STATUS_OK;
678 }
679
680
681 /*
682   handle a alter context request
683 */
684 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
685 {
686         struct ncacn_packet pkt;
687         struct data_blob_list_item *rep;
688         NTSTATUS status;
689         uint32_t result=0, reason=0;
690         uint32_t context_id;
691
692         /* handle any authentication that is being requested */
693         if (!dcesrv_auth_alter(call)) {
694                 /* TODO: work out the right reject code */
695                 result = DCERPC_BIND_PROVIDER_REJECT;
696                 reason = DCERPC_BIND_REASON_ASYNTAX;            
697         }
698
699         context_id = call->pkt.u.alter.ctx_list[0].context_id;
700
701         /* see if they are asking for a new interface */
702         if (result == 0 &&
703             dcesrv_find_context(call->conn, context_id) == NULL) {
704                 status = dcesrv_alter_new_context(call, context_id);
705                 if (!NT_STATUS_IS_OK(status)) {
706                         result = DCERPC_BIND_PROVIDER_REJECT;
707                         reason = DCERPC_BIND_REASON_ASYNTAX;            
708                 }
709         }
710
711         /* setup a alter_resp */
712         dcesrv_init_hdr(&pkt);
713         pkt.auth_length = 0;
714         pkt.call_id = call->pkt.call_id;
715         pkt.ptype = DCERPC_PKT_ALTER_RESP;
716         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
717         pkt.u.alter_resp.max_xmit_frag = 0x2000;
718         pkt.u.alter_resp.max_recv_frag = 0x2000;
719         pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
720         pkt.u.alter_resp.num_results = 1;
721         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
722         if (!pkt.u.alter_resp.ctx_list) {
723                 return NT_STATUS_NO_MEMORY;
724         }
725         pkt.u.alter_resp.ctx_list[0].result = result;
726         pkt.u.alter_resp.ctx_list[0].reason = reason;
727         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
728         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
729         pkt.u.alter_resp.secondary_address = "";
730
731         if (!dcesrv_auth_alter_ack(call, &pkt)) {
732                 return dcesrv_bind_nak(call, 0);
733         }
734
735         rep = talloc(call, struct data_blob_list_item);
736         if (!rep) {
737                 return NT_STATUS_NO_MEMORY;
738         }
739
740         status = ncacn_push_auth(&rep->blob, call, &pkt, 
741                                   call->conn->auth_state.auth_info);
742         if (!NT_STATUS_IS_OK(status)) {
743                 return status;
744         }
745
746         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
747
748         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
749         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
750
751         return NT_STATUS_OK;
752 }
753
754 /*
755   handle a dcerpc request packet
756 */
757 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
758 {
759         struct ndr_pull *pull;
760         NTSTATUS status;
761         struct dcesrv_connection_context *context;
762
763         /* if authenticated, and the mech we use can't do async replies, don't use them... */
764         if (call->conn->auth_state.gensec_security && 
765             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
766                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
767         }
768
769         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
770         if (context == NULL) {
771                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
772         }
773
774         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
775         NT_STATUS_HAVE_NO_MEMORY(pull);
776
777         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
778
779         call->context   = context;
780         call->ndr_pull  = pull;
781
782         if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
783                 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
784         }
785
786         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
787                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
788         }
789
790         /* unravel the NDR for the packet */
791         status = context->iface->ndr_pull(call, call, pull, &call->r);
792         if (!NT_STATUS_IS_OK(status)) {
793                 return dcesrv_fault(call, call->fault_code);
794         }
795
796         if (pull->offset != pull->data_size) {
797                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
798                          pull->data_size - pull->offset));
799                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
800         }
801
802         /* call the dispatch function */
803         status = context->iface->dispatch(call, call, call->r);
804         if (!NT_STATUS_IS_OK(status)) {
805                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
806                          context->iface->name, 
807                          call->pkt.u.request.opnum,
808                          dcerpc_errstr(pull, call->fault_code)));
809                 return dcesrv_fault(call, call->fault_code);
810         }
811
812         /* add the call to the pending list */
813         DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
814
815         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
816                 return NT_STATUS_OK;
817         }
818
819         return dcesrv_reply(call);
820 }
821
822 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
823 {
824         struct ndr_push *push;
825         NTSTATUS status;
826         DATA_BLOB stub;
827         uint32_t total_length;
828         struct dcesrv_connection_context *context = call->context;
829
830         /* call the reply function */
831         status = context->iface->reply(call, call, call->r);
832         if (!NT_STATUS_IS_OK(status)) {
833                 return dcesrv_fault(call, call->fault_code);
834         }
835
836         /* form the reply NDR */
837         push = ndr_push_init_ctx(call);
838         NT_STATUS_HAVE_NO_MEMORY(push);
839
840         /* carry over the pointer count to the reply in case we are
841            using full pointer. See NDR specification for full
842            pointers */
843         push->ptr_count = call->ndr_pull->ptr_count;
844
845         if (lp_rpc_big_endian()) {
846                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
847         }
848
849         status = context->iface->ndr_push(call, call, push, call->r);
850         if (!NT_STATUS_IS_OK(status)) {
851                 return dcesrv_fault(call, call->fault_code);
852         }
853
854         stub = ndr_push_blob(push);
855
856         total_length = stub.length;
857
858         do {
859                 uint32_t length;
860                 struct data_blob_list_item *rep;
861                 struct ncacn_packet pkt;
862
863                 rep = talloc(call, struct data_blob_list_item);
864                 NT_STATUS_HAVE_NO_MEMORY(rep);
865
866                 length = stub.length;
867                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
868                         /* the 32 is to cope with signing data */
869                         length = call->conn->cli_max_recv_frag - 
870                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
871                 }
872
873                 /* form the dcerpc response packet */
874                 dcesrv_init_hdr(&pkt);
875                 pkt.auth_length = 0;
876                 pkt.call_id = call->pkt.call_id;
877                 pkt.ptype = DCERPC_PKT_RESPONSE;
878                 pkt.pfc_flags = 0;
879                 if (stub.length == total_length) {
880                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
881                 }
882                 if (length == stub.length) {
883                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
884                 }
885                 pkt.u.response.alloc_hint = stub.length;
886                 pkt.u.response.context_id = call->pkt.u.request.context_id;
887                 pkt.u.response.cancel_count = 0;
888                 pkt.u.response.stub_and_verifier.data = stub.data;
889                 pkt.u.response.stub_and_verifier.length = length;
890
891                 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
892                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
893                 }
894
895                 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
896
897                 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
898                 
899                 stub.data += length;
900                 stub.length -= length;
901         } while (stub.length != 0);
902
903         /* move the call from the pending to the finished calls list */
904         DLIST_REMOVE(call->conn->pending_call_list, call);
905         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
906
907         if (call->conn->call_list && call->conn->call_list->replies) {
908                 if (call->conn->transport.report_output_data) {
909                         call->conn->transport.report_output_data(call->conn);
910                 }
911         }
912
913         return NT_STATUS_OK;
914 }
915
916 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
917 {
918         if (!conn->transport.get_my_addr) {
919                 return NULL;
920         }
921
922         return conn->transport.get_my_addr(conn, mem_ctx);
923 }
924
925 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
926 {
927         if (!conn->transport.get_peer_addr) {
928                 return NULL;
929         }
930
931         return conn->transport.get_peer_addr(conn, mem_ctx);
932 }
933
934 /*
935   work out if we have a full packet yet
936 */
937 static BOOL dce_full_packet(const DATA_BLOB *data)
938 {
939         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
940                 return False;
941         }
942         if (dcerpc_get_frag_length(data) > data->length) {
943                 return False;
944         }
945         return True;
946 }
947
948 /*
949   we might have consumed only part of our input - advance past that part
950 */
951 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
952 {
953         DATA_BLOB blob;
954
955         if (dce_conn->partial_input.length == offset) {
956                 data_blob_free(&dce_conn->partial_input);
957                 return;
958         }
959
960         blob = dce_conn->partial_input;
961         dce_conn->partial_input = data_blob(blob.data + offset,
962                                             blob.length - offset);
963         data_blob_free(&blob);
964 }
965
966 /*
967   process some input to a dcerpc endpoint server.
968 */
969 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
970 {
971         struct ndr_pull *ndr;
972         NTSTATUS status;
973         struct dcesrv_call_state *call;
974         DATA_BLOB blob;
975
976         call = talloc_zero(dce_conn, struct dcesrv_call_state);
977         if (!call) {
978                 talloc_free(dce_conn->partial_input.data);
979                 return NT_STATUS_NO_MEMORY;
980         }
981         call->conn              = dce_conn;
982         call->event_ctx         = dce_conn->event_ctx;
983         call->msg_ctx           = dce_conn->msg_ctx;
984         call->state_flags       = call->conn->state_flags;
985         call->time              = timeval_current();
986
987         blob = dce_conn->partial_input;
988         blob.length = dcerpc_get_frag_length(&blob);
989
990         ndr = ndr_pull_init_blob(&blob, call);
991         if (!ndr) {
992                 talloc_free(dce_conn->partial_input.data);
993                 talloc_free(call);
994                 return NT_STATUS_NO_MEMORY;
995         }
996
997         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
998                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
999         }
1000
1001         status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1002         if (!NT_STATUS_IS_OK(status)) {
1003                 talloc_free(dce_conn->partial_input.data);
1004                 talloc_free(call);
1005                 return status;
1006         }
1007
1008         /* we have to check the signing here, before combining the
1009            pdus */
1010         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1011             !dcesrv_auth_request(call, &blob)) {
1012                 dce_partial_advance(dce_conn, blob.length);
1013                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1014         }
1015
1016         dce_partial_advance(dce_conn, blob.length);
1017
1018         /* see if this is a continued packet */
1019         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1020             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1021                 struct dcesrv_call_state *call2 = call;
1022                 uint32_t alloc_size;
1023
1024                 /* we only allow fragmented requests, no other packet types */
1025                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1026                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1027                 }
1028
1029                 /* this is a continuation of an existing call - find the call then
1030                    tack it on the end */
1031                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1032                 if (!call) {
1033                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1034                 }
1035
1036                 if (call->pkt.ptype != call2->pkt.ptype) {
1037                         /* trying to play silly buggers are we? */
1038                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1039                 }
1040
1041                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1042                         call2->pkt.u.request.stub_and_verifier.length;
1043                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1044                         alloc_size = call->pkt.u.request.alloc_hint;
1045                 }
1046
1047                 call->pkt.u.request.stub_and_verifier.data = 
1048                         talloc_realloc(call, 
1049                                        call->pkt.u.request.stub_and_verifier.data, 
1050                                        uint8_t, alloc_size);
1051                 if (!call->pkt.u.request.stub_and_verifier.data) {
1052                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1053                 }
1054                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1055                        call->pkt.u.request.stub_and_verifier.length,
1056                        call2->pkt.u.request.stub_and_verifier.data,
1057                        call2->pkt.u.request.stub_and_verifier.length);
1058                 call->pkt.u.request.stub_and_verifier.length += 
1059                         call2->pkt.u.request.stub_and_verifier.length;
1060
1061                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1062
1063                 talloc_free(call2);
1064         }
1065
1066         /* this may not be the last pdu in the chain - if its isn't then
1067            just put it on the incoming_fragmented_call_list and wait for the rest */
1068         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1069             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1070                 DLIST_ADD_END(dce_conn->incoming_fragmented_call_list, call, 
1071                               struct dcesrv_call_state *);
1072                 return NT_STATUS_OK;
1073         } 
1074         
1075         /* This removes any fragments we may have had stashed away */
1076         DLIST_REMOVE(dce_conn->incoming_fragmented_call_list, call);
1077
1078         switch (call->pkt.ptype) {
1079         case DCERPC_PKT_BIND:
1080                 status = dcesrv_bind(call);
1081                 break;
1082         case DCERPC_PKT_AUTH3:
1083                 status = dcesrv_auth3(call);
1084                 break;
1085         case DCERPC_PKT_ALTER:
1086                 status = dcesrv_alter(call);
1087                 break;
1088         case DCERPC_PKT_REQUEST:
1089                 status = dcesrv_request(call);
1090                 break;
1091         default:
1092                 status = NT_STATUS_INVALID_PARAMETER;
1093                 break;
1094         }
1095
1096         /* if we are going to be sending a reply then add
1097            it to the list of pending calls. We add it to the end to keep the call
1098            list in the order we will answer */
1099         if (!NT_STATUS_IS_OK(status)) {
1100                 talloc_free(call);
1101         }
1102
1103         return status;
1104 }
1105
1106
1107 /*
1108   provide some input to a dcerpc endpoint server. This passes data
1109   from a dcerpc client into the server
1110 */
1111 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1112 {
1113         NTSTATUS status;
1114
1115         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1116                                                       dce_conn->partial_input.data,
1117                                                       uint8_t,
1118                                                       dce_conn->partial_input.length + data->length);
1119         if (!dce_conn->partial_input.data) {
1120                 return NT_STATUS_NO_MEMORY;
1121         }
1122         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1123                data->data, data->length);
1124         dce_conn->partial_input.length += data->length;
1125
1126         while (dce_full_packet(&dce_conn->partial_input)) {
1127                 status = dcesrv_input_process(dce_conn);
1128                 if (!NT_STATUS_IS_OK(status)) {
1129                         return status;
1130                 }
1131         }
1132
1133         return NT_STATUS_OK;
1134 }
1135
1136 /*
1137   retrieve some output from a dcerpc server
1138   The caller supplies a function that will be called to do the
1139   actual output. 
1140
1141   The first argument to write_fn() will be 'private', the second will
1142   be a pointer to a buffer containing the data to be sent and the 3rd
1143   will be a pointer to a size_t variable that will be set to the
1144   number of bytes that are consumed from the output.
1145
1146   from the current fragment
1147 */
1148 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1149                        void *private_data,
1150                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1151 {
1152         NTSTATUS status;
1153         struct dcesrv_call_state *call;
1154         struct data_blob_list_item *rep;
1155         size_t nwritten;
1156
1157         call = dce_conn->call_list;
1158         if (!call || !call->replies) {
1159                 if (dce_conn->pending_call_list) {
1160                         /* TODO: we need to say act async here
1161                          *       as we know we have pending requests
1162                          *       which will be finished at a time
1163                          */
1164                         return NT_STATUS_FOOBAR;
1165                 }
1166                 return NT_STATUS_FOOBAR;
1167         }
1168         rep = call->replies;
1169
1170         status = write_fn(private_data, &rep->blob, &nwritten);
1171         NT_STATUS_IS_ERR_RETURN(status);
1172
1173         rep->blob.length -= nwritten;
1174         rep->blob.data += nwritten;
1175
1176         if (rep->blob.length == 0) {
1177                 /* we're done with this section of the call */
1178                 DLIST_REMOVE(call->replies, rep);
1179         }
1180
1181         if (call->replies == NULL) {
1182                 /* we're done with the whole call */
1183                 DLIST_REMOVE(dce_conn->call_list, call);
1184                 talloc_free(call);
1185         }
1186
1187         return status;
1188 }
1189
1190 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1191 {
1192         NTSTATUS status;
1193         struct dcesrv_context *dce_ctx;
1194         int i;
1195
1196         if (!endpoint_servers) {
1197                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1198                 return NT_STATUS_INTERNAL_ERROR;
1199         }
1200
1201         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1202         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1203         dce_ctx->endpoint_list  = NULL;
1204
1205         for (i=0;endpoint_servers[i];i++) {
1206                 const struct dcesrv_endpoint_server *ep_server;
1207
1208                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1209                 if (!ep_server) {
1210                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1211                         return NT_STATUS_INTERNAL_ERROR;
1212                 }
1213
1214                 status = ep_server->init_server(dce_ctx, ep_server);
1215                 if (!NT_STATUS_IS_OK(status)) {
1216                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1217                                 nt_errstr(status)));
1218                         return status;
1219                 }
1220         }
1221
1222         *_dce_ctx = dce_ctx;
1223         return NT_STATUS_OK;
1224 }
1225
1226 /*
1227   initialise the dcerpc server context for ncacn_np based services
1228 */
1229 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1230 {
1231         NTSTATUS status;
1232         struct dcesrv_context *dce_ctx;
1233
1234         status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1235         NT_STATUS_NOT_OK_RETURN(status);
1236
1237         *_dce_ctx = dce_ctx;
1238         return NT_STATUS_OK;
1239 }
1240
1241 /* the list of currently registered DCERPC endpoint servers.
1242  */
1243 static struct ep_server {
1244         struct dcesrv_endpoint_server *ep_server;
1245 } *ep_servers = NULL;
1246 static int num_ep_servers;
1247
1248 /*
1249   register a DCERPC endpoint server. 
1250
1251   The 'name' can be later used by other backends to find the operations
1252   structure for this backend.  
1253
1254   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1255 */
1256 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1257 {
1258         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1259         
1260         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1261                 /* its already registered! */
1262                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1263                          ep_server->name));
1264                 return NT_STATUS_OBJECT_NAME_COLLISION;
1265         }
1266
1267         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1268         if (!ep_servers) {
1269                 smb_panic("out of memory in dcerpc_register");
1270         }
1271
1272         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1273         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1274
1275         num_ep_servers++;
1276
1277         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1278                  ep_server->name));
1279
1280         return NT_STATUS_OK;
1281 }
1282
1283 /*
1284   return the operations structure for a named backend of the specified type
1285 */
1286 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1287 {
1288         int i;
1289
1290         for (i=0;i<num_ep_servers;i++) {
1291                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1292                         return ep_servers[i].ep_server;
1293                 }
1294         }
1295
1296         return NULL;
1297 }
1298
1299 /*
1300   return the DCERPC module version, and the size of some critical types
1301   This can be used by endpoint server modules to either detect compilation errors, or provide
1302   multiple implementations for different smbd compilation options in one module
1303 */
1304 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1305 {
1306         static const struct dcesrv_critical_sizes critical_sizes = {
1307                 DCERPC_MODULE_VERSION,
1308                 sizeof(struct dcesrv_context),
1309                 sizeof(struct dcesrv_endpoint),
1310                 sizeof(struct dcesrv_endpoint_server),
1311                 sizeof(struct dcesrv_interface),
1312                 sizeof(struct dcesrv_if_list),
1313                 sizeof(struct dcesrv_connection),
1314                 sizeof(struct dcesrv_call_state),
1315                 sizeof(struct dcesrv_auth),
1316                 sizeof(struct dcesrv_handle)
1317         };
1318
1319         return &critical_sizes;
1320 }
1321
1322 /*
1323   open the dcerpc server sockets
1324 */
1325 static void dcesrv_task_init(struct task_server *task)
1326 {
1327         NTSTATUS status;
1328         struct dcesrv_context *dce_ctx;
1329         struct dcesrv_endpoint *e;
1330
1331         task_server_set_title(task, "task[dcesrv]");
1332
1333         status = dcesrv_init_context(task->event_ctx,
1334                                      lp_dcerpc_endpoint_servers(),
1335                                      &dce_ctx);
1336         if (!NT_STATUS_IS_OK(status)) goto failed;
1337
1338         /* Make sure the directory for NCALRPC exists */
1339         if (!directory_exist(lp_ncalrpc_dir())) {
1340                 mkdir(lp_ncalrpc_dir(), 0755);
1341         }
1342
1343         for (e=dce_ctx->endpoint_list;e;e=e->next) {
1344                 switch (e->ep_description->transport) {
1345                 case NCACN_UNIX_STREAM:
1346                         status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1347                         if (!NT_STATUS_IS_OK(status)) goto failed;
1348                         break;
1349                 
1350                 case NCALRPC:
1351                         status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1352                         if (!NT_STATUS_IS_OK(status)) goto failed;
1353                         break;
1354
1355                 case NCACN_IP_TCP:
1356                         status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1357                         if (!NT_STATUS_IS_OK(status)) goto failed;
1358                         break;
1359                         
1360                 case NCACN_NP:
1361 /*                      FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1362                         if (!NT_STATUS_IS_OK(status)) goto failed;
1363 */                      break;
1364
1365                 default:
1366                         status = NT_STATUS_NOT_SUPPORTED;
1367                         if (!NT_STATUS_IS_OK(status)) goto failed;
1368                 }
1369         }
1370
1371         return;
1372 failed:
1373         task_server_terminate(task, "Failed to startup dcerpc server task");    
1374 }
1375
1376 /*
1377   called on startup of the smb server service It's job is to start
1378   listening on all configured sockets
1379 */
1380 static NTSTATUS dcesrv_init(struct event_context *event_context, 
1381                             const struct model_ops *model_ops)
1382 {       
1383         return task_server_startup(event_context, model_ops, dcesrv_task_init);
1384 }
1385
1386 NTSTATUS server_service_rpc_init(void)
1387 {
1388         init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1389         init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1390
1391         run_init_functions(static_init);
1392         run_init_functions(shared_init);
1393
1394         talloc_free(shared_init);
1395         
1396         return register_server_service("rpc", dcesrv_init);
1397 }