r2614: support CONNECT level DCE/RPC security in both client and
[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.session_key = dcerpc_generic_session_key;
40         p->security_state.generic_state = NULL;
41         p->binding_string = NULL;
42         p->flags = 0;
43         p->srv_max_xmit_frag = 0;
44         p->srv_max_recv_frag = 0;
45         p->last_fault_code = 0;
46         p->pending = NULL;
47
48         return p;
49 }
50
51 /* 
52    choose the next call id to use
53 */
54 static uint32_t next_call_id(struct dcerpc_pipe *p)
55 {
56         p->call_id++;
57         if (p->call_id == 0) {
58                 p->call_id++;
59         }
60         return p->call_id;
61 }
62
63 /* close down a dcerpc over SMB pipe */
64 void dcerpc_pipe_close(struct dcerpc_pipe *p)
65 {
66         if (!p) return;
67         p->reference_count--;
68         if (p->reference_count <= 0) {
69                 if (p->security_state.generic_state) {
70                         gensec_end(&p->security_state.generic_state);
71                 }
72                 p->transport.shutdown_pipe(p);
73                 talloc_free(p);
74         }
75 }
76
77 /* we need to be able to get/set the fragment length without doing a full
78    decode */
79 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
80 {
81         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
82                 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
83         } else {
84                 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
85         }
86 }
87
88 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
89 {
90         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
91                 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
92         } else {
93                 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
94         }
95 }
96
97 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
98 {
99         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
100                 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
101         } else {
102                 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
103         }
104 }
105
106
107 /*
108   setup for a ndr pull, also setting up any flags from the binding string
109 */
110 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
111 {
112         struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
113
114         if (ndr == NULL) return ndr;
115
116         if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
117                 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
118         }
119
120         if (p->flags & DCERPC_NDR_REF_ALLOC) {
121                 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
122         }
123
124         return ndr;
125 }
126
127 /* 
128    parse a data blob into a dcerpc_packet structure. This handles both
129    input and output packets
130 */
131 static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
132                             struct dcerpc_packet *pkt)
133 {
134         struct ndr_pull *ndr;
135
136         ndr = ndr_pull_init_flags(p, blob, mem_ctx);
137         if (!ndr) {
138                 return NT_STATUS_NO_MEMORY;
139         }
140
141         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
142                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
143         }
144
145         return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
146 }
147
148 /*
149   generate a CONNECT level verifier
150 */
151 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
152 {
153         *blob = data_blob_talloc(mem_ctx, NULL, 16);
154         if (blob->data == NULL) {
155                 return NT_STATUS_NO_MEMORY;
156         }
157         SIVAL(blob->data, 0, 1);
158         memset(blob->data+4, 0, 12);
159         return NT_STATUS_OK;
160 }
161
162 /*
163   generate a CONNECT level verifier
164 */
165 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
166 {
167         if (blob->length != 16 ||
168             IVAL(blob->data, 0) != 1) {
169                 return NT_STATUS_ACCESS_DENIED;
170         }
171         return NT_STATUS_OK;
172 }
173
174 /* 
175    parse a possibly signed blob into a dcerpc request packet structure
176 */
177 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, 
178                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
179                                          struct dcerpc_packet *pkt)
180 {
181         struct ndr_pull *ndr;
182         NTSTATUS status;
183         struct dcerpc_auth auth;
184         DATA_BLOB auth_blob;
185
186         /* non-signed packets are simpler */
187         if (!p->security_state.auth_info || 
188             !p->security_state.generic_state) {
189                 return dcerpc_pull(p, blob, mem_ctx, pkt);
190         }
191
192         ndr = ndr_pull_init_flags(p, 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         /* pull the basic packet */
202         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
203         if (!NT_STATUS_IS_OK(status)) {
204                 return status;
205         }
206
207         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
208                 return status;
209         }
210
211         if (pkt->auth_length == 0 &&
212             p->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
213                 return NT_STATUS_OK;
214         }
215
216         auth_blob.length = 8 + pkt->auth_length;
217
218         /* check for a valid length */
219         if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
220                 return NT_STATUS_INFO_LENGTH_MISMATCH;
221         }
222
223         auth_blob.data = 
224                 pkt->u.response.stub_and_verifier.data + 
225                 pkt->u.response.stub_and_verifier.length - auth_blob.length;
226         pkt->u.response.stub_and_verifier.length -= auth_blob.length;
227
228         /* pull the auth structure */
229         ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
230         if (!ndr) {
231                 return NT_STATUS_NO_MEMORY;
232         }
233
234         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
235                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
236         }
237
238         status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
239         if (!NT_STATUS_IS_OK(status)) {
240                 return status;
241         }
242         
243         
244         /* check signature or unseal the packet */
245         switch (p->security_state.auth_info->auth_level) {
246         case DCERPC_AUTH_LEVEL_PRIVACY:
247                 status = gensec_unseal_packet(p->security_state.generic_state, 
248                                               mem_ctx, 
249                                               blob->data + DCERPC_REQUEST_LENGTH,
250                                               pkt->u.response.stub_and_verifier.length, 
251                                               blob->data,
252                                               blob->length - auth.credentials.length,
253                                               &auth.credentials);
254                 memcpy(pkt->u.response.stub_and_verifier.data,
255                        blob->data + DCERPC_REQUEST_LENGTH,
256                        pkt->u.response.stub_and_verifier.length);
257                 break;
258                 
259         case DCERPC_AUTH_LEVEL_INTEGRITY:
260                 status = gensec_check_packet(p->security_state.generic_state, 
261                                              mem_ctx, 
262                                              pkt->u.response.stub_and_verifier.data, 
263                                              pkt->u.response.stub_and_verifier.length, 
264                                              blob->data,
265                                              blob->length - auth.credentials.length,
266                                              &auth.credentials);
267                 break;
268
269         case DCERPC_AUTH_LEVEL_CONNECT:
270                 status = dcerpc_check_connect_verifier(&auth.credentials);
271                 break;
272
273         case DCERPC_AUTH_LEVEL_NONE:
274                 break;
275
276         default:
277                 status = NT_STATUS_INVALID_LEVEL;
278                 break;
279         }
280         
281         /* remove the indicated amount of paddiing */
282         if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
283                 return NT_STATUS_INFO_LENGTH_MISMATCH;
284         }
285         pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
286
287         return status;
288 }
289
290
291 /* 
292    push a dcerpc request packet into a blob, possibly signing it.
293 */
294 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, 
295                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
296                                          struct dcerpc_packet *pkt)
297 {
298         NTSTATUS status;
299         struct ndr_push *ndr;
300         DATA_BLOB creds2;
301
302         /* non-signed packets are simpler */
303         if (!p->security_state.auth_info || 
304             !p->security_state.generic_state) {
305                 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
306         }
307
308         ndr = ndr_push_init_ctx(mem_ctx);
309         if (!ndr) {
310                 return NT_STATUS_NO_MEMORY;
311         }
312
313         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
314                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
315         }
316
317         status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
318         if (!NT_STATUS_IS_OK(status)) {
319                 return status;
320         }
321
322         /* pad to 16 byte multiple in the payload portion of the
323            packet. This matches what w2k3 does */
324         p->security_state.auth_info->auth_pad_length = 
325                 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
326         ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
327
328         /* sign or seal the packet */
329         switch (p->security_state.auth_info->auth_level) {
330         case DCERPC_AUTH_LEVEL_PRIVACY:
331         case DCERPC_AUTH_LEVEL_INTEGRITY:
332                 p->security_state.auth_info->credentials
333                         = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
334                 data_blob_clear(&p->security_state.auth_info->credentials);
335                 break;
336
337         case DCERPC_AUTH_LEVEL_CONNECT:
338                 status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials);
339                 break;
340                 
341         case DCERPC_AUTH_LEVEL_NONE:
342                 p->security_state.auth_info->credentials = data_blob(NULL, 0);
343                 break;
344                 
345         default:
346                 status = NT_STATUS_INVALID_LEVEL;
347                 break;
348         }
349         
350         if (!NT_STATUS_IS_OK(status)) {
351                 return status;
352         }       
353
354         /* add the auth verifier */
355         status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
356         if (!NT_STATUS_IS_OK(status)) {
357                 return status;
358         }
359
360         /* extract the whole packet as a blob */
361         *blob = ndr_push_blob(ndr);
362
363         /* fill in the fragment length and auth_length, we can't fill
364            in these earlier as we don't know the signature length (it
365            could be variable length) */
366         dcerpc_set_frag_length(blob, blob->length);
367         dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
368
369         /* sign or seal the packet */
370         switch (p->security_state.auth_info->auth_level) {
371         case DCERPC_AUTH_LEVEL_PRIVACY:
372                 status = gensec_seal_packet(p->security_state.generic_state, 
373                                             mem_ctx, 
374                                             blob->data + DCERPC_REQUEST_LENGTH, 
375                                             pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
376                                             blob->data,
377                                             blob->length - 
378                                             p->security_state.auth_info->credentials.length,
379                                             &creds2);
380                 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
381                 break;
382
383         case DCERPC_AUTH_LEVEL_INTEGRITY:
384                 status = gensec_sign_packet(p->security_state.generic_state, 
385                                             mem_ctx, 
386                                             blob->data + DCERPC_REQUEST_LENGTH, 
387                                             pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
388                                             blob->data,
389                                             blob->length - 
390                                             p->security_state.auth_info->credentials.length,
391                                             &creds2);
392                 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
393                 break;
394
395         case DCERPC_AUTH_LEVEL_CONNECT:
396                 break;
397
398         case DCERPC_AUTH_LEVEL_NONE:
399                 p->security_state.auth_info->credentials = data_blob(NULL, 0);
400                 break;
401
402         default:
403                 status = NT_STATUS_INVALID_LEVEL;
404                 break;
405         }
406
407         data_blob_free(&p->security_state.auth_info->credentials);
408
409         return NT_STATUS_OK;
410 }
411
412
413 /* 
414    fill in the fixed values in a dcerpc header 
415 */
416 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
417 {
418         pkt->rpc_vers = 5;
419         pkt->rpc_vers_minor = 0;
420         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
421                 pkt->drep[0] = 0;
422         } else {
423                 pkt->drep[0] = DCERPC_DREP_LE;
424         }
425         pkt->drep[1] = 0;
426         pkt->drep[2] = 0;
427         pkt->drep[3] = 0;
428 }
429
430 /*
431   hold the state of pending full requests
432 */
433 struct full_request_state {
434         DATA_BLOB *reply_blob;
435         NTSTATUS status;
436 };
437
438 /*
439   receive a reply to a full request
440  */
441 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob, 
442                               NTSTATUS status)
443 {
444         struct full_request_state *state = p->full_request_private;
445
446         if (!NT_STATUS_IS_OK(status)) {
447                 state->status = status;
448                 return;
449         }
450         state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
451         state->reply_blob = NULL;
452 }
453
454 /*
455   perform a single pdu synchronous request - used for the bind code
456   this cannot be mixed with normal async requests
457 */
458 static NTSTATUS full_request(struct dcerpc_pipe *p, 
459                              TALLOC_CTX *mem_ctx,
460                              DATA_BLOB *request_blob,
461                              DATA_BLOB *reply_blob)
462 {
463         struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
464         NTSTATUS status;
465
466         if (state == NULL) {
467                 return NT_STATUS_NO_MEMORY;
468         }
469
470         state->reply_blob = reply_blob;
471         state->status = NT_STATUS_OK;
472
473         p->transport.recv_data = full_request_recv;
474         p->full_request_private = state;
475
476         status = p->transport.send_request(p, request_blob, True);
477         if (!NT_STATUS_IS_OK(status)) {
478                 return status;
479         }
480
481         while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
482                 struct event_context *ctx = p->transport.event_context(p);
483                 if (event_loop_once(ctx) != 0) {
484                         return NT_STATUS_CONNECTION_DISCONNECTED;
485                 }
486         }
487
488         return state->status;
489 }
490
491
492 /* 
493    perform a bind using the given syntax 
494
495    the auth_info structure is updated with the reply authentication info
496    on success
497 */
498 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
499                      TALLOC_CTX *mem_ctx,
500                      const struct dcerpc_syntax_id *syntax,
501                      const struct dcerpc_syntax_id *transfer_syntax)
502 {
503         struct dcerpc_packet pkt;
504         NTSTATUS status;
505         DATA_BLOB blob;
506
507         p->syntax = *syntax;
508         p->transfer_syntax = *transfer_syntax;
509
510         init_dcerpc_hdr(p, &pkt);
511
512         pkt.ptype = DCERPC_PKT_BIND;
513         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
514         pkt.call_id = p->call_id;
515         pkt.auth_length = 0;
516
517         pkt.u.bind.max_xmit_frag = 5840;
518         pkt.u.bind.max_recv_frag = 5840;
519         pkt.u.bind.assoc_group_id = 0;
520         pkt.u.bind.num_contexts = 1;
521         pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
522         if (!pkt.u.bind.ctx_list) {
523                 return NT_STATUS_NO_MEMORY;
524         }
525         pkt.u.bind.ctx_list[0].context_id = 0;
526         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
527         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
528         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
529         pkt.u.bind.auth_info = data_blob(NULL, 0);
530
531         /* construct the NDR form of the packet */
532         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
533         if (!NT_STATUS_IS_OK(status)) {
534                 return status;
535         }
536
537         /* send it on its way */
538         status = full_request(p, mem_ctx, &blob, &blob);
539         if (!NT_STATUS_IS_OK(status)) {
540                 return status;
541         }
542
543         /* unmarshall the NDR */
544         status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
545         if (!NT_STATUS_IS_OK(status)) {
546                 return status;
547         }
548
549         if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
550                 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
551                 return NT_STATUS_ACCESS_DENIED;
552         }
553
554         if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
555             pkt.u.bind_ack.num_results == 0 ||
556             pkt.u.bind_ack.ctx_list[0].result != 0) {
557                 return NT_STATUS_UNSUCCESSFUL;
558         }
559
560         if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
561                 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
562                 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
563         }
564
565         /* the bind_ack might contain a reply set of credentials */
566         if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
567                 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
568                                               mem_ctx,
569                                               p->security_state.auth_info,
570                                               (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
571         }
572
573         return status;  
574 }
575
576 /* 
577    perform a alter context using the given syntax 
578
579    the auth_info structure is updated with the reply authentication info
580    on success
581 */
582 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p, 
583                      TALLOC_CTX *mem_ctx)
584 {
585         struct dcerpc_packet pkt;
586         NTSTATUS status;
587         DATA_BLOB blob;
588
589         init_dcerpc_hdr(p, &pkt);
590
591         pkt.ptype = DCERPC_PKT_ALTER;
592         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
593         pkt.call_id = p->call_id;
594         pkt.auth_length = 0;
595
596         pkt.u.alter.max_xmit_frag = 0x2000;
597         pkt.u.alter.max_recv_frag = 0x2000;
598         pkt.u.alter.assoc_group_id = 0;
599         pkt.u.alter.num_contexts = 1;
600         pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
601         if (!pkt.u.alter.ctx_list) {
602                 return NT_STATUS_NO_MEMORY;
603         }
604         pkt.u.alter.ctx_list[0].context_id = 0;
605         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
606         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
607         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
608         pkt.u.alter.auth_info = data_blob(NULL, 0);
609
610         /* construct the NDR form of the packet */
611         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
612         if (!NT_STATUS_IS_OK(status)) {
613                 return status;
614         }
615
616         /* send it on its way */
617         status = full_request(p, mem_ctx, &blob, &blob);
618         if (!NT_STATUS_IS_OK(status)) {
619                 return status;
620         }
621
622         /* unmarshall the NDR */
623         status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
624         if (!NT_STATUS_IS_OK(status)) {
625                 return status;
626         }
627
628         if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
629             pkt.u.alter_ack.num_results == 0 ||
630             pkt.u.alter_ack.ctx_list[0].result != 0) {
631                 status = NT_STATUS_UNSUCCESSFUL;
632         }
633
634         /* the bind_ack might contain a reply set of credentials */
635         if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
636                 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
637                                               mem_ctx,
638                                               p->security_state.auth_info,
639                                               (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
640         }
641
642         return status;  
643 }
644
645 /* 
646    perform a continued bind (and auth3)
647 */
648 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p, 
649                       TALLOC_CTX *mem_ctx)
650 {
651         struct dcerpc_packet pkt;
652         NTSTATUS status;
653         DATA_BLOB blob;
654
655         init_dcerpc_hdr(p, &pkt);
656
657         pkt.ptype = DCERPC_PKT_AUTH3;
658         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
659         pkt.call_id = next_call_id(p);
660         pkt.auth_length = 0;
661         pkt.u.auth._pad = 0;
662         pkt.u.auth.auth_info = data_blob(NULL, 0);
663
664         /* construct the NDR form of the packet */
665         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
666         if (!NT_STATUS_IS_OK(status)) {
667                 return status;
668         }
669
670         /* send it on its way */
671         status = p->transport.send_request(p, &blob, False);
672         if (!NT_STATUS_IS_OK(status)) {
673                 return status;
674         }
675
676         return status;  
677 }
678
679
680 /* perform a dcerpc bind, using the uuid as the key */
681 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, 
682                             TALLOC_CTX *mem_ctx,
683                             const char *uuid, uint_t version)
684 {
685         struct dcerpc_syntax_id syntax;
686         struct dcerpc_syntax_id transfer_syntax;
687         NTSTATUS status;
688
689         status = GUID_from_string(uuid, &syntax.uuid);
690         if (!NT_STATUS_IS_OK(status)) {
691                 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
692                 return status;
693         }
694         syntax.if_version = version;
695
696         status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
697         if (!NT_STATUS_IS_OK(status)) {
698                 return status;
699         }
700         transfer_syntax.if_version = NDR_GUID_VERSION;
701
702         return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
703 }
704
705 /*
706   process a fragment received from the transport layer during a
707   request
708 */
709 static void dcerpc_request_recv_data(struct dcerpc_pipe *p, 
710                                      DATA_BLOB *data,
711                                      NTSTATUS status)
712 {
713         struct dcerpc_packet pkt;
714         struct rpc_request *req;
715         uint_t length;
716         
717         if (!NT_STATUS_IS_OK(status)) {
718                 /* all pending requests get the error */
719                 while (p->pending) {
720                         req = p->pending;
721                         req->state = RPC_REQUEST_DONE;
722                         req->status = status;
723                         DLIST_REMOVE(p->pending, req);
724                         if (req->async.callback) {
725                                 req->async.callback(req);
726                         }
727                 }
728                 return;
729         }
730
731         pkt.call_id = 0;
732
733         status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
734
735         /* find the matching request. Notice we match before we check
736            the status.  this is ok as a pending call_id can never be
737            zero */
738         for (req=p->pending;req;req=req->next) {
739                 if (pkt.call_id == req->call_id) break;
740         }
741
742         if (req == NULL) {
743                 DEBUG(2,("dcerpc_request: unmatched call_id in response packet\n"));
744                 return;
745         }
746
747         if (!NT_STATUS_IS_OK(status)) {
748                 req->status = status;
749                 req->state = RPC_REQUEST_DONE;
750                 DLIST_REMOVE(p->pending, req);
751                 if (req->async.callback) {
752                         req->async.callback(req);
753                 }
754                 return;
755         }
756
757         if (pkt.ptype == DCERPC_PKT_FAULT) {
758                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(p, pkt.u.fault.status)));
759                 req->fault_code = pkt.u.fault.status;
760                 req->status = NT_STATUS_NET_WRITE_FAULT;
761                 req->state = RPC_REQUEST_DONE;
762                 DLIST_REMOVE(p->pending, req);
763                 if (req->async.callback) {
764                         req->async.callback(req);
765                 }
766                 return;
767         }
768
769         if (pkt.ptype != DCERPC_PKT_RESPONSE) {
770                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
771                          (int)pkt.ptype)); 
772                 req->fault_code = DCERPC_FAULT_OTHER;
773                 req->status = NT_STATUS_NET_WRITE_FAULT;
774                 req->state = RPC_REQUEST_DONE;
775                 DLIST_REMOVE(p->pending, req);
776                 if (req->async.callback) {
777                         req->async.callback(req);
778                 }
779                 return;
780         }
781
782         length = pkt.u.response.stub_and_verifier.length;
783
784         if (length > 0) {
785                 req->payload.data = talloc_realloc(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 }