r7702: Implement [charset()] attribute.
[Samba/ekacnet.git] / source / librpc / ndr / ndr_string.c
blob95e9df39f06aa649777ea43b1cb9c0908fe512e1
1 /*
2 Unix SMB/CIFS implementation.
4 routines for marshalling/unmarshalling string types
6 Copyright (C) Andrew Tridgell 2003
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
24 #include "system/network.h"
27 pull a general string from the wire
29 NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
31 char *as=NULL;
32 uint32_t len1, ofs, len2;
33 uint16_t len3;
34 int ret;
35 int chset = CH_UTF16;
36 unsigned byte_mul = 2;
37 unsigned flags = ndr->flags;
38 unsigned c_len_term = 0;
40 if (!(ndr_flags & NDR_SCALARS)) {
41 return NT_STATUS_OK;
44 if (NDR_BE(ndr)) {
45 chset = CH_UTF16BE;
48 if (flags & LIBNDR_FLAG_STR_ASCII) {
49 chset = CH_DOS;
50 byte_mul = 1;
51 flags &= ~LIBNDR_FLAG_STR_ASCII;
54 if (flags & LIBNDR_FLAG_STR_UTF8) {
55 chset = CH_UTF8;
56 byte_mul = 1;
57 flags &= ~LIBNDR_FLAG_STR_UTF8;
60 flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
61 if (flags & LIBNDR_FLAG_STR_CHARLEN) {
62 c_len_term = 1;
63 flags &= ~LIBNDR_FLAG_STR_CHARLEN;
66 switch (flags & LIBNDR_STRING_FLAGS) {
67 case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
68 case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
69 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
70 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
71 if (ofs != 0) {
72 return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
73 ndr->flags & LIBNDR_STRING_FLAGS);
75 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2));
76 if (len2 > len1) {
77 return ndr_pull_error(ndr, NDR_ERR_STRING,
78 "Bad string lengths len1=%u ofs=%u len2=%u\n",
79 len1, ofs, len2);
81 if (len2 == 0) {
82 *s = talloc_strdup(ndr, "");
83 break;
85 NDR_PULL_NEED_BYTES(ndr, (len2 + c_len_term)*byte_mul);
86 ret = convert_string_talloc(ndr, chset, CH_UNIX,
87 ndr->data+ndr->offset,
88 (len2 + c_len_term)*byte_mul,
89 (void **)&as);
90 if (ret == -1) {
91 return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
92 "Bad character conversion");
94 NDR_CHECK(ndr_pull_advance(ndr, (len2 + c_len_term)*byte_mul));
96 /* this is a way of detecting if a string is sent with the wrong
97 termination */
98 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
99 if (strlen(as) < (len2 + c_len_term)) {
100 DEBUG(6,("short string '%s'\n", as));
102 } else {
103 if (strlen(as) == (len2 + c_len_term)) {
104 DEBUG(6,("long string '%s'\n", as));
107 *s = as;
108 break;
110 case LIBNDR_FLAG_STR_SIZE4:
111 case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
112 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
113 NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
114 if (len1 == 0) {
115 *s = talloc_strdup(ndr, "");
116 break;
118 ret = convert_string_talloc(ndr, chset, CH_UNIX,
119 ndr->data+ndr->offset,
120 (len1 + c_len_term)*byte_mul,
121 (void **)&as);
122 if (ret == -1) {
123 return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
124 "Bad character conversion");
126 NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));
128 /* this is a way of detecting if a string is sent with the wrong
129 termination */
130 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
131 if (strlen(as) < (len1 + c_len_term)) {
132 DEBUG(6,("short string '%s'\n", as));
134 } else {
135 if (strlen(as) == (len1 + c_len_term)) {
136 DEBUG(6,("long string '%s'\n", as));
139 *s = as;
140 break;
142 case LIBNDR_FLAG_STR_LEN4:
143 case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
144 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
145 if (ofs != 0) {
146 return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
147 ndr->flags & LIBNDR_STRING_FLAGS);
149 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
150 NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
151 if (len1 == 0) {
152 *s = talloc_strdup(ndr, "");
153 break;
155 ret = convert_string_talloc(ndr, chset, CH_UNIX,
156 ndr->data+ndr->offset,
157 (len1 + c_len_term)*byte_mul,
158 (void **)&as);
159 if (ret == -1) {
160 return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
161 "Bad character conversion");
163 NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));
165 /* this is a way of detecting if a string is sent with the wrong
166 termination */
167 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
168 if (strlen(as) < (len1 + c_len_term)) {
169 DEBUG(6,("short string '%s'\n", as));
171 } else {
172 if (strlen(as) == (len1 + c_len_term)) {
173 DEBUG(6,("long string '%s'\n", as));
176 *s = as;
177 break;
180 case LIBNDR_FLAG_STR_SIZE2:
181 case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM:
182 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
183 NDR_PULL_NEED_BYTES(ndr, (len3 + c_len_term)*byte_mul);
184 if (len3 == 0) {
185 *s = talloc_strdup(ndr, "");
186 break;
188 ret = convert_string_talloc(ndr, chset, CH_UNIX,
189 ndr->data+ndr->offset,
190 (len3 + c_len_term)*byte_mul,
191 (void **)&as);
192 if (ret == -1) {
193 return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
194 "Bad character conversion");
196 NDR_CHECK(ndr_pull_advance(ndr, (len3 + c_len_term)*byte_mul));
198 /* this is a way of detecting if a string is sent with the wrong
199 termination */
200 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
201 if (strlen(as) < (len3 + c_len_term)) {
202 DEBUG(6,("short string '%s'\n", as));
204 } else {
205 if (strlen(as) == (len3 + c_len_term)) {
206 DEBUG(6,("long string '%s'\n", as));
209 *s = as;
210 break;
212 case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
213 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
214 NDR_PULL_NEED_BYTES(ndr, len3);
215 if (len3 == 0) {
216 *s = talloc_strdup(ndr, "");
217 break;
219 ret = convert_string_talloc(ndr, chset, CH_UNIX,
220 ndr->data+ndr->offset,
221 len3,
222 (void **)&as);
223 if (ret == -1) {
224 return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
225 "Bad character conversion");
227 NDR_CHECK(ndr_pull_advance(ndr, len3));
228 *s = as;
229 break;
231 case LIBNDR_FLAG_STR_NULLTERM:
232 if (byte_mul == 1) {
233 len1 = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset);
234 } else {
235 len1 = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset);
237 ret = convert_string_talloc(ndr, chset, CH_UNIX,
238 ndr->data+ndr->offset,
239 len1,
240 (void **)&as);
241 if (ret == -1) {
242 return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
243 "Bad character conversion");
245 NDR_CHECK(ndr_pull_advance(ndr, len1));
246 *s = as;
247 break;
249 case LIBNDR_FLAG_STR_FIXLEN15:
250 case LIBNDR_FLAG_STR_FIXLEN32:
251 len1 = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15;
252 NDR_PULL_NEED_BYTES(ndr, len1*byte_mul);
253 ret = convert_string_talloc(ndr, chset, CH_UNIX,
254 ndr->data+ndr->offset,
255 len1*byte_mul,
256 (void **)&as);
257 if (ret == -1) {
258 return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
259 "Bad character conversion");
261 NDR_CHECK(ndr_pull_advance(ndr, len1*byte_mul));
262 *s = as;
263 break;
265 default:
266 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
267 ndr->flags & LIBNDR_STRING_FLAGS);
270 return NT_STATUS_OK;
275 push a general string onto the wire
277 NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
279 ssize_t s_len, c_len, d_len;
280 int ret;
281 int chset = CH_UTF16;
282 unsigned flags = ndr->flags;
283 unsigned byte_mul = 2;
284 unsigned c_len_term = 1;
286 if (!(ndr_flags & NDR_SCALARS)) {
287 return NT_STATUS_OK;
290 if (NDR_BE(ndr)) {
291 chset = CH_UTF16BE;
294 s_len = s?strlen(s):0;
295 c_len = s?strlen_m(s):0;
297 if (flags & LIBNDR_FLAG_STR_ASCII) {
298 chset = CH_DOS;
299 byte_mul = 1;
300 flags &= ~LIBNDR_FLAG_STR_ASCII;
303 if (flags & LIBNDR_FLAG_STR_UTF8) {
304 chset = CH_UTF8;
305 byte_mul = 1;
306 flags &= ~LIBNDR_FLAG_STR_UTF8;
309 flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
311 if (flags & LIBNDR_FLAG_STR_CHARLEN) {
312 c_len_term = 0;
313 flags &= ~LIBNDR_FLAG_STR_CHARLEN;
316 switch (flags & LIBNDR_STRING_FLAGS) {
317 case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
318 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len+c_len_term));
319 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
320 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len+c_len_term));
321 NDR_PUSH_NEED_BYTES(ndr, byte_mul*(c_len+1));
322 ret = convert_string(CH_UNIX, chset,
323 s, s_len+1,
324 ndr->data+ndr->offset,
325 byte_mul*(c_len+1));
326 if (ret == -1) {
327 return ndr_push_error(ndr, NDR_ERR_CHARCNV,
328 "Bad character conversion");
330 ndr->offset += byte_mul*(c_len+1);
331 break;
333 case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
334 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
335 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
336 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
337 NDR_PUSH_NEED_BYTES(ndr, c_len*byte_mul);
338 ret = convert_string(CH_UNIX, chset,
339 s, s_len,
340 ndr->data+ndr->offset, c_len*byte_mul);
341 if (ret == -1) {
342 return ndr_push_error(ndr, NDR_ERR_CHARCNV,
343 "Bad character conversion");
345 ndr->offset += c_len*byte_mul;
346 break;
348 case LIBNDR_FLAG_STR_LEN4:
349 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
350 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len + c_len_term));
351 NDR_PUSH_NEED_BYTES(ndr, byte_mul*(c_len+1));
352 ret = convert_string(CH_UNIX, chset,
353 s, s_len + 1,
354 ndr->data+ndr->offset, byte_mul*(c_len+1));
355 if (ret == -1) {
356 return ndr_push_error(ndr, NDR_ERR_CHARCNV,
357 "Bad character conversion");
359 ndr->offset += byte_mul*(c_len+1);
360 break;
362 case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
363 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
364 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
365 NDR_PUSH_NEED_BYTES(ndr, byte_mul*c_len);
366 ret = convert_string(CH_UNIX, chset,
367 s, s_len,
368 ndr->data+ndr->offset, byte_mul*c_len);
369 if (ret == -1) {
370 return ndr_push_error(ndr, NDR_ERR_CHARCNV,
371 "Bad character conversion");
373 ndr->offset += byte_mul*c_len;
374 break;
376 case LIBNDR_FLAG_STR_SIZE4:
377 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len + c_len_term));
378 NDR_PUSH_NEED_BYTES(ndr, byte_mul*(c_len+1));
379 ret = convert_string(CH_UNIX, chset,
380 s, s_len + 1,
381 ndr->data+ndr->offset, byte_mul*(c_len+1));
382 if (ret == -1) {
383 return ndr_push_error(ndr, NDR_ERR_CHARCNV,
384 "Bad character conversion");
386 ndr->offset += byte_mul*(c_len+1);
387 break;
389 case LIBNDR_FLAG_STR_SIZE2:
390 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len + c_len_term));
391 NDR_PUSH_NEED_BYTES(ndr, byte_mul*(c_len+1));
392 ret = convert_string(CH_UNIX, chset,
393 s, s_len + 1,
394 ndr->data+ndr->offset, byte_mul*(c_len+1));
395 if (ret == -1) {
396 return ndr_push_error(ndr, NDR_ERR_CHARCNV,
397 "Bad character conversion");
399 ndr->offset += byte_mul*(c_len+1);
400 break;
402 case LIBNDR_FLAG_STR_NULLTERM:
403 NDR_PUSH_NEED_BYTES(ndr, byte_mul*(c_len+1));
404 ret = convert_string(CH_UNIX, chset,
405 s, s_len+1,
406 ndr->data+ndr->offset, byte_mul*(c_len+1));
407 if (ret == -1) {
408 return ndr_push_error(ndr, NDR_ERR_CHARCNV,
409 "Bad character conversion");
411 ndr->offset += byte_mul*(c_len+1);
412 break;
414 case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
415 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len*byte_mul));
416 NDR_PUSH_NEED_BYTES(ndr, c_len*byte_mul);
417 ret = convert_string(CH_UNIX, chset,
418 s, s_len,
419 ndr->data+ndr->offset, c_len*byte_mul);
420 if (ret == -1) {
421 return ndr_push_error(ndr, NDR_ERR_CHARCNV,
422 "Bad character conversion");
424 ndr->offset += c_len*byte_mul;
425 break;
427 case LIBNDR_FLAG_STR_FIXLEN15:
428 case LIBNDR_FLAG_STR_FIXLEN32:
429 d_len = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15;
430 NDR_PUSH_NEED_BYTES(ndr, byte_mul*d_len);
431 ret = convert_string(CH_UNIX, chset,
432 s, s_len,
433 ndr->data+ndr->offset, byte_mul*d_len);
434 if (ret == -1) {
435 return ndr_push_error(ndr, NDR_ERR_CHARCNV,
436 "Bad character conversion");
438 ndr->offset += byte_mul*d_len;
439 break;
441 default:
442 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
443 ndr->flags & LIBNDR_STRING_FLAGS);
446 return NT_STATUS_OK;
450 push a general string onto the wire
452 size_t ndr_string_array_size(struct ndr_push *ndr, const char *s)
454 size_t c_len;
455 unsigned flags = ndr->flags;
456 unsigned byte_mul = 2;
457 unsigned c_len_term = 1;
459 if (flags & LIBNDR_FLAG_STR_FIXLEN32) {
460 return 32;
462 if (flags & LIBNDR_FLAG_STR_FIXLEN15) {
463 return 15;
466 c_len = s?strlen_m(s):0;
468 if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_UTF8)) {
469 byte_mul = 1;
472 if (flags & LIBNDR_FLAG_STR_NOTERM) {
473 c_len_term = 0;
476 c_len = c_len + c_len_term;
478 if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
479 c_len = c_len * byte_mul;
482 return c_len;
485 void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s)
487 if (s) {
488 ndr->print(ndr, "%-25s: '%s'", name, s);
489 } else {
490 ndr->print(ndr, "%-25s: NULL", name);
494 uint32_t ndr_size_string(int ret, const char * const* string, int flags)
496 /* FIXME: Is this correct for all strings ? */
497 if(!(*string)) return ret;
498 return ret+strlen(*string)+1;
502 pull a general string array from the wire
504 NTSTATUS ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a)
506 const char **a = *_a;
507 uint32_t count;
509 if (!(ndr_flags & NDR_SCALARS)) {
510 return NT_STATUS_OK;
513 for (count = 0;; count++) {
514 const char *s = NULL;
515 a = talloc_realloc(ndr, a, const char *, count + 2);
516 NT_STATUS_HAVE_NO_MEMORY(a);
517 a[count] = NULL;
518 a[count+1] = NULL;
520 NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
521 if (strcmp("", s)==0) {
522 a[count] = NULL;
523 break;
524 } else {
525 a[count] = s;
529 *_a =a;
530 return NT_STATUS_OK;
534 push a general string array onto the wire
536 NTSTATUS ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a)
538 uint32_t count;
540 if (!(ndr_flags & NDR_SCALARS)) {
541 return NT_STATUS_OK;
544 for (count = 0; a && a[count]; count++) {
545 NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
548 NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
550 return NT_STATUS_OK;
553 void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a)
555 uint32_t count;
556 uint32_t i;
558 for (count = 0; a && a[count]; count++) {}
560 ndr->print(ndr, "%s: ARRAY(%d)", name, count);
561 ndr->depth++;
562 for (i=0;i<count;i++) {
563 char *idx=NULL;
564 asprintf(&idx, "[%d]", i);
565 if (idx) {
566 ndr_print_string(ndr, idx, a[i]);
567 free(idx);
570 ndr->depth--;
573 /* Return number of elements in a string including the last (zeroed) element */
574 uint32_t ndr_string_length(void *_var, uint32_t element_size)
576 uint32_t i;
577 uint8_t zero[4] = {0,0,0,0};
578 char *var = _var;
580 for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++);
582 return i+1;
585 NTSTATUS ndr_check_string_terminator(struct ndr_pull *ndr, const void *_var, uint32_t count, uint32_t element_size)
587 const char *var = _var;
588 uint32_t i;
590 var += element_size*(count-1);
592 for (i = 0; i < element_size; i++) {
593 if (var[i] != 0) {
594 return NT_STATUS_UNSUCCESSFUL;
598 return NT_STATUS_OK;
602 NTSTATUS ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, char **var, uint32_t length, uint8_t byte_mul, int chset)
604 int ret;
605 NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
606 ret = convert_string_talloc(ndr, chset, CH_UNIX,
607 ndr->data+ndr->offset,
608 length*byte_mul,
609 (void **)var);
610 if (ret == -1) {
611 return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
612 "Bad character conversion");
614 NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
616 return NT_STATUS_OK;
619 NTSTATUS ndr_push_charset(struct ndr_push *ndr, int ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, int chset)
621 int ret;
622 NDR_PUSH_NEED_BYTES(ndr, byte_mul*length);
623 ret = convert_string(CH_UNIX, chset,
624 var, length,
625 ndr->data+ndr->offset,
626 byte_mul*length);
627 if (ret == -1) {
628 return ndr_push_error(ndr, NDR_ERR_CHARCNV,
629 "Bad character conversion");
631 ndr->offset += byte_mul*length;
633 return NT_STATUS_OK;