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