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