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