summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2016-12-12 13:57:10 +1100
committerDamien Miller <djm@mindrot.org>2016-12-12 13:58:59 +1100
commitdda78a03af32e7994f132d923c2046e98b7c56c8 (patch)
tree589e87350c833aada6358afc719b7e08f7b64b75
parentc35995048f41239fc8895aadc3374c5f75180554 (diff)
Force Turkish locales back to C/POSIX; bz#2643
Turkish locales are unique in their handling of the letters 'i' and 'I' (yes, they are different letters) and OpenSSH isn't remotely prepared to deal with that. For now, the best we can do is to force OpenSSH to use the C/POSIX locale and try to preserve the UTF-8 encoding if possible. ok dtucker@
-rw-r--r--scp.c2
-rw-r--r--sftp.c2
-rw-r--r--ssh.c3
-rw-r--r--utf8.c42
-rw-r--r--utf8.h1
5 files changed, 47 insertions, 3 deletions
diff --git a/scp.c b/scp.c
index c67cd71df..b4db85198 100644
--- a/scp.c
+++ b/scp.c
@@ -379,7 +379,7 @@ main(int argc, char **argv)
379 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 379 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
380 sanitise_stdfd(); 380 sanitise_stdfd();
381 381
382 setlocale(LC_CTYPE, ""); 382 msetlocale();
383 383
384 /* Copy argv, because we modify it */ 384 /* Copy argv, because we modify it */
385 newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv)); 385 newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv));
diff --git a/sftp.c b/sftp.c
index af6e3a69a..2b8fdabfb 100644
--- a/sftp.c
+++ b/sftp.c
@@ -2272,7 +2272,7 @@ main(int argc, char **argv)
2272 ssh_malloc_init(); /* must be called before any mallocs */ 2272 ssh_malloc_init(); /* must be called before any mallocs */
2273 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 2273 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
2274 sanitise_stdfd(); 2274 sanitise_stdfd();
2275 setlocale(LC_CTYPE, ""); 2275 msetlocale();
2276 2276
2277 __progname = ssh_get_progname(argv[0]); 2277 __progname = ssh_get_progname(argv[0]);
2278 memset(&args, '\0', sizeof(args)); 2278 memset(&args, '\0', sizeof(args));
diff --git a/ssh.c b/ssh.c
index 8aa8daae4..ee0b16dc2 100644
--- a/ssh.c
+++ b/ssh.c
@@ -109,6 +109,7 @@
109#include "version.h" 109#include "version.h"
110#include "ssherr.h" 110#include "ssherr.h"
111#include "myproposal.h" 111#include "myproposal.h"
112#include "utf8.h"
112 113
113#ifdef ENABLE_PKCS11 114#ifdef ENABLE_PKCS11
114#include "ssh-pkcs11.h" 115#include "ssh-pkcs11.h"
@@ -589,7 +590,7 @@ main(int ac, char **av)
589 */ 590 */
590 umask(022); 591 umask(022);
591 592
592 setlocale(LC_CTYPE, ""); 593 msetlocale();
593 594
594 /* 595 /*
595 * Initialize option structure to indicate that no values have been 596 * Initialize option structure to indicate that no values have been
diff --git a/utf8.c b/utf8.c
index f563d3738..87fa9e89a 100644
--- a/utf8.c
+++ b/utf8.c
@@ -27,6 +27,7 @@
27# include <langinfo.h> 27# include <langinfo.h>
28#endif 28#endif
29#include <limits.h> 29#include <limits.h>
30#include <locale.h>
30#include <stdarg.h> 31#include <stdarg.h>
31#include <stdio.h> 32#include <stdio.h>
32#include <stdlib.h> 33#include <stdlib.h>
@@ -288,3 +289,44 @@ mprintf(const char *fmt, ...)
288 va_end(ap); 289 va_end(ap);
289 return ret; 290 return ret;
290} 291}
292
293/*
294 * Set up libc for multibyte output in the user's chosen locale.
295 *
296 * XXX: we are known to have problems with Turkish (i/I confusion) so we
297 * deliberately fall back to the C locale for now. Longer term we should
298 * always prefer to select C.[encoding] if possible, but there's no
299 * standardisation in locales between systems, so we'll need to survey
300 * what's out there first.
301 */
302void
303msetlocale(void)
304{
305 const char *vars[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL };
306 char *cp;
307 int i;
308
309 /*
310 * We can't yet cope with dotless/dotted I in Turkish locales,
311 * so fall back to the C locale for these.
312 */
313 for (i = 0; vars[i] != NULL; i++) {
314 if ((cp = getenv(vars[i])) == NULL)
315 continue;
316 if (strncasecmp(cp, "TR", 2) != 0)
317 break;
318 /*
319 * If we're in a UTF-8 locale then prefer to use
320 * the C.UTF-8 locale (or equivalent) if it exists.
321 */
322 if ((strcasestr(cp, "UTF-8") != NULL ||
323 strcasestr(cp, "UTF8") != NULL) &&
324 (setlocale(LC_CTYPE, "C.UTF-8") != NULL ||
325 setlocale(LC_CTYPE, "POSIX.UTF-8") != NULL))
326 return;
327 setlocale(LC_CTYPE, "C");
328 return;
329 }
330 /* We can handle this locale */
331 setlocale(LC_CTYPE, "");
332}
diff --git a/utf8.h b/utf8.h
index 43ce1d55d..88c5a34a3 100644
--- a/utf8.h
+++ b/utf8.h
@@ -22,3 +22,4 @@ int fmprintf(FILE *, const char *, ...)
22int vfmprintf(FILE *, const char *, va_list); 22int vfmprintf(FILE *, const char *, va_list);
23int snmprintf(char *, size_t, int *, const char *, ...) 23int snmprintf(char *, size_t, int *, const char *, ...)
24 __attribute__((format(printf, 4, 5))); 24 __attribute__((format(printf, 4, 5)));
25void msetlocale(void);