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 ); | 
