/src/samba/librpc/ndr/ndr_string.c
Line | Count | Source (jump to first uncovered line) |
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 | | _PUBLIC_ enum ndr_err_code ndr_pull_string(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **s) |
29 | 20.3M | { |
30 | 20.3M | char *as=NULL; |
31 | 20.3M | uint32_t len1, ofs, len2; |
32 | 20.3M | uint16_t len3; |
33 | 20.3M | size_t conv_src_len = 0, converted_size; |
34 | 20.3M | int do_convert = 1, chset = CH_UTF16; |
35 | 20.3M | unsigned byte_mul = 2; |
36 | 20.3M | libndr_flags flags = ndr->flags; |
37 | 20.3M | unsigned c_len_term = 0; |
38 | | |
39 | 20.3M | if (!(ndr_flags & NDR_SCALARS)) { |
40 | 0 | return NDR_ERR_SUCCESS; |
41 | 0 | } |
42 | | |
43 | 20.3M | if (NDR_BE(ndr)) { |
44 | 3.47M | chset = CH_UTF16BE; |
45 | 3.47M | } |
46 | | |
47 | | /* |
48 | | * We will check this flag, but from the unmodified |
49 | | * ndr->flags, so just remove it from flags |
50 | | */ |
51 | 20.3M | flags &= ~LIBNDR_FLAG_STR_NO_EMBEDDED_NUL; |
52 | | |
53 | 20.3M | switch (flags & LIBNDR_ENCODING_FLAGS) { |
54 | 9.13M | case 0: |
55 | 9.13M | break; |
56 | | |
57 | 844k | case LIBNDR_FLAG_STR_ASCII: |
58 | 844k | chset = CH_DOS; |
59 | 844k | byte_mul = 1; |
60 | 844k | break; |
61 | | |
62 | 10.3M | case LIBNDR_FLAG_STR_UTF8: |
63 | 10.3M | chset = CH_UTF8; |
64 | 10.3M | byte_mul = 1; |
65 | 10.3M | break; |
66 | | |
67 | 0 | case LIBNDR_FLAG_STR_RAW8: |
68 | 0 | do_convert = 0; |
69 | 0 | byte_mul = 1; |
70 | 0 | break; |
71 | | |
72 | 0 | default: |
73 | 0 | return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n", |
74 | 20.3M | ndr->flags & LIBNDR_STRING_FLAGS); |
75 | 20.3M | } |
76 | 20.3M | flags &= ~LIBNDR_ENCODING_FLAGS; |
77 | | |
78 | 20.3M | flags &= ~LIBNDR_FLAG_STR_CONFORMANT; |
79 | 20.3M | if (flags & LIBNDR_FLAG_STR_CHARLEN) { |
80 | 1.31M | c_len_term = 1; |
81 | 1.31M | flags &= ~LIBNDR_FLAG_STR_CHARLEN; |
82 | 1.31M | } |
83 | | |
84 | 20.3M | switch (flags & LIBNDR_STRING_FLAGS) { |
85 | 0 | case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4: |
86 | 0 | case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: |
87 | 0 | NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); |
88 | 0 | NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs)); |
89 | 0 | if (ofs != 0) { |
90 | 0 | return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%"PRI_LIBNDR_FLAGS"\n", |
91 | 0 | ndr->flags & LIBNDR_STRING_FLAGS); |
92 | 0 | } |
93 | 0 | NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2)); |
94 | 0 | if (len2 > len1) { |
95 | 0 | return ndr_pull_error(ndr, NDR_ERR_STRING, |
96 | 0 | "Bad string lengths len1=%"PRIu32" ofs=%"PRIu32" len2=%"PRIu32"\n", |
97 | 0 | len1, ofs, len2); |
98 | 0 | } else if (len1 != len2) { |
99 | 0 | DEBUG(6,("len1[%"PRIu32"] != len2[%"PRIu32"]\n", len1, len2)); |
100 | 0 | } |
101 | 0 | conv_src_len = len2 + c_len_term; |
102 | 0 | break; |
103 | | |
104 | 0 | case LIBNDR_FLAG_STR_SIZE4: |
105 | 742k | case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: |
106 | 742k | NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); |
107 | 742k | conv_src_len = len1 + c_len_term; |
108 | 742k | break; |
109 | | |
110 | 158k | case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE: |
111 | 158k | NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); |
112 | 158k | conv_src_len = len1; |
113 | 158k | byte_mul = 1; /* the length is now absolute */ |
114 | 158k | break; |
115 | | |
116 | 0 | case LIBNDR_FLAG_STR_LEN4: |
117 | 0 | case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM: |
118 | 0 | NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs)); |
119 | 0 | if (ofs != 0) { |
120 | 0 | return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%"PRI_LIBNDR_FLAGS"\n", |
121 | 0 | ndr->flags & LIBNDR_STRING_FLAGS); |
122 | 0 | } |
123 | 0 | NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); |
124 | 0 | conv_src_len = len1 + c_len_term; |
125 | 0 | break; |
126 | | |
127 | 0 | case LIBNDR_FLAG_STR_SIZE2: |
128 | 1.00M | case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM: |
129 | 1.00M | NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); |
130 | 1.00M | conv_src_len = len3 + c_len_term; |
131 | 1.00M | break; |
132 | | |
133 | 0 | case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE: |
134 | 0 | NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); |
135 | 0 | conv_src_len = len3; |
136 | 0 | byte_mul = 1; /* the length is now absolute */ |
137 | 0 | break; |
138 | | |
139 | 17.1M | case LIBNDR_FLAG_STR_NULLTERM: |
140 | | /* |
141 | | * We ensure that conv_src_len cannot equal 0 by |
142 | | * requiring that there be enough bytes for at least |
143 | | * the NULL terminator |
144 | | */ |
145 | 17.1M | if (byte_mul == 1) { |
146 | 9.44M | NDR_PULL_NEED_BYTES(ndr, 1); |
147 | 9.44M | conv_src_len = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset); |
148 | 9.44M | } else { |
149 | 7.65M | NDR_PULL_NEED_BYTES(ndr, 2); |
150 | 7.65M | conv_src_len = utf16_null_terminated_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset); |
151 | 7.65M | } |
152 | 17.0M | byte_mul = 1; /* the length is now absolute */ |
153 | 17.0M | break; |
154 | | |
155 | 1.32M | case LIBNDR_FLAG_STR_NOTERM: |
156 | 1.32M | if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { |
157 | 0 | return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS" (missing NDR_REMAINING)\n", |
158 | 0 | ndr->flags & LIBNDR_STRING_FLAGS); |
159 | 0 | } |
160 | 1.32M | conv_src_len = ndr->data_size - ndr->offset; |
161 | 1.32M | byte_mul = 1; /* the length is now absolute */ |
162 | 1.32M | break; |
163 | | |
164 | 0 | default: |
165 | 0 | return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n", |
166 | 20.3M | ndr->flags & LIBNDR_STRING_FLAGS); |
167 | 20.3M | } |
168 | | |
169 | 20.3M | NDR_PULL_NEED_BYTES(ndr, conv_src_len * byte_mul); |
170 | 20.3M | if (conv_src_len == 0) { |
171 | 3.10M | as = talloc_strdup(ndr->current_mem_ctx, ""); |
172 | 3.10M | converted_size = 0; |
173 | 3.10M | if (!as) { |
174 | 0 | return ndr_pull_error(ndr, NDR_ERR_ALLOC, |
175 | 0 | "Failed to talloc_strndup() in zero-length ndr_pull_string()"); |
176 | 0 | } |
177 | 17.2M | } else { |
178 | 17.2M | if (!do_convert) { |
179 | 0 | as = talloc_strndup(ndr->current_mem_ctx, |
180 | 0 | (char *)ndr->data + ndr->offset, |
181 | 0 | conv_src_len); |
182 | 0 | if (!as) { |
183 | 0 | return ndr_pull_error(ndr, NDR_ERR_ALLOC, |
184 | 0 | "Failed to talloc_strndup() in RAW8 ndr_pull_string()"); |
185 | 0 | } |
186 | 0 | converted_size = MIN(strlen(as)+1, conv_src_len); |
187 | 17.2M | } else if (!convert_string_talloc(ndr->current_mem_ctx, chset, |
188 | 17.2M | CH_UNIX, ndr->data + ndr->offset, |
189 | 17.2M | conv_src_len * byte_mul, |
190 | 17.2M | &as, |
191 | 17.2M | &converted_size)) { |
192 | 3.50k | return ndr_pull_error(ndr, NDR_ERR_CHARCNV, |
193 | 3.50k | "Bad character conversion with flags 0x%"PRI_LIBNDR_FLAGS, flags); |
194 | 3.50k | } |
195 | 17.2M | } |
196 | | |
197 | | /* this is a way of detecting if a string is sent with the wrong |
198 | | termination */ |
199 | 20.3M | if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { |
200 | 3.23M | if (converted_size > 0 && as[converted_size-1] == '\0') { |
201 | 4.76k | DEBUG(6,("short string '%s', sent with NULL termination despite NOTERM flag in IDL\n", as)); |
202 | 4.76k | } |
203 | | /* |
204 | | * We check the original ndr->flags as it has already |
205 | | * been removed from the local variable flags |
206 | | */ |
207 | 3.23M | if (ndr->flags & LIBNDR_FLAG_STR_NO_EMBEDDED_NUL) { |
208 | 157k | size_t strlen_of_unix_string = strlen(as); |
209 | 157k | if (strlen_of_unix_string != converted_size) { |
210 | 164 | return ndr_pull_error(ndr, NDR_ERR_CHARCNV, |
211 | 164 | "Embedded NUL at position %zu in " |
212 | 164 | "converted string " |
213 | 164 | "(and therefore source string) " |
214 | 164 | "despite " |
215 | 164 | "LIBNDR_FLAG_STR_NO_EMBEDDED_NUL\n", |
216 | 164 | strlen_of_unix_string); |
217 | 164 | } |
218 | 157k | } |
219 | 17.0M | } else { |
220 | | /* |
221 | | * We check the original ndr->flags as it has already |
222 | | * been removed from the local variable flags |
223 | | */ |
224 | 17.0M | if (ndr->flags & LIBNDR_FLAG_STR_NO_EMBEDDED_NUL) { |
225 | 0 | size_t strlen_of_unix_string = strlen(as); |
226 | 0 | if (converted_size > 0 && strlen_of_unix_string != converted_size - 1) { |
227 | 0 | return ndr_pull_error(ndr, NDR_ERR_CHARCNV, |
228 | 0 | "Embedded NUL at position %zu in " |
229 | 0 | "converted string " |
230 | 0 | "(and therefore source string) " |
231 | 0 | "despite " |
232 | 0 | "LIBNDR_FLAG_STR_NO_EMBEDDED_NUL\n", |
233 | 0 | strlen_of_unix_string); |
234 | 0 | } |
235 | 0 | } |
236 | 17.0M | if (converted_size > 0 && as[converted_size-1] != '\0') { |
237 | 97.9k | DEBUG(6,("long string '%s', sent without NULL termination (which was expected)\n", as)); |
238 | 97.9k | } |
239 | 17.0M | } |
240 | | |
241 | 20.3M | NDR_CHECK(ndr_pull_advance(ndr, conv_src_len * byte_mul)); |
242 | 20.3M | *s = as; |
243 | | |
244 | 20.3M | return NDR_ERR_SUCCESS; |
245 | 20.3M | } |
246 | | |
247 | | |
248 | | /** |
249 | | push a general string onto the wire |
250 | | */ |
251 | | _PUBLIC_ enum ndr_err_code ndr_push_string(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *s) |
252 | 12.5M | { |
253 | 12.5M | ssize_t s_len, c_len; |
254 | 12.5M | size_t d_len; |
255 | 12.5M | int do_convert = 1, chset = CH_UTF16; |
256 | 12.5M | libndr_flags flags = ndr->flags; |
257 | 12.5M | unsigned byte_mul = 2; |
258 | 12.5M | const uint8_t *dest = NULL; |
259 | 12.5M | uint8_t *dest_to_free = NULL; |
260 | 12.5M | static const uint8_t null_byte[] = {0}; |
261 | 12.5M | enum ndr_err_code ndr_err = NDR_ERR_SUCCESS; |
262 | | |
263 | 12.5M | if (!(ndr_flags & NDR_SCALARS)) { |
264 | 0 | return NDR_ERR_SUCCESS; |
265 | 0 | } |
266 | | |
267 | 12.5M | if (NDR_BE(ndr)) { |
268 | 1.98M | chset = CH_UTF16BE; |
269 | 1.98M | } |
270 | | |
271 | 12.5M | s_len = s?strlen(s):0; |
272 | | |
273 | | /* |
274 | | * We will check this flag, but from the unmodified |
275 | | * ndr->flags, so just remove it from flags |
276 | | */ |
277 | 12.5M | flags &= ~LIBNDR_FLAG_STR_NO_EMBEDDED_NUL; |
278 | | |
279 | 12.5M | switch (flags & LIBNDR_ENCODING_FLAGS) { |
280 | 10.2M | case 0: |
281 | 10.2M | break; |
282 | | |
283 | 243k | case LIBNDR_FLAG_STR_ASCII: |
284 | 243k | chset = CH_DOS; |
285 | 243k | byte_mul = 1; |
286 | 243k | break; |
287 | | |
288 | 2.10M | case LIBNDR_FLAG_STR_UTF8: |
289 | 2.10M | chset = CH_UTF8; |
290 | 2.10M | byte_mul = 1; |
291 | 2.10M | break; |
292 | | |
293 | 0 | case LIBNDR_FLAG_STR_RAW8: |
294 | 0 | do_convert = 0; |
295 | 0 | byte_mul = 1; |
296 | 0 | break; |
297 | | |
298 | 0 | default: |
299 | 0 | return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n", |
300 | 12.5M | ndr->flags & LIBNDR_STRING_FLAGS); |
301 | 12.5M | } |
302 | 12.5M | flags &= ~LIBNDR_ENCODING_FLAGS; |
303 | | |
304 | 12.5M | flags &= ~LIBNDR_FLAG_STR_CONFORMANT; |
305 | | |
306 | 12.5M | if (!(flags & LIBNDR_FLAG_STR_NOTERM)) { |
307 | 6.56M | s_len++; |
308 | 6.56M | } |
309 | | |
310 | 12.5M | if (s_len == 0) { |
311 | 5.61M | d_len = 0; |
312 | 5.61M | dest = null_byte; |
313 | 6.95M | } else if (!do_convert) { |
314 | 0 | d_len = s_len; |
315 | 0 | dest = (const uint8_t *)s; |
316 | 6.95M | } else { |
317 | 6.95M | bool ok; |
318 | | |
319 | 6.95M | ok = convert_string_talloc(ndr, CH_UNIX, chset, s, s_len, |
320 | 6.95M | &dest_to_free, &d_len); |
321 | 6.95M | if (!ok) { |
322 | 0 | return ndr_push_error(ndr, NDR_ERR_CHARCNV, |
323 | 0 | "Bad character push conversion with flags 0x%"PRI_LIBNDR_FLAGS, flags); |
324 | 0 | } |
325 | | |
326 | 6.95M | dest = dest_to_free; |
327 | 6.95M | } |
328 | | |
329 | 12.5M | if (flags & LIBNDR_FLAG_STR_BYTESIZE) { |
330 | 356k | c_len = d_len; |
331 | 356k | flags &= ~LIBNDR_FLAG_STR_BYTESIZE; |
332 | 12.2M | } else if (flags & LIBNDR_FLAG_STR_CHARLEN) { |
333 | 3.99M | c_len = (d_len / byte_mul)-1; |
334 | 3.99M | flags &= ~LIBNDR_FLAG_STR_CHARLEN; |
335 | 8.21M | } else { |
336 | 8.21M | c_len = d_len / byte_mul; |
337 | 8.21M | } |
338 | | |
339 | 12.5M | switch (flags & LIBNDR_STRING_FLAGS) { |
340 | 0 | case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4: |
341 | 0 | case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: |
342 | 0 | ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len); |
343 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
344 | 0 | goto out; |
345 | 0 | } |
346 | 0 | ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, 0); |
347 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
348 | 0 | goto out; |
349 | 0 | } |
350 | 0 | ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len); |
351 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
352 | 0 | goto out; |
353 | 0 | } |
354 | 0 | ndr_err = ndr_push_bytes(ndr, dest, d_len); |
355 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
356 | 0 | goto out; |
357 | 0 | } |
358 | 0 | break; |
359 | | |
360 | 0 | case LIBNDR_FLAG_STR_LEN4: |
361 | 0 | case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM: |
362 | 0 | ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, 0); |
363 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
364 | 0 | goto out; |
365 | 0 | } |
366 | 0 | ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len); |
367 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
368 | 0 | goto out; |
369 | 0 | } |
370 | 0 | ndr_err = ndr_push_bytes(ndr, dest, d_len); |
371 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
372 | 0 | goto out; |
373 | 0 | } |
374 | 0 | break; |
375 | | |
376 | 0 | case LIBNDR_FLAG_STR_SIZE4: |
377 | 570k | case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: |
378 | 570k | ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len); |
379 | 570k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
380 | 0 | goto out; |
381 | 0 | } |
382 | 570k | ndr_err = ndr_push_bytes(ndr, dest, d_len); |
383 | 570k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
384 | 0 | goto out; |
385 | 0 | } |
386 | 570k | break; |
387 | | |
388 | 570k | case LIBNDR_FLAG_STR_SIZE2: |
389 | 924k | case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM: |
390 | 924k | ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, c_len); |
391 | 924k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
392 | 0 | goto out; |
393 | 0 | } |
394 | 924k | ndr_err = ndr_push_bytes(ndr, dest, d_len); |
395 | 924k | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
396 | 0 | goto out; |
397 | 0 | } |
398 | 924k | break; |
399 | | |
400 | 6.56M | case LIBNDR_FLAG_STR_NULLTERM: |
401 | 6.56M | ndr_err = ndr_push_bytes(ndr, dest, d_len); |
402 | 6.56M | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
403 | 0 | goto out; |
404 | 0 | } |
405 | 6.56M | break; |
406 | | |
407 | 6.56M | default: |
408 | 4.51M | if (ndr->flags & LIBNDR_FLAG_REMAINING) { |
409 | 4.51M | ndr_err = ndr_push_bytes(ndr, dest, d_len); |
410 | 4.51M | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
411 | 0 | goto out; |
412 | 0 | } |
413 | 4.51M | break; |
414 | 4.51M | } |
415 | | |
416 | 0 | ndr_err = ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n", |
417 | 0 | ndr->flags & LIBNDR_STRING_FLAGS); |
418 | 0 | goto out; |
419 | 12.5M | } |
420 | | |
421 | 12.5M | out: |
422 | 12.5M | TALLOC_FREE(dest_to_free); |
423 | 12.5M | return ndr_err; |
424 | 12.5M | } |
425 | | |
426 | | /** |
427 | | push a general string onto the wire |
428 | | */ |
429 | | _PUBLIC_ size_t ndr_string_array_size(struct ndr_push *ndr, const char *s) |
430 | 0 | { |
431 | 0 | size_t c_len; |
432 | 0 | libndr_flags flags = ndr->flags; |
433 | 0 | unsigned byte_mul = 2; |
434 | 0 | unsigned c_len_term = 1; |
435 | |
|
436 | 0 | if (flags & LIBNDR_FLAG_STR_RAW8) { |
437 | 0 | c_len = s?strlen(s):0; |
438 | 0 | } else { |
439 | 0 | c_len = s?strlen_m(s):0; |
440 | 0 | } |
441 | |
|
442 | 0 | if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_RAW8|LIBNDR_FLAG_STR_UTF8)) { |
443 | 0 | byte_mul = 1; |
444 | 0 | } |
445 | |
|
446 | 0 | if (flags & LIBNDR_FLAG_STR_NOTERM) { |
447 | 0 | c_len_term = 0; |
448 | 0 | } |
449 | |
|
450 | 0 | c_len = c_len + c_len_term; |
451 | |
|
452 | 0 | if (flags & LIBNDR_FLAG_STR_BYTESIZE) { |
453 | 0 | c_len = c_len * byte_mul; |
454 | 0 | } |
455 | |
|
456 | 0 | return c_len; |
457 | 0 | } |
458 | | |
459 | | _PUBLIC_ void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s) |
460 | 18.3M | { |
461 | 18.3M | if (NDR_HIDE_SECRET(ndr)) { |
462 | 42 | ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name); |
463 | 42 | return; |
464 | 42 | } |
465 | 18.3M | if (s) { |
466 | 17.6M | ndr->print(ndr, "%-25s: '%s'", name, s); |
467 | 17.6M | } else { |
468 | 710k | ndr->print(ndr, "%-25s: NULL", name); |
469 | 710k | } |
470 | 18.3M | } |
471 | | |
472 | | _PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, ndr_flags_type flags) |
473 | 0 | { |
474 | | /* FIXME: Is this correct for all strings ? */ |
475 | 0 | if(!(*string)) return ret; |
476 | 0 | return ret+strlen(*string)+1; |
477 | 0 | } |
478 | | |
479 | | /** |
480 | | pull a UTF‐16 string from the wire |
481 | | */ |
482 | | _PUBLIC_ enum ndr_err_code ndr_pull_u16string(struct ndr_pull *ndr, |
483 | | ndr_flags_type ndr_flags, |
484 | | const unsigned char **s) |
485 | 805 | { |
486 | 805 | unsigned char *as = NULL; |
487 | 805 | const char *const src_str = (char *)ndr->data + ndr->offset; |
488 | 805 | size_t src_len = 0; |
489 | | |
490 | 805 | if (!(ndr_flags & NDR_SCALARS)) { |
491 | 0 | return NDR_ERR_SUCCESS; |
492 | 0 | } |
493 | | |
494 | 805 | if (NDR_BE(ndr)) { |
495 | | /* |
496 | | * It isn’t clear how this type should be encoded in a |
497 | | * big‐endian context. |
498 | | */ |
499 | 0 | return ndr_pull_error( |
500 | 0 | ndr, |
501 | 0 | NDR_ERR_STRING, |
502 | 0 | "u16string does not support big‐endian encoding\n"); |
503 | 0 | } |
504 | | |
505 | 805 | if (ndr->flags & LIBNDR_ENCODING_FLAGS) { |
506 | 0 | return ndr_pull_error( |
507 | 0 | ndr, |
508 | 0 | NDR_ERR_STRING, |
509 | 0 | "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS |
510 | 0 | " passed to ndr_pull_u16string()\n", |
511 | 0 | ndr->flags & LIBNDR_STRING_FLAGS); |
512 | 0 | } |
513 | | |
514 | 805 | switch (ndr->flags & LIBNDR_STRING_FLAGS) { |
515 | 805 | case LIBNDR_FLAG_STR_NULLTERM: |
516 | | /* |
517 | | * We ensure that src_len cannot equal 0 by |
518 | | * requiring that there be enough bytes for at least |
519 | | * the NULL terminator |
520 | | */ |
521 | 805 | NDR_PULL_NEED_BYTES(ndr, 2); |
522 | 793 | src_len = utf16_null_terminated_len_n(src_str, |
523 | 793 | ndr->data_size - |
524 | 793 | ndr->offset); |
525 | 793 | break; |
526 | | |
527 | 0 | default: |
528 | 0 | return ndr_pull_error( |
529 | 805 | ndr, |
530 | 805 | NDR_ERR_STRING, |
531 | 805 | "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS |
532 | 805 | " passed to ndr_pull_u16string()\n", |
533 | 805 | ndr->flags & LIBNDR_STRING_FLAGS); |
534 | 805 | } |
535 | | |
536 | 793 | NDR_PULL_NEED_BYTES(ndr, src_len); |
537 | 793 | as = talloc_utf16_strlendup(ndr->current_mem_ctx, |
538 | 793 | src_str, |
539 | 793 | src_len); |
540 | 793 | if (as == NULL) { |
541 | 0 | return ndr_pull_error(ndr, |
542 | 0 | NDR_ERR_ALLOC, |
543 | 0 | "Failed to talloc_utf16_strlendup() in " |
544 | 0 | "ndr_pull_u16string()"); |
545 | 0 | } |
546 | | |
547 | 793 | NDR_CHECK(ndr_pull_advance(ndr, src_len)); |
548 | 793 | *s = as; |
549 | | |
550 | 793 | return NDR_ERR_SUCCESS; |
551 | 793 | } |
552 | | |
553 | | /** |
554 | | push a UTF‐16 string onto the wire |
555 | | */ |
556 | | _PUBLIC_ enum ndr_err_code ndr_push_u16string(struct ndr_push *ndr, |
557 | | ndr_flags_type ndr_flags, |
558 | | const unsigned char *s) |
559 | 1.39k | { |
560 | 1.39k | size_t s_len; |
561 | | |
562 | 1.39k | if (!(ndr_flags & NDR_SCALARS)) { |
563 | 0 | return NDR_ERR_SUCCESS; |
564 | 0 | } |
565 | | |
566 | 1.39k | if (NDR_BE(ndr)) { |
567 | | /* |
568 | | * It isn’t clear how this type should be encoded in a |
569 | | * big‐endian context. |
570 | | */ |
571 | 0 | return ndr_push_error( |
572 | 0 | ndr, |
573 | 0 | NDR_ERR_STRING, |
574 | 0 | "u16string does not support big‐endian encoding\n"); |
575 | 0 | } |
576 | | |
577 | 1.39k | if (s == NULL) { |
578 | 0 | return ndr_push_error( |
579 | 0 | ndr, |
580 | 0 | NDR_ERR_INVALID_POINTER, |
581 | 0 | "NULL pointer passed to ndr_push_u16string()"); |
582 | 0 | } |
583 | | |
584 | 1.39k | s_len = utf16_null_terminated_len(s); |
585 | 1.39k | if (s_len > UINT32_MAX) { |
586 | 0 | return ndr_push_error( |
587 | 0 | ndr, |
588 | 0 | NDR_ERR_LENGTH, |
589 | 0 | "length overflow in ndr_push_u16string()"); |
590 | 0 | } |
591 | | |
592 | 1.39k | if (ndr->flags & LIBNDR_ENCODING_FLAGS) { |
593 | 0 | return ndr_push_error( |
594 | 0 | ndr, |
595 | 0 | NDR_ERR_STRING, |
596 | 0 | "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS |
597 | 0 | " passed to ndr_push_u16string()\n", |
598 | 0 | ndr->flags & LIBNDR_STRING_FLAGS); |
599 | 0 | } |
600 | | |
601 | 1.39k | switch (ndr->flags & LIBNDR_STRING_FLAGS) { |
602 | 1.39k | case LIBNDR_FLAG_STR_NULLTERM: |
603 | 1.39k | NDR_CHECK(ndr_push_bytes(ndr, s, s_len)); |
604 | 1.39k | break; |
605 | | |
606 | 1.39k | default: |
607 | 0 | if (ndr->flags & LIBNDR_FLAG_REMAINING) { |
608 | 0 | NDR_CHECK(ndr_push_bytes(ndr, s, s_len)); |
609 | 0 | break; |
610 | 0 | } |
611 | | |
612 | 0 | return ndr_push_error( |
613 | 1.39k | ndr, |
614 | 1.39k | NDR_ERR_STRING, |
615 | 1.39k | "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS |
616 | 1.39k | " passed to ndr_push_u16string()\n", |
617 | 1.39k | ndr->flags & LIBNDR_STRING_FLAGS); |
618 | 1.39k | } |
619 | | |
620 | 1.39k | return NDR_ERR_SUCCESS; |
621 | 1.39k | } |
622 | | |
623 | | _PUBLIC_ void ndr_print_u16string(struct ndr_print *ndr, |
624 | | const char *name, |
625 | | const unsigned char *s) |
626 | 737 | { |
627 | 737 | return ndr_print_array_uint8(ndr, |
628 | 737 | name, |
629 | 737 | s, |
630 | 737 | utf16_len(s)); |
631 | 737 | } |
632 | | |
633 | | static uint32_t guess_string_array_size(struct ndr_pull *ndr, ndr_flags_type ndr_flags) |
634 | 7.11k | { |
635 | | /* |
636 | | * Here we could do something clever like count the number of zeros in |
637 | | * the ndr data, but it is probably sufficient to pick a lowish number |
638 | | * (compared to the overhead of the talloc header) and let the |
639 | | * exponential resizing deal with longer arrays. |
640 | | */ |
641 | 7.11k | return 5; |
642 | 7.11k | } |
643 | | |
644 | | static enum ndr_err_code extend_string_array(struct ndr_pull *ndr, |
645 | | const char ***_a, |
646 | | uint32_t *count) |
647 | 29.2k | { |
648 | 29.2k | const char **a = *_a; |
649 | 29.2k | uint32_t inc = *count / 4 + 3; |
650 | 29.2k | uint32_t alloc_size = *count + inc; |
651 | | |
652 | 29.2k | if (alloc_size < *count) { |
653 | | /* overflow ! */ |
654 | 0 | return NDR_ERR_ALLOC; |
655 | 0 | } |
656 | | /* |
657 | | * We allocate and zero two more bytes than we report back, so that |
658 | | * the string array will always be NULL terminated. |
659 | | */ |
660 | 29.2k | a = talloc_realloc(ndr->current_mem_ctx, a, |
661 | 29.2k | const char *, |
662 | 29.2k | alloc_size); |
663 | 29.2k | NDR_ERR_HAVE_NO_MEMORY(a); |
664 | | |
665 | 29.2k | memset(a + *count, 0, inc * sizeof(a[0])); |
666 | 29.2k | *_a = a; |
667 | 29.2k | *count = alloc_size - 2; |
668 | 29.2k | return NDR_ERR_SUCCESS; |
669 | 29.2k | } |
670 | | |
671 | | /** |
672 | | pull a general string array from the wire |
673 | | */ |
674 | | _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char ***_a) |
675 | 7.11k | { |
676 | 7.11k | const char **a = NULL; |
677 | 7.11k | uint32_t count; |
678 | 7.11k | libndr_flags flags = ndr->flags; |
679 | 7.11k | libndr_flags saved_flags = ndr->flags; |
680 | 7.11k | uint32_t alloc_size; |
681 | | |
682 | 7.11k | if (!(ndr_flags & NDR_SCALARS)) { |
683 | 0 | return NDR_ERR_SUCCESS; |
684 | 0 | } |
685 | | |
686 | 7.11k | alloc_size = guess_string_array_size(ndr, ndr_flags); |
687 | 7.11k | a = talloc_zero_array(ndr->current_mem_ctx, const char *, alloc_size + 2); |
688 | 7.11k | NDR_ERR_HAVE_NO_MEMORY(a); |
689 | | |
690 | 7.11k | switch (flags & (LIBNDR_FLAG_STR_NULLTERM|LIBNDR_FLAG_STR_NOTERM)) { |
691 | 6.56k | case LIBNDR_FLAG_STR_NULLTERM: |
692 | | /* |
693 | | * here the strings are null terminated |
694 | | * but also the array is null terminated if LIBNDR_FLAG_REMAINING |
695 | | * is specified |
696 | | */ |
697 | 3.99M | for (count = 0;; count++) { |
698 | 3.99M | TALLOC_CTX *tmp_ctx; |
699 | 3.99M | const char *s = NULL; |
700 | 3.99M | if (count == alloc_size) { |
701 | 24.8k | NDR_CHECK(extend_string_array(ndr, |
702 | 24.8k | &a, |
703 | 24.8k | &alloc_size)); |
704 | 24.8k | } |
705 | | |
706 | 3.99M | tmp_ctx = ndr->current_mem_ctx; |
707 | 3.99M | ndr->current_mem_ctx = a; |
708 | 3.99M | NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s)); |
709 | 3.99M | ndr->current_mem_ctx = tmp_ctx; |
710 | 3.99M | if ((ndr->data_size - ndr->offset) == 0 && ndr->flags & LIBNDR_FLAG_REMAINING) |
711 | 1.42k | { |
712 | 1.42k | a[count] = s; |
713 | 1.42k | break; |
714 | 1.42k | } |
715 | 3.99M | if (strcmp("", s)==0) { |
716 | 4.87k | a[count] = NULL; |
717 | 4.87k | break; |
718 | 3.99M | } else { |
719 | 3.99M | a[count] = s; |
720 | 3.99M | } |
721 | 3.99M | } |
722 | | |
723 | 6.30k | *_a =a; |
724 | 6.30k | break; |
725 | | |
726 | 556 | case LIBNDR_FLAG_STR_NOTERM: |
727 | 556 | if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { |
728 | 0 | return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS" (missing NDR_REMAINING)\n", |
729 | 0 | ndr->flags & LIBNDR_STRING_FLAGS); |
730 | 0 | } |
731 | | /* |
732 | | * here the strings are not null terminated |
733 | | * but separated by a null terminator |
734 | | * |
735 | | * which means the same as: |
736 | | * Every string is null terminated except the last |
737 | | * string is terminated by the end of the buffer |
738 | | * |
739 | | * as LIBNDR_FLAG_STR_NULLTERM also end at the end |
740 | | * of the buffer, we can pull each string with this flag |
741 | | * |
742 | | * The big difference with the case LIBNDR_FLAG_STR_NOTERM + |
743 | | * LIBNDR_FLAG_REMAINING is that the last string will not be null terminated |
744 | | */ |
745 | 556 | ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING); |
746 | 556 | ndr->flags |= LIBNDR_FLAG_STR_NULLTERM; |
747 | | |
748 | 7.19M | for (count = 0; ((ndr->data_size - ndr->offset) > 0); count++) { |
749 | 7.19M | TALLOC_CTX *tmp_ctx; |
750 | 7.19M | const char *s = NULL; |
751 | 7.19M | if (count == alloc_size) { |
752 | 4.34k | NDR_CHECK(extend_string_array(ndr, |
753 | 4.34k | &a, |
754 | 4.34k | &alloc_size)); |
755 | 4.34k | } |
756 | | |
757 | 7.19M | tmp_ctx = ndr->current_mem_ctx; |
758 | 7.19M | ndr->current_mem_ctx = a; |
759 | 7.19M | NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s)); |
760 | 7.19M | ndr->current_mem_ctx = tmp_ctx; |
761 | 7.19M | a[count] = s; |
762 | 7.19M | } |
763 | | |
764 | 467 | a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 1); |
765 | 467 | NDR_ERR_HAVE_NO_MEMORY(a); |
766 | 467 | *_a = a; |
767 | 467 | break; |
768 | | |
769 | 0 | default: |
770 | 0 | return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n", |
771 | 7.11k | ndr->flags & LIBNDR_STRING_FLAGS); |
772 | 7.11k | } |
773 | | |
774 | 6.76k | ndr->flags = saved_flags; |
775 | 6.76k | return NDR_ERR_SUCCESS; |
776 | 7.11k | } |
777 | | |
778 | | /** |
779 | | push a general string array onto the wire |
780 | | */ |
781 | | _PUBLIC_ enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char **a) |
782 | 5.70k | { |
783 | 5.70k | uint32_t count; |
784 | 5.70k | libndr_flags flags = ndr->flags; |
785 | 5.70k | libndr_flags saved_flags = ndr->flags; |
786 | | |
787 | 5.70k | if (!(ndr_flags & NDR_SCALARS)) { |
788 | 0 | return NDR_ERR_SUCCESS; |
789 | 0 | } |
790 | | |
791 | 5.70k | switch (flags & LIBNDR_STRING_FLAGS) { |
792 | 5.23k | case LIBNDR_FLAG_STR_NULLTERM: |
793 | 2.30M | for (count = 0; a && a[count]; count++) { |
794 | 2.30M | NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count])); |
795 | 2.30M | } |
796 | | /* If LIBNDR_FLAG_REMAINING then we do not add a null terminator to the array */ |
797 | 5.23k | if (!(flags & LIBNDR_FLAG_REMAINING)) |
798 | 1.87k | { |
799 | 1.87k | NDR_CHECK(ndr_push_string(ndr, ndr_flags, "")); |
800 | 1.87k | } |
801 | 5.23k | break; |
802 | | |
803 | 5.23k | case LIBNDR_FLAG_STR_NOTERM: |
804 | 240 | if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { |
805 | 0 | return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS" (missing NDR_REMAINING)\n", |
806 | 0 | ndr->flags & LIBNDR_STRING_FLAGS); |
807 | 0 | } |
808 | | |
809 | 482k | for (count = 0; a && a[count]; count++) { |
810 | 481k | if (count > 0) { |
811 | 481k | ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING); |
812 | 481k | ndr->flags |= LIBNDR_FLAG_STR_NULLTERM; |
813 | 481k | NDR_CHECK(ndr_push_string(ndr, ndr_flags, "")); |
814 | 481k | ndr->flags = saved_flags; |
815 | 481k | } |
816 | 481k | NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count])); |
817 | 481k | } |
818 | | |
819 | 240 | break; |
820 | | |
821 | 240 | default: |
822 | 227 | return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n", |
823 | 5.70k | ndr->flags & LIBNDR_STRING_FLAGS); |
824 | 5.70k | } |
825 | | |
826 | 5.47k | ndr->flags = saved_flags; |
827 | 5.47k | return NDR_ERR_SUCCESS; |
828 | 5.70k | } |
829 | | |
830 | | _PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a) |
831 | 5.98k | { |
832 | 5.98k | uint32_t count; |
833 | 5.98k | uint32_t i; |
834 | | |
835 | 10.2M | for (count = 0; a && a[count]; count++) {} |
836 | | |
837 | 5.98k | ndr->print(ndr, "%s: ARRAY(%"PRIu32")", name, count); |
838 | 5.98k | ndr->depth++; |
839 | 10.2M | for (i=0;i<count;i++) { |
840 | 10.2M | char *idx=NULL; |
841 | 10.2M | if (asprintf(&idx, "[%"PRIu32"]", i) != -1) { |
842 | 10.2M | ndr_print_string(ndr, idx, a[i]); |
843 | 10.2M | free(idx); |
844 | 10.2M | } |
845 | 10.2M | } |
846 | 5.98k | ndr->depth--; |
847 | 5.98k | } |
848 | | |
849 | | _PUBLIC_ size_t ndr_size_string_array(const char **a, uint32_t count, libndr_flags flags) |
850 | 42.8k | { |
851 | 42.8k | uint32_t i; |
852 | 42.8k | size_t size = 0; |
853 | 42.8k | int rawbytes = 0; |
854 | | |
855 | 42.8k | if (flags & LIBNDR_FLAG_STR_RAW8) { |
856 | 0 | rawbytes = 1; |
857 | 0 | flags &= ~LIBNDR_FLAG_STR_RAW8; |
858 | 0 | } |
859 | | |
860 | 42.8k | switch (flags & LIBNDR_STRING_FLAGS) { |
861 | 42.8k | case LIBNDR_FLAG_STR_NULLTERM: |
862 | 501k | for (i = 0; i < count; i++) { |
863 | 458k | size += rawbytes?strlen(a[i]) + 1:strlen_m_term(a[i]); |
864 | 458k | } |
865 | 42.8k | break; |
866 | 0 | case LIBNDR_FLAG_STR_NOTERM: |
867 | 0 | for (i = 0; i < count; i++) { |
868 | 0 | size += rawbytes?strlen(a[i]):strlen_m(a[i]); |
869 | 0 | } |
870 | 0 | break; |
871 | 0 | default: |
872 | 0 | return 0; |
873 | 42.8k | } |
874 | | |
875 | 42.8k | return size; |
876 | 42.8k | } |
877 | | |
878 | | /** |
879 | | * Return number of elements in a string including the last (zeroed) element |
880 | | */ |
881 | | _PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size) |
882 | 0 | { |
883 | 0 | uint32_t i; |
884 | 0 | uint8_t zero[4] = {0,0,0,0}; |
885 | 0 | const char *var = (const char *)_var; |
886 | |
|
887 | 0 | for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++); |
888 | |
|
889 | 0 | return i+1; |
890 | 0 | } |
891 | | |
892 | | /** |
893 | | * @brief Get the string length including the null terminator if available. |
894 | | * |
895 | | * This checks the string length based on the elements. The returned number |
896 | | * includes the terminating null byte(s) if found. |
897 | | * |
898 | | * @param[in] _var The string to calculate the length for. |
899 | | * |
900 | | * @param[in] length The length of the buffer passed by _var. |
901 | | * |
902 | | * @param[in] element_size The element_size of a string char in bytes. |
903 | | * |
904 | | * @return The length of the strings or 0. |
905 | | */ |
906 | | static uint32_t ndr_string_n_length(const void *_var, |
907 | | size_t length, |
908 | | uint32_t element_size) |
909 | 73.1k | { |
910 | 73.1k | size_t i = 0; |
911 | 73.1k | uint8_t zero[4] = {0,0,0,0}; |
912 | 73.1k | const char *var = (const char *)_var; |
913 | 73.1k | int cmp; |
914 | | |
915 | 73.1k | if (element_size > 4) { |
916 | 0 | return 0; |
917 | 0 | } |
918 | | |
919 | 10.9M | for (i = 0; i < length; i++, var += element_size) { |
920 | 10.9M | cmp = memcmp(var, zero, element_size); |
921 | 10.9M | if (cmp == 0) { |
922 | 33.4k | break; |
923 | 33.4k | } |
924 | 10.9M | } |
925 | | |
926 | 73.1k | if (i == length) { |
927 | 39.6k | return length; |
928 | 39.6k | } |
929 | | |
930 | 33.4k | return i + 1; |
931 | 73.1k | } |
932 | | |
933 | | _PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size) |
934 | 696k | { |
935 | 696k | uint32_t i; |
936 | 696k | uint32_t save_offset; |
937 | | |
938 | 696k | if (count == 0) { |
939 | 5.11k | return NDR_ERR_RANGE; |
940 | 5.11k | } |
941 | | |
942 | 691k | if (element_size && count - 1 > UINT32_MAX / element_size) { |
943 | 1.47k | return NDR_ERR_RANGE; |
944 | 1.47k | } |
945 | | |
946 | 689k | save_offset = ndr->offset; |
947 | 689k | NDR_CHECK(ndr_pull_advance(ndr, (count - 1) * element_size)); |
948 | 675k | NDR_PULL_NEED_BYTES(ndr, element_size); |
949 | | |
950 | 1.50M | for (i = 0; i < element_size; i++) { |
951 | 831k | if (ndr->data[ndr->offset+i] != 0) { |
952 | 887 | ndr->offset = save_offset; |
953 | | |
954 | 887 | return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries"); |
955 | 887 | } |
956 | 831k | } |
957 | | |
958 | 673k | ndr->offset = save_offset; |
959 | | |
960 | 673k | return NDR_ERR_SUCCESS; |
961 | 674k | } |
962 | | |
963 | | _PUBLIC_ enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset) |
964 | 3.87M | { |
965 | 3.87M | size_t converted_size; |
966 | | |
967 | 3.87M | if (length == 0) { |
968 | 2.19M | *var = talloc_strdup(ndr->current_mem_ctx, ""); |
969 | 2.19M | if (*var == NULL) { |
970 | 0 | return ndr_pull_error(ndr, NDR_ERR_ALLOC, |
971 | 0 | "Failed to talloc_strdup() in ndr_pull_charset()"); |
972 | 0 | } |
973 | 2.19M | return NDR_ERR_SUCCESS; |
974 | 2.19M | } |
975 | | |
976 | 1.67M | if (NDR_BE(ndr) && chset == CH_UTF16) { |
977 | 121 | chset = CH_UTF16BE; |
978 | 121 | } |
979 | | |
980 | 1.67M | if ((byte_mul != 0) && (length > UINT32_MAX/byte_mul)) { |
981 | 659 | return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "length overflow"); |
982 | 659 | } |
983 | 1.67M | NDR_PULL_NEED_BYTES(ndr, length*byte_mul); |
984 | | |
985 | 1.67M | if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, |
986 | 1.67M | ndr->data+ndr->offset, length*byte_mul, |
987 | 1.67M | var, |
988 | 1.67M | &converted_size)) |
989 | 7.66k | { |
990 | 7.66k | return ndr_pull_error(ndr, NDR_ERR_CHARCNV, |
991 | 7.66k | "Bad character conversion"); |
992 | 7.66k | } |
993 | 1.66M | NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul)); |
994 | | |
995 | 1.66M | return NDR_ERR_SUCCESS; |
996 | 1.66M | } |
997 | | |
998 | | _PUBLIC_ enum ndr_err_code ndr_pull_charset_to_null(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset) |
999 | 73.5k | { |
1000 | 73.5k | size_t converted_size; |
1001 | 73.5k | uint32_t str_len; |
1002 | | |
1003 | 73.5k | if (length == 0) { |
1004 | 0 | *var = talloc_strdup(ndr->current_mem_ctx, ""); |
1005 | 0 | if (*var == NULL) { |
1006 | 0 | return ndr_pull_error(ndr, NDR_ERR_ALLOC, |
1007 | 0 | "Failed to talloc_strdup() in ndr_pull_charset_to_null()"); |
1008 | 0 | } |
1009 | 0 | return NDR_ERR_SUCCESS; |
1010 | 0 | } |
1011 | | |
1012 | 73.5k | if (NDR_BE(ndr) && chset == CH_UTF16) { |
1013 | 0 | chset = CH_UTF16BE; |
1014 | 0 | } |
1015 | | |
1016 | 73.5k | if ((byte_mul != 0) && (length > UINT32_MAX/byte_mul)) { |
1017 | 0 | return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "length overflow"); |
1018 | 0 | } |
1019 | 73.5k | NDR_PULL_NEED_BYTES(ndr, length*byte_mul); |
1020 | | |
1021 | 73.1k | str_len = ndr_string_n_length(ndr->data+ndr->offset, length, byte_mul); |
1022 | 73.1k | if (str_len == 0) { |
1023 | 0 | return ndr_pull_error(ndr, NDR_ERR_LENGTH, |
1024 | 0 | "Invalid length"); |
1025 | 0 | } |
1026 | | |
1027 | 73.1k | if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, |
1028 | 73.1k | ndr->data+ndr->offset, str_len*byte_mul, |
1029 | 73.1k | var, |
1030 | 73.1k | &converted_size)) |
1031 | 40 | { |
1032 | 40 | return ndr_pull_error(ndr, NDR_ERR_CHARCNV, |
1033 | 40 | "Bad character conversion"); |
1034 | 40 | } |
1035 | 73.0k | NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul)); |
1036 | | |
1037 | 73.0k | return NDR_ERR_SUCCESS; |
1038 | 73.0k | } |
1039 | | |
1040 | | _PUBLIC_ enum ndr_err_code ndr_push_charset(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset) |
1041 | 1.47M | { |
1042 | 1.47M | size_t required; |
1043 | | |
1044 | 1.47M | if (NDR_BE(ndr) && chset == CH_UTF16) { |
1045 | 0 | chset = CH_UTF16BE; |
1046 | 0 | } |
1047 | | |
1048 | 1.47M | if ((byte_mul != 0) && (length > SIZE_MAX/byte_mul)) { |
1049 | 0 | return ndr_push_error(ndr, NDR_ERR_LENGTH, "length overflow"); |
1050 | 0 | } |
1051 | 1.47M | required = byte_mul * length; |
1052 | | |
1053 | 1.47M | NDR_PUSH_NEED_BYTES(ndr, required); |
1054 | | |
1055 | 1.47M | if (required) { |
1056 | 1.08M | size_t size = 0; |
1057 | | |
1058 | 1.08M | if (var == NULL) { |
1059 | 0 | return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer"); |
1060 | 0 | } |
1061 | | |
1062 | 1.08M | if (!convert_string(CH_UNIX, chset, |
1063 | 1.08M | var, strlen(var), |
1064 | 1.08M | ndr->data+ndr->offset, required, &size)) { |
1065 | 196 | return ndr_push_error(ndr, NDR_ERR_CHARCNV, |
1066 | 196 | "Bad character conversion"); |
1067 | 196 | } |
1068 | | |
1069 | | /* Make sure the remaining part of the string is filled with zeroes */ |
1070 | 1.08M | if (size < required) { |
1071 | 828k | memset(ndr->data+ndr->offset+size, 0, required-size); |
1072 | 828k | } |
1073 | 1.08M | } |
1074 | | |
1075 | 1.47M | ndr->offset += required; |
1076 | | |
1077 | 1.47M | return NDR_ERR_SUCCESS; |
1078 | 1.47M | } |
1079 | | |
1080 | | _PUBLIC_ enum ndr_err_code ndr_push_charset_to_null(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset) |
1081 | 8.38k | { |
1082 | 8.38k | const char *str = var; |
1083 | | |
1084 | 8.38k | if (str == NULL) { |
1085 | 0 | str = "\0"; /* i.e. two zero bytes, for UTF16 null word. */ |
1086 | 0 | length = 1; |
1087 | 0 | } |
1088 | | |
1089 | 8.38k | return ndr_push_charset(ndr, ndr_flags, str, length, byte_mul, chset); |
1090 | 8.38k | } |
1091 | | |
1092 | | /* Return number of elements in a string in the specified charset */ |
1093 | | _PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset) |
1094 | 1.01M | { |
1095 | 1.01M | switch (chset) { |
1096 | | /* case CH_UTF16: this has the same value as CH_UTF16LE */ |
1097 | 276k | case CH_UTF16LE: |
1098 | 276k | case CH_UTF16BE: |
1099 | 276k | case CH_UTF16MUNGED: |
1100 | 1.01M | case CH_UTF8: |
1101 | 1.01M | return strlen_m_ext_term((const char *)var, CH_UNIX, chset); |
1102 | 573 | case CH_DOS: |
1103 | 573 | case CH_UNIX: |
1104 | 573 | return strlen((const char *)var)+1; |
1105 | 0 | default: |
1106 | | /* Fallback, this should never happen */ |
1107 | 0 | return strlen((const char *)var)+1; |
1108 | 1.01M | } |
1109 | 1.01M | } |