r6714: We can only ask GENSEC questions if we are authenticated.
[bbaumbach/samba-autobuild/.git] / source4 / rpc_server / dcerpc_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc core code
5
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Stefan (metze) Metzmacher 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_epmapper.h"
26 #include "librpc/gen_ndr/ndr_oxidresolver.h"
27 #include "auth/auth.h"
28 #include "dlinklist.h"
29 #include "rpc_server/dcerpc_server.h"
30 #include "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 authenticated, and the mech we use can't do async replies, don't use them... */
746         if (call->conn->auth_state.gensec_security && 
747             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
748                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
749         }
750
751         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
752         if (context == NULL) {
753                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
754         }
755
756         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
757         NT_STATUS_HAVE_NO_MEMORY(pull);
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 dcerpc_packet pkt;
839
840                 rep = talloc(call, struct dcesrv_call_reply);
841                 NT_STATUS_HAVE_NO_MEMORY(rep);
842
843                 length = stub.length;
844                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
845                         /* the 32 is to cope with signing data */
846                         length = call->conn->cli_max_recv_frag - 
847                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
848                 }
849
850                 /* form the dcerpc response packet */
851                 dcesrv_init_hdr(&pkt);
852                 pkt.auth_length = 0;
853                 pkt.call_id = call->pkt.call_id;
854                 pkt.ptype = DCERPC_PKT_RESPONSE;
855                 pkt.pfc_flags = 0;
856                 if (stub.length == total_length) {
857                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
858                 }
859                 if (length == stub.length) {
860                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
861                 }
862                 pkt.u.response.alloc_hint = stub.length;
863                 pkt.u.response.context_id = call->pkt.u.request.context_id;
864                 pkt.u.response.cancel_count = 0;
865                 pkt.u.response.stub_and_verifier.data = stub.data;
866                 pkt.u.response.stub_and_verifier.length = length;
867
868                 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
869                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
870                 }
871
872                 dcerpc_set_frag_length(&rep->data, rep->data.length);
873
874                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
875                 
876                 stub.data += length;
877                 stub.length -= length;
878         } while (stub.length != 0);
879
880         /* move the call from the pending to the finished calls list */
881         DLIST_REMOVE(call->conn->pending_call_list, call);
882         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
883
884         if (call->conn->call_list && call->conn->call_list->replies) {
885                 if (call->conn->srv_conn &&
886                     call->conn->srv_conn->event.fde) {
887                         EVENT_FD_WRITEABLE(call->conn->srv_conn->event.fde);
888                 }
889         }
890
891         return NT_STATUS_OK;
892 }
893
894
895 /*
896   work out if we have a full packet yet
897 */
898 static BOOL dce_full_packet(const DATA_BLOB *data)
899 {
900         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
901                 return False;
902         }
903         if (dcerpc_get_frag_length(data) > data->length) {
904                 return False;
905         }
906         return True;
907 }
908
909 /*
910   we might have consumed only part of our input - advance past that part
911 */
912 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
913 {
914         DATA_BLOB blob;
915
916         if (dce_conn->partial_input.length == offset) {
917                 data_blob_free(&dce_conn->partial_input);
918                 return;
919         }
920
921         blob = dce_conn->partial_input;
922         dce_conn->partial_input = data_blob(blob.data + offset,
923                                             blob.length - offset);
924         data_blob_free(&blob);
925 }
926
927 /*
928   process some input to a dcerpc endpoint server.
929 */
930 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
931 {
932         struct ndr_pull *ndr;
933         NTSTATUS status;
934         struct dcesrv_call_state *call;
935         DATA_BLOB blob;
936
937         call = talloc(dce_conn, struct dcesrv_call_state);
938         if (!call) {
939                 talloc_free(dce_conn->partial_input.data);
940                 return NT_STATUS_NO_MEMORY;
941         }
942         call->conn = dce_conn;
943         call->replies = NULL;
944         call->context = NULL;
945
946         blob = dce_conn->partial_input;
947         blob.length = dcerpc_get_frag_length(&blob);
948
949         ndr = ndr_pull_init_blob(&blob, call);
950         if (!ndr) {
951                 talloc_free(dce_conn->partial_input.data);
952                 talloc_free(call);
953                 return NT_STATUS_NO_MEMORY;
954         }
955
956         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
957                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
958         }
959
960         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
961         if (!NT_STATUS_IS_OK(status)) {
962                 talloc_free(dce_conn->partial_input.data);
963                 talloc_free(call);
964                 return status;
965         }
966
967         /* we have to check the signing here, before combining the
968            pdus */
969         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
970             !dcesrv_auth_request(call, &blob)) {
971                 dce_partial_advance(dce_conn, blob.length);
972                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
973         }
974
975         dce_partial_advance(dce_conn, blob.length);
976
977         /* see if this is a continued packet */
978         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
979             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
980                 struct dcesrv_call_state *call2 = call;
981                 uint32_t alloc_size;
982
983                 /* we only allow fragmented requests, no other packet types */
984                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
985                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
986                 }
987
988                 /* this is a continuation of an existing call - find the call then
989                    tack it on the end */
990                 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
991                 if (!call) {
992                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
993                 }
994
995                 if (call->pkt.ptype != call2->pkt.ptype) {
996                         /* trying to play silly buggers are we? */
997                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
998                 }
999
1000                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1001                         call2->pkt.u.request.stub_and_verifier.length;
1002                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1003                         alloc_size = call->pkt.u.request.alloc_hint;
1004                 }
1005
1006                 call->pkt.u.request.stub_and_verifier.data = 
1007                         talloc_realloc(call, 
1008                                        call->pkt.u.request.stub_and_verifier.data, 
1009                                        uint8_t, alloc_size);
1010                 if (!call->pkt.u.request.stub_and_verifier.data) {
1011                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1012                 }
1013                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1014                        call->pkt.u.request.stub_and_verifier.length,
1015                        call2->pkt.u.request.stub_and_verifier.data,
1016                        call2->pkt.u.request.stub_and_verifier.length);
1017                 call->pkt.u.request.stub_and_verifier.length += 
1018                         call2->pkt.u.request.stub_and_verifier.length;
1019
1020                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1021
1022                 talloc_free(call2);
1023         }
1024
1025         /* this may not be the last pdu in the chain - if its isn't then
1026            just put it on the call_list and wait for the rest */
1027         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1028             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1029                 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
1030                 return NT_STATUS_OK;
1031         }
1032
1033         switch (call->pkt.ptype) {
1034         case DCERPC_PKT_BIND:
1035                 status = dcesrv_bind(call);
1036                 break;
1037         case DCERPC_PKT_AUTH3:
1038                 status = dcesrv_auth3(call);
1039                 break;
1040         case DCERPC_PKT_ALTER:
1041                 status = dcesrv_alter(call);
1042                 break;
1043         case DCERPC_PKT_REQUEST:
1044                 status = dcesrv_request(call);
1045                 break;
1046         default:
1047                 status = NT_STATUS_INVALID_PARAMETER;
1048                 break;
1049         }
1050
1051         /* if we are going to be sending a reply then add
1052            it to the list of pending calls. We add it to the end to keep the call
1053            list in the order we will answer */
1054         if (!NT_STATUS_IS_OK(status)) {
1055                 talloc_free(call);
1056         }
1057
1058         return status;
1059 }
1060
1061
1062 /*
1063   provide some input to a dcerpc endpoint server. This passes data
1064   from a dcerpc client into the server
1065 */
1066 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1067 {
1068         NTSTATUS status;
1069
1070         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1071                                                       dce_conn->partial_input.data,
1072                                                       uint8_t,
1073                                                       dce_conn->partial_input.length + data->length);
1074         if (!dce_conn->partial_input.data) {
1075                 return NT_STATUS_NO_MEMORY;
1076         }
1077         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1078                data->data, data->length);
1079         dce_conn->partial_input.length += data->length;
1080
1081         while (dce_full_packet(&dce_conn->partial_input)) {
1082                 status = dcesrv_input_process(dce_conn);
1083                 if (!NT_STATUS_IS_OK(status)) {
1084                         return status;
1085                 }
1086         }
1087
1088         return NT_STATUS_OK;
1089 }
1090
1091 /*
1092   retrieve some output from a dcerpc server
1093   The caller supplies a function that will be called to do the
1094   actual output. 
1095
1096   The first argument to write_fn() will be 'private', the second will
1097   be a pointer to a buffer containing the data to be sent and the 3rd
1098   will be the number of bytes to be sent.
1099
1100   write_fn() should return the number of bytes successfully written.
1101
1102   this will return STATUS_BUFFER_OVERFLOW if there is more to be read
1103   from the current fragment
1104 */
1105 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1106                        void *private,
1107                        ssize_t (*write_fn)(void *, DATA_BLOB *))
1108 {
1109         struct dcesrv_call_state *call;
1110         struct dcesrv_call_reply *rep;
1111         ssize_t nwritten;
1112
1113         call = dce_conn->call_list;
1114         if (!call || !call->replies) {
1115                 if (dce_conn->pending_call_list) {
1116                         /* TODO: we need to say act async here
1117                          *       as we know we have pending requests
1118                          *       which will be finished at a time
1119                          */
1120                         return NT_STATUS_FOOBAR;
1121                 }
1122                 return NT_STATUS_FOOBAR;
1123         }
1124         rep = call->replies;
1125
1126         nwritten = write_fn(private, &rep->data);
1127         if (nwritten == -1) {
1128                 /* TODO: hmm, how do we cope with this? destroy the
1129                    connection perhaps? */
1130                 return NT_STATUS_UNSUCCESSFUL;
1131         }
1132
1133         rep->data.length -= nwritten;
1134         rep->data.data += nwritten;
1135
1136         if (rep->data.length == 0) {
1137                 /* we're done with this section of the call */
1138                 DLIST_REMOVE(call->replies, rep);
1139         } else {
1140                 return STATUS_BUFFER_OVERFLOW;
1141         }
1142
1143         if (call->replies == NULL) {
1144                 /* we're done with the whole call */
1145                 DLIST_REMOVE(dce_conn->call_list, call);
1146                 talloc_free(call);
1147         }
1148
1149         return NT_STATUS_OK;
1150 }
1151
1152
1153 /*
1154   write_fn() for dcesrv_output_blob()
1155 */
1156 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1157 {
1158         DATA_BLOB *blob = private;
1159         if (out->length < blob->length) {
1160                 blob->length = out->length;
1161         }
1162         memcpy(blob->data, out->data, blob->length);
1163         return blob->length;
1164 }
1165
1166 /*
1167   a simple wrapper for dcesrv_output() for when we want to output
1168   into a data blob
1169 */
1170 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn, 
1171                             DATA_BLOB *blob)
1172 {
1173         return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1174 }
1175
1176 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, uint32_t state_flags, struct dcesrv_context **_dce_ctx)
1177 {
1178         NTSTATUS status;
1179         struct dcesrv_context *dce_ctx;
1180         int i;
1181
1182         if (!endpoint_servers) {
1183                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1184                 return NT_STATUS_INTERNAL_ERROR;
1185         }
1186
1187         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1188         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1189         dce_ctx->endpoint_list  = NULL;
1190         dce_ctx->state_flags    = state_flags;
1191
1192         for (i=0;endpoint_servers[i];i++) {
1193                 const struct dcesrv_endpoint_server *ep_server;
1194
1195                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1196                 if (!ep_server) {
1197                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1198                         return NT_STATUS_INTERNAL_ERROR;
1199                 }
1200
1201                 status = ep_server->init_server(dce_ctx, ep_server);
1202                 if (!NT_STATUS_IS_OK(status)) {
1203                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1204                                 nt_errstr(status)));
1205                         return status;
1206                 }
1207         }
1208
1209         *_dce_ctx = dce_ctx;
1210         return NT_STATUS_OK;
1211 }
1212
1213 /*
1214   initialise the dcerpc server context for ncacn_np based services
1215 */
1216 NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1217 {
1218         NTSTATUS status;
1219         struct dcesrv_context *dce_ctx;
1220
1221         status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), 0, &dce_ctx);
1222         NT_STATUS_NOT_OK_RETURN(status);
1223
1224         *_dce_ctx = dce_ctx;
1225         return NT_STATUS_OK;
1226 }
1227
1228 /* the list of currently registered DCERPC endpoint servers.
1229  */
1230 static struct ep_server {
1231         struct dcesrv_endpoint_server *ep_server;
1232 } *ep_servers = NULL;
1233 static int num_ep_servers;
1234
1235 /*
1236   register a DCERPC endpoint server. 
1237
1238   The 'name' can be later used by other backends to find the operations
1239   structure for this backend.  
1240
1241   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1242 */
1243 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1244 {
1245         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1246         
1247         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1248                 /* its already registered! */
1249                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1250                          ep_server->name));
1251                 return NT_STATUS_OBJECT_NAME_COLLISION;
1252         }
1253
1254         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1255         if (!ep_servers) {
1256                 smb_panic("out of memory in dcerpc_register");
1257         }
1258
1259         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1260         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1261
1262         num_ep_servers++;
1263
1264         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1265                  ep_server->name));
1266
1267         return NT_STATUS_OK;
1268 }
1269
1270 /*
1271   return the operations structure for a named backend of the specified type
1272 */
1273 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1274 {
1275         int i;
1276
1277         for (i=0;i<num_ep_servers;i++) {
1278                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1279                         return ep_servers[i].ep_server;
1280                 }
1281         }
1282
1283         return NULL;
1284 }
1285
1286 /*
1287   return the DCERPC module version, and the size of some critical types
1288   This can be used by endpoint server modules to either detect compilation errors, or provide
1289   multiple implementations for different smbd compilation options in one module
1290 */
1291 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1292 {
1293         static const struct dcesrv_critical_sizes critical_sizes = {
1294                 DCERPC_MODULE_VERSION,
1295                 sizeof(struct dcesrv_context),
1296                 sizeof(struct dcesrv_endpoint),
1297                 sizeof(struct dcesrv_endpoint_server),
1298                 sizeof(struct dcesrv_interface),
1299                 sizeof(struct dcesrv_if_list),
1300                 sizeof(struct dcesrv_connection),
1301                 sizeof(struct dcesrv_call_state),
1302                 sizeof(struct dcesrv_auth),
1303                 sizeof(struct dcesrv_handle)
1304         };
1305
1306         return &critical_sizes;
1307 }
1308
1309 /*
1310   initialise the dcerpc server context for socket based services
1311 */
1312 static NTSTATUS dcesrv_init(struct event_context *event_context, const struct model_ops *model_ops)
1313 {
1314         NTSTATUS status;
1315         struct dcesrv_context *dce_ctx;
1316
1317         status = dcesrv_init_context(event_context,
1318                                      lp_dcerpc_endpoint_servers(),
1319                                      DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1320                                      &dce_ctx);
1321         NT_STATUS_NOT_OK_RETURN(status);
1322
1323         return dcesrv_sock_init(dce_ctx, event_context, model_ops);
1324 }
1325
1326
1327 NTSTATUS server_service_rpc_init(void)
1328 {
1329         return register_server_service("rpc", dcesrv_init);
1330 }