12e24859ec93657d99f779e9101e8f951ae27130
[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
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_t 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         if (!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         call->context   = context;
758         call->event_ctx = context->conn->srv_conn->event.ctx;
759         call->ndr_pull  = pull;
760
761         if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
762                 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
763         }
764
765         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
766                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
767         }
768
769         /* unravel the NDR for the packet */
770         status = context->iface->ndr_pull(call, call, pull, &call->r);
771         if (!NT_STATUS_IS_OK(status)) {
772                 return dcesrv_fault(call, call->fault_code);
773         }
774
775         if (pull->offset != pull->data_size) {
776                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
777                          pull->data_size - pull->offset));
778                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
779         }
780
781         /* call the dispatch function */
782         status = context->iface->dispatch(call, call, call->r);
783         if (!NT_STATUS_IS_OK(status)) {
784                 return dcesrv_fault(call, call->fault_code);
785         }
786
787         /* add the call to the pending list */
788         DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
789
790         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
791                 return NT_STATUS_OK;
792         }
793
794         return dcesrv_reply(call);
795 }
796
797 NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
798 {
799         struct ndr_push *push;
800         NTSTATUS status;
801         DATA_BLOB stub;
802         uint32_t total_length;
803         struct dcesrv_connection_context *context = call->context;
804
805         /* call the reply function */
806         status = context->iface->reply(call, call, call->r);
807         if (!NT_STATUS_IS_OK(status)) {
808                 return dcesrv_fault(call, call->fault_code);
809         }
810
811         /* form the reply NDR */
812         push = ndr_push_init_ctx(call);
813         NT_STATUS_HAVE_NO_MEMORY(push);
814
815         /* carry over the pointer count to the reply in case we are
816            using full pointer. See NDR specification for full
817            pointers */
818         push->ptr_count = call->ndr_pull->ptr_count;
819
820         if (lp_rpc_big_endian()) {
821                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
822         }
823
824         status = context->iface->ndr_push(call, call, push, call->r);
825         if (!NT_STATUS_IS_OK(status)) {
826                 return dcesrv_fault(call, call->fault_code);
827         }
828
829         stub = ndr_push_blob(push);
830
831         total_length = stub.length;
832
833         do {
834                 uint32_t length;
835                 struct dcesrv_call_reply *rep;
836                 struct dcerpc_packet pkt;
837
838                 rep = talloc(call, struct dcesrv_call_reply);
839                 NT_STATUS_HAVE_NO_MEMORY(rep);
840
841                 length = stub.length;
842                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
843                         /* the 32 is to cope with signing data */
844                         length = call->conn->cli_max_recv_frag - 
845                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
846                 }
847
848                 /* form the dcerpc response packet */
849                 dcesrv_init_hdr(&pkt);
850                 pkt.auth_length = 0;
851                 pkt.call_id = call->pkt.call_id;
852                 pkt.ptype = DCERPC_PKT_RESPONSE;
853                 pkt.pfc_flags = 0;
854                 if (stub.length == total_length) {
855                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
856                 }
857                 if (length == stub.length) {
858                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
859                 }
860                 pkt.u.response.alloc_hint = stub.length;
861                 pkt.u.response.context_id = call->pkt.u.request.context_id;
862                 pkt.u.response.cancel_count = 0;
863                 pkt.u.response.stub_and_verifier.data = stub.data;
864                 pkt.u.response.stub_and_verifier.length = length;
865
866                 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
867                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
868                 }
869
870                 dcerpc_set_frag_length(&rep->data, rep->data.length);
871
872                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
873                 
874                 stub.data += length;
875                 stub.length -= length;
876         } while (stub.length != 0);
877
878         /* move the call from the pending to the finished calls list */
879         DLIST_REMOVE(call->conn->pending_call_list, call);
880         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
881
882         if (call->conn->call_list && call->conn->call_list->replies) {
883                 if (call->conn->srv_conn &&
884                     call->conn->srv_conn->event.fde) {
885                         EVENT_FD_WRITEABLE(call->conn->srv_conn->event.fde);
886                 }
887         }
888
889         return NT_STATUS_OK;
890 }
891
892
893 /*
894   work out if we have a full packet yet
895 */
896 static BOOL dce_full_packet(const DATA_BLOB *data)
897 {
898         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
899                 return False;
900         }
901         if (dcerpc_get_frag_length(data) > data->length) {
902                 return False;
903         }
904         return True;
905 }
906
907 /*
908   we might have consumed only part of our input - advance past that part
909 */
910 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
911 {
912         DATA_BLOB blob;
913
914         if (dce_conn->partial_input.length == offset) {
915                 data_blob_free(&dce_conn->partial_input);
916                 return;
917         }
918
919         blob = dce_conn->partial_input;
920         dce_conn->partial_input = data_blob(blob.data + offset,
921                                             blob.length - offset);
922         data_blob_free(&blob);
923 }
924
925 /*
926   process some input to a dcerpc endpoint server.
927 */
928 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
929 {
930         struct ndr_pull *ndr;
931         NTSTATUS status;
932         struct dcesrv_call_state *call;
933         DATA_BLOB blob;
934
935         call = talloc(dce_conn, struct dcesrv_call_state);
936         if (!call) {
937                 talloc_free(dce_conn->partial_input.data);
938                 return NT_STATUS_NO_MEMORY;
939         }
940         call->conn = dce_conn;
941         call->replies = NULL;
942         call->context = NULL;
943
944         blob = dce_conn->partial_input;
945         blob.length = dcerpc_get_frag_length(&blob);
946
947         ndr = ndr_pull_init_blob(&blob, call);
948         if (!ndr) {
949                 talloc_free(dce_conn->partial_input.data);
950                 talloc_free(call);
951                 return NT_STATUS_NO_MEMORY;
952         }
953
954         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
955                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
956         }
957
958         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
959         if (!NT_STATUS_IS_OK(status)) {
960                 talloc_free(dce_conn->partial_input.data);
961                 talloc_free(call);
962                 return status;
963         }
964
965         /* we have to check the signing here, before combining the
966            pdus */
967         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
968             !dcesrv_auth_request(call, &blob)) {
969                 dce_partial_advance(dce_conn, blob.length);
970                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
971         }
972
973         dce_partial_advance(dce_conn, blob.length);
974
975         /* see if this is a continued packet */
976         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
977             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
978                 struct dcesrv_call_state *call2 = call;
979                 uint32_t alloc_size;
980
981                 /* we only allow fragmented requests, no other packet types */
982                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
983                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
984                 }
985
986                 /* this is a continuation of an existing call - find the call then
987                    tack it on the end */
988                 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
989                 if (!call) {
990                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
991                 }
992
993                 if (call->pkt.ptype != call2->pkt.ptype) {
994                         /* trying to play silly buggers are we? */
995                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
996                 }
997
998                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
999                         call2->pkt.u.request.stub_and_verifier.length;
1000                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1001                         alloc_size = call->pkt.u.request.alloc_hint;
1002                 }
1003
1004                 call->pkt.u.request.stub_and_verifier.data = 
1005                         talloc_realloc(call, 
1006                                        call->pkt.u.request.stub_and_verifier.data, 
1007                                        uint8_t, alloc_size);
1008                 if (!call->pkt.u.request.stub_and_verifier.data) {
1009                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1010                 }
1011                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1012                        call->pkt.u.request.stub_and_verifier.length,
1013                        call2->pkt.u.request.stub_and_verifier.data,
1014                        call2->pkt.u.request.stub_and_verifier.length);
1015                 call->pkt.u.request.stub_and_verifier.length += 
1016                         call2->pkt.u.request.stub_and_verifier.length;
1017
1018                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1019
1020                 talloc_free(call2);
1021         }
1022
1023         /* this may not be the last pdu in the chain - if its isn't then
1024            just put it on the call_list and wait for the rest */
1025         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1026             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1027                 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
1028                 return NT_STATUS_OK;
1029         }
1030
1031         switch (call->pkt.ptype) {
1032         case DCERPC_PKT_BIND:
1033                 status = dcesrv_bind(call);
1034                 break;
1035         case DCERPC_PKT_AUTH3:
1036                 status = dcesrv_auth3(call);
1037                 break;
1038         case DCERPC_PKT_ALTER:
1039                 status = dcesrv_alter(call);
1040                 break;
1041         case DCERPC_PKT_REQUEST:
1042                 status = dcesrv_request(call);
1043                 break;
1044         default:
1045                 status = NT_STATUS_INVALID_PARAMETER;
1046                 break;
1047         }
1048
1049         /* if we are going to be sending a reply then add
1050            it to the list of pending calls. We add it to the end to keep the call
1051            list in the order we will answer */
1052         if (!NT_STATUS_IS_OK(status)) {
1053                 talloc_free(call);
1054         }
1055
1056         return status;
1057 }
1058
1059
1060 /*
1061   provide some input to a dcerpc endpoint server. This passes data
1062   from a dcerpc client into the server
1063 */
1064 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1065 {
1066         NTSTATUS status;
1067
1068         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1069                                                       dce_conn->partial_input.data,
1070                                                       uint8_t,
1071                                                       dce_conn->partial_input.length + data->length);
1072         if (!dce_conn->partial_input.data) {
1073                 return NT_STATUS_NO_MEMORY;
1074         }
1075         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1076                data->data, data->length);
1077         dce_conn->partial_input.length += data->length;
1078
1079         while (dce_full_packet(&dce_conn->partial_input)) {
1080                 status = dcesrv_input_process(dce_conn);
1081                 if (!NT_STATUS_IS_OK(status)) {
1082                         return status;
1083                 }
1084         }
1085
1086         return NT_STATUS_OK;
1087 }
1088
1089 /*
1090   retrieve some output from a dcerpc server
1091   The caller supplies a function that will be called to do the
1092   actual output. 
1093
1094   The first argument to write_fn() will be 'private', the second will
1095   be a pointer to a buffer containing the data to be sent and the 3rd
1096   will be the number of bytes to be sent.
1097
1098   write_fn() should return the number of bytes successfully written.
1099
1100   this will return STATUS_BUFFER_OVERFLOW if there is more to be read
1101   from the current fragment
1102 */
1103 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1104                        void *private,
1105                        ssize_t (*write_fn)(void *, DATA_BLOB *))
1106 {
1107         struct dcesrv_call_state *call;
1108         struct dcesrv_call_reply *rep;
1109         ssize_t nwritten;
1110
1111         call = dce_conn->call_list;
1112         if (!call || !call->replies) {
1113                 if (dce_conn->pending_call_list) {
1114                         /* TODO: we need to say act async here
1115                          *       as we know we have pending requests
1116                          *       which will be finished at a time
1117                          */
1118                         return NT_STATUS_FOOBAR;
1119                 }
1120                 return NT_STATUS_FOOBAR;
1121         }
1122         rep = call->replies;
1123
1124         nwritten = write_fn(private, &rep->data);
1125         if (nwritten == -1) {
1126                 /* TODO: hmm, how do we cope with this? destroy the
1127                    connection perhaps? */
1128                 return NT_STATUS_UNSUCCESSFUL;
1129         }
1130
1131         rep->data.length -= nwritten;
1132         rep->data.data += nwritten;
1133
1134         if (rep->data.length == 0) {
1135                 /* we're done with this section of the call */
1136                 DLIST_REMOVE(call->replies, rep);
1137         } else {
1138                 return STATUS_BUFFER_OVERFLOW;
1139         }
1140
1141         if (call->replies == NULL) {
1142                 /* we're done with the whole call */
1143                 DLIST_REMOVE(dce_conn->call_list, call);
1144                 talloc_free(call);
1145         }
1146
1147         return NT_STATUS_OK;
1148 }
1149
1150
1151 /*
1152   write_fn() for dcesrv_output_blob()
1153 */
1154 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1155 {
1156         DATA_BLOB *blob = private;
1157         if (out->length < blob->length) {
1158                 blob->length = out->length;
1159         }
1160         memcpy(blob->data, out->data, blob->length);
1161         return blob->length;
1162 }
1163
1164 /*
1165   a simple wrapper for dcesrv_output() for when we want to output
1166   into a data blob
1167 */
1168 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn, 
1169                             DATA_BLOB *blob)
1170 {
1171         return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1172 }
1173
1174 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, uint32_t state_flags, struct dcesrv_context **_dce_ctx)
1175 {
1176         NTSTATUS status;
1177         struct dcesrv_context *dce_ctx;
1178         int i;
1179
1180         if (!endpoint_servers) {
1181                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1182                 return NT_STATUS_INTERNAL_ERROR;
1183         }
1184
1185         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1186         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1187         dce_ctx->endpoint_list  = NULL;
1188         dce_ctx->state_flags    = state_flags;
1189
1190         for (i=0;endpoint_servers[i];i++) {
1191                 const struct dcesrv_endpoint_server *ep_server;
1192
1193                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1194                 if (!ep_server) {
1195                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1196                         return NT_STATUS_INTERNAL_ERROR;
1197                 }
1198
1199                 status = ep_server->init_server(dce_ctx, ep_server);
1200                 if (!NT_STATUS_IS_OK(status)) {
1201                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1202                                 nt_errstr(status)));
1203                         return status;
1204                 }
1205         }
1206
1207         *_dce_ctx = dce_ctx;
1208         return NT_STATUS_OK;
1209 }
1210
1211 /*
1212   initialise the dcerpc server context for ncacn_np based services
1213 */
1214 NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1215 {
1216         NTSTATUS status;
1217         struct dcesrv_context *dce_ctx;
1218
1219         status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), 0, &dce_ctx);
1220         NT_STATUS_NOT_OK_RETURN(status);
1221
1222         *_dce_ctx = dce_ctx;
1223         return NT_STATUS_OK;
1224 }
1225
1226 /* the list of currently registered DCERPC endpoint servers.
1227  */
1228 static struct ep_server {
1229         struct dcesrv_endpoint_server *ep_server;
1230 } *ep_servers = NULL;
1231 static int num_ep_servers;
1232
1233 /*
1234   register a DCERPC endpoint server. 
1235
1236   The 'name' can be later used by other backends to find the operations
1237   structure for this backend.  
1238
1239   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1240 */
1241 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1242 {
1243         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1244         
1245         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1246                 /* its already registered! */
1247                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1248                          ep_server->name));
1249                 return NT_STATUS_OBJECT_NAME_COLLISION;
1250         }
1251
1252         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1253         if (!ep_servers) {
1254                 smb_panic("out of memory in dcerpc_register");
1255         }
1256
1257         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1258         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1259
1260         num_ep_servers++;
1261
1262         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1263                  ep_server->name));
1264
1265         return NT_STATUS_OK;
1266 }
1267
1268 /*
1269   return the operations structure for a named backend of the specified type
1270 */
1271 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1272 {
1273         int i;
1274
1275         for (i=0;i<num_ep_servers;i++) {
1276                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1277                         return ep_servers[i].ep_server;
1278                 }
1279         }
1280
1281         return NULL;
1282 }
1283
1284 /*
1285   return the DCERPC module version, and the size of some critical types
1286   This can be used by endpoint server modules to either detect compilation errors, or provide
1287   multiple implementations for different smbd compilation options in one module
1288 */
1289 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1290 {
1291         static const struct dcesrv_critical_sizes critical_sizes = {
1292                 DCERPC_MODULE_VERSION,
1293                 sizeof(struct dcesrv_context),
1294                 sizeof(struct dcesrv_endpoint),
1295                 sizeof(struct dcesrv_endpoint_server),
1296                 sizeof(struct dcesrv_interface),
1297                 sizeof(struct dcesrv_if_list),
1298                 sizeof(struct dcesrv_connection),
1299                 sizeof(struct dcesrv_call_state),
1300                 sizeof(struct dcesrv_auth),
1301                 sizeof(struct dcesrv_handle)
1302         };
1303
1304         return &critical_sizes;
1305 }
1306
1307 /*
1308   initialise the dcerpc server context for socket based services
1309 */
1310 static NTSTATUS dcesrv_init(struct event_context *event_context, const struct model_ops *model_ops)
1311 {
1312         NTSTATUS status;
1313         struct dcesrv_context *dce_ctx;
1314
1315         status = dcesrv_init_context(event_context,
1316                                      lp_dcerpc_endpoint_servers(),
1317                                      DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1318                                      &dce_ctx);
1319         NT_STATUS_NOT_OK_RETURN(status);
1320
1321         return dcesrv_sock_init(dce_ctx, event_context, model_ops);
1322 }
1323
1324
1325 NTSTATUS server_service_rpc_init(void)
1326 {
1327         return register_server_service("rpc", dcesrv_init);
1328 }