5780de0c302bfabd65729f0ddce24a90d063616c
[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    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /*
26   find the set of endpoint operations for an endpoint server
27 */
28 static const struct dcesrv_endpoint_ops *find_endpoint(struct dcesrv_context *dce,
29                                                        const struct dcesrv_endpoint *endpoint)
30 {
31         struct dce_endpoint *ep;
32         for (ep=dce->endpoint_list; ep; ep=ep->next) {
33                 if (ep->endpoint_ops->query_endpoint(endpoint)) {
34                         return ep->endpoint_ops;
35                 }
36         }
37         return NULL;
38 }
39
40 /*
41   find a call that is pending in our call list
42 */
43 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_state *dce, uint16 call_id)
44 {
45         struct dcesrv_call_state *c;
46         for (c=dce->call_list;c;c=c->next) {
47                 if (c->pkt.call_id == call_id) {
48                         return c;
49                 }
50         }
51         return NULL;
52 }
53
54 /*
55   register an endpoint server
56 */
57 BOOL dcesrv_endpoint_register(struct dcesrv_context *dce, 
58                               const struct dcesrv_endpoint_ops *ops,
59                               const struct dcerpc_interface_table *table)
60 {
61         BOOL done_smb=False;
62         BOOL done_tcp=False;
63         int i;
64
65         for (i=0;i<table->endpoints->count;i++) {
66                 struct dce_endpoint *ep;
67                 BOOL tcp;
68
69                 tcp = (strncasecmp(table->endpoints->names[i], "TCP-", 4) == 0);
70
71                 if (tcp) {
72                         if (done_tcp) continue;
73                         done_tcp = True;
74                 } else {
75                         if (done_smb) continue;
76                         done_smb = True;
77                 }
78
79                 ep = malloc(sizeof(*ep));
80                 if (!ep) {
81                         return False;
82                 }
83
84                 if (tcp) {
85                         ep->endpoint.type = ENDPOINT_TCP;
86                         ep->endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4);
87                 } else {
88                         ep->endpoint.type = ENDPOINT_SMB;
89                         ep->endpoint.info.smb_pipe = table->endpoints->names[i];
90                 }
91
92                 ep->endpoint_ops = ops;
93                 DLIST_ADD(dce->endpoint_list, ep);
94         }
95
96         return True;
97 }
98
99 /*
100   connect to a dcerpc endpoint
101 */
102 NTSTATUS dcesrv_endpoint_connect_ops(struct dcesrv_context *dce,
103                                      const struct dcesrv_endpoint *endpoint,
104                                      const struct dcesrv_endpoint_ops *ops,
105                                      struct dcesrv_state **p)
106 {
107         TALLOC_CTX *mem_ctx;
108         NTSTATUS status;
109
110         mem_ctx = talloc_init("dcesrv_endpoint_connect");
111         if (!mem_ctx) {
112                 return NT_STATUS_NO_MEMORY;
113         }
114
115         *p = talloc_p(mem_ctx, struct dcesrv_state);
116         if (! *p) {
117                 talloc_destroy(mem_ctx);
118                 return NT_STATUS_NO_MEMORY;
119         }
120
121         (*p)->dce = dce;
122         (*p)->mem_ctx = mem_ctx;
123         (*p)->endpoint = *endpoint;
124         (*p)->ops = ops;
125         (*p)->private = NULL;
126         (*p)->call_list = NULL;
127         (*p)->cli_max_recv_frag = 0;
128         (*p)->ndr = NULL;
129         (*p)->dispatch = NULL;
130         (*p)->handles = NULL;
131         (*p)->next_handle = 0;
132         (*p)->partial_input = data_blob(NULL, 0);
133         (*p)->auth_state.ntlmssp_state = NULL;
134         (*p)->auth_state.auth_info = NULL;
135
136         /* make sure the endpoint server likes the connection */
137         status = ops->connect(*p);
138         if (!NT_STATUS_IS_OK(status)) {
139                 talloc_destroy(mem_ctx);
140                 return status;
141         }
142         
143         return NT_STATUS_OK;
144 }
145
146 /*
147   connect to a dcerpc endpoint
148 */
149 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce,
150                                  const struct dcesrv_endpoint *endpoint,
151                                  struct dcesrv_state **p)
152 {
153         const struct dcesrv_endpoint_ops *ops;
154
155         /* make sure this endpoint exists */
156         ops = find_endpoint(dce, endpoint);
157         if (!ops) {
158                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
159         }
160
161         return dcesrv_endpoint_connect_ops(dce, endpoint, ops, p);
162 }
163
164
165 /*
166   disconnect a link to an endpoint
167 */
168 void dcesrv_endpoint_disconnect(struct dcesrv_state *p)
169 {
170         p->ops->disconnect(p);
171
172         /* destroy any handles */
173         while (p->handles) {
174                 TALLOC_CTX *m = p->handles->mem_ctx;
175                 DLIST_REMOVE(p->handles, p->handles);
176                 talloc_destroy(m);
177         }
178         
179         talloc_destroy(p->mem_ctx);
180 }
181
182 /*
183   return a dcerpc fault
184 */
185 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
186 {
187         struct dcerpc_packet pkt;
188         struct dcesrv_call_reply *rep;
189         NTSTATUS status;
190
191         /* setup a bind_ack */
192         pkt.rpc_vers = 5;
193         pkt.rpc_vers_minor = 0;
194         pkt.drep[0] = 0x10; /* Little endian */
195         pkt.drep[1] = 0;
196         pkt.drep[2] = 0;
197         pkt.drep[3] = 0;
198         pkt.auth_length = 0;
199         pkt.call_id = call->pkt.call_id;
200         pkt.ptype = DCERPC_PKT_FAULT;
201         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
202         pkt.u.fault.alloc_hint = 0;
203         pkt.u.fault.context_id = 0;
204         pkt.u.fault.cancel_count = 0;
205         pkt.u.fault.status = fault_code;
206
207         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
208         if (!rep) {
209                 return NT_STATUS_NO_MEMORY;
210         }
211
212         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL, 0);
213         if (!NT_STATUS_IS_OK(status)) {
214                 return status;
215         }
216
217         SSVAL(rep->data.data,  DCERPC_FRAG_LEN_OFFSET, rep->data.length);
218
219         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
220
221         return NT_STATUS_OK;    
222 }
223
224
225 /*
226   return a dcerpc fault from a ntstatus code
227 */
228 static NTSTATUS dcesrv_fault_nt(struct dcesrv_call_state *call, NTSTATUS status)
229 {
230         uint32 fault_code = DCERPC_FAULT_OTHER;
231
232         /* TODO: we need to expand this table to include more mappings */
233         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
234                 fault_code = DCERPC_FAULT_CONTEXT_MISMATCH;
235         }
236
237         return dcesrv_fault(call, fault_code);
238 }
239
240
241 /*
242   return a dcerpc bind_nak
243 */
244 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason)
245 {
246         struct dcerpc_packet pkt;
247         struct dcesrv_call_reply *rep;
248         NTSTATUS status;
249
250         /* setup a bind_ack */
251         pkt.rpc_vers = 5;
252         pkt.rpc_vers_minor = 0;
253         pkt.drep[0] = 0x10; /* Little endian */
254         pkt.drep[1] = 0;
255         pkt.drep[2] = 0;
256         pkt.drep[3] = 0;
257         pkt.auth_length = 0;
258         pkt.call_id = call->pkt.call_id;
259         pkt.ptype = DCERPC_PKT_BIND_NAK;
260         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
261         pkt.u.bind_nak.reject_reason = reason;
262         pkt.u.bind_nak.num_versions = 0;
263
264         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
265         if (!rep) {
266                 return NT_STATUS_NO_MEMORY;
267         }
268
269         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL, 0);
270         if (!NT_STATUS_IS_OK(status)) {
271                 return status;
272         }
273
274         SSVAL(rep->data.data,  DCERPC_FRAG_LEN_OFFSET, rep->data.length);
275
276         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
277
278         return NT_STATUS_OK;    
279 }
280
281
282 /*
283   handle a bind request
284 */
285 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
286 {
287         const char *uuid, *transfer_syntax;
288         uint32 if_version, transfer_syntax_version;
289         struct dcerpc_packet pkt;
290         struct dcesrv_call_reply *rep;
291         NTSTATUS status;
292         uint32 result=0, reason=0;
293
294         if (call->pkt.u.bind.num_contexts != 1 ||
295             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
296                 return dcesrv_bind_nak(call, 0);
297         }
298
299         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
300         uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
301         if (!uuid) {
302                 return dcesrv_bind_nak(call, 0);
303         }
304
305         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
306         transfer_syntax = GUID_string(call->mem_ctx, 
307                                       &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
308         if (!transfer_syntax ||
309             strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
310             NDR_GUID_VERSION != transfer_syntax_version) {
311                 /* we only do NDR encoded dcerpc */
312                 return dcesrv_bind_nak(call, 0);
313         }
314
315         if (!call->dce->ops->set_interface(call->dce, uuid, if_version)) {
316                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
317                 /* we don't know about that interface */
318                 result = DCERPC_BIND_PROVIDER_REJECT;
319                 reason = DCERPC_BIND_REASON_ASYNTAX;
320         }
321
322         if (call->dce->cli_max_recv_frag == 0) {
323                 call->dce->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
324         }
325
326         /* handle any authentication that is being requested */
327         if (!dcesrv_auth_bind(call)) {
328                 return dcesrv_bind_nak(call, 0);
329         }
330
331         /* setup a bind_ack */
332         pkt.rpc_vers = 5;
333         pkt.rpc_vers_minor = 0;
334         pkt.drep[0] = 0x10; /* Little endian */
335         pkt.drep[1] = 0;
336         pkt.drep[2] = 0;
337         pkt.drep[3] = 0;
338         pkt.auth_length = 0;
339         pkt.call_id = call->pkt.call_id;
340         pkt.ptype = DCERPC_PKT_BIND_ACK;
341         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
342         pkt.u.bind_ack.max_xmit_frag = 0x2000;
343         pkt.u.bind_ack.max_recv_frag = 0x2000;
344         pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
345         if (call->dce->ndr) {
346                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s", 
347                                                                    call->dce->ndr->name);
348         } else {
349                 pkt.u.bind_ack.secondary_address = "";
350         }
351         pkt.u.bind_ack.num_results = 1;
352         pkt.u.bind_ack.ctx_list = talloc_p(call->mem_ctx, struct dcerpc_ack_ctx);
353         if (!pkt.u.bind_ack.ctx_list) {
354                 return NT_STATUS_NO_MEMORY;
355         }
356         pkt.u.bind_ack.ctx_list[0].result = result;
357         pkt.u.bind_ack.ctx_list[0].reason = reason;
358         GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
359         pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
360         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
361
362         if (!dcesrv_auth_bind_ack(call, &pkt)) {
363                 return dcesrv_bind_nak(call, 0);
364         }
365
366         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
367         if (!rep) {
368                 return NT_STATUS_NO_MEMORY;
369         }
370
371         status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, 
372                                   call->dce->auth_state.auth_info, 0);
373         if (!NT_STATUS_IS_OK(status)) {
374                 return status;
375         }
376
377         SSVAL(rep->data.data,  DCERPC_FRAG_LEN_OFFSET, rep->data.length);
378
379         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
380         DLIST_ADD_END(call->dce->call_list, call, struct dcesrv_call_state *);
381
382         return NT_STATUS_OK;
383 }
384
385
386 /*
387   handle a auth3 request
388 */
389 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
390 {
391         /* handle the auth3 in the auth code */
392         if (!dcesrv_auth_auth3(call)) {
393                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
394         }
395
396         talloc_destroy(call->mem_ctx);
397
398         /* we don't send a reply to a auth3 request, except by a
399            fault */
400         return NT_STATUS_OK;
401 }
402
403
404 /*
405   handle a dcerpc request packet
406 */
407 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
408 {
409         struct ndr_pull *pull;
410         struct ndr_push *push;
411         uint16 opnum;
412         void *r;
413         NTSTATUS status;
414         DATA_BLOB stub;
415
416         opnum = call->pkt.u.request.opnum;
417
418         if (opnum >= call->dce->ndr->num_calls) {
419                 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
420         }
421
422         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call->mem_ctx);
423         if (!pull) {
424                 return NT_STATUS_NO_MEMORY;
425         }
426
427         r = talloc(call->mem_ctx, call->dce->ndr->calls[opnum].struct_size);
428         if (!r) {
429                 return NT_STATUS_NO_MEMORY;
430         }
431
432         /* unravel the NDR for the packet */
433         status = call->dce->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
434         if (!NT_STATUS_IS_OK(status)) {
435                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
436         }
437
438         /* call the dispatch function */
439         status = call->dce->dispatch[opnum](call->dce, call->mem_ctx, r);
440         if (!NT_STATUS_IS_OK(status)) {
441                 return dcesrv_fault_nt(call, status);
442         }
443
444         /* form the reply NDR */
445         push = ndr_push_init_ctx(call->mem_ctx);
446         if (!push) {
447                 return NT_STATUS_NO_MEMORY;
448         }
449
450         status = call->dce->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
451         if (!NT_STATUS_IS_OK(status)) {
452                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
453         }
454
455         stub = ndr_push_blob(push);
456
457         do {
458                 uint32 length;
459                 struct dcesrv_call_reply *rep;
460                 struct dcerpc_packet pkt;
461
462                 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
463                 if (!rep) {
464                         return NT_STATUS_NO_MEMORY;
465                 }
466
467                 length = stub.length;
468                 if (length + DCERPC_RESPONSE_LENGTH > call->dce->cli_max_recv_frag) {
469                         /* the 32 is to cope with signing data */
470                         length = call->dce->cli_max_recv_frag - 
471                                 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
472                 }
473
474                 /* form the dcerpc response packet */
475                 pkt.rpc_vers = 5;
476                 pkt.rpc_vers_minor = 0;
477                 pkt.drep[0] = 0x10; /* Little endian */
478                 pkt.drep[1] = 0;
479                 pkt.drep[2] = 0;
480                 pkt.drep[3] = 0;
481                 pkt.auth_length = 0;
482                 pkt.call_id = call->pkt.call_id;
483                 pkt.ptype = DCERPC_PKT_RESPONSE;
484                 pkt.pfc_flags = 0;
485                 if (!call->replies) {
486                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
487                 }
488                 if (length == stub.length) {
489                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
490                 }
491                 pkt.u.response.alloc_hint = stub.length;
492                 pkt.u.response.context_id = call->pkt.u.request.context_id;
493                 pkt.u.response.cancel_count = 0;
494                 pkt.u.response.stub_and_verifier.data = stub.data;
495                 pkt.u.response.stub_and_verifier.length = length;
496
497                 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
498                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
499                 }
500
501                 SSVAL(rep->data.data,  DCERPC_FRAG_LEN_OFFSET, rep->data.length);
502
503                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
504                 
505                 stub.data += length;
506                 stub.length -= length;
507         } while (stub.length != 0);
508
509         DLIST_ADD_END(call->dce->call_list, call, struct dcesrv_call_state *);
510
511         return NT_STATUS_OK;
512 }
513
514
515 /*
516   work out if we have a full packet yet
517 */
518 static BOOL dce_full_packet(const DATA_BLOB *data)
519 {
520         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
521                 return False;
522         }
523         if (SVAL(data->data, DCERPC_FRAG_LEN_OFFSET) > data->length) {
524                 return False;
525         }
526         return True;
527 }
528
529 /*
530   we might have consumed only part of our input - advance past that part
531 */
532 static void dce_partial_advance(struct dcesrv_state *dce, uint32 offset)
533 {
534         DATA_BLOB blob;
535
536         if (dce->partial_input.length == offset) {
537                 free(dce->partial_input.data);
538                 dce->partial_input = data_blob(NULL, 0);
539                 return;
540         }
541
542         blob = dce->partial_input;
543         dce->partial_input = data_blob(blob.data + offset,
544                                        blob.length - offset);
545         free(blob.data);
546 }
547
548 /*
549   process some input to a dcerpc endpoint server.
550 */
551 NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
552 {
553         struct ndr_pull *ndr;
554         TALLOC_CTX *mem_ctx;
555         NTSTATUS status;
556         struct dcesrv_call_state *call;
557         DATA_BLOB blob;
558
559         mem_ctx = talloc_init("dcesrv_input");
560         if (!mem_ctx) {
561                 return NT_STATUS_NO_MEMORY;
562         }
563         call = talloc_p(mem_ctx, struct dcesrv_call_state);
564         if (!call) {
565                 talloc_free(dce->mem_ctx, dce->partial_input.data);
566                 talloc_destroy(mem_ctx);
567                 return NT_STATUS_NO_MEMORY;
568         }
569         call->mem_ctx = mem_ctx;
570         call->dce = dce;
571         call->replies = NULL;
572
573         blob = dce->partial_input;
574         blob.length = SVAL(blob.data, DCERPC_FRAG_LEN_OFFSET);
575
576         ndr = ndr_pull_init_blob(&blob, mem_ctx);
577         if (!ndr) {
578                 talloc_free(dce->mem_ctx, dce->partial_input.data);
579                 talloc_destroy(mem_ctx);
580                 return NT_STATUS_NO_MEMORY;
581         }
582
583         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
584         if (!NT_STATUS_IS_OK(status)) {
585                 talloc_free(dce->mem_ctx, dce->partial_input.data);
586                 talloc_destroy(mem_ctx);
587                 return status;
588         }
589
590         dce_partial_advance(dce, blob.length);
591
592         /* we have to check the signing here, before combining the
593            pdus */
594         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
595             !dcesrv_auth_request(call)) {
596                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
597         }
598
599         /* see if this is a continued packet */
600         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
601                 struct dcesrv_call_state *call2 = call;
602                 uint32 alloc_size;
603
604                 /* we only allow fragmented requests, no other packet types */
605                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
606                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
607                 }
608
609                 /* this is a continuation of an existing call - find the call then
610                    tack it on the end */
611                 call = dcesrv_find_call(dce, call2->pkt.call_id);
612                 if (!call) {
613                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
614                 }
615
616                 if (call->pkt.ptype != call2->pkt.ptype) {
617                         /* trying to play silly buggers are we? */
618                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
619                 }
620
621                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
622                         call2->pkt.u.request.stub_and_verifier.length;
623                 if (call->pkt.u.request.alloc_hint > alloc_size) {
624                         alloc_size = call->pkt.u.request.alloc_hint;
625                 }
626
627                 call->pkt.u.request.stub_and_verifier.data = 
628                         talloc_realloc(call->mem_ctx,
629                                        call->pkt.u.request.stub_and_verifier.data, alloc_size);
630                 if (!call->pkt.u.request.stub_and_verifier.data) {
631                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
632                 }
633                 memcpy(call->pkt.u.request.stub_and_verifier.data +
634                        call->pkt.u.request.stub_and_verifier.length,
635                        call2->pkt.u.request.stub_and_verifier.data,
636                        call2->pkt.u.request.stub_and_verifier.length);
637                 call->pkt.u.request.stub_and_verifier.length += 
638                         call2->pkt.u.request.stub_and_verifier.length;
639
640                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
641         }
642
643         /* this may not be the last pdu in the chain - if its isn't then
644            just put it on the call_list and wait for the rest */
645         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
646                 DLIST_ADD_END(dce->call_list, call, struct dcesrv_call_state *);
647                 return NT_STATUS_OK;
648         }
649
650         switch (call->pkt.ptype) {
651         case DCERPC_PKT_BIND:
652                 status = dcesrv_bind(call);
653                 break;
654         case DCERPC_PKT_AUTH3:
655                 status = dcesrv_auth3(call);
656                 break;
657         case DCERPC_PKT_REQUEST:
658                 status = dcesrv_request(call);
659                 break;
660         default:
661                 status = NT_STATUS_INVALID_PARAMETER;
662                 break;
663         }
664
665         /* if we are going to be sending a reply then add
666            it to the list of pending calls. We add it to the end to keep the call
667            list in the order we will answer */
668         if (!NT_STATUS_IS_OK(status)) {
669                 talloc_destroy(mem_ctx);
670         }
671
672         return status;
673 }
674
675
676 /*
677   provide some input to a dcerpc endpoint server. This passes data
678   from a dcerpc client into the server
679 */
680 NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
681 {
682         NTSTATUS status;
683
684         dce->partial_input.data = Realloc(dce->partial_input.data,
685                                           dce->partial_input.length + data->length);
686         if (!dce->partial_input.data) {
687                 return NT_STATUS_NO_MEMORY;
688         }
689         memcpy(dce->partial_input.data + dce->partial_input.length,
690                data->data, data->length);
691         dce->partial_input.length += data->length;
692
693         while (dce_full_packet(&dce->partial_input)) {
694                 status = dcesrv_input_process(dce);
695                 if (!NT_STATUS_IS_OK(status)) {
696                         return status;
697                 }
698         }
699
700         return NT_STATUS_OK;
701 }
702
703 /*
704   retrieve some output from a dcerpc server. The amount of data that
705   is wanted is in data->length and data->data is already allocated
706   to hold that much data.
707 */
708 NTSTATUS dcesrv_output(struct dcesrv_state *dce, DATA_BLOB *data)
709 {
710         struct dcesrv_call_state *call;
711         struct dcesrv_call_reply *rep;
712
713         call = dce->call_list;
714         if (!call || !call->replies) {
715                 return NT_STATUS_FOOBAR;
716         }
717         rep = call->replies;
718
719         if (data->length >= rep->data.length) {
720                 data->length = rep->data.length;
721         }
722
723         memcpy(data->data, rep->data.data, data->length);
724         rep->data.length -= data->length;
725         rep->data.data += data->length;
726
727         if (rep->data.length == 0) {
728                 /* we're done with this section of the call */
729                 DLIST_REMOVE(call->replies, rep);
730         }
731
732         if (call->replies == NULL) {
733                 /* we're done with the whole call */
734                 DLIST_REMOVE(dce->call_list, call);
735                 talloc_destroy(call->mem_ctx);
736         }
737
738         return NT_STATUS_OK;
739 }
740
741
742 /*
743   a useful function for implementing the query endpoint op
744  */
745 BOOL dcesrv_table_query(const struct dcerpc_interface_table *table,
746                         const struct dcesrv_endpoint *ep)
747 {
748         int i;
749         const struct dcerpc_endpoint_list *endpoints = table->endpoints;
750
751         if (ep->type != ENDPOINT_SMB) {
752                 return False;
753         }
754
755         for (i=0;i<endpoints->count;i++) {
756                 if (strcasecmp(ep->info.smb_pipe, endpoints->names[i]) == 0) {
757                         return True;
758                 }
759         }
760         return False;
761 }
762
763
764 /*
765   a useful function for implementing the lookup_endpoints op
766  */
767 int dcesrv_lookup_endpoints(const struct dcerpc_interface_table *table,
768                             TALLOC_CTX *mem_ctx,
769                             struct dcesrv_ep_iface **e)
770 {
771         int i;
772         *e = talloc_array_p(mem_ctx, struct dcesrv_ep_iface, table->endpoints->count);
773         if (! *e) {
774                 return -1;
775         }
776
777         for (i=0;i<table->endpoints->count;i++) {
778                 (*e)[i].name = table->name;
779                 (*e)[i].uuid = table->uuid;
780                 (*e)[i].if_version = table->if_version;
781                 if (strncmp(table->endpoints->names[i], "TCP-", 4) == 0) {
782                         (*e)[i].endpoint.type = ENDPOINT_TCP;
783                         (*e)[i].endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4);
784                 } else {
785                         (*e)[i].endpoint.type = ENDPOINT_SMB;
786                         (*e)[i].endpoint.info.smb_pipe = table->endpoints->names[i];
787                 }
788         }
789
790         return i;
791 }
792
793
794 BOOL dcesrv_set_interface(struct dcesrv_state *dce, 
795                           const char *uuid, uint32 if_version,
796                           const struct dcerpc_interface_table *table,
797                           const dcesrv_dispatch_fn_t *dispatch_table)
798 {
799         if (strcasecmp(table->uuid, uuid) != 0 || if_version != table->if_version) {
800                 DEBUG(2,("Attempt to use unknown interface %s/%d\n", uuid, if_version));
801                 return False;
802         }
803
804         dce->ndr = table;
805         dce->dispatch = dispatch_table;
806         return True;
807 }
808
809
810 /*
811   initialise the dcerpc server subsystem
812 */
813 BOOL dcesrv_init(struct dcesrv_context *dce)
814 {
815         rpc_rpcecho_init(dce);
816         rpc_epmapper_init(dce);
817         return True;
818 }