Signed-off-by: Christian Hesse <mail@xxxxxxxx> --- configure.ac | 11 ++++++ defines.h | 5 +++ log.c | 3 +- sshkey.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 106 insertions(+), 21 deletions(-) diff --git a/configure.ac b/configure.ac index bb0095f..7e3965f 100644 --- a/configure.ac +++ b/configure.ac @@ -383,6 +383,8 @@ AC_CHECK_HEADERS([ \ inttypes.h \ limits.h \ locale.h \ + iconv.h \ + langinfo.h \ login.h \ maillock.h \ ndir.h \ @@ -4641,6 +4643,15 @@ AC_ARG_ENABLE([pututxline], fi ] ) +AC_ARG_ENABLE([unicode], + [ --disable-unicode disable use of unicode [no]], + [ + if test "x$enableval" = "xno" ; then + AC_DEFINE([DISABLE_UNICODE], [1], + [Define if you don't want to use unicode]) + fi + ] +) AC_ARG_WITH([lastlog], [ --with-lastlog=FILE|DIR specify lastlog location [common locations]], [ diff --git a/defines.h b/defines.h index fa0ccba..7ea69cc 100644 --- a/defines.h +++ b/defines.h @@ -850,4 +850,9 @@ struct winsize { # endif /* gcc version */ #endif /* __predict_true */ +#if defined(HAVE_LOCALE_H) && defined(HAVE_ICONV_H) && \ + defined(HAVE_LANGINFO_H) && !defined(DISABLE_UNICODE) +# define USE_UNICODE +#endif + #endif /* _DEFINES_H */ diff --git a/log.c b/log.c index 32e1d2e..7463617 100644 --- a/log.c +++ b/log.c @@ -444,8 +444,9 @@ do_log(LogLevel level, const char *fmt, va_list args) tmp_handler(level, fmtbuf, log_handler_ctx); log_handler = tmp_handler; } else if (log_on_stderr) { - snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf); + /* we want unicode multi byte characters, so do not use fmtbuf here */ (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); + (void)write(log_stderr_fd, "\r\n", 2); } else { #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); diff --git a/sshkey.c b/sshkey.c index cfe5980..554087f 100644 --- a/sshkey.c +++ b/sshkey.c @@ -44,6 +44,12 @@ #include <stdio.h> #include <string.h> #include <resolv.h> +#ifdef USE_UNICODE +#include <locale.h> +#include <unistd.h> +#include <iconv.h> +#include <langinfo.h> +#endif /* USE_UNICODE */ #ifdef HAVE_UTIL_H #include <util.h> #endif /* HAVE_UTIL_H */ @@ -1088,17 +1094,75 @@ fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len, * Chars to be used after each other every time the worm * intersects with itself. Matter of taste. */ + char *border_ascii[] = { "+", "-", "[", "]", "+", "|", "+", "+" }; + char **border; char *augmentation_string = " .o+=*BOX@%&#/^SE"; - char *retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X]; + char *retval, *p, title[FLDSIZE_X - 2], hash[FLDSIZE_X - 2]; u_char field[FLDSIZE_X][FLDSIZE_Y]; size_t i, tlen, hlen; u_int b; int x, y, r; size_t len = strlen(augmentation_string) - 1; - if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL) + if ((retval = malloc((FLDSIZE_X + 7) * FLDSIZE_Y + FLDSIZE_X * 3 * 2)) == NULL) return NULL; +#ifdef USE_UNICODE + iconv_t cd; + /* unicode character codes for box drawing + * http://unicode.org/charts/PDF/U2500.pdf */ + uint32_t border_unicode[] = { + 0x250c, /* ┌ upper left */ + 0x2500, /* ─ horizontal */ + 0x2524, /* ┤ left of title/hash */ + 0x251c, /* ├ right of title/hash */ + 0x2510, /* ┐ upper right */ + 0x2502, /* │ vertical */ + 0x2514, /* └ lower left */ + 0x2518 /* ┘ lower right */ }; + /* border_buffer is array of array of char + * we use this to have statically allocated buffer */ + char border_buffer[8][5]; + /* border_encoded is array of pointer to char */ + char *border_encoded[8]; + + if (isatty(fileno(stdout)) == 1) { + /* initialize locale */ + setlocale(LC_ALL, ""); + +#if __BYTE_ORDER == __LITTLE_ENDIAN + cd = iconv_open(nl_langinfo(CODESET), "UTF32LE"); +#elif __BYTE_ORDER == __BIG_ENDIAN + cd = iconv_open(nl_langinfo(CODESET), "UTF32BE"); +#else +#error Unknown __BYTE_ORDER +#endif + + /* encode the border elements */ + for (int i = 0; i < 8; i++) { + size_t in_size = sizeof(uint32_t);; + size_t out_size = sizeof(border_buffer[i]); + char *input = (char *) &border_unicode[i]; + char *output = border_buffer[i]; + + memset(border_buffer[i], 0, out_size); + iconv(cd, &input, &in_size, &output, &out_size); + + /* if iconv() was successful we have a string with non-zero length + * fall back to ascii otherwise */ + if (border_buffer[i][0] != 0) + border_encoded[i] = border_buffer[i]; + else + border_encoded[i] = border_ascii[i]; + } + + iconv_close(cd); + + border = border_encoded; + } else +#endif /* USE_UNICODE */ + border = border_ascii; + /* initialize field */ memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char)); x = FLDSIZE_X / 2; @@ -1132,47 +1196,51 @@ fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len, field[x][y] = len; /* assemble title */ - r = snprintf(title, sizeof(title), "[%s %u]", + r = snprintf(title, sizeof(title), "%s %u", sshkey_type(k), sshkey_size(k)); - /* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */ + /* If "type size" won't fit, then try "type"; fits "ED25519-CERT" */ if (r < 0 || r > (int)sizeof(title)) - r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k)); + r = snprintf(title, sizeof(title), "%s", sshkey_type(k)); tlen = (r <= 0) ? 0 : strlen(title); /* assemble hash ID. */ - r = snprintf(hash, sizeof(hash), "[%s]", alg); + r = snprintf(hash, sizeof(hash), "%s", alg); hlen = (r <= 0) ? 0 : strlen(hash); /* output upper border */ p = retval; - *p++ = '+'; - for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++) - *p++ = '-'; + p += sprintf(p, "%s", border[0]); + for (i = 0; i < (FLDSIZE_X - tlen - 2) / 2; i++) + p += sprintf(p, "%s", border[1]); + p += sprintf(p, "%s", border[2]); memcpy(p, title, tlen); p += tlen; - for (i += tlen; i < FLDSIZE_X; i++) - *p++ = '-'; - *p++ = '+'; + p += sprintf(p, "%s", border[3]); + for (i += tlen + 2; i < FLDSIZE_X; i++) + p += sprintf(p, "%s", border[1]); + p += sprintf(p, "%s", border[4]); *p++ = '\n'; /* output content */ for (y = 0; y < FLDSIZE_Y; y++) { - *p++ = '|'; + p += sprintf(p, "%s", border[5]); for (x = 0; x < FLDSIZE_X; x++) *p++ = augmentation_string[MIN(field[x][y], len)]; - *p++ = '|'; + p += sprintf(p, "%s", border[5]); *p++ = '\n'; } /* output lower border */ - *p++ = '+'; - for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++) - *p++ = '-'; + p += sprintf(p, "%s", border[6]); + for (i = 0; i < (FLDSIZE_X - hlen - 2) / 2; i++) + p += sprintf(p, "%s", border[1]); + p += sprintf(p, "%s", border[2]); memcpy(p, hash, hlen); p += hlen; - for (i += hlen; i < FLDSIZE_X; i++) - *p++ = '-'; - *p++ = '+'; + p += sprintf(p, "%s", border[3]); + for (i += hlen + 2; i < FLDSIZE_X; i++) + p += sprintf(p, "%s", border[1]); + p += sprintf(p, "%s", border[7]); return retval; } -- 2.4.5 _______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev