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