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