r4728: split up server_services into:
[gd/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 "events.h"
31
32 /*
33   see if two endpoints match
34 */
35 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
36                             const struct dcerpc_binding *ep2)
37 {
38         if (ep1->transport != ep2->transport) {
39                 return False;
40         }
41
42         if (!ep1->endpoint || !ep2->endpoint) {
43                 return ep1->endpoint == ep2->endpoint;
44         }
45
46         if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0) 
47                 return False;
48
49         return True;
50 }
51
52 /*
53   find an endpoint in the dcesrv_context
54 */
55 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
56                                              const struct dcerpc_binding *ep_description)
57 {
58         struct dcesrv_endpoint *ep;
59         for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
60                 if (endpoints_match(&ep->ep_description, ep_description)) {
61                         return ep;
62                 }
63         }
64         return NULL;
65 }
66
67 /*
68   find a registered context_id from a bind or alter_context
69 */
70 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn, 
71                                                                    uint32_t context_id)
72 {
73         struct dcesrv_connection_context *c;
74         for (c=conn->contexts;c;c=c->next) {
75                 if (c->context_id == context_id) return c;
76         }
77         return NULL;
78 }
79
80 /*
81   see if a uuid and if_version match to an interface
82 */
83 static BOOL interface_match(const struct dcesrv_interface *if1,
84                                                         const struct dcesrv_interface *if2)
85 {
86         if (if1->if_version != if2->if_version) {
87                 return False;
88         }
89
90         if (strcmp(if1->uuid, if2->uuid)==0) {
91                 return True;
92         }                       
93
94         return False;
95 }
96
97 /*
98   find the interface operations on an endpoint
99 */
100 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
101                                                      const struct dcesrv_interface *iface)
102 {
103         struct dcesrv_if_list *ifl;
104         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
105                 if (interface_match(&(ifl->iface), iface)) {
106                         return &(ifl->iface);
107                 }
108         }
109         return NULL;
110 }
111
112 /*
113   see if a uuid and if_version match to an interface
114 */
115 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
116                                     const char *uuid, uint32_t if_version)
117 {
118         if (iface->if_version != if_version) {
119                 return False;
120         }
121
122         if (strcmp(iface->uuid, uuid)==0) {
123                 return True;
124         }                       
125
126         return False;
127 }
128
129 /*
130   find the interface operations on an endpoint by uuid
131 */
132 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
133                                                              const char *uuid, uint32_t if_version)
134 {
135         struct dcesrv_if_list *ifl;
136         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
137                 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
138                         return &(ifl->iface);
139                 }
140         }
141         return NULL;
142 }
143
144 /*
145   find a call that is pending in our call list
146 */
147 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
148 {
149         struct dcesrv_call_state *c;
150         for (c=dce_conn->call_list;c;c=c->next) {
151                 if (c->pkt.call_id == call_id) {
152                         return c;
153                 }
154         }
155         return NULL;
156 }
157
158 /*
159   register an interface on an endpoint
160 */
161 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
162                                    const char *ep_name,
163                                    const struct dcesrv_interface *iface,
164                                    const struct security_descriptor *sd)
165 {
166         struct dcesrv_endpoint *ep;
167         struct dcesrv_if_list *ifl;
168         struct dcerpc_binding binding;
169         BOOL add_ep = False;
170         NTSTATUS status;
171         
172         status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
173
174         if (NT_STATUS_IS_ERR(status)) {
175                 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
176                 return status;
177         }
178
179         /* check if this endpoint exists
180          */
181         if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
182                 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
183                 if (!ep) {
184                         return NT_STATUS_NO_MEMORY;
185                 }
186                 ZERO_STRUCTP(ep);
187                 ep->ep_description = binding;
188                 add_ep = True;
189         }
190
191         /* see if the interface is already registered on te endpoint */
192         if (find_interface(ep, iface)!=NULL) {
193                 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
194                         iface->name, ep_name));
195                 return NT_STATUS_OBJECT_NAME_COLLISION;
196         }
197
198         /* talloc a new interface list element */
199         ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
200         if (!ifl) {
201                 return NT_STATUS_NO_MEMORY;
202         }
203
204         /* copy the given interface struct to the one on the endpoints interface list */
205         memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
206
207         /* if we have a security descriptor given,
208          * we should see if we can set it up on the endpoint
209          */
210         if (sd != NULL) {
211                 /* if there's currently no security descriptor given on the endpoint
212                  * we try to set it
213                  */
214                 if (ep->sd == NULL) {
215                         ep->sd = security_descriptor_copy(dce_ctx, sd);
216                 }
217
218                 /* if now there's no security descriptor given on the endpoint
219                  * something goes wrong, either we failed to copy the security descriptor
220                  * or there was already one on the endpoint
221                  */
222                 if (ep->sd != NULL) {
223                         DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
224                                  "                           on endpoint '%s'\n",
225                                 iface->name, ep_name));
226                         if (add_ep) free(ep);
227                         free(ifl);
228                         return NT_STATUS_OBJECT_NAME_COLLISION;
229                 }
230         }
231
232         /* finally add the interface on the endpoint */
233         DLIST_ADD(ep->interface_list, ifl);
234
235         /* if it's a new endpoint add it to the dcesrv_context */
236         if (add_ep) {
237                 DLIST_ADD(dce_ctx->endpoint_list, ep);
238         }
239
240         DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
241                 iface->name, ep_name));
242
243         return NT_STATUS_OK;
244 }
245
246 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
247                                               DATA_BLOB *session_key)
248 {
249         if (p->auth_state.session_info->session_key.length) {
250                 *session_key = p->auth_state.session_info->session_key;
251                 return NT_STATUS_OK;
252         }
253         return NT_STATUS_NO_USER_SESSION_KEY;
254 }
255
256 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
257                                     DATA_BLOB *session_key)
258 {
259         /* this took quite a few CPU cycles to find ... */
260         session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
261         session_key->length = 16;
262         return NT_STATUS_OK;
263 }
264
265 /*
266   fetch the user session key - may be default (above) or the SMB session key
267 */
268 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
269                                   DATA_BLOB *session_key)
270 {
271         return p->auth_state.session_key(p, session_key);
272 }
273
274
275 /*
276   destroy a link to an endpoint
277 */
278 static int dcesrv_endpoint_destructor(void *ptr)
279 {
280         struct dcesrv_connection *p = ptr;
281
282         while (p->contexts) {
283                 struct dcesrv_connection_context *c = p->contexts;
284
285                 DLIST_REMOVE(p->contexts, c);
286
287                 if (c->iface) {
288                         c->iface->unbind(c, c->iface);
289                 }
290         }
291
292         return 0;
293 }
294
295
296 /*
297   connect to a dcerpc endpoint
298 */
299 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
300                                  TALLOC_CTX *mem_ctx,
301                                  const struct dcesrv_endpoint *ep,
302                                  struct server_connection *srv_conn,
303                                  struct dcesrv_connection **_p)
304 {
305         struct dcesrv_connection *p;
306
307         p = talloc(mem_ctx, struct dcesrv_connection);
308         NT_STATUS_HAVE_NO_MEMORY(p);
309
310         p->dce_ctx = dce_ctx;
311         p->endpoint = ep;
312         p->contexts = NULL;
313         p->call_list = NULL;
314         p->pending_call_list = NULL;
315         p->cli_max_recv_frag = 0;
316         p->partial_input = data_blob(NULL, 0);
317         p->auth_state.auth_info = NULL;
318         p->auth_state.gensec_security = NULL;
319         p->auth_state.session_info = NULL;
320         p->auth_state.session_key = dcesrv_generic_session_key;
321         p->srv_conn = srv_conn;
322
323         talloc_set_destructor(p, dcesrv_endpoint_destructor);
324
325         *_p = p;
326         return NT_STATUS_OK;
327 }
328
329 /*
330   search and connect to a dcerpc endpoint
331 */
332 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
333                                         TALLOC_CTX *mem_ctx,
334                                         const struct dcerpc_binding *ep_description,
335                                         struct auth_session_info *session_info,
336                                         struct server_connection *srv_conn,
337                                         struct dcesrv_connection **dce_conn_p)
338 {
339         NTSTATUS status;
340         const struct dcesrv_endpoint *ep;
341
342         /* make sure this endpoint exists */
343         ep = find_endpoint(dce_ctx, ep_description);
344         if (!ep) {
345                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
346         }
347
348         status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, srv_conn, dce_conn_p);
349         if (!NT_STATUS_IS_OK(status)) {
350                 return status;
351         }
352
353         (*dce_conn_p)->auth_state.session_info = talloc_reference((*dce_conn_p), session_info);
354         (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
355
356         /* TODO: check security descriptor of the endpoint here 
357          *       if it's a smb named pipe
358          *       if it's failed free dce_conn_p
359          */
360
361         return NT_STATUS_OK;
362 }
363
364
365 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
366 {
367         pkt->rpc_vers = 5;
368         pkt->rpc_vers_minor = 0;
369         if (lp_rpc_big_endian()) {
370                 pkt->drep[0] = 0;
371         } else {
372                 pkt->drep[0] = DCERPC_DREP_LE;
373         }
374         pkt->drep[1] = 0;
375         pkt->drep[2] = 0;
376         pkt->drep[3] = 0;
377 }
378
379 /*
380   return a dcerpc fault
381 */
382 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
383 {
384         struct dcerpc_packet pkt;
385         struct dcesrv_call_reply *rep;
386         NTSTATUS status;
387
388         /* setup a bind_ack */
389         dcesrv_init_hdr(&pkt);
390         pkt.auth_length = 0;
391         pkt.call_id = call->pkt.call_id;
392         pkt.ptype = DCERPC_PKT_FAULT;
393         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
394         pkt.u.fault.alloc_hint = 0;
395         pkt.u.fault.context_id = 0;
396         pkt.u.fault.cancel_count = 0;
397         pkt.u.fault.status = fault_code;
398
399         rep = talloc_p(call, struct dcesrv_call_reply);
400         if (!rep) {
401                 return NT_STATUS_NO_MEMORY;
402         }
403
404         status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
405         if (!NT_STATUS_IS_OK(status)) {
406                 return status;
407         }
408
409         dcerpc_set_frag_length(&rep->data, rep->data.length);
410
411         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
412         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
413
414         return NT_STATUS_OK;    
415 }
416
417
418 /*
419   return a dcerpc bind_nak
420 */
421 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
422 {
423         struct dcerpc_packet pkt;
424         struct dcesrv_call_reply *rep;
425         NTSTATUS status;
426
427         /* setup a bind_nak */
428         dcesrv_init_hdr(&pkt);
429         pkt.auth_length = 0;
430         pkt.call_id = call->pkt.call_id;
431         pkt.ptype = DCERPC_PKT_BIND_NAK;
432         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
433         pkt.u.bind_nak.reject_reason = reason;
434         pkt.u.bind_nak.num_versions = 0;
435
436         rep = talloc_p(call, struct dcesrv_call_reply);
437         if (!rep) {
438                 return NT_STATUS_NO_MEMORY;
439         }
440
441         status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
442         if (!NT_STATUS_IS_OK(status)) {
443                 return status;
444         }
445
446         dcerpc_set_frag_length(&rep->data, rep->data.length);
447
448         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
449         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
450
451         return NT_STATUS_OK;    
452 }
453
454
455 /*
456   handle a bind request
457 */
458 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
459 {
460         const char *uuid, *transfer_syntax;
461         uint32_t if_version, transfer_syntax_version;
462         struct dcerpc_packet pkt;
463         struct dcesrv_call_reply *rep;
464         NTSTATUS status;
465         uint32_t result=0, reason=0;
466         uint32_t context_id;
467         const struct dcesrv_interface *iface;
468
469         if (call->pkt.u.bind.num_contexts != 1 ||
470             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
471                 return dcesrv_bind_nak(call, 0);
472         }
473
474         context_id = call->pkt.u.bind.ctx_list[0].context_id;
475
476         /* you can't bind twice on one context */
477         if (dcesrv_find_context(call->conn, context_id) != NULL) {
478                 return dcesrv_bind_nak(call, 0);
479         }
480
481         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
482         uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
483         if (!uuid) {
484                 return dcesrv_bind_nak(call, 0);
485         }
486
487         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
488         transfer_syntax = GUID_string(call, 
489                                       &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
490         if (!transfer_syntax ||
491             strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
492             NDR_GUID_VERSION != transfer_syntax_version) {
493                 /* we only do NDR encoded dcerpc */
494                 return dcesrv_bind_nak(call, 0);
495         }
496
497         iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
498         if (iface == NULL) {
499                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
500                 /* we don't know about that interface */
501                 result = DCERPC_BIND_PROVIDER_REJECT;
502                 reason = DCERPC_BIND_REASON_ASYNTAX;            
503         }
504
505         if (iface) {
506                 /* add this context to the list of available context_ids */
507                 struct dcesrv_connection_context *context = talloc(call->conn, 
508                                                                    struct dcesrv_connection_context);
509                 if (context == NULL) {
510                         return dcesrv_bind_nak(call, 0);
511                 }
512                 context->conn = call->conn;
513                 context->iface = iface;
514                 context->context_id = context_id;
515                 context->private = NULL;
516                 context->handles = NULL;
517                 DLIST_ADD(call->conn->contexts, context);
518                 call->context = context;
519         }
520
521         if (call->conn->cli_max_recv_frag == 0) {
522                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
523         }
524
525         /* handle any authentication that is being requested */
526         if (!dcesrv_auth_bind(call)) {
527                 /* TODO: work out the right reject code */
528                 return dcesrv_bind_nak(call, 0);
529         }
530
531         /* setup a bind_ack */
532         dcesrv_init_hdr(&pkt);
533         pkt.auth_length = 0;
534         pkt.call_id = call->pkt.call_id;
535         pkt.ptype = DCERPC_PKT_BIND_ACK;
536         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
537         pkt.u.bind_ack.max_xmit_frag = 0x2000;
538         pkt.u.bind_ack.max_recv_frag = 0x2000;
539         pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
540         if (iface) {
541                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
542                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
543         } else {
544                 pkt.u.bind_ack.secondary_address = "";
545         }
546         pkt.u.bind_ack.num_results = 1;
547         pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
548         if (!pkt.u.bind_ack.ctx_list) {
549                 return NT_STATUS_NO_MEMORY;
550         }
551         pkt.u.bind_ack.ctx_list[0].result = result;
552         pkt.u.bind_ack.ctx_list[0].reason = reason;
553         GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
554         pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
555         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
556
557         if (!dcesrv_auth_bind_ack(call, &pkt)) {
558                 return dcesrv_bind_nak(call, 0);
559         }
560
561         if (iface) {
562                 status = iface->bind(call, iface);
563                 if (!NT_STATUS_IS_OK(status)) {
564                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", 
565                                  uuid, if_version, nt_errstr(status)));
566                         return dcesrv_bind_nak(call, 0);
567                 }
568         }
569
570         rep = talloc(call, struct dcesrv_call_reply);
571         if (!rep) {
572                 return NT_STATUS_NO_MEMORY;
573         }
574
575         status = dcerpc_push_auth(&rep->data, call, &pkt, 
576                                   call->conn->auth_state.auth_info);
577         if (!NT_STATUS_IS_OK(status)) {
578                 return status;
579         }
580
581         dcerpc_set_frag_length(&rep->data, rep->data.length);
582
583         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
584         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
585
586         return NT_STATUS_OK;
587 }
588
589
590 /*
591   handle a auth3 request
592 */
593 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
594 {
595         /* handle the auth3 in the auth code */
596         if (!dcesrv_auth_auth3(call)) {
597                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
598         }
599
600         talloc_free(call);
601
602         /* we don't send a reply to a auth3 request, except by a
603            fault */
604         return NT_STATUS_OK;
605 }
606
607
608 /*
609   handle a bind request
610 */
611 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32 context_id)
612 {
613         uint32_t if_version, transfer_syntax_version;
614         const char *uuid, *transfer_syntax;
615         struct dcesrv_connection_context *context;
616         const struct dcesrv_interface *iface;
617
618         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
619         uuid = GUID_string(call, &call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid);
620         if (!uuid) {
621                 return NT_STATUS_NO_MEMORY;
622         }
623
624         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
625         transfer_syntax = GUID_string(call, 
626                                       &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid);
627         if (!transfer_syntax ||
628             strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
629             NDR_GUID_VERSION != transfer_syntax_version) {
630                 /* we only do NDR encoded dcerpc */
631                 return NT_STATUS_NO_MEMORY;
632         }
633
634         iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
635         if (iface == NULL) {
636                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
637                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
638         }
639
640         /* add this context to the list of available context_ids */
641         context = talloc(call->conn, struct dcesrv_connection_context);
642         if (context == NULL) {
643                 return NT_STATUS_NO_MEMORY;
644         }
645         context->conn = call->conn;
646         context->iface = iface;
647         context->context_id = context_id;
648         context->private = NULL;
649         context->handles = NULL;
650         DLIST_ADD(call->conn->contexts, context);
651         call->context = context;
652
653         return NT_STATUS_OK;
654 }
655
656
657 /*
658   handle a bind request
659 */
660 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
661 {
662         struct dcerpc_packet pkt;
663         struct dcesrv_call_reply *rep;
664         NTSTATUS status;
665         uint32_t result=0, reason=0;
666         uint32_t context_id;
667
668         /* handle any authentication that is being requested */
669         if (!dcesrv_auth_alter(call)) {
670                 /* TODO: work out the right reject code */
671                 result = DCERPC_BIND_PROVIDER_REJECT;
672                 reason = DCERPC_BIND_REASON_ASYNTAX;            
673         }
674
675         context_id = call->pkt.u.alter.ctx_list[0].context_id;
676
677         /* see if they are asking for a new interface */
678         if (result == 0 &&
679             dcesrv_find_context(call->conn, context_id) == NULL) {
680                 status = dcesrv_alter_new_context(call, context_id);
681                 if (!NT_STATUS_IS_OK(status)) {
682                         result = DCERPC_BIND_PROVIDER_REJECT;
683                         reason = DCERPC_BIND_REASON_ASYNTAX;            
684                 }
685         }
686
687         /* setup a alter_resp */
688         dcesrv_init_hdr(&pkt);
689         pkt.auth_length = 0;
690         pkt.call_id = call->pkt.call_id;
691         pkt.ptype = DCERPC_PKT_ALTER_RESP;
692         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
693         pkt.u.alter_resp.max_xmit_frag = 0x2000;
694         pkt.u.alter_resp.max_recv_frag = 0x2000;
695         pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
696         pkt.u.alter_resp.num_results = 1;
697         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
698         if (!pkt.u.alter_resp.ctx_list) {
699                 return NT_STATUS_NO_MEMORY;
700         }
701         pkt.u.alter_resp.ctx_list[0].result = result;
702         pkt.u.alter_resp.ctx_list[0].reason = reason;
703         GUID_from_string(NDR_GUID, &pkt.u.alter_resp.ctx_list[0].syntax.uuid);
704         pkt.u.alter_resp.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
705         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
706         pkt.u.alter_resp.secondary_address = "";
707
708         if (!dcesrv_auth_alter_ack(call, &pkt)) {
709                 return dcesrv_bind_nak(call, 0);
710         }
711
712         rep = talloc_p(call, struct dcesrv_call_reply);
713         if (!rep) {
714                 return NT_STATUS_NO_MEMORY;
715         }
716
717         status = dcerpc_push_auth(&rep->data, call, &pkt, 
718                                   call->conn->auth_state.auth_info);
719         if (!NT_STATUS_IS_OK(status)) {
720                 return status;
721         }
722
723         dcerpc_set_frag_length(&rep->data, rep->data.length);
724
725         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
726         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
727
728         return NT_STATUS_OK;
729 }
730
731 /*
732   handle a dcerpc request packet
733 */
734 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
735 {
736         struct ndr_pull *pull;
737         NTSTATUS status;
738         struct dcesrv_connection_context *context;
739
740         call->fault_code        = 0;
741         call->state_flags       = call->conn->dce_ctx->state_flags;
742         call->time              = timeval_current();
743
744         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
745         if (context == NULL) {
746                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
747         }
748
749         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
750         NT_STATUS_HAVE_NO_MEMORY(pull);
751
752         call->context   = context;
753         call->event_ctx = context->conn->srv_conn->event.ctx;
754         call->ndr_pull  = pull;
755
756         if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
757                 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
758         }
759
760         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
761                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
762         }
763
764         /* unravel the NDR for the packet */
765         status = context->iface->ndr_pull(call, call, pull, &call->r);
766         if (!NT_STATUS_IS_OK(status)) {
767                 return dcesrv_fault(call, call->fault_code);
768         }
769
770         if (pull->offset != pull->data_size) {
771                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
772                          pull->data_size - pull->offset));
773                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
774         }
775
776         /* call the dispatch function */
777         status = context->iface->dispatch(call, call, call->r);
778         if (!NT_STATUS_IS_OK(status)) {
779                 return dcesrv_fault(call, call->fault_code);
780         }
781
782         /* add the call to the pending list */
783         DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
784
785         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
786                 return NT_STATUS_OK;
787         }
788
789         return dcesrv_reply(call);
790 }
791
792 NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
793 {
794         struct ndr_push *push;
795         NTSTATUS status;
796         DATA_BLOB stub;
797         uint32_t total_length;
798         struct dcesrv_connection_context *context = call->context;
799
800         /* call the reply function */
801         status = context->iface->reply(call, call, call->r);
802         if (!NT_STATUS_IS_OK(status)) {
803                 return dcesrv_fault(call, call->fault_code);
804         }
805
806         /* form the reply NDR */
807         push = ndr_push_init_ctx(call);
808         NT_STATUS_HAVE_NO_MEMORY(push);
809
810         /* carry over the pointer count to the reply in case we are
811            using full pointer. See NDR specification for full
812            pointers */
813         push->ptr_count = call->ndr_pull->ptr_count;
814
815         if (lp_rpc_big_endian()) {
816                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
817         }
818
819         status = context->iface->ndr_push(call, call, push, call->r);
820         if (!NT_STATUS_IS_OK(status)) {
821                 return dcesrv_fault(call, call->fault_code);
822         }
823
824         stub = ndr_push_blob(push);
825
826         total_length = stub.length;
827
828         do {
829                 uint32_t length;
830                 struct dcesrv_call_reply *rep;
831                 struct dcerpc_packet pkt;
832
833                 rep = talloc(call, struct dcesrv_call_reply);
834                 NT_STATUS_HAVE_NO_MEMORY(rep);
835
836                 length = stub.length;
837                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
838                         /* the 32 is to cope with signing data */
839                         length = call->conn->cli_max_recv_frag - 
840                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
841                 }
842
843                 /* form the dcerpc response packet */
844                 dcesrv_init_hdr(&pkt);
845                 pkt.auth_length = 0;
846                 pkt.call_id = call->pkt.call_id;
847                 pkt.ptype = DCERPC_PKT_RESPONSE;
848                 pkt.pfc_flags = 0;
849                 if (stub.length == total_length) {
850                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
851                 }
852                 if (length == stub.length) {
853                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
854                 }
855                 pkt.u.response.alloc_hint = stub.length;
856                 pkt.u.response.context_id = call->pkt.u.request.context_id;
857                 pkt.u.response.cancel_count = 0;
858                 pkt.u.response.stub_and_verifier.data = stub.data;
859                 pkt.u.response.stub_and_verifier.length = length;
860
861                 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
862                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
863                 }
864
865                 dcerpc_set_frag_length(&rep->data, rep->data.length);
866
867                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
868                 
869                 stub.data += length;
870                 stub.length -= length;
871         } while (stub.length != 0);
872
873         /* move the call from the pending to the finished calls list */
874         DLIST_REMOVE(call->conn->pending_call_list, call);
875         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
876
877         if (call->conn->call_list && call->conn->call_list->replies) {
878                 if (call->conn->srv_conn &&
879                     call->conn->srv_conn->event.fde) {
880                         call->conn->srv_conn->event.fde->flags |= EVENT_FD_WRITE;
881                 }
882         }
883
884         return NT_STATUS_OK;
885 }
886
887
888 /*
889   work out if we have a full packet yet
890 */
891 static BOOL dce_full_packet(const DATA_BLOB *data)
892 {
893         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
894                 return False;
895         }
896         if (dcerpc_get_frag_length(data) > data->length) {
897                 return False;
898         }
899         return True;
900 }
901
902 /*
903   we might have consumed only part of our input - advance past that part
904 */
905 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
906 {
907         DATA_BLOB blob;
908
909         if (dce_conn->partial_input.length == offset) {
910                 data_blob_free(&dce_conn->partial_input);
911                 return;
912         }
913
914         blob = dce_conn->partial_input;
915         dce_conn->partial_input = data_blob(blob.data + offset,
916                                             blob.length - offset);
917         data_blob_free(&blob);
918 }
919
920 /*
921   process some input to a dcerpc endpoint server.
922 */
923 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
924 {
925         struct ndr_pull *ndr;
926         NTSTATUS status;
927         struct dcesrv_call_state *call;
928         DATA_BLOB blob;
929
930         call = talloc(dce_conn, struct dcesrv_call_state);
931         if (!call) {
932                 talloc_free(dce_conn->partial_input.data);
933                 return NT_STATUS_NO_MEMORY;
934         }
935         call->conn = dce_conn;
936         call->replies = NULL;
937         call->context = NULL;
938
939         blob = dce_conn->partial_input;
940         blob.length = dcerpc_get_frag_length(&blob);
941
942         ndr = ndr_pull_init_blob(&blob, call);
943         if (!ndr) {
944                 talloc_free(dce_conn->partial_input.data);
945                 talloc_free(call);
946                 return NT_STATUS_NO_MEMORY;
947         }
948
949         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
950                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
951         }
952
953         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
954         if (!NT_STATUS_IS_OK(status)) {
955                 talloc_free(dce_conn->partial_input.data);
956                 talloc_free(call);
957                 return status;
958         }
959
960         /* we have to check the signing here, before combining the
961            pdus */
962         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
963             !dcesrv_auth_request(call, &blob)) {
964                 dce_partial_advance(dce_conn, blob.length);
965                 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);          
966         }
967
968         dce_partial_advance(dce_conn, blob.length);
969
970         /* see if this is a continued packet */
971         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
972             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
973                 struct dcesrv_call_state *call2 = call;
974                 uint32_t alloc_size;
975
976                 /* we only allow fragmented requests, no other packet types */
977                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
978                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
979                 }
980
981                 /* this is a continuation of an existing call - find the call then
982                    tack it on the end */
983                 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
984                 if (!call) {
985                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
986                 }
987
988                 if (call->pkt.ptype != call2->pkt.ptype) {
989                         /* trying to play silly buggers are we? */
990                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
991                 }
992
993                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
994                         call2->pkt.u.request.stub_and_verifier.length;
995                 if (call->pkt.u.request.alloc_hint > alloc_size) {
996                         alloc_size = call->pkt.u.request.alloc_hint;
997                 }
998
999                 call->pkt.u.request.stub_and_verifier.data = 
1000                         talloc_realloc(call, 
1001                                        call->pkt.u.request.stub_and_verifier.data, 
1002                                        uint8_t, alloc_size);
1003                 if (!call->pkt.u.request.stub_and_verifier.data) {
1004                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1005                 }
1006                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1007                        call->pkt.u.request.stub_and_verifier.length,
1008                        call2->pkt.u.request.stub_and_verifier.data,
1009                        call2->pkt.u.request.stub_and_verifier.length);
1010                 call->pkt.u.request.stub_and_verifier.length += 
1011                         call2->pkt.u.request.stub_and_verifier.length;
1012
1013                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1014
1015                 talloc_free(call2);
1016         }
1017
1018         /* this may not be the last pdu in the chain - if its isn't then
1019            just put it on the call_list and wait for the rest */
1020         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1021             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1022                 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
1023                 return NT_STATUS_OK;
1024         }
1025
1026         switch (call->pkt.ptype) {
1027         case DCERPC_PKT_BIND:
1028                 status = dcesrv_bind(call);
1029                 break;
1030         case DCERPC_PKT_AUTH3:
1031                 status = dcesrv_auth3(call);
1032                 break;
1033         case DCERPC_PKT_ALTER:
1034                 status = dcesrv_alter(call);
1035                 break;
1036         case DCERPC_PKT_REQUEST:
1037                 status = dcesrv_request(call);
1038                 break;
1039         default:
1040                 status = NT_STATUS_INVALID_PARAMETER;
1041                 break;
1042         }
1043
1044         /* if we are going to be sending a reply then add
1045            it to the list of pending calls. We add it to the end to keep the call
1046            list in the order we will answer */
1047         if (!NT_STATUS_IS_OK(status)) {
1048                 talloc_free(call);
1049         }
1050
1051         return status;
1052 }
1053
1054
1055 /*
1056   provide some input to a dcerpc endpoint server. This passes data
1057   from a dcerpc client into the server
1058 */
1059 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1060 {
1061         NTSTATUS status;
1062
1063         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1064                                                       dce_conn->partial_input.data,
1065                                                       uint8_t,
1066                                                       dce_conn->partial_input.length + data->length);
1067         if (!dce_conn->partial_input.data) {
1068                 return NT_STATUS_NO_MEMORY;
1069         }
1070         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1071                data->data, data->length);
1072         dce_conn->partial_input.length += data->length;
1073
1074         while (dce_full_packet(&dce_conn->partial_input)) {
1075                 status = dcesrv_input_process(dce_conn);
1076                 if (!NT_STATUS_IS_OK(status)) {
1077                         return status;
1078                 }
1079         }
1080
1081         return NT_STATUS_OK;
1082 }
1083
1084 /*
1085   retrieve some output from a dcerpc server
1086   The caller supplies a function that will be called to do the
1087   actual output. 
1088
1089   The first argument to write_fn() will be 'private', the second will
1090   be a pointer to a buffer containing the data to be sent and the 3rd
1091   will be the number of bytes to be sent.
1092
1093   write_fn() should return the number of bytes successfully written.
1094
1095   this will return STATUS_BUFFER_OVERFLOW if there is more to be read
1096   from the current fragment
1097 */
1098 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
1099                        void *private,
1100                        ssize_t (*write_fn)(void *, DATA_BLOB *))
1101 {
1102         struct dcesrv_call_state *call;
1103         struct dcesrv_call_reply *rep;
1104         ssize_t nwritten;
1105
1106         call = dce_conn->call_list;
1107         if (!call || !call->replies) {
1108                 if (dce_conn->pending_call_list) {
1109                         /* TODO: we need to say act async here
1110                          *       as we know we have pending requests
1111                          *       which will be finished at a time
1112                          */
1113                         return NT_STATUS_FOOBAR;
1114                 }
1115                 return NT_STATUS_FOOBAR;
1116         }
1117         rep = call->replies;
1118
1119         nwritten = write_fn(private, &rep->data);
1120         if (nwritten == -1) {
1121                 /* TODO: hmm, how do we cope with this? destroy the
1122                    connection perhaps? */
1123                 return NT_STATUS_UNSUCCESSFUL;
1124         }
1125
1126         rep->data.length -= nwritten;
1127         rep->data.data += nwritten;
1128
1129         if (rep->data.length == 0) {
1130                 /* we're done with this section of the call */
1131                 DLIST_REMOVE(call->replies, rep);
1132         } else {
1133                 return STATUS_BUFFER_OVERFLOW;
1134         }
1135
1136         if (call->replies == NULL) {
1137                 /* we're done with the whole call */
1138                 DLIST_REMOVE(dce_conn->call_list, call);
1139                 talloc_free(call);
1140         }
1141
1142         return NT_STATUS_OK;
1143 }
1144
1145
1146 /*
1147   write_fn() for dcesrv_output_blob()
1148 */
1149 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1150 {
1151         DATA_BLOB *blob = private;
1152         if (out->length < blob->length) {
1153                 blob->length = out->length;
1154         }
1155         memcpy(blob->data, out->data, blob->length);
1156         return blob->length;
1157 }
1158
1159 /*
1160   a simple wrapper for dcesrv_output() for when we want to output
1161   into a data blob
1162 */
1163 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn, 
1164                             DATA_BLOB *blob)
1165 {
1166         return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1167 }
1168
1169 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, uint32_t state_flags, struct dcesrv_context **_dce_ctx)
1170 {
1171         NTSTATUS status;
1172         struct dcesrv_context *dce_ctx;
1173         int i;
1174
1175         DEBUG(1,("dcesrv_init\n"));
1176
1177         if (!endpoint_servers) {
1178                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1179                 return NT_STATUS_INTERNAL_ERROR;
1180         }
1181
1182         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1183         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1184         dce_ctx->endpoint_list  = NULL;
1185         dce_ctx->state_flags    = state_flags;
1186
1187         for (i=0;endpoint_servers[i];i++) {
1188                 const struct dcesrv_endpoint_server *ep_server;
1189
1190                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1191                 if (!ep_server) {
1192                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1193                         return NT_STATUS_INTERNAL_ERROR;
1194                 }
1195
1196                 status = ep_server->init_server(dce_ctx, ep_server);
1197                 if (!NT_STATUS_IS_OK(status)) {
1198                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1199                                 nt_errstr(status)));
1200                         return status;
1201                 }
1202         }
1203
1204         *_dce_ctx = dce_ctx;
1205         return NT_STATUS_OK;
1206 }
1207
1208 /*
1209   initialise the dcerpc server context
1210 */
1211 NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1212 {
1213         NTSTATUS status;
1214         struct dcesrv_context *dce_ctx;
1215
1216         status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), 0, &dce_ctx);
1217         NT_STATUS_NOT_OK_RETURN(status);
1218
1219         *_dce_ctx = dce_ctx;
1220         return NT_STATUS_OK;
1221 }
1222
1223 static void dcesrv_init(struct server_service *service)
1224 {
1225         NTSTATUS status;
1226         struct dcesrv_context *dce_ctx;
1227
1228         DEBUG(1,("dcesrv_init\n"));
1229
1230         status = dcesrv_init_context(service,
1231                                      lp_dcerpc_endpoint_servers(),
1232                                      DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1233                                      &dce_ctx);
1234         if (!NT_STATUS_IS_OK(status)) {
1235                 return;
1236         }
1237
1238         service->service.private_data = dce_ctx;
1239
1240         dcesrv_sock_init(service);
1241
1242         return; 
1243 }
1244
1245 static void dcesrv_accept(struct server_connection *srv_conn)
1246 {
1247         dcesrv_sock_accept(srv_conn);
1248 }
1249
1250 static void dcesrv_recv(struct server_connection *srv_conn, 
1251                         struct timeval t, uint16_t flags)
1252 {
1253         dcesrv_sock_recv(srv_conn, t, flags);
1254 }
1255
1256 static void dcesrv_send(struct server_connection *srv_conn, 
1257                         struct timeval t, uint16_t flags)
1258 {
1259         dcesrv_sock_send(srv_conn, t, flags);
1260 }
1261
1262 /* the list of currently registered DCERPC endpoint servers.
1263  */
1264 static struct ep_server {
1265         struct dcesrv_endpoint_server *ep_server;
1266 } *ep_servers = NULL;
1267 static int num_ep_servers;
1268
1269 /*
1270   register a DCERPC endpoint server. 
1271
1272   The 'name' can be later used by other backends to find the operations
1273   structure for this backend.  
1274
1275   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1276 */
1277 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1278 {
1279         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1280         
1281         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1282                 /* its already registered! */
1283                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1284                          ep_server->name));
1285                 return NT_STATUS_OBJECT_NAME_COLLISION;
1286         }
1287
1288         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1289         if (!ep_servers) {
1290                 smb_panic("out of memory in dcerpc_register");
1291         }
1292
1293         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1294         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1295
1296         num_ep_servers++;
1297
1298         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1299                  ep_server->name));
1300
1301         return NT_STATUS_OK;
1302 }
1303
1304 /*
1305   return the operations structure for a named backend of the specified type
1306 */
1307 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1308 {
1309         int i;
1310
1311         for (i=0;i<num_ep_servers;i++) {
1312                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1313                         return ep_servers[i].ep_server;
1314                 }
1315         }
1316
1317         return NULL;
1318 }
1319
1320 /*
1321   return the DCERPC module version, and the size of some critical types
1322   This can be used by endpoint server modules to either detect compilation errors, or provide
1323   multiple implementations for different smbd compilation options in one module
1324 */
1325 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1326 {
1327         static const struct dcesrv_critical_sizes critical_sizes = {
1328                 DCERPC_MODULE_VERSION,
1329                 sizeof(struct dcesrv_context),
1330                 sizeof(struct dcesrv_endpoint),
1331                 sizeof(struct dcesrv_endpoint_server),
1332                 sizeof(struct dcesrv_interface),
1333                 sizeof(struct dcesrv_if_list),
1334                 sizeof(struct dcesrv_connection),
1335                 sizeof(struct dcesrv_call_state),
1336                 sizeof(struct dcesrv_auth),
1337                 sizeof(struct dcesrv_handle)
1338         };
1339
1340         return &critical_sizes;
1341 }
1342
1343 static const struct server_stream_ops dcesrv_stream_ops = {
1344         .name                   = "rpc",
1345         .socket_init            = NULL,
1346         .accept_connection      = dcesrv_accept,
1347         .recv_handler           = dcesrv_recv,
1348         .send_handler           = dcesrv_send,
1349         .idle_handler           = NULL,
1350         .close_connection       = NULL
1351 };
1352
1353 const struct server_stream_ops *dcesrv_get_stream_ops(void)
1354 {
1355         return &dcesrv_stream_ops;
1356 }
1357
1358 static const struct server_service_ops dcesrv_ops = {
1359         .name                   = "rpc",
1360         .service_init           = dcesrv_init,
1361 };
1362
1363 const struct server_service_ops *dcesrv_get_ops(void)
1364 {
1365         return &dcesrv_ops;
1366 }
1367
1368 NTSTATUS server_service_rpc_init(void)
1369 {
1370         return NT_STATUS_OK;    
1371 }