r2185: add a callback function to the dcerpc async API
[samba.git] / source4 / librpc / rpc / dcerpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Tim Potter 2003
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 /* initialise a dcerpc pipe. This currently assumes a SMB named pipe
26    transport */
27 struct dcerpc_pipe *dcerpc_pipe_init(void)
28 {
29         struct dcerpc_pipe *p;
30
31         p = talloc_p(NULL, struct dcerpc_pipe);
32         if (!p) {
33                 return NULL;
34         }
35
36         p->reference_count = 0;
37         p->call_id = 1;
38         p->security_state.auth_info = NULL;
39         p->security_state.generic_state = NULL;
40         p->binding_string = NULL;
41         p->flags = 0;
42         p->srv_max_xmit_frag = 0;
43         p->srv_max_recv_frag = 0;
44         p->last_fault_code = 0;
45         p->pending = NULL;
46
47         return p;
48 }
49
50 /* 
51    choose the next call id to use
52 */
53 static uint32_t next_call_id(struct dcerpc_pipe *p)
54 {
55         p->call_id++;
56         if (p->call_id == 0) {
57                 p->call_id++;
58         }
59         return p->call_id;
60 }
61
62 /* close down a dcerpc over SMB pipe */
63 void dcerpc_pipe_close(struct dcerpc_pipe *p)
64 {
65         if (!p) return;
66         p->reference_count--;
67         if (p->reference_count <= 0) {
68                 if (p->security_state.generic_state) {
69                         gensec_end(&p->security_state.generic_state);
70                 }
71                 p->transport.shutdown_pipe(p);
72                 talloc_free(p);
73         }
74 }
75
76 /* we need to be able to get/set the fragment length without doing a full
77    decode */
78 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
79 {
80         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
81                 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
82         } else {
83                 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
84         }
85 }
86
87 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
88 {
89         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
90                 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
91         } else {
92                 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
93         }
94 }
95
96 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
97 {
98         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
99                 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
100         } else {
101                 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
102         }
103 }
104
105
106 /*
107   setup for a ndr pull, also setting up any flags from the binding string
108 */
109 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
110 {
111         struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
112
113         if (ndr == NULL) return ndr;
114
115         if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
116                 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
117         }
118
119         return ndr;
120 }
121
122 /* 
123    parse a data blob into a dcerpc_packet structure. This handles both
124    input and output packets
125 */
126 static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
127                             struct dcerpc_packet *pkt)
128 {
129         struct ndr_pull *ndr;
130
131         ndr = ndr_pull_init_flags(p, blob, mem_ctx);
132         if (!ndr) {
133                 return NT_STATUS_NO_MEMORY;
134         }
135
136         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
137                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
138         }
139
140         return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
141 }
142
143 /* 
144    parse a possibly signed blob into a dcerpc request packet structure
145 */
146 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, 
147                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
148                                          struct dcerpc_packet *pkt)
149 {
150         struct ndr_pull *ndr;
151         NTSTATUS status;
152         struct dcerpc_auth auth;
153         DATA_BLOB auth_blob;
154
155         /* non-signed packets are simpler */
156         if (!p->security_state.auth_info || !p->security_state.generic_state) {
157                 return dcerpc_pull(p, blob, mem_ctx, pkt);
158         }
159
160         ndr = ndr_pull_init_flags(p, blob, mem_ctx);
161         if (!ndr) {
162                 return NT_STATUS_NO_MEMORY;
163         }
164
165         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
166                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
167         }
168
169         /* pull the basic packet */
170         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
171         if (!NT_STATUS_IS_OK(status)) {
172                 return status;
173         }
174
175         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
176                 return status;
177         }
178
179         auth_blob.length = 8 + pkt->auth_length;
180
181         /* check for a valid length */
182         if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
183                 return NT_STATUS_INFO_LENGTH_MISMATCH;
184         }
185
186         auth_blob.data = 
187                 pkt->u.response.stub_and_verifier.data + 
188                 pkt->u.response.stub_and_verifier.length - auth_blob.length;
189         pkt->u.response.stub_and_verifier.length -= auth_blob.length;
190
191         /* pull the auth structure */
192         ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
193         if (!ndr) {
194                 return NT_STATUS_NO_MEMORY;
195         }
196
197         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
198                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
199         }
200
201         status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
202         if (!NT_STATUS_IS_OK(status)) {
203                 return status;
204         }
205
206
207         /* check signature or unseal the packet */
208         switch (p->security_state.auth_info->auth_level) {
209         case DCERPC_AUTH_LEVEL_PRIVACY:
210                 status = gensec_unseal_packet(p->security_state.generic_state, 
211                                               mem_ctx, 
212                                               pkt->u.response.stub_and_verifier.data, 
213                                               pkt->u.response.stub_and_verifier.length, 
214                                               &auth.credentials);
215                 break;
216                 
217         case DCERPC_AUTH_LEVEL_INTEGRITY:
218                 status = gensec_check_packet(p->security_state.generic_state, 
219                                              mem_ctx, 
220                                              pkt->u.response.stub_and_verifier.data, 
221                                              pkt->u.response.stub_and_verifier.length, 
222                                              &auth.credentials);
223                 break;
224
225         case DCERPC_AUTH_LEVEL_NONE:
226                 break;
227
228         default:
229                 status = NT_STATUS_INVALID_LEVEL;
230                 break;
231         }
232
233         /* remove the indicated amount of paddiing */
234         if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
235                 return NT_STATUS_INFO_LENGTH_MISMATCH;
236         }
237         pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
238
239         return status;
240 }
241
242
243 /* 
244    push a dcerpc request packet into a blob, possibly signing it.
245 */
246 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, 
247                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
248                                          struct dcerpc_packet *pkt)
249 {
250         NTSTATUS status;
251         struct ndr_push *ndr;
252
253         /* non-signed packets are simpler */
254         if (!p->security_state.auth_info || !p->security_state.generic_state) {
255                 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
256         }
257
258         ndr = ndr_push_init_ctx(mem_ctx);
259         if (!ndr) {
260                 return NT_STATUS_NO_MEMORY;
261         }
262
263         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
264                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
265         }
266
267         status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
268         if (!NT_STATUS_IS_OK(status)) {
269                 return status;
270         }
271
272         /* pad to 16 byte multiple in the payload portion of the
273            packet. This matches what w2k3 does */
274         p->security_state.auth_info->auth_pad_length = 
275                 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
276         ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
277
278         /* sign or seal the packet */
279         switch (p->security_state.auth_info->auth_level) {
280         case DCERPC_AUTH_LEVEL_PRIVACY:
281                 status = gensec_seal_packet(p->security_state.generic_state, 
282                                             mem_ctx, 
283                                             ndr->data + DCERPC_REQUEST_LENGTH, 
284                                             ndr->offset - DCERPC_REQUEST_LENGTH,
285                                             &p->security_state.auth_info->credentials);
286                 break;
287
288         case DCERPC_AUTH_LEVEL_INTEGRITY:
289                 status = gensec_sign_packet(p->security_state.generic_state, 
290                                             mem_ctx, 
291                                             ndr->data + DCERPC_REQUEST_LENGTH, 
292                                             ndr->offset - DCERPC_REQUEST_LENGTH,
293                                             &p->security_state.auth_info->credentials);
294                 break;
295
296         case DCERPC_AUTH_LEVEL_NONE:
297                 p->security_state.auth_info->credentials = data_blob(NULL, 0);
298                 break;
299
300         default:
301                 status = NT_STATUS_INVALID_LEVEL;
302                 break;
303         }
304
305         if (!NT_STATUS_IS_OK(status)) {
306                 return status;
307         }       
308
309         /* add the auth verifier */
310         status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
311         if (!NT_STATUS_IS_OK(status)) {
312                 return status;
313         }
314
315         /* extract the whole packet as a blob */
316         *blob = ndr_push_blob(ndr);
317
318         /* fill in the fragment length and auth_length, we can't fill
319            in these earlier as we don't know the signature length (it
320            could be variable length) */
321         dcerpc_set_frag_length(blob, blob->length);
322         dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
323
324         data_blob_free(&p->security_state.auth_info->credentials);
325
326         return NT_STATUS_OK;
327 }
328
329
330 /* 
331    fill in the fixed values in a dcerpc header 
332 */
333 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
334 {
335         pkt->rpc_vers = 5;
336         pkt->rpc_vers_minor = 0;
337         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
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   hold the state of pending full requests
349 */
350 struct full_request_state {
351         DATA_BLOB *reply_blob;
352         NTSTATUS status;
353 };
354
355 /*
356   receive a reply to a full request
357  */
358 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob, 
359                               NTSTATUS status)
360 {
361         struct full_request_state *state = p->full_request_private;
362
363         if (!NT_STATUS_IS_OK(status)) {
364                 state->status = status;
365                 return;
366         }
367         state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
368         state->reply_blob = NULL;
369 }
370
371 /*
372   perform a single pdu synchronous request - used for the bind code
373   this cannot be mixed with normal async requests
374 */
375 static NTSTATUS full_request(struct dcerpc_pipe *p, 
376                              TALLOC_CTX *mem_ctx,
377                              DATA_BLOB *request_blob,
378                              DATA_BLOB *reply_blob)
379 {
380         struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
381         NTSTATUS status;
382
383         if (state == NULL) {
384                 return NT_STATUS_NO_MEMORY;
385         }
386
387         state->reply_blob = reply_blob;
388         state->status = NT_STATUS_OK;
389
390         p->transport.recv_data = full_request_recv;
391         p->full_request_private = state;
392
393         status = p->transport.send_request(p, request_blob, True);
394         if (!NT_STATUS_IS_OK(status)) {
395                 return status;
396         }
397
398         while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
399                 struct event_context *ctx = p->transport.event_context(p);
400                 event_loop_once(ctx);
401         }
402
403         return state->status;
404 }
405
406
407 /* 
408    perform a bind using the given syntax 
409
410    the auth_info structure is updated with the reply authentication info
411    on success
412 */
413 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
414                      TALLOC_CTX *mem_ctx,
415                      const struct dcerpc_syntax_id *syntax,
416                      const struct dcerpc_syntax_id *transfer_syntax)
417 {
418         struct dcerpc_packet pkt;
419         NTSTATUS status;
420         DATA_BLOB blob;
421
422         p->syntax = *syntax;
423         p->transfer_syntax = *transfer_syntax;
424
425         init_dcerpc_hdr(p, &pkt);
426
427         pkt.ptype = DCERPC_PKT_BIND;
428         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
429         pkt.call_id = p->call_id;
430         pkt.auth_length = 0;
431
432         pkt.u.bind.max_xmit_frag = 0x2000;
433         pkt.u.bind.max_recv_frag = 0x2000;
434         pkt.u.bind.assoc_group_id = 0;
435         pkt.u.bind.num_contexts = 1;
436         pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
437         if (!pkt.u.bind.ctx_list) {
438                 return NT_STATUS_NO_MEMORY;
439         }
440         pkt.u.bind.ctx_list[0].context_id = 0;
441         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
442         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
443         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
444         pkt.u.bind.auth_info = data_blob(NULL, 0);
445
446         /* construct the NDR form of the packet */
447         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
448         if (!NT_STATUS_IS_OK(status)) {
449                 return status;
450         }
451
452         /* send it on its way */
453         status = full_request(p, mem_ctx, &blob, &blob);
454         if (!NT_STATUS_IS_OK(status)) {
455                 return status;
456         }
457
458         /* unmarshall the NDR */
459         status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
460         if (!NT_STATUS_IS_OK(status)) {
461                 return status;
462         }
463
464         if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
465             pkt.u.bind_ack.num_results == 0 ||
466             pkt.u.bind_ack.ctx_list[0].result != 0) {
467                 status = NT_STATUS_UNSUCCESSFUL;
468         }
469
470         if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
471                 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
472                 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
473         }
474
475         /* the bind_ack might contain a reply set of credentials */
476         if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
477                 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
478                                               mem_ctx,
479                                               p->security_state.auth_info,
480                                               (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
481         }
482
483         return status;  
484 }
485
486 /* 
487    perform a alter context using the given syntax 
488
489    the auth_info structure is updated with the reply authentication info
490    on success
491 */
492 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p, 
493                      TALLOC_CTX *mem_ctx)
494 {
495         struct dcerpc_packet pkt;
496         NTSTATUS status;
497         DATA_BLOB blob;
498
499         init_dcerpc_hdr(p, &pkt);
500
501         pkt.ptype = DCERPC_PKT_ALTER;
502         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
503         pkt.call_id = p->call_id;
504         pkt.auth_length = 0;
505
506         pkt.u.alter.max_xmit_frag = 0x2000;
507         pkt.u.alter.max_recv_frag = 0x2000;
508         pkt.u.alter.assoc_group_id = 0;
509         pkt.u.alter.num_contexts = 1;
510         pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
511         if (!pkt.u.alter.ctx_list) {
512                 return NT_STATUS_NO_MEMORY;
513         }
514         pkt.u.alter.ctx_list[0].context_id = 0;
515         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
516         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
517         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
518         pkt.u.alter.auth_info = data_blob(NULL, 0);
519
520         /* construct the NDR form of the packet */
521         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
522         if (!NT_STATUS_IS_OK(status)) {
523                 return status;
524         }
525
526         /* send it on its way */
527         status = full_request(p, mem_ctx, &blob, &blob);
528         if (!NT_STATUS_IS_OK(status)) {
529                 return status;
530         }
531
532         /* unmarshall the NDR */
533         status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
534         if (!NT_STATUS_IS_OK(status)) {
535                 return status;
536         }
537
538         if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
539             pkt.u.alter_ack.num_results == 0 ||
540             pkt.u.alter_ack.ctx_list[0].result != 0) {
541                 status = NT_STATUS_UNSUCCESSFUL;
542         }
543
544         /* the bind_ack might contain a reply set of credentials */
545         if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
546                 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
547                                               mem_ctx,
548                                               p->security_state.auth_info,
549                                               (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
550         }
551
552         return status;  
553 }
554
555 /* 
556    perform a continued bind (and auth3)
557 */
558 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p, 
559                       TALLOC_CTX *mem_ctx)
560 {
561         struct dcerpc_packet pkt;
562         NTSTATUS status;
563         DATA_BLOB blob;
564
565         init_dcerpc_hdr(p, &pkt);
566
567         pkt.ptype = DCERPC_PKT_AUTH3;
568         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
569         pkt.call_id = next_call_id(p);
570         pkt.auth_length = 0;
571         pkt.u.auth._pad = 0;
572         pkt.u.auth.auth_info = data_blob(NULL, 0);
573
574         /* construct the NDR form of the packet */
575         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
576         if (!NT_STATUS_IS_OK(status)) {
577                 return status;
578         }
579
580         /* send it on its way */
581         status = p->transport.send_request(p, &blob, False);
582         if (!NT_STATUS_IS_OK(status)) {
583                 return status;
584         }
585
586         return status;  
587 }
588
589
590 /* perform a dcerpc bind, using the uuid as the key */
591 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, 
592                             TALLOC_CTX *mem_ctx,
593                             const char *uuid, uint_t version)
594 {
595         struct dcerpc_syntax_id syntax;
596         struct dcerpc_syntax_id transfer_syntax;
597         NTSTATUS status;
598
599         status = GUID_from_string(uuid, &syntax.uuid);
600         if (!NT_STATUS_IS_OK(status)) {
601                 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
602                 return status;
603         }
604         syntax.if_version = version;
605
606         status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
607         if (!NT_STATUS_IS_OK(status)) {
608                 return status;
609         }
610         transfer_syntax.if_version = NDR_GUID_VERSION;
611
612         return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
613 }
614
615 /*
616   process a fragment received from the transport layer during a
617   request
618 */
619 static void dcerpc_request_recv_data(struct dcerpc_pipe *p, 
620                                      DATA_BLOB *data,
621                                      NTSTATUS status)
622 {
623         struct dcerpc_packet pkt;
624         struct rpc_request *req;
625         uint_t length;
626         
627         if (!NT_STATUS_IS_OK(status)) {
628                 /* all pending requests get the error */
629                 while (p->pending) {
630                         req = p->pending;
631                         req->state = RPC_REQUEST_DONE;
632                         req->status = status;
633                         DLIST_REMOVE(p->pending, req);
634                         if (req->async.callback) {
635                                 req->async.callback(req);
636                         }
637                 }
638                 return;
639         }
640
641         pkt.call_id = 0;
642
643         status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
644
645         /* find the matching request. Notice we match before we check
646            the status.  this is ok as a pending call_id can never be
647            zero */
648         for (req=p->pending;req;req=req->next) {
649                 if (pkt.call_id == req->call_id) break;
650         }
651
652         if (req == NULL) {
653                 DEBUG(2,("dcerpc_request: unmatched call_id in response packet\n"));
654                 return;
655         }
656
657         if (!NT_STATUS_IS_OK(status)) {
658                 req->status = status;
659                 req->state = RPC_REQUEST_DONE;
660                 DLIST_REMOVE(p->pending, req);
661                 if (req->async.callback) {
662                         req->async.callback(req);
663                 }
664                 return;
665         }
666
667         if (pkt.ptype == DCERPC_PKT_FAULT) {
668                 DEBUG(5,("rpc fault 0x%x\n", pkt.u.fault.status));
669                 req->fault_code = pkt.u.fault.status;
670                 req->status = NT_STATUS_NET_WRITE_FAULT;
671                 req->state = RPC_REQUEST_DONE;
672                 DLIST_REMOVE(p->pending, req);
673                 if (req->async.callback) {
674                         req->async.callback(req);
675                 }
676                 return;
677         }
678
679         if (pkt.ptype != DCERPC_PKT_RESPONSE) {
680                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
681                          (int)pkt.ptype)); 
682                 req->fault_code = DCERPC_FAULT_OTHER;
683                 req->status = NT_STATUS_NET_WRITE_FAULT;
684                 req->state = RPC_REQUEST_DONE;
685                 DLIST_REMOVE(p->pending, req);
686                 if (req->async.callback) {
687                         req->async.callback(req);
688                 }
689                 return;
690         }
691
692         length = pkt.u.response.stub_and_verifier.length;
693
694         if (length > 0) {
695                 req->payload.data = talloc_realloc(req->payload.data, 
696                                                    req->payload.length + length);
697                 if (!req->payload.data) {
698                         req->status = NT_STATUS_NO_MEMORY;
699                         req->state = RPC_REQUEST_DONE;
700                         DLIST_REMOVE(p->pending, req);
701                         if (req->async.callback) {
702                                 req->async.callback(req);
703                         }
704                         return;
705                 }
706                 memcpy(req->payload.data+req->payload.length, 
707                        pkt.u.response.stub_and_verifier.data, length);
708                 req->payload.length += length;
709         }
710
711         if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
712                 p->transport.send_read(p);
713                 return;
714         }
715
716         /* we've got the full payload */
717         req->state = RPC_REQUEST_DONE;
718         DLIST_REMOVE(p->pending, req);
719
720         if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
721                 req->flags |= DCERPC_PULL_BIGENDIAN;
722         } else {
723                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
724         }
725
726         if (req->async.callback) {
727                 req->async.callback(req);
728         }
729 }
730
731
732 /*
733   perform the send size of a async dcerpc request
734 */
735 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
736                                         uint16_t opnum,
737                                         TALLOC_CTX *mem_ctx,
738                                         DATA_BLOB *stub_data)
739 {
740         struct rpc_request *req;
741         struct dcerpc_packet pkt;
742         DATA_BLOB blob;
743         uint32_t remaining, chunk_size;
744
745         p->transport.recv_data = dcerpc_request_recv_data;
746
747         req = talloc_p(mem_ctx, struct rpc_request);
748         if (req == NULL) {
749                 return NULL;
750         }
751
752         req->p = p;
753         req->call_id = next_call_id(p);
754         req->status = NT_STATUS_OK;
755         req->state = RPC_REQUEST_PENDING;
756         req->payload = data_blob(NULL, 0);
757         req->flags = 0;
758         req->fault_code = 0;
759         req->async.callback = NULL;
760
761         init_dcerpc_hdr(p, &pkt);
762
763         remaining = stub_data->length;
764
765         /* we can write a full max_recv_frag size, minus the dcerpc
766            request header size */
767         chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
768
769         pkt.ptype = DCERPC_PKT_REQUEST;
770         pkt.call_id = req->call_id;
771         pkt.auth_length = 0;
772         pkt.u.request.alloc_hint = remaining;
773         pkt.u.request.context_id = 0;
774         pkt.u.request.opnum = opnum;
775
776         /* we send a series of pdus without waiting for a reply until
777            the last pdu */
778         while (remaining > chunk_size) {
779                 if (remaining == stub_data->length) {
780                         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST;
781                 } else {
782                         pkt.pfc_flags = 0;
783                 }
784
785                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
786                         (stub_data->length - remaining);
787                 pkt.u.request.stub_and_verifier.length = chunk_size;
788
789                 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
790                 if (!NT_STATUS_IS_OK(req->status)) {
791                         req->state = RPC_REQUEST_DONE;
792                         return req;
793                 }
794                 
795                 req->status = p->transport.send_request(p, &blob, False);
796                 if (!NT_STATUS_IS_OK(req->status)) {
797                         req->state = RPC_REQUEST_DONE;
798                         return req;
799                 }               
800
801                 remaining -= chunk_size;
802         }
803
804         /* now we send a pdu with LAST_FRAG sent and get the first
805            part of the reply */
806         if (remaining == stub_data->length) {
807                 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
808         } else {
809                 pkt.pfc_flags = DCERPC_PFC_FLAG_LAST;
810         }
811         pkt.u.request.stub_and_verifier.data = stub_data->data + 
812                 (stub_data->length - remaining);
813         pkt.u.request.stub_and_verifier.length = remaining;
814
815         req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
816         if (!NT_STATUS_IS_OK(req->status)) {
817                 req->state = RPC_REQUEST_DONE;
818                 return req;
819         }
820
821         /* send the final pdu */
822         req->status = p->transport.send_request(p, &blob, True);
823
824         if (!NT_STATUS_IS_OK(req->status)) {
825                 req->state = RPC_REQUEST_DONE;
826         }
827
828         DLIST_ADD(p->pending, req);
829
830         return req;
831 }
832
833 /*
834   return the event context for a dcerpc pipe
835   used by callers who wish to operate asynchronously
836 */
837 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
838 {
839         return p->transport.event_context(p);
840 }
841
842
843
844 /*
845   perform the receive side of a async dcerpc request
846 */
847 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
848                              TALLOC_CTX *mem_ctx,
849                              DATA_BLOB *stub_data)
850 {
851         NTSTATUS status;
852
853         while (req->state == RPC_REQUEST_PENDING) {
854                 struct event_context *ctx = dcerpc_event_context(req->p);
855                 event_loop_once(ctx);
856         }
857         *stub_data = req->payload;
858         status = req->status;
859         if (stub_data->data) {
860                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
861         }
862         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
863                 req->p->last_fault_code = req->fault_code;
864         }
865         talloc_free(req);
866         return status;
867 }
868
869 /*
870   perform a full request/response pair on a dcerpc pipe
871 */
872 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
873                         uint16_t opnum,
874                         TALLOC_CTX *mem_ctx,
875                         DATA_BLOB *stub_data_in,
876                         DATA_BLOB *stub_data_out)
877 {
878         struct rpc_request *req;
879
880         req = dcerpc_request_send(p, opnum, mem_ctx, stub_data_in);
881         if (req == NULL) {
882                 return NT_STATUS_NO_MEMORY;
883         }
884
885         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
886 }
887
888
889 /*
890   this is a paranoid NDR validator. For every packet we push onto the wire
891   we pull it back again, then push it again. Then we compare the raw NDR data
892   for that to the NDR we initially generated. If they don't match then we know
893   we must have a bug in either the pull or push side of our code
894 */
895 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p, 
896                                        TALLOC_CTX *mem_ctx,
897                                        DATA_BLOB blob,
898                                        size_t struct_size,
899                                        NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
900                                        NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
901 {
902         void *st;
903         struct ndr_pull *pull;
904         struct ndr_push *push;
905         NTSTATUS status;
906         DATA_BLOB blob2;
907
908         st = talloc(mem_ctx, struct_size);
909         if (!st) {
910                 return NT_STATUS_NO_MEMORY;
911         }
912
913         pull = ndr_pull_init_flags(p, &blob, mem_ctx);
914         if (!pull) {
915                 return NT_STATUS_NO_MEMORY;
916         }
917
918         status = ndr_pull(pull, NDR_IN, st);
919         if (!NT_STATUS_IS_OK(status)) {
920                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
921                                       "failed input validation pull - %s",
922                                       nt_errstr(status));
923         }
924
925         push = ndr_push_init_ctx(mem_ctx);
926         if (!push) {
927                 return NT_STATUS_NO_MEMORY;
928         }       
929
930         status = ndr_push(push, NDR_IN, st);
931         if (!NT_STATUS_IS_OK(status)) {
932                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
933                                       "failed input validation push - %s",
934                                       nt_errstr(status));
935         }
936
937         blob2 = ndr_push_blob(push);
938
939         if (!data_blob_equal(&blob, &blob2)) {
940                 DEBUG(3,("original:\n"));
941                 dump_data(3, blob.data, blob.length);
942                 DEBUG(3,("secondary:\n"));
943                 dump_data(3, blob2.data, blob2.length);
944                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
945                                       "failed input validation data - %s",
946                                       nt_errstr(status));
947         }
948
949         return NT_STATUS_OK;
950 }
951
952 /*
953   this is a paranoid NDR input validator. For every packet we pull
954   from the wire we push it back again then pull and push it
955   again. Then we compare the raw NDR data for that to the NDR we
956   initially generated. If they don't match then we know we must have a
957   bug in either the pull or push side of our code
958 */
959 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
960                                         TALLOC_CTX *mem_ctx,
961                                         void *struct_ptr,
962                                         size_t struct_size,
963                                         NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
964                                         NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
965 {
966         void *st;
967         struct ndr_pull *pull;
968         struct ndr_push *push;
969         NTSTATUS status;
970         DATA_BLOB blob, blob2;
971
972         st = talloc(mem_ctx, struct_size);
973         if (!st) {
974                 return NT_STATUS_NO_MEMORY;
975         }
976         memcpy(st, struct_ptr, struct_size);
977
978         push = ndr_push_init_ctx(mem_ctx);
979         if (!push) {
980                 return NT_STATUS_NO_MEMORY;
981         }       
982
983         status = ndr_push(push, NDR_OUT, struct_ptr);
984         if (!NT_STATUS_IS_OK(status)) {
985                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
986                                       "failed output validation push - %s",
987                                       nt_errstr(status));
988         }
989
990         blob = ndr_push_blob(push);
991
992         pull = ndr_pull_init_flags(p, &blob, mem_ctx);
993         if (!pull) {
994                 return NT_STATUS_NO_MEMORY;
995         }
996
997         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
998         status = ndr_pull(pull, NDR_OUT, st);
999         if (!NT_STATUS_IS_OK(status)) {
1000                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1001                                       "failed output validation pull - %s",
1002                                       nt_errstr(status));
1003         }
1004
1005         push = ndr_push_init_ctx(mem_ctx);
1006         if (!push) {
1007                 return NT_STATUS_NO_MEMORY;
1008         }       
1009
1010         status = ndr_push(push, NDR_OUT, st);
1011         if (!NT_STATUS_IS_OK(status)) {
1012                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1013                                       "failed output validation push2 - %s",
1014                                       nt_errstr(status));
1015         }
1016
1017         blob2 = ndr_push_blob(push);
1018
1019         if (!data_blob_equal(&blob, &blob2)) {
1020                 DEBUG(3,("original:\n"));
1021                 dump_data(3, blob.data, blob.length);
1022                 DEBUG(3,("secondary:\n"));
1023                 dump_data(3, blob2.data, blob2.length);
1024                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1025                                       "failed output validation data - %s",
1026                                       nt_errstr(status));
1027         }
1028
1029         return NT_STATUS_OK;
1030 }
1031
1032
1033 /*
1034   send a rpc request with a given set of ndr helper functions
1035
1036   call dcerpc_ndr_request_recv() to receive the answer
1037 */
1038 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1039                                             uint32_t opnum,
1040                                             TALLOC_CTX *mem_ctx,
1041                                             NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1042                                             NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1043                                             void *struct_ptr,
1044                                             size_t struct_size)
1045 {
1046         struct ndr_push *push;
1047         NTSTATUS status;
1048         DATA_BLOB request;
1049         struct rpc_request *req;
1050
1051         /* setup for a ndr_push_* call */
1052         push = ndr_push_init();
1053         if (!push) {
1054                 return NULL;
1055         }
1056
1057         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1058                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1059         }
1060
1061         /* push the structure into a blob */
1062         status = ndr_push(push, NDR_IN, struct_ptr);
1063         if (!NT_STATUS_IS_OK(status)) {
1064                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1065                          nt_errstr(status)));
1066                 ndr_push_free(push);
1067                 return NULL;
1068         }
1069
1070         /* retrieve the blob */
1071         request = ndr_push_blob(push);
1072
1073         if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1074                 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size, 
1075                                                 ndr_push, ndr_pull);
1076                 if (!NT_STATUS_IS_OK(status)) {
1077                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1078                                  nt_errstr(status)));
1079                         ndr_push_free(push);
1080                         return NULL;
1081                 }
1082         }
1083
1084         DEBUG(10,("rpc request data:\n"));
1085         dump_data(10, request.data, request.length);
1086
1087         /* make the actual dcerpc request */
1088         req = dcerpc_request_send(p, opnum, mem_ctx, &request);
1089
1090         if (req != NULL) {
1091                 req->ndr.ndr_push = ndr_push;
1092                 req->ndr.ndr_pull = ndr_pull;
1093                 req->ndr.struct_ptr = struct_ptr;
1094                 req->ndr.struct_size = struct_size;
1095                 req->ndr.mem_ctx = mem_ctx;
1096         }
1097
1098         ndr_push_free(push);
1099         
1100         return req;
1101 }
1102
1103 /*
1104   receive the answer from a dcerpc_ndr_request_send()
1105 */
1106 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1107 {
1108         struct dcerpc_pipe *p = req->p;
1109         NTSTATUS status;
1110         DATA_BLOB response;
1111         struct ndr_pull *pull;
1112         struct rpc_request_ndr ndr = req->ndr;
1113         uint_t flags;
1114
1115         /* make sure the recv code doesn't free the request, as we
1116            need to grab the flags element before it is freed */
1117         talloc_increase_ref_count(req);
1118
1119         status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1120         if (!NT_STATUS_IS_OK(status)) {
1121                 return status;
1122         }
1123
1124         flags = req->flags;
1125         talloc_free(req);
1126
1127         /* prepare for ndr_pull_* */
1128         pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1129         if (!pull) {
1130                 return NT_STATUS_NO_MEMORY;
1131         }
1132
1133         if (flags & DCERPC_PULL_BIGENDIAN) {
1134                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1135         }
1136
1137         DEBUG(10,("rpc reply data:\n"));
1138         dump_data(10, pull->data, pull->data_size);
1139
1140         /* pull the structure from the blob */
1141         status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1142         if (!NT_STATUS_IS_OK(status)) {
1143                 return status;
1144         }
1145
1146         if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1147                 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size, 
1148                                                  ndr.ndr_push, ndr.ndr_pull);
1149                 if (!NT_STATUS_IS_OK(status)) {
1150                         return status;
1151                 }
1152         }
1153
1154         if (pull->offset != pull->data_size) {
1155                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1156                          pull->data_size - pull->offset));
1157                 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1158                    but it turns out that early versions of NT
1159                    (specifically NT3.1) add junk onto the end of rpc
1160                    packets, so if we want to interoperate at all with
1161                    those versions then we need to ignore this error */
1162         }
1163
1164         return NT_STATUS_OK;
1165 }
1166
1167
1168 /*
1169   a useful helper function for synchronous rpc requests 
1170
1171   this can be used when you have ndr push/pull functions in the
1172   standard format
1173 */
1174 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1175                             uint32_t opnum,
1176                             TALLOC_CTX *mem_ctx,
1177                             NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1178                             NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1179                             void *struct_ptr,
1180                             size_t struct_size)
1181 {
1182         struct rpc_request *req;
1183
1184         req = dcerpc_ndr_request_send(p, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1185         if (req == NULL) {
1186                 return NT_STATUS_NO_MEMORY;
1187         }
1188
1189         return dcerpc_ndr_request_recv(req);
1190 }
1191
1192
1193 /*
1194   a useful function for retrieving the server name we connected to
1195 */
1196 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1197 {
1198         if (!p->transport.peer_name) {
1199                 return "";
1200         }
1201         return p->transport.peer_name(p);
1202 }
1203
1204 /*
1205   a useful function to get the auth_level 
1206 */
1207
1208 uint32 dcerpc_auth_level(struct dcerpc_pipe *p) 
1209 {
1210         uint8_t auth_level;
1211
1212         if (p->flags & DCERPC_SEAL) {
1213                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1214         } else if (p->flags & DCERPC_SIGN) {
1215                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1216         } else {
1217                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1218         }
1219         return auth_level;
1220 }