r3428: switched to using minimal includes for the auto-generated RPC code.
[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 #include "librpc/gen_ndr/ndr_epmapper.h"
25
26 /* initialise a dcerpc pipe. */
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 %u in response packet\n", pkt.call_id));
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, 
786                                                    req->payload.data, 
787                                                    req->payload.length + length);
788                 if (!req->payload.data) {
789                         req->status = NT_STATUS_NO_MEMORY;
790                         req->state = RPC_REQUEST_DONE;
791                         DLIST_REMOVE(p->pending, req);
792                         if (req->async.callback) {
793                                 req->async.callback(req);
794                         }
795                         return;
796                 }
797                 memcpy(req->payload.data+req->payload.length, 
798                        pkt.u.response.stub_and_verifier.data, length);
799                 req->payload.length += length;
800         }
801
802         if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
803                 p->transport.send_read(p);
804                 return;
805         }
806
807         /* we've got the full payload */
808         req->state = RPC_REQUEST_DONE;
809         DLIST_REMOVE(p->pending, req);
810
811         if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
812                 req->flags |= DCERPC_PULL_BIGENDIAN;
813         } else {
814                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
815         }
816
817         if (req->async.callback) {
818                 req->async.callback(req);
819         }
820 }
821
822
823 /*
824   make sure requests are cleaned up 
825  */
826 static int dcerpc_req_destructor(void *ptr)
827 {
828         struct rpc_request *req = ptr;
829         DLIST_REMOVE(req->p->pending, req);
830         return 0;
831 }
832
833 /*
834   perform the send size of a async dcerpc request
835 */
836 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
837                                         uint16_t opnum,
838                                         TALLOC_CTX *mem_ctx,
839                                         DATA_BLOB *stub_data)
840 {
841         struct rpc_request *req;
842         struct dcerpc_packet pkt;
843         DATA_BLOB blob;
844         uint32_t remaining, chunk_size;
845         BOOL first_packet = True;
846
847         p->transport.recv_data = dcerpc_request_recv_data;
848
849         req = talloc_p(mem_ctx, struct rpc_request);
850         if (req == NULL) {
851                 return NULL;
852         }
853
854         req->p = p;
855         req->call_id = next_call_id(p);
856         req->status = NT_STATUS_OK;
857         req->state = RPC_REQUEST_PENDING;
858         req->payload = data_blob(NULL, 0);
859         req->flags = 0;
860         req->fault_code = 0;
861         req->async.callback = NULL;
862
863         init_dcerpc_hdr(p, &pkt);
864
865         remaining = stub_data->length;
866
867         /* we can write a full max_recv_frag size, minus the dcerpc
868            request header size */
869         chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
870
871         pkt.ptype = DCERPC_PKT_REQUEST;
872         pkt.call_id = req->call_id;
873         pkt.auth_length = 0;
874         pkt.u.request.alloc_hint = remaining;
875         pkt.u.request.context_id = 0;
876         pkt.u.request.opnum = opnum;
877
878         DLIST_ADD(p->pending, req);
879
880         /* we send a series of pdus without waiting for a reply */
881         while (remaining > 0 || first_packet) {
882                 uint32_t chunk = MIN(chunk_size, remaining);
883                 BOOL last_frag = False;
884
885                 first_packet = False;
886                 pkt.pfc_flags = 0;
887
888                 if (remaining == stub_data->length) {
889                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
890                 }
891                 if (chunk == remaining) {
892                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
893                         last_frag = True;
894                 }
895
896                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
897                         (stub_data->length - remaining);
898                 pkt.u.request.stub_and_verifier.length = chunk;
899
900                 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
901                 if (!NT_STATUS_IS_OK(req->status)) {
902                         req->state = RPC_REQUEST_DONE;
903                         DLIST_REMOVE(p->pending, req);
904                         return req;
905                 }
906                 
907                 req->status = p->transport.send_request(p, &blob, last_frag);
908                 if (!NT_STATUS_IS_OK(req->status)) {
909                         req->state = RPC_REQUEST_DONE;
910                         DLIST_REMOVE(p->pending, req);
911                         return req;
912                 }               
913
914                 remaining -= chunk;
915         }
916
917         talloc_set_destructor(req, dcerpc_req_destructor);
918
919         return req;
920 }
921
922 /*
923   return the event context for a dcerpc pipe
924   used by callers who wish to operate asynchronously
925 */
926 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
927 {
928         return p->transport.event_context(p);
929 }
930
931
932
933 /*
934   perform the receive side of a async dcerpc request
935 */
936 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
937                              TALLOC_CTX *mem_ctx,
938                              DATA_BLOB *stub_data)
939 {
940         NTSTATUS status;
941
942         while (req->state == RPC_REQUEST_PENDING) {
943                 struct event_context *ctx = dcerpc_event_context(req->p);
944                 if (event_loop_once(ctx) != 0) {
945                         return NT_STATUS_CONNECTION_DISCONNECTED;
946                 }
947         }
948         *stub_data = req->payload;
949         status = req->status;
950         if (stub_data->data) {
951                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
952         }
953         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
954                 req->p->last_fault_code = req->fault_code;
955         }
956         talloc_free(req);
957         return status;
958 }
959
960 /*
961   perform a full request/response pair on a dcerpc pipe
962 */
963 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
964                         uint16_t opnum,
965                         TALLOC_CTX *mem_ctx,
966                         DATA_BLOB *stub_data_in,
967                         DATA_BLOB *stub_data_out)
968 {
969         struct rpc_request *req;
970
971         req = dcerpc_request_send(p, opnum, mem_ctx, stub_data_in);
972         if (req == NULL) {
973                 return NT_STATUS_NO_MEMORY;
974         }
975
976         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
977 }
978
979
980 /*
981   this is a paranoid NDR validator. For every packet we push onto the wire
982   we pull it back again, then push it again. Then we compare the raw NDR data
983   for that to the NDR we initially generated. If they don't match then we know
984   we must have a bug in either the pull or push side of our code
985 */
986 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p, 
987                                        TALLOC_CTX *mem_ctx,
988                                        DATA_BLOB blob,
989                                        size_t struct_size,
990                                        NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
991                                        NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
992 {
993         void *st;
994         struct ndr_pull *pull;
995         struct ndr_push *push;
996         NTSTATUS status;
997         DATA_BLOB blob2;
998
999         st = talloc(mem_ctx, struct_size);
1000         if (!st) {
1001                 return NT_STATUS_NO_MEMORY;
1002         }
1003
1004         pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1005         if (!pull) {
1006                 return NT_STATUS_NO_MEMORY;
1007         }
1008
1009         status = ndr_pull(pull, NDR_IN, st);
1010         if (!NT_STATUS_IS_OK(status)) {
1011                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1012                                       "failed input validation pull - %s",
1013                                       nt_errstr(status));
1014         }
1015
1016         push = ndr_push_init_ctx(mem_ctx);
1017         if (!push) {
1018                 return NT_STATUS_NO_MEMORY;
1019         }       
1020
1021         status = ndr_push(push, NDR_IN, st);
1022         if (!NT_STATUS_IS_OK(status)) {
1023                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1024                                       "failed input validation push - %s",
1025                                       nt_errstr(status));
1026         }
1027
1028         blob2 = ndr_push_blob(push);
1029
1030         if (!data_blob_equal(&blob, &blob2)) {
1031                 DEBUG(3,("original:\n"));
1032                 dump_data(3, blob.data, blob.length);
1033                 DEBUG(3,("secondary:\n"));
1034                 dump_data(3, blob2.data, blob2.length);
1035                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1036                                       "failed input validation data - %s",
1037                                       nt_errstr(status));
1038         }
1039
1040         return NT_STATUS_OK;
1041 }
1042
1043 /*
1044   this is a paranoid NDR input validator. For every packet we pull
1045   from the wire we push it back again then pull and push it
1046   again. Then we compare the raw NDR data for that to the NDR we
1047   initially generated. If they don't match then we know we must have a
1048   bug in either the pull or push side of our code
1049 */
1050 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
1051                                         TALLOC_CTX *mem_ctx,
1052                                         void *struct_ptr,
1053                                         size_t struct_size,
1054                                         NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1055                                         NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1056 {
1057         void *st;
1058         struct ndr_pull *pull;
1059         struct ndr_push *push;
1060         NTSTATUS status;
1061         DATA_BLOB blob, blob2;
1062
1063         st = talloc(mem_ctx, struct_size);
1064         if (!st) {
1065                 return NT_STATUS_NO_MEMORY;
1066         }
1067         memcpy(st, struct_ptr, struct_size);
1068
1069         push = ndr_push_init_ctx(mem_ctx);
1070         if (!push) {
1071                 return NT_STATUS_NO_MEMORY;
1072         }       
1073
1074         status = ndr_push(push, NDR_OUT, struct_ptr);
1075         if (!NT_STATUS_IS_OK(status)) {
1076                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1077                                       "failed output validation push - %s",
1078                                       nt_errstr(status));
1079         }
1080
1081         blob = ndr_push_blob(push);
1082
1083         pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1084         if (!pull) {
1085                 return NT_STATUS_NO_MEMORY;
1086         }
1087
1088         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1089         status = ndr_pull(pull, NDR_OUT, st);
1090         if (!NT_STATUS_IS_OK(status)) {
1091                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1092                                       "failed output validation pull - %s",
1093                                       nt_errstr(status));
1094         }
1095
1096         push = ndr_push_init_ctx(mem_ctx);
1097         if (!push) {
1098                 return NT_STATUS_NO_MEMORY;
1099         }       
1100
1101         status = ndr_push(push, NDR_OUT, st);
1102         if (!NT_STATUS_IS_OK(status)) {
1103                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1104                                       "failed output validation push2 - %s",
1105                                       nt_errstr(status));
1106         }
1107
1108         blob2 = ndr_push_blob(push);
1109
1110         if (!data_blob_equal(&blob, &blob2)) {
1111                 DEBUG(3,("original:\n"));
1112                 dump_data(3, blob.data, blob.length);
1113                 DEBUG(3,("secondary:\n"));
1114                 dump_data(3, blob2.data, blob2.length);
1115                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1116                                       "failed output validation data - %s",
1117                                       nt_errstr(status));
1118         }
1119
1120         return NT_STATUS_OK;
1121 }
1122
1123
1124 /*
1125   send a rpc request with a given set of ndr helper functions
1126
1127   call dcerpc_ndr_request_recv() to receive the answer
1128 */
1129 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1130                                             uint32_t opnum,
1131                                             TALLOC_CTX *mem_ctx,
1132                                             NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1133                                             NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1134                                             void *struct_ptr,
1135                                             size_t struct_size)
1136 {
1137         struct ndr_push *push;
1138         NTSTATUS status;
1139         DATA_BLOB request;
1140         struct rpc_request *req;
1141
1142         /* setup for a ndr_push_* call */
1143         push = ndr_push_init();
1144         if (!push) {
1145                 return NULL;
1146         }
1147
1148         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1149                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1150         }
1151
1152         /* push the structure into a blob */
1153         status = ndr_push(push, NDR_IN, struct_ptr);
1154         if (!NT_STATUS_IS_OK(status)) {
1155                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1156                          nt_errstr(status)));
1157                 ndr_push_free(push);
1158                 return NULL;
1159         }
1160
1161         /* retrieve the blob */
1162         request = ndr_push_blob(push);
1163
1164         if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1165                 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size, 
1166                                                 ndr_push, ndr_pull);
1167                 if (!NT_STATUS_IS_OK(status)) {
1168                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1169                                  nt_errstr(status)));
1170                         ndr_push_free(push);
1171                         return NULL;
1172                 }
1173         }
1174
1175         DEBUG(10,("rpc request data:\n"));
1176         dump_data(10, request.data, request.length);
1177
1178         /* make the actual dcerpc request */
1179         req = dcerpc_request_send(p, opnum, mem_ctx, &request);
1180
1181         if (req != NULL) {
1182                 req->ndr.ndr_push = ndr_push;
1183                 req->ndr.ndr_pull = ndr_pull;
1184                 req->ndr.struct_ptr = struct_ptr;
1185                 req->ndr.struct_size = struct_size;
1186                 req->ndr.mem_ctx = mem_ctx;
1187         }
1188
1189         ndr_push_free(push);
1190         
1191         return req;
1192 }
1193
1194 /*
1195   receive the answer from a dcerpc_ndr_request_send()
1196 */
1197 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1198 {
1199         struct dcerpc_pipe *p = req->p;
1200         NTSTATUS status;
1201         DATA_BLOB response;
1202         struct ndr_pull *pull;
1203         struct rpc_request_ndr ndr = req->ndr;
1204         uint_t flags;
1205
1206         /* make sure the recv code doesn't free the request, as we
1207            need to grab the flags element before it is freed */
1208         talloc_increase_ref_count(req);
1209
1210         status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1211         if (!NT_STATUS_IS_OK(status)) {
1212                 return status;
1213         }
1214
1215         flags = req->flags;
1216         talloc_free(req);
1217
1218         /* prepare for ndr_pull_* */
1219         pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1220         if (!pull) {
1221                 return NT_STATUS_NO_MEMORY;
1222         }
1223
1224         if (flags & DCERPC_PULL_BIGENDIAN) {
1225                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1226         }
1227
1228         DEBUG(10,("rpc reply data:\n"));
1229         dump_data(10, pull->data, pull->data_size);
1230
1231         /* pull the structure from the blob */
1232         status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1233         if (!NT_STATUS_IS_OK(status)) {
1234                 return status;
1235         }
1236
1237         if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1238                 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size, 
1239                                                  ndr.ndr_push, ndr.ndr_pull);
1240                 if (!NT_STATUS_IS_OK(status)) {
1241                         return status;
1242                 }
1243         }
1244
1245         if (pull->offset != pull->data_size) {
1246                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1247                          pull->data_size - pull->offset));
1248                 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1249                    but it turns out that early versions of NT
1250                    (specifically NT3.1) add junk onto the end of rpc
1251                    packets, so if we want to interoperate at all with
1252                    those versions then we need to ignore this error */
1253         }
1254
1255         return NT_STATUS_OK;
1256 }
1257
1258
1259 /*
1260   a useful helper function for synchronous rpc requests 
1261
1262   this can be used when you have ndr push/pull functions in the
1263   standard format
1264 */
1265 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1266                             uint32_t opnum,
1267                             TALLOC_CTX *mem_ctx,
1268                             NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1269                             NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1270                             void *struct_ptr,
1271                             size_t struct_size)
1272 {
1273         struct rpc_request *req;
1274
1275         req = dcerpc_ndr_request_send(p, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1276         if (req == NULL) {
1277                 return NT_STATUS_NO_MEMORY;
1278         }
1279
1280         return dcerpc_ndr_request_recv(req);
1281 }
1282
1283
1284 /*
1285   a useful function for retrieving the server name we connected to
1286 */
1287 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1288 {
1289         if (!p->transport.peer_name) {
1290                 return "";
1291         }
1292         return p->transport.peer_name(p);
1293 }
1294
1295 /*
1296   a useful function to get the auth_level 
1297 */
1298
1299 uint32 dcerpc_auth_level(struct dcerpc_pipe *p) 
1300 {
1301         uint8_t auth_level;
1302
1303         if (p->flags & DCERPC_SEAL) {
1304                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1305         } else if (p->flags & DCERPC_SIGN) {
1306                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1307         } else if (p->flags & DCERPC_CONNECT) {
1308                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1309         } else {
1310                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1311         }
1312         return auth_level;
1313 }