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