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