s3-dcerpc: Fix ability to receive Big Endian PDUs
[mat/samba.git] / librpc / rpc / dcerpc_util.c
1 /*
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Andrew Tridgell 2003-2005
6    Copyright (C) Jelmer Vernooij 2004-2005
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "librpc/rpc/dcerpc.h"
24 #include "librpc/gen_ndr/ndr_dcerpc.h"
25
26 /* we need to be able to get/set the fragment length without doing a full
27    decode */
28 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
29 {
30         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
31                 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
32         } else {
33                 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
34         }
35 }
36
37 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
38 {
39         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
40                 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
41         } else {
42                 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
43         }
44 }
45
46 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
47 {
48         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
49                 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
50         } else {
51                 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
52         }
53 }
54
55 uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob)
56 {
57         return blob->data[DCERPC_DREP_OFFSET];
58 }
59
60 /*
61   pull an dcerpc_auth structure, taking account of any auth padding in
62   the blob at the end of the structure
63  */
64 NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
65                                   TALLOC_CTX *mem_ctx,
66                                   DATA_BLOB *pkt_auth_blob,
67                                   struct dcerpc_auth *auth,
68                                   uint32_t *auth_length,
69                                   bool check_pad)
70 {
71         struct ndr_pull *ndr;
72         enum ndr_err_code ndr_err;
73         uint32_t pad;
74
75         pad = pkt_auth_blob->length - (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length);
76
77         /* paranoia check for pad size. This would be caught anyway by
78            the ndr_pull_advance() a few lines down, but it scared
79            Jeremy enough for him to call me, so we might as well check
80            it now, just to prevent someone posting a bogus YouTube
81            video in the future.
82         */
83         if (pad > pkt_auth_blob->length) {
84                 return NT_STATUS_INFO_LENGTH_MISMATCH;
85         }
86
87         *auth_length = pkt_auth_blob->length - pad;
88
89         ndr = ndr_pull_init_blob(pkt_auth_blob, mem_ctx);
90         if (!ndr) {
91                 return NT_STATUS_NO_MEMORY;
92         }
93
94         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
95                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
96         }
97
98         ndr_err = ndr_pull_advance(ndr, pad);
99         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
100                 talloc_free(ndr);
101                 return ndr_map_error2ntstatus(ndr_err);
102         }
103
104         ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
105         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
106                 talloc_free(ndr);
107                 return ndr_map_error2ntstatus(ndr_err);
108         }
109
110         if (check_pad && pad != auth->auth_pad_length) {
111                 DEBUG(1,(__location__ ": WARNING: pad length mismatch. Calculated %u  got %u\n",
112                          (unsigned)pad, (unsigned)auth->auth_pad_length));
113         }
114
115         DEBUG(6,(__location__ ": auth_pad_length %u\n",
116                  (unsigned)auth->auth_pad_length));
117
118         talloc_steal(mem_ctx, auth->credentials.data);
119         talloc_free(ndr);
120
121         return NT_STATUS_OK;
122 }