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