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