diff --git a/Makefile.am b/Makefile.am index 82101c57..0d95873c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -250,7 +250,7 @@ if NO_STRTONUM nodist_tmux_SOURCES += compat/strtonum.c endif if NO_B64_NTOP -nodist_tmux_SOURCES += compat/b64_ntop.c +nodist_tmux_SOURCES += compat/base64.c endif if NO_CFMAKERAW nodist_tmux_SOURCES += compat/cfmakeraw.c diff --git a/compat.h b/compat.h index f5275223..e1e11ec6 100644 --- a/compat.h +++ b/compat.h @@ -242,9 +242,11 @@ void setproctitle(const char *, ...); #endif #ifndef HAVE_B64_NTOP -/* b64_ntop.c */ -#undef b64_ntop /* for Cygwin */ +/* base64.c */ +#undef b64_ntop +#undef b64_pton int b64_ntop(const char *, size_t, char *, size_t); +int b64_pton(const char *, u_char *, size_t); #endif #ifndef HAVE_FORKPTY diff --git a/compat/b64_ntop.c b/compat/base64.c similarity index 67% rename from compat/b64_ntop.c rename to compat/base64.c index 2b4dc2d4..e90696df 100644 --- a/compat/b64_ntop.c +++ b/compat/base64.c @@ -1,5 +1,7 @@ +/* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */ + /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -41,19 +43,18 @@ */ #include -#include #include - #include #include +#include #include +#include #include + #include #include -#define Assert(Cond) if (!(Cond)) abort() - static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; @@ -122,11 +123,16 @@ static const char Pad64 = '='; */ int -b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { +b64_ntop(src, srclength, target, targsize) + u_char const *src; + size_t srclength; + char *target; + size_t targsize; +{ size_t datalength = 0; - uint8_t input[3]; - uint8_t output[4]; - size_t i; + u_char input[3]; + u_char output[4]; + int i; while (2 < srclength) { input[0] = *src++; @@ -138,10 +144,6 @@ b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; - Assert(output[0] < 64); - Assert(output[1] < 64); - Assert(output[2] < 64); - Assert(output[3] < 64); if (datalength + 4 > targsize) return (-1); @@ -161,9 +163,6 @@ b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); - Assert(output[0] < 64); - Assert(output[1] < 64); - Assert(output[2] < 64); if (datalength + 4 > targsize) return (-1); @@ -180,3 +179,137 @@ b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (datalength); } + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +b64_pton(src, target, targsize) + char const *src; + u_char *target; + size_t targsize; +{ + int tarindex, state, ch; + u_char nextbyte; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = (unsigned char)*src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + nextbyte = ((pos - Base64) & 0x0f) << 4; + if (tarindex + 1 < targsize) + target[tarindex+1] = nextbyte; + else if (nextbyte) + return (-1); + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + nextbyte = ((pos - Base64) & 0x03) << 6; + if (tarindex + 1 < targsize) + target[tarindex+1] = nextbyte; + else if (nextbyte) + return (-1); + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = (unsigned char)*src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = (unsigned char)*src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = (unsigned char)*src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = (unsigned char)*src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && tarindex < targsize && + target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} diff --git a/configure.ac b/configure.ac index d17b6722..acd63f39 100644 --- a/configure.ac +++ b/configure.ac @@ -260,7 +260,7 @@ if test "x$enable_utf8proc" = xyes; then fi AM_CONDITIONAL(HAVE_UTF8PROC, [test "x$enable_utf8proc" = xyes]) -# Check for b64_ntop. +# Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. AC_MSG_CHECKING(for b64_ntop) AC_TRY_LINK( [