Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : routines for marshalling/unmarshalling string types
5 :
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 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/ndr/libndr.h"
24 :
25 : /**
26 : pull a general string from the wire
27 : */
28 1856222 : _PUBLIC_ enum ndr_err_code ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
29 : {
30 1856222 : char *as=NULL;
31 : uint32_t len1, ofs, len2;
32 : uint16_t len3;
33 1856222 : size_t conv_src_len = 0, converted_size;
34 1856222 : int do_convert = 1, chset = CH_UTF16;
35 1856222 : unsigned byte_mul = 2;
36 1856222 : unsigned flags = ndr->flags;
37 1856222 : unsigned c_len_term = 0;
38 :
39 1856222 : if (!(ndr_flags & NDR_SCALARS)) {
40 0 : return NDR_ERR_SUCCESS;
41 : }
42 :
43 1856222 : if (NDR_BE(ndr)) {
44 15618 : chset = CH_UTF16BE;
45 : }
46 :
47 1856222 : if (flags & LIBNDR_FLAG_STR_ASCII) {
48 48048 : chset = CH_DOS;
49 48048 : byte_mul = 1;
50 48048 : flags &= ~LIBNDR_FLAG_STR_ASCII;
51 : }
52 :
53 1856222 : if (flags & LIBNDR_FLAG_STR_UTF8) {
54 1134325 : chset = CH_UTF8;
55 1134325 : byte_mul = 1;
56 1134325 : flags &= ~LIBNDR_FLAG_STR_UTF8;
57 : }
58 :
59 1856222 : if (flags & LIBNDR_FLAG_STR_RAW8) {
60 0 : do_convert = 0;
61 0 : byte_mul = 1;
62 0 : flags &= ~LIBNDR_FLAG_STR_RAW8;
63 : }
64 :
65 1856222 : flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
66 1856222 : if (flags & LIBNDR_FLAG_STR_CHARLEN) {
67 168178 : c_len_term = 1;
68 168178 : flags &= ~LIBNDR_FLAG_STR_CHARLEN;
69 : }
70 :
71 1856222 : switch (flags & LIBNDR_STRING_FLAGS) {
72 0 : case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
73 : case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
74 0 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
75 0 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
76 0 : if (ofs != 0) {
77 0 : return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
78 : ndr->flags & LIBNDR_STRING_FLAGS);
79 : }
80 0 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2));
81 0 : if (len2 > len1) {
82 0 : return ndr_pull_error(ndr, NDR_ERR_STRING,
83 : "Bad string lengths len1=%u ofs=%u len2=%u\n",
84 : len1, ofs, len2);
85 0 : } else if (len1 != len2) {
86 0 : DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as));
87 : }
88 0 : conv_src_len = len2 + c_len_term;
89 0 : break;
90 :
91 0 : case LIBNDR_FLAG_STR_SIZE4:
92 : case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
93 0 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
94 0 : conv_src_len = len1 + c_len_term;
95 0 : break;
96 :
97 0 : case LIBNDR_FLAG_STR_LEN4:
98 : case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
99 0 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
100 0 : if (ofs != 0) {
101 0 : return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
102 : ndr->flags & LIBNDR_STRING_FLAGS);
103 : }
104 0 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
105 0 : conv_src_len = len1 + c_len_term;
106 0 : break;
107 :
108 0 : case LIBNDR_FLAG_STR_SIZE2:
109 : case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM:
110 0 : NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
111 0 : conv_src_len = len3 + c_len_term;
112 0 : break;
113 :
114 0 : case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
115 0 : NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
116 0 : conv_src_len = len3;
117 0 : byte_mul = 1; /* the length is now absolute */
118 0 : break;
119 :
120 1190594 : case LIBNDR_FLAG_STR_NULLTERM:
121 : /*
122 : * We ensure that conv_str_len cannot return 0 by
123 : * requring that there be enough bytes for at least
124 : * the NULL terminator
125 : */
126 1190594 : if (byte_mul == 1) {
127 1182373 : NDR_PULL_NEED_BYTES(ndr, 1);
128 1182373 : conv_src_len = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset);
129 : } else {
130 8221 : NDR_PULL_NEED_BYTES(ndr, 2);
131 8221 : conv_src_len = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset);
132 : }
133 1190594 : byte_mul = 1; /* the length is now absolute */
134 1190594 : break;
135 :
136 665628 : case LIBNDR_FLAG_STR_NOTERM:
137 665628 : if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
138 0 : return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
139 : ndr->flags & LIBNDR_STRING_FLAGS);
140 : }
141 665628 : conv_src_len = ndr->data_size - ndr->offset;
142 665628 : byte_mul = 1; /* the length is now absolute */
143 665628 : break;
144 :
145 0 : default:
146 0 : return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
147 : ndr->flags & LIBNDR_STRING_FLAGS);
148 : }
149 :
150 1856222 : NDR_PULL_NEED_BYTES(ndr, conv_src_len * byte_mul);
151 1856222 : if (conv_src_len == 0) {
152 3072 : as = talloc_strdup(ndr->current_mem_ctx, "");
153 3072 : converted_size = 0;
154 : } else {
155 1853150 : if (!do_convert) {
156 0 : as = talloc_strndup(ndr->current_mem_ctx,
157 0 : (char *)ndr->data + ndr->offset,
158 : conv_src_len);
159 0 : if (!as) {
160 0 : return ndr_pull_error(ndr, NDR_ERR_ALLOC,
161 : "Failed to talloc_strndup() in RAW8 ndr_string_pull()");
162 : }
163 0 : converted_size = MIN(strlen(as)+1, conv_src_len);
164 3549553 : } else if (!convert_string_talloc(ndr->current_mem_ctx, chset,
165 1853150 : CH_UNIX, ndr->data + ndr->offset,
166 : conv_src_len * byte_mul,
167 : (void **)(void *)&as,
168 : &converted_size)) {
169 0 : return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
170 : "Bad character conversion with flags 0x%x", flags);
171 : }
172 : }
173 :
174 : /* this is a way of detecting if a string is sent with the wrong
175 : termination */
176 1856222 : if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
177 665628 : if (as && converted_size > 0 && as[converted_size-1] == '\0') {
178 0 : DEBUG(6,("short string '%s', sent with NULL termination despite NOTERM flag in IDL\n", as));
179 : }
180 : } else {
181 1190594 : if (as && converted_size > 0 && as[converted_size-1] != '\0') {
182 0 : DEBUG(6,("long string '%s', send without NULL termination (which was expected)\n", as));
183 : }
184 : }
185 :
186 1856222 : NDR_CHECK(ndr_pull_advance(ndr, conv_src_len * byte_mul));
187 1856222 : *s = as;
188 :
189 1856222 : return NDR_ERR_SUCCESS;
190 : }
191 :
192 :
193 : /**
194 : push a general string onto the wire
195 : */
196 1106391 : _PUBLIC_ enum ndr_err_code ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
197 : {
198 : ssize_t s_len, c_len;
199 : size_t d_len;
200 1106391 : int do_convert = 1, chset = CH_UTF16;
201 1106391 : unsigned flags = ndr->flags;
202 1106391 : unsigned byte_mul = 2;
203 1106391 : uint8_t *dest = NULL;
204 :
205 1106391 : if (!(ndr_flags & NDR_SCALARS)) {
206 0 : return NDR_ERR_SUCCESS;
207 : }
208 :
209 1106391 : if (NDR_BE(ndr)) {
210 26547 : chset = CH_UTF16BE;
211 : }
212 :
213 1106391 : s_len = s?strlen(s):0;
214 :
215 1106391 : if (flags & LIBNDR_FLAG_STR_ASCII) {
216 32255 : chset = CH_DOS;
217 32255 : byte_mul = 1;
218 32255 : flags &= ~LIBNDR_FLAG_STR_ASCII;
219 : }
220 :
221 1106391 : if (flags & LIBNDR_FLAG_STR_UTF8) {
222 260048 : chset = CH_UTF8;
223 260048 : byte_mul = 1;
224 260048 : flags &= ~LIBNDR_FLAG_STR_UTF8;
225 : }
226 :
227 1106391 : if (flags & LIBNDR_FLAG_STR_RAW8) {
228 0 : do_convert = 0;
229 0 : byte_mul = 1;
230 0 : flags &= ~LIBNDR_FLAG_STR_RAW8;
231 : }
232 :
233 1106391 : flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
234 :
235 1106391 : if (!(flags & LIBNDR_FLAG_STR_NOTERM)) {
236 372023 : s_len++;
237 : }
238 :
239 1106391 : if (s_len == 0) {
240 12240 : d_len = 0;
241 12240 : dest = (uint8_t *)talloc_strdup(ndr, "");
242 1094151 : } else if (!do_convert) {
243 0 : d_len = s_len;
244 0 : dest = (uint8_t *)talloc_strndup(ndr, s, s_len);
245 1094151 : } else if (!convert_string_talloc(ndr, CH_UNIX, chset, s, s_len,
246 : (void **)(void *)&dest, &d_len))
247 : {
248 0 : return ndr_push_error(ndr, NDR_ERR_CHARCNV,
249 : "Bad character push conversion with flags 0x%x", flags);
250 : }
251 :
252 1106391 : if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
253 0 : c_len = d_len;
254 0 : flags &= ~LIBNDR_FLAG_STR_BYTESIZE;
255 1106391 : } else if (flags & LIBNDR_FLAG_STR_CHARLEN) {
256 554776 : c_len = (d_len / byte_mul)-1;
257 554776 : flags &= ~LIBNDR_FLAG_STR_CHARLEN;
258 : } else {
259 551615 : c_len = d_len / byte_mul;
260 : }
261 :
262 1106391 : switch ((flags & LIBNDR_STRING_FLAGS) & ~LIBNDR_FLAG_STR_NOTERM) {
263 0 : case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
264 0 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
265 0 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
266 0 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
267 0 : NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
268 0 : break;
269 :
270 0 : case LIBNDR_FLAG_STR_LEN4:
271 0 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
272 0 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
273 0 : NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
274 0 : break;
275 :
276 189 : case LIBNDR_FLAG_STR_SIZE4:
277 189 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
278 189 : NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
279 189 : break;
280 :
281 0 : case LIBNDR_FLAG_STR_SIZE2:
282 0 : NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len));
283 0 : NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
284 0 : break;
285 :
286 372023 : case LIBNDR_FLAG_STR_NULLTERM:
287 372023 : NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
288 372023 : break;
289 :
290 734179 : default:
291 734179 : if (ndr->flags & LIBNDR_FLAG_REMAINING) {
292 734179 : NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
293 734179 : break;
294 : }
295 :
296 0 : return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
297 : ndr->flags & LIBNDR_STRING_FLAGS);
298 : }
299 :
300 1106391 : talloc_free(dest);
301 :
302 1106391 : return NDR_ERR_SUCCESS;
303 : }
304 :
305 : /**
306 : push a general string onto the wire
307 : */
308 0 : _PUBLIC_ size_t ndr_string_array_size(struct ndr_push *ndr, const char *s)
309 : {
310 : size_t c_len;
311 0 : unsigned flags = ndr->flags;
312 0 : unsigned byte_mul = 2;
313 0 : unsigned c_len_term = 1;
314 :
315 0 : if (flags & LIBNDR_FLAG_STR_RAW8) {
316 0 : c_len = s?strlen(s):0;
317 : } else {
318 0 : c_len = s?strlen_m(s):0;
319 : }
320 :
321 0 : if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_RAW8|LIBNDR_FLAG_STR_UTF8)) {
322 0 : byte_mul = 1;
323 : }
324 :
325 0 : if (flags & LIBNDR_FLAG_STR_NOTERM) {
326 0 : c_len_term = 0;
327 : }
328 :
329 0 : c_len = c_len + c_len_term;
330 :
331 0 : if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
332 0 : c_len = c_len * byte_mul;
333 : }
334 :
335 0 : return c_len;
336 : }
337 :
338 85286 : _PUBLIC_ void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s)
339 : {
340 85286 : if (NDR_HIDE_SECRET(ndr)) {
341 0 : ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
342 0 : return;
343 : }
344 85286 : if (s) {
345 85044 : ndr->print(ndr, "%-25s: '%s'", name, s);
346 : } else {
347 242 : ndr->print(ndr, "%-25s: NULL", name);
348 : }
349 : }
350 :
351 0 : _PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, int flags)
352 : {
353 : /* FIXME: Is this correct for all strings ? */
354 0 : if(!(*string)) return ret;
355 0 : return ret+strlen(*string)+1;
356 : }
357 :
358 6 : static uint32_t guess_string_array_size(struct ndr_pull *ndr, int ndr_flags)
359 : {
360 : /*
361 : * Here we could do something clever like count the number of zeros in
362 : * the ndr data, but it is probably sufficient to pick a lowish number
363 : * (compared to the overhead of the talloc header) and let the
364 : * expontential resizing deal with longer arrays.
365 : */
366 6 : return 5;
367 : }
368 :
369 0 : static enum ndr_err_code extend_string_array(struct ndr_pull *ndr,
370 : const char ***_a,
371 : uint32_t *count)
372 : {
373 0 : const char **a = *_a;
374 0 : uint32_t inc = *count / 4 + 3;
375 0 : uint32_t alloc_size = *count + inc;
376 :
377 0 : if (alloc_size < *count) {
378 : /* overflow ! */
379 0 : return NDR_ERR_ALLOC;
380 : }
381 : /*
382 : * We allocate and zero two more bytes than we report back, so that
383 : * the string array will always be NULL terminated.
384 : */
385 0 : a = talloc_realloc(ndr->current_mem_ctx, a,
386 : const char *,
387 : alloc_size);
388 0 : NDR_ERR_HAVE_NO_MEMORY(a);
389 :
390 0 : memset(a + *count, 0, inc * sizeof(a[0]));
391 0 : *_a = a;
392 0 : *count = alloc_size - 2;
393 0 : return NDR_ERR_SUCCESS;
394 : }
395 :
396 : /**
397 : pull a general string array from the wire
398 : */
399 6 : _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a)
400 : {
401 6 : const char **a = NULL;
402 : uint32_t count;
403 6 : unsigned flags = ndr->flags;
404 6 : unsigned saved_flags = ndr->flags;
405 : uint32_t alloc_size;
406 :
407 6 : if (!(ndr_flags & NDR_SCALARS)) {
408 0 : return NDR_ERR_SUCCESS;
409 : }
410 :
411 6 : alloc_size = guess_string_array_size(ndr, ndr_flags);
412 6 : a = talloc_zero_array(ndr->current_mem_ctx, const char *, alloc_size + 2);
413 6 : NDR_ERR_HAVE_NO_MEMORY(a);
414 :
415 6 : switch (flags & (LIBNDR_FLAG_STR_NULLTERM|LIBNDR_FLAG_STR_NOTERM)) {
416 6 : case LIBNDR_FLAG_STR_NULLTERM:
417 : /*
418 : * here the strings are null terminated
419 : * but also the array is null terminated if LIBNDR_FLAG_REMAINING
420 : * is specified
421 : */
422 6 : for (count = 0;; count++) {
423 : TALLOC_CTX *tmp_ctx;
424 6 : const char *s = NULL;
425 6 : if (count == alloc_size) {
426 0 : NDR_CHECK(extend_string_array(ndr,
427 : &a,
428 : &alloc_size));
429 : }
430 :
431 6 : tmp_ctx = ndr->current_mem_ctx;
432 6 : ndr->current_mem_ctx = a;
433 6 : NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
434 6 : ndr->current_mem_ctx = tmp_ctx;
435 6 : if ((ndr->data_size - ndr->offset) == 0 && ndr->flags & LIBNDR_FLAG_REMAINING)
436 : {
437 6 : a[count] = s;
438 6 : break;
439 : }
440 0 : if (strcmp("", s)==0) {
441 0 : a[count] = NULL;
442 0 : break;
443 : } else {
444 0 : a[count] = s;
445 : }
446 : }
447 :
448 6 : *_a =a;
449 6 : break;
450 :
451 0 : case LIBNDR_FLAG_STR_NOTERM:
452 0 : if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
453 0 : return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
454 : ndr->flags & LIBNDR_STRING_FLAGS);
455 : }
456 : /*
457 : * here the strings are not null terminated
458 : * but separated by a null terminator
459 : *
460 : * which means the same as:
461 : * Every string is null terminated exept the last
462 : * string is terminated by the end of the buffer
463 : *
464 : * as LIBNDR_FLAG_STR_NULLTERM also end at the end
465 : * of the buffer, we can pull each string with this flag
466 : *
467 : * The big difference with the case LIBNDR_FLAG_STR_NOTERM +
468 : * LIBNDR_FLAG_REMAINING is that the last string will not be null terminated
469 : */
470 0 : ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
471 0 : ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
472 :
473 0 : for (count = 0; ((ndr->data_size - ndr->offset) > 0); count++) {
474 : TALLOC_CTX *tmp_ctx;
475 0 : const char *s = NULL;
476 0 : if (count == alloc_size) {
477 0 : NDR_CHECK(extend_string_array(ndr,
478 : &a,
479 : &alloc_size));
480 : }
481 :
482 0 : tmp_ctx = ndr->current_mem_ctx;
483 0 : ndr->current_mem_ctx = a;
484 0 : NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
485 0 : ndr->current_mem_ctx = tmp_ctx;
486 0 : a[count] = s;
487 : }
488 :
489 0 : a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 1);
490 0 : NDR_ERR_HAVE_NO_MEMORY(a);
491 0 : *_a = a;
492 0 : break;
493 :
494 0 : default:
495 0 : return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
496 : ndr->flags & LIBNDR_STRING_FLAGS);
497 : }
498 :
499 6 : ndr->flags = saved_flags;
500 6 : return NDR_ERR_SUCCESS;
501 : }
502 :
503 : /**
504 : push a general string array onto the wire
505 : */
506 25085 : _PUBLIC_ enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a)
507 : {
508 : uint32_t count;
509 25085 : unsigned flags = ndr->flags;
510 25085 : unsigned saved_flags = ndr->flags;
511 :
512 25085 : if (!(ndr_flags & NDR_SCALARS)) {
513 0 : return NDR_ERR_SUCCESS;
514 : }
515 :
516 25085 : switch (flags & LIBNDR_STRING_FLAGS) {
517 123 : case LIBNDR_FLAG_STR_NULLTERM:
518 246 : for (count = 0; a && a[count]; count++) {
519 123 : NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
520 : }
521 : /* If LIBNDR_FLAG_REMAINING then we do not add a null terminator to the array */
522 123 : if (!(flags & LIBNDR_FLAG_REMAINING))
523 : {
524 117 : NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
525 : }
526 123 : break;
527 :
528 24962 : case LIBNDR_FLAG_STR_NOTERM:
529 24962 : if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
530 0 : return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
531 : ndr->flags & LIBNDR_STRING_FLAGS);
532 : }
533 :
534 98965 : for (count = 0; a && a[count]; count++) {
535 74003 : if (count > 0) {
536 49041 : ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
537 49041 : ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
538 49041 : NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
539 49041 : ndr->flags = saved_flags;
540 : }
541 74003 : NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
542 : }
543 :
544 24962 : break;
545 :
546 0 : default:
547 0 : return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
548 : ndr->flags & LIBNDR_STRING_FLAGS);
549 : }
550 :
551 25085 : ndr->flags = saved_flags;
552 25085 : return NDR_ERR_SUCCESS;
553 : }
554 :
555 0 : _PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a)
556 : {
557 : uint32_t count;
558 : uint32_t i;
559 :
560 0 : for (count = 0; a && a[count]; count++) {}
561 :
562 0 : ndr->print(ndr, "%s: ARRAY(%d)", name, count);
563 0 : ndr->depth++;
564 0 : for (i=0;i<count;i++) {
565 0 : char *idx=NULL;
566 0 : if (asprintf(&idx, "[%d]", i) != -1) {
567 0 : ndr_print_string(ndr, idx, a[i]);
568 0 : free(idx);
569 : }
570 : }
571 0 : ndr->depth--;
572 0 : }
573 :
574 0 : _PUBLIC_ size_t ndr_size_string_array(const char **a, uint32_t count, int flags)
575 : {
576 : uint32_t i;
577 0 : size_t size = 0;
578 0 : int rawbytes = 0;
579 :
580 0 : if (flags & LIBNDR_FLAG_STR_RAW8) {
581 0 : rawbytes = 1;
582 0 : flags &= ~LIBNDR_FLAG_STR_RAW8;
583 : }
584 :
585 0 : switch (flags & LIBNDR_STRING_FLAGS) {
586 0 : case LIBNDR_FLAG_STR_NULLTERM:
587 0 : for (i = 0; i < count; i++) {
588 0 : size += rawbytes?strlen(a[i]) + 1:strlen_m_term(a[i]);
589 : }
590 0 : break;
591 0 : case LIBNDR_FLAG_STR_NOTERM:
592 0 : for (i = 0; i < count; i++) {
593 0 : size += rawbytes?strlen(a[i]):strlen_m(a[i]);
594 : }
595 0 : break;
596 0 : default:
597 0 : return 0;
598 : }
599 :
600 0 : return size;
601 : }
602 :
603 : /**
604 : * Return number of elements in a string including the last (zeroed) element
605 : */
606 0 : _PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size)
607 : {
608 : uint32_t i;
609 0 : uint8_t zero[4] = {0,0,0,0};
610 0 : const char *var = (const char *)_var;
611 :
612 0 : for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++);
613 :
614 0 : return i+1;
615 : }
616 :
617 : /**
618 : * @brief Get the string length including the null terminator if available.
619 : *
620 : * This checks the string length based on the elements. The returned number
621 : * includes the terminating null byte(s) if found.
622 : *
623 : * @param[in] _var The string the calculate the length for.
624 : *
625 : * @param[in] length The length of the buffer passed by _var.
626 : *
627 : * @param[in] element_size The element_size of a string char in bytes.
628 : *
629 : * @return The length of the strings or 0.
630 : */
631 0 : static uint32_t ndr_string_n_length(const void *_var,
632 : size_t length,
633 : uint32_t element_size)
634 : {
635 0 : size_t i = 0;
636 0 : uint8_t zero[4] = {0,0,0,0};
637 0 : const char *var = (const char *)_var;
638 : int cmp;
639 :
640 0 : if (element_size > 4) {
641 0 : return 0;
642 : }
643 :
644 0 : for (i = 0; i < length; i++, var += element_size) {
645 0 : cmp = memcmp(var, zero, element_size);
646 0 : if (cmp == 0) {
647 0 : break;
648 : }
649 : }
650 :
651 0 : if (i == length) {
652 0 : return length;
653 : }
654 :
655 0 : return i + 1;
656 : }
657 :
658 4794280 : _PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size)
659 : {
660 : uint32_t i;
661 : uint32_t save_offset;
662 :
663 4794280 : save_offset = ndr->offset;
664 4794280 : NDR_CHECK(ndr_pull_advance(ndr, (count - 1) * element_size));
665 4794280 : NDR_PULL_NEED_BYTES(ndr, element_size);
666 :
667 11539487 : for (i = 0; i < element_size; i++) {
668 6745207 : if (ndr->data[ndr->offset+i] != 0) {
669 0 : ndr->offset = save_offset;
670 :
671 0 : return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries");
672 : }
673 : }
674 :
675 4794280 : ndr->offset = save_offset;
676 :
677 4794280 : return NDR_ERR_SUCCESS;
678 : }
679 :
680 9380225 : _PUBLIC_ enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset)
681 : {
682 : size_t converted_size;
683 :
684 9380225 : if (length == 0) {
685 588679 : *var = talloc_strdup(ndr->current_mem_ctx, "");
686 588679 : return NDR_ERR_SUCCESS;
687 : }
688 :
689 8791546 : if (NDR_BE(ndr) && chset == CH_UTF16) {
690 503060 : chset = CH_UTF16BE;
691 : }
692 :
693 8791546 : if ((byte_mul != 0) && (length > UINT32_MAX/byte_mul)) {
694 0 : return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "length overflow");
695 : }
696 8791546 : NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
697 :
698 17118812 : if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
699 17118812 : ndr->data+ndr->offset, length*byte_mul,
700 : discard_const_p(void *, var),
701 : &converted_size))
702 : {
703 0 : return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
704 : "Bad character conversion");
705 : }
706 8791546 : NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
707 :
708 8791546 : return NDR_ERR_SUCCESS;
709 : }
710 :
711 0 : _PUBLIC_ enum ndr_err_code ndr_pull_charset_to_null(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset)
712 : {
713 : size_t converted_size;
714 : uint32_t str_len;
715 :
716 0 : if (length == 0) {
717 0 : *var = talloc_strdup(ndr->current_mem_ctx, "");
718 0 : return NDR_ERR_SUCCESS;
719 : }
720 :
721 0 : if (NDR_BE(ndr) && chset == CH_UTF16) {
722 0 : chset = CH_UTF16BE;
723 : }
724 :
725 0 : NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
726 :
727 0 : str_len = ndr_string_n_length(ndr->data+ndr->offset, length, byte_mul);
728 0 : if (str_len == 0) {
729 0 : return ndr_pull_error(ndr, NDR_ERR_LENGTH,
730 : "Invalid length");
731 : }
732 :
733 0 : if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
734 0 : ndr->data+ndr->offset, str_len*byte_mul,
735 : discard_const_p(void *, var),
736 : &converted_size))
737 : {
738 0 : return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
739 : "Bad character conversion");
740 : }
741 0 : NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
742 :
743 0 : return NDR_ERR_SUCCESS;
744 : }
745 :
746 17270776 : _PUBLIC_ enum ndr_err_code ndr_push_charset(struct ndr_push *ndr, int ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset)
747 : {
748 : size_t required;
749 :
750 17270776 : if (NDR_BE(ndr) && chset == CH_UTF16) {
751 23785 : chset = CH_UTF16BE;
752 : }
753 :
754 17270776 : if ((byte_mul != 0) && (length > SIZE_MAX/byte_mul)) {
755 0 : return ndr_push_error(ndr, NDR_ERR_LENGTH, "length overflow");
756 : }
757 17270776 : required = byte_mul * length;
758 :
759 17270776 : NDR_PUSH_NEED_BYTES(ndr, required);
760 :
761 17270776 : if (required) {
762 16678032 : size_t size = 0;
763 :
764 16678032 : if (var == NULL) {
765 0 : return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
766 : }
767 :
768 16678032 : if (!convert_string(CH_UNIX, chset,
769 : var, strlen(var),
770 16678032 : ndr->data+ndr->offset, required, &size)) {
771 0 : return ndr_push_error(ndr, NDR_ERR_CHARCNV,
772 : "Bad character conversion");
773 : }
774 :
775 : /* Make sure the remaining part of the string is filled with zeroes */
776 16678032 : if (size < required) {
777 15086649 : memset(ndr->data+ndr->offset+size, 0, required-size);
778 : }
779 : }
780 :
781 17270776 : ndr->offset += required;
782 :
783 17270776 : return NDR_ERR_SUCCESS;
784 : }
785 :
786 0 : _PUBLIC_ enum ndr_err_code ndr_push_charset_to_null(struct ndr_push *ndr, int ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset)
787 : {
788 0 : const char *str = var;
789 :
790 0 : if (str == NULL) {
791 0 : str = "\0"; /* i.e. two zero bytes, for UTF16 null word. */
792 0 : length = 1;
793 : }
794 :
795 0 : return ndr_push_charset(ndr, ndr_flags, str, length, byte_mul, chset);
796 : }
797 :
798 : /* Return number of elements in a string in the specified charset */
799 9058323 : _PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset)
800 : {
801 9058323 : switch (chset) {
802 : /* case CH_UTF16: this has the same value as CH_UTF16LE */
803 8987130 : case CH_UTF16LE:
804 : case CH_UTF16BE:
805 : case CH_UTF16MUNGED:
806 : case CH_UTF8:
807 8987130 : return strlen_m_ext_term((const char *)var, CH_UNIX, chset);
808 71193 : case CH_DOS:
809 : case CH_UNIX:
810 71193 : return strlen((const char *)var)+1;
811 : }
812 :
813 : /* Fallback, this should never happen */
814 0 : return strlen((const char *)var)+1;
815 : }
|