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