OpenVAS Scanner 23.32.3
charcnv.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Greenbone AG
2 * SPDX-FileCopyrightText: 2003 Martin Pool
3 * SPDX-FileCopyrightText: 2001 Simo Sorce
4 * SPDX-FileCopyrightText: 2001 Andrew Tridgell
5 * SPDX-FileCopyrightText: 2001 Igor Vergeichik <iverg@mail.ru>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
33#include "byteorder.h"
34#include "iconv.h"
35#include "proto.h"
36#include "smb.h"
37
38#include <gvm/base/logging.h>
39
40#ifndef SMB_STRDUP
41#define SMB_STRDUP(s) strdup (s)
42#endif
43
44#ifndef uint8
45#define uint8 uint8_t
46#endif
47
48#ifndef uint16
49#define uint16 uint16_t
50#endif
51
52#ifndef _PUBLIC_
53#define _PUBLIC_
54#endif
55
56#undef G_LOG_DOMAIN
60#define G_LOG_DOMAIN "lib nasl"
61
62typedef unsigned int bool;
63#define False 0
64#define True 1
65
68size_t
69convert_string_ntlmssp (charset_t from, charset_t to, void const *src,
70 size_t srclen, void *dest, size_t destlen,
71 bool allow_badcharcnv);
72static int
74{
75 char buf[10];
76 uint16_t c2 = 0;
77 size_t len1, len2;
78
79 len1 = convert_string_ntlmssp (CH_UTF16LE, CH_DOS, &c, 2, buf, sizeof (buf),
80 False);
81
82 /* convert_string_ntlmssp returns a size_t value, and uses
83 * (size_t) -1 as error code */
84 if (len1 == 0 || len1 == (size_t) -1)
85 {
86 return 0;
87 }
88 len2 = convert_string_ntlmssp (CH_DOS, CH_UTF16LE, buf, len1, &c2, 2, False);
89 if (len2 != 2)
90 {
91 return 0;
92 }
93 return (c == c2);
94}
95
96/* We can parameterize this if someone complains.... JRA. */
97
98static char
100{
101 return '_';
102}
103
118
120static bool
121 conv_silent_ntlmssp; /* Should we do a debug if the conversion fails ? */
122
123static void
125{
126 static int mapped_file;
127 int i;
128 const char *allowed = ".!#$%&'()_-@^`~";
129
130 if (mapped_file)
131 {
132 /* Can't unmap files, so stick with what we have */
133 return;
134 }
135
136 /* we're using a dynamically created valid_table.
137 * It might need to be regenerated if the code page changed.
138 * We know that we're not using a mapped file, so we can
139 * free() the old one. */
140
141 /* use free rather than unmap */
143
144 valid_table_ntlmssp = (uint8 *) SMB_MALLOC (0x10000);
145 for (i = 0; i < 128; i++)
146 {
147 valid_table_ntlmssp[i] = isalnum (i) || strchr (allowed, i);
148 }
149
151
152 for (; i < 0x10000; i++)
153 {
154 uint16_t c;
155 SSVAL (&c, 0, i);
157 }
158}
159
160/*******************************************************************
161 * Count the number of characters in a uint16_t string.
162 * ********************************************************************/
163
164static size_t
166{
167 size_t len;
168 uint16 c;
169
170 for (len = 0; *(COPY_UCS2_CHAR (&c, src)); src++, len++)
171 {
172 ;
173 }
174
175 return len;
176}
177
181static const char *
183{
184 const char *ret = NULL;
185
186 if (ch == CH_UTF16LE)
187 ret = "UTF-16LE";
188 else if (ch == CH_UTF16BE)
189 ret = "UTF-16BE";
190 else if (ch == CH_UTF8)
191 ret = "UTF8";
192
193#if defined(HAVE_NL_LANGINFO) && defined(CODESET)
194 if (ret && !strcmp (ret, "LOCALE"))
195 {
196 const char *ln = NULL;
197
198#ifdef HAVE_SETLOCALE
199 setlocale (LC_ALL, "");
200#endif
201 ln = nl_langinfo (CODESET);
202 if (ln)
203 {
204 /* Check whether the charset name is supported
205 by iconv */
206 smb_iconv_t handle = smb_iconv_open_ntlmssp (ln, "UCS-2LE");
207 if (handle == (smb_iconv_t) -1)
208 {
209 ln = NULL;
210 }
211 else
212 {
214 }
215 }
216 ret = ln;
217 }
218#endif
219
220 if (!ret || !*ret)
221 ret = "ASCII";
222 return ret;
223}
224
225void
227{
228 static int initialized = False;
229
230 if (!initialized)
231 {
232 initialized = True;
234 }
235}
236
244void
246{
247 int c1, c2;
248 bool did_reload = False;
249
250 /* so that charset_name() works we need to get the UNIX<->UCS2 going
251 first */
255
259
260 for (c1 = 0; c1 < NUM_CHARSETS; c1++)
261 {
262 for (c2 = 0; c2 < NUM_CHARSETS; c2++)
263 {
264 const char *n1 = charset_name_ntlmssp ((charset_t) c1);
265 const char *n2 = charset_name_ntlmssp ((charset_t) c2);
266 if (conv_handles_ntlmssp[c1][c2]
267 && strcmp (n1, conv_handles_ntlmssp[c1][c2]->from_name) == 0
268 && strcmp (n2, conv_handles_ntlmssp[c1][c2]->to_name) == 0)
269 continue;
270
271 did_reload = True;
272
273 if (conv_handles_ntlmssp[c1][c2])
275
277 if (conv_handles_ntlmssp[c1][c2] == (smb_iconv_t) -1)
278 {
279 if (c1 != CH_UTF16LE && c1 != CH_UTF16BE)
280 {
281 n1 = "ASCII";
282 }
283 if (c2 != CH_UTF16LE && c2 != CH_UTF16BE)
284 {
285 n2 = "ASCII";
286 }
288 if (!conv_handles_ntlmssp[c1][c2])
289 {
290 g_message ("init_iconv_ntlmssp: conv_handle"
291 " initialization failed");
292 }
293 }
294 }
295 }
296
297 if (did_reload)
298 {
299 /* XXX: Does this really get called every time the dos
300 * codepage changes? */
301 /* XXX: Is the did_reload test too strict? */
305 }
306}
307
323
324static size_t
326 size_t srclen, void *dest, size_t destlen,
327 bool allow_bad_conv)
328{
329 size_t i_len, o_len;
330 size_t retval;
331 const char *inbuf = (const char *) src;
332 char *outbuf = (char *) dest;
333 smb_iconv_t descriptor;
334
336
337 descriptor = conv_handles_ntlmssp[from][to];
338
339 if (srclen == (size_t) -1)
340 {
341 if (from == CH_UTF16LE || from == CH_UTF16BE)
342 {
343 srclen = (strlen_w_ntlmssp ((const uint16 *) src) + 1) * 2;
344 }
345 else
346 {
347 srclen = strlen ((const char *) src) + 1;
348 }
349 }
350
351 if (descriptor == (smb_iconv_t) -1 || descriptor == (smb_iconv_t) 0)
352 return (size_t) -1;
353
354 i_len = srclen;
355 o_len = destlen;
356
357again:
358
359 retval = smb_iconv_ntlmssp (descriptor, &inbuf, &i_len, &outbuf, &o_len);
360 if (retval == (size_t) -1)
361 {
362 switch (errno)
363 {
364 case EINVAL:
365 /* Incomplete multibyte sequence */
367 if (allow_bad_conv)
368 goto use_as_is;
369 return (size_t) -1;
370 case E2BIG:
371 /* No more room */
372 break;
373 case EILSEQ:
374 /* Illegal multibyte sequence */
375 if (allow_bad_conv)
376 goto use_as_is;
377
378 return (size_t) -1;
379 default:
380 /* unknown error */
381 return (size_t) -1;
382 }
383 }
384 return destlen - o_len;
385
386use_as_is:
387
388 /*
389 * Conversion not supported. This is actually an error, but there are so
390 * many misconfigured iconv systems and smb.conf's out there we can't just
391 * fail. Do a very bad conversion instead.... JRA.
392 */
393
394 {
395 if (o_len == 0 || i_len == 0)
396 return destlen - o_len;
397
398 if (((from == CH_UTF16LE) || (from == CH_UTF16BE))
399 && ((to != CH_UTF16LE) && (to != CH_UTF16BE)))
400 {
401 /* Can't convert from utf16 any endian to multibyte.
402 Replace with the default fail char.
403 */
404 if (i_len < 2)
405 return destlen - o_len;
406 if (i_len >= 2)
407 {
409
410 outbuf++;
411 o_len--;
412
413 inbuf += 2;
414 i_len -= 2;
415 }
416
417 if (o_len == 0 || i_len == 0)
418 return destlen - o_len;
419
420 /* Keep trying with the next char... */
421 goto again;
422 }
423 else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE)
424 {
425 /* Can't convert to UTF16LE - just widen by adding the
426 default fail char then zero.
427 */
428 if (o_len < 2)
429 return destlen - o_len;
430
431 outbuf[0] = lp_failed_convert_char_ntlmssp ();
432 outbuf[1] = '\0';
433
434 inbuf++;
435 i_len--;
436
437 outbuf += 2;
438 o_len -= 2;
439
440 if (o_len == 0 || i_len == 0)
441 return destlen - o_len;
442
443 /* Keep trying with the next char... */
444 goto again;
445 }
446 else if (from != CH_UTF16LE && from != CH_UTF16BE && to != CH_UTF16LE
447 && to != CH_UTF16BE)
448 {
449 /* Failed multibyte to multibyte. Just copy the default fail char and
450 try again. */
451 outbuf[0] = lp_failed_convert_char_ntlmssp ();
452
453 inbuf++;
454 i_len--;
455
456 outbuf++;
457 o_len--;
458
459 if (o_len == 0 || i_len == 0)
460 return destlen - o_len;
461
462 /* Keep trying with the next char... */
463 goto again;
464 }
465 else
466 {
467 /* Keep compiler happy.... */
468 return destlen - o_len;
469 }
470 }
471}
472
491
492size_t
493convert_string_ntlmssp (charset_t from, charset_t to, void const *src,
494 size_t srclen, void *dest, size_t destlen,
495 bool allow_bad_conv)
496{
497 /*
498 * NB. We deliberately don't do a strlen here if srclen == -1.
499 * This is very expensive over millions of calls and is taken
500 * care of in the slow path in convert_string_internal. JRA.
501 */
502
503 if (srclen == 0)
504 return 0;
505
506 if (from != CH_UTF16LE && from != CH_UTF16BE && to != CH_UTF16LE
507 && to != CH_UTF16BE)
508 {
509 const unsigned char *p = (const unsigned char *) src;
510 unsigned char *q = (unsigned char *) dest;
511 size_t slen = srclen;
512 size_t dlen = destlen;
513 unsigned char lastp = '\0';
514 size_t retval = 0;
515
516 /* If all characters are ascii, fast path here. */
517 while (slen && dlen)
518 {
519 if ((lastp = *p) <= 0x7f)
520 {
521 *q++ = *p++;
522 if (slen != (size_t) -1)
523 {
524 slen--;
525 }
526 dlen--;
527 retval++;
528 if (!lastp)
529 break;
530 }
531 else
532 {
533#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
534 goto general_case;
535#else
537 from, to, p, slen, q, dlen, allow_bad_conv);
538 if (ret == (size_t) -1)
539 {
540 return ret;
541 }
542 return retval + ret;
543#endif
544 }
545 }
546 if (!dlen)
547 {
548 /* Even if we fast path we should note if we ran out of room. */
549 if (((slen != (size_t) -1) && slen)
550 || ((slen == (size_t) -1) && lastp))
551 {
552 errno = E2BIG;
553 }
554 }
555 return retval;
556 }
557 else if (from == CH_UTF16LE && to != CH_UTF16LE)
558 {
559 const unsigned char *p = (const unsigned char *) src;
560 unsigned char *q = (unsigned char *) dest;
561 size_t retval = 0;
562 size_t slen = srclen;
563 size_t dlen = destlen;
564 unsigned char lastp = '\0';
565
566 /* If all characters are ascii, fast path here. */
567 while (((slen == (size_t) -1) || (slen >= 2)) && dlen)
568 {
569 if (((lastp = *p) <= 0x7f) && (p[1] == 0))
570 {
571 *q++ = *p;
572 if (slen != (size_t) -1)
573 {
574 slen -= 2;
575 }
576 p += 2;
577 dlen--;
578 retval++;
579 if (!lastp)
580 break;
581 }
582 else
583 {
584#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
585 goto general_case;
586#else
587 return retval
588 + convert_string_internal_ntlmssp (from, to, p, slen, q,
589 dlen, allow_bad_conv);
590#endif
591 }
592 }
593 if (!dlen)
594 {
595 /* Even if we fast path we should note if we ran out of room. */
596 if (((slen != (size_t) -1) && slen)
597 || ((slen == (size_t) -1) && lastp))
598 {
599 errno = E2BIG;
600 }
601 }
602 return retval;
603 }
604 else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE)
605 {
606 const unsigned char *p = (const unsigned char *) src;
607 unsigned char *q = (unsigned char *) dest;
608 size_t retval = 0;
609 size_t slen = srclen;
610 size_t dlen = destlen;
611 unsigned char lastp = '\0';
612
613 /* If all characters are ascii, fast path here. */
614 while (slen && (dlen >= 2))
615 {
616 if ((lastp = *p) <= 0x7F)
617 {
618 *q++ = *p++;
619 *q++ = '\0';
620 if (slen != (size_t) -1)
621 {
622 slen--;
623 }
624 dlen -= 2;
625 retval += 2;
626 if (!lastp)
627 break;
628 }
629 else
630 {
631#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
632 goto general_case;
633#else
634 return retval
635 + convert_string_internal_ntlmssp (from, to, p, slen, q,
636 dlen, allow_bad_conv);
637#endif
638 }
639 }
640 if (!dlen)
641 {
642 /* Even if we fast path we should note if we ran out of room. */
643 if (((slen != (size_t) -1) && slen)
644 || ((slen == (size_t) -1) && lastp))
645 {
646 errno = E2BIG;
647 }
648 }
649 return retval;
650 }
651
652#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
653general_case:
654#endif
655 return convert_string_internal_ntlmssp (from, to, src, srclen, dest, destlen,
656 allow_bad_conv);
657}
Unix SMB/CIFS implementation. SMB Byte handling.
#define SSVAL(buf, pos, val)
Definition byteorder.h:116
static smb_iconv_t conv_handles_ntlmssp[NUM_CHARSETS][NUM_CHARSETS]
Definition charcnv.c:119
static size_t strlen_w_ntlmssp(const uint16 *src)
Definition charcnv.c:165
#define uint8
Definition charcnv.c:45
#define False
Definition charcnv.c:63
static size_t convert_string_internal_ntlmssp(charset_t from, charset_t to, void const *src, size_t srclen, void *dest, size_t destlen, bool allow_bad_conv)
Definition charcnv.c:325
static bool conv_silent_ntlmssp
Definition charcnv.c:121
unsigned int bool
Definition charcnv.c:62
size_t convert_string_ntlmssp(charset_t from, charset_t to, void const *src, size_t srclen, void *dest, size_t destlen, bool allow_badcharcnv)
Definition charcnv.c:493
static uint8 * valid_table_ntlmssp
Definition charcnv.c:66
void init_iconv_ntlmssp(void)
Definition charcnv.c:245
static const char * charset_name_ntlmssp(charset_t ch)
Definition charcnv.c:182
static void init_valid_table_ntlmssp(void)
Definition charcnv.c:124
#define True
Definition charcnv.c:64
void lazy_initialize_conv_ntlmssp(void)
Definition charcnv.c:226
static int check_dos_char_slowly_ntlmssp(uint16 c)
Definition charcnv.c:73
static bool valid_table_use_unmap_ntlmssp
Definition charcnv.c:67
static char lp_failed_convert_char_ntlmssp(void)
Definition charcnv.c:99
#define uint16
Definition charcnv.c:49
#define NUM_CHARSETS
Definition charset.h:34
charset_t
Definition charset.h:24
@ CH_UTF16BE
Definition charset.h:31
@ CH_UNIX
Definition charset.h:27
@ CH_DOS
Definition charset.h:29
@ CH_UTF16LE
Definition charset.h:25
@ CH_UTF8
Definition charset.h:30
int smb_iconv_close_ntlmssp(smb_iconv_t cd)
Definition iconv.c:203
smb_iconv_t smb_iconv_open_ntlmssp(const char *tocode, const char *fromcode)
Definition iconv.c:101
size_t smb_iconv_ntlmssp(smb_iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
Definition iconv.c:53
Unix SMB/CIFS implementation. iconv memory system include wrappers.
#define EILSEQ
Definition iconv.h:40
uint8_t len
Unix SMB/CIFS implementation.
struct _smb_iconv_t * smb_iconv_t
#define COPY_UCS2_CHAR(dest, src)
Definition smb.h:164