aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile4
-rw-r--r--lib/des.c646
-rw-r--r--lib/des.h51
-rw-r--r--lib/http_client.c171
-rw-r--r--lib/http_client.h42
-rw-r--r--lib/json.c743
-rw-r--r--lib/json.h192
-rw-r--r--lib/json_util.c62
-rw-r--r--lib/json_util.h35
-rw-r--r--lib/misc.c8
-rw-r--r--lib/misc.h4
-rw-r--r--lib/oauth2.c84
-rw-r--r--lib/ssl_bogus.c76
-rw-r--r--lib/ssl_gnutls.c81
-rw-r--r--lib/ssl_nss.c333
-rw-r--r--lib/ssl_openssl.c71
-rw-r--r--lib/xmltree.c21
-rw-r--r--lib/xmltree.h4
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 );
diff --git a/lib/misc.c b/lib/misc.c
index a7065757..49c4aa5d 100644
--- a/lib/misc.c
+++ b/lib/misc.c
@@ -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;
diff --git a/lib/misc.h b/lib/misc.h
index 7e03de2d..059c8231 100644
--- a/lib/misc.h
+++ b/lib/misc.h
@@ -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 );