completed the linkage between the endpoint mapper and the dcerpc
[kai/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
134         /* make sure the endpoint server likes the connection */
135         status = ops->connect(*p);
136         if (!NT_STATUS_IS_OK(status)) {
137                 talloc_destroy(mem_ctx);
138                 return status;
139         }
140         
141         return NT_STATUS_OK;
142 }
143
144 /*
145   connect to a dcerpc endpoint
146 */
147 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce,
148                                  const struct dcesrv_endpoint *endpoint,
149                                  struct dcesrv_state **p)
150 {
151         const struct dcesrv_endpoint_ops *ops;
152
153         /* make sure this endpoint exists */
154         ops = find_endpoint(dce, endpoint);
155         if (!ops) {
156                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
157         }
158
159         return dcesrv_endpoint_connect_ops(dce, endpoint, ops, p);
160 }
161
162
163 /*
164   disconnect a link to an endpoint
165 */
166 void dcesrv_endpoint_disconnect(struct dcesrv_state *p)
167 {
168         p->ops->disconnect(p);
169
170         /* destroy any handles */
171         while (p->handles) {
172                 TALLOC_CTX *m = p->handles->mem_ctx;
173                 DLIST_REMOVE(p->handles, p->handles);
174                 talloc_destroy(m);
175         }
176         
177         talloc_destroy(p->mem_ctx);
178 }
179
180 /*
181   return a dcerpc fault
182 */
183 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
184 {
185         struct ndr_push *push;
186         struct dcerpc_packet pkt;
187         struct dcesrv_call_reply *rep;
188         NTSTATUS status;
189
190         /* setup a bind_ack */
191         pkt.rpc_vers = 5;
192         pkt.rpc_vers_minor = 0;
193         pkt.drep[0] = 0x10; /* Little endian */
194         pkt.drep[1] = 0;
195         pkt.drep[2] = 0;
196         pkt.drep[3] = 0;
197         pkt.auth_length = 0;
198         pkt.call_id = call->pkt.call_id;
199         pkt.ptype = DCERPC_PKT_FAULT;
200         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
201         pkt.u.fault.alloc_hint = 0;
202         pkt.u.fault.context_id = 0;
203         pkt.u.fault.cancel_count = 0;
204         pkt.u.fault.status = fault_code;
205
206         /* now form the NDR for the fault */
207         push = ndr_push_init_ctx(call->mem_ctx);
208         if (!push) {
209                 return NT_STATUS_NO_MEMORY;
210         }
211
212         status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt);
213         if (!NT_STATUS_IS_OK(status)) {
214                 return status;
215         }
216
217         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
218         if (!rep) {
219                 return NT_STATUS_NO_MEMORY;
220         }
221
222         rep->data = ndr_push_blob(push);
223         SSVAL(rep->data.data,  DCERPC_FRAG_LEN_OFFSET, rep->data.length);
224
225         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
226
227         return NT_STATUS_OK;    
228 }
229
230
231 /*
232   return a dcerpc fault from a ntstatus code
233 */
234 static NTSTATUS dcesrv_fault_nt(struct dcesrv_call_state *call, NTSTATUS status)
235 {
236         uint32 fault_code = DCERPC_FAULT_OTHER;
237
238         /* TODO: we need to expand this table to include more mappings */
239         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
240                 fault_code = DCERPC_FAULT_CONTEXT_MISMATCH;
241         }
242
243         return dcesrv_fault(call, fault_code);
244 }
245
246
247 /*
248   return a dcerpc bind_nak
249 */
250 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason)
251 {
252         struct ndr_push *push;
253         struct dcerpc_packet pkt;
254         struct dcesrv_call_reply *rep;
255         NTSTATUS status;
256
257         /* setup a bind_ack */
258         pkt.rpc_vers = 5;
259         pkt.rpc_vers_minor = 0;
260         pkt.drep[0] = 0x10; /* Little endian */
261         pkt.drep[1] = 0;
262         pkt.drep[2] = 0;
263         pkt.drep[3] = 0;
264         pkt.auth_length = 0;
265         pkt.call_id = call->pkt.call_id;
266         pkt.ptype = DCERPC_PKT_BIND_NAK;
267         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
268         pkt.u.bind_nak.reject_reason = reason;
269         pkt.u.bind_nak.num_versions = 0;
270
271         /* now form the NDR for the bind_nak */
272         push = ndr_push_init_ctx(call->mem_ctx);
273         if (!push) {
274                 return NT_STATUS_NO_MEMORY;
275         }
276
277         status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt);
278         if (!NT_STATUS_IS_OK(status)) {
279                 return status;
280         }
281
282         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
283         if (!rep) {
284                 return NT_STATUS_NO_MEMORY;
285         }
286
287         rep->data = ndr_push_blob(push);
288         SSVAL(rep->data.data,  DCERPC_FRAG_LEN_OFFSET, rep->data.length);
289
290         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
291
292         return NT_STATUS_OK;    
293 }
294
295
296 /*
297   handle a bind request
298 */
299 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
300 {
301         const char *uuid, *transfer_syntax;
302         uint32 if_version, transfer_syntax_version;
303         struct dcerpc_packet pkt;
304         struct ndr_push *push;
305         struct dcesrv_call_reply *rep;
306         NTSTATUS status;
307         uint32 result=0, reason=0;
308
309         if (call->pkt.u.bind.num_contexts != 1 ||
310             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
311                 return dcesrv_bind_nak(call, 0);
312         }
313
314         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.major_version;
315         uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
316         if (!uuid) {
317                 return dcesrv_bind_nak(call, 0);
318         }
319
320         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].major_version;
321         transfer_syntax = GUID_string(call->mem_ctx, 
322                                       &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
323         if (!transfer_syntax ||
324             strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
325             NDR_GUID_VERSION != transfer_syntax_version) {
326                 /* we only do NDR encoded dcerpc */
327                 return dcesrv_bind_nak(call, 0);
328         }
329
330         if (!call->dce->ops->set_interface(call->dce, uuid, if_version)) {
331                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
332                 /* we don't know about that interface */
333                 result = DCERPC_BIND_PROVIDER_REJECT;
334                 reason = DCERPC_BIND_REASON_ASYNTAX;
335         }
336
337         if (call->dce->cli_max_recv_frag == 0) {
338                 call->dce->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
339         }
340
341         /* setup a bind_ack */
342         pkt.rpc_vers = 5;
343         pkt.rpc_vers_minor = 0;
344         pkt.drep[0] = 0x10; /* Little endian */
345         pkt.drep[1] = 0;
346         pkt.drep[2] = 0;
347         pkt.drep[3] = 0;
348         pkt.auth_length = 0;
349         pkt.call_id = call->pkt.call_id;
350         pkt.ptype = DCERPC_PKT_BIND_ACK;
351         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
352         pkt.u.bind_ack.max_xmit_frag = 0x2000;
353         pkt.u.bind_ack.max_recv_frag = 0x2000;
354         pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
355         if (call->dce->ndr) {
356                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s", 
357                                                                    call->dce->ndr->name);
358         } else {
359                 pkt.u.bind_ack.secondary_address = "";
360         }
361         pkt.u.bind_ack.num_results = 1;
362         pkt.u.bind_ack.ctx_list = talloc_p(call->mem_ctx, struct dcerpc_ack_ctx);
363         if (!pkt.u.bind_ack.ctx_list) {
364                 return NT_STATUS_NO_MEMORY;
365         }
366         pkt.u.bind_ack.ctx_list[0].result = result;
367         pkt.u.bind_ack.ctx_list[0].reason = reason;
368         GUID_from_string(uuid, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
369         pkt.u.bind_ack.ctx_list[0].syntax.major_version = if_version;
370         pkt.u.bind_ack.ctx_list[0].syntax.minor_version = 0;
371         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
372
373         /* now form the NDR for the bind_ack */
374         push = ndr_push_init_ctx(call->mem_ctx);
375         if (!push) {
376                 return NT_STATUS_NO_MEMORY;
377         }
378
379         status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt);
380         if (!NT_STATUS_IS_OK(status)) {
381                 return status;
382         }
383
384         rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
385         if (!rep) {
386                 return NT_STATUS_NO_MEMORY;
387         }
388
389         rep->data = ndr_push_blob(push);
390         SSVAL(rep->data.data,  DCERPC_FRAG_LEN_OFFSET, rep->data.length);
391
392         DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
393
394         return NT_STATUS_OK;
395 }
396
397
398 /*
399   handle a dcerpc request packet
400 */
401 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
402 {
403         struct ndr_pull *pull;
404         struct ndr_push *push;
405         uint16 opnum;
406         void *r;
407         NTSTATUS status;
408         DATA_BLOB stub;
409
410         opnum = call->pkt.u.request.opnum;
411
412         if (opnum >= call->dce->ndr->num_calls) {
413                 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
414         }
415
416         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call->mem_ctx);
417         if (!pull) {
418                 return NT_STATUS_NO_MEMORY;
419         }
420
421         r = talloc(call->mem_ctx, call->dce->ndr->calls[opnum].struct_size);
422         if (!r) {
423                 return NT_STATUS_NO_MEMORY;
424         }
425
426         /* unravel the NDR for the packet */
427         status = call->dce->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
428         if (!NT_STATUS_IS_OK(status)) {
429                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
430         }
431
432         /* call the dispatch function */
433         status = call->dce->dispatch[opnum](call->dce, call->mem_ctx, r);
434         if (!NT_STATUS_IS_OK(status)) {
435                 return dcesrv_fault_nt(call, status);
436         }
437
438         /* form the reply NDR */
439         push = ndr_push_init_ctx(call->mem_ctx);
440         if (!push) {
441                 return NT_STATUS_NO_MEMORY;
442         }
443
444         status = call->dce->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
445         if (!NT_STATUS_IS_OK(status)) {
446                 return dcesrv_fault(call, DCERPC_FAULT_NDR);
447         }
448
449         stub = ndr_push_blob(push);
450
451         do {
452                 uint32 length;
453                 struct dcesrv_call_reply *rep;
454                 struct dcerpc_packet pkt;
455
456                 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
457                 if (!rep) {
458                         return NT_STATUS_NO_MEMORY;
459                 }
460
461                 length = stub.length;
462                 if (length + DCERPC_RESPONSE_LENGTH > call->dce->cli_max_recv_frag) {
463                         length = call->dce->cli_max_recv_frag - DCERPC_RESPONSE_LENGTH;
464                 }
465
466                 /* form the dcerpc response packet */
467                 pkt.rpc_vers = 5;
468                 pkt.rpc_vers_minor = 0;
469                 pkt.drep[0] = 0x10; /* Little endian */
470                 pkt.drep[1] = 0;
471                 pkt.drep[2] = 0;
472                 pkt.drep[3] = 0;
473                 pkt.auth_length = 0;
474                 pkt.call_id = call->pkt.call_id;
475                 pkt.ptype = DCERPC_PKT_RESPONSE;
476                 pkt.pfc_flags = 0;
477                 if (!call->replies) {
478                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
479                 }
480                 if (length == stub.length) {
481                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
482                 }
483                 pkt.u.response.alloc_hint = stub.length;
484                 pkt.u.response.context_id = call->pkt.u.request.context_id;
485                 pkt.u.response.cancel_count = 0;
486                 pkt.u.response.stub_and_verifier.data = stub.data;
487                 pkt.u.response.stub_and_verifier.length = length;
488
489                 push = ndr_push_init_ctx(call->mem_ctx);
490                 if (!push) {
491                         return NT_STATUS_NO_MEMORY;
492                 }
493                 
494                 status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt);
495                 if (!NT_STATUS_IS_OK(status)) {
496                         return status;
497                 }
498                 
499                 rep->data = ndr_push_blob(push);
500                 SSVAL(rep->data.data,  DCERPC_FRAG_LEN_OFFSET, rep->data.length);
501
502                 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
503                 
504                 stub.data += length;
505                 stub.length -= length;
506         } while (stub.length != 0);
507
508         return NT_STATUS_OK;
509 }
510
511
512 /*
513   work out if we have a full packet yet
514 */
515 static BOOL dce_full_packet(const DATA_BLOB *data)
516 {
517         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
518                 return False;
519         }
520         if (SVAL(data->data, DCERPC_FRAG_LEN_OFFSET) > data->length) {
521                 return False;
522         }
523         return True;
524 }
525
526 /*
527   we might have consumed only part of our input - advance past that part
528 */
529 static void dce_partial_advance(struct dcesrv_state *dce, uint32 offset)
530 {
531         DATA_BLOB blob;
532
533         if (dce->partial_input.length == offset) {
534                 talloc_free(dce->mem_ctx, dce->partial_input.data);
535                 dce->partial_input = data_blob(NULL, 0);
536                 return;
537         }
538
539         blob = dce->partial_input;
540         dce->partial_input = data_blob_talloc(dce->mem_ctx, 
541                                               blob.data + offset,
542                                               blob.length - offset);
543         talloc_free(dce->mem_ctx, blob.data);
544 }
545
546 /*
547   provide some input to a dcerpc endpoint server. This passes data
548   from a dcerpc client into the server
549 */
550 NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
551 {
552         struct ndr_pull *ndr;
553         TALLOC_CTX *mem_ctx;
554         NTSTATUS status;
555         struct dcesrv_call_state *call;
556
557         dce->partial_input.data = talloc_realloc(dce->mem_ctx,
558                                                  dce->partial_input.data,
559                                                  dce->partial_input.length + data->length);
560         if (!dce->partial_input.data) {
561                 return NT_STATUS_NO_MEMORY;
562         }
563         memcpy(dce->partial_input.data + dce->partial_input.length,
564                data->data, data->length);
565         dce->partial_input.length += data->length;
566
567         if (!dce_full_packet(&dce->partial_input)) {
568                 return NT_STATUS_OK;
569         }
570
571         mem_ctx = talloc_init("dcesrv_input");
572         if (!mem_ctx) {
573                 return NT_STATUS_NO_MEMORY;
574         }
575         call = talloc_p(mem_ctx, struct dcesrv_call_state);
576         if (!call) {
577                 talloc_free(dce->mem_ctx, dce->partial_input.data);
578                 talloc_destroy(mem_ctx);
579                 return NT_STATUS_NO_MEMORY;
580         }
581         call->mem_ctx = mem_ctx;
582         call->dce = dce;
583         call->replies = NULL;
584
585         ndr = ndr_pull_init_blob(&dce->partial_input, mem_ctx);
586         if (!ndr) {
587                 talloc_free(dce->mem_ctx, dce->partial_input.data);
588                 talloc_destroy(mem_ctx);
589                 return NT_STATUS_NO_MEMORY;
590         }
591
592         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
593         if (!NT_STATUS_IS_OK(status)) {
594                 talloc_free(dce->mem_ctx, dce->partial_input.data);
595                 talloc_destroy(mem_ctx);
596                 return status;
597         }
598
599         dce_partial_advance(dce, ndr->offset);
600
601         /* see if this is a continued packet */
602         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
603                 struct dcesrv_call_state *call2 = call;
604                 uint32 alloc_size;
605
606                 /* we only allow fragmented requests, no other packet types */
607                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
608                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
609                 }
610
611                 /* this is a continuation of an existing call - find the call then
612                    tack it on the end */
613                 call = dcesrv_find_call(dce, call2->pkt.call_id);
614                 if (!call) {
615                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
616                 }
617
618                 if (call->pkt.ptype != call2->pkt.ptype) {
619                         /* trying to play silly buggers are we? */
620                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
621                 }
622
623                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
624                         call2->pkt.u.request.stub_and_verifier.length;
625                 if (call->pkt.u.request.alloc_hint > alloc_size) {
626                         alloc_size = call->pkt.u.request.alloc_hint;
627                 }
628
629                 call->pkt.u.request.stub_and_verifier.data = 
630                         talloc_realloc(call->mem_ctx,
631                                        call->pkt.u.request.stub_and_verifier.data, alloc_size);
632                 if (!call->pkt.u.request.stub_and_verifier.data) {
633                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
634                 }
635                 memcpy(call->pkt.u.request.stub_and_verifier.data +
636                        call->pkt.u.request.stub_and_verifier.length,
637                        call2->pkt.u.request.stub_and_verifier.data,
638                        call2->pkt.u.request.stub_and_verifier.length);
639                 call->pkt.u.request.stub_and_verifier.length += 
640                         call2->pkt.u.request.stub_and_verifier.length;
641
642                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
643         }
644
645         /* this may not be the last pdu in the chain - if its isn't then
646            just put it on the call_list and wait for the rest */
647         if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
648                 DLIST_ADD_END(dce->call_list, call, struct dcesrv_call_state *);
649                 return NT_STATUS_OK;
650         }
651
652         switch (call->pkt.ptype) {
653         case DCERPC_PKT_BIND:
654                 status = dcesrv_bind(call);
655                 break;
656         case DCERPC_PKT_REQUEST:
657                 status = dcesrv_request(call);
658                 break;
659         default:
660                 status = NT_STATUS_INVALID_PARAMETER;
661                 break;
662         }
663
664         /* if we are going to be sending a reply then add
665            it to the list of pending calls. We add it to the end to keep the call
666            list in the order we will answer */
667         if (NT_STATUS_IS_OK(status)) {
668                 DLIST_ADD_END(dce->call_list, call, struct dcesrv_call_state *);
669         } else {
670                 talloc_destroy(mem_ctx);
671         }
672
673         return status;
674 }
675
676 /*
677   retrieve some output from a dcerpc server. The amount of data that
678   is wanted is in data->length and data->data is already allocated
679   to hold that much data.
680 */
681 NTSTATUS dcesrv_output(struct dcesrv_state *dce, DATA_BLOB *data)
682 {
683         struct dcesrv_call_state *call;
684         struct dcesrv_call_reply *rep;
685
686         call = dce->call_list;
687         if (!call || !call->replies) {
688                 return NT_STATUS_FOOBAR;
689         }
690         rep = call->replies;
691
692         if (data->length >= rep->data.length) {
693                 data->length = rep->data.length;
694         }
695
696         memcpy(data->data, rep->data.data, data->length);
697         rep->data.length -= data->length;
698         rep->data.data += data->length;
699
700         if (rep->data.length == 0) {
701                 /* we're done with this section of the call */
702                 DLIST_REMOVE(call->replies, rep);
703         }
704
705         if (call->replies == NULL) {
706                 /* we're done with the whole call */
707                 DLIST_REMOVE(dce->call_list, call);
708                 talloc_destroy(call->mem_ctx);
709         }
710
711         return NT_STATUS_OK;
712 }
713
714
715 /*
716   a useful function for implementing the query endpoint op
717  */
718 BOOL dcesrv_table_query(const struct dcerpc_interface_table *table,
719                         const struct dcesrv_endpoint *ep)
720 {
721         int i;
722         const struct dcerpc_endpoint_list *endpoints = table->endpoints;
723
724         if (ep->type != ENDPOINT_SMB) {
725                 return False;
726         }
727
728         for (i=0;i<endpoints->count;i++) {
729                 if (strcasecmp(ep->info.smb_pipe, endpoints->names[i]) == 0) {
730                         return True;
731                 }
732         }
733         return False;
734 }
735
736
737 /*
738   a useful function for implementing the lookup_endpoints op
739  */
740 int dcesrv_lookup_endpoints(const struct dcerpc_interface_table *table,
741                             TALLOC_CTX *mem_ctx,
742                             struct dcesrv_ep_iface **e)
743 {
744         int i;
745         *e = talloc_array_p(mem_ctx, struct dcesrv_ep_iface, table->endpoints->count);
746         if (! *e) {
747                 return -1;
748         }
749
750         for (i=0;i<table->endpoints->count;i++) {
751                 (*e)[i].name = table->name;
752                 (*e)[i].uuid = table->uuid;
753                 (*e)[i].if_version = table->if_version;
754                 if (strncmp(table->endpoints->names[i], "TCP-", 4) == 0) {
755                         (*e)[i].endpoint.type = ENDPOINT_TCP;
756                         (*e)[i].endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4);
757                 } else {
758                         (*e)[i].endpoint.type = ENDPOINT_SMB;
759                         (*e)[i].endpoint.info.smb_pipe = table->endpoints->names[i];
760                 }
761         }
762
763         return i;
764 }
765
766
767 /*
768   initialise the dcerpc server subsystem
769 */
770 BOOL dcesrv_init(struct dcesrv_context *dce)
771 {
772         rpc_echo_init(dce);
773         rpc_epmapper_init(dce);
774         return True;
775 }