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