Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : TDR (Trivial Data Representation) helper functions
5 : Based loosely on ndr.c by Andrew Tridgell.
6 :
7 : Copyright (C) Jelmer Vernooij 2005
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 3 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, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/filesys.h"
25 : #include "system/network.h"
26 : #include "lib/tdr/tdr.h"
27 :
28 : #define TDR_BASE_MARSHALL_SIZE 1024
29 :
30 : #define TDR_PUSH_NEED_BYTES(tdr, n) TDR_CHECK(tdr_push_expand(tdr, tdr->data.length+(n)))
31 :
32 : #define TDR_PULL_NEED_BYTES(tdr, n) do { \
33 : if ((n) > tdr->data.length || tdr->offset + (n) > tdr->data.length) { \
34 : return NT_STATUS_BUFFER_TOO_SMALL; \
35 : } \
36 : } while(0)
37 :
38 : #define TDR_BE(tdr) ((tdr)->flags & TDR_BIG_ENDIAN)
39 :
40 : #define TDR_CVAL(tdr, ofs) CVAL(tdr->data.data,ofs)
41 : #define TDR_SVAL(tdr, ofs) (TDR_BE(tdr)?RSVAL(tdr->data.data,ofs):SVAL(tdr->data.data,ofs))
42 : #define TDR_IVAL(tdr, ofs) (TDR_BE(tdr)?RIVAL(tdr->data.data,ofs):IVAL(tdr->data.data,ofs))
43 : #define TDR_SCVAL(tdr, ofs, v) SCVAL(tdr->data.data,ofs,v)
44 : #define TDR_SSVAL(tdr, ofs, v) do { if (TDR_BE(tdr)) { RSSVAL(tdr->data.data,ofs,v); } else SSVAL(tdr->data.data,ofs,v); } while (0)
45 : #define TDR_SIVAL(tdr, ofs, v) do { if (TDR_BE(tdr)) { RSIVAL(tdr->data.data,ofs,v); } else SIVAL(tdr->data.data,ofs,v); } while (0)
46 :
47 : /**
48 : expand the available space in the buffer to 'size'
49 : */
50 9484 : NTSTATUS tdr_push_expand(struct tdr_push *tdr, uint32_t size)
51 : {
52 9484 : if (talloc_get_size(tdr->data.data) >= size) {
53 9411 : return NT_STATUS_OK;
54 : }
55 :
56 73 : tdr->data.data = talloc_realloc(tdr, tdr->data.data, uint8_t, tdr->data.length + TDR_BASE_MARSHALL_SIZE);
57 :
58 73 : if (tdr->data.data == NULL)
59 0 : return NT_STATUS_NO_MEMORY;
60 :
61 73 : return NT_STATUS_OK;
62 : }
63 :
64 :
65 145 : NTSTATUS tdr_pull_uint8(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint8_t *v)
66 : {
67 145 : TDR_PULL_NEED_BYTES(tdr, 1);
68 145 : *v = TDR_CVAL(tdr, tdr->offset);
69 145 : tdr->offset += 1;
70 145 : return NT_STATUS_OK;
71 : }
72 :
73 8177 : NTSTATUS tdr_push_uint8(struct tdr_push *tdr, const uint8_t *v)
74 : {
75 8177 : TDR_PUSH_NEED_BYTES(tdr, 1);
76 8177 : TDR_SCVAL(tdr, tdr->data.length, *v);
77 8177 : tdr->data.length += 1;
78 8177 : return NT_STATUS_OK;
79 : }
80 :
81 0 : NTSTATUS tdr_print_uint8(struct tdr_print *tdr, const char *name, uint8_t *v)
82 : {
83 0 : tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
84 0 : return NT_STATUS_OK;
85 : }
86 :
87 167 : NTSTATUS tdr_pull_uint16(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint16_t *v)
88 : {
89 167 : TDR_PULL_NEED_BYTES(tdr, 2);
90 167 : *v = TDR_SVAL(tdr, tdr->offset);
91 167 : tdr->offset += 2;
92 167 : return NT_STATUS_OK;
93 : }
94 :
95 44 : NTSTATUS tdr_pull_uint1632(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint16_t *v)
96 : {
97 44 : return tdr_pull_uint16(tdr, ctx, v);
98 : }
99 :
100 130 : NTSTATUS tdr_push_uint16(struct tdr_push *tdr, const uint16_t *v)
101 : {
102 130 : TDR_PUSH_NEED_BYTES(tdr, 2);
103 130 : TDR_SSVAL(tdr, tdr->data.length, *v);
104 130 : tdr->data.length += 2;
105 130 : return NT_STATUS_OK;
106 : }
107 :
108 33 : NTSTATUS tdr_push_uint1632(struct tdr_push *tdr, const uint16_t *v)
109 : {
110 33 : return tdr_push_uint16(tdr, v);
111 : }
112 :
113 0 : NTSTATUS tdr_print_uint16(struct tdr_print *tdr, const char *name, uint16_t *v)
114 : {
115 0 : tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
116 0 : return NT_STATUS_OK;
117 : }
118 :
119 768 : NTSTATUS tdr_pull_uint32(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint32_t *v)
120 : {
121 768 : TDR_PULL_NEED_BYTES(tdr, 4);
122 768 : *v = TDR_IVAL(tdr, tdr->offset);
123 768 : tdr->offset += 4;
124 768 : return NT_STATUS_OK;
125 : }
126 :
127 1036 : NTSTATUS tdr_push_uint32(struct tdr_push *tdr, const uint32_t *v)
128 : {
129 1036 : TDR_PUSH_NEED_BYTES(tdr, 4);
130 1036 : TDR_SIVAL(tdr, tdr->data.length, *v);
131 1036 : tdr->data.length += 4;
132 1036 : return NT_STATUS_OK;
133 : }
134 :
135 0 : NTSTATUS tdr_print_uint32(struct tdr_print *tdr, const char *name, uint32_t *v)
136 : {
137 0 : tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
138 0 : return NT_STATUS_OK;
139 : }
140 :
141 120 : NTSTATUS tdr_pull_charset(struct tdr_pull *tdr, TALLOC_CTX *ctx, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
142 : {
143 120 : size_t ret;
144 :
145 120 : if (length == -1) {
146 1 : switch (chset) {
147 1 : case CH_DOS:
148 1 : length = ascii_len_n((const char*)tdr->data.data+tdr->offset, tdr->data.length-tdr->offset);
149 1 : break;
150 0 : case CH_UTF16:
151 0 : length = utf16_null_terminated_len_n(tdr->data.data+tdr->offset, tdr->data.length-tdr->offset);
152 0 : break;
153 :
154 0 : default:
155 0 : return NT_STATUS_INVALID_PARAMETER;
156 : }
157 : }
158 :
159 120 : if (length == 0) {
160 1 : *v = talloc_strdup(ctx, "");
161 1 : return NT_STATUS_OK;
162 : }
163 :
164 119 : TDR_PULL_NEED_BYTES(tdr, el_size*length);
165 :
166 119 : if (!convert_string_talloc(ctx, chset, CH_UNIX, tdr->data.data+tdr->offset, el_size*length, v, &ret)) {
167 0 : return NT_STATUS_INVALID_PARAMETER;
168 : }
169 :
170 119 : tdr->offset += length * el_size;
171 :
172 119 : return NT_STATUS_OK;
173 : }
174 :
175 102 : NTSTATUS tdr_push_charset(struct tdr_push *tdr, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
176 : {
177 102 : size_t required, size = 0;
178 102 : bool ret;
179 :
180 102 : if (length == -1) {
181 1 : length = strlen(*v) + 1; /* Extra element for null character */
182 : }
183 :
184 102 : required = el_size * length;
185 102 : TDR_PUSH_NEED_BYTES(tdr, required);
186 :
187 102 : ret = convert_string(CH_UNIX, chset, *v, strlen(*v), tdr->data.data+tdr->data.length, required, &size);
188 102 : if (ret == false) {
189 0 : return NT_STATUS_INVALID_PARAMETER;
190 : }
191 :
192 : /* Make sure the remaining part of the string is filled with zeroes */
193 102 : if (size < required) {
194 5 : memset(tdr->data.data+tdr->data.length+size, 0, required-size);
195 : }
196 :
197 102 : tdr->data.length += required;
198 :
199 102 : return NT_STATUS_OK;
200 : }
201 :
202 0 : NTSTATUS tdr_print_charset(struct tdr_print *tdr, const char *name, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
203 : {
204 0 : tdr->print(tdr, "%-25s: %s", name, *v);
205 0 : return NT_STATUS_OK;
206 : }
207 :
208 : /**
209 : parse a hyper
210 : */
211 44 : NTSTATUS tdr_pull_hyper(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint64_t *v)
212 : {
213 44 : TDR_PULL_NEED_BYTES(tdr, 8);
214 44 : *v = TDR_IVAL(tdr, tdr->offset);
215 44 : *v |= (uint64_t)(TDR_IVAL(tdr, tdr->offset+4)) << 32;
216 44 : tdr->offset += 8;
217 44 : return NT_STATUS_OK;
218 : }
219 :
220 : /**
221 : push a hyper
222 : */
223 39 : NTSTATUS tdr_push_hyper(struct tdr_push *tdr, uint64_t *v)
224 : {
225 39 : TDR_PUSH_NEED_BYTES(tdr, 8);
226 39 : TDR_SIVAL(tdr, tdr->data.length, ((*v) & 0xFFFFFFFF));
227 39 : TDR_SIVAL(tdr, tdr->data.length+4, ((*v)>>32));
228 39 : tdr->data.length += 8;
229 39 : return NT_STATUS_OK;
230 : }
231 :
232 : /**
233 : push a NTTIME
234 : */
235 39 : NTSTATUS tdr_push_NTTIME(struct tdr_push *tdr, NTTIME *t)
236 : {
237 39 : TDR_CHECK(tdr_push_hyper(tdr, t));
238 39 : return NT_STATUS_OK;
239 : }
240 :
241 : /**
242 : pull a NTTIME
243 : */
244 44 : NTSTATUS tdr_pull_NTTIME(struct tdr_pull *tdr, TALLOC_CTX *ctx, NTTIME *t)
245 : {
246 44 : TDR_CHECK(tdr_pull_hyper(tdr, ctx, t));
247 44 : return NT_STATUS_OK;
248 : }
249 :
250 : /**
251 : push a time_t
252 : */
253 0 : NTSTATUS tdr_push_time_t(struct tdr_push *tdr, time_t *t)
254 : {
255 0 : return tdr_push_uint32(tdr, (uint32_t *)t);
256 : }
257 :
258 : /**
259 : pull a time_t
260 : */
261 0 : NTSTATUS tdr_pull_time_t(struct tdr_pull *tdr, TALLOC_CTX *ctx, time_t *t)
262 : {
263 0 : uint32_t tt;
264 0 : TDR_CHECK(tdr_pull_uint32(tdr, ctx, &tt));
265 0 : *t = tt;
266 0 : return NT_STATUS_OK;
267 : }
268 :
269 0 : NTSTATUS tdr_print_time_t(struct tdr_print *tdr, const char *name, time_t *t)
270 : {
271 0 : if (*t == (time_t)-1 || *t == 0) {
272 0 : tdr->print(tdr, "%-25s: (time_t)%d", name, (int)*t);
273 : } else {
274 0 : tdr->print(tdr, "%-25s: %s", name, timestring(tdr, *t));
275 : }
276 :
277 0 : return NT_STATUS_OK;
278 : }
279 :
280 0 : NTSTATUS tdr_print_NTTIME(struct tdr_print *tdr, const char *name, NTTIME *t)
281 : {
282 0 : tdr->print(tdr, "%-25s: %s", name, nt_time_string(tdr, *t));
283 :
284 0 : return NT_STATUS_OK;
285 : }
286 :
287 0 : NTSTATUS tdr_print_DATA_BLOB(struct tdr_print *tdr, const char *name, DATA_BLOB *r)
288 : {
289 0 : tdr->print(tdr, "%-25s: DATA_BLOB length=%u", name, r->length);
290 0 : if (r->length) {
291 0 : dump_data(10, r->data, r->length);
292 : }
293 :
294 0 : return NT_STATUS_OK;
295 : }
296 :
297 : #define TDR_ALIGN(l,n) (((l) & ((n)-1)) == 0?0:((n)-((l)&((n)-1))))
298 :
299 : /*
300 : push a DATA_BLOB onto the wire.
301 : */
302 0 : NTSTATUS tdr_push_DATA_BLOB(struct tdr_push *tdr, DATA_BLOB *blob)
303 : {
304 0 : if (tdr->flags & TDR_ALIGN2) {
305 0 : blob->length = TDR_ALIGN(tdr->data.length, 2);
306 0 : } else if (tdr->flags & TDR_ALIGN4) {
307 0 : blob->length = TDR_ALIGN(tdr->data.length, 4);
308 0 : } else if (tdr->flags & TDR_ALIGN8) {
309 0 : blob->length = TDR_ALIGN(tdr->data.length, 8);
310 : }
311 :
312 0 : TDR_PUSH_NEED_BYTES(tdr, blob->length);
313 :
314 0 : memcpy(tdr->data.data+tdr->data.length, blob->data, blob->length);
315 0 : return NT_STATUS_OK;
316 : }
317 :
318 : /*
319 : pull a DATA_BLOB from the wire.
320 : */
321 0 : NTSTATUS tdr_pull_DATA_BLOB(struct tdr_pull *tdr, TALLOC_CTX *ctx, DATA_BLOB *blob)
322 : {
323 0 : uint32_t length;
324 :
325 0 : if (tdr->flags & TDR_ALIGN2) {
326 0 : length = TDR_ALIGN(tdr->offset, 2);
327 0 : } else if (tdr->flags & TDR_ALIGN4) {
328 0 : length = TDR_ALIGN(tdr->offset, 4);
329 0 : } else if (tdr->flags & TDR_ALIGN8) {
330 0 : length = TDR_ALIGN(tdr->offset, 8);
331 0 : } else if (tdr->flags & TDR_REMAINING) {
332 0 : length = tdr->data.length - tdr->offset;
333 : } else {
334 0 : return NT_STATUS_INVALID_PARAMETER;
335 : }
336 :
337 0 : if (tdr->data.length - tdr->offset < length) {
338 0 : length = tdr->data.length - tdr->offset;
339 : }
340 :
341 0 : TDR_PULL_NEED_BYTES(tdr, length);
342 :
343 0 : *blob = data_blob_talloc(tdr, tdr->data.data+tdr->offset, length);
344 0 : tdr->offset += length;
345 0 : return NT_STATUS_OK;
346 : }
347 :
348 89 : struct tdr_push *tdr_push_init(TALLOC_CTX *mem_ctx)
349 : {
350 89 : struct tdr_push *push = talloc_zero(mem_ctx, struct tdr_push);
351 :
352 89 : if (push == NULL)
353 0 : return NULL;
354 :
355 0 : return push;
356 : }
357 :
358 73 : struct tdr_pull *tdr_pull_init(TALLOC_CTX *mem_ctx)
359 : {
360 73 : struct tdr_pull *pull = talloc_zero(mem_ctx, struct tdr_pull);
361 :
362 73 : if (pull == NULL)
363 0 : return NULL;
364 :
365 0 : return pull;
366 : }
367 :
368 4 : NTSTATUS tdr_push_to_fd(int fd, tdr_push_fn_t push_fn, const void *p)
369 : {
370 4 : struct tdr_push *push = tdr_push_init(NULL);
371 :
372 4 : if (push == NULL)
373 0 : return NT_STATUS_NO_MEMORY;
374 :
375 4 : if (NT_STATUS_IS_ERR(push_fn(push, p))) {
376 0 : DEBUG(1, ("Error pushing data\n"));
377 0 : talloc_free(push);
378 0 : return NT_STATUS_UNSUCCESSFUL;
379 : }
380 :
381 4 : if (write(fd, push->data.data, push->data.length) < push->data.length) {
382 0 : DEBUG(1, ("Error writing all data\n"));
383 0 : return NT_STATUS_UNSUCCESSFUL;
384 : }
385 :
386 4 : talloc_free(push);
387 :
388 4 : return NT_STATUS_OK;
389 : }
390 :
391 0 : void tdr_print_debug_helper(struct tdr_print *tdr, const char *format, ...)
392 : {
393 0 : va_list ap;
394 0 : char *s = NULL;
395 0 : int i, ret;
396 :
397 0 : va_start(ap, format);
398 0 : ret = vasprintf(&s, format, ap);
399 0 : va_end(ap);
400 :
401 0 : if (ret == -1) {
402 0 : return;
403 : }
404 :
405 0 : for (i=0;i<tdr->level;i++) { DEBUG(0,(" ")); }
406 :
407 0 : DEBUG(0,("%s\n", s));
408 0 : free(s);
409 : }
|