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