diff --git a/configure.ac b/configure.ac index 69d9b22d..0f016fdd 100644 --- a/configure.ac +++ b/configure.ac @@ -129,7 +129,6 @@ TP_ARG_ENABLE(authorization, if test x"$authorization_enabled" = x"yes"; then ADDITIONAL_OBJECTS="$ADDITIONAL_OBJECTS auth.o coding.o" AC_DEFINE(AUTHORIZATION_ENABLE) - AC_CHECK_LIB([crypto], [EVP_MD_CTX_init],[], [AC_MSG_FAILURE([could not find crypto])]) fi dnl Include the transparent proxy support diff --git a/src/auth.c b/src/auth.c index 08a38bb2..ab66ae94 100644 --- a/src/auth.c +++ b/src/auth.c @@ -80,26 +80,33 @@ int check_auth (hashmap_t headers, hashmap_t auth_table) char *val; char *sep; char *credential; - char *plain_credential; + unsigned char *plain_credential; char *username, *password; - size_t length; + ssize_t length; hashmap_iter result_iter; + int success = 0; /* We don't anticipate successful auth, start with failed state */ /* * If there is no auth table allow everything. */ - if (!auth_table) + if (!auth_table) { return 1; + } result_iter = hashmap_find (headers, "Proxy-Authorization"); /* * No Proxy-Authorization header */ - if (hashmap_is_end (headers, result_iter) || - hashmap_return_entry (headers, result_iter, - &key, (void **) &val) < 0) { + if (hashmap_is_end (headers, result_iter)) { + return 0; + } + + length = hashmap_return_entry (headers, result_iter, + &key, (void **) &val); + if (length < 0) { return 0; } + val[length] = 0; /* value is not NULL terminated */ sep = strchr(val, ' '); /* @@ -122,47 +129,58 @@ int check_auth (hashmap_t headers, hashmap_t auth_table) fprintf (stderr, "{credential: %s}\n", credential); #endif - if(base64_decode(credential, (unsigned char **)&plain_credential, &length) != 0) { - free(plain_credential); - return 0; + /* This call allocates a memory buffer, after this we + * need to free plain_credential before exiting -> goto exit; + */ + if( (length = base64_decode(credential, &plain_credential)) < 1) { + goto exit; } #ifndef NDEBUG - fprintf (stderr, "{plain credential: %s}\n", plain_credential); + fprintf (stderr, "{plain credential: '%s'}\n", plain_credential); #endif - sep = strchr(plain_credential, ':'); + sep = strchr((char *)plain_credential, ':'); /* * No ':' in credential */ if (sep == NULL) { - return 0; + goto exit; } *sep = '\0'; - username = plain_credential; + username = (char *) plain_credential; password = sep + 1; +#ifndef NDEBUG + fprintf (stderr, "Username: '%s' Password: '%s'\n", username, password); +#endif + result_iter = hashmap_find (auth_table, username); /* * No such user */ - if (hashmap_is_end (auth_table, result_iter) || - hashmap_return_entry (auth_table, result_iter, - &key, (void **) &val) < 0) { - free(plain_credential); - return 0; + if (hashmap_is_end (auth_table, result_iter)) { + goto exit; + } + length = hashmap_return_entry (auth_table, result_iter, + &key, (void **) &val); + if (length < 0) { + goto exit; } + val[length] = 0; /* value is not NULL terminated */ /* * Wrong password */ if (strcmp(val, password) != 0) { - free(plain_credential); - return 0; + goto exit; } - free(plain_credential); + /* If we arrived here, authentication was successful */ + success = 1; - return 1; + exit: + free(plain_credential); + return success; } diff --git a/src/coding.c b/src/coding.c index 9d9fe8e7..914c88a1 100644 --- a/src/coding.c +++ b/src/coding.c @@ -1,50 +1,254 @@ +/* + * Lots of this code has been taken from the libbas64 project. + * https://github.com/kisom/libbase64/blob/master/src/base64.c + * + * The reason to take this source code is that it is fairly small + * and not too complex, and no need to bring in additional external + * resources for something trivial as BASE64 decoding only + * + * + * Copyright (c) 2013 by Kyle Isom . + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. +*/ + + +#include "common.h" #include "coding.h" -#include -#include - -int base64_decode(char *b64msg, unsigned char **buffer, size_t *length) { - BIO *bio, *b64; - int plain_len; - int b64_len; - /* - * In case that random pointer is freed - */ - *buffer = NULL; - - b64_len = strlen(b64msg); - - /* - * Calculate length of decoded message - */ - plain_len = (b64_len * 3) / 4; - if (b64msg[b64_len-1] == '=') { - plain_len -= 1; - if (b64msg[b64_len-2] == '=') { - plain_len -= 1; - } - } - if (plain_len < 0) { - return -1; - } - (*buffer) = (unsigned char *)malloc(sizeof(unsigned char) * plain_len); - (*buffer)[plain_len-1] = '\0'; - - /* - * Build BIO chain - */ - bio = BIO_new_mem_buf(b64msg, -1); - b64 = BIO_new(BIO_f_base64()); - BIO_push(b64, bio); - - /* - * Decode - */ - if (BIO_read(b64, *buffer, plain_len) != plain_len) { - BIO_free_all(b64); +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + + +/* 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. + */ +size_t base64_decode(char *src, unsigned char **buffer) { + size_t tarindex = 0; + size_t targsize = 0; + int state = 0; + int ch = 0; + char *pos = NULL; + unsigned char *target = NULL; + + /* Garbage in, garbage out. -1 indicates error */ + if (!src) { + (*buffer) = NULL; return -1; } - BIO_free_all(b64); - return 0; + /* Allocate memory buffer to the return buffer */ + targsize = (strlen(src) * 3) / 4; + (*buffer) = (unsigned char *) malloc(targsize); + target = (*buffer); + + while ((ch = *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 + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + 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 = *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 = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *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 = *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 && 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/src/coding.h b/src/coding.h index 59bb24bc..505a9c77 100644 --- a/src/coding.h +++ b/src/coding.h @@ -22,7 +22,6 @@ #ifndef TINYPROXY_CODING_H #define TINYPROXY_CODING_H -#include "common.h" +size_t base64_decode(char *b64msg, unsigned char **buffer); -int base64_decode(char *b64msg, unsigned char **buffer, size_t *length); #endif