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