Merge remote-tracking branch 'IOMultiplexer/v2'
authorpk910 <philipp@zoelle1.de>
Thu, 24 Jul 2014 08:48:08 +0000 (10:48 +0200)
committerpk910 <philipp@zoelle1.de>
Thu, 24 Jul 2014 08:48:08 +0000 (10:48 +0200)
Conflicts:
src/IOHandler/IODNSLookup.c
src/IOHandler/IODNSLookup.h

1  2 
configure.ac
src/crypt_base64.c
src/crypt_base64.h
src/crypt_rsa.c
src/ircd_auth.c
src/ircd_client.c
src/ircd_parse.c
src/struct_client.h
src/struct_user.h

diff --cc configure.ac
index 44f4e88c1f7f52e9981d1bd612deda67d5edb5e7,4275959d2caf16b73054236bb343d5bfcd31e588..aa5b500c48416c132aef6208d20914ec46576a36
@@@ -36,22 -36,22 +36,14 @@@ AC_CHECK_FUNCS([usleep select socket in
  AC_CHECK_HEADERS([fcntl.h sys/socket.h sys/select.h sys/time.h sys/types.h unistd.h windows.h winsock2.h errno.h sys/epoll.h sys/event.h])
  
  AC_CHECK_LIB(ws2_32, main, [ LIBS="$LIBS -lws2_32" ], [])
--have_gnutls="no"
--AC_CHECK_LIB(gnutls, gnutls_init, [
--  AC_CHECK_HEADERS(gnutls/gnutls.h, [
--    LIBS="$LIBS -lgnutls"
--    have_gnutls="yes"
--  ])
--])
--if test x"$have_gnutls" = xno; then
--  AC_CHECK_LIB(ssl, SSL_read, [
--    AC_CHECK_LIB(crypto, X509_new, [
--      AC_CHECK_HEADERS(openssl/ssl.h openssl/err.h openssl/rand.h, [
--        LIBS="$LIBS -lssl -lcrypto"
--      ])
++
++AC_CHECK_LIB(ssl, SSL_read, [
++  AC_CHECK_LIB(crypto, X509_new, [
++    AC_CHECK_HEADERS(openssl/ssl.h openssl/err.h openssl/rand.h, [
++      LIBS="$LIBS -lssl -lcrypto"
      ])
    ])
--fi
++])
  AC_CHECK_LIB(pthread, pthread_create, [
    AC_CHECK_HEADERS(pthread.h, [
      LIBS="$LIBS -lpthread"
index 2e54c922e90674f63d633f71fcc4c93fe7762cce,0000000000000000000000000000000000000000..60e10eee7182f8b907aac0d09b00c4fe6b80a94f
mode 100644,000000..100644
--- /dev/null
@@@ -1,102 -1,0 +1,105 @@@
-       for (int i = 0, j = 0; i < input_length;) {
 +/* crypt_base64.c - NextIRCd
 + * 
 + * 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 3 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, see <http://www.gnu.org/licenses/>. 
 + */
 +
 +#include "crypt_base64.h"
 +#include <stdint.h>
 +#include <stdlib.h>
 +
 +static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
 +                                                              'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
 +                                                              'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
 +                                                              'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
 +                                                              'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
 +                                                              'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
 +                                                              'w', 'x', 'y', 'z', '0', '1', '2', '3',
 +                                                              '4', '5', '6', '7', '8', '9', '+', '/'};
 +static char *decoding_table = NULL;
 +static int mod_table[] = {0, 2, 1};
 +
 +
 +char *crypt_base64_encode(const unsigned char *data, size_t input_length, size_t *output_length) {
 +      *output_length = 4 * ((input_length + 2) / 3);
 +      
 +      char *encoded_data = malloc(*output_length);
 +      if (encoded_data == NULL)
 +              return NULL;
 +      
-       for (int i = 0; i < mod_table[input_length % 3]; i++)
++      int i, j;
++      for (i = 0, j = 0; i < input_length;) {
 +              uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
 +              uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
 +              uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
 +              
 +              uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
 +              
 +              encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
 +              encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
 +              encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
 +              encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
 +      }
 +      
-       for (int i = 0, j = 0; i < input_length;) {
++      for (i = 0; i < mod_table[input_length % 3]; i++)
 +              encoded_data[*output_length - 1 - i] = '=';
 +      
 +      return encoded_data;
 +}
 +
 +
 +unsigned char *crypt_base64_decode(const char *data, size_t input_length, size_t *output_length) {
 +      if (decoding_table == NULL)
 +              crypt_base64_init();
 +      if (input_length % 4 != 0)
 +              return NULL;
 +      
 +      *output_length = input_length / 4 * 3;
 +      if (data[input_length - 1] == '=') (*output_length)--;
 +      if (data[input_length - 2] == '=') (*output_length)--;
 +      
 +      unsigned char *decoded_data = malloc(*output_length);
 +      if (decoded_data == NULL)
 +              return NULL;
 +      
-       for (int i = 0; i < 64; i++)
++      int i, j;
++      for (i = 0, j = 0; i < input_length;) {
 +              uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
 +              uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
 +              uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
 +              uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
 +              
 +              uint32_t triple = (sextet_a << 3 * 6)
 +              + (sextet_b << 2 * 6)
 +              + (sextet_c << 1 * 6)
 +              + (sextet_d << 0 * 6);
 +              
 +              if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
 +              if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
 +              if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
 +      }
 +      
 +      return decoded_data;
 +}
 +
 +
 +void crypt_base64_init() {
 +      decoding_table = malloc(256);
++      int i;
++      for (i = 0; i < 64; i++)
 +              decoding_table[(unsigned char) encoding_table[i]] = i;
 +}
 +
 +void crypt_base64_deinit() {
 +      free(decoding_table);
 +}
index 5ada93c6b675a3c2e0dca528ce0be000d02b44e8,0000000000000000000000000000000000000000..2892573ed7a8ce977a64464d421f49cf16f1eaf7
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,28 @@@
 +/* crypt_base64.h - NextIRCd
 + * Copyright (C) 2012-2013  Philipp Kreil (pk910)
 + * 
 + * 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 3 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, see <http://www.gnu.org/licenses/>. 
 + */
 +
 +#ifndef _crypt_base64_h
 +#define _crypt_base64_h
++#include <stdlib.h>
 +
 +void crypt_base64_init();
 +void crypt_base64_deinit();
 +
 +char *crypt_base64_encode(const unsigned char *data, size_t input_length, size_t *output_length);
 +unsigned char *crypt_base64_decode(const char *data, size_t input_length, size_t *output_length);
 +
 +#endif
diff --cc src/crypt_rsa.c
index 80450f1222cabb1a9b3b09ca84a5dd8fe4fd6cda,0000000000000000000000000000000000000000..c78bf8907ad31c447217b7692dbdd83e54c6184c
mode 100644,000000..100644
--- /dev/null
@@@ -1,501 -1,0 +1,458 @@@
- int main(char *argv[], int argc) {
-       crypt_init();
-       
-       struct crypt_rsa_privkey *privkey;
-       FILE *fp;
-       if(fp = fopen("privkey.pem", "r")) {
-               char buffer[4096];
-               fread(buffer, sizeof(buffer), 1, fp);
-               fclose(fp);
-               
-               privkey = crypt_load_privkey(buffer);
-       } else {
-               privkey = crypt_generate_privkey(2048);
-               
-               fp = fopen("privkey.pem", "w");
-               char *buffer = crypt_export_privkey(privkey, 0);
-               fprintf(fp, "%s", buffer);
-               free(buffer);
-               fclose(fp);
-       }
-       
-       struct crypt_rsa_pubkey *pubkey = crypt_get_pubkey(privkey);
-       char plain[] = "Test String!!!";
-       char *crypted = NULL;
-       int len = crypt_encrypt_data(pubkey, plain, sizeof(plain), &crypted);
-       
-       printf("Crypt Len: %d\n", len);
-       printf("Crypt: ");
-       int i;
-       for(i = 0; i < len; i++) {
-               printf(" %02X", ((unsigned int)crypted[i] & 0xFF));
-       }
-       printf("\n");
-       
-       char *decrypted = NULL;
-       len = crypt_decrypt_data(privkey, crypted, len, &decrypted);
-       printf("Decrypt Len: %d\n", len);
-       printf("Decrypt: %s\n", decrypted);
- }
 +/* crypt_rsa.c - NextIRCd
 + * Copyright (C) 2012-2013  Philipp Kreil (pk910)
 + * 
 + * 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 3 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, see <http://www.gnu.org/licenses/>. 
 + */
 +#include "../config.h"
 +#include "crypt_rsa.h"
 +
 +#include <stdio.h>
 +#include <malloc.h>
 +#include <stdlib.h>
 +#include <string.h>
 +
 +/*
 +// GnuTLS Backend not working because of gnutls_pubkey_encrypt_data doesn't exists prior to GnuTLS 3.0
 +// still searching for a replacement...
 +
 +#if defined(HAVE_GNUTLS_GNUTLS_H)
 +#include <gnutls/gnutls.h>
 +#include <gnutls/x509.h>
 +#include <gnutls/abstract.h>
 +
 +struct crypt_rsa_pubkey {
 +      unsigned int free_crt : 1;
 +      unsigned int free_pubkey : 1;
 +      gnutls_x509_crt_t crt;
 +      gnutls_pubkey_t pubkey;
 +};
 +
 +struct crypt_rsa_privkey {
 +      unsigned int free_key : 1;
 +      unsigned int free_privkey : 1;
 +      gnutls_x509_privkey_t key;
 +      gnutls_privkey_t privkey;
 +};
 +
 +void crypt_rsa_init() {
 +      gnutls_global_init();
 +}
 +
 +void crypt_rsa_deinit() {
 +      gnutls_global_deinit();
 +}
 +
 +struct crypt_rsa_pubkey *crypt_rsa_load_pubkey(const char *key) {
 +      struct crypt_rsa_pubkey *pubkey = calloc(1, sizeof(*pubkey));
 +      int ret;
 +      const gnutls_datum_t key_dat = {(void *)key, strlen(key)};
 +      
 +      if(!pubkey)
 +              return NULL;
 +      
 +      ret = gnutls_x509_crt_init(&pubkey->crt);
 +      if(ret < 0)
 +              goto crypt_rsa_load_pubkey_fail;
 +      pubkey->free_crt = 1;
 +      
 +      ret = gnutls_x509_crt_import(pubkey->crt, &key_dat, GNUTLS_X509_FMT_PEM);
 +      if (ret < 0)
 +              goto crypt_rsa_load_pubkey_fail;
 +      
 +      ret = gnutls_pubkey_init(&pubkey->pubkey);
 +      if(ret < 0)
 +              goto crypt_rsa_load_pubkey_fail;
 +      pubkey->free_pubkey = 1;
 +      
 +      ret = gnutls_pubkey_import_x509(pubkey->pubkey, pubkey->crt, 0);
 +      if(ret < 0)
 +              goto crypt_rsa_load_pubkey_fail;
 +      
 +      return pubkey;
 +      crypt_rsa_load_pubkey_fail:
 +      crypt_rsa_unload_pubkey(pubkey);
 +      return NULL;
 +}
 +
 +void crypt_rsa_unload_pubkey(struct crypt_rsa_pubkey *pubkey) {
 +      if(pubkey->free_crt)
 +              gnutls_x509_crt_deinit(pubkey->crt);
 +      if(pubkey->free_pubkey)
 +              gnutls_pubkey_deinit(pubkey->pubkey);
 +      free(pubkey);
 +}
 +
 +char *crypt_rsa_export_pubkey(struct crypt_rsa_pubkey *pubkey) {
 +      size_t size = 1024;
 +      char *buffer = malloc(size);
 +      int ret;
 +      
 +      ret = gnutls_pubkey_export(pubkey->pubkey, GNUTLS_X509_FMT_PEM, buffer, &size);
 +      if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
 +              buffer = realloc(buffer, size);
 +              ret = gnutls_pubkey_export(pubkey->pubkey, GNUTLS_X509_FMT_PEM, buffer, &size);
 +      }
 +      if(ret < 0) {
 +              free(buffer);
 +              return NULL;
 +      }
 +      return buffer;
 +}
 +
 +struct crypt_rsa_privkey *crypt_rsa_load_privkey(const char *key) {
 +      struct crypt_rsa_privkey *privkey = calloc(1, sizeof(*privkey));
 +      int ret;
 +      
 +      const gnutls_datum_t key_dat = {(void *)key, strlen(key)};
 +      
 +      ret = gnutls_x509_privkey_init(&privkey->key);
 +      if(ret < 0)
 +              goto crypt_rsa_load_privkey_fail;
 +      privkey->free_key = 1;
 +      
 +      ret = gnutls_x509_privkey_import(privkey->key, &key_dat, GNUTLS_X509_FMT_PEM);
 +      if (ret < 0)
 +              goto crypt_rsa_load_privkey_fail;
 +      
 +      ret = gnutls_privkey_init(&privkey->privkey);
 +      if(ret < 0)
 +              goto crypt_rsa_load_privkey_fail;
 +      privkey->free_privkey = 1;
 +      
 +      ret = gnutls_privkey_import_x509(privkey->privkey, privkey->key, 0);
 +      if(ret < 0)
 +              goto crypt_rsa_load_privkey_fail;
 +      
 +      return privkey;
 +      crypt_rsa_load_privkey_fail:
 +      crypt_rsa_unload_privkey(privkey);
 +      return NULL;
 +}
 +
 +struct crypt_rsa_privkey *crypt_rsa_generate_privkey(const int keysize) {
 +      struct crypt_rsa_privkey *privkey = calloc(1, sizeof(*privkey));
 +      int ret;
 +      
 +      ret = gnutls_x509_privkey_init(&privkey->key);
 +      if(ret < 0)
 +              goto crypt_rsa_generate_privkey_fail;
 +      privkey->free_key = 1;
 +      
 +      ret = gnutls_x509_privkey_generate(privkey->key, GNUTLS_PK_RSA, keysize, 0);
 +      if (ret < 0)
 +              goto crypt_rsa_generate_privkey_fail;
 +      
 +      ret = gnutls_privkey_init(&privkey->privkey);
 +      if(ret < 0)
 +              goto crypt_rsa_generate_privkey_fail;
 +      privkey->free_privkey = 1;
 +      
 +      ret = gnutls_privkey_import_x509(privkey->privkey, privkey->key, 0);
 +      if(ret < 0)
 +              goto crypt_rsa_generate_privkey_fail;
 +      
 +      return privkey;
 +      crypt_rsa_generate_privkey_fail:
 +      crypt_rsa_unload_privkey(privkey);
 +      return NULL;
 +}
 +
 +char *crypt_rsa_export_privkey(struct crypt_rsa_privkey *privkey, int pubkey) {
 +      size_t size = 1024;
 +      char *buffer = malloc(size);
 +      int ret;
 +      
 +      if(pubkey) {
 +              gnutls_pubkey_t pkey;
 +              ret = gnutls_pubkey_init(&pkey);
 +              if(ret < 0) {
 +                      free(buffer);
 +                      return NULL;
 +              }
 +              ret = gnutls_pubkey_import_privkey(pkey, privkey->privkey, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE, 0);
 +              if(ret < 0) {
 +                      free(buffer);
 +                      gnutls_pubkey_deinit(pkey);
 +                      return NULL;
 +              }
 +              ret = gnutls_pubkey_export(pkey, GNUTLS_X509_FMT_PEM, buffer, &size);
 +              if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
 +                      buffer = realloc(buffer, size);
 +                      ret = gnutls_pubkey_export(pkey, GNUTLS_X509_FMT_PEM, buffer, &size);
 +              }
 +              gnutls_pubkey_deinit(pkey);
 +      } else {
 +              ret = gnutls_x509_privkey_export(privkey->key, GNUTLS_X509_FMT_PEM, buffer, &size);
 +              if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
 +                      buffer = realloc(buffer, size);
 +                      ret = gnutls_x509_privkey_export(privkey->key, GNUTLS_X509_FMT_PEM, buffer, &size);
 +              }
 +      }
 +      if(ret < 0) {
 +              free(buffer);
 +              return NULL;
 +      }
 +      return buffer;
 +}
 +
 +void crypt_rsa_unload_privkey(struct crypt_rsa_privkey *privkey) {
 +      if(privkey->free_key)
 +              gnutls_x509_privkey_deinit(privkey->key);
 +      if(privkey->free_privkey)
 +              gnutls_privkey_deinit(privkey->privkey);
 +      free(privkey);
 +}
 +
 +struct crypt_rsa_pubkey *crypt_rsa_get_pubkey(struct crypt_rsa_privkey *privkey) {
 +      struct crypt_rsa_pubkey *pubkey = calloc(1, sizeof(*pubkey));
 +      if(!pubkey)
 +              return NULL;
 +      int ret;
 +      
 +      ret = gnutls_pubkey_init(&pubkey->pubkey);
 +      if(ret < 0)
 +              goto crypt_rsa_get_pubkey_fail;
 +      pubkey->free_pubkey = 1;
 +      
 +      ret = gnutls_pubkey_import_privkey(pubkey->pubkey, privkey->privkey, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE, 0);
 +      if(ret < 0)
 +              goto crypt_rsa_get_pubkey_fail;
 +      
 +      return pubkey;
 +      crypt_rsa_get_pubkey_fail:
 +      crypt_rsa_unload_pubkey(pubkey);
 +      return NULL;
 +}
 +
 +int crypt_rsa_encrypt_data(struct crypt_rsa_pubkey *pubkey, const char *data, int datalen, char **encrypted) {
 +      const gnutls_datum_t data_dat = {(void *)data, datalen};
 +      gnutls_datum_t out;
 +      
 +      int ret = gnutls_pubkey_encrypt_data(pubkey->pubkey, 0, &data_dat, &out);
 +      if(ret < 0)
 +              return ret;
 +      
 +      *encrypted = out.data;
 +      return out.size;
 +}
 +
 +int crypt_rsa_decrypt_data(struct crypt_rsa_privkey *privkey, const char *encrypted, int enclen, char **data) {
 +      const gnutls_datum_t enc_dat = {(void *)encrypted, enclen};
 +      gnutls_datum_t out;
 +      
 +      int ret = gnutls_privkey_decrypt_data(privkey->privkey, 0, &enc_dat, &out);
 +      if(ret < 0)
 +              return ret;
 +      
 +      *data = out.data;
 +      return out.size;
 +}
 +
 +int crypt_rsa_encrypt_maxlen(struct crypt_rsa_pubkey *pubkey) {
 +      //int size = (pubkey->pubkey->bits / 8) - 12;
 +      //todo!
 +      int size = 1024;
 +      return size;
 +}
 +
 +void crypt_rsa_encrypt_free(char *encrypted) {
 +      gnutls_free(encrypted);
 +}
 +
 +void crypt_rsa_decrypt_free(char *data) {
 +      gnutls_free(data);
 +}
 +
 +#elif defined(HAVE_OPENSSL_SSL_H)
 +*/
 +
 +#include <openssl/pem.h>
 +#include <openssl/ssl.h>
 +#include <openssl/rsa.h>
 +#include <openssl/evp.h>
 +#include <openssl/bio.h>
 +#include <openssl/err.h>
 +
 +struct crypt_rsa_pubkey {
 +      RSA *rsa;
 +};
 +
 +struct crypt_rsa_privkey {
 +      RSA *rsa;
 +};
 +
 +void crypt_rsa_init() {
 +      
 +}
 +
 +void crypt_rsa_deinit() {
 +      
 +}
 +
 +RSA *createRSA(unsigned char *key, int public) {
 +    RSA *rsa= NULL;
 +    BIO *keybio ;
 +    keybio = BIO_new_mem_buf(key, -1);
 +    if(!keybio)
 +        return NULL;
 +    if(public)
 +        rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
 +    else
 +        rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL);
 +    BIO_free(keybio);
 +    return rsa;
 +}
 +
 +struct crypt_rsa_pubkey *crypt_rsa_load_pubkey(const char *key) {
 +      struct crypt_rsa_pubkey *pubkey = calloc(1, sizeof(*pubkey));
 +      if(!pubkey)
 +              return NULL;
 +      
 +      RSA *rsa = createRSA((unsigned char *) key, 1);
 +      
 +      if(!rsa) {
 +              free(pubkey);
 +              return NULL;
 +      }
 +      
 +      pubkey->rsa = rsa;
 +      return pubkey;
 +}
 +
 +void crypt_rsa_unload_pubkey(struct crypt_rsa_pubkey *pubkey) {
 +      RSA_free(pubkey->rsa);
 +      free(pubkey);
 +}
 +
 +char *crypt_rsa_export_pubkey(struct crypt_rsa_pubkey *pubkey) {
 +      BIO *bio = BIO_new(BIO_s_mem());
 +      PEM_write_bio_RSA_PUBKEY(bio, pubkey->rsa);
 +      
 +      int keylen = BIO_pending(bio);
 +      char *key = calloc(1, keylen+1);
 +      BIO_read(bio, key, keylen);
 +      
 +      BIO_free_all(bio);
 +      return key;
 +}
 +
 +struct crypt_rsa_privkey *crypt_rsa_load_privkey(const char *key) {
 +      struct crypt_rsa_privkey *privkey = calloc(1, sizeof(*privkey));
 +      if(!privkey)
 +              return NULL;
 +      
 +      RSA *rsa = createRSA((unsigned char *) key, 0);
 +      
 +      if(!rsa) {
 +              free(privkey);
 +              return NULL;
 +      }
 +      
 +      privkey->rsa = rsa;
 +      return privkey;
 +}
 +
 +struct crypt_rsa_privkey *crypt_rsa_generate_privkey(const int keysize) {
 +      struct crypt_rsa_privkey *privkey = calloc(1, sizeof(*privkey));
 +      if(!privkey)
 +              return NULL;
 +              
 +      BIGNUM *e = BN_new();
 +      RSA *rsa = RSA_new();
 +      
 +      BN_set_word(e, 65537);
 +      if (!RSA_generate_key_ex(rsa, keysize, e, NULL)) {
 +              BN_free(e);
 +              RSA_free(rsa);
 +              free(privkey);
 +              return NULL;
 +      }
 +      
 +      privkey->rsa = rsa;
 +      return privkey;
 +}
 +
 +char *crypt_rsa_export_privkey(struct crypt_rsa_privkey *privkey, int pubkey) {
 +      BIO *bio = BIO_new(BIO_s_mem());
 +      if(pubkey)
 +              PEM_write_bio_RSA_PUBKEY(bio, privkey->rsa);
 +      else
 +              PEM_write_bio_RSAPrivateKey(bio, privkey->rsa, NULL, NULL, 0, NULL, NULL);
 +      
 +      int keylen = BIO_pending(bio);
 +      char *key = calloc(1, keylen+1);
 +      BIO_read(bio, key, keylen);
 +      
 +      BIO_free_all(bio);
 +      return key;
 +}
 +
 +void crypt_rsa_unload_privkey(struct crypt_rsa_privkey *privkey) {
 +      RSA_free(privkey->rsa);
 +      free(privkey);
 +}
 +
 +struct crypt_rsa_pubkey *crypt_rsa_get_pubkey(struct crypt_rsa_privkey *privkey) {
 +      struct crypt_rsa_pubkey *pubkey = calloc(1, sizeof(*pubkey));
 +      if(!pubkey)
 +              return NULL;
 +      
 +      RSA *rsa = RSA_new();
 +      memcpy(rsa, privkey->rsa, sizeof(*rsa));
 +      
 +      pubkey->rsa = rsa;
 +      return pubkey;
 +}
 +
 +int crypt_rsa_encrypt_data(struct crypt_rsa_pubkey *pubkey, const char *data, int datalen, char **encrypted) {
 +      if(!pubkey)
 +              return 0;
 +      if(datalen > crypt_rsa_encrypt_maxlen(pubkey))
 +              return 0;
 +      *encrypted = malloc(RSA_size(pubkey->rsa));
 +      if(!*encrypted)
 +              return 0;
 +      int ret = RSA_public_encrypt(datalen, data, *encrypted, pubkey->rsa, RSA_PKCS1_PADDING);
 +      if(ret <= 0)
 +              free(*encrypted);
 +      return ret;
 +}
 +
 +int crypt_rsa_decrypt_data(struct crypt_rsa_privkey *privkey, const char *encrypted, int enclen, char **data) {
 +      if(!privkey)
 +              return 0;
 +      if(enclen > RSA_size(privkey->rsa))
 +              return 0;
 +      *data = malloc(RSA_size(privkey->rsa));
 +      if(!*data)
 +              return 0;
 +      int ret = RSA_private_decrypt(enclen, encrypted, *data, privkey->rsa, RSA_PKCS1_PADDING);
 +      if(ret <= 0)
 +              free(*data);
 +      return ret;
 +}
 +
 +int crypt_rsa_encrypt_maxlen(struct crypt_rsa_pubkey *pubkey) {
 +      return RSA_size(pubkey->rsa) - 12;
 +}
 +
 +void crypt_rsa_encrypt_free(char *encrypted) {
 +      free(encrypted);
 +}
 +
 +void crypt_rsa_decrypt_free(char *data) {
 +      free(data);
 +}
 +
 +//#endif
diff --cc src/ircd_auth.c
index 0478f9b25b3ee319666d031908f237c055000678,0000000000000000000000000000000000000000..8079db1c78ff89092687b1ca5a1be44eba316dca
mode 100644,000000..100644
--- /dev/null
@@@ -1,84 -1,0 +1,85 @@@
-               authlist_first = auth
 +/* ircd_auth.c - NextIRCd
 + * Copyright (C) 2012-2013  Philipp Kreil (pk910)
 + * 
 + * 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 3 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, see <http://www.gnu.org/licenses/>. 
 + */
++
++#include <string.h>
++
 +#include "struct_auth.h"
 +#include "struct_connection.h"
 +#include "ircd_client.h"
 +#include "IOHandler/IOSockets.h"
 +#include "IOHandler/IODNSLookup.h"
 +#include "version.h"
 +
 +static IODNS_CALLBACK(auth_dns_callback);
 +
 +static struct Auth *authlist_first = NULL;
 +static struct Auth *authlist_last = NULL;
 +
 +struct Auth *auth_new(struct Connection *conn) {
 +      struct Auth *auth = calloc(1, sizeof(*auth));
 +      client_printf(conn, "NOTICE AUTH :*** NextIRCd v%d.%d (%s)", VERSION_NUMBER, patchlevel, revision);
 +      
 +      auth->conn = conn;
 +      time(&auth->startup_time);
 +      
 +      auth->prev = authlist_last;
 +      auth->next = NULL;
 +      if(!authlist_last)
-               if(sockaddr->addresslen == sizeof(struct sockaddr_in)) {
-                       //ipv4
-                       inet_ntop(AF_INET, (void *)(&((struct sockaddr_in *)sockaddr->address)->sin_addr), auth->host, HOSTLEN);
-               } else {
-                       //ipv6
++              authlist_first = auth;
 +      authlist_last = auth;
 +      
 +      return auth;
 +}
 +
 +void auth_start_dnsreverse(struct Auth *auth) {
 +      client_printf(auth->conn, "NOTICE AUTH :*** Looking up your hostname");
 +      
 +      struct IODNSAddress *sockaddr;
 +      sockaddr = iosocket_get_remote_addr(auth->conn->socket);
 +      if(sockaddr) {
 +              auth->dnslookup = iodns_getnameinfo(sockaddr->address, sockaddr->addresslen, auth_dns_callback, auth);
 +      } else {
 +              // critical error!
 +      }
 +}
 +
 +static IODNS_CALLBACK(auth_dns_callback) {
 +      struct Auth *auth = event->query->data;
 +      struct IODNSResult *dnsresult = event->result;
 +      
 +      if(event->type == IODNSEVENT_SUCCESS) {
 +              strncpy(auth->host, dnsresult->result.host, HOSTLEN);
 +              client_printf(auth->conn, "NOTICE AUTH :*** Found your hostname (%s)", auth->host);
 +      } else {
 +              struct IODNSAddress *sockaddr = iosocket_get_remote_addr(auth->conn->socket);
-               }
++              if(auth->conn->ipv6)
 +                      inet_ntop(AF_INET6, (void *)(&((struct sockaddr_in6 *)sockaddr->address)->sin6_addr), auth->host, HOSTLEN);
++              else
++                      inet_ntop(AF_INET, (void *)(&((struct sockaddr_in *)sockaddr->address)->sin_addr), auth->host, HOSTLEN);
++              
 +              client_printf(auth->conn, "NOTICE AUTH :*** Couldn't look up your hostname. Using your IP instead (%s)", auth->host);
 +      }
 +      if(dnsresult)
 +              iodns_free_result(dnsresult);
 +      
 +      auth_try_finish(auth);
 +}
 +
 +
 +void auth_try_finish(struct Auth *auth) {
 +
 +}
index 5af6f1d2bf40d29864ad69d6619950e50d40e0cd,0000000000000000000000000000000000000000..6fddf0966bbee8e2d5ab2b20dc144ce85526f54f
mode 100644,000000..100644
--- /dev/null
@@@ -1,51 -1,0 +1,52 @@@
 +/* ircd_client.c - NextIRCd
 + * Copyright (C) 2012-2013  Philipp Kreil (pk910)
 + * 
 + * 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 3 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, see <http://www.gnu.org/licenses/>. 
 + */
 +
 +#include "ircd_client.h"
 +#include "ircd_sock.h"
 +#include "struct_connection.h"
 +#include "struct_auth.h"
 +#include "ircd_config.h"
++#include "ircd_auth.h"
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <stdarg.h>
 +#define CLIENT_MAXLEN 512
 +
 +void client_printf(struct Connection *conn, const char *text, ...) {
 +    va_list arg_list;
 +      char sendBuf[CLIENT_MAXLEN];
 +      int pos;
 +      sendBuf[0] = '\0';
 +      va_start(arg_list, text);
 +      pos = vsnprintf(sendBuf, CLIENT_MAXLEN - 2, text, arg_list);
 +      va_end(arg_list);
 +      if (pos < 0 || pos > (CLIENT_MAXLEN - 2)) pos = CLIENT_MAXLEN - 2;
 +      sendBuf[pos] = '\n';
 +    sendBuf[pos+1] = '\0';
 +      socket_send(conn, sendBuf, pos+1);
 +}
 +
 +void client_connected(struct Connection *conn) {
 +    struct Auth *auth = auth_new(conn);
 +      
 +      auth_start_dnsreverse(auth);
 +}
 +
 +void client_disconnected(struct Connection *conn) {
 +    
 +}
index 12dc6deb66faa12f582bb1ddf836a40aef61b3a4,0000000000000000000000000000000000000000..1bfa8b78fbf482a29f47f372bff1b6491c2ed7f6
mode 100644,000000..100644
--- /dev/null
@@@ -1,305 -1,0 +1,313 @@@
- #include "cmd_ping.h"
 +/* ircd_client.c - NextIRCd
 + * Copyright (C) 2012-2013  Philipp Kreil (pk910)
 + * 
 + * 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 3 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, see <http://www.gnu.org/licenses/>. 
 + */
 +
++#include <stdlib.h>
++#include <string.h>
++
 +#include "tools.h"
 +#include "IOHandler/IOSockets.h"
++#include "ircd_parse.h"
++struct Server;
++#include "struct_client.h"
++#include "struct_auth.h"
++#include "struct_servermsg.h"
 +
 +typedef int cmd_client_t(struct Client *client, char *argv[], int argc);
 +typedef int cmd_auth_t(struct Auth *auth, char *argv[], int argc);
 +typedef int cmd_server_t(struct Server *server, char *argv[], int argc);
 +
 +static struct ServerMsg parse_static_srvmsg;
 +
 +#define PARSE_CLIFLAG_OPONLY 0x01
 +
 +//include all commands
- } parse_command_list {
++#include "cmd_nick.h"
 +
 +
 +struct {
 +      struct {
 +              const char *client;
 +              const char *server;
 +      } tokens;
 +      struct {
 +              cmd_client_t *function;
 +              unsigned int min_argc : 8;
 +              unsigned int max_argc : 8;
 +              unsigned int flags : 8;
 +      } client;
 +      struct {
 +              cmd_auth_t *function;
 +              unsigned int min_argc : 8;
 +              unsigned int max_argc : 8;
 +              unsigned int flags : 8;
 +      } auth;
 +      struct {
 +              cmd_server_t *function;
 +              unsigned int min_argc : 8;
 +              unsigned int max_argc : 8;
 +              unsigned int flags : 8;
 +      } server;
 +      
-         while (*line == ' ')
-             *line++ = 0;
-         if (*line == ':') {
++} parse_command_list[] = {
 +      {{"PING", "P"}, /* Ping Command */
 +              {NULL, 0, 1, 0}, /* Client */
 +              {NULL, 0, 1, 0}, /* Unauthed */
 +              {NULL, 0, 1, 0}  /* Server */
 +      },
 +      {{"PASS", NULL}, /* PASS Command */
 +              {NULL, 0, 1, 0}, /* Client */
 +              {NULL, 0, 1, 0}, /* Unauthed */
 +              {NULL, 0, 1, 0}  /* Server */
 +      },
 +      {{"NICK", "N"}, /* Nick Command */
 +              {cmd_nick_cli, 1, 1, 0}, /* Client */
 +              {cmd_nick_auth, 1, 1, 0}, /* Unauthed */
 +              {NULL, 0, 1, 0}  /* Server */
 +      },
 +      {{"USER", "U"}, /* User Command */
 +              {NULL, 0, 1, 0}, /* Client */
 +              {NULL, 0, 1, 0}, /* Unauthed */
 +              {NULL, 0, 1, 0}  /* Server */
 +      },
 +      
 +      {{NULL, NULL},{NULL, 0, 0, 0},{NULL, 0, 0, 0},{NULL, 0, 0, 0}}
 +};
 +
 +static char *parse_irc_token(char **data) {
 +      //find next " "
 +      int i;
 +      char *token = *data;
 +      for(i = 0; *data[i]; i++) {
 +              if(*data[i] != ' ') {
 +                      *data[i] = '\0';
 +                      *data += i+1;
 +                      break;
 +              }
 +      }
 +      return token;
 +}
 +
 +static char **parse_irc_params(char *data, int *argc, int maxargs) {
 +      if(maxargs == 0) {
 +              *argc = 0;
 +              return NULL;
 +      }
 +    char **argv = calloc(maxargs, sizeof(*argv));
 +    while(*data) {
 +        //skip leading spaces
-            argv[*argc++] = line + 1;
++        while (*data == ' ')
++            *data++ = 0;
++        if (*data == ':') {
 +           //the rest is a single parameter
-         argv[*argc++] = line;
-         if (argc >= maxargs)
++           argv[*argc++] = data + 1;
 +           break;
 +        }
-         while (*line != ' ' && *line)
-             line++;
++        argv[*argc++] = data;
++        if (*argc >= maxargs)
 +            break;
-                       srvmsg->destinations->dst[0].destination.resolved_destination = 0;
++        while (*data != ' ' && *data)
++            data++;
 +    }
 +    return argv;
 +}
 +
 +/* Client Data Format
 +* <TOKEN> <arg1> <arg2>
 +*/
 +void parse_client_data(struct Client *client, char *data) {
 +    char *token = parse_irc_token(&data);
 +      int found = 0;
 +      int i;
 +      for(i = 0; (parse_command_list[i].tokens.client ||  parse_command_list[i].tokens.server); i++) {
 +              if(stricmp(parse_command_list[i].tokens.client, token)) {
 +                      found = 1;
 +                      break;
 +              }
 +      }
 +      if(found && !parse_command_list[i].client.function) {
 +              // reply 462 You may not reregister
 +      } else if(found) {
 +              int argc;
 +              char **argv = parse_irc_params(data, &argc, parse_command_list[i].client.max_argc);
 +              if(argc < parse_command_list[i].client.min_argc) {
 +                      // reply 461 Not enough parameters
 +              } else {
 +                      int ret = parse_command_list[i].client.function(client, argv, argc);
 +                      if(ret) {
 +                              // error occurred!
 +                              // do something?
 +                      }
 +              }
 +              free(argv);
 +      } else {
 +              // reply 421 Unknown command
 +      }
 +}
 +
 +void parse_unauth_data(struct Auth *auth, char *data) {
 +      char *token = parse_irc_token(&data);
 +      int found = 0;
 +      int i;
 +      for(i = 0; (parse_command_list[i].tokens.client ||  parse_command_list[i].tokens.server); i++) {
 +              if(stricmp(parse_command_list[i].tokens.client, token)) {
 +                      found = 1;
 +                      break;
 +              }
 +      }
 +      if(found && !parse_command_list[i].auth.function) {
 +              // reply 451 Register first.
 +      } else if(found) {
 +              int argc;
 +              char **argv = parse_irc_params(data, &argc, parse_command_list[i].auth.max_argc);
 +              if(argc < parse_command_list[i].auth.min_argc) {
 +                      // reply 461 Not enough parameters
 +              } else {
 +                      int ret = parse_command_list[i].auth.function(auth, argv, argc);
 +                      if(ret) {
 +                              // error occurred!
 +                              // do something?
 +                      }
 +              }
 +              free(argv);
 +      } else {
 +              // reply 421 Unknown command
 +      }
 +}
 +
 +/* Unicast                  Multicast                 Broadcast
 +* <src-srvnum> 4 Bytes      <source>     4 Bytes      <source>     4 Bytes
 +* <length>     2 Bytes      <length>     2 Bytes      <length>     2 Bytes
 +* <flags>      1 Byte       <flags>      1 Byte       <flags>      1 Byte
 +* <token>      x Bytes      <token>      x Bytes      <token>      x Bytes
 +* " "          1 Byte       " "          1 Byte       " "          1 Byte
 +* <dst-srvnum> 4 Bytes      <servers>    1 Byte       <ttl>        1 Byte
 +*                           <dst-srv01>  4 Bytes      
 +*                           <dst-srv02>  4 Bytes      
 +* <args>                    <args>                    <args>
 +*/
 +void parse_server_data(struct Server *server, struct IOSocketBuffer *buffer) {
 +      struct ServerMsg *srvmsg = &parse_static_srvmsg;
 +      unsigned char *buf = (unsigned char *)buffer->buffer;
 +      unsigned int buflen, require_more = 0;
 +      int i;
 +      
 +      while(buffer->bufpos >= 9 && !require_more) { //require at least 9 Bytes
 +              srvmsg->source.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
 +              srvmsg->resolved_source = 0;
 +              srvmsg->msglen = ((buf[4] << 8) | buf[5]);
 +              srvmsg->msgflags = buf[6];
 +              srvmsg->msgtype  = (buf[6] & SERVERMSG_TYPEMASK);
 +              
 +              if(buffer->bufpos < srvmsg->msglen) {
 +                      require_more = 1;
 +                      break;
 +              }
 +              
 +              for(i = 0; buffer->bufpos > i+7; i++) {
 +                      if(buf[i+7] == ' ') {
 +                              if(i >= MAXSERVERTOKENLEN)
 +                                      srvmsg->token[MAXSERVERTOKENLEN] = '\0';
 +                              else
 +                                      srvmsg->token[i] = '\0';
 +                              break;
 +                      }
 +                      if(i >= MAXSERVERTOKENLEN)
 +                              continue;
 +                      srvmsg->token[i] = buf[i+7];
 +              }
 +              if(buf[i+7] != ' ') {
 +                      require_more = 1;
 +                      break;
 +              }
 +              buf += i+8;
 +              buflen = buffer->bufpos - (i+8);
 +              
 +              switch(srvmsg->msgtype) {
 +              case SERVERMSG_TYPE_UNICAST:
 +                      if(buflen < 4) {
 +                              require_more = 1;
 +                              break;
 +                      }
 +                      srvmsg->destinations = malloc(sizeof(struct ServerMsgDstMap));
 +                      srvmsg->destinations->dstcount = 1;
 +                      srvmsg->destinations->dst[0].destination.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
-                               srvmsg->destinations->dst[i].destination.resolved_destination = 0;
++                      srvmsg->destinations->dst[0].resolved_destination = 0;
 +                      break;
 +              case SERVERMSG_TYPE_MULTICAST:
 +                      if(buflen < 5) {
 +                              require_more = 1;
 +                              break;
 +                      }
 +                      unsigned int srvcount = buf[0];
 +                      buf++;
 +                      buflen--;
 +                      if(buflen < (srvcount * 4)) {
 +                              require_more = 1;
 +                              break;
 +                      }
 +                      srvmsg->destinations = malloc(sizeof(struct ServerMsgDstMap) + (sizeof(struct ServerMsgDestination) * (srvcount - 1)));
 +                      srvmsg->destinations->dstcount = srvcount;
 +                      for(i = 0; i < srvcount; i++) {
 +                              srvmsg->destinations->dst[i].destination.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
-               srvmsg->arglen = srvmsg->msglen - (buf - buffer->buffer);
++                              srvmsg->destinations->dst[i].resolved_destination = 0;
 +                              buf += 4;
 +                              buflen -= 4;
 +                      }
 +                      break;
 +              case SERVERMSG_TYPE_BROADCAST:
 +                      if(buflen == 0) {
 +                              require_more = 1;
 +                              break;
 +                      }
 +                      srvmsg->destinations = NULL;
 +                      srvmsg->msgttl = buf[0];
 +                      buf++;
 +                      buflen--;
 +                      break;
 +              default:
 +                      // PARSE ERROR
 +                      goto parse_server_data_finish;
 +              }
 +              
-                       srvmsg->bufpos = 0;
++              srvmsg->arglen = srvmsg->msglen - (buf - (unsigned char *)buffer->buffer);
 +              srvmsg->args = buf;
 +              
 +              int found = 0;
 +              for(i = 0; (parse_command_list[i].tokens.client ||  parse_command_list[i].tokens.server); i++) {
 +                      if(stricmp(parse_command_list[i].tokens.server, srvmsg->token)) {
 +                              found = 1;
 +                              break;
 +                      }
 +              }
 +              if(!found)
 +                      goto parse_server_data_finish;
 +              
 +              //exec command function
 +              
 +      
 +              parse_server_data_finish:
 +              if(srvmsg->destinations)
 +                      free(srvmsg->destinations);
 +              
 +              if(srvmsg->msglen > buffer->bufpos) {
 +                      memmove(buffer->buffer, buffer->buffer + srvmsg->msglen, srvmsg->msglen - buffer->bufpos);
 +                      buffer->bufpos -= srvmsg->msglen;
 +              } else 
++                      buffer->bufpos = 0;
 +      }
 +}
 +
index 537b832a5abd8c3c65181c9cddb73ddcd1ad81ad,0000000000000000000000000000000000000000..a944bb2a0df7d811663bb6108ab9ac3730b27be9
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,58 @@@
- #include "crypto_md5.h"
 +/* struct_client.h - NextIRCd
 + * Copyright (C) 2012-2013  Philipp Kreil (pk910)
 + * 
 + * 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 3 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, see <http://www.gnu.org/licenses/>. 
 + */
 +
 +#ifndef _struct_client_h
 +#define _struct_client_h
-       struct Client *prev, *next
++#include "crypt_md5.h"
 +#include "struct_user.h"
 +
 +struct Connection;
 +struct User;
 +
 +struct ClientNickChange;
 +
 +#define AWAYLEN  300
 +
 +/* Client represents a local User */
 +struct Client {
 +    struct Connection *conn;
 +      struct User *user;
 +      
 +      struct ClientNickChange *nickchange;
 +      
 +      time_t userage;
 +      time_t nickage;
 +      time_t lastping;
 +      time_t idlelen;
 +    
 +      char *userage_sign;
 +      char *nickage_sign;
 +      
 +      char awaymsg[AWAYLEN-1];
 +      
 +      unsigned int isonline : 1;
 +      unsigned int isaway : 1;
 +      
++      struct Client *prev, *next;
 +};
 +
 +struct ClientNickChange {
 +      char newnick[NICKLEN+1];
 +      char nickhash[MDHASHLEN];
 +};
 +
 +#endif
index 9fc65c3597c78e1320c032550a34d039d0400664,0000000000000000000000000000000000000000..57aac3db5f97a634a4b6d4db310fb3383574e101
mode 100644,000000..100644
--- /dev/null
@@@ -1,44 -1,0 +1,44 @@@
- #include "crypto_md5.h"
 +/* struct_user.h - NextIRCd
 + * Copyright (C) 2012-2013  Philipp Kreil (pk910)
 + * 
 + * 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 3 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, see <http://www.gnu.org/licenses/>. 
 + */
 +
 +#ifndef _struct_user_h
 +#define _struct_user_h
++#include "crypt_md5.h"
 +
 +#define NICKLEN   30
 +#define IDENTLEN  15
 +#define HOSTLEN   63
 +#define REALLEN   50
 +
 +struct User {
 +    unsigned int usernum;
 +      unsigned int servernum;
 +      
 +      struct Server *server;
 +      
 +      unsigned int islocal : 1;
 +      
 +      char nick[NICKLEN+1];
 +      char nickhash[MDHASHLEN];
 +      char ident[IDENTLEN+1];
 +      char realname[REALLEN+1];
 +      char hostname[HOSTLEN+1];
 +      
 +      struct Member *channels;
 +};
 +
 +#endif