/************************************************************************ * IRC - Internet Relay Chat, servlink/servlink.c * * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: control.c,v 1.2 2002/08/13 14:45:12 fishwaldo Exp $ */ #include "setup.h" #include #include #include #include #include #ifdef HAVE_LIBCRYPTO #include #include #endif #ifdef HAVE_LIBZ #include #endif #include "servlink.h" #include "io.h" #include "control.h" static cmd_handler cmd_set_zip_out_level; static cmd_handler cmd_start_zip_out; static cmd_handler cmd_start_zip_in; static cmd_handler cmd_set_crypt_in_cipher; static cmd_handler cmd_set_crypt_in_key; static cmd_handler cmd_start_crypt_in; static cmd_handler cmd_set_crypt_out_cipher; static cmd_handler cmd_set_crypt_out_key; static cmd_handler cmd_start_crypt_out; static cmd_handler cmd_init; struct command_def command_table[] = { { CMD_SET_ZIP_OUT_LEVEL, cmd_set_zip_out_level, COMMAND_FLAG_DATA }, { CMD_START_ZIP_OUT, cmd_start_zip_out, 0 }, { CMD_START_ZIP_IN, cmd_start_zip_in, 0 }, { CMD_SET_CRYPT_IN_CIPHER, cmd_set_crypt_in_cipher, COMMAND_FLAG_DATA }, { CMD_SET_CRYPT_IN_KEY, cmd_set_crypt_in_key, COMMAND_FLAG_DATA }, { CMD_START_CRYPT_IN, cmd_start_crypt_in, 0 }, { CMD_SET_CRYPT_OUT_CIPHER, cmd_set_crypt_out_cipher, COMMAND_FLAG_DATA }, { CMD_SET_CRYPT_OUT_KEY, cmd_set_crypt_out_key, COMMAND_FLAG_DATA }, { CMD_START_CRYPT_OUT, cmd_start_crypt_out, 0 }, { CMD_INJECT_RECVQ, process_recvq, COMMAND_FLAG_DATA }, { CMD_INJECT_SENDQ, process_sendq, COMMAND_FLAG_DATA }, { CMD_INIT, cmd_init, 0 }, { CMD_ZIPSTATS, send_zipstats, 0 }, { 0, 0, 0 } }; void cmd_set_zip_out_level(struct ctrl_command *cmd) { #ifdef HAVE_LIBZ out_state.zip_state.level = *cmd->data; if ((out_state.zip_state.level < -1) || (out_state.zip_state.level > 9)) send_error("invalid compression level %d", out_state.zip_state.level); #else send_error("can't set compression level - no libz support!"); #endif } void cmd_start_zip_out(struct ctrl_command *cmd) { #ifdef HAVE_LIBZ int ret; if (out_state.zip) send_error("can't start compression - already started!"); out_state.zip_state.z_stream.total_in = 0; out_state.zip_state.z_stream.total_out = 0; out_state.zip_state.z_stream.zalloc = (alloc_func)0; out_state.zip_state.z_stream.zfree = (free_func)0; out_state.zip_state.z_stream.data_type = Z_ASCII; if (out_state.zip_state.level <= 0) out_state.zip_state.level = Z_DEFAULT_COMPRESSION; if ((ret = deflateInit(&out_state.zip_state.z_stream, out_state.zip_state.level)) != Z_OK) send_error("deflateInit failed: %d", ret); out_state.zip = 1; #else send_error("can't start compression - no libz support!"); #endif } void cmd_start_zip_in(struct ctrl_command *cmd) { #ifdef HAVE_LIBZ int ret; if (in_state.zip) send_error("can't start decompression - already started!"); in_state.zip_state.z_stream.total_in = 0; in_state.zip_state.z_stream.total_out = 0; in_state.zip_state.z_stream.zalloc = (alloc_func)0; in_state.zip_state.z_stream.zfree = (free_func)0; in_state.zip_state.z_stream.data_type = Z_ASCII; if ((ret = inflateInit(&in_state.zip_state.z_stream)) != Z_OK) send_error("inflateInit failed: %d", ret); in_state.zip = 1; #else send_error("can't start decompression - no libz support!"); #endif } void cmd_set_crypt_in_cipher(struct ctrl_command *cmd) { #ifdef HAVE_LIBCRYPTO unsigned int cipher = *cmd->data; if (in_state.crypt_state.cipher) send_error("can't set decryption cipher - already set!"); switch (cipher) { #ifdef HAVE_EVP_BF_CFB case CIPHER_BF: in_state.crypt_state.cipher = EVP_bf_cfb(); break; #endif #ifdef HAVE_EVP_CAST5_CFB case CIPHER_CAST: in_state.crypt_state.cipher = EVP_cast5_cfb(); break; #endif #ifdef HAVE_EVP_DES_CFB case CIPHER_DES: in_state.crypt_state.cipher = EVP_des_cfb(); break; #endif #ifdef HAVE_EVP_DES_EDE3_CFB case CIPHER_3DES: in_state.crypt_state.cipher = EVP_des_ede3_cfb(); break; #endif #ifdef HAVE_EVP_IDEA_CFB case CIPHER_IDEA: in_state.crypt_state.cipher = EVP_idea_cfb(); break; #endif #ifdef HAVE_EVP_RC5_32_12_16_CFB case CIPHER_RC5_8: in_state.crypt_state.cipher = EVP_rc5_32_12_16_cfb(); in_state.crypt_state.rounds = 8; break; case CIPHER_RC5_12: in_state.crypt_state.cipher = EVP_rc5_32_12_16_cfb(); in_state.crypt_state.rounds = 12; break; case CIPHER_RC5_16: in_state.crypt_state.cipher = EVP_rc5_32_12_16_cfb(); in_state.crypt_state.rounds = 16; break; #endif default: send_error("can't set decryption cipher - invalid cipher: %d!", cipher); /* invalid cipher */ break; } #else send_error("can't set decryption cipher - no OpenSSL support!"); #endif } void cmd_set_crypt_in_key(struct ctrl_command *cmd) { #ifdef HAVE_LIBCRYPTO if (in_state.crypt_state.key) send_error("can't set decryption key - already set!"); in_state.crypt_state.keylen = cmd->datalen; in_state.crypt_state.key = malloc(cmd->datalen); memcpy(in_state.crypt_state.key, cmd->data, cmd->datalen); #else send_error("can't set decryption key - no OpenSSL support!"); #endif } void cmd_start_crypt_in(struct ctrl_command *cmd) { #ifdef HAVE_LIBCRYPTO if (in_state.crypt) send_error("can't start decryption - already started!"); if (!in_state.crypt_state.cipher) send_error("can't start decryption - no cipher set!"); if (!in_state.crypt_state.key) send_error("can't start decryption - no key set!"); in_state.crypt = 1; if (!EVP_DecryptInit(&in_state.crypt_state.ctx, in_state.crypt_state.cipher, NULL, NULL)) send_error("can't start decryption - DecryptInit (1) failed: %s!", ERR_error_string(ERR_get_error(), NULL)); /* * XXX - ugly hack to work around OpenSSL bug * if/when OpenSSL fix it, or give proper workaround * use that, and force minimum OpenSSL version * * Without this hack, BF/256 will fail. */ /* cast to avoid warning */ *(unsigned int *)( &in_state.crypt_state.ctx.cipher->flags) |= EVP_CIPH_VARIABLE_LENGTH; if (!EVP_CIPHER_CTX_set_key_length(&in_state.crypt_state.ctx, in_state.crypt_state.keylen)) send_error("can't start decryption - set_key_length failed: %s!", ERR_error_string(ERR_get_error(), NULL)); in_state.crypt_state.ivlen = EVP_CIPHER_CTX_iv_length(&in_state.crypt_state.ctx); if (in_state.crypt_state.ivlen) in_state.crypt_state.iv = calloc(in_state.crypt_state.ivlen, 1); if (in_state.crypt_state.rounds) { if (!EVP_CIPHER_CTX_ctrl(&in_state.crypt_state.ctx, EVP_CTRL_SET_RC5_ROUNDS, in_state.crypt_state.rounds, NULL)) send_error("can't start decryption - SET_RC5_ROUNDS failed: %s!", ERR_error_string(ERR_get_error(), NULL)); } if (!EVP_DecryptInit(&in_state.crypt_state.ctx, NULL, in_state.crypt_state.key, in_state.crypt_state.iv)) send_error("can't start decryption - DecryptInit (2) failed: %s!", ERR_error_string(ERR_get_error(), NULL)); #else send_error("can't start decryption - no OpenSSL support!"); #endif } void cmd_set_crypt_out_cipher(struct ctrl_command *cmd) { #ifdef HAVE_LIBCRYPTO unsigned int cipher = *cmd->data; if (out_state.crypt_state.cipher) send_error("can't set encryption cipher - already set!"); switch (cipher) { #ifdef HAVE_EVP_BF_CFB case CIPHER_BF: out_state.crypt_state.cipher = EVP_bf_cfb(); break; #endif #ifdef HAVE_EVP_CAST5_CFB case CIPHER_CAST: out_state.crypt_state.cipher = EVP_cast5_cfb(); break; #endif #ifdef HAVE_EVP_DES_CFB case CIPHER_DES: out_state.crypt_state.cipher = EVP_des_cfb(); break; #endif #ifdef HAVE_EVP_DES_EDE3_CFB case CIPHER_3DES: out_state.crypt_state.cipher = EVP_des_ede3_cfb(); break; #endif #ifdef HAVE_EVP_IDEA_CFB case CIPHER_IDEA: out_state.crypt_state.cipher = EVP_idea_cfb(); break; #endif #ifdef HAVE_EVP_RC5_32_12_16_CFB case CIPHER_RC5_8: out_state.crypt_state.cipher = EVP_rc5_32_12_16_cfb(); out_state.crypt_state.rounds = 8; break; case CIPHER_RC5_12: out_state.crypt_state.cipher = EVP_rc5_32_12_16_cfb(); out_state.crypt_state.rounds = 12; break; case CIPHER_RC5_16: out_state.crypt_state.cipher = EVP_rc5_32_12_16_cfb(); out_state.crypt_state.rounds = 16; break; #endif default: send_error("can't set encryption cipher - invalid cipher %d!", cipher); /* invalid cipher */ } #else send_error("can't set encryption cipher - no OpenSSL support!"); #endif } void cmd_set_crypt_out_key(struct ctrl_command *cmd) { #ifdef HAVE_LIBCRYPTO if (out_state.crypt_state.key) send_error("can't set encryption key - already set!"); out_state.crypt_state.keylen = cmd->datalen; out_state.crypt_state.key = malloc(cmd->datalen); memcpy(out_state.crypt_state.key, cmd->data, cmd->datalen); #else send_error("can't set encryption key - no OpenSSL support!"); #endif } void cmd_start_crypt_out(struct ctrl_command *cmd) { #ifdef HAVE_LIBCRYPTO if (out_state.crypt) send_error("can't start encryption - already started!"); if (!out_state.crypt_state.cipher) send_error("can't start encryption - no cipher set!"); if (!out_state.crypt_state.key) send_error("can't start encryption - no key set!"); out_state.crypt = 1; if (!EVP_EncryptInit(&out_state.crypt_state.ctx, out_state.crypt_state.cipher, NULL, NULL)) send_error("can't start encryption - EncryptInit (1) failed: %s!", ERR_error_string(ERR_get_error(), NULL)); /* * XXX - ugly hack to work around OpenSSL bug * if/when OpenSSL fix it, or give proper workaround * use that, and force minimum OpenSSL version * * Without this hack, BF/256 will fail. */ /* cast to avoid warning */ *(unsigned int *)(&out_state.crypt_state.ctx.cipher->flags) |= EVP_CIPH_VARIABLE_LENGTH; if (!EVP_CIPHER_CTX_set_key_length(&out_state.crypt_state.ctx, out_state.crypt_state.keylen)) send_error("can't start encryption - set_key_length failed: %s!", ERR_error_string(ERR_get_error(), NULL)); out_state.crypt_state.ivlen = EVP_CIPHER_CTX_iv_length(&out_state.crypt_state.ctx); if (out_state.crypt_state.ivlen) out_state.crypt_state.iv = calloc(out_state.crypt_state.ivlen, 1); if (out_state.crypt_state.rounds) { if (!EVP_CIPHER_CTX_ctrl(&out_state.crypt_state.ctx, EVP_CTRL_SET_RC5_ROUNDS, out_state.crypt_state.rounds, NULL)) send_error("can't start encryption - SET_RC5_ROUNDS failed: %s!", ERR_error_string(ERR_get_error(), NULL)); } if (!EVP_EncryptInit(&out_state.crypt_state.ctx, NULL, out_state.crypt_state.key, out_state.crypt_state.iv)) send_error("can't start encryption - EncryptInit (2) failed: %s!", ERR_error_string(ERR_get_error(), NULL)); #else send_error("can't start encryption - no OpenSSL suppport!"); #endif } void cmd_init(struct ctrl_command *cmd) { if (in_state.active || out_state.active) send_error("CMD_INIT sent twice!"); in_state.active = 1; out_state.active = 1; CONTROL_R.read_cb = read_ctrl; CONTROL_W.write_cb = NULL; LOCAL_R.read_cb = read_data; LOCAL_W.write_cb = NULL; REMOTE_R.read_cb = read_net; REMOTE_W.write_cb = NULL; }