beccac78ca5a933e52809367475ac9f1d317c0d1
[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    
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         status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
325         if (!NT_STATUS_IS_OK(status)) {
326                 return status;
327         }
328
329         /* pad to 16 byte multiple in the payload portion of the
330            packet. This matches what w2k3 does */
331         p->security_state.auth_info->auth_pad_length = 
332                 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
333         ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
334
335         /* sign or seal the packet */
336         switch (p->security_state.auth_info->auth_level) {
337         case DCERPC_AUTH_LEVEL_PRIVACY:
338         case DCERPC_AUTH_LEVEL_INTEGRITY:
339                 p->security_state.auth_info->credentials
340                         = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
341                 data_blob_clear(&p->security_state.auth_info->credentials);
342                 break;
343
344         case DCERPC_AUTH_LEVEL_CONNECT:
345                 status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials);
346                 break;
347                 
348         case DCERPC_AUTH_LEVEL_NONE:
349                 p->security_state.auth_info->credentials = data_blob(NULL, 0);
350                 break;
351                 
352         default:
353                 status = NT_STATUS_INVALID_LEVEL;
354                 break;
355         }
356         
357         if (!NT_STATUS_IS_OK(status)) {
358                 return status;
359         }       
360
361         /* add the auth verifier */
362         status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
363         if (!NT_STATUS_IS_OK(status)) {
364                 return status;
365         }
366
367         /* extract the whole packet as a blob */
368         *blob = ndr_push_blob(ndr);
369
370         /* fill in the fragment length and auth_length, we can't fill
371            in these earlier as we don't know the signature length (it
372            could be variable length) */
373         dcerpc_set_frag_length(blob, blob->length);
374         dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
375
376         /* sign or seal the packet */
377         switch (p->security_state.auth_info->auth_level) {
378         case DCERPC_AUTH_LEVEL_PRIVACY:
379                 status = gensec_seal_packet(p->security_state.generic_state, 
380                                             mem_ctx, 
381                                             blob->data + DCERPC_REQUEST_LENGTH, 
382                                             pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
383                                             blob->data,
384                                             blob->length - 
385                                             p->security_state.auth_info->credentials.length,
386                                             &creds2);
387                 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
388                 break;
389
390         case DCERPC_AUTH_LEVEL_INTEGRITY:
391                 status = gensec_sign_packet(p->security_state.generic_state, 
392                                             mem_ctx, 
393                                             blob->data + DCERPC_REQUEST_LENGTH, 
394                                             pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
395                                             blob->data,
396                                             blob->length - 
397                                             p->security_state.auth_info->credentials.length,
398                                             &creds2);
399                 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
400                 break;
401
402         case DCERPC_AUTH_LEVEL_CONNECT:
403                 break;
404
405         case DCERPC_AUTH_LEVEL_NONE:
406                 p->security_state.auth_info->credentials = data_blob(NULL, 0);
407                 break;
408
409         default:
410                 status = NT_STATUS_INVALID_LEVEL;
411                 break;
412         }
413
414         data_blob_free(&p->security_state.auth_info->credentials);
415
416         return NT_STATUS_OK;
417 }
418
419
420 /* 
421    fill in the fixed values in a dcerpc header 
422 */
423 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
424 {
425         pkt->rpc_vers = 5;
426         pkt->rpc_vers_minor = 0;
427         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
428                 pkt->drep[0] = 0;
429         } else {
430                 pkt->drep[0] = DCERPC_DREP_LE;
431         }
432         pkt->drep[1] = 0;
433         pkt->drep[2] = 0;
434         pkt->drep[3] = 0;
435 }
436
437 /*
438   hold the state of pending full requests
439 */
440 struct full_request_state {
441         DATA_BLOB *reply_blob;
442         NTSTATUS status;
443 };
444
445 /*
446   receive a reply to a full request
447  */
448 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob, 
449                               NTSTATUS status)
450 {
451         struct full_request_state *state = p->full_request_private;
452
453         if (!NT_STATUS_IS_OK(status)) {
454                 state->status = status;
455                 return;
456         }
457         state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
458         state->reply_blob = NULL;
459 }
460
461 /*
462   perform a single pdu synchronous request - used for the bind code
463   this cannot be mixed with normal async requests
464 */
465 static NTSTATUS full_request(struct dcerpc_pipe *p, 
466                              TALLOC_CTX *mem_ctx,
467                              DATA_BLOB *request_blob,
468                              DATA_BLOB *reply_blob)
469 {
470         struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
471         NTSTATUS status;
472
473         if (state == NULL) {
474                 return NT_STATUS_NO_MEMORY;
475         }
476
477         state->reply_blob = reply_blob;
478         state->status = NT_STATUS_OK;
479
480         p->transport.recv_data = full_request_recv;
481         p->full_request_private = state;
482
483         status = p->transport.send_request(p, request_blob, True);
484         if (!NT_STATUS_IS_OK(status)) {
485                 return status;
486         }
487
488         while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
489                 struct event_context *ctx = p->transport.event_context(p);
490                 if (event_loop_once(ctx) != 0) {
491                         return NT_STATUS_CONNECTION_DISCONNECTED;
492                 }
493         }
494
495         return state->status;
496 }
497
498
499 /* 
500    perform a bind using the given syntax 
501
502    the auth_info structure is updated with the reply authentication info
503    on success
504 */
505 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
506                      TALLOC_CTX *mem_ctx,
507                      const struct dcerpc_syntax_id *syntax,
508                      const struct dcerpc_syntax_id *transfer_syntax)
509 {
510         struct dcerpc_packet pkt;
511         NTSTATUS status;
512         DATA_BLOB blob;
513
514         p->syntax = *syntax;
515         p->transfer_syntax = *transfer_syntax;
516
517         init_dcerpc_hdr(p, &pkt);
518
519         pkt.ptype = DCERPC_PKT_BIND;
520         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
521         pkt.call_id = p->call_id;
522         pkt.auth_length = 0;
523
524         pkt.u.bind.max_xmit_frag = 5840;
525         pkt.u.bind.max_recv_frag = 5840;
526         pkt.u.bind.assoc_group_id = 0;
527         pkt.u.bind.num_contexts = 1;
528         pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
529         if (!pkt.u.bind.ctx_list) {
530                 return NT_STATUS_NO_MEMORY;
531         }
532         pkt.u.bind.ctx_list[0].context_id = 0;
533         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
534         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
535         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
536         pkt.u.bind.auth_info = data_blob(NULL, 0);
537
538         /* construct the NDR form of the packet */
539         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
540         if (!NT_STATUS_IS_OK(status)) {
541                 return status;
542         }
543
544         /* send it on its way */
545         status = full_request(p, mem_ctx, &blob, &blob);
546         if (!NT_STATUS_IS_OK(status)) {
547                 return status;
548         }
549
550         /* unmarshall the NDR */
551         status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
552         if (!NT_STATUS_IS_OK(status)) {
553                 return status;
554         }
555
556         if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
557                 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
558                 return NT_STATUS_ACCESS_DENIED;
559         }
560
561         if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
562             pkt.u.bind_ack.num_results == 0 ||
563             pkt.u.bind_ack.ctx_list[0].result != 0) {
564                 return NT_STATUS_UNSUCCESSFUL;
565         }
566
567         if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
568                 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
569                 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
570         }
571
572         /* the bind_ack might contain a reply set of credentials */
573         if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
574                 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
575                                               mem_ctx,
576                                               p->security_state.auth_info,
577                                               (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
578         }
579
580         return status;  
581 }
582
583 /* 
584    perform a alter context using the given syntax 
585
586    the auth_info structure is updated with the reply authentication info
587    on success
588 */
589 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p, 
590                      TALLOC_CTX *mem_ctx)
591 {
592         struct dcerpc_packet pkt;
593         NTSTATUS status;
594         DATA_BLOB blob;
595
596         init_dcerpc_hdr(p, &pkt);
597
598         pkt.ptype = DCERPC_PKT_ALTER;
599         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
600         pkt.call_id = p->call_id;
601         pkt.auth_length = 0;
602
603         pkt.u.alter.max_xmit_frag = 0x2000;
604         pkt.u.alter.max_recv_frag = 0x2000;
605         pkt.u.alter.assoc_group_id = 0;
606         pkt.u.alter.num_contexts = 1;
607         pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
608         if (!pkt.u.alter.ctx_list) {
609                 return NT_STATUS_NO_MEMORY;
610         }
611         pkt.u.alter.ctx_list[0].context_id = 0;
612         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
613         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
614         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
615         pkt.u.alter.auth_info = data_blob(NULL, 0);
616
617         /* construct the NDR form of the packet */
618         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
619         if (!NT_STATUS_IS_OK(status)) {
620                 return status;
621         }
622
623         /* send it on its way */
624         status = full_request(p, mem_ctx, &blob, &blob);
625         if (!NT_STATUS_IS_OK(status)) {
626                 return status;
627         }
628
629         /* unmarshall the NDR */
630         status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
631         if (!NT_STATUS_IS_OK(status)) {
632                 return status;
633         }
634
635         if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
636             pkt.u.alter_ack.num_results == 0 ||
637             pkt.u.alter_ack.ctx_list[0].result != 0) {
638                 status = NT_STATUS_UNSUCCESSFUL;
639         }
640
641         /* the bind_ack might contain a reply set of credentials */
642         if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
643                 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
644                                               mem_ctx,
645                                               p->security_state.auth_info,
646                                               (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
647         }
648
649         return status;  
650 }
651
652 /* 
653    perform a continued bind (and auth3)
654 */
655 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p, 
656                       TALLOC_CTX *mem_ctx)
657 {
658         struct dcerpc_packet pkt;
659         NTSTATUS status;
660         DATA_BLOB blob;
661
662         init_dcerpc_hdr(p, &pkt);
663
664         pkt.ptype = DCERPC_PKT_AUTH3;
665         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
666         pkt.call_id = next_call_id(p);
667         pkt.auth_length = 0;
668         pkt.u.auth._pad = 0;
669         pkt.u.auth.auth_info = data_blob(NULL, 0);
670
671         /* construct the NDR form of the packet */
672         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
673         if (!NT_STATUS_IS_OK(status)) {
674                 return status;
675         }
676
677         /* send it on its way */
678         status = p->transport.send_request(p, &blob, False);
679         if (!NT_STATUS_IS_OK(status)) {
680                 return status;
681         }
682
683         return status;  
684 }
685
686
687 /* perform a dcerpc bind, using the uuid as the key */
688 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, 
689                             TALLOC_CTX *mem_ctx,
690                             const char *uuid, uint_t version)
691 {
692         struct dcerpc_syntax_id syntax;
693         struct dcerpc_syntax_id transfer_syntax;
694         NTSTATUS status;
695
696         status = GUID_from_string(uuid, &syntax.uuid);
697         if (!NT_STATUS_IS_OK(status)) {
698                 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
699                 return status;
700         }
701         syntax.if_version = version;
702
703         status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
704         if (!NT_STATUS_IS_OK(status)) {
705                 return status;
706         }
707         transfer_syntax.if_version = NDR_GUID_VERSION;
708
709         return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
710 }
711
712 /*
713   process a fragment received from the transport layer during a
714   request
715 */
716 static void dcerpc_request_recv_data(struct dcerpc_pipe *p, 
717                                      DATA_BLOB *data,
718                                      NTSTATUS status)
719 {
720         struct dcerpc_packet pkt;
721         struct rpc_request *req;
722         uint_t length;
723         
724         if (!NT_STATUS_IS_OK(status)) {
725                 /* all pending requests get the error */
726                 while (p->pending) {
727                         req = p->pending;
728                         req->state = RPC_REQUEST_DONE;
729                         req->status = status;
730                         DLIST_REMOVE(p->pending, req);
731                         if (req->async.callback) {
732                                 req->async.callback(req);
733                         }
734                 }
735                 return;
736         }
737
738         pkt.call_id = 0;
739
740         status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
741
742         /* find the matching request. Notice we match before we check
743            the status.  this is ok as a pending call_id can never be
744            zero */
745         for (req=p->pending;req;req=req->next) {
746                 if (pkt.call_id == req->call_id) break;
747         }
748
749         if (req == NULL) {
750                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
751                 return;
752         }
753
754         if (!NT_STATUS_IS_OK(status)) {
755                 req->status = status;
756                 req->state = RPC_REQUEST_DONE;
757                 DLIST_REMOVE(p->pending, req);
758                 if (req->async.callback) {
759                         req->async.callback(req);
760                 }
761                 return;
762         }
763
764         if (pkt.ptype == DCERPC_PKT_FAULT) {
765                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(p, pkt.u.fault.status)));
766                 req->fault_code = pkt.u.fault.status;
767                 req->status = NT_STATUS_NET_WRITE_FAULT;
768                 req->state = RPC_REQUEST_DONE;
769                 DLIST_REMOVE(p->pending, req);
770                 if (req->async.callback) {
771                         req->async.callback(req);
772                 }
773                 return;
774         }
775
776         if (pkt.ptype != DCERPC_PKT_RESPONSE) {
777                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
778                          (int)pkt.ptype)); 
779                 req->fault_code = DCERPC_FAULT_OTHER;
780                 req->status = NT_STATUS_NET_WRITE_FAULT;
781                 req->state = RPC_REQUEST_DONE;
782                 DLIST_REMOVE(p->pending, req);
783                 if (req->async.callback) {
784                         req->async.callback(req);
785                 }
786                 return;
787         }
788
789         length = pkt.u.response.stub_and_verifier.length;
790
791         if (length > 0) {
792                 req->payload.data = talloc_realloc(req, 
793                                                    req->payload.data, 
794                                                    req->payload.length + length);
795                 if (!req->payload.data) {
796                         req->status = NT_STATUS_NO_MEMORY;
797                         req->state = RPC_REQUEST_DONE;
798                         DLIST_REMOVE(p->pending, req);
799                         if (req->async.callback) {
800                                 req->async.callback(req);
801                         }
802                         return;
803                 }
804                 memcpy(req->payload.data+req->payload.length, 
805                        pkt.u.response.stub_and_verifier.data, length);
806                 req->payload.length += length;
807         }
808
809         if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
810                 p->transport.send_read(p);
811                 return;
812         }
813
814         /* we've got the full payload */
815         req->state = RPC_REQUEST_DONE;
816         DLIST_REMOVE(p->pending, req);
817
818         if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
819                 req->flags |= DCERPC_PULL_BIGENDIAN;
820         } else {
821                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
822         }
823
824         if (req->async.callback) {
825                 req->async.callback(req);
826         }
827 }
828
829
830 /*
831   make sure requests are cleaned up 
832  */
833 static int dcerpc_req_destructor(void *ptr)
834 {
835         struct rpc_request *req = ptr;
836         DLIST_REMOVE(req->p->pending, req);
837         return 0;
838 }
839
840 /*
841   perform the send size of a async dcerpc request
842 */
843 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
844                                         struct GUID *object,
845                                         uint16_t opnum,
846                                         TALLOC_CTX *mem_ctx,
847                                         DATA_BLOB *stub_data)
848 {
849         struct rpc_request *req;
850         struct dcerpc_packet pkt;
851         DATA_BLOB blob;
852         uint32_t remaining, chunk_size;
853         BOOL first_packet = True;
854
855         p->transport.recv_data = dcerpc_request_recv_data;
856
857         req = talloc_p(mem_ctx, struct rpc_request);
858         if (req == NULL) {
859                 return NULL;
860         }
861
862         req->p = p;
863         req->call_id = next_call_id(p);
864         req->status = NT_STATUS_OK;
865         req->state = RPC_REQUEST_PENDING;
866         req->payload = data_blob(NULL, 0);
867         req->flags = 0;
868         req->fault_code = 0;
869         req->async.callback = NULL;
870
871         init_dcerpc_hdr(p, &pkt);
872
873         remaining = stub_data->length;
874
875         /* we can write a full max_recv_frag size, minus the dcerpc
876            request header size */
877         chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
878
879         pkt.ptype = DCERPC_PKT_REQUEST;
880         pkt.call_id = req->call_id;
881         pkt.auth_length = 0;
882         pkt.u.request.alloc_hint = remaining;
883         pkt.u.request.context_id = 0;
884         pkt.u.request.opnum = opnum;
885         if (object) {
886                 pkt.object.object = *object;
887                 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
888                 /* FIXME: pfc_cflags is reset below! */
889         }
890
891         DLIST_ADD(p->pending, req);
892
893         /* we send a series of pdus without waiting for a reply */
894         while (remaining > 0 || first_packet) {
895                 uint32_t chunk = MIN(chunk_size, remaining);
896                 BOOL last_frag = False;
897
898                 first_packet = False;
899                 pkt.pfc_flags = 0;
900
901                 if (remaining == stub_data->length) {
902                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
903                 }
904                 if (chunk == remaining) {
905                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
906                         last_frag = True;
907                 }
908
909                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
910                         (stub_data->length - remaining);
911                 pkt.u.request.stub_and_verifier.length = chunk;
912
913                 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
914                 if (!NT_STATUS_IS_OK(req->status)) {
915                         req->state = RPC_REQUEST_DONE;
916                         DLIST_REMOVE(p->pending, req);
917                         return req;
918                 }
919                 
920                 req->status = p->transport.send_request(p, &blob, last_frag);
921                 if (!NT_STATUS_IS_OK(req->status)) {
922                         req->state = RPC_REQUEST_DONE;
923                         DLIST_REMOVE(p->pending, req);
924                         return req;
925                 }               
926
927                 remaining -= chunk;
928         }
929
930         talloc_set_destructor(req, dcerpc_req_destructor);
931
932         return req;
933 }
934
935 /*
936   return the event context for a dcerpc pipe
937   used by callers who wish to operate asynchronously
938 */
939 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
940 {
941         return p->transport.event_context(p);
942 }
943
944
945
946 /*
947   perform the receive side of a async dcerpc request
948 */
949 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
950                              TALLOC_CTX *mem_ctx,
951                              DATA_BLOB *stub_data)
952 {
953         NTSTATUS status;
954
955         while (req->state == RPC_REQUEST_PENDING) {
956                 struct event_context *ctx = dcerpc_event_context(req->p);
957                 if (event_loop_once(ctx) != 0) {
958                         return NT_STATUS_CONNECTION_DISCONNECTED;
959                 }
960         }
961         *stub_data = req->payload;
962         status = req->status;
963         if (stub_data->data) {
964                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
965         }
966         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
967                 req->p->last_fault_code = req->fault_code;
968         }
969         talloc_free(req);
970         return status;
971 }
972
973 /*
974   perform a full request/response pair on a dcerpc pipe
975 */
976 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
977                         struct OBJREF *object,
978                         uint16_t opnum,
979                         TALLOC_CTX *mem_ctx,
980                         DATA_BLOB *stub_data_in,
981                         DATA_BLOB *stub_data_out)
982 {
983         struct rpc_request *req;
984
985         req = dcerpc_request_send(p, object, opnum, mem_ctx, stub_data_in);
986         if (req == NULL) {
987                 return NT_STATUS_NO_MEMORY;
988         }
989
990         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
991 }
992
993
994 /*
995   this is a paranoid NDR validator. For every packet we push onto the wire
996   we pull it back again, then push it again. Then we compare the raw NDR data
997   for that to the NDR we initially generated. If they don't match then we know
998   we must have a bug in either the pull or push side of our code
999 */
1000 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p, 
1001                                        TALLOC_CTX *mem_ctx,
1002                                        DATA_BLOB blob,
1003                                        size_t struct_size,
1004                                        NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1005                                        NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1006 {
1007         void *st;
1008         struct ndr_pull *pull;
1009         struct ndr_push *push;
1010         NTSTATUS status;
1011         DATA_BLOB blob2;
1012
1013         st = talloc(mem_ctx, struct_size);
1014         if (!st) {
1015                 return NT_STATUS_NO_MEMORY;
1016         }
1017
1018         pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1019         if (!pull) {
1020                 return NT_STATUS_NO_MEMORY;
1021         }
1022
1023         status = ndr_pull(pull, NDR_IN, st);
1024         if (!NT_STATUS_IS_OK(status)) {
1025                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1026                                       "failed input validation pull - %s",
1027                                       nt_errstr(status));
1028         }
1029
1030         push = ndr_push_init_ctx(mem_ctx);
1031         if (!push) {
1032                 return NT_STATUS_NO_MEMORY;
1033         }       
1034
1035         status = ndr_push(push, NDR_IN, st);
1036         if (!NT_STATUS_IS_OK(status)) {
1037                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1038                                       "failed input validation push - %s",
1039                                       nt_errstr(status));
1040         }
1041
1042         blob2 = ndr_push_blob(push);
1043
1044         if (!data_blob_equal(&blob, &blob2)) {
1045                 DEBUG(3,("original:\n"));
1046                 dump_data(3, blob.data, blob.length);
1047                 DEBUG(3,("secondary:\n"));
1048                 dump_data(3, blob2.data, blob2.length);
1049                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1050                                       "failed input validation data - %s",
1051                                       nt_errstr(status));
1052         }
1053
1054         return NT_STATUS_OK;
1055 }
1056
1057 /*
1058   this is a paranoid NDR input validator. For every packet we pull
1059   from the wire we push it back again then pull and push it
1060   again. Then we compare the raw NDR data for that to the NDR we
1061   initially generated. If they don't match then we know we must have a
1062   bug in either the pull or push side of our code
1063 */
1064 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
1065                                         TALLOC_CTX *mem_ctx,
1066                                         void *struct_ptr,
1067                                         size_t struct_size,
1068                                         NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1069                                         NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1070 {
1071         void *st;
1072         struct ndr_pull *pull;
1073         struct ndr_push *push;
1074         NTSTATUS status;
1075         DATA_BLOB blob, blob2;
1076
1077         st = talloc(mem_ctx, struct_size);
1078         if (!st) {
1079                 return NT_STATUS_NO_MEMORY;
1080         }
1081         memcpy(st, struct_ptr, struct_size);
1082
1083         push = ndr_push_init_ctx(mem_ctx);
1084         if (!push) {
1085                 return NT_STATUS_NO_MEMORY;
1086         }       
1087
1088         status = ndr_push(push, NDR_OUT, struct_ptr);
1089         if (!NT_STATUS_IS_OK(status)) {
1090                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1091                                       "failed output validation push - %s",
1092                                       nt_errstr(status));
1093         }
1094
1095         blob = ndr_push_blob(push);
1096
1097         pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1098         if (!pull) {
1099                 return NT_STATUS_NO_MEMORY;
1100         }
1101
1102         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1103         status = ndr_pull(pull, NDR_OUT, st);
1104         if (!NT_STATUS_IS_OK(status)) {
1105                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1106                                       "failed output validation pull - %s",
1107                                       nt_errstr(status));
1108         }
1109
1110         push = ndr_push_init_ctx(mem_ctx);
1111         if (!push) {
1112                 return NT_STATUS_NO_MEMORY;
1113         }       
1114
1115         status = ndr_push(push, NDR_OUT, st);
1116         if (!NT_STATUS_IS_OK(status)) {
1117                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1118                                       "failed output validation push2 - %s",
1119                                       nt_errstr(status));
1120         }
1121
1122         blob2 = ndr_push_blob(push);
1123
1124         if (!data_blob_equal(&blob, &blob2)) {
1125                 DEBUG(3,("original:\n"));
1126                 dump_data(3, blob.data, blob.length);
1127                 DEBUG(3,("secondary:\n"));
1128                 dump_data(3, blob2.data, blob2.length);
1129                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1130                                       "failed output validation data - %s",
1131                                       nt_errstr(status));
1132         }
1133
1134         return NT_STATUS_OK;
1135 }
1136
1137
1138 /*
1139   send a rpc request with a given set of ndr helper functions
1140
1141   call dcerpc_ndr_request_recv() to receive the answer
1142 */
1143 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1144                                                 struct OBJREF *object,
1145                                             uint32_t opnum,
1146                                             TALLOC_CTX *mem_ctx,
1147                                             NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1148                                             NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1149                                             void *struct_ptr,
1150                                             size_t struct_size)
1151 {
1152         struct ndr_push *push;
1153         NTSTATUS status;
1154         DATA_BLOB request;
1155         struct rpc_request *req;
1156
1157         /* setup for a ndr_push_* call */
1158         push = ndr_push_init();
1159         if (!push) {
1160                 return NULL;
1161         }
1162
1163         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1164                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1165         }
1166
1167         /* push the structure into a blob */
1168         status = ndr_push(push, NDR_IN, struct_ptr);
1169         if (!NT_STATUS_IS_OK(status)) {
1170                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1171                          nt_errstr(status)));
1172                 ndr_push_free(push);
1173                 return NULL;
1174         }
1175
1176         /* retrieve the blob */
1177         request = ndr_push_blob(push);
1178
1179         if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1180                 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size, 
1181                                                 ndr_push, ndr_pull);
1182                 if (!NT_STATUS_IS_OK(status)) {
1183                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1184                                  nt_errstr(status)));
1185                         ndr_push_free(push);
1186                         return NULL;
1187                 }
1188         }
1189
1190         DEBUG(10,("rpc request data:\n"));
1191         dump_data(10, request.data, request.length);
1192
1193         /* make the actual dcerpc request */
1194         req = dcerpc_request_send(p, object, opnum, mem_ctx, &request);
1195
1196         if (req != NULL) {
1197                 req->ndr.ndr_push = ndr_push;
1198                 req->ndr.ndr_pull = ndr_pull;
1199                 req->ndr.struct_ptr = struct_ptr;
1200                 req->ndr.struct_size = struct_size;
1201                 req->ndr.mem_ctx = mem_ctx;
1202         }
1203
1204         ndr_push_free(push);
1205         
1206         return req;
1207 }
1208
1209 /*
1210   receive the answer from a dcerpc_ndr_request_send()
1211 */
1212 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1213 {
1214         struct dcerpc_pipe *p = req->p;
1215         NTSTATUS status;
1216         DATA_BLOB response;
1217         struct ndr_pull *pull;
1218         struct rpc_request_ndr ndr = req->ndr;
1219         uint_t flags;
1220
1221         /* make sure the recv code doesn't free the request, as we
1222            need to grab the flags element before it is freed */
1223         talloc_increase_ref_count(req);
1224
1225         status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1226         if (!NT_STATUS_IS_OK(status)) {
1227                 return status;
1228         }
1229
1230         flags = req->flags;
1231         talloc_free(req);
1232
1233         /* prepare for ndr_pull_* */
1234         pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1235         if (!pull) {
1236                 return NT_STATUS_NO_MEMORY;
1237         }
1238
1239         if (flags & DCERPC_PULL_BIGENDIAN) {
1240                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1241         }
1242
1243         DEBUG(10,("rpc reply data:\n"));
1244         dump_data(10, pull->data, pull->data_size);
1245
1246         /* pull the structure from the blob */
1247         status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1248         if (!NT_STATUS_IS_OK(status)) {
1249                 return status;
1250         }
1251
1252         if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1253                 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size, 
1254                                                  ndr.ndr_push, ndr.ndr_pull);
1255                 if (!NT_STATUS_IS_OK(status)) {
1256                         return status;
1257                 }
1258         }
1259
1260         if (pull->offset != pull->data_size) {
1261                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1262                          pull->data_size - pull->offset));
1263                 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1264                    but it turns out that early versions of NT
1265                    (specifically NT3.1) add junk onto the end of rpc
1266                    packets, so if we want to interoperate at all with
1267                    those versions then we need to ignore this error */
1268         }
1269
1270         return NT_STATUS_OK;
1271 }
1272
1273
1274 /*
1275   a useful helper function for synchronous rpc requests 
1276
1277   this can be used when you have ndr push/pull functions in the
1278   standard format
1279 */
1280 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1281                                 struct OBJREF *object,
1282                             uint32_t opnum,
1283                             TALLOC_CTX *mem_ctx,
1284                             NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1285                             NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1286                             void *struct_ptr,
1287                             size_t struct_size)
1288 {
1289         struct rpc_request *req;
1290
1291         req = dcerpc_ndr_request_send(p, object, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1292         if (req == NULL) {
1293                 return NT_STATUS_NO_MEMORY;
1294         }
1295
1296         return dcerpc_ndr_request_recv(req);
1297 }
1298
1299
1300 /*
1301   a useful function for retrieving the server name we connected to
1302 */
1303 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1304 {
1305         if (!p->transport.peer_name) {
1306                 return "";
1307         }
1308         return p->transport.peer_name(p);
1309 }
1310
1311 /*
1312   a useful function to get the auth_level 
1313 */
1314
1315 uint32 dcerpc_auth_level(struct dcerpc_pipe *p) 
1316 {
1317         uint8_t auth_level;
1318
1319         if (p->flags & DCERPC_SEAL) {
1320                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1321         } else if (p->flags & DCERPC_SIGN) {
1322                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1323         } else if (p->flags & DCERPC_CONNECT) {
1324                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1325         } else {
1326                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1327         }
1328         return auth_level;
1329 }