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