diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile | 4 | ||||
-rw-r--r-- | lib/des.c | 646 | ||||
-rw-r--r-- | lib/des.h | 51 | ||||
-rw-r--r-- | lib/http_client.c | 171 | ||||
-rw-r--r-- | lib/http_client.h | 42 | ||||
-rw-r--r-- | lib/json.c | 743 | ||||
-rw-r--r-- | lib/json.h | 192 | ||||
-rw-r--r-- | lib/json_util.c | 62 | ||||
-rw-r--r-- | lib/json_util.h | 35 | ||||
-rw-r--r-- | lib/misc.c | 8 | ||||
-rw-r--r-- | lib/misc.h | 4 | ||||
-rw-r--r-- | lib/oauth2.c | 84 | ||||
-rw-r--r-- | lib/ssl_bogus.c | 76 | ||||
-rw-r--r-- | lib/ssl_gnutls.c | 81 | ||||
-rw-r--r-- | lib/ssl_nss.c | 333 | ||||
-rw-r--r-- | lib/ssl_openssl.c | 71 | ||||
-rw-r--r-- | lib/xmltree.c | 21 | ||||
-rw-r--r-- | lib/xmltree.h | 4 |
18 files changed, 1588 insertions, 1040 deletions
diff --git a/lib/Makefile b/lib/Makefile index 76c41fc3..f20b3797 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -12,7 +12,7 @@ _SRCDIR_ := $(_SRCDIR_)lib/ endif # [SH] Program variables -objects = arc.o base64.o $(DES) $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o oauth2.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o +objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o json.o json_util.o md5.o misc.o oauth.o oauth2.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o LFLAGS += -r @@ -41,6 +41,6 @@ $(objects): ../Makefile.settings Makefile $(objects): %.o: $(_SRCDIR_)%.c @echo '*' Compiling $< - @$(CC) -c $(CFLAGS) $< -o $@ + @$(CC) -c $(CFLAGS) $(CFLAGS_BITLBEE) $< -o $@ -include .depend/*.d diff --git a/lib/des.c b/lib/des.c deleted file mode 100644 index 3b9cc8d5..00000000 --- a/lib/des.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * FIPS-46-3 compliant 3DES implementation - * - * Copyright (C) 2001-2003 Christophe Devine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Modified for BitlBee: Added a function compatible with the existing - * function in ssl_openssl.c, fairly specialised for MSN auth (since that's - * all this is used for at least for now). - * - * Added some consts to the tables at the top, and disabled some 64-bit - * and 128-bit key code that I don't need. - * - * *Many* thanks to Christophe for this compact and easy to import code. - */ - -#include <string.h> -#include <glib.h> -#include "des.h" - -/* the eight DES S-boxes */ - -static const uint32_t SB1[64] = -{ - 0x01010400, 0x00000000, 0x00010000, 0x01010404, - 0x01010004, 0x00010404, 0x00000004, 0x00010000, - 0x00000400, 0x01010400, 0x01010404, 0x00000400, - 0x01000404, 0x01010004, 0x01000000, 0x00000004, - 0x00000404, 0x01000400, 0x01000400, 0x00010400, - 0x00010400, 0x01010000, 0x01010000, 0x01000404, - 0x00010004, 0x01000004, 0x01000004, 0x00010004, - 0x00000000, 0x00000404, 0x00010404, 0x01000000, - 0x00010000, 0x01010404, 0x00000004, 0x01010000, - 0x01010400, 0x01000000, 0x01000000, 0x00000400, - 0x01010004, 0x00010000, 0x00010400, 0x01000004, - 0x00000400, 0x00000004, 0x01000404, 0x00010404, - 0x01010404, 0x00010004, 0x01010000, 0x01000404, - 0x01000004, 0x00000404, 0x00010404, 0x01010400, - 0x00000404, 0x01000400, 0x01000400, 0x00000000, - 0x00010004, 0x00010400, 0x00000000, 0x01010004 -}; - -static const uint32_t SB2[64] = -{ - 0x80108020, 0x80008000, 0x00008000, 0x00108020, - 0x00100000, 0x00000020, 0x80100020, 0x80008020, - 0x80000020, 0x80108020, 0x80108000, 0x80000000, - 0x80008000, 0x00100000, 0x00000020, 0x80100020, - 0x00108000, 0x00100020, 0x80008020, 0x00000000, - 0x80000000, 0x00008000, 0x00108020, 0x80100000, - 0x00100020, 0x80000020, 0x00000000, 0x00108000, - 0x00008020, 0x80108000, 0x80100000, 0x00008020, - 0x00000000, 0x00108020, 0x80100020, 0x00100000, - 0x80008020, 0x80100000, 0x80108000, 0x00008000, - 0x80100000, 0x80008000, 0x00000020, 0x80108020, - 0x00108020, 0x00000020, 0x00008000, 0x80000000, - 0x00008020, 0x80108000, 0x00100000, 0x80000020, - 0x00100020, 0x80008020, 0x80000020, 0x00100020, - 0x00108000, 0x00000000, 0x80008000, 0x00008020, - 0x80000000, 0x80100020, 0x80108020, 0x00108000 -}; - -static const uint32_t SB3[64] = -{ - 0x00000208, 0x08020200, 0x00000000, 0x08020008, - 0x08000200, 0x00000000, 0x00020208, 0x08000200, - 0x00020008, 0x08000008, 0x08000008, 0x00020000, - 0x08020208, 0x00020008, 0x08020000, 0x00000208, - 0x08000000, 0x00000008, 0x08020200, 0x00000200, - 0x00020200, 0x08020000, 0x08020008, 0x00020208, - 0x08000208, 0x00020200, 0x00020000, 0x08000208, - 0x00000008, 0x08020208, 0x00000200, 0x08000000, - 0x08020200, 0x08000000, 0x00020008, 0x00000208, - 0x00020000, 0x08020200, 0x08000200, 0x00000000, - 0x00000200, 0x00020008, 0x08020208, 0x08000200, - 0x08000008, 0x00000200, 0x00000000, 0x08020008, - 0x08000208, 0x00020000, 0x08000000, 0x08020208, - 0x00000008, 0x00020208, 0x00020200, 0x08000008, - 0x08020000, 0x08000208, 0x00000208, 0x08020000, - 0x00020208, 0x00000008, 0x08020008, 0x00020200 -}; - -static const uint32_t SB4[64] = -{ - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802080, 0x00800081, 0x00800001, 0x00002001, - 0x00000000, 0x00802000, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00800080, 0x00800001, - 0x00000001, 0x00002000, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002001, 0x00002080, - 0x00800081, 0x00000001, 0x00002080, 0x00800080, - 0x00002000, 0x00802080, 0x00802081, 0x00000081, - 0x00800080, 0x00800001, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00000000, 0x00802000, - 0x00002080, 0x00800080, 0x00800081, 0x00000001, - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802081, 0x00000081, 0x00000001, 0x00002000, - 0x00800001, 0x00002001, 0x00802080, 0x00800081, - 0x00002001, 0x00002080, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002000, 0x00802080 -}; - -static const uint32_t SB5[64] = -{ - 0x00000100, 0x02080100, 0x02080000, 0x42000100, - 0x00080000, 0x00000100, 0x40000000, 0x02080000, - 0x40080100, 0x00080000, 0x02000100, 0x40080100, - 0x42000100, 0x42080000, 0x00080100, 0x40000000, - 0x02000000, 0x40080000, 0x40080000, 0x00000000, - 0x40000100, 0x42080100, 0x42080100, 0x02000100, - 0x42080000, 0x40000100, 0x00000000, 0x42000000, - 0x02080100, 0x02000000, 0x42000000, 0x00080100, - 0x00080000, 0x42000100, 0x00000100, 0x02000000, - 0x40000000, 0x02080000, 0x42000100, 0x40080100, - 0x02000100, 0x40000000, 0x42080000, 0x02080100, - 0x40080100, 0x00000100, 0x02000000, 0x42080000, - 0x42080100, 0x00080100, 0x42000000, 0x42080100, - 0x02080000, 0x00000000, 0x40080000, 0x42000000, - 0x00080100, 0x02000100, 0x40000100, 0x00080000, - 0x00000000, 0x40080000, 0x02080100, 0x40000100 -}; - -static const uint32_t SB6[64] = -{ - 0x20000010, 0x20400000, 0x00004000, 0x20404010, - 0x20400000, 0x00000010, 0x20404010, 0x00400000, - 0x20004000, 0x00404010, 0x00400000, 0x20000010, - 0x00400010, 0x20004000, 0x20000000, 0x00004010, - 0x00000000, 0x00400010, 0x20004010, 0x00004000, - 0x00404000, 0x20004010, 0x00000010, 0x20400010, - 0x20400010, 0x00000000, 0x00404010, 0x20404000, - 0x00004010, 0x00404000, 0x20404000, 0x20000000, - 0x20004000, 0x00000010, 0x20400010, 0x00404000, - 0x20404010, 0x00400000, 0x00004010, 0x20000010, - 0x00400000, 0x20004000, 0x20000000, 0x00004010, - 0x20000010, 0x20404010, 0x00404000, 0x20400000, - 0x00404010, 0x20404000, 0x00000000, 0x20400010, - 0x00000010, 0x00004000, 0x20400000, 0x00404010, - 0x00004000, 0x00400010, 0x20004010, 0x00000000, - 0x20404000, 0x20000000, 0x00400010, 0x20004010 -}; - -static const uint32_t SB7[64] = -{ - 0x00200000, 0x04200002, 0x04000802, 0x00000000, - 0x00000800, 0x04000802, 0x00200802, 0x04200800, - 0x04200802, 0x00200000, 0x00000000, 0x04000002, - 0x00000002, 0x04000000, 0x04200002, 0x00000802, - 0x04000800, 0x00200802, 0x00200002, 0x04000800, - 0x04000002, 0x04200000, 0x04200800, 0x00200002, - 0x04200000, 0x00000800, 0x00000802, 0x04200802, - 0x00200800, 0x00000002, 0x04000000, 0x00200800, - 0x04000000, 0x00200800, 0x00200000, 0x04000802, - 0x04000802, 0x04200002, 0x04200002, 0x00000002, - 0x00200002, 0x04000000, 0x04000800, 0x00200000, - 0x04200800, 0x00000802, 0x00200802, 0x04200800, - 0x00000802, 0x04000002, 0x04200802, 0x04200000, - 0x00200800, 0x00000000, 0x00000002, 0x04200802, - 0x00000000, 0x00200802, 0x04200000, 0x00000800, - 0x04000002, 0x04000800, 0x00000800, 0x00200002 -}; - -static const uint32_t SB8[64] = -{ - 0x10001040, 0x00001000, 0x00040000, 0x10041040, - 0x10000000, 0x10001040, 0x00000040, 0x10000000, - 0x00040040, 0x10040000, 0x10041040, 0x00041000, - 0x10041000, 0x00041040, 0x00001000, 0x00000040, - 0x10040000, 0x10000040, 0x10001000, 0x00001040, - 0x00041000, 0x00040040, 0x10040040, 0x10041000, - 0x00001040, 0x00000000, 0x00000000, 0x10040040, - 0x10000040, 0x10001000, 0x00041040, 0x00040000, - 0x00041040, 0x00040000, 0x10041000, 0x00001000, - 0x00000040, 0x10040040, 0x00001000, 0x00041040, - 0x10001000, 0x00000040, 0x10000040, 0x10040000, - 0x10040040, 0x10000000, 0x00040000, 0x10001040, - 0x00000000, 0x10041040, 0x00040040, 0x10000040, - 0x10040000, 0x10001000, 0x10001040, 0x00000000, - 0x10041040, 0x00041000, 0x00041000, 0x00001040, - 0x00001040, 0x00040040, 0x10000000, 0x10041000 -}; - -/* PC1: left and right halves bit-swap */ - -static const uint32_t LHs[16] = -{ - 0x00000000, 0x00000001, 0x00000100, 0x00000101, - 0x00010000, 0x00010001, 0x00010100, 0x00010101, - 0x01000000, 0x01000001, 0x01000100, 0x01000101, - 0x01010000, 0x01010001, 0x01010100, 0x01010101 -}; - -static const uint32_t RHs[16] = -{ - 0x00000000, 0x01000000, 0x00010000, 0x01010000, - 0x00000100, 0x01000100, 0x00010100, 0x01010100, - 0x00000001, 0x01000001, 0x00010001, 0x01010001, - 0x00000101, 0x01000101, 0x00010101, 0x01010101, -}; - -/* platform-independant 32-bit integer manipulation macros */ - -#define GET_UINT32(n,b,i) \ -{ \ - (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ - | ( (uint32_t) (b)[(i) + 1] << 16 ) \ - | ( (uint32_t) (b)[(i) + 2] << 8 ) \ - | ( (uint32_t) (b)[(i) + 3] ); \ -} - -#define PUT_UINT32(n,b,i) \ -{ \ - (b)[(i) ] = (uint8_t) ( (n) >> 24 ); \ - (b)[(i) + 1] = (uint8_t) ( (n) >> 16 ); \ - (b)[(i) + 2] = (uint8_t) ( (n) >> 8 ); \ - (b)[(i) + 3] = (uint8_t) ( (n) ); \ -} - -/* Initial Permutation macro */ - -#define DES_IP(X,Y) \ -{ \ - T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ - T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ - T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ - T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ - Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ - T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ - X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ -} - -/* Final Permutation macro */ - -#define DES_FP(X,Y) \ -{ \ - X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ - T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ - Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ - T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ - T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ - T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ - T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ -} - -/* DES round macro */ - -#define DES_ROUND(X,Y) \ -{ \ - T = *SK++ ^ X; \ - Y ^= SB8[ (T ) & 0x3F ] ^ \ - SB6[ (T >> 8) & 0x3F ] ^ \ - SB4[ (T >> 16) & 0x3F ] ^ \ - SB2[ (T >> 24) & 0x3F ]; \ - \ - T = *SK++ ^ ((X << 28) | (X >> 4)); \ - Y ^= SB7[ (T ) & 0x3F ] ^ \ - SB5[ (T >> 8) & 0x3F ] ^ \ - SB3[ (T >> 16) & 0x3F ] ^ \ - SB1[ (T >> 24) & 0x3F ]; \ -} - -/* DES key schedule */ - -int des_main_ks( uint32_t SK[32], const uint8_t key[8] ) -{ - int i; - uint32_t X, Y, T; - - GET_UINT32( X, key, 0 ); - GET_UINT32( Y, key, 4 ); - - /* Permuted Choice 1 */ - - T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); - T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); - - X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) - | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) - | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) - | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); - - Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) - | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) - | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) - | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); - - X &= 0x0FFFFFFF; - Y &= 0x0FFFFFFF; - - /* calculate subkeys */ - - for( i = 0; i < 16; i++ ) - { - if( i < 2 || i == 8 || i == 15 ) - { - X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; - Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; - } - else - { - X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; - Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; - } - - *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) - | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) - | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) - | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) - | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) - | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) - | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) - | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) - | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) - | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) - | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); - - *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) - | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) - | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) - | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) - | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) - | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) - | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) - | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) - | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) - | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) - | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); - } - - return( 0 ); -} - -#if TEST -int des_set_key( des_context *ctx, uint8_t key[8] ) -{ - int i; - - /* setup encryption subkeys */ - - des_main_ks( ctx->esk, key ); - - /* setup decryption subkeys */ - - for( i = 0; i < 32; i += 2 ) - { - ctx->dsk[i ] = ctx->esk[30 - i]; - ctx->dsk[i + 1] = ctx->esk[31 - i]; - } - - return( 0 ); -} - -/* DES 64-bit block encryption/decryption */ - -void des_crypt( uint32_t SK[32], uint8_t input[8], uint8_t output[8] ) -{ - uint32_t X, Y, T; - - GET_UINT32( X, input, 0 ); - GET_UINT32( Y, input, 4 ); - - DES_IP( X, Y ); - - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - - DES_FP( Y, X ); - - PUT_UINT32( Y, output, 0 ); - PUT_UINT32( X, output, 4 ); -} - -void des_encrypt( des_context *ctx, uint8_t input[8], uint8_t output[8] ) -{ - des_crypt( ctx->esk, input, output ); -} - -void des_decrypt( des_context *ctx, uint8_t input[8], uint8_t output[8] ) -{ - des_crypt( ctx->dsk, input, output ); -} - -/* Triple-DES key schedule */ - -int des3_set_2keys( des3_context *ctx, const uint8_t key1[8], const uint8_t key2[8] ) -{ - int i; - - des_main_ks( ctx->esk , key1 ); - des_main_ks( ctx->dsk + 32, key2 ); - - for( i = 0; i < 32; i += 2 ) - { - ctx->dsk[i ] = ctx->esk[30 - i]; - ctx->dsk[i + 1] = ctx->esk[31 - i]; - - ctx->esk[i + 32] = ctx->dsk[62 - i]; - ctx->esk[i + 33] = ctx->dsk[63 - i]; - - ctx->esk[i + 64] = ctx->esk[ i]; - ctx->esk[i + 65] = ctx->esk[ 1 + i]; - - ctx->dsk[i + 64] = ctx->dsk[ i]; - ctx->dsk[i + 65] = ctx->dsk[ 1 + i]; - } - - return( 0 ); -} -#endif - -int des3_set_3keys( des3_context *ctx, const uint8_t key1[8], const uint8_t key2[8], - const uint8_t key3[8] ) -{ - int i; - - des_main_ks( ctx->esk , key1 ); - des_main_ks( ctx->dsk + 32, key2 ); - des_main_ks( ctx->esk + 64, key3 ); - - for( i = 0; i < 32; i += 2 ) - { - ctx->dsk[i ] = ctx->esk[94 - i]; - ctx->dsk[i + 1] = ctx->esk[95 - i]; - - ctx->esk[i + 32] = ctx->dsk[62 - i]; - ctx->esk[i + 33] = ctx->dsk[63 - i]; - - ctx->dsk[i + 64] = ctx->esk[30 - i]; - ctx->dsk[i + 65] = ctx->esk[31 - i]; - } - - return( 0 ); -} - -/* Triple-DES 64-bit block encryption/decryption */ - -void des3_crypt( uint32_t SK[96], uint8_t input[8], uint8_t output[8] ) -{ - uint32_t X, Y, T; - - GET_UINT32( X, input, 0 ); - GET_UINT32( Y, input, 4 ); - - DES_IP( X, Y ); - - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - - DES_ROUND( X, Y ); DES_ROUND( Y, X ); - DES_ROUND( X, Y ); DES_ROUND( Y, X ); - DES_ROUND( X, Y ); DES_ROUND( Y, X ); - DES_ROUND( X, Y ); DES_ROUND( Y, X ); - DES_ROUND( X, Y ); DES_ROUND( Y, X ); - DES_ROUND( X, Y ); DES_ROUND( Y, X ); - DES_ROUND( X, Y ); DES_ROUND( Y, X ); - DES_ROUND( X, Y ); DES_ROUND( Y, X ); - - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - DES_ROUND( Y, X ); DES_ROUND( X, Y ); - - DES_FP( Y, X ); - - PUT_UINT32( Y, output, 0 ); - PUT_UINT32( X, output, 4 ); -} - -void des3_encrypt( des3_context *ctx, uint8_t input[8], uint8_t output[8] ) -{ - des3_crypt( ctx->esk, input, output ); -} - -void des3_decrypt( des3_context *ctx, uint8_t input[8], uint8_t output[8] ) -{ - des3_crypt( ctx->dsk, input, output ); -} - -size_t ssl_des3_encrypt( const unsigned char *key, size_t key_len, const unsigned char *input, - size_t input_len, const unsigned char *iv, unsigned char **res ) -{ - des3_context ctx3; - size_t off; - uint8_t buf[8]; - - /* Keep it simple, for as long as this is just used for MSN auth anyway. */ - if( key_len != 24 || ( input_len % 8 ) != 0 ) - return 0; - - *res = g_malloc( input_len ); - des3_set_3keys( &ctx3, key, key + 8, key + 16 ); - - /* This loop does CBC 3DES. */ - memcpy( buf, iv, 8 ); - for( off = 0; off < input_len; off += 8 ) - { - int i; - - for( i = 0; i < 8; i ++ ) - buf[i] ^= input[off+i]; - des3_encrypt( &ctx3, buf, buf ); - memcpy( *res + off, buf, 8 ); - } - - return input_len; -} - -#ifdef TEST - -#include <string.h> -#include <stdio.h> - -/* - * Triple-DES Monte Carlo Test: ECB mode - * source: NIST - tripledes-vectors.zip - */ - -static const unsigned char DES3_keys[3][8] = -{ - { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, - { 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01 }, - { 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 } -}; - -static const unsigned char DES3_init[8] = -{ - 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 -}; - -static const unsigned char DES3_enc_test[3][8] = -{ - { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, - { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, - { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } -}; - -static const unsigned char DES3_dec_test[3][8] = -{ - { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, - { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, - { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } -}; - -int main( void ) -{ - int m, n, i; - des_context ctx; - des3_context ctx3; - unsigned char buf[8]; - - for( m = 0; m < 2; m++ ) - { - printf( "\n Triple-DES Monte Carlo Test (ECB mode) - " ); - - if( m == 0 ) printf( "encryption\n\n" ); - if( m == 1 ) printf( "decryption\n\n" ); - - for( n = 0; n < 3; n++ ) - { - printf( " Test %d, key size = %3d bits: ", - n + 1, 64 + n * 64 ); - - fflush( stdout ); - - memcpy( buf, DES3_init, 8 ); - - switch( n ) - { - case 0: - des_set_key( &ctx, DES3_keys[0] ); - break; - - case 1: - des3_set_2keys( &ctx3, DES3_keys[0], - DES3_keys[1] ); - break; - - case 2: - des3_set_3keys( &ctx3, DES3_keys[0], - DES3_keys[1], - DES3_keys[2] ); - break; - } - - for( i = 0; i < 10000; i++ ) - { - if( n == 0 ) - { - if( m == 0 ) des_encrypt( &ctx, buf, buf ); - if( m == 1 ) des_decrypt( &ctx, buf, buf ); - } - else - { - if( m == 0 ) des3_encrypt( &ctx3, buf, buf ); - if( m == 1 ) des3_decrypt( &ctx3, buf, buf ); - } - } - - if( ( m == 0 && memcmp( buf, DES3_enc_test[n], 8 ) ) || - ( m == 1 && memcmp( buf, DES3_dec_test[n], 8 ) ) ) - { - printf( "failed!\n" ); - return( 1 ); - } - - printf( "passed.\n" ); - } - } - - printf( "\n" ); - - return( 0 ); -} - -#endif diff --git a/lib/des.h b/lib/des.h deleted file mode 100644 index 92fbfd22..00000000 --- a/lib/des.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * FIPS-46-3 compliant 3DES implementation - * - * Copyright (C) 2001-2003 Christophe Devine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _DES_H -#define _DES_H - -#include <stdint.h> - -typedef struct -{ - uint32_t esk[32]; /* DES encryption subkeys */ - uint32_t dsk[32]; /* DES decryption subkeys */ -} -des_context; - -typedef struct -{ - uint32_t esk[96]; /* Triple-DES encryption subkeys */ - uint32_t dsk[96]; /* Triple-DES decryption subkeys */ -} -des3_context; - -int des_set_key( des_context *ctx, uint8_t key[8] ); -void des_encrypt( des_context *ctx, uint8_t input[8], uint8_t output[8] ); -void des_decrypt( des_context *ctx, uint8_t input[8], uint8_t output[8] ); - -int des3_set_2keys( des3_context *ctx, const uint8_t key1[8], const uint8_t key2[8] ); -int des3_set_3keys( des3_context *ctx, const uint8_t key1[8], const uint8_t key2[8], - const uint8_t key3[8] ); - -void des3_encrypt( des3_context *ctx, uint8_t input[8], uint8_t output[8] ); -void des3_decrypt( des3_context *ctx, uint8_t input[8], uint8_t output[8] ); - -#endif /* des.h */ diff --git a/lib/http_client.c b/lib/http_client.c index 98a99f7c..b384e1f0 100644 --- a/lib/http_client.c +++ b/lib/http_client.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2011 Wilmer van der Gaast and others * + * Copyright 2002-2012 Wilmer van der Gaast and others * \********************************************************************/ /* HTTP(S) module */ @@ -72,7 +72,7 @@ struct http_request *http_dorequest( char *host, int port, int ssl, char *reques if( getenv( "BITLBEE_DEBUG" ) ) printf( "About to send HTTP request:\n%s\n", req->request ); - return( req ); + return req; } struct http_request *http_dorequest_url( char *url_string, http_input_function func, gpointer data ) @@ -192,12 +192,14 @@ static gboolean http_ssl_connected( gpointer data, int returncode, void *source, return http_connected( data, req->fd, cond ); } +static gboolean http_handle_headers( struct http_request *req ); + static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ) { struct http_request *req = data; - int evil_server = 0; - char buffer[2048]; - char *end1, *end2; + char buffer[4096]; + char *s; + size_t content_length; int st; if( req->inpa > 0 ) @@ -216,12 +218,12 @@ static gboolean http_incoming_data( gpointer data, int source, b_input_condition servers that LOVE to send invalid TLS packets that abort connections! \o/ */ - goto got_reply; + goto eof; } } else if( st == 0 ) { - goto got_reply; + goto eof; } } else @@ -237,28 +239,70 @@ static gboolean http_incoming_data( gpointer data, int source, b_input_condition } else if( st == 0 ) { - goto got_reply; + goto eof; } } - if( st > 0 ) + if( st > 0 && !req->sbuf ) { req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 ); memcpy( req->reply_headers + req->bytes_read, buffer, st ); req->bytes_read += st; + + st = 0; + } + + if( st >= 0 && ( req->flags & HTTPC_STREAMING ) ) + { + if( !req->reply_body && + ( strstr( req->reply_headers, "\r\n\r\n" ) || + strstr( req->reply_headers, "\n\n" ) ) ) + { + size_t hlen; + + /* We've now received all headers, so process them once + before we start feeding back data. */ + if( !http_handle_headers( req ) ) + return FALSE; + + hlen = req->reply_body - req->reply_headers; + + req->sblen = req->bytes_read - hlen; + req->sbuf = g_memdup( req->reply_body, req->sblen + 1 ); + req->reply_headers = g_realloc( req->reply_headers, hlen + 1 ); + + req->reply_body = req->sbuf; + } + + if( st > 0 ) + { + int pos = req->reply_body - req->sbuf; + req->sbuf = g_realloc( req->sbuf, req->sblen + st + 1 ); + memcpy( req->sbuf + req->sblen, buffer, st ); + req->bytes_read += st; + req->sblen += st; + req->sbuf[req->sblen] = '\0'; + req->reply_body = req->sbuf + pos; + req->body_size = req->sblen - pos; + } + + if( req->reply_body ) + req->func( req ); } + if( ssl_pending( req->ssl ) ) + return http_incoming_data( data, source, cond ); + /* There will be more! */ req->inpa = b_input_add( req->fd, req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_READ, http_incoming_data, req ); - if( ssl_pending( req->ssl ) ) - return http_incoming_data( data, source, cond ); - else - return FALSE; + return FALSE; -got_reply: +eof: + req->flags |= HTTPC_EOF; + /* Maybe if the webserver is overloaded, or when there's bad SSL support... */ if( req->bytes_read == 0 ) @@ -267,8 +311,50 @@ got_reply: goto cleanup; } + if( !( req->flags & HTTPC_STREAMING ) ) + { + /* Returns FALSE if we were redirected, in which case we should abort + and not run any callback yet. */ + if( !http_handle_headers( req ) ) + return FALSE; + } + +cleanup: + if( req->ssl ) + ssl_disconnect( req->ssl ); + else + closesocket( req->fd ); + + if( ( s = get_rfc822_header( req->reply_headers, "Content-Length", 0 ) ) && + sscanf( s, "%zd", &content_length ) == 1 ) + { + if( content_length < req->body_size ) + { + req->status_code = -1; + g_free( req->status_string ); + req->status_string = g_strdup( "Response truncated" ); + } + } + g_free( s ); + + if( getenv( "BITLBEE_DEBUG" ) && req ) + printf( "Finishing HTTP request with status: %s\n", + req->status_string ? req->status_string : "NULL" ); + + req->func( req ); + http_free( req ); + return FALSE; +} + +/* Splits headers and body. Checks result code, in case of 300s it'll handle + redirects. If this returns FALSE, don't call any callbacks! */ +static gboolean http_handle_headers( struct http_request *req ) +{ + char *end1, *end2; + int evil_server = 0; + /* Zero termination is very convenient. */ - req->reply_headers[req->bytes_read] = 0; + req->reply_headers[req->bytes_read] = '\0'; /* Find the separation between headers and body, and keep stupid webservers in mind. */ @@ -287,7 +373,7 @@ got_reply: else { req->status_string = g_strdup( "Malformed HTTP reply" ); - goto cleanup; + return TRUE; } *end1 = 0; @@ -304,7 +390,7 @@ got_reply: if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) { - if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 ) + if( sscanf( end1 + 1, "%hd", &req->status_code ) != 1 ) { req->status_string = g_strdup( "Can't parse status code" ); req->status_code = -1; @@ -347,7 +433,7 @@ got_reply: if( loc == NULL ) /* We can't handle this redirect... */ { req->status_string = g_strdup( "Can't locate Location: header" ); - goto cleanup; + return TRUE; } loc += 11; @@ -367,7 +453,7 @@ got_reply: req->status_string = g_strdup( "Can't handle recursive redirects" ); - goto cleanup; + return TRUE; } else { @@ -378,7 +464,7 @@ got_reply: s = strstr( loc, "\r\n" ); if( s == NULL ) - goto cleanup; + return TRUE; url = g_new0( url_t, 1 ); *s = 0; @@ -387,7 +473,7 @@ got_reply: { req->status_string = g_strdup( "Malformed redirect URL" ); g_free( url ); - goto cleanup; + return TRUE; } /* Find all headers and, if necessary, the POST request contents. @@ -399,7 +485,7 @@ got_reply: { req->status_string = g_strdup( "Error while rebuilding request string" ); g_free( url ); - goto cleanup; + return TRUE; } /* More or less HTTP/1.0 compliant, from my reading of RFC 2616. @@ -465,7 +551,7 @@ got_reply: { req->status_string = g_strdup( "Connection problem during redirect" ); g_free( new_request ); - goto cleanup; + return TRUE; } g_free( req->request ); @@ -478,23 +564,40 @@ got_reply: return FALSE; } - /* Assume that a closed connection means we're finished, this indeed - breaks with keep-alive connections and faulty connections. */ - req->finished = 1; + return TRUE; +} + +void http_flush_bytes( struct http_request *req, size_t len ) +{ + if( len <= 0 || len > req->body_size || !( req->flags & HTTPC_STREAMING ) ) + return; + + req->reply_body += len; + req->body_size -= len; + + if( req->reply_body - req->sbuf >= 512 ) + { + char *new = g_memdup( req->reply_body, req->body_size + 1 ); + g_free( req->sbuf ); + req->reply_body = req->sbuf = new; + req->sblen = req->body_size; + } +} -cleanup: +void http_close( struct http_request *req ) +{ + if( !req ) + return; + + if( req->inpa > 0 ) + b_event_remove( req->inpa ); + if( req->ssl ) ssl_disconnect( req->ssl ); else closesocket( req->fd ); - if( getenv( "BITLBEE_DEBUG" ) && req ) - printf( "Finishing HTTP request with status: %s\n", - req->status_string ? req->status_string : "NULL" ); - - req->func( req ); http_free( req ); - return FALSE; } static void http_free( struct http_request *req ) @@ -502,6 +605,6 @@ static void http_free( struct http_request *req ) g_free( req->request ); g_free( req->reply_headers ); g_free( req->status_string ); + g_free( req->sbuf ); g_free( req ); } - diff --git a/lib/http_client.h b/lib/http_client.h index 27c484ff..ca427118 100644 --- a/lib/http_client.h +++ b/lib/http_client.h @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2005 Wilmer van der Gaast and others * + * Copyright 2002-2012 Wilmer van der Gaast and others * \********************************************************************/ /* HTTP(S) module */ @@ -25,23 +25,26 @@ /* http_client allows you to talk (asynchronously, again) to HTTP servers. In the "background" it will send the whole query and wait for a complete - response to come back. Right now it's only used by the MSN Passport - authentication code, but it might be useful for other things too (for - example the AIM usericon patch uses this so icons can be stored on - webservers instead of the local filesystem). + response to come back. Initially written for MS Passport authentication, + but used for many other things now like OAuth and Twitter. - Didn't test this too much, but it seems to work well. Just don't look - at the code that handles HTTP 30x redirects. ;-) The function is - probably not very useful for downloading lots of data since it keeps - everything in a memory buffer until the download is completed (and - can't pass any data or whatever before then). It's very useful for - doing quick requests without blocking the whole program, though. */ + It's very useful for doing quick requests without blocking the whole + program. Unfortunately it doesn't support fancy stuff like HTTP keep- + alives. */ #include <glib.h> #include "ssl_client.h" struct http_request; +typedef enum http_client_flags +{ + HTTPC_STREAMING = 1, + HTTPC_EOF = 2, + + /* Let's reserve 0x1000000+ for lib users. */ +} http_client_flags_t; + /* Your callback function should look like this: */ typedef void (*http_input_function)( struct http_request * ); @@ -52,28 +55,31 @@ struct http_request { char *request; /* The request to send to the server. */ int request_length; /* Its size. */ - int status_code; /* The numeric HTTP status code. (Or -1 + short status_code; /* The numeric HTTP status code. (Or -1 if something really went wrong) */ char *status_string; /* The error text. */ char *reply_headers; char *reply_body; int body_size; /* The number of bytes in reply_body. */ - int finished; /* Set to non-0 if the request was completed - successfully. */ - int redir_ttl; /* You can set it to 0 if you don't want + short redir_ttl; /* You can set it to 0 if you don't want http_client to follow them. */ + http_client_flags_t flags; + http_input_function func; gpointer data; /* Please don't touch the things down here, you shouldn't need them. */ - void *ssl; int fd; int inpa; int bytes_written; int bytes_read; + + /* Used in streaming mode. Caller should read from reply_body. */ + char *sbuf; + size_t sblen; }; /* The _url variant is probably more useful than the raw version. The raw @@ -82,3 +88,7 @@ struct http_request are also supported (using ssl_client). */ struct http_request *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); struct http_request *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); + +/* For streaming connections only; flushes len bytes at the start of the buffer. */ +void http_flush_bytes( struct http_request *req, size_t len ); +void http_close( struct http_request *req ); diff --git a/lib/json.c b/lib/json.c new file mode 100644 index 00000000..fb973001 --- /dev/null +++ b/lib/json.c @@ -0,0 +1,743 @@ + +/* vim: set et ts=3 sw=3 ft=c: + * + * Copyright (C) 2012 James McLaughlin et al. All rights reserved. + * https://github.com/udp/json-parser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "json.h" + +#ifdef _MSC_VER + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif +#endif + +#ifdef __cplusplus + const struct _json_value json_value_none; /* zero-d by ctor */ +#else + const struct _json_value json_value_none = { 0 }; +#endif + +#include <glib.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +typedef unsigned short json_uchar; + +static unsigned char hex_value (json_char c) +{ + if (c >= 'A' && c <= 'F') + return (c - 'A') + 10; + + if (c >= 'a' && c <= 'f') + return (c - 'a') + 10; + + if (c >= '0' && c <= '9') + return c - '0'; + + return 0xFF; +} + +typedef struct +{ + json_settings settings; + int first_pass; + + unsigned long used_memory; + + unsigned int uint_max; + unsigned long ulong_max; + +} json_state; + +static void * json_alloc (json_state * state, unsigned long size, int zero) +{ + void * mem; + + if ((state->ulong_max - state->used_memory) < size) + return 0; + + if (state->settings.max_memory + && (state->used_memory += size) > state->settings.max_memory) + { + return 0; + } + + if (! (mem = zero ? calloc (size, 1) : malloc (size))) + return 0; + + return mem; +} + +static int new_value + (json_state * state, json_value ** top, json_value ** root, json_value ** alloc, json_type type) +{ + json_value * value; + int values_size; + + if (!state->first_pass) + { + value = *top = *alloc; + *alloc = (*alloc)->_reserved.next_alloc; + + if (!*root) + *root = value; + + switch (value->type) + { + case json_array: + + if (! (value->u.array.values = (json_value **) json_alloc + (state, value->u.array.length * sizeof (json_value *), 0)) ) + { + return 0; + } + + break; + + case json_object: + + values_size = sizeof (*value->u.object.values) * value->u.object.length; + + if (! ((*(void **) &value->u.object.values) = json_alloc + (state, values_size + ((unsigned long) value->u.object.values), 0)) ) + { + return 0; + } + + value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size; + + break; + + case json_string: + + if (! (value->u.string.ptr = (json_char *) json_alloc + (state, (value->u.string.length + 1) * sizeof (json_char), 0)) ) + { + return 0; + } + + break; + + default: + break; + }; + + value->u.array.length = 0; + + return 1; + } + + value = (json_value *) json_alloc (state, sizeof (json_value), 1); + + if (!value) + return 0; + + if (!*root) + *root = value; + + value->type = type; + value->parent = *top; + + if (*alloc) + (*alloc)->_reserved.next_alloc = value; + + *alloc = *top = value; + + return 1; +} + +#define e_off \ + ((int) (i - cur_line_begin)) + +#define whitespace \ + case '\n': ++ cur_line; cur_line_begin = i; \ + case ' ': case '\t': case '\r' + +#define string_add(b) \ + do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0); + +const static int + flag_next = 1, flag_reproc = 2, flag_need_comma = 4, flag_seek_value = 8, flag_exponent = 16, + flag_got_exponent_sign = 32, flag_escaped = 64, flag_string = 128, flag_need_colon = 256, + flag_done = 512; + +json_value * json_parse_ex (json_settings * settings, const json_char * json, char * error_buf) +{ + json_char error [128]; + unsigned int cur_line; + const json_char * cur_line_begin, * i; + json_value * top, * root, * alloc = 0; + json_state state; + int flags; + + error[0] = '\0'; + + memset (&state, 0, sizeof (json_state)); + memcpy (&state.settings, settings, sizeof (json_settings)); + + memset (&state.uint_max, 0xFF, sizeof (state.uint_max)); + memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); + + state.uint_max -= 8; /* limit of how much can be added before next check */ + state.ulong_max -= 8; + + for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass) + { + json_uchar uchar; + unsigned char uc_b1, uc_b2, uc_b3, uc_b4; + json_char * string = 0; + unsigned int string_length = 0; + + top = root = 0; + flags = flag_seek_value; + + cur_line = 1; + cur_line_begin = json; + + for (i = json ;; ++ i) + { + json_char b = *i; + + if (flags & flag_done) + { + if (!b) + break; + + switch (b) + { + whitespace: + continue; + + default: + sprintf (error, "%d:%d: Trailing garbage: `%c`", cur_line, e_off, b); + goto e_failed; + }; + } + + if (flags & flag_string) + { + if (!b) + { sprintf (error, "Unexpected EOF in string (at %d:%d)", cur_line, e_off); + goto e_failed; + } + + if (string_length > state.uint_max) + goto e_overflow; + + if (flags & flag_escaped) + { + flags &= ~ flag_escaped; + + switch (b) + { + case 'b': string_add ('\b'); break; + case 'f': string_add ('\f'); break; + case 'n': string_add ('\n'); break; + case 'r': string_add ('\r'); break; + case 't': string_add ('\t'); break; + case 'u': + + if ((uc_b1 = hex_value (*++ i)) == 0xFF || (uc_b2 = hex_value (*++ i)) == 0xFF + || (uc_b3 = hex_value (*++ i)) == 0xFF || (uc_b4 = hex_value (*++ i)) == 0xFF) + { + sprintf (error, "Invalid character value `%c` (at %d:%d)", b, cur_line, e_off); + goto e_failed; + } + + uc_b1 = uc_b1 * 16 + uc_b2; + uc_b2 = uc_b3 * 16 + uc_b4; + + uchar = ((json_char) uc_b1) * 256 + uc_b2; + + if (sizeof (json_char) >= sizeof (json_uchar) || (uc_b1 == 0 && uc_b2 <= 0x7F)) + { + string_add ((json_char) uchar); + break; + } + + if (uchar <= 0x7FF) + { + if (state.first_pass) + string_length += 2; + else + { string [string_length ++] = 0xC0 | ((uc_b2 & 0xC0) >> 6) | ((uc_b1 & 0x7) << 2); + string [string_length ++] = 0x80 | (uc_b2 & 0x3F); + } + + break; + } + + if (state.first_pass) + string_length += 3; + else + { string [string_length ++] = 0xE0 | ((uc_b1 & 0xF0) >> 4); + string [string_length ++] = 0x80 | ((uc_b1 & 0xF) << 2) | ((uc_b2 & 0xC0) >> 6); + string [string_length ++] = 0x80 | (uc_b2 & 0x3F); + } + + break; + + default: + string_add (b); + }; + + continue; + } + + if (b == '\\') + { + flags |= flag_escaped; + continue; + } + + if (b == '"') + { + if (!state.first_pass) + string [string_length] = 0; + + flags &= ~ flag_string; + string = 0; + + switch (top->type) + { + case json_string: + + top->u.string.length = string_length; + flags |= flag_next; + + break; + + case json_object: + + if (state.first_pass) + (*(json_char **) &top->u.object.values) += string_length + 1; + else + { + top->u.object.values [top->u.object.length].name + = (json_char *) top->_reserved.object_mem; + + (*(json_char **) &top->_reserved.object_mem) += string_length + 1; + } + + flags |= flag_seek_value | flag_need_colon; + continue; + + default: + break; + }; + } + else + { + string_add (b); + continue; + } + } + + if (flags & flag_seek_value) + { + switch (b) + { + whitespace: + continue; + + case ']': + + if (top->type == json_array) + flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; + else if (!state.settings.settings & json_relaxed_commas) + { sprintf (error, "%d:%d: Unexpected ]", cur_line, e_off); + goto e_failed; + } + + break; + + default: + + if (flags & flag_need_comma) + { + if (b == ',') + { flags &= ~ flag_need_comma; + continue; + } + else + { sprintf (error, "%d:%d: Expected , before %c", cur_line, e_off, b); + goto e_failed; + } + } + + if (flags & flag_need_colon) + { + if (b == ':') + { flags &= ~ flag_need_colon; + continue; + } + else + { sprintf (error, "%d:%d: Expected : before %c", cur_line, e_off, b); + goto e_failed; + } + } + + flags &= ~ flag_seek_value; + + switch (b) + { + case '{': + + if (!new_value (&state, &top, &root, &alloc, json_object)) + goto e_alloc_failure; + + continue; + + case '[': + + if (!new_value (&state, &top, &root, &alloc, json_array)) + goto e_alloc_failure; + + flags |= flag_seek_value; + continue; + + case '"': + + if (!new_value (&state, &top, &root, &alloc, json_string)) + goto e_alloc_failure; + + flags |= flag_string; + + string = top->u.string.ptr; + string_length = 0; + + continue; + + case 't': + + if (*(++ i) != 'r' || *(++ i) != 'u' || *(++ i) != 'e') + goto e_unknown_value; + + if (!new_value (&state, &top, &root, &alloc, json_boolean)) + goto e_alloc_failure; + + top->u.boolean = 1; + + flags |= flag_next; + break; + + case 'f': + + if (*(++ i) != 'a' || *(++ i) != 'l' || *(++ i) != 's' || *(++ i) != 'e') + goto e_unknown_value; + + if (!new_value (&state, &top, &root, &alloc, json_boolean)) + goto e_alloc_failure; + + flags |= flag_next; + break; + + case 'n': + + if (*(++ i) != 'u' || *(++ i) != 'l' || *(++ i) != 'l') + goto e_unknown_value; + + if (!new_value (&state, &top, &root, &alloc, json_null)) + goto e_alloc_failure; + + flags |= flag_next; + break; + + default: + + if (isdigit (b) || b == '-') + { + if (!new_value (&state, &top, &root, &alloc, json_integer)) + goto e_alloc_failure; + + flags &= ~ (flag_exponent | flag_got_exponent_sign); + + if (state.first_pass) + continue; + + if (top->type == json_double) + top->u.dbl = g_ascii_strtod (i, (json_char **) &i); + else + top->u.integer = g_ascii_strtoll (i, (json_char **) &i, 10); + + flags |= flag_next | flag_reproc; + } + else + { sprintf (error, "%d:%d: Unexpected %c when seeking value", cur_line, e_off, b); + goto e_failed; + } + }; + }; + } + else + { + switch (top->type) + { + case json_object: + + switch (b) + { + whitespace: + continue; + + case '"': + + if (flags & flag_need_comma && (!state.settings.settings & json_relaxed_commas)) + { + sprintf (error, "%d:%d: Expected , before \"", cur_line, e_off); + goto e_failed; + } + + flags |= flag_string; + + string = (json_char *) top->_reserved.object_mem; + string_length = 0; + + break; + + case '}': + + flags = (flags & ~ flag_need_comma) | flag_next; + break; + + case ',': + + if (flags & flag_need_comma) + { + flags &= ~ flag_need_comma; + break; + } + + default: + + sprintf (error, "%d:%d: Unexpected `%c` in object", cur_line, e_off, b); + goto e_failed; + }; + + break; + + case json_integer: + case json_double: + + if (isdigit (b)) + continue; + + if (b == 'e' || b == 'E') + { + if (!(flags & flag_exponent)) + { + flags |= flag_exponent; + top->type = json_double; + + continue; + } + } + else if (b == '+' || b == '-') + { + if (flags & flag_exponent && !(flags & flag_got_exponent_sign)) + { + flags |= flag_got_exponent_sign; + continue; + } + } + else if (b == '.' && top->type == json_integer) + { + top->type = json_double; + continue; + } + + flags |= flag_next | flag_reproc; + break; + + default: + break; + }; + } + + if (flags & flag_reproc) + { + flags &= ~ flag_reproc; + -- i; + } + + if (flags & flag_next) + { + flags = (flags & ~ flag_next) | flag_need_comma; + + if (!top->parent) + { + /* root value done */ + + flags |= flag_done; + continue; + } + + if (top->parent->type == json_array) + flags |= flag_seek_value; + + if (!state.first_pass) + { + json_value * parent = top->parent; + + switch (parent->type) + { + case json_object: + + parent->u.object.values + [parent->u.object.length].value = top; + + break; + + case json_array: + + parent->u.array.values + [parent->u.array.length] = top; + + break; + + default: + break; + }; + } + + if ( (++ top->parent->u.array.length) > state.uint_max) + goto e_overflow; + + top = top->parent; + + continue; + } + } + + alloc = root; + } + + return root; + +e_unknown_value: + + sprintf (error, "%d:%d: Unknown value", cur_line, e_off); + goto e_failed; + +e_alloc_failure: + + strcpy (error, "Memory allocation failure"); + goto e_failed; + +e_overflow: + + sprintf (error, "%d:%d: Too long (caught overflow)", cur_line, e_off); + goto e_failed; + +e_failed: + + if (error_buf) + { + if (*error) + strcpy (error_buf, error); + else + strcpy (error_buf, "Unknown error"); + } + + if (state.first_pass) + alloc = root; + + while (alloc) + { + top = alloc->_reserved.next_alloc; + free (alloc); + alloc = top; + } + + if (!state.first_pass) + json_value_free (root); + + return 0; +} + +json_value * json_parse (const json_char * json) +{ + json_settings settings; + memset (&settings, 0, sizeof (json_settings)); + + return json_parse_ex (&settings, json, 0); +} + +void json_value_free (json_value * value) +{ + json_value * cur_value; + + if (!value) + return; + + value->parent = 0; + + while (value) + { + switch (value->type) + { + case json_array: + + if (!value->u.array.length) + { + free (value->u.array.values); + break; + } + + value = value->u.array.values [-- value->u.array.length]; + continue; + + case json_object: + + if (!value->u.object.length) + { + free (value->u.object.values); + break; + } + + value = value->u.object.values [-- value->u.object.length].value; + continue; + + case json_string: + + free (value->u.string.ptr); + break; + + default: + break; + }; + + cur_value = value; + value = value->parent; + free (cur_value); + } +} + + diff --git a/lib/json.h b/lib/json.h new file mode 100644 index 00000000..3800565a --- /dev/null +++ b/lib/json.h @@ -0,0 +1,192 @@ + +/* vim: set et ts=3 sw=3 ft=c: + * + * Copyright (C) 2012 James McLaughlin et al. All rights reserved. + * https://github.com/udp/json-parser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _JSON_H +#define _JSON_H + +#ifndef json_char + #define json_char char +#endif + +#ifdef __cplusplus + + #include <string.h> + + extern "C" + { + +#endif + +typedef struct +{ + unsigned long max_memory; + int settings; + +} json_settings; + +#define json_relaxed_commas 1 + +typedef enum +{ + json_none, + json_object, + json_array, + json_integer, + json_double, + json_string, + json_boolean, + json_null + +} json_type; + +extern const struct _json_value json_value_none; + +typedef struct _json_value +{ + struct _json_value * parent; + + json_type type; + + union + { + int boolean; + long long integer; + double dbl; + + struct + { + unsigned int length; + json_char * ptr; /* null terminated */ + + } string; + + struct + { + unsigned int length; + + struct + { + json_char * name; + struct _json_value * value; + + } * values; + + } object; + + struct + { + unsigned int length; + struct _json_value ** values; + + } array; + + } u; + + union + { + struct _json_value * next_alloc; + void * object_mem; + + } _reserved; + + + /* Some C++ operator sugar */ + + #ifdef __cplusplus + + public: + + inline _json_value () + { memset (this, 0, sizeof (_json_value)); + } + + inline const struct _json_value &operator [] (int index) const + { + if (type != json_array || index < 0 + || ((unsigned int) index) >= u.array.length) + { + return json_value_none; + } + + return *u.array.values [index]; + } + + inline const struct _json_value &operator [] (const char * index) const + { + if (type != json_object) + return json_value_none; + + for (unsigned int i = 0; i < u.object.length; ++ i) + if (!strcmp (u.object.values [i].name, index)) + return *u.object.values [i].value; + + return json_value_none; + } + + inline operator const char * () const + { + switch (type) + { + case json_string: + return u.string.ptr; + + default: + return ""; + }; + } + + inline operator long () const + { return u.integer; + } + + inline operator bool () const + { return u.boolean != 0; + } + + #endif + +} json_value; + +json_value * json_parse + (const json_char * json); + +json_value * json_parse_ex + (json_settings * settings, const json_char * json, char * error); + +void json_value_free (json_value *); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif + + diff --git a/lib/json_util.c b/lib/json_util.c new file mode 100644 index 00000000..2f1bc7e8 --- /dev/null +++ b/lib/json_util.c @@ -0,0 +1,62 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Helper functions for json.c * +* * +* Copyright 2012-2012 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <glib.h> + +#include "json_util.h" + +json_value *json_o_get( const json_value *obj, const json_char *name ) +{ + int i; + + if( !obj || obj->type != json_object ) + return NULL; + + for( i = 0; i < obj->u.object.length; ++ i) + if( strcmp( obj->u.object.values[i].name, name ) == 0 ) + return obj->u.object.values[i].value; + + return NULL; +} + +const char *json_o_str( const json_value *obj, const json_char *name ) +{ + json_value *ret = json_o_get( obj, name ); + + if( ret && ret->type == json_string ) + return ret->u.string.ptr; + else + return NULL; +} + +char *json_o_strdup( const json_value *obj, const json_char *name ) +{ + json_value *ret = json_o_get( obj, name ); + + if( ret && ret->type == json_string && ret->u.string.ptr ) + return g_memdup( ret->u.string.ptr, ret->u.string.length + 1 ); + else + return NULL; +} diff --git a/lib/json_util.h b/lib/json_util.h new file mode 100644 index 00000000..c2ddb0d1 --- /dev/null +++ b/lib/json_util.h @@ -0,0 +1,35 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Helper functions for json.c * +* * +* Copyright 2012-2012 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +#include "json.h" + +#define JSON_O_FOREACH(o, k, v) \ + char *k; json_value *v; int __i; \ + for( __i = 0; ( __i < (o)->u.object.length ) && \ + ( k = (o)->u.object.values[__i].name ) && \ + ( v = (o)->u.object.values[__i].value ); \ + __i ++ ) + +json_value *json_o_get( const json_value *obj, const json_char *name ); +const char *json_o_str( const json_value *obj, const json_char *name ); +char *json_o_strdup( const json_value *obj, const json_char *name ); @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2006 Wilmer van der Gaast and others * + * Copyright 2002-2012 Wilmer van der Gaast and others * \********************************************************************/ /* @@ -10,7 +10,7 @@ * * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> * (and possibly other members of the Gaim team) - * Copyright 2002-2006 Wilmer van der Gaast <wilmer@gaast.net> + * Copyright 2002-2012 Wilmer van der Gaast <wilmer@gaast.net> */ /* @@ -729,10 +729,10 @@ char **split_command_parts( char *command ) return cmd; } -char *get_rfc822_header( char *text, char *header, int len ) +char *get_rfc822_header( const char *text, const char *header, int len ) { int hlen = strlen( header ), i; - char *ret; + const char *ret; if( text == NULL ) return NULL; @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2012 Wilmer van der Gaast and others * \********************************************************************/ /* Misc. functions */ @@ -67,6 +67,6 @@ G_MODULE_EXPORT char *word_wrap( const char *msg, int line_len ); G_MODULE_EXPORT gboolean ssl_sockerr_again( void *ssl ); G_MODULE_EXPORT int md5_verify_password( char *password, char *hash ); G_MODULE_EXPORT char **split_command_parts( char *command ); -G_MODULE_EXPORT char *get_rfc822_header( char *text, char *header, int len ); +G_MODULE_EXPORT char *get_rfc822_header( const char *text, const char *header, int len ); #endif diff --git a/lib/oauth2.c b/lib/oauth2.c index 87965d04..6921a6d5 100644 --- a/lib/oauth2.c +++ b/lib/oauth2.c @@ -3,7 +3,7 @@ * BitlBee - An IRC to IM gateway * * Simple OAuth client (consumer) implementation. * * * -* Copyright 2010-2011 Wilmer van der Gaast <wilmer@gaast.net> * +* Copyright 2010-2012 Wilmer van der Gaast <wilmer@gaast.net> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -25,6 +25,7 @@ #include "http_client.h" #include "oauth2.h" #include "oauth.h" +#include "json.h" #include "url.h" char *oauth2_url( const struct oauth2_service *sp ) @@ -43,7 +44,6 @@ struct oauth2_access_token_data gpointer data; }; -static char *oauth2_json_dumb_get( const char *json, const char *key ); static void oauth2_access_token_done( struct http_request *req ); int oauth2_access_token( const struct oauth2_service *sp, @@ -102,7 +102,7 @@ static void oauth2_access_token_done( struct http_request *req ) { struct oauth2_access_token_data *cb_data = req->data; char *atoken = NULL, *rtoken = NULL; - const char *content_type; + char *content_type; if( getenv( "BITLBEE_DEBUG" ) && req->reply_body ) printf( "%s\n", req->reply_body ); @@ -114,8 +114,22 @@ static void oauth2_access_token_done( struct http_request *req ) } else if( content_type && strstr( content_type, "application/json" ) ) { - atoken = oauth2_json_dumb_get( req->reply_body, "access_token" ); - rtoken = oauth2_json_dumb_get( req->reply_body, "refresh_token" ); + json_value *js = json_parse( req->reply_body ); + if( js && js->type == json_object ) + { + int i; + + for( i = 0; i < js->u.object.length; i ++ ) + { + if( js->u.object.values[i].value->type != json_string ) + continue; + if( strcmp( js->u.object.values[i].name, "access_token" ) == 0 ) + atoken = g_strdup( js->u.object.values[i].value->u.string.ptr ); + if( strcmp( js->u.object.values[i].name, "refresh_token" ) == 0 ) + rtoken = g_strdup( js->u.object.values[i].value->u.string.ptr ); + } + } + json_value_free( js ); } else { @@ -131,66 +145,8 @@ static void oauth2_access_token_done( struct http_request *req ) printf( "Extracted atoken=%s rtoken=%s\n", atoken, rtoken ); cb_data->func( cb_data->data, atoken, rtoken ); + g_free( content_type ); g_free( atoken ); g_free( rtoken ); g_free( cb_data ); } - -/* Super dumb. I absolutely refuse to use/add a complete json parser library - (adding a new dependency to BitlBee for the first time in.. 6 years?) just - to parse 100 bytes of data. So I have to do my own parsing because OAuth2 - dropped support for XML. (GRRR!) This is very dumb and for example won't - work for integer values, nor will it strip/handle backslashes. */ -static char *oauth2_json_dumb_get( const char *json, const char *key ) -{ - int is_key = 0; /* 1 == reading key, 0 == reading value */ - int found_key = 0; - - while( json && *json ) - { - /* Grab strings and see if they're what we're looking for. */ - if( *json == '"' || *json == '\'' ) - { - char q = *json; - const char *str_start; - json ++; - str_start = json; - - while( *json ) - { - /* \' and \" are not string terminators. */ - if( *json == '\\' && json[1] == q ) - json ++; - /* But without a \ it is. */ - else if( *json == q ) - break; - json ++; - } - if( *json == '\0' ) - return NULL; - - if( is_key && strncmp( str_start, key, strlen( key ) ) == 0 ) - { - found_key = 1; - } - else if( !is_key && found_key ) - { - char *ret = g_memdup( str_start, json - str_start + 1 ); - ret[json-str_start] = '\0'; - return ret; - } - - } - else if( *json == '{' || *json == ',' ) - { - found_key = 0; - is_key = 1; - } - else if( *json == ':' ) - is_key = 0; - - json ++; - } - - return NULL; -} diff --git a/lib/ssl_bogus.c b/lib/ssl_bogus.c deleted file mode 100644 index e134201d..00000000 --- a/lib/ssl_bogus.c +++ /dev/null @@ -1,76 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* SSL module - dummy version */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "ssl_client.h" - -int ssl_errno; - -void ssl_init( void ) -{ -} - -void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data ) -{ - return( NULL ); -} - -int ssl_read( void *conn, char *buf, int len ) -{ - return( -1 ); -} - -int ssl_write( void *conn, const char *buf, int len ) -{ - return( -1 ); -} - -void ssl_disconnect( void *conn_ ) -{ -} - -int ssl_getfd( void *conn ) -{ - return( -1 ); -} - -void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data ) -{ - return NULL; -} - -b_input_condition ssl_getdirection( void *conn ) -{ - return B_EV_IO_READ; -} - -int ssl_pending( void *conn ) -{ - return 0; -} - -char *ssl_verify_strerror( int code ) -{ - return NULL; -} diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index 93601ba6..b698e630 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2011 Wilmer van der Gaast and others * + * Copyright 2002-2012 Wilmer van der Gaast and others * \********************************************************************/ /* SSL module - GnuTLS version */ @@ -37,7 +37,7 @@ int ssl_errno = 0; static gboolean initialized = FALSE; -gnutls_certificate_credentials xcred; +gnutls_certificate_credentials_t xcred; #include <limits.h> @@ -59,9 +59,11 @@ struct scd char *hostname; gboolean verify; - gnutls_session session; + gnutls_session_t session; }; +static GHashTable *session_cache; + static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ); static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); @@ -84,8 +86,10 @@ void ssl_init( void ) { gnutls_certificate_set_x509_trust_file( xcred, global.conf->cafile, GNUTLS_X509_FMT_PEM ); - /* Not needed in GnuTLS 2.11+ but we support older versions for now. */ - gnutls_certificate_set_verify_flags( xcred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT ); + /* Not needed in GnuTLS 2.11+ (enabled by default there) so + don't do it (resets possible other defaults). */ + if( !gnutls_check_version( "2.11" ) ) + gnutls_certificate_set_verify_flags( xcred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT ); } initialized = TRUE; @@ -94,6 +98,8 @@ void ssl_init( void ) gnutls_global_set_log_level( 3 ); */ + session_cache = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free ); + atexit( ssl_deinit ); } @@ -101,18 +107,20 @@ static void ssl_deinit( void ) { gnutls_global_deinit(); gnutls_certificate_free_credentials( xcred ); + g_hash_table_destroy( session_cache ); + session_cache = NULL; } void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data ) { struct scd *conn = g_new0( struct scd, 1 ); - conn->fd = proxy_connect( host, port, ssl_connected, conn ); conn->func = func; conn->data = data; conn->inpa = -1; conn->hostname = g_strdup( host ); conn->verify = verify && global.conf->cafile; + conn->fd = proxy_connect( host, port, ssl_connected, conn ); if( conn->fd < 0 ) { @@ -131,7 +139,7 @@ void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function conn->func = func; conn->data = data; conn->inpa = -1; - conn->hostname = hostname; + conn->hostname = g_strdup( hostname ); /* For now, SSL verification is globally enabled by setting the cafile setting in bitlbee.conf. Commented out by default because probably @@ -168,9 +176,9 @@ static int verify_certificate_callback( gnutls_session_t session ) int gnutlsret; int verifyret = 0; gnutls_x509_crt_t cert; - const char *hostname; + struct scd *conn; - hostname = gnutls_session_get_ptr( session ); + conn = gnutls_session_get_ptr( session ); gnutlsret = gnutls_certificate_verify_peers2( session, &status ); if( gnutlsret < 0 ) @@ -208,7 +216,7 @@ static int verify_certificate_callback( gnutls_session_t session ) if( cert_list == NULL || gnutls_x509_crt_import( cert, &cert_list[0], GNUTLS_X509_FMT_DER ) < 0 ) return VERIFY_CERT_ERROR; - if( !gnutls_x509_crt_check_hostname( cert, hostname ) ) + if( !gnutls_x509_crt_check_hostname( cert, conn->hostname ) ) { verifyret |= VERIFY_CERT_INVALID; verifyret |= VERIFY_CERT_WRONG_HOSTNAME; @@ -219,6 +227,45 @@ static int verify_certificate_callback( gnutls_session_t session ) return verifyret; } +struct ssl_session +{ + size_t size; + char data[]; +}; + +static void ssl_cache_add( struct scd *conn ) +{ + size_t data_size; + struct ssl_session *data; + char *hostname; + + if( !conn->hostname || + gnutls_session_get_data( conn->session, NULL, &data_size ) != 0 ) + return; + + data = g_malloc( sizeof( struct ssl_session ) + data_size ); + if( gnutls_session_get_data( conn->session, data->data, &data->size ) != 0 ) + { + g_free( data ); + return; + } + + hostname = g_strdup( conn->hostname ); + g_hash_table_insert( session_cache, hostname, data ); +} + +static void ssl_cache_resume( struct scd *conn ) +{ + struct ssl_session *data; + + if( conn->hostname && + ( data = g_hash_table_lookup( session_cache, conn->hostname ) ) ) + { + gnutls_session_set_data( conn->session, data->data, data->size ); + g_hash_table_remove( session_cache, conn->hostname ); + } +} + char *ssl_verify_strerror( int code ) { GString *ret = g_string_new( "" ); @@ -264,16 +311,20 @@ static gboolean ssl_connected( gpointer data, gint source, b_input_condition con ssl_init(); gnutls_init( &conn->session, GNUTLS_CLIENT ); - if( conn->verify ) - gnutls_session_set_ptr( conn->session, (void *) conn->hostname ); + gnutls_session_set_ptr( conn->session, (void *) conn ); #if GNUTLS_VERSION_NUMBER < 0x020c00 gnutls_transport_set_lowat( conn->session, 0 ); #endif gnutls_set_default_priority( conn->session ); gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, xcred ); + if( conn->hostname && !isdigit( conn->hostname[0] ) ) + gnutls_server_name_set( conn->session, GNUTLS_NAME_DNS, + conn->hostname, strlen( conn->hostname ) ); sock_make_nonblocking( conn->fd ); - gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) GNUTLS_STUPID_CAST conn->fd ); + gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr_t) GNUTLS_STUPID_CAST conn->fd ); + + ssl_cache_resume( conn ); return ssl_handshake( data, source, cond ); } @@ -315,7 +366,8 @@ static gboolean ssl_handshake( gpointer data, gint source, b_input_condition con { /* For now we can't handle non-blocking perfectly everywhere... */ sock_make_blocking( conn->fd ); - + + ssl_cache_add( conn ); conn->established = TRUE; conn->func( conn->data, 0, conn, cond ); } @@ -399,6 +451,7 @@ void ssl_disconnect( void *conn_ ) if( conn->session ) gnutls_deinit( conn->session ); + g_free( conn->hostname ); g_free( conn ); } diff --git a/lib/ssl_nss.c b/lib/ssl_nss.c index d50620d5..e8de884f 100644 --- a/lib/ssl_nss.c +++ b/lib/ssl_nss.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2005 Wilmer van der Gaast and others * + * Copyright 2002-2012 Wilmer van der Gaast and others * \********************************************************************/ /* SSL module - NSS version */ @@ -39,39 +39,46 @@ #include <seccomon.h> #include <secerr.h> #include <sslerr.h> +#include <assert.h> +#include <unistd.h> int ssl_errno = 0; static gboolean initialized = FALSE; -struct scd -{ +#define SSLDEBUG 0 + +struct scd { ssl_input_function func; gpointer data; int fd; + char *hostname; PRFileDesc *prfd; gboolean established; gboolean verify; }; -static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); -static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_connected(gpointer data, gint source, + b_input_condition cond); +static gboolean ssl_starttls_real(gpointer data, gint source, + b_input_condition cond); - -static SECStatus nss_auth_cert (void *arg, PRFileDesc *socket, PRBool checksig, PRBool isserver) +static SECStatus nss_auth_cert(void *arg, PRFileDesc * socket, PRBool checksig, + PRBool isserver) { return SECSuccess; } -static SECStatus nss_bad_cert (void *arg, PRFileDesc *socket) +static SECStatus nss_bad_cert(void *arg, PRFileDesc * socket) { PRErrorCode err; - if(!arg) return SECFailure; + if (!arg) + return SECFailure; - *(PRErrorCode *)arg = err = PORT_GetError(); + *(PRErrorCode *) arg = err = PORT_GetError(); - switch(err) { + switch (err) { case SEC_ERROR_INVALID_AVA: case SEC_ERROR_INVALID_TIME: case SEC_ERROR_BAD_SIGNATURE: @@ -93,52 +100,63 @@ static SECStatus nss_bad_cert (void *arg, PRFileDesc *socket) } } - -void ssl_init( void ) +void ssl_init(void) { - PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + // https://www.mozilla.org/projects/security/pki/nss/ref/ssl/sslfnc.html#1234224 + // This NSS function is not intended for use with SSL, which + // requires that the certificate and key database files be + // opened. Relates to whole non-verification of servers for now. NSS_NoDB_Init(NULL); NSS_SetDomesticPolicy(); initialized = TRUE; } -void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data ) +void *ssl_connect(char *host, int port, gboolean verify, + ssl_input_function func, gpointer data) { - struct scd *conn = g_new0( struct scd, 1 ); - - conn->fd = proxy_connect( host, port, ssl_connected, conn ); + struct scd *conn = g_new0(struct scd, 1); + + conn->fd = proxy_connect(host, port, ssl_connected, conn); conn->func = func; conn->data = data; - - if( conn->fd < 0 ) - { - g_free( conn ); - return( NULL ); + conn->hostname = g_strdup(host); + + if (conn->fd < 0) { + g_free(conn->hostname); + g_free(conn); + return (NULL); } - - if( !initialized ) - { + + if (!initialized) { ssl_init(); } - - return( conn ); + return (conn); } -static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ) +static gboolean ssl_starttls_real(gpointer data, gint source, + b_input_condition cond) { struct scd *conn = data; - return ssl_connected( conn, conn->fd, B_EV_IO_WRITE ); + return ssl_connected(conn, conn->fd, B_EV_IO_WRITE); } -void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data ) +void *ssl_starttls(int fd, char *hostname, gboolean verify, + ssl_input_function func, gpointer data) { - struct scd *conn = g_new0( struct scd, 1 ); + struct scd *conn = g_new0(struct scd, 1); conn->fd = fd; conn->func = func; conn->data = data; + conn->hostname = hostname; + + /* For now, SSL verification is globally enabled by setting the cafile + setting in bitlbee.conf. Commented out by default because probably + not everyone has this file in the same place and plenty of folks + may not have the cert of their private Jabber server in it. */ conn->verify = verify && global.conf->cafile; /* This function should be called via a (short) timeout instead of @@ -150,108 +168,255 @@ void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function In short, doing things like this makes the rest of the code a lot simpler. */ - b_timeout_add( 1, ssl_starttls_real, conn ); + b_timeout_add(1, ssl_starttls_real, conn); return conn; } -static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) +static gboolean ssl_connected(gpointer data, gint source, + b_input_condition cond) { struct scd *conn = data; - + /* Right now we don't have any verification functionality for NSS. */ - if( conn->verify ) - { - conn->func( conn->data, 1, NULL, cond ); - if( source >= 0 ) closesocket( source ); - g_free( conn ); + if (conn->verify) { + conn->func(conn->data, 1, NULL, cond); + if (source >= 0) + closesocket(source); + g_free(conn->hostname); + g_free(conn); return FALSE; } - - if( source == -1 ) + + if (source == -1) goto ssl_connected_failure; - + /* Until we find out how to handle non-blocking I/O with NSS... */ - sock_make_blocking( conn->fd ); - + sock_make_blocking(conn->fd); + conn->prfd = SSL_ImportFD(NULL, PR_ImportTCPSocket(source)); + if (!conn->prfd) + goto ssl_connected_failure; SSL_OptionSet(conn->prfd, SSL_SECURITY, PR_TRUE); SSL_OptionSet(conn->prfd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); - SSL_BadCertHook(conn->prfd, (SSLBadCertHandler)nss_bad_cert, NULL); - SSL_AuthCertificateHook(conn->prfd, (SSLAuthCertificate)nss_auth_cert, (void *)CERT_GetDefaultCertDB()); + SSL_BadCertHook(conn->prfd, (SSLBadCertHandler) nss_bad_cert, NULL); + SSL_AuthCertificateHook(conn->prfd, (SSLAuthCertificate) nss_auth_cert, + (void *)CERT_GetDefaultCertDB()); + SSL_SetURL(conn->prfd, conn->hostname); SSL_ResetHandshake(conn->prfd, PR_FALSE); if (SSL_ForceHandshake(conn->prfd)) { goto ssl_connected_failure; } - - + conn->established = TRUE; - conn->func( conn->data, 0, conn, cond ); + conn->func(conn->data, 0, conn, cond); return FALSE; - - ssl_connected_failure: - - conn->func( conn->data, 0, NULL, cond ); - - PR_Close( conn -> prfd ); - if( source >= 0 ) closesocket( source ); - g_free( conn ); - + + ssl_connected_failure: + + conn->func(conn->data, 0, NULL, cond); + + if (conn->prfd) + PR_Close(conn->prfd); + if (source >= 0) + closesocket(source); + g_free(conn->hostname); + g_free(conn); + return FALSE; } -int ssl_read( void *conn, char *buf, int len ) +int ssl_read(void *conn, char *buf, int len) { - if( !((struct scd*)conn)->established ) - return( 0 ); - - return( PR_Read( ((struct scd*)conn)->prfd, buf, len ) ); + int st; + PRErrorCode PR_err; + + if (!((struct scd *)conn)->established) { + ssl_errno = SSL_NOHANDSHAKE; + return -1; + } + + st = PR_Read(((struct scd *)conn)->prfd, buf, len); + PR_err = PR_GetError(); + + ssl_errno = SSL_OK; + if (PR_err == PR_WOULD_BLOCK_ERROR) + ssl_errno = SSL_AGAIN; + + if (SSLDEBUG && getenv("BITLBEE_DEBUG") && st > 0) + len = write(STDERR_FILENO, buf, st); + + return st; } -int ssl_write( void *conn, const char *buf, int len ) +int ssl_write(void *conn, const char *buf, int len) { - if( !((struct scd*)conn)->established ) - return( 0 ); - - return( PR_Write ( ((struct scd*)conn)->prfd, buf, len ) ); + int st; + PRErrorCode PR_err; + + if (!((struct scd *)conn)->established) { + ssl_errno = SSL_NOHANDSHAKE; + return -1; + } + st = PR_Write(((struct scd *)conn)->prfd, buf, len); + PR_err = PR_GetError(); + + ssl_errno = SSL_OK; + if (PR_err == PR_WOULD_BLOCK_ERROR) + ssl_errno = SSL_AGAIN; + + if (SSLDEBUG && getenv("BITLBEE_DEBUG") && st > 0) + len = write(2, buf, st); + + return st; } -int ssl_pending( void *conn ) +int ssl_pending(void *conn) { - struct scd *c = (struct scd *) conn; + struct scd *c = (struct scd *)conn; - if( c == NULL ) { + if (c == NULL) { return 0; } - return ( c->established && SSL_DataPending( c->prfd ) > 0 ); + return (c->established && SSL_DataPending(c->prfd) > 0); } -void ssl_disconnect( void *conn_ ) +void ssl_disconnect(void *conn_) { struct scd *conn = conn_; - - PR_Close( conn->prfd ); - closesocket( conn->fd ); - - g_free( conn ); + + // When we swich to NSS_Init, we should have here + // NSS_Shutdown(); + + if (conn->prfd) + PR_Close(conn->prfd); + + g_free(conn->hostname); + g_free(conn); } -int ssl_getfd( void *conn ) +int ssl_getfd(void *conn) { - return( ((struct scd*)conn)->fd ); + return (((struct scd *)conn)->fd); } -b_input_condition ssl_getdirection( void *conn ) +b_input_condition ssl_getdirection(void *conn) { /* Just in case someone calls us, let's return the most likely case: */ return B_EV_IO_READ; } -char *ssl_verify_strerror( int code ) +char *ssl_verify_strerror(int code) +{ + return + g_strdup + ("SSL certificate verification not supported by BitlBee NSS code."); +} + +size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, + const unsigned char *input, size_t input_len, + const unsigned char *iv, unsigned char **res) { - return g_strdup( "SSL certificate verification not supported by BitlBee NSS code." ); +#define CIPHER_MECH CKM_DES3_CBC +#define MAX_OUTPUT_LEN 72 + + int len1; + unsigned int len2; + + PK11Context *ctx = NULL; + PK11SlotInfo *slot = NULL; + SECItem keyItem; + SECItem ivItem; + SECItem *secParam = NULL; + PK11SymKey *symKey = NULL; + + size_t rc; + SECStatus rv; + + if (!initialized) { + ssl_init(); + } + + keyItem.data = (unsigned char *)key; + keyItem.len = key_len; + + slot = PK11_GetBestSlot(CIPHER_MECH, NULL); + if (slot == NULL) { + fprintf(stderr, "PK11_GetBestSlot failed (err %d)\n", + PR_GetError()); + rc = 0; + goto out; + } + + symKey = + PK11_ImportSymKey(slot, CIPHER_MECH, PK11_OriginUnwrap, CKA_ENCRYPT, + &keyItem, NULL); + if (symKey == NULL) { + fprintf(stderr, "PK11_ImportSymKey failed (err %d)\n", + PR_GetError()); + rc = 0; + goto out; + } + + ivItem.data = (unsigned char *)iv; + /* See msn_soap_passport_sso_handle_response in protocols/msn/soap.c */ + ivItem.len = 8; + + secParam = PK11_ParamFromIV(CIPHER_MECH, &ivItem); + if (secParam == NULL) { + fprintf(stderr, "PK11_ParamFromIV failed (err %d)\n", + PR_GetError()); + rc = 0; + goto out; + } + + ctx = + PK11_CreateContextBySymKey(CIPHER_MECH, CKA_ENCRYPT, symKey, + secParam); + if (ctx == NULL) { + fprintf(stderr, "PK11_CreateContextBySymKey failed (err %d)\n", + PR_GetError()); + rc = 0; + goto out; + } + + *res = g_new0(unsigned char, MAX_OUTPUT_LEN); + + rv = PK11_CipherOp(ctx, *res, &len1, MAX_OUTPUT_LEN, + (unsigned char *)input, input_len); + if (rv != SECSuccess) { + fprintf(stderr, "PK11_CipherOp failed (err %d)\n", + PR_GetError()); + rc = 0; + goto out; + } + + assert(len1 <= MAX_OUTPUT_LEN); + + rv = PK11_DigestFinal(ctx, *res + len1, &len2, + (unsigned int)MAX_OUTPUT_LEN - len1); + if (rv != SECSuccess) { + fprintf(stderr, "PK11_DigestFinal failed (err %d)\n", + PR_GetError()); + rc = 0; + goto out; + } + + rc = len1 + len2; + + out: + if (ctx) + PK11_DestroyContext(ctx, PR_TRUE); + if (symKey) + PK11_FreeSymKey(symKey); + if (secParam) + SECITEM_FreeItem(secParam, PR_TRUE); + if (slot) + PK11_FreeSlot(slot); + + return rc; } diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c index c1aa6b1b..3486f044 100644 --- a/lib/ssl_openssl.c +++ b/lib/ssl_openssl.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2012 Wilmer van der Gaast and others * \********************************************************************/ /* SSL module - OpenSSL version */ @@ -46,13 +46,16 @@ struct scd int fd; gboolean established; gboolean verify; + char *hostname; int inpa; int lasterr; /* Necessary for SSL_get_error */ SSL *ssl; - SSL_CTX *ssl_ctx; }; +static SSL_CTX *ssl_ctx; + +static void ssl_conn_free( struct scd *conn ); static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ); static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); @@ -60,9 +63,14 @@ static gboolean ssl_handshake( gpointer data, gint source, b_input_condition con void ssl_init( void ) { - initialized = TRUE; + const SSL_METHOD *meth; + SSL_library_init(); - // SSLeay_add_ssl_algorithms(); + + meth = TLSv1_client_method(); + ssl_ctx = SSL_CTX_new( meth ); + + initialized = TRUE; } void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data ) @@ -72,13 +80,14 @@ void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function fun conn->fd = proxy_connect( host, port, ssl_connected, conn ); if( conn->fd < 0 ) { - g_free( conn ); + ssl_conn_free( conn ); return NULL; } conn->func = func; conn->data = data; conn->inpa = -1; + conn->hostname = g_strdup( host ); return conn; } @@ -92,6 +101,7 @@ void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function conn->data = data; conn->inpa = -1; conn->verify = verify && global.conf->cafile; + conn->hostname = g_strdup( hostname ); /* This function should be called via a (short) timeout instead of directly from here, because these SSL calls are *supposed* to be @@ -117,15 +127,13 @@ static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) { struct scd *conn = data; - const SSL_METHOD *meth; - /* Right now we don't have any verification functionality for OpenSSL. */ - if( conn->verify ) { + /* Right now we don't have any verification functionality for OpenSSL. */ conn->func( conn->data, 1, NULL, cond ); if( source >= 0 ) closesocket( source ); - g_free( conn ); + ssl_conn_free( conn ); return FALSE; } @@ -138,12 +146,11 @@ static gboolean ssl_connected( gpointer data, gint source, b_input_condition con ssl_init(); } - meth = TLSv1_client_method(); - conn->ssl_ctx = SSL_CTX_new( meth ); - if( conn->ssl_ctx == NULL ) + + if( ssl_ctx == NULL ) goto ssl_connected_failure; - conn->ssl = SSL_new( conn->ssl_ctx ); + conn->ssl = SSL_new( ssl_ctx ); if( conn->ssl == NULL ) goto ssl_connected_failure; @@ -151,23 +158,14 @@ static gboolean ssl_connected( gpointer data, gint source, b_input_condition con sock_make_nonblocking( conn->fd ); SSL_set_fd( conn->ssl, conn->fd ); + if( conn->hostname && !isdigit( conn->hostname[0] ) ) + SSL_set_tlsext_host_name( conn->ssl, conn->hostname ); + return ssl_handshake( data, source, cond ); ssl_connected_failure: conn->func( conn->data, 0, NULL, cond ); - - if( conn->ssl ) - { - SSL_shutdown( conn->ssl ); - SSL_free( conn->ssl ); - } - if( conn->ssl_ctx ) - { - SSL_CTX_free( conn->ssl_ctx ); - } - if( source >= 0 ) closesocket( source ); - g_free( conn ); - + ssl_disconnect( conn ); return FALSE; } @@ -183,14 +181,7 @@ static gboolean ssl_handshake( gpointer data, gint source, b_input_condition con if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE ) { conn->func( conn->data, 0, NULL, cond ); - - SSL_shutdown( conn->ssl ); - SSL_free( conn->ssl ); - SSL_CTX_free( conn->ssl_ctx ); - - if( source >= 0 ) closesocket( source ); - g_free( conn ); - + ssl_disconnect( conn ); return FALSE; } @@ -260,6 +251,14 @@ int ssl_pending( void *conn ) SSL_pending( ((struct scd*)conn)->ssl ) > 0 : 0; } +static void ssl_conn_free( struct scd *conn ) +{ + SSL_free( conn->ssl ); + g_free( conn->hostname ); + g_free( conn ); + +} + void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; @@ -272,9 +271,7 @@ void ssl_disconnect( void *conn_ ) closesocket( conn->fd ); - SSL_free( conn->ssl ); - SSL_CTX_free( conn->ssl_ctx ); - g_free( conn ); + ssl_conn_free( conn ); } int ssl_getfd( void *conn ) diff --git a/lib/xmltree.c b/lib/xmltree.c index 3906029c..0726d387 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -3,7 +3,7 @@ * BitlBee - An IRC to IM gateway * * Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * * * -* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* Copyright 2006-2012 Wilmer van der Gaast <wilmer@gaast.net> * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * @@ -162,9 +162,8 @@ int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) xt_status st; int i; - /* Just in case someone likes infinite loops... */ if( xt->root == NULL ) - return 0; + return 1; if( node == NULL ) return xt_handle( xt, xt->root, depth ); @@ -262,15 +261,21 @@ void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ) } } -struct xt_node *xt_from_string( const char *in ) +struct xt_node *xt_from_string( const char *in, int len ) { struct xt_parser *parser; - struct xt_node *ret; + struct xt_node *ret = NULL; + + if( len == 0 ) + len = strlen( in ); parser = xt_new( NULL, NULL ); - xt_feed( parser, in, strlen( in ) ); - ret = parser->root; - parser->root = NULL; + xt_feed( parser, in, len ); + if( parser->cur == NULL ) + { + ret = parser->root; + parser->root = NULL; + } xt_free( parser ); return ret; diff --git a/lib/xmltree.h b/lib/xmltree.h index cfd3361c..a41cbac1 100644 --- a/lib/xmltree.h +++ b/lib/xmltree.h @@ -3,7 +3,7 @@ * BitlBee - An IRC to IM gateway * * Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * * * -* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* Copyright 2006-2012 Wilmer van der Gaast <wilmer@gaast.net> * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * @@ -81,7 +81,7 @@ void xt_reset( struct xt_parser *xt ); int xt_feed( struct xt_parser *xt, const char *text, int text_len ); int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ); void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ); -struct xt_node *xt_from_string( const char *in ); +struct xt_node *xt_from_string( const char *in, int text_len ); char *xt_to_string( struct xt_node *node ); char *xt_to_string_i( struct xt_node *node ); void xt_print( struct xt_node *node ); |