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