r623: setUserInfo level 24 (password set) now works in the SAMR server. This includes all
[samba.git] / source4 / rpc_server / dcerpc_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc core code
5
6    Copyright (C) Andrew Tridgell 2003
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 (strcmp(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 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 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 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(dce_ctx->mem_ctx, sizeof(*ep));
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(dce_ctx->mem_ctx, sizeof(*ifl));
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->mem_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 /*
243   connect to a dcerpc endpoint
244 */
245 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
246                                  const struct dcesrv_endpoint *ep,
247                                  struct dcesrv_connection **p)
248 {
249         TALLOC_CTX *mem_ctx;
250
251         mem_ctx = talloc_init("dcesrv_endpoint_connect");
252         if (!mem_ctx) {
253                 return NT_STATUS_NO_MEMORY;
254         }
255
256         *p = talloc_p(mem_ctx, struct dcesrv_connection);
257         if (! *p) {
258                 talloc_destroy(mem_ctx);
259                 return NT_STATUS_NO_MEMORY;
260         }
261
262         (*p)->dce_ctx = dce_ctx;
263         (*p)->mem_ctx = mem_ctx;
264         (*p)->endpoint = ep;
265         (*p)->iface = NULL;
266         (*p)->private = NULL;
267         (*p)->call_list = NULL;
268         (*p)->cli_max_recv_frag = 0;
269         (*p)->handles = NULL;
270         (*p)->partial_input = data_blob(NULL, 0);
271         (*p)->auth_state.ntlmssp_state = NULL;
272         (*p)->auth_state.auth_info = NULL;
273         (*p)->session_key = data_blob(NULL, 0);
274
275         return NT_STATUS_OK;
276 }
277
278 /*
279   set the transport level session key
280 */
281 void dcesrv_set_session_key(struct dcesrv_connection *p, DATA_BLOB key)
282 {
283         p->session_key = data_blob_talloc(p->mem_ctx, key.data, key.length);
284 }
285
286 /*
287   search and connect to a dcerpc endpoint
288 */
289 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
290                                         const struct dcesrv_ep_description *ep_description,
291                                         struct dcesrv_connection **dce_conn_p)
292 {
293         NTSTATUS status;
294         const struct dcesrv_endpoint *ep;
295
296         /* make sure this endpoint exists */
297         ep = find_endpoint(dce_ctx, ep_description);
298         if (!ep) {
299                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
300         }
301
302         status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
303         if (!NT_STATUS_IS_OK(status)) {
304                 return status;
305         }
306
307         /* TODO: check security descriptor of the endpoint here 
308          *       if it's a smb named pipe
309          *       if it's failed free dce_conn_p
310          */
311
312         return NT_STATUS_OK;
313 }
314
315
316 /*
317   disconnect a link to an endpoint
318 */
319 void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
320 {
321         if (p->iface) {
322                 p->iface->unbind(p, p->iface);
323         }
324
325         /* destroy any handles */
326         while (p->handles) {
327                 dcesrv_handle_destroy(p, p->handles);
328         }
329         
330         talloc_destroy(p->mem_ctx);
331 }
332
333 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
334 {
335         pkt->rpc_vers = 5;
336         pkt->rpc_vers_minor = 0;
337         if (lp_rpc_big_endian()) {
338                 pkt->drep[0] = 0;
339         } else {
340                 pkt->drep[0] = DCERPC_DREP_LE;
341         }
342         pkt->drep[1] = 0;
343         pkt->drep[2] = 0;
344         pkt->drep[3] = 0;
345 }
346
347 /*
348   return a dcerpc fault
349 */
350 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
351 {
352         struct dcerpc_packet pkt;
353         struct dcesrv_call_reply *rep;
354         NTSTATUS status;
355
356         /* setup a bind_ack */
357         dcesrv_init_hdr(&pkt);
358         pkt.auth_length = 0;
359         pkt.call_id = call->pkt.call_id;
360         pkt.ptype = DCERPC_PKT_FAULT;
361         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
362         pkt.u.fault.alloc_hint = 0;
363         pkt.u.fault.context_id = 0;
364         pkt.u.fault.cancel_count = 0;
365         pkt.u.fault.status = fault_code;
366
367         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
368         if (!rep) {
369                 return NT_STATUS_NO_MEMORY;
370         }
371
372         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
373         if (!NT_STATUS_IS_OK(status)) {
374                 return status;
375         }
376
377         dcerpc_set_frag_length(&rep->data, rep->data.length);
378
379         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
380         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
381
382         return NT_STATUS_OK;    
383 }
384
385
386 /*
387   return a dcerpc bind_nak
388 */
389 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason)
390 {
391         struct dcerpc_packet pkt;
392         struct dcesrv_call_reply *rep;
393         NTSTATUS status;
394
395         /* setup a bind_nak */
396         dcesrv_init_hdr(&pkt);
397         pkt.auth_length = 0;
398         pkt.call_id = call->pkt.call_id;
399         pkt.ptype = DCERPC_PKT_BIND_NAK;
400         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
401         pkt.u.bind_nak.reject_reason = reason;
402         pkt.u.bind_nak.num_versions = 0;
403
404         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
405         if (!rep) {
406                 return NT_STATUS_NO_MEMORY;
407         }
408
409         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
410         if (!NT_STATUS_IS_OK(status)) {
411                 return status;
412         }
413
414         dcerpc_set_frag_length(&rep->data, rep->data.length);
415
416         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
417         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
418
419         return NT_STATUS_OK;    
420 }
421
422
423 /*
424   handle a bind request
425 */
426 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
427 {
428         const char *uuid, *transfer_syntax;
429         uint32 if_version, transfer_syntax_version;
430         struct dcerpc_packet pkt;
431         struct dcesrv_call_reply *rep;
432         NTSTATUS status;
433         uint32 result=0, reason=0;
434
435         if (call->pkt.u.bind.num_contexts != 1 ||
436             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
437                 return dcesrv_bind_nak(call, 0);
438         }
439
440         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
441         uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
442         if (!uuid) {
443                 return dcesrv_bind_nak(call, 0);
444         }
445
446         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
447         transfer_syntax = GUID_string(call->mem_ctx, 
448                                       &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
449         if (!transfer_syntax ||
450             strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
451             NDR_GUID_VERSION != transfer_syntax_version) {
452                 /* we only do NDR encoded dcerpc */
453                 return dcesrv_bind_nak(call, 0);
454         }
455
456         call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
457         if (!call->conn->iface) {
458                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
459                 /* we don't know about that interface */
460                 result = DCERPC_BIND_PROVIDER_REJECT;
461                 reason = DCERPC_BIND_REASON_ASYNTAX;            
462         }
463
464         if (call->conn->cli_max_recv_frag == 0) {
465                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
466         }
467
468         /* handle any authentication that is being requested */
469         if (!dcesrv_auth_bind(call)) {
470                 /* TODO: work out the right reject code */
471                 return dcesrv_bind_nak(call, 0);
472         }
473
474         /* setup a bind_ack */
475         dcesrv_init_hdr(&pkt);
476         pkt.auth_length = 0;
477         pkt.call_id = call->pkt.call_id;
478         pkt.ptype = DCERPC_PKT_BIND_ACK;
479         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
480         pkt.u.bind_ack.max_xmit_frag = 0x2000;
481         pkt.u.bind_ack.max_recv_frag = 0x2000;
482         pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
483         if (call->conn->iface && call->conn->iface->ndr) {
484                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s", 
485                                                                    call->conn->iface->ndr->name);
486         } else {
487                 pkt.u.bind_ack.secondary_address = "";
488         }
489         pkt.u.bind_ack.num_results = 1;
490         pkt.u.bind_ack.ctx_list = talloc_p(call->mem_ctx, struct dcerpc_ack_ctx);
491         if (!pkt.u.bind_ack.ctx_list) {
492                 return NT_STATUS_NO_MEMORY;
493         }
494         pkt.u.bind_ack.ctx_list[0].result = result;
495         pkt.u.bind_ack.ctx_list[0].reason = reason;
496         GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
497         pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
498         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
499
500         if (!dcesrv_auth_bind_ack(call, &pkt)) {
501                 return dcesrv_bind_nak(call, 0);
502         }
503
504         if (call->conn->iface) {
505                 status = call->conn->iface->bind(call, call->conn->iface);
506                 if (!NT_STATUS_IS_OK(status)) {
507                         DEBUG(2,("Request for dcerpc interface %s/%d rejected\n", uuid, if_version));
508                         return status;
509                 }
510         }
511
512         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
513         if (!rep) {
514                 return NT_STATUS_NO_MEMORY;
515         }
516
517         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, 
518                                   call->conn->auth_state.auth_info);
519         if (!NT_STATUS_IS_OK(status)) {
520                 return status;
521         }
522
523         dcerpc_set_frag_length(&rep->data, rep->data.length);
524
525         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
526         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
527
528         return NT_STATUS_OK;
529 }
530
531
532 /*
533   handle a auth3 request
534 */
535 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
536 {
537         /* handle the auth3 in the auth code */
538         if (!dcesrv_auth_auth3(call)) {
539                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
540         }
541
542         talloc_destroy(call->mem_ctx);
543
544         /* we don't send a reply to a auth3 request, except by a
545            fault */
546         return NT_STATUS_OK;
547 }
548
549
550 /*
551   handle a dcerpc request packet
552 */
553 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
554 {
555         struct ndr_pull *pull;
556         struct ndr_push *push;
557         uint16 opnum;
558         void *r;
559         NTSTATUS status;
560         DATA_BLOB stub;
561         uint32 total_length;
562
563         opnum = call->pkt.u.request.opnum;
564
565         if (opnum >= call->conn->iface->ndr->num_calls) {
566                 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
567         }
568
569         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call->mem_ctx);
570         if (!pull) {
571                 return NT_STATUS_NO_MEMORY;
572         }
573
574         r = talloc(call->mem_ctx, call->conn->iface->ndr->calls[opnum].struct_size);
575         if (!r) {
576                 return NT_STATUS_NO_MEMORY;
577         }
578
579         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
580                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
581         }
582
583         /* unravel the NDR for the packet */
584         status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
585         if (!NT_STATUS_IS_OK(status)) {
586                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
587         }
588
589         call->fault_code = 0;
590
591         /* call the dispatch function */
592         status = call->conn->iface->dispatch(call, call->mem_ctx, r);
593         if (!NT_STATUS_IS_OK(status)) {
594                 return dcesrv_fault(call, call->fault_code);
595         }
596
597         /* form the reply NDR */
598         push = ndr_push_init_ctx(call->mem_ctx);
599         if (!push) {
600                 return NT_STATUS_NO_MEMORY;
601         }
602
603         if (lp_rpc_big_endian()) {
604                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
605         }
606
607         status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
608         if (!NT_STATUS_IS_OK(status)) {
609                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
610         }
611
612         stub = ndr_push_blob(push);
613
614         total_length = stub.length;
615
616         do {
617                 uint32 length;
618                 struct dcesrv_call_reply *rep;
619                 struct dcerpc_packet pkt;
620
621                 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
622                 if (!rep) {
623                         return NT_STATUS_NO_MEMORY;
624                 }
625
626                 length = stub.length;
627                 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
628                         /* the 32 is to cope with signing data */
629                         length = call->conn->cli_max_recv_frag - 
630                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
631                 }
632
633                 /* form the dcerpc response packet */
634                 dcesrv_init_hdr(&pkt);
635                 pkt.auth_length = 0;
636                 pkt.call_id = call->pkt.call_id;
637                 pkt.ptype = DCERPC_PKT_RESPONSE;
638                 pkt.pfc_flags = 0;
639                 if (stub.length == total_length) {
640                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
641                 }
642                 if (length == stub.length) {
643                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
644                 }
645                 pkt.u.response.alloc_hint = stub.length;
646                 pkt.u.response.context_id = call->pkt.u.request.context_id;
647                 pkt.u.response.cancel_count = 0;
648                 pkt.u.response.stub_and_verifier.data = stub.data;
649                 pkt.u.response.stub_and_verifier.length = length;
650
651                 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
652                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
653                 }
654
655                 dcerpc_set_frag_length(&rep->data, rep->data.length);
656
657                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
658                 
659                 stub.data += length;
660                 stub.length -= length;
661         } while (stub.length != 0);
662
663         DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
664
665         return NT_STATUS_OK;
666 }
667
668
669 /*
670   work out if we have a full packet yet
671 */
672 static BOOL dce_full_packet(const DATA_BLOB *data)
673 {
674         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
675                 return False;
676         }
677         if (dcerpc_get_frag_length(data) > data->length) {
678                 return False;
679         }
680         return True;
681 }
682
683 /*
684   we might have consumed only part of our input - advance past that part
685 */
686 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32 offset)
687 {
688         DATA_BLOB blob;
689
690         if (dce_conn->partial_input.length == offset) {
691                 data_blob_free(&dce_conn->partial_input);
692                 return;
693         }
694
695         blob = dce_conn->partial_input;
696         dce_conn->partial_input = data_blob(blob.data + offset,
697                                             blob.length - offset);
698         data_blob_free(&blob);
699 }
700
701 /*
702   process some input to a dcerpc endpoint server.
703 */
704 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
705 {
706         struct ndr_pull *ndr;
707         TALLOC_CTX *mem_ctx;
708         NTSTATUS status;
709         struct dcesrv_call_state *call;
710         DATA_BLOB blob;
711
712         mem_ctx = talloc_init("dcesrv_input");
713         if (!mem_ctx) {
714                 return NT_STATUS_NO_MEMORY;
715         }
716         call = talloc_p(mem_ctx, struct dcesrv_call_state);
717         if (!call) {
718                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
719                 talloc_destroy(mem_ctx);
720                 return NT_STATUS_NO_MEMORY;
721         }
722         call->mem_ctx = mem_ctx;
723         call->conn = dce_conn;
724         call->replies = NULL;
725
726         blob = dce_conn->partial_input;
727         blob.length = dcerpc_get_frag_length(&blob);
728
729         ndr = ndr_pull_init_blob(&blob, mem_ctx);
730         if (!ndr) {
731                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
732                 talloc_destroy(mem_ctx);
733                 return NT_STATUS_NO_MEMORY;
734         }
735
736         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
737                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
738         }
739
740         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
741         if (!NT_STATUS_IS_OK(status)) {
742                 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
743                 talloc_destroy(mem_ctx);
744                 return status;
745         }
746
747         dce_partial_advance(dce_conn, blob.length);
748
749         /* we have to check the signing here, before combining the
750            pdus */
751         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
752             !dcesrv_auth_request(call)) {
753                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
754         }
755
756         /* see if this is a continued packet */
757         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
758                 struct dcesrv_call_state *call2 = call;
759                 uint32 alloc_size;
760
761                 /* we only allow fragmented requests, no other packet types */
762                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
763                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
764                 }
765
766                 /* this is a continuation of an existing call - find the call then
767                    tack it on the end */
768                 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
769                 if (!call) {
770                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
771                 }
772
773                 if (call->pkt.ptype != call2->pkt.ptype) {
774                         /* trying to play silly buggers are we? */
775                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
776                 }
777
778                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
779                         call2->pkt.u.request.stub_and_verifier.length;
780                 if (call->pkt.u.request.alloc_hint > alloc_size) {
781                         alloc_size = call->pkt.u.request.alloc_hint;
782                 }
783
784                 call->pkt.u.request.stub_and_verifier.data = 
785                         talloc_realloc(call->mem_ctx,
786                                        call->pkt.u.request.stub_and_verifier.data, alloc_size);
787                 if (!call->pkt.u.request.stub_and_verifier.data) {
788                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
789                 }
790                 memcpy(call->pkt.u.request.stub_and_verifier.data +
791                        call->pkt.u.request.stub_and_verifier.length,
792                        call2->pkt.u.request.stub_and_verifier.data,
793                        call2->pkt.u.request.stub_and_verifier.length);
794                 call->pkt.u.request.stub_and_verifier.length += 
795                         call2->pkt.u.request.stub_and_verifier.length;
796
797                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
798         }
799
800         /* this may not be the last pdu in the chain - if its isn't then
801            just put it on the call_list and wait for the rest */
802         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
803                 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
804                 return NT_STATUS_OK;
805         }
806
807         switch (call->pkt.ptype) {
808         case DCERPC_PKT_BIND:
809                 status = dcesrv_bind(call);
810                 break;
811         case DCERPC_PKT_AUTH3:
812                 status = dcesrv_auth3(call);
813                 break;
814         case DCERPC_PKT_REQUEST:
815                 status = dcesrv_request(call);
816                 break;
817         default:
818                 status = NT_STATUS_INVALID_PARAMETER;
819                 break;
820         }
821
822         /* if we are going to be sending a reply then add
823            it to the list of pending calls. We add it to the end to keep the call
824            list in the order we will answer */
825         if (!NT_STATUS_IS_OK(status)) {
826                 talloc_destroy(mem_ctx);
827         }
828
829         return status;
830 }
831
832
833 /*
834   provide some input to a dcerpc endpoint server. This passes data
835   from a dcerpc client into the server
836 */
837 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
838 {
839         NTSTATUS status;
840
841         /* handle the very common case that the input contains a full packet and there
842            is no partial packet pending. In this case we can avoid a copy of the
843            data */
844         if (dce_conn->partial_input.length == 0) {
845                 dce_conn->partial_input = *data;
846                 /* make sure that dce_partial_advance doesn't free this data */
847                 dce_conn->partial_input.free = NULL;
848                 while (dce_full_packet(&dce_conn->partial_input)) {
849                         status = dcesrv_input_process(dce_conn);
850                         if (!NT_STATUS_IS_OK(status)) {
851                                 return status;
852                         }
853                 }
854                 if (dce_conn->partial_input.length) {
855                         /* there was some data left over. We have to copy this
856                            as the caller may free the data */
857                         dce_conn->partial_input = 
858                                 data_blob(dce_conn->partial_input.data,
859                                           dce_conn->partial_input.length);
860                         if (!dce_conn->partial_input.data) {
861                                 return NT_STATUS_NO_MEMORY;
862                         }
863                 }
864                 return NT_STATUS_OK;
865         }
866
867         dce_conn->partial_input.data = Realloc(dce_conn->partial_input.data,
868                                           dce_conn->partial_input.length + data->length);
869         if (!dce_conn->partial_input.data) {
870                 return NT_STATUS_NO_MEMORY;
871         }
872         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
873                data->data, data->length);
874         dce_conn->partial_input.length += data->length;
875
876         while (dce_full_packet(&dce_conn->partial_input)) {
877                 status = dcesrv_input_process(dce_conn);
878                 if (!NT_STATUS_IS_OK(status)) {
879                         return status;
880                 }
881         }
882
883         return NT_STATUS_OK;
884 }
885
886 /*
887   retrieve some output from a dcerpc server
888   The caller supplies a function that will be called to do the
889   actual output. 
890
891   The first argument to write_fn() will be 'private', the second will
892   be a pointer to a buffer containing the data to be sent and the 3rd
893   will be the number of bytes to be sent.
894
895   write_fn() should return the number of bytes successfully written.
896 */
897 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
898                        void *private,
899                        ssize_t (*write_fn)(void *, const void *, size_t))
900 {
901         struct dcesrv_call_state *call;
902         struct dcesrv_call_reply *rep;
903         ssize_t nwritten;
904
905         call = dce_conn->call_list;
906         if (!call || !call->replies) {
907                 return NT_STATUS_FOOBAR;
908         }
909         rep = call->replies;
910
911         nwritten = write_fn(private, rep->data.data, rep->data.length);
912         if (nwritten == -1) {
913                 /* TODO: hmm, how do we cope with this? destroy the
914                    connection perhaps? */
915                 return NT_STATUS_UNSUCCESSFUL;
916         }
917
918         rep->data.length -= nwritten;
919         rep->data.data += nwritten;
920
921         if (rep->data.length == 0) {
922                 /* we're done with this section of the call */
923                 DLIST_REMOVE(call->replies, rep);
924         }
925
926         if (call->replies == NULL) {
927                 /* we're done with the whole call */
928                 DLIST_REMOVE(dce_conn->call_list, call);
929                 talloc_destroy(call->mem_ctx);
930         }
931
932         return NT_STATUS_OK;
933 }
934
935
936 /*
937   write_fn() for dcesrv_output_blob()
938 */
939 static ssize_t dcesrv_output_blob_write_fn(void *private, const void *buf, size_t count)
940 {
941         DATA_BLOB *blob = private;
942         if (count < blob->length) {
943                 blob->length = count;
944         }
945         memcpy(blob->data, buf, blob->length);
946         return blob->length;
947 }
948
949 /*
950   a simple wrapper for dcesrv_output() for when we want to output
951   into a data blob
952 */
953 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn, 
954                             DATA_BLOB *blob)
955 {
956         return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
957 }
958
959 /*
960   initialise the dcerpc server context
961 */
962 NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
963 {
964         int i;
965         const char **endpoint_servers = lp_dcerpc_endpoint_servers();
966
967         dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
968         if (!dce_ctx->mem_ctx) {
969                 DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
970                 return NT_STATUS_NO_MEMORY;
971         }
972
973         dce_ctx->endpoint_list = NULL;
974
975         if (!endpoint_servers) {
976                 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
977                 return NT_STATUS_OK;
978         }
979
980         for (i=0;endpoint_servers[i];i++) {
981                 NTSTATUS ret;
982                 const struct dcesrv_endpoint_server *ep_server;
983                 
984                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
985                 if (!ep_server) {
986                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
987                         return NT_STATUS_UNSUCCESSFUL;
988                 }
989
990                 ret = ep_server->init_server(dce_ctx, ep_server);
991                 if (!NT_STATUS_IS_OK(ret)) {
992                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
993                         return ret;
994                 }
995         }
996
997         return NT_STATUS_OK;
998 }
999
1000 /* the list of currently registered DCERPC endpoint servers.
1001  */
1002 static struct {
1003         struct dcesrv_endpoint_server *ep_server;
1004 } *ep_servers = NULL;
1005 static int num_ep_servers;
1006
1007 /*
1008   register a DCERPC endpoint server. 
1009
1010   The 'name' can be later used by other backends to find the operations
1011   structure for this backend.  
1012
1013   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1014 */
1015 static NTSTATUS decrpc_register_ep_server(void *_ep_server)
1016 {
1017         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1018         
1019         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1020                 /* its already registered! */
1021                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1022                          ep_server->name));
1023                 return NT_STATUS_OBJECT_NAME_COLLISION;
1024         }
1025
1026         ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1027         if (!ep_servers) {
1028                 smb_panic("out of memory in decrpc_register");
1029         }
1030
1031         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1032         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1033
1034         num_ep_servers++;
1035
1036         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1037                  ep_server->name));
1038
1039         return NT_STATUS_OK;
1040 }
1041
1042 /*
1043   return the operations structure for a named backend of the specified type
1044 */
1045 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1046 {
1047         int i;
1048
1049         for (i=0;i<num_ep_servers;i++) {
1050                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1051                         return ep_servers[i].ep_server;
1052                 }
1053         }
1054
1055         return NULL;
1056 }
1057
1058 /*
1059   return the DCERPC module version, and the size of some critical types
1060   This can be used by endpoint server modules to either detect compilation errors, or provide
1061   multiple implementations for different smbd compilation options in one module
1062 */
1063 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1064 {
1065         static const struct dcesrv_critical_sizes critical_sizes = {
1066                 DCERPC_MODULE_VERSION,
1067                 sizeof(struct dcesrv_context),
1068                 sizeof(struct dcesrv_endpoint),
1069                 sizeof(struct dcesrv_endpoint_server),
1070                 sizeof(struct dcesrv_ep_description),
1071                 sizeof(struct dcesrv_interface),
1072                 sizeof(struct dcesrv_if_list),
1073                 sizeof(struct dcesrv_connection),
1074                 sizeof(struct dcesrv_call_state),
1075                 sizeof(struct dcesrv_auth),
1076                 sizeof(struct dcesrv_handle)
1077         };
1078
1079         return &critical_sizes;
1080 }
1081
1082 /*
1083   initialise the DCERPC subsystem
1084 */
1085 BOOL dcesrv_init(void)
1086 {
1087         NTSTATUS status;
1088
1089         status = register_subsystem("dcerpc", decrpc_register_ep_server); 
1090         if (!NT_STATUS_IS_OK(status)) {
1091                 return False;
1092         }
1093
1094         /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1095         static_init_dcerpc;
1096
1097         DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1098         return True;
1099 }