r8023: use a pointer to a DATA_BLOB for each reply,
[kai/samba.git] / source / 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 "lib/events/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 = talloc_reference(ep, 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         p->processing = False;
324
325         talloc_set_destructor(p, dcesrv_endpoint_destructor);
326
327         *_p = p;
328         return NT_STATUS_OK;
329 }
330
331 /*
332   search and connect to a dcerpc endpoint
333 */
334 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
335                                         TALLOC_CTX *mem_ctx,
336                                         const struct dcerpc_binding *ep_description,
337                                         struct auth_session_info *session_info,
338                                         struct stream_connection *srv_conn,
339                                         struct dcesrv_connection **dce_conn_p)
340 {
341         NTSTATUS status;
342         const struct dcesrv_endpoint *ep;
343
344         /* make sure this endpoint exists */
345         ep = find_endpoint(dce_ctx, ep_description);
346         if (!ep) {
347                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
348         }
349
350         status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, srv_conn, dce_conn_p);
351         if (!NT_STATUS_IS_OK(status)) {
352                 return status;
353         }
354
355         (*dce_conn_p)->auth_state.session_info = talloc_reference((*dce_conn_p), session_info);
356         (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
357
358         /* TODO: check security descriptor of the endpoint here 
359          *       if it's a smb named pipe
360          *       if it's failed free dce_conn_p
361          */
362
363         return NT_STATUS_OK;
364 }
365
366
367 static void dcesrv_init_hdr(struct ncacn_packet *pkt)
368 {
369         pkt->rpc_vers = 5;
370         pkt->rpc_vers_minor = 0;
371         if (lp_rpc_big_endian()) {
372                 pkt->drep[0] = 0;
373         } else {
374                 pkt->drep[0] = DCERPC_DREP_LE;
375         }
376         pkt->drep[1] = 0;
377         pkt->drep[2] = 0;
378         pkt->drep[3] = 0;
379 }
380
381 /*
382   return a dcerpc fault
383 */
384 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
385 {
386         struct ncacn_packet pkt;
387         struct dcesrv_call_reply *rep;
388         NTSTATUS status;
389
390         /* setup a bind_ack */
391         dcesrv_init_hdr(&pkt);
392         pkt.auth_length = 0;
393         pkt.call_id = call->pkt.call_id;
394         pkt.ptype = DCERPC_PKT_FAULT;
395         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
396         pkt.u.fault.alloc_hint = 0;
397         pkt.u.fault.context_id = 0;
398         pkt.u.fault.cancel_count = 0;
399         pkt.u.fault.status = fault_code;
400
401         rep = talloc(call, struct dcesrv_call_reply);
402         NT_STATUS_HAVE_NO_MEMORY(rep);
403
404         rep->data = talloc(call, DATA_BLOB);
405         NT_STATUS_HAVE_NO_MEMORY(rep->data);
406
407         status = ncacn_push_auth(rep->data, call, &pkt, NULL);
408         NT_STATUS_NOT_OK_RETURN(status);
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 ncacn_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         NT_STATUS_HAVE_NO_MEMORY(rep);
439
440         rep->data = talloc(call, DATA_BLOB);
441         NT_STATUS_HAVE_NO_MEMORY(rep->data);
442
443         status = ncacn_push_auth(rep->data, call, &pkt, NULL);
444         NT_STATUS_NOT_OK_RETURN(status);
445
446         dcerpc_set_frag_length(rep->data, rep->data->length);
447
448         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
449         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
450
451         return NT_STATUS_OK;    
452 }
453
454
455 /*
456   handle a bind request
457 */
458 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
459 {
460         const char *uuid, *transfer_syntax;
461         uint32_t if_version, transfer_syntax_version;
462         struct ncacn_packet pkt;
463         struct dcesrv_call_reply *rep;
464         NTSTATUS status;
465         uint32_t result=0, reason=0;
466         uint32_t context_id;
467         const struct dcesrv_interface *iface;
468
469         if (call->pkt.u.bind.num_contexts < 1 ||
470             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
471                 return dcesrv_bind_nak(call, 0);
472         }
473
474         context_id = call->pkt.u.bind.ctx_list[0].context_id;
475
476         /* you can't bind twice on one context */
477         if (dcesrv_find_context(call->conn, context_id) != NULL) {
478                 return dcesrv_bind_nak(call, 0);
479         }
480
481         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
482         uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
483         if (!uuid) {
484                 return dcesrv_bind_nak(call, 0);
485         }
486
487         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
488         transfer_syntax = GUID_string(call, 
489                                       &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
490         if (!transfer_syntax ||
491             strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
492             NDR_GUID_VERSION != transfer_syntax_version) {
493                 /* we only do NDR encoded dcerpc */
494                 DEBUG(0,("Non NDR transfer syntax requested - %s\n", transfer_syntax));
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         NT_STATUS_HAVE_NO_MEMORY(rep);
573
574         rep->data = talloc(call, DATA_BLOB);
575         NT_STATUS_HAVE_NO_MEMORY(rep->data);
576
577         status = ncacn_push_auth(rep->data, call, &pkt, 
578                                  call->conn->auth_state.auth_info);
579         NT_STATUS_NOT_OK_RETURN(status);
580
581         dcerpc_set_frag_length(rep->data, rep->data->length);
582
583         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
584         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
585
586         return NT_STATUS_OK;
587 }
588
589
590 /*
591   handle a auth3 request
592 */
593 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
594 {
595         /* handle the auth3 in the auth code */
596         if (!dcesrv_auth_auth3(call)) {
597                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
598         }
599
600         talloc_free(call);
601
602         /* we don't send a reply to a auth3 request, except by a
603            fault */
604         return NT_STATUS_OK;
605 }
606
607
608 /*
609   handle a bind request
610 */
611 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
612 {
613         uint32_t if_version, transfer_syntax_version;
614         const char *uuid, *transfer_syntax;
615         struct dcesrv_connection_context *context;
616         const struct dcesrv_interface *iface;
617
618         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
619         uuid = GUID_string(call, &call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid);
620         if (!uuid) {
621                 return NT_STATUS_NO_MEMORY;
622         }
623
624         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
625         transfer_syntax = GUID_string(call, 
626                                       &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid);
627         if (!transfer_syntax ||
628             strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
629             NDR_GUID_VERSION != transfer_syntax_version) {
630                 /* we only do NDR encoded dcerpc */
631                 return NT_STATUS_NO_MEMORY;
632         }
633
634         iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
635         if (iface == NULL) {
636                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
637                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
638         }
639
640         /* add this context to the list of available context_ids */
641         context = talloc(call->conn, struct dcesrv_connection_context);
642         if (context == NULL) {
643                 return NT_STATUS_NO_MEMORY;
644         }
645         context->conn = call->conn;
646         context->iface = iface;
647         context->context_id = context_id;
648         context->private = NULL;
649         context->handles = NULL;
650         DLIST_ADD(call->conn->contexts, context);
651         call->context = context;
652
653         return NT_STATUS_OK;
654 }
655
656
657 /*
658   handle a bind request
659 */
660 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
661 {
662         struct ncacn_packet pkt;
663         struct dcesrv_call_reply *rep;
664         NTSTATUS status;
665         uint32_t result=0, reason=0;
666         uint32_t context_id;
667
668         /* handle any authentication that is being requested */
669         if (!dcesrv_auth_alter(call)) {
670                 /* TODO: work out the right reject code */
671                 result = DCERPC_BIND_PROVIDER_REJECT;
672                 reason = DCERPC_BIND_REASON_ASYNTAX;            
673         }
674
675         context_id = call->pkt.u.alter.ctx_list[0].context_id;
676
677         /* see if they are asking for a new interface */
678         if (result == 0 &&
679             dcesrv_find_context(call->conn, context_id) == NULL) {
680                 status = dcesrv_alter_new_context(call, context_id);
681                 if (!NT_STATUS_IS_OK(status)) {
682                         result = DCERPC_BIND_PROVIDER_REJECT;
683                         reason = DCERPC_BIND_REASON_ASYNTAX;            
684                 }
685         }
686
687         /* setup a alter_resp */
688         dcesrv_init_hdr(&pkt);
689         pkt.auth_length = 0;
690         pkt.call_id = call->pkt.call_id;
691         pkt.ptype = DCERPC_PKT_ALTER_RESP;
692         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
693         pkt.u.alter_resp.max_xmit_frag = 0x2000;
694         pkt.u.alter_resp.max_recv_frag = 0x2000;
695         pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
696         pkt.u.alter_resp.num_results = 1;
697         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
698         if (!pkt.u.alter_resp.ctx_list) {
699                 return NT_STATUS_NO_MEMORY;
700         }
701         pkt.u.alter_resp.ctx_list[0].result = result;
702         pkt.u.alter_resp.ctx_list[0].reason = reason;
703         GUID_from_string(NDR_GUID, &pkt.u.alter_resp.ctx_list[0].syntax.uuid);
704         pkt.u.alter_resp.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
705         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
706         pkt.u.alter_resp.secondary_address = "";
707
708         if (!dcesrv_auth_alter_ack(call, &pkt)) {
709                 return dcesrv_bind_nak(call, 0);
710         }
711
712         rep = talloc(call, struct dcesrv_call_reply);
713         NT_STATUS_HAVE_NO_MEMORY(rep);
714
715         rep->data = talloc(call, DATA_BLOB);
716         NT_STATUS_HAVE_NO_MEMORY(rep->data);
717
718         status = ncacn_push_auth(rep->data, call, &pkt, 
719                                  call->conn->auth_state.auth_info);
720         NT_STATUS_IS_OK_RETURN(status);
721
722         dcerpc_set_frag_length(rep->data, rep->data->length);
723
724         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
725         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
726
727         return NT_STATUS_OK;
728 }
729
730 /*
731   handle a dcerpc request packet
732 */
733 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
734 {
735         struct ndr_pull *pull;
736         NTSTATUS status;
737         struct dcesrv_connection_context *context;
738
739         call->fault_code        = 0;
740         call->state_flags       = call->conn->dce_ctx->state_flags;
741         call->time              = timeval_current();
742
743         /* if authenticated, and the mech we use can't do async replies, don't use them... */
744         if (call->conn->auth_state.gensec_security && 
745             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
746                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
747         }
748
749         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
750         if (context == NULL) {
751                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
752         }
753
754         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
755         NT_STATUS_HAVE_NO_MEMORY(pull);
756
757         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
758
759         call->context   = context;
760         call->event_ctx = context->conn->srv_conn->event.ctx;
761         call->ndr_pull  = pull;
762
763         if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
764                 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
765         }
766
767         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
768                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
769         }
770
771         /* unravel the NDR for the packet */
772         status = context->iface->ndr_pull(call, call, pull, &call->r);
773         if (!NT_STATUS_IS_OK(status)) {
774                 return dcesrv_fault(call, call->fault_code);
775         }
776
777         if (pull->offset != pull->data_size) {
778                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
779                          pull->data_size - pull->offset));
780                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
781         }
782
783         /* call the dispatch function */
784         status = context->iface->dispatch(call, call, call->r);
785         if (!NT_STATUS_IS_OK(status)) {
786                 return dcesrv_fault(call, call->fault_code);
787         }
788
789         /* add the call to the pending list */
790         DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
791
792         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
793                 return NT_STATUS_OK;
794         }
795
796         return dcesrv_reply(call);
797 }
798
799 NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
800 {
801         struct ndr_push *push;
802         NTSTATUS status;
803         DATA_BLOB stub;
804         uint32_t total_length;
805         struct dcesrv_connection_context *context = call->context;
806
807         /* call the reply function */
808         status = context->iface->reply(call, call, call->r);
809         if (!NT_STATUS_IS_OK(status)) {
810                 return dcesrv_fault(call, call->fault_code);
811         }
812
813         /* form the reply NDR */
814         push = ndr_push_init_ctx(call);
815         NT_STATUS_HAVE_NO_MEMORY(push);
816
817         /* carry over the pointer count to the reply in case we are
818            using full pointer. See NDR specification for full
819            pointers */
820         push->ptr_count = call->ndr_pull->ptr_count;
821
822         if (lp_rpc_big_endian()) {
823                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
824         }
825
826         status = context->iface->ndr_push(call, call, push, call->r);
827         if (!NT_STATUS_IS_OK(status)) {
828                 return dcesrv_fault(call, call->fault_code);
829         }
830
831         stub = ndr_push_blob(push);
832
833         total_length = stub.length;
834
835         do {
836                 uint32_t length;
837                 struct dcesrv_call_reply *rep;
838                 struct ncacn_packet pkt;
839
840                 rep = talloc(call, struct dcesrv_call_reply);
841                 NT_STATUS_HAVE_NO_MEMORY(rep);
842
843                 rep->data = talloc(call, DATA_BLOB);
844                 NT_STATUS_HAVE_NO_MEMORY(rep->data);
845
846                 length = stub.length;
847                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
848                         /* the 32 is to cope with signing data */
849                         length = call->conn->cli_max_recv_frag - 
850                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
851                 }
852
853                 /* form the dcerpc response packet */
854                 dcesrv_init_hdr(&pkt);
855                 pkt.auth_length = 0;
856                 pkt.call_id = call->pkt.call_id;
857                 pkt.ptype = DCERPC_PKT_RESPONSE;
858                 pkt.pfc_flags = 0;
859                 if (stub.length == total_length) {
860                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
861                 }
862                 if (length == stub.length) {
863                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
864                 }
865                 pkt.u.response.alloc_hint = stub.length;
866                 pkt.u.response.context_id = call->pkt.u.request.context_id;
867                 pkt.u.response.cancel_count = 0;
868                 pkt.u.response.stub_and_verifier.data = stub.data;
869                 pkt.u.response.stub_and_verifier.length = length;
870
871                 if (!dcesrv_auth_response(call, rep->data, &pkt)) {
872                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
873                 }
874
875                 dcerpc_set_frag_length(rep->data, rep->data->length);
876
877                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
878                 
879                 stub.data += length;
880                 stub.length -= length;
881         } while (stub.length != 0);
882
883         /* move the call from the pending to the finished calls list */
884         DLIST_REMOVE(call->conn->pending_call_list, call);
885         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
886
887         if (call->conn->call_list && call->conn->call_list->replies) {
888                 if (call->conn->srv_conn &&
889                     call->conn->srv_conn->event.fde) {
890                         EVENT_FD_WRITEABLE(call->conn->srv_conn->event.fde);
891                 }
892         }
893
894         return NT_STATUS_OK;
895 }
896
897
898 /*
899   work out if we have a full packet yet
900 */
901 static BOOL dce_full_packet(const DATA_BLOB *data)
902 {
903         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
904                 return False;
905         }
906         if (dcerpc_get_frag_length(data) > data->length) {
907                 return False;
908         }
909         return True;
910 }
911
912 /*
913   we might have consumed only part of our input - advance past that part
914 */
915 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
916 {
917         DATA_BLOB blob;
918
919         if (dce_conn->partial_input.length == offset) {
920                 data_blob_free(&dce_conn->partial_input);
921                 return;
922         }
923
924         blob = dce_conn->partial_input;
925         dce_conn->partial_input = data_blob(blob.data + offset,
926                                             blob.length - offset);
927         data_blob_free(&blob);
928 }
929
930 /*
931   process some input to a dcerpc endpoint server.
932 */
933 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
934 {
935         struct ndr_pull *ndr;
936         NTSTATUS status;
937         struct dcesrv_call_state *call;
938         DATA_BLOB blob;
939
940         call = talloc(dce_conn, struct dcesrv_call_state);
941         if (!call) {
942                 talloc_free(dce_conn->partial_input.data);
943                 return NT_STATUS_NO_MEMORY;
944         }
945         call->conn      = dce_conn;
946         call->replies   = NULL;
947         call->context   = NULL;
948         call->event_ctx = dce_conn->srv_conn->event.ctx;
949
950         blob = dce_conn->partial_input;
951         blob.length = dcerpc_get_frag_length(&blob);
952
953         ndr = ndr_pull_init_blob(&blob, call);
954         if (!ndr) {
955                 talloc_free(dce_conn->partial_input.data);
956                 talloc_free(call);
957                 return NT_STATUS_NO_MEMORY;
958         }
959
960         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
961                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
962         }
963
964         status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
965         if (!NT_STATUS_IS_OK(status)) {
966                 talloc_free(dce_conn->partial_input.data);
967                 talloc_free(call);
968                 return status;
969         }
970
971         /* we have to check the signing here, before combining the
972            pdus */
973         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
974             !dcesrv_auth_request(call, &blob)) {
975                 dce_partial_advance(dce_conn, blob.length);
976                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
977         }
978
979         dce_partial_advance(dce_conn, blob.length);
980
981         /* see if this is a continued packet */
982         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
983             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
984                 struct dcesrv_call_state *call2 = call;
985                 uint32_t alloc_size;
986
987                 /* we only allow fragmented requests, no other packet types */
988                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
989                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
990                 }
991
992                 /* this is a continuation of an existing call - find the call then
993                    tack it on the end */
994                 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
995                 if (!call) {
996                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
997                 }
998
999                 if (call->pkt.ptype != call2->pkt.ptype) {
1000                         /* trying to play silly buggers are we? */
1001                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1002                 }
1003
1004                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1005                         call2->pkt.u.request.stub_and_verifier.length;
1006                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1007                         alloc_size = call->pkt.u.request.alloc_hint;
1008                 }
1009
1010                 call->pkt.u.request.stub_and_verifier.data = 
1011                         talloc_realloc(call, 
1012                                        call->pkt.u.request.stub_and_verifier.data, 
1013                                        uint8_t, alloc_size);
1014                 if (!call->pkt.u.request.stub_and_verifier.data) {
1015                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1016                 }
1017                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1018                        call->pkt.u.request.stub_and_verifier.length,
1019                        call2->pkt.u.request.stub_and_verifier.data,
1020                        call2->pkt.u.request.stub_and_verifier.length);
1021                 call->pkt.u.request.stub_and_verifier.length += 
1022                         call2->pkt.u.request.stub_and_verifier.length;
1023
1024                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1025
1026                 talloc_free(call2);
1027         }
1028
1029         /* this may not be the last pdu in the chain - if its isn't then
1030            just put it on the call_list and wait for the rest */
1031         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1032             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1033                 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
1034                 return NT_STATUS_OK;
1035         }
1036
1037         switch (call->pkt.ptype) {
1038         case DCERPC_PKT_BIND:
1039                 status = dcesrv_bind(call);
1040                 break;
1041         case DCERPC_PKT_AUTH3:
1042                 status = dcesrv_auth3(call);
1043                 break;
1044         case DCERPC_PKT_ALTER:
1045                 status = dcesrv_alter(call);
1046                 break;
1047         case DCERPC_PKT_REQUEST:
1048                 status = dcesrv_request(call);
1049                 break;
1050         default:
1051                 status = NT_STATUS_INVALID_PARAMETER;
1052                 break;
1053         }
1054
1055         /* if we are going to be sending a reply then add
1056            it to the list of pending calls. We add it to the end to keep the call
1057            list in the order we will answer */
1058         if (!NT_STATUS_IS_OK(status)) {
1059                 talloc_free(call);
1060         }
1061
1062         return status;
1063 }
1064
1065
1066 /*
1067   provide some input to a dcerpc endpoint server. This passes data
1068   from a dcerpc client into the server
1069 */
1070 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1071 {
1072         NTSTATUS status;
1073
1074         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1075                                                       dce_conn->partial_input.data,
1076                                                       uint8_t,
1077                                                       dce_conn->partial_input.length + data->length);
1078         if (!dce_conn->partial_input.data) {
1079                 return NT_STATUS_NO_MEMORY;
1080         }
1081         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1082                data->data, data->length);
1083         dce_conn->partial_input.length += data->length;
1084
1085         while (dce_full_packet(&dce_conn->partial_input)) {
1086                 status = dcesrv_input_process(dce_conn);
1087                 if (!NT_STATUS_IS_OK(status)) {
1088                         return status;
1089                 }
1090         }
1091
1092         return NT_STATUS_OK;
1093 }
1094
1095 /*
1096   retrieve some output from a dcerpc server
1097   The caller supplies a function that will be called to do the
1098   actual output. 
1099
1100   The first argument to write_fn() will be 'private', the second will
1101   be a pointer to a buffer containing the data to be sent and the 3rd
1102   will be a pointer to a size_t variable that will be set to the
1103   number of bytes that are consumed from the output.
1104
1105   from the current fragment
1106 */
1107 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1108                        void *private_data,
1109                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1110 {
1111         NTSTATUS status;
1112         struct dcesrv_call_state *call;
1113         struct dcesrv_call_reply *rep;
1114         size_t nwritten;
1115
1116         call = dce_conn->call_list;
1117         if (!call || !call->replies) {
1118                 if (dce_conn->pending_call_list) {
1119                         /* TODO: we need to say act async here
1120                          *       as we know we have pending requests
1121                          *       which will be finished at a time
1122                          */
1123                         return NT_STATUS_FOOBAR;
1124                 }
1125                 return NT_STATUS_FOOBAR;
1126         }
1127         rep = call->replies;
1128
1129         status = write_fn(private_data, rep->data, &nwritten);
1130         NT_STATUS_IS_ERR_RETURN(status);
1131
1132         rep->data->length -= nwritten;
1133         rep->data->data += nwritten;
1134
1135         if (rep->data->length == 0) {
1136                 /* we're done with this section of the call */
1137                 DLIST_REMOVE(call->replies, rep);
1138         }
1139
1140         if (call->replies == NULL) {
1141                 /* we're done with the whole call */
1142                 DLIST_REMOVE(dce_conn->call_list, call);
1143                 talloc_free(call);
1144         }
1145
1146         return status;
1147 }
1148
1149 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, uint32_t state_flags, struct dcesrv_context **_dce_ctx)
1150 {
1151         NTSTATUS status;
1152         struct dcesrv_context *dce_ctx;
1153         int i;
1154
1155         if (!endpoint_servers) {
1156                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1157                 return NT_STATUS_INTERNAL_ERROR;
1158         }
1159
1160         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1161         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1162         dce_ctx->endpoint_list  = NULL;
1163         dce_ctx->state_flags    = state_flags;
1164
1165         for (i=0;endpoint_servers[i];i++) {
1166                 const struct dcesrv_endpoint_server *ep_server;
1167
1168                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1169                 if (!ep_server) {
1170                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1171                         return NT_STATUS_INTERNAL_ERROR;
1172                 }
1173
1174                 status = ep_server->init_server(dce_ctx, ep_server);
1175                 if (!NT_STATUS_IS_OK(status)) {
1176                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1177                                 nt_errstr(status)));
1178                         return status;
1179                 }
1180         }
1181
1182         *_dce_ctx = dce_ctx;
1183         return NT_STATUS_OK;
1184 }
1185
1186 /*
1187   initialise the dcerpc server context for ncacn_np based services
1188 */
1189 NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1190 {
1191         NTSTATUS status;
1192         struct dcesrv_context *dce_ctx;
1193
1194         status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), 0, &dce_ctx);
1195         NT_STATUS_NOT_OK_RETURN(status);
1196
1197         *_dce_ctx = dce_ctx;
1198         return NT_STATUS_OK;
1199 }
1200
1201 /* the list of currently registered DCERPC endpoint servers.
1202  */
1203 static struct ep_server {
1204         struct dcesrv_endpoint_server *ep_server;
1205 } *ep_servers = NULL;
1206 static int num_ep_servers;
1207
1208 /*
1209   register a DCERPC endpoint server. 
1210
1211   The 'name' can be later used by other backends to find the operations
1212   structure for this backend.  
1213
1214   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1215 */
1216 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1217 {
1218         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1219         
1220         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1221                 /* its already registered! */
1222                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1223                          ep_server->name));
1224                 return NT_STATUS_OBJECT_NAME_COLLISION;
1225         }
1226
1227         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1228         if (!ep_servers) {
1229                 smb_panic("out of memory in dcerpc_register");
1230         }
1231
1232         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1233         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1234
1235         num_ep_servers++;
1236
1237         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1238                  ep_server->name));
1239
1240         return NT_STATUS_OK;
1241 }
1242
1243 /*
1244   return the operations structure for a named backend of the specified type
1245 */
1246 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1247 {
1248         int i;
1249
1250         for (i=0;i<num_ep_servers;i++) {
1251                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1252                         return ep_servers[i].ep_server;
1253                 }
1254         }
1255
1256         return NULL;
1257 }
1258
1259 /*
1260   return the DCERPC module version, and the size of some critical types
1261   This can be used by endpoint server modules to either detect compilation errors, or provide
1262   multiple implementations for different smbd compilation options in one module
1263 */
1264 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1265 {
1266         static const struct dcesrv_critical_sizes critical_sizes = {
1267                 DCERPC_MODULE_VERSION,
1268                 sizeof(struct dcesrv_context),
1269                 sizeof(struct dcesrv_endpoint),
1270                 sizeof(struct dcesrv_endpoint_server),
1271                 sizeof(struct dcesrv_interface),
1272                 sizeof(struct dcesrv_if_list),
1273                 sizeof(struct dcesrv_connection),
1274                 sizeof(struct dcesrv_call_state),
1275                 sizeof(struct dcesrv_auth),
1276                 sizeof(struct dcesrv_handle)
1277         };
1278
1279         return &critical_sizes;
1280 }
1281
1282 /*
1283   initialise the dcerpc server context for socket based services
1284 */
1285 static NTSTATUS dcesrv_init(struct event_context *event_context, const struct model_ops *model_ops)
1286 {
1287         NTSTATUS status;
1288         struct dcesrv_context *dce_ctx;
1289
1290         status = dcesrv_init_context(event_context,
1291                                      lp_dcerpc_endpoint_servers(),
1292                                      DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1293                                      &dce_ctx);
1294         NT_STATUS_NOT_OK_RETURN(status);
1295
1296         return dcesrv_sock_init(dce_ctx, event_context, model_ops);
1297 }
1298
1299
1300 NTSTATUS server_service_rpc_init(void)
1301 {
1302         return register_server_service("rpc", dcesrv_init);
1303 }