3fe2d87475e2268aecf2290103dd5b1a19e721c9
[samba.git] / source4 / librpc / rpc / dcerpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Tim Potter 2003
6    Copyright (C) Andrew Tridgell 2003
7    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                                                    req->payload.length + length);
815                 if (!req->payload.data) {
816                         req->status = NT_STATUS_NO_MEMORY;
817                         req->state = RPC_REQUEST_DONE;
818                         DLIST_REMOVE(p->pending, req);
819                         if (req->async.callback) {
820                                 req->async.callback(req);
821                         }
822                         return;
823                 }
824                 memcpy(req->payload.data+req->payload.length, 
825                        pkt.u.response.stub_and_verifier.data, length);
826                 req->payload.length += length;
827         }
828
829         if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
830                 p->transport.send_read(p);
831                 return;
832         }
833
834         /* we've got the full payload */
835         req->state = RPC_REQUEST_DONE;
836         DLIST_REMOVE(p->pending, req);
837
838         if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
839                 req->flags |= DCERPC_PULL_BIGENDIAN;
840         } else {
841                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
842         }
843
844         if (req->async.callback) {
845                 req->async.callback(req);
846         }
847 }
848
849
850 /*
851   make sure requests are cleaned up 
852  */
853 static int dcerpc_req_destructor(void *ptr)
854 {
855         struct rpc_request *req = ptr;
856         DLIST_REMOVE(req->p->pending, req);
857         return 0;
858 }
859
860 /*
861   perform the send size of a async dcerpc request
862 */
863 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
864                                         const struct GUID *object,
865                                         uint16_t opnum,
866                                         TALLOC_CTX *mem_ctx,
867                                         DATA_BLOB *stub_data)
868 {
869         struct rpc_request *req;
870         struct dcerpc_packet pkt;
871         DATA_BLOB blob;
872         uint32_t remaining, chunk_size;
873         BOOL first_packet = True;
874
875         p->transport.recv_data = dcerpc_request_recv_data;
876
877         req = talloc_p(mem_ctx, struct rpc_request);
878         if (req == NULL) {
879                 return NULL;
880         }
881
882         req->p = p;
883         req->call_id = next_call_id(p);
884         req->status = NT_STATUS_OK;
885         req->state = RPC_REQUEST_PENDING;
886         req->payload = data_blob(NULL, 0);
887         req->flags = 0;
888         req->fault_code = 0;
889         req->async.callback = NULL;
890
891         init_dcerpc_hdr(p, &pkt);
892
893         remaining = stub_data->length;
894
895         /* we can write a full max_recv_frag size, minus the dcerpc
896            request header size */
897         chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
898
899         pkt.ptype = DCERPC_PKT_REQUEST;
900         pkt.call_id = req->call_id;
901         pkt.auth_length = 0;
902         pkt.pfc_flags = 0;
903         pkt.u.request.alloc_hint = remaining;
904         pkt.u.request.context_id = 0;
905         pkt.u.request.opnum = opnum;
906
907         if (object) {
908                 pkt.u.request.object.object = *object;
909                 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
910                 chunk_size -= ndr_size_GUID(object,0);
911         }
912
913         DLIST_ADD(p->pending, req);
914
915         /* we send a series of pdus without waiting for a reply */
916         while (remaining > 0 || first_packet) {
917                 uint32_t chunk = MIN(chunk_size, remaining);
918                 BOOL last_frag = False;
919
920                 first_packet = False;
921                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
922
923                 if (remaining == stub_data->length) {
924                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
925                 }
926                 if (chunk == remaining) {
927                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
928                         last_frag = True;
929                 }
930
931                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
932                         (stub_data->length - remaining);
933                 pkt.u.request.stub_and_verifier.length = chunk;
934
935                 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
936                 if (!NT_STATUS_IS_OK(req->status)) {
937                         req->state = RPC_REQUEST_DONE;
938                         DLIST_REMOVE(p->pending, req);
939                         return req;
940                 }
941                 
942                 req->status = p->transport.send_request(p, &blob, last_frag);
943                 if (!NT_STATUS_IS_OK(req->status)) {
944                         req->state = RPC_REQUEST_DONE;
945                         DLIST_REMOVE(p->pending, req);
946                         return req;
947                 }               
948
949                 remaining -= chunk;
950         }
951
952         talloc_set_destructor(req, dcerpc_req_destructor);
953
954         return req;
955 }
956
957 /*
958   return the event context for a dcerpc pipe
959   used by callers who wish to operate asynchronously
960 */
961 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
962 {
963         return p->transport.event_context(p);
964 }
965
966
967
968 /*
969   perform the receive side of a async dcerpc request
970 */
971 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
972                              TALLOC_CTX *mem_ctx,
973                              DATA_BLOB *stub_data)
974 {
975         NTSTATUS status;
976
977         while (req->state == RPC_REQUEST_PENDING) {
978                 struct event_context *ctx = dcerpc_event_context(req->p);
979                 if (event_loop_once(ctx) != 0) {
980                         return NT_STATUS_CONNECTION_DISCONNECTED;
981                 }
982         }
983         *stub_data = req->payload;
984         status = req->status;
985         if (stub_data->data) {
986                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
987         }
988         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
989                 req->p->last_fault_code = req->fault_code;
990         }
991         talloc_free(req);
992         return status;
993 }
994
995 /*
996   perform a full request/response pair on a dcerpc pipe
997 */
998 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
999                         struct GUID *object,
1000                         uint16_t opnum,
1001                         TALLOC_CTX *mem_ctx,
1002                         DATA_BLOB *stub_data_in,
1003                         DATA_BLOB *stub_data_out)
1004 {
1005         struct rpc_request *req;
1006
1007         req = dcerpc_request_send(p, object, opnum, mem_ctx, stub_data_in);
1008         if (req == NULL) {
1009                 return NT_STATUS_NO_MEMORY;
1010         }
1011
1012         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1013 }
1014
1015
1016 /*
1017   this is a paranoid NDR validator. For every packet we push onto the wire
1018   we pull it back again, then push it again. Then we compare the raw NDR data
1019   for that to the NDR we initially generated. If they don't match then we know
1020   we must have a bug in either the pull or push side of our code
1021 */
1022 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p, 
1023                                        TALLOC_CTX *mem_ctx,
1024                                        DATA_BLOB blob,
1025                                        size_t struct_size,
1026                                        NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1027                                        NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1028 {
1029         void *st;
1030         struct ndr_pull *pull;
1031         struct ndr_push *push;
1032         NTSTATUS status;
1033         DATA_BLOB blob2;
1034
1035         st = talloc(mem_ctx, struct_size);
1036         if (!st) {
1037                 return NT_STATUS_NO_MEMORY;
1038         }
1039
1040         pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1041         if (!pull) {
1042                 return NT_STATUS_NO_MEMORY;
1043         }
1044
1045         status = ndr_pull(pull, NDR_IN, st);
1046         if (!NT_STATUS_IS_OK(status)) {
1047                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1048                                       "failed input validation pull - %s",
1049                                       nt_errstr(status));
1050         }
1051
1052         push = ndr_push_init_ctx(mem_ctx);
1053         if (!push) {
1054                 return NT_STATUS_NO_MEMORY;
1055         }       
1056
1057         status = ndr_push(push, NDR_IN, st);
1058         if (!NT_STATUS_IS_OK(status)) {
1059                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1060                                       "failed input validation push - %s",
1061                                       nt_errstr(status));
1062         }
1063
1064         blob2 = ndr_push_blob(push);
1065
1066         if (!data_blob_equal(&blob, &blob2)) {
1067                 DEBUG(3,("original:\n"));
1068                 dump_data(3, blob.data, blob.length);
1069                 DEBUG(3,("secondary:\n"));
1070                 dump_data(3, blob2.data, blob2.length);
1071                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1072                                       "failed input validation data - %s",
1073                                       nt_errstr(status));
1074         }
1075
1076         return NT_STATUS_OK;
1077 }
1078
1079 /*
1080   this is a paranoid NDR input validator. For every packet we pull
1081   from the wire we push it back again then pull and push it
1082   again. Then we compare the raw NDR data for that to the NDR we
1083   initially generated. If they don't match then we know we must have a
1084   bug in either the pull or push side of our code
1085 */
1086 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
1087                                         TALLOC_CTX *mem_ctx,
1088                                         void *struct_ptr,
1089                                         size_t struct_size,
1090                                         NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1091                                         NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1092 {
1093         void *st;
1094         struct ndr_pull *pull;
1095         struct ndr_push *push;
1096         NTSTATUS status;
1097         DATA_BLOB blob, blob2;
1098
1099         st = talloc(mem_ctx, struct_size);
1100         if (!st) {
1101                 return NT_STATUS_NO_MEMORY;
1102         }
1103         memcpy(st, struct_ptr, struct_size);
1104
1105         push = ndr_push_init_ctx(mem_ctx);
1106         if (!push) {
1107                 return NT_STATUS_NO_MEMORY;
1108         }       
1109
1110         status = ndr_push(push, NDR_OUT, struct_ptr);
1111         if (!NT_STATUS_IS_OK(status)) {
1112                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1113                                       "failed output validation push - %s",
1114                                       nt_errstr(status));
1115         }
1116
1117         blob = ndr_push_blob(push);
1118
1119         pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1120         if (!pull) {
1121                 return NT_STATUS_NO_MEMORY;
1122         }
1123
1124         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1125         status = ndr_pull(pull, NDR_OUT, st);
1126         if (!NT_STATUS_IS_OK(status)) {
1127                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1128                                       "failed output validation pull - %s",
1129                                       nt_errstr(status));
1130         }
1131
1132         push = ndr_push_init_ctx(mem_ctx);
1133         if (!push) {
1134                 return NT_STATUS_NO_MEMORY;
1135         }       
1136
1137         status = ndr_push(push, NDR_OUT, st);
1138         if (!NT_STATUS_IS_OK(status)) {
1139                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1140                                       "failed output validation push2 - %s",
1141                                       nt_errstr(status));
1142         }
1143
1144         blob2 = ndr_push_blob(push);
1145
1146         if (!data_blob_equal(&blob, &blob2)) {
1147                 DEBUG(3,("original:\n"));
1148                 dump_data(3, blob.data, blob.length);
1149                 DEBUG(3,("secondary:\n"));
1150                 dump_data(3, blob2.data, blob2.length);
1151                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1152                                       "failed output validation data - %s",
1153                                       nt_errstr(status));
1154         }
1155
1156         return NT_STATUS_OK;
1157 }
1158
1159
1160 /*
1161  send a rpc request given a dcerpc_call structure 
1162  */
1163 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1164                                                 const struct GUID *object,
1165                                                 const struct dcerpc_interface_table *table,
1166                                                 uint32_t opnum, 
1167                                                 TALLOC_CTX *mem_ctx, 
1168                                                 void *r)
1169 {
1170         const struct dcerpc_interface_call *call;
1171         struct ndr_push *push;
1172         NTSTATUS status;
1173         DATA_BLOB request;
1174         struct rpc_request *req;
1175
1176         call = &table->calls[opnum];
1177
1178         /* setup for a ndr_push_* call */
1179         push = ndr_push_init();
1180         if (!push) {
1181                 return NULL;
1182         }
1183
1184         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1185                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1186         }
1187
1188         /* push the structure into a blob */
1189         status = call->ndr_push(push, NDR_IN, r);
1190         if (!NT_STATUS_IS_OK(status)) {
1191                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1192                          nt_errstr(status)));
1193                 ndr_push_free(push);
1194                 return NULL;
1195         }
1196
1197         /* retrieve the blob */
1198         request = ndr_push_blob(push);
1199
1200         if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1201                 status = dcerpc_ndr_validate_in(p, mem_ctx, request, call->struct_size, 
1202                                                 call->ndr_push, call->ndr_pull);
1203                 if (!NT_STATUS_IS_OK(status)) {
1204                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1205                                  nt_errstr(status)));
1206                         ndr_push_free(push);
1207                         return NULL;
1208                 }
1209         }
1210
1211         DEBUG(10,("rpc request data:\n"));
1212         dump_data(10, request.data, request.length);
1213
1214         /* make the actual dcerpc request */
1215         req = dcerpc_request_send(p, object, opnum, mem_ctx, &request);
1216
1217         if (req != NULL) {
1218                 req->ndr.table = table;
1219                 req->ndr.opnum = opnum;
1220                 req->ndr.struct_ptr = r;
1221                 req->ndr.mem_ctx = mem_ctx;
1222         }
1223
1224         ndr_push_free(push);
1225         
1226         return req;
1227 }
1228
1229 /*
1230   receive the answer from a dcerpc_ndr_request_send()
1231 */
1232 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1233 {
1234         struct dcerpc_pipe *p = req->p;
1235         NTSTATUS status;
1236         DATA_BLOB response;
1237         struct ndr_pull *pull;
1238         uint_t flags;
1239         TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1240         void *r = req->ndr.struct_ptr;
1241         uint32_t opnum = req->ndr.opnum;
1242         const struct dcerpc_interface_table *table = req->ndr.table;
1243         const struct dcerpc_interface_call *call = &table->calls[opnum];
1244
1245         /* make sure the recv code doesn't free the request, as we
1246            need to grab the flags element before it is freed */
1247         talloc_increase_ref_count(req);
1248
1249         status = dcerpc_request_recv(req, mem_ctx, &response);
1250         if (!NT_STATUS_IS_OK(status)) {
1251                 return status;
1252         }
1253
1254         flags = req->flags;
1255         talloc_free(req);
1256
1257         /* prepare for ndr_pull_* */
1258         pull = ndr_pull_init_flags(p, &response, mem_ctx);
1259         if (!pull) {
1260                 return NT_STATUS_NO_MEMORY;
1261         }
1262
1263         if (flags & DCERPC_PULL_BIGENDIAN) {
1264                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1265         }
1266
1267         DEBUG(10,("rpc reply data:\n"));
1268         dump_data(10, pull->data, pull->data_size);
1269
1270         /* pull the structure from the blob */
1271         status = call->ndr_pull(pull, NDR_OUT, r);
1272         if (!NT_STATUS_IS_OK(status)) {
1273                 dcerpc_log_packet(table, opnum, NDR_OUT, 
1274                                   &response);
1275                 return status;
1276         }
1277
1278         if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1279                 status = dcerpc_ndr_validate_out(p, mem_ctx, r, call->struct_size, 
1280                                                  call->ndr_push, call->ndr_pull);
1281                 if (!NT_STATUS_IS_OK(status)) {
1282                         dcerpc_log_packet(table, opnum, NDR_OUT, 
1283                                   &response);
1284                         return status;
1285                 }
1286         }
1287
1288         if (pull->offset != pull->data_size) {
1289                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1290                          pull->data_size - pull->offset));
1291                 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1292                    but it turns out that early versions of NT
1293                    (specifically NT3.1) add junk onto the end of rpc
1294                    packets, so if we want to interoperate at all with
1295                    those versions then we need to ignore this error */
1296         }
1297
1298         return NT_STATUS_OK;
1299 }
1300
1301
1302 /*
1303   a useful helper function for synchronous rpc requests 
1304
1305   this can be used when you have ndr push/pull functions in the
1306   standard format
1307 */
1308 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1309                             const struct GUID *object,
1310                             const struct dcerpc_interface_table *table,
1311                             uint32_t opnum, 
1312                             TALLOC_CTX *mem_ctx, 
1313                             void *r)
1314 {
1315         struct rpc_request *req;
1316
1317         req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1318         if (req == NULL) {
1319                 return NT_STATUS_NO_MEMORY;
1320         }
1321
1322         return dcerpc_ndr_request_recv(req);
1323 }
1324
1325
1326 /*
1327   a useful function for retrieving the server name we connected to
1328 */
1329 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1330 {
1331         if (!p->transport.peer_name) {
1332                 return "";
1333         }
1334         return p->transport.peer_name(p);
1335 }
1336
1337 /*
1338   a useful function to get the auth_level 
1339 */
1340
1341 uint32 dcerpc_auth_level(struct dcerpc_pipe *p) 
1342 {
1343         uint8_t auth_level;
1344
1345         if (p->flags & DCERPC_SEAL) {
1346                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1347         } else if (p->flags & DCERPC_SIGN) {
1348                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1349         } else if (p->flags & DCERPC_CONNECT) {
1350                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1351         } else {
1352                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1353         }
1354         return auth_level;
1355 }