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