From 1adde65db245ec1fca752cfee4c198badf40fb5f Mon Sep 17 00:00:00 2001 From: Jakub Sławiński Date: Tue, 15 Mar 2005 01:22:55 +0100 Subject: v0.6 - Fixed: default password incompatibilities from config file - Added: "client's id" option - Lightly Modified: verbose mode - Added: temporary listen ports - Fixed: bug in printing "client's id" - Added: 'dateformat' option to set format of the date in the logs - Modified: command line option and config file behaviour - Added: logging to a socket - Fixed: parsing config file - Fixed: major bug in packet buffering - Added: several clients-users in one realm - Modified: default hostname used by afserver - Modified: server listening behaviour (for clients) - Fixed: bug in checking options values - Modified: verbose mode - Modified: client initial connection to server - Added: connection time / uptime statistics - Added: first version of remote administration (statistics only) - Fixed: major bug in remove_client routine - Added: 'raclients' option - Added: use of automake/autoconf - Added: creating ~/.apf directory - Modified: the way of creating/managing keys/certificates - Added: 'dnslookups' option - Modified: usage functions - Fixed: no handling of missing 'listen' option after 'newrealm' in config file - Added: 'quit' command in remote administration mode - Modified: logging error messages during initialization - Modified: 'newrealm' changed to 'realm' in config file - Added: realm names - Modified: connection time / uptime - Added: client names / unique numbers - Added: user unique numbers - Fixed: segmentation fault after 'quit' command --- src/afserver.c | 1720 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1720 insertions(+) create mode 100644 src/afserver.c (limited to 'src/afserver.c') diff --git a/src/afserver.c b/src/afserver.c new file mode 100644 index 0000000..d1e11b7 --- /dev/null +++ b/src/afserver.c @@ -0,0 +1,1720 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 jeremian + * + * 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. + * + */ + +#include + +#include "afserver.h" + +static struct option long_options[] = { + {"help", 0, 0, 'h'}, + {"hostname", 1, 0, 'n'}, + {"listenport", 1, 0, 'l'}, + {"manageport", 1, 0, 'm'}, + {"timeout", 1, 0, 't'}, + {"verbose", 0, 0, 'v'}, + {"users", 1, 0, 'u'}, + {"clients", 1, 0, 'C'}, + {"realm", 1, 0, 'r'}, + {"raclients", 1, 0, 'R'}, + {"usrpcli", 1, 0, 'U'}, + {"climode", 1, 0, 'M'}, + {"cerfile", 1, 0, 'c'}, + {"keyfile", 1, 0, 'k'}, + {"cfgfile", 1, 0, 'f'}, + {"proto", 1, 0, 'p'}, + {"lightlog", 1, 0, 'o'}, + {"heavylog", 1, 0, 'O'}, + {"heavysocklog", 1, 0, 'S'}, + {"lightsocklog", 1, 0, 's'}, + {"nossl", 0, 0, 301}, + {"nozlib", 0, 0, 302}, + {"pass", 1, 0, 303}, +#ifdef AF_INET6 + {"ipv4", 0, 0, '4'}, + {"ipv6", 0, 0, '6'}, +#endif + {"baseport", 0, 0, 'b'}, + {"dnslookups", 0, 0, 311}, + {"dateformat", 1, 0, 'D'}, + {0, 0, 0, 0} +}; + +static ConfigurationT config; + +int +main(int argc, char **argv) +{ + int i, j=0, k, l, n, flags, sent = 0; + socklen_t len; + unsigned char buff[9000]; + int maxfdp1; + fd_set rset, allset, wset, tmpset; + int manconnecting, numofcon, length; + char* name = NULL; + char** listen = NULL; + int listencount = 0; + char** manage = NULL; + int managecount = 0; + char* amount = NULL; + char* clients = NULL; + char* raclients = NULL; + char* usrpcli = NULL; + char* clim = NULL; + char* filenam = NULL; + char* type = NULL; + char* timeout = NULL; + char* realmname = NULL; + unsigned char pass[4] = {1, 2, 3, 4}; + char verbose = 0; + char mode = 0; + char ipfam = 0; + char baseport = 0; + char dnslookups = 0; + RealmT* pointer = NULL; + struct sigaction act; + + char* certif = NULL; + char* keys = NULL; + char* logfnam = NULL; + char* logsport = NULL; + char* dateformat = NULL; + char logging = 0; + char socklogging = 0; + + SSL_METHOD* method; + SSL_CTX* ctx; + SSL* tmp_ssl; + + sigfillset(&(act.sa_mask)); + act.sa_flags = 0; + + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &act, NULL); + act.sa_handler = sig_int; + sigaction(SIGINT, &act, NULL); + + TYPE_SET_SSL(mode); + TYPE_SET_ZLIB(mode); + + config.certif = NULL; + config.keys = NULL; + config.size = 0; + config.realmtable = NULL; + config.logging = 0; + config.socklogging = 0; + config.logfnam = NULL; + config.logsport = NULL; + config.dateformat = NULL; + +#ifdef AF_INET6 + while ((n = getopt_long(argc, argv, "hn:l:m:vu:c:k:f:p:o:O:46t:C:U:M:bD:S:s:R:r:", long_options, 0)) != -1) { +#else + while ((n = getopt_long(argc, argv, "hn:l:m:vu:c:k:f:p:o:O:t:C:U:M:bD:S:s:R:r:", long_options, 0)) != -1) { +#endif + switch (n) { + case 'h': { + usage(AF_VER("Active port forwarder (server)")); + break; + } + case 'n': { + name = optarg; + break; + } + case 'l': { + ++listencount; + listen = realloc(listen, sizeof(char*)); + listen[listencount-1] = optarg; + break; + } + case 'm': { + ++managecount; + manage = realloc(manage, sizeof(char*)); + manage[managecount-1] = optarg; + break; + } + case 't': { + timeout = optarg; + break; + } + case 'v': { + ++verbose; + break; + } + case 'u': { + amount = optarg; + break; + } + case 'C': { + clients = optarg; + break; + } + case 'r': { + realmname = optarg; + break; + } + case 'R': { + raclients = optarg; + break; + } + case 'U': { + usrpcli = optarg; + break; + } + case 'M': { + clim = optarg; + break; + } + case 'c': { + certif = optarg; + break; + } + case 'k': { + keys = optarg; + break; + } + case 'p': { + type = optarg; + break; + } + case 'f': { + filenam = optarg; + break; + } + case 'O': { + logfnam = optarg; + logging = 3; + break; + } + case 'o': { + logfnam = optarg; + logging = 1; + break; + } + case 'S': { + logsport = optarg; + socklogging = 3; + break; + } + case 's': { + logsport = optarg; + socklogging = 1; + break; + } + case 301: { + TYPE_UNSET_SSL(mode); + break; + } + case 302: { + TYPE_UNSET_ZLIB(mode); + break; + } + case 303: { + n = strlen(optarg); + memset(pass, 0, 4); + for (i = 0; i < n; ++i) { + pass[i%4] += optarg[i]; + } + sent = 1; + break; + } +#ifdef AF_INET6 + case '4': { + if (ipfam != 0) { + ipfam = -1; + } + else { + ipfam = 4; + } + break; + } + case '6': { + if (ipfam != 0) { + ipfam = -1; + } + else { + ipfam = 6; + } + break; + } +#endif + case 'b': { + baseport = 1; + break; + } + case 311: { + dnslookups = 1; + break; + } + case 'D': { + dateformat = optarg; + break; + } + case '?': { + usage(""); + break; + } + } + } + + if (optind < argc) { + usage("Unrecognized non-option elements"); + } + + if (filenam != NULL) { + config = parsefile(filenam, &n); + if (n) { + printf("parsing failed! line:%d\n", n); + exit(1); + } + else { + if (certif == NULL) { + config.certif = "cacert.pem"; + } + else { + config.certif = certif; + } + if (keys == NULL) { + config.keys = "server.rsa"; + } + else { + config.keys = keys; + } + if (logfnam != NULL) { + config.logfnam = logfnam; + } + if (logsport != NULL) { + config.logsport = logsport; + } + if (dateformat != NULL) { + config.dateformat = dateformat; + } + if (logging != 0) { + config.logging = logging; + } + if (socklogging != 0) { + config.socklogging = socklogging; + } + + if ((k = loginit(verbose, config.logging, config.socklogging, + config.logfnam, config.logsport, config.dateformat))) { + switch (k) { + case 1: + printf("Can't open file to log to... exiting\n"); + break; + case 2: + printf("Can't connect to localhost:%s... exiting\n", logsport); + break; + case 3: + printf("Can't open socket to log to... exiting\n"); + break; + } + exit(1); + } + + aflog(1, "cfg file OK! (readed realms: %d)", config.size); + if (name != NULL) + aflog(1, "Warning: hostname=%s will be ignored", name); + if (listen != NULL) + aflog(1, "Warning: listenport will be ignored"); + if (manage != NULL) + aflog(1, "Warning: manageport will be ignored"); + if (realmname != NULL) + aflog(1, "Warning: realmname=%s will be ignored", realmname); + if (sent == 1) + aflog(1, "Warning: password from command line will be ignored"); + } + } + else { + config.certif = certif; + config.keys = keys; + config.logfnam = logfnam; + config.logsport = logsport; + config.dateformat = dateformat; + config.logging = logging; + config.socklogging = socklogging; + + if ((k = loginit(verbose, config.logging, config.socklogging, + config.logfnam, config.logsport, config.dateformat))) { + switch (k) { + case 1: + printf("Can't open file to log to... exiting\n"); + break; + case 2: + printf("Can't connect to localhost:%s... exiting\n", logsport); + break; + case 3: + printf("Can't open socket to log to... exiting\n"); + break; + } + exit(1); + } + + if (listen == NULL) { + listencount = 1; + listen = calloc(1, sizeof(char*)); + listen[0] = "50127"; + } + if (manage == NULL) { + managecount = 1; + manage = calloc(1, sizeof(char*)); + manage[0] = "50126"; + } + if (managecount != listencount) { + aflog(0, "Number of listen and manage options are not the same... exiting"); + exit(1); + } + if (config.certif == NULL) { + config.certif = "cacert.pem"; + } + if (config.keys == NULL) { + config.keys = "server.rsa"; + } + if (type == NULL) { + type = "tcp"; + } + config.size = 1; + config.realmtable = calloc(config.size, sizeof(RealmT)); + config.realmtable[0].hostname = name; + config.realmtable[0].usrclinum = managecount; + config.realmtable[0].usrclitable = calloc(managecount, sizeof(UsrCliT)); + for (i = 0; i < config.realmtable[0].usrclinum; ++i) { + config.realmtable[0].usrclitable[i].lisportnum = listen[i]; + config.realmtable[0].usrclitable[i].manportnum = manage[i]; + } + config.realmtable[0].users = amount; + config.realmtable[0].clients = clients; + config.realmtable[0].raclients = raclients; + config.realmtable[0].timeout = timeout; + config.realmtable[0].usrpcli = usrpcli; + config.realmtable[0].clim = clim; + config.realmtable[0].baseport = baseport; + config.realmtable[0].dnslookups = dnslookups; + config.realmtable[0].realmname = realmname; + memcpy(config.realmtable[0].pass, pass, 4); + if (strcmp(type, "tcp") == 0) { + TYPE_SET_TCP(config.realmtable[0].type); + } + else if (strcmp(type, "udp") == 0) { + TYPE_SET_UDP(config.realmtable[0].type); + } + else { + TYPE_SET_ZERO(config.realmtable[0].type); + } +#ifdef AF_INET6 + if (ipfam == -1) { + aflog(0, "Conflicting types of ip protocol family... exiting"); + exit(1); + } + else if (ipfam == 4) { + TYPE_SET_IPV4(config.realmtable[0].type); + } + else if (ipfam == 6) { + TYPE_SET_IPV6(config.realmtable[0].type); + } +#endif + config.realmtable[0].type |= mode; + } + + maxfdp1 = manconnecting = 0; + + SSL_library_init(); + method = SSLv3_server_method(); + ctx = SSL_CTX_new(method); + if (SSL_CTX_set_cipher_list(ctx, "ALL:@STRENGTH") == 0) { + aflog(0, "Setting ciphers list failed... exiting"); + exit(1); + } + if ((flags = create_apf_dir())) { + aflog(1, "Warning: Creating ~/.apf directory failed (%d)", flags); + } + if ((flags = generate_rsa_key(&config.keys))) { + aflog(1, "Warning: Something bad happened when generating rsa keys... (%d)", flags); + } + if (SSL_CTX_use_RSAPrivateKey_file(ctx, config.keys, SSL_FILETYPE_PEM) != 1) { + aflog(0, "Setting rsa key failed (%s)... exiting", config.keys); + exit(1); + } + if ((flags = generate_certificate(&config.certif, config.keys))) { + aflog(1, "Warning: Something bad happened when generating certificate... (%d)", flags); + } + if (SSL_CTX_use_certificate_file(ctx, config.certif, SSL_FILETYPE_PEM) != 1) { + aflog(0, "Setting certificate failed (%s)... exiting", config.certif); + exit(1); + } + + if (config.size == 0) { + aflog(0, "Working without sense is really without sense..."); + exit(1); + } + + FD_ZERO(&allset); + FD_ZERO(&wset); + + for (i = 0; i < config.size; ++i) { + if (config.realmtable[i].usrclinum == 0) { + aflog(0, "You have to specify at least one listen port and one manage port in each realm"); + exit(1); + } + for (j = 0; j < config.realmtable[i].usrclinum; ++j) { + if ((config.realmtable[i].usrclitable[j].lisportnum == NULL) || + (config.realmtable[i].usrclitable[j].manportnum == NULL)) { + aflog(0, "Missing some of the variables...\nRealm: %d\nlistenport[%d]: %s\nmanageport[%d]: %s", + i, j, config.realmtable[i].usrclitable[j].lisportnum, + j, config.realmtable[i].usrclitable[j].manportnum); + exit(1); + } + } + /* checking type of the realm */ + if (!TYPE_IS_SET(config.realmtable[i].type)) { + if (type != NULL) { + if (strcmp(type, "tcp") == 0) { + TYPE_SET_TCP(config.realmtable[i].type); + } + else if (strcmp(type, "udp") == 0) { + TYPE_SET_UDP(config.realmtable[i].type); + } + else { + TYPE_SET_TCP(config.realmtable[i].type); + } + } + else { + TYPE_SET_TCP(config.realmtable[i].type); + } + } +#ifdef AF_INET6 + /* using user's value for ipfam*/ + if (TYPE_IS_UNSPEC(config.realmtable[i].type)) { + if (ipfam == -1) { + aflog(0, "Conflicting types of ip protocol family... exiting"); + exit(1); + } + else if (ipfam == 4) { + TYPE_SET_IPV4(config.realmtable[i].type); + } + else if (ipfam == 6) { + TYPE_SET_IPV6(config.realmtable[i].type); + } + } +#endif + /* using user's values for zlib and ssl mode*/ + if (!TYPE_IS_SSL(mode)) { + TYPE_UNSET_SSL(config.realmtable[i].type); + } + if (!TYPE_IS_ZLIB(mode)) { + TYPE_UNSET_ZLIB(config.realmtable[i].type); + } + /* using user's baseport value*/ + if (config.realmtable[i].baseport == 0) { + config.realmtable[i].baseport = baseport; + } + /* using user's dnslookups value*/ + if (config.realmtable[i].dnslookups == 0) { + config.realmtable[i].dnslookups = dnslookups; + } + /* checking users amount */ + set_value(&(config.realmtable[i].users), amount, "5"); + check_value(&(config.realmtable[i].usernum), config.realmtable[i].users, "Invalid users amount"); + /* checking clients amount */ + set_value(&(config.realmtable[i].clients), clients, "1"); + check_value(&(config.realmtable[i].clinum), config.realmtable[i].clients, "Invalid clients amount"); + /* checking raclients amount */ + set_value(&(config.realmtable[i].raclients), raclients, "1"); + check_value(&(config.realmtable[i].raclinum), config.realmtable[i].raclients, "Invalid raclients amount"); + /* checking usrpcli value */ + set_value(&(config.realmtable[i].usrpcli), usrpcli, config.realmtable[i].users); + check_value(&(config.realmtable[i].upcnum), config.realmtable[i].usrpcli, "Invalid usrpcli value"); + /* checking timeout value */ + set_value(&(config.realmtable[i].timeout), timeout, "5"); + check_value(&(config.realmtable[i].tmout), config.realmtable[i].timeout, "Invalid timeout value"); + /* checking climode value */ + set_value(&(config.realmtable[i].clim), clim, "1"); + check_value(&(config.realmtable[i].climode), config.realmtable[i].clim, "Invalid climode value"); + /* allocating memory*/ + config.realmtable[i].contable = calloc( config.realmtable[i].usernum, sizeof(ConnectuserT)); + if (config.realmtable[i].contable == NULL) { + aflog(0, "Calloc error - try define smaller amount of users"); + exit(1); + } + config.realmtable[i].clitable = calloc( config.realmtable[i].clinum, sizeof(ConnectclientT)); + if (config.realmtable[i].clitable == NULL) { + aflog(0, "Calloc error - try define smaller amount of clients"); + exit(1); + } + config.realmtable[i].raclitable = calloc( config.realmtable[i].raclinum, sizeof(ConnectclientT)); + if (config.realmtable[i].raclitable == NULL) { + aflog(0, "Calloc error - try define smaller amount of raclients"); + exit(1); + } + ipfam = 0x01; +#ifdef AF_INET6 + if (TYPE_IS_IPV4(config.realmtable[i].type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(config.realmtable[i].type)) { + ipfam |= 0x04; + } +#endif + if (config.realmtable[i].baseport == 0) { + for (j = 0; j < config.realmtable[i].usrclinum; ++j) { + if (ip_listen(&(config.realmtable[i].usrclitable[j].listenfd), config.realmtable[i].hostname, + config.realmtable[i].usrclitable[j].lisportnum, (&(config.realmtable[i].addrlen)), ipfam)) { + aflog(0, +#ifdef AF_INET6 + "tcp_listen_%s error for %s, %s", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", +#else + "tcp_listen error for %s, %s", +#endif + config.realmtable[i].hostname, config.realmtable[i].usrclitable[j].lisportnum); + exit(1); + } + } + } + for (j = 0; j < config.realmtable[i].usrclinum; ++j) { + if (ip_listen(&(config.realmtable[i].usrclitable[j].managefd), config.realmtable[i].hostname, + config.realmtable[i].usrclitable[j].manportnum, (&(config.realmtable[i].addrlen)), ipfam)) { + aflog(0, +#ifdef AF_INET6 + "tcp_listen_%s error for %s, %s", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", +#else + "tcp_listen error for %s, %s", +#endif + config.realmtable[i].hostname, config.realmtable[i].usrclitable[j].manportnum); + exit(1); + } + } + config.realmtable[i].cliaddr = malloc(config.realmtable[i].addrlen); + + for (j=0; j (config.realmtable[i].usrclitable[j].managefd+1)) ? + maxfdp1 : (config.realmtable[i].usrclitable[j].managefd+1); + } + if (config.realmtable[i].baseport == 0) { + for (j = 0; j < config.realmtable[i].usrclinum; ++j) { + FD_SET(config.realmtable[i].usrclitable[j].listenfd, &allset); + maxfdp1 = (maxfdp1 > (config.realmtable[i].usrclitable[j].listenfd+1)) ? + maxfdp1 : (config.realmtable[i].usrclitable[j].listenfd+1); + } + } + config.realmtable[i].usercon = 0; + config.realmtable[i].clicon = 0; + config.realmtable[i].raclicon = 0; + for (j=0; jselect, maxfdp1: %d", maxfdp1); + if (manconnecting) { + /* find out, in what realm client is trying to connect */ + l = -1; + for (k = 0; k < config.size; ++k) { + for (j=0; j < config.realmtable[k].clinum; ++j) { + if ((config.realmtable[k].clitable[j].ready == 1) || (config.realmtable[k].clitable[j].ready == 2)) { + i = k; + k = config.size; + l = 0; + break; /* so i points to first good realm and j to good client */ + } + } + if (l == -1) { + for (j=0; j < config.realmtable[k].raclinum; ++j) { + if ((config.realmtable[k].raclitable[j].ready==1) || (config.realmtable[k].raclitable[j].ready==2)) { + i = k; + k = config.size; + l = 1; + break; /* so i points to first good realm and j to good client */ + } + } + } + } + if (!l) { + if (select(maxfdp1, &rset, &tmpset, NULL, (&(config.realmtable[i].clitable[j].tv))) == 0) { + close (config.realmtable[i].clitable[j].cliconn.commfd); + FD_CLR(config.realmtable[i].clitable[j].cliconn.commfd, &allset); + SSL_clear(config.realmtable[i].clitable[j].cliconn.ssl); + config.realmtable[i].clitable[j].ready = 0; + manconnecting--; + config.realmtable[i].clicon--; + aflog(1, " realm[%s]: Client[%s]: SSL_accept failed (timeout)", + get_realmname(&config, i), get_clientname(pointer, j)); + } + } + else { + if (select(maxfdp1, &rset, &tmpset, NULL, (&(config.realmtable[i].raclitable[j].tv))) == 0) { + close (config.realmtable[i].raclitable[j].cliconn.commfd); + FD_CLR(config.realmtable[i].raclitable[j].cliconn.commfd, &allset); + SSL_clear(config.realmtable[i].raclitable[j].cliconn.ssl); + config.realmtable[i].raclitable[j].ready = 0; + manconnecting--; + config.realmtable[i].clicon--; + aflog(1, " realm[%s]: Client[%s] (ra): SSL_accept failed (timeout)", + get_realmname(&config, i), get_raclientname(pointer, j)); + } + } + } + else { + select(maxfdp1, &rset, &tmpset, NULL, NULL); + } + aflog(3, " >>after select..."); + + for (j = 0; j < config.size; ++j) { + pointer = (&(config.realmtable[j])); + for (i = 0; i usernum; ++i) { + if ((pointer->contable[i].state == S_STATE_OPEN) || (pointer->contable[i].state == S_STATE_STOPPED)) + if (FD_ISSET(pointer->contable[i].connfd, &rset)) { + k = eval_usernum(&(pointer->clitable[pointer->contable[i].whatcli]), i); + aflog(3, " realm[%s]: Client[%s]: user[%d]: FD_ISSET", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + if (TYPE_IS_TCP(pointer->type)) { /* forwarding tcp packets */ + n = read(pointer->contable[i].connfd, &buff[5], 8091); + if (n == -1) { + if (errno == EAGAIN) { + continue; + } + aflog(3, " realm[%s]: Client[%s]: user[%d]: READ ERROR (%d)", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k), errno); + n = 0; + } + if (n) { + aflog(2, " realm[%s]: Client[%s]: FROM user[%d]: MESSAGE length=%d", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k), n); + if ((buff[5] == AF_S_MESSAGE) && (buff[6] == AF_S_LOGIN) && (buff[7] == AF_S_MESSAGE)) { + aflog(2, " WARNING: got packet similiar to udp"); + } + buff[0] = AF_S_MESSAGE; /* sending message */ + buff[1] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, buff, n+5); + } + else { + aflog(1, " realm[%s]: Client[%s]: user[%d]: CLOSED", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + aflog(2, " IP:%s PORT:%s", pointer->contable[i].namebuf, + pointer->contable[i].portbuf); + close(pointer->contable[i].connfd); + FD_CLR(pointer->contable[i].connfd, &allset); + FD_CLR(pointer->contable[i].connfd, &wset); + pointer->contable[i].state = S_STATE_CLOSING; + freebuflist(&pointer->contable[i].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, buff, 5); + } + } + else { /* when forwarding udp packets */ + n = readn(pointer->contable[i].connfd, buff, 5 ); + if (n != 5) { + n = 0; + } + if (n) { + if ((buff[0] == AF_S_MESSAGE) && (buff[1] == AF_S_LOGIN) && (buff[2] == AF_S_MESSAGE)) { + length = buff[3]; + length = length << 8; + length += buff[4]; /* this is length of message */ + if ((n = readn(pointer->contable[i].connfd, &buff[5], length)) != 0) { + aflog(2, " realm[%s]: Client[%s]: FROM user[%d]: MESSAGE length=%d", + get_realmname(&config, j), get_clientname(pointer, pointer->contable[i].whatcli), + get_username(pointer, k), n); + buff[1] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, + buff, n+5); + } + } + else { + n = 0; + } + } + + if (n == 0) { + aflog(1, " realm[%s]: Client[%s]: user[%d]: CLOSED (udp mode)", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + aflog(2, " IP:%s PORT:%s", pointer->contable[i].namebuf, + pointer->contable[i].portbuf); + close(pointer->contable[i].connfd); + FD_CLR(pointer->contable[i].connfd, &allset); + FD_CLR(pointer->contable[i].connfd, &wset); + pointer->contable[i].state = S_STATE_CLOSING; + freebuflist(&pointer->contable[i].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, buff, 5); + } + + } + } + } + /* ------------------------------------ */ + for (i = 0; i usernum; ++i) { + if (pointer->contable[i].state == S_STATE_STOPPED) + if (FD_ISSET(pointer->contable[i].connfd, &tmpset)) { + k = eval_usernum(&(pointer->clitable[pointer->contable[i].whatcli]), i); + aflog(3, " realm[%s]: Client[%s]: user[%d]: FD_ISSET - WRITE", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + n = pointer->contable[i].head->msglen - pointer->contable[i].head->actptr; + sent = write(pointer->contable[i].connfd, + &(pointer->contable[i].head->buff[pointer->contable[i].head->actptr]), n); + if ((sent > 0) && (sent != n)) { + pointer->contable[i].head->actptr+=sent; + aflog(3, " realm[%s]: Client[%s]: user[%d]: (%d/%d)", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k), sent, n); + } + else if ((sent == -1) && (errno == EAGAIN)) { + aflog(3, " realm[%s]: Client[%s]: user[%d]: EAGAIN", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + } + else if (sent == -1) { + aflog(1, " realm[%s]: Client[%s]: user[%d]: CLOSED", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + aflog(2, " IP:%s PORT:%s", pointer->contable[i].namebuf, pointer->contable[i].portbuf); + close(pointer->contable[i].connfd); + FD_CLR(pointer->contable[i].connfd, &allset); + FD_CLR(pointer->contable[i].connfd, &wset); + pointer->contable[i].state = S_STATE_CLOSING; + freebuflist(&pointer->contable[i].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, buff, 5); + } + else { + aflog(3, " realm[%s]: Client[%s]: user[%d]: (%d/%d)", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k), sent, n); + deleteblnode(&pointer->contable[i].head); + if (pointer->contable[i].head == NULL) { + pointer->contable[i].state = S_STATE_OPEN; + FD_CLR(pointer->contable[i].connfd, &wset); + buff[0] = AF_S_CAN_SEND; /* stopping transfer */ + buff[1] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + aflog(3, " realm[%s]: Client[%s]: TO user[%d]: BUFFERING MESSAGE ENDED", + get_realmname(&config, j), get_clientname(pointer, pointer->contable[i].whatcli), + get_username(pointer, k)); + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, buff, 5); + } + } + } + } + /* ------------------------------------ */ + if (pointer->baseport == 0) { + for (l = 0; l < pointer->usrclinum; ++l) { + if (FD_ISSET(pointer->usrclitable[l].listenfd, &rset)) { + len = pointer->addrlen; + sent = accept(pointer->usrclitable[l].listenfd, pointer->cliaddr, &len); + flags = fcntl(sent, F_GETFL, 0); + fcntl(sent, F_SETFL, flags | O_NONBLOCK); + aflog(3, " realm[%s]: listenfd: FD_ISSET", get_realmname(&config, j)); + k = find_client(pointer, pointer->climode, l); + if (pointer->clitable[k].ready == 3) { + if (pointer->usercon == pointer->usernum) { + close(sent); + aflog(3, " realm[%s]: user limit EXCEEDED", get_realmname(&config, j)); + } + else if(pointer->clitable[k].usercon == pointer->clitable[k].usernum) { + close(sent); + aflog(3, " realm[%s]: Client[%s]: usrpcli limit EXCEEDED", + get_realmname(&config, j), get_clientname(pointer, k)); + } + else { + for (i = 0; i < pointer->usernum; ++i) { + if (pointer->contable[i].state == S_STATE_CLEAR) { + pointer->contable[i].userid = pointer->usercounter; + ++(pointer->usercounter); + aflog(1, " realm[%s]: Client[%s]: new user: CONNECTING from IP: %s", + get_realmname(&config, j), get_clientname(pointer, k), + sock_ntop(pointer->cliaddr, len, pointer->contable[i].namebuf, + pointer->contable[i].portbuf, pointer->dnslookups)); + pointer->contable[i].connfd = sent; + pointer->contable[i].state = S_STATE_OPENING; + pointer->contable[i].whatcli = k; + time(&pointer->contable[i].connecttime); + pointer->usercon++; + pointer->clitable[k].usercon++; + memcpy(&buff[5], pointer->contable[i].namebuf, 128); + memcpy(&buff[133], pointer->contable[i].portbuf, 7); + n = 135; + i = find_usernum(&(pointer->clitable[k]), i); + buff[0] = AF_S_CONOPEN; /* opening connection */ + buff[1] = i >> 8; /* high bits of user number */ + buff[2] = i; /* low bits of user number */ + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(pointer->type, pointer->clitable[k].cliconn, buff, n+5); + break; + } + } + } + } + else { + close(sent); + aflog(3, " realm[%s]: Client(%d) is NOT CONNECTED", + get_realmname(&config, j), k); + } + } + } + } + /* ------------------------------------ */ + if (pointer->baseport == 1) + for (k = 0; k < pointer->clinum; ++k) + if (pointer->clitable[k].ready == 3) /* Command file descriptor */ + if (FD_ISSET(pointer->clitable[k].listenfd, &rset)) { + len = pointer->addrlen; + sent = accept(pointer->clitable[k].listenfd, pointer->cliaddr, &len); + flags = fcntl(sent, F_GETFL, 0); + fcntl(sent, F_SETFL, flags | O_NONBLOCK); + aflog(3, " realm[%s]: Client[%s]: listenfd: FD_ISSET", + get_realmname(&config, j), get_clientname(pointer, k)); + if (pointer->clitable[k].ready == 3) { + if (pointer->usercon == pointer->usernum) { + close(sent); + aflog(3, " realm[%s]: user limit EXCEEDED", get_realmname(&config, j)); + } + else if(pointer->clitable[k].usercon == pointer->clitable[k].usernum) { + close(sent); + aflog(3, " realm[%s]: Client[%s]: usrpcli limit EXCEEDED", + get_realmname(&config, j), get_clientname(pointer, k)); + } + else { + for (i = 0; i < pointer->usernum; ++i) { + if (pointer->contable[i].state == S_STATE_CLEAR) { + pointer->contable[i].userid = pointer->usercounter; + ++(pointer->usercounter); + aflog(1, " realm[%s]: Client[%s]: new user: CONNECTING from IP: %s", + get_realmname(&config, j), get_clientname(pointer, k), + sock_ntop(pointer->cliaddr, len, pointer->contable[i].namebuf, pointer->contable[i].portbuf, pointer->dnslookups)); + pointer->contable[i].connfd = sent; + pointer->contable[i].state = S_STATE_OPENING; + pointer->contable[i].whatcli = k; + time(&pointer->contable[i].connecttime); + pointer->usercon++; + pointer->clitable[k].usercon++; + memcpy(&buff[5], pointer->contable[i].namebuf, 128); + memcpy(&buff[133], pointer->contable[i].portbuf, 7); + n = 135; + i = find_usernum(&(pointer->clitable[k]), i); + buff[0] = AF_S_CONOPEN; /* opening connection */ + buff[1] = i >> 8; /* high bits of user number */ + buff[2] = i; /* low bits of user number */ + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(pointer->type, pointer->clitable[k].cliconn, buff, n+5); + break; + } + } + } + } + } + /* ------------------------------------ */ + for (k = 0; k < pointer->clinum; ++k) + if ((pointer->clitable[k].ready != 0) && (FD_ISSET(pointer->clitable[k].cliconn.commfd, &rset))) { + if (pointer->clitable[k].ready == 1) { + make_ssl_initialize(&(pointer->clitable[k].cliconn)); + aflog(2, " realm[%s]: new Client[%s]: SSL_accept", + get_realmname(&config, j), get_clientname(pointer, k)); + switch (make_ssl_accept(&(pointer->clitable[k].cliconn))) { + case 2: { + close (pointer->clitable[k].cliconn.commfd); + FD_CLR(pointer->clitable[k].cliconn.commfd, &allset); + SSL_clear(pointer->clitable[k].cliconn.ssl); + pointer->clitable[k].ready = 0; + manconnecting--; + pointer->clicon--; + aflog(1, " realm[%s]: new Client[%s]: DENIED by SSL_accept", + get_realmname(&config, j), get_clientname(pointer, k)); + } + case 1: { + continue; + } + default: { + aflog(1, " realm[%s]: new Client[%s]: ACCEPTED by SSL_accept", + get_realmname(&config, j), get_clientname(pointer, k)); + pointer->clitable[k].ready = 2; + continue; + } + } + } + aflog(3, " realm[%s]: Client[%s]: commfd: FD_ISSET", + get_realmname(&config, j), get_clientname(pointer, k)); + if (pointer->clitable[k].ready == 2) { + n = get_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->clitable[k].cliconn, buff, -5); + } + else { + n = get_message(pointer->type, pointer->clitable[k].cliconn, buff, -5); + } + if (n == -1) { + if (errno == EAGAIN) { + aflog(4, " realm[%s]: Client[%s]: commfd: EAGAIN", + get_realmname(&config, j), get_clientname(pointer, k)); + continue; + } + else { + aflog(4, " realm[%s]: Client[%s]: commfd: ERROR: %d", + get_realmname(&config, j), get_clientname(pointer, k), errno); + n = 0; + } + } + else if (n != 5) { + if (n != 0) { + aflog(4, " realm[%s]: Client[%s]: header length = %d --> closing client", + get_realmname(&config, j), get_clientname(pointer, k), n); + } + n = 0; + } + if (n==0) { + remove_client(pointer, k, &allset, &wset, &manconnecting); + aflog(1, " realm[%s]: Client[%s]: commfd: CLOSED", + get_realmname(&config, j), get_clientname(pointer, k)); + continue; + } + + numofcon = buff[1]; + numofcon = numofcon << 8; + numofcon += buff[2]; /* this is id of user */ + length = buff[3]; + length = length << 8; + length += buff[4]; /* this is length of message */ + + if ((k == pointer->clinum) && (buff[0] != AF_S_LOGIN) && + (buff[0] != AF_S_ADMIN_LOGIN) && (buff[0] != AF_S_ADMIN_CMD)) { + buff[0] = AF_S_WRONG; + } + if (pointer->clitable[k].ready<2) { + aflog(1, " realm[%s]: Client[%s]: Impossible behaviour --> ignoring", + get_realmname(&config, j), get_clientname(pointer, k)); + continue; + } + if ((pointer->clitable[k].ready == 2) && (buff[0] != AF_S_LOGIN) && (buff[0] != AF_S_ADMIN_LOGIN)) { + buff[0] = AF_S_WRONG; + } + + switch (buff[0]) { + case AF_S_CONCLOSED : { + n = numofcon; + numofcon = eval_numofcon(pointer, k, numofcon); + if ((numofcon>=0) && (numofcon<(pointer->usernum)) && ((pointer->clitable[k].ready)==3)) { + pointer->usercon--; + pointer->clitable[k].usercon--; + pointer->clitable[k].users[n] = -1; + if (pointer->contable[numofcon].state == S_STATE_CLOSING) { + pointer->contable[numofcon].state = S_STATE_CLEAR; + aflog(3, " realm[%s]: user[%d]: CLOSE CONFIRMED", + get_realmname(&config, j), get_username(pointer, numofcon)); + } + else if ((pointer->contable[numofcon].state == S_STATE_OPEN) || + (pointer->contable[numofcon].state == S_STATE_STOPPED)) { + aflog(1, " realm[%s]: user[%d]: KICKED", + get_realmname(&config, j), get_username(pointer, numofcon)); + aflog(2, " IP:%s PORT:%s", pointer->contable[numofcon].namebuf, + pointer->contable[numofcon].portbuf); + close(pointer->contable[numofcon].connfd); + FD_CLR(pointer->contable[numofcon].connfd, &allset); + FD_CLR(pointer->contable[numofcon].connfd, &wset); + pointer->contable[numofcon].state = S_STATE_CLEAR; + freebuflist(&pointer->contable[numofcon].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[k].cliconn, buff, 5); + } + } + else { + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + case AF_S_CONOPEN : { + numofcon = eval_numofcon(pointer, k, numofcon); + if ((numofcon>=0) && (numofcon<(pointer->usernum)) && ((pointer->clitable[k].ready)==3)) { + if (pointer->contable[numofcon].state == S_STATE_OPENING) { + aflog(2, " realm[%s]: user[%d]: NEW", + get_realmname(&config, j), get_username(pointer, numofcon)); + FD_SET(pointer->contable[numofcon].connfd, &allset); + maxfdp1 = (maxfdp1 > (pointer->contable[numofcon].connfd+1)) ? + maxfdp1 : (pointer->contable[numofcon].connfd+1); + pointer->contable[numofcon].state = S_STATE_OPEN; + } + } + else { + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + case AF_S_CANT_OPEN : { + n = numofcon; + numofcon = eval_numofcon(pointer, k, numofcon); + if ((numofcon>=0) && (numofcon<(pointer->usernum)) && ((pointer->clitable[k].ready)==3)) { + if (pointer->contable[numofcon].state == S_STATE_OPENING) { + aflog(2, " realm[%s]: user[%d]: DROPPED", + get_realmname(&config, j), get_username(pointer, numofcon)); + pointer->usercon--; + pointer->clitable[k].usercon--; + pointer->clitable[k].users[n] = -1; + close(pointer->contable[numofcon].connfd); + pointer->contable[numofcon].state = S_STATE_CLEAR; + } + } + else { + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + case AF_S_MESSAGE : { + if ((pointer->clitable[k].ready) != 3) { + remove_client(pointer, k, &allset, &wset, &manconnecting); + break; + } + if (TYPE_IS_UDP(pointer->type)) { /* udp */ + n = get_message(pointer->type, pointer->clitable[k].cliconn, &buff[5], length); + } + else { + n = get_message(pointer->type, pointer->clitable[k].cliconn, buff, length); + } + numofcon = eval_numofcon(pointer, k, numofcon); + if ((numofcon>=0) && (numofcon<(pointer->usernum))) { + if (pointer->contable[numofcon].state == S_STATE_OPEN) { + aflog(2, " realm[%s]: TO user[%d]: MESSAGE length=%d", + get_realmname(&config, j), get_username(pointer, numofcon), n); + if (TYPE_IS_UDP(pointer->type)) { /* udp */ + buff[1] = AF_S_LOGIN; + buff[2] = AF_S_MESSAGE; + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + sent = write(pointer->contable[numofcon].connfd, buff, n+5); + if (sent == -1) { + aflog(1, " realm[%s]: user[%d]: CLOSED (write-udp)", + get_realmname(&config, j), get_username(pointer, numofcon)); + aflog(2, " IP:%s PORT:%s", pointer->contable[numofcon].namebuf, + pointer->contable[numofcon].portbuf); + close(pointer->contable[numofcon].connfd); + FD_CLR(pointer->contable[numofcon].connfd, &allset); + FD_CLR(pointer->contable[numofcon].connfd, &wset); + pointer->contable[numofcon].state = S_STATE_CLOSING; + freebuflist(&pointer->contable[numofcon].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[k].cliconn, buff, 5); + } + } + else { /* tcp */ + sent = write(pointer->contable[numofcon].connfd, buff, n); + if ((sent > 0) && (sent != n)) { + insertblnode(&(pointer->contable[numofcon].head), sent, n, buff); + pointer->contable[numofcon].state = S_STATE_STOPPED; + FD_SET(pointer->contable[numofcon].connfd, &wset); + buff[0] = AF_S_DONT_SEND; /* stopping transfer */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + aflog(3, " realm[%s]: TO user[%d]: BUFFERING MESSAGE STARTED (%d/%d)", + get_realmname(&config, j), get_username(pointer, numofcon), sent, n); + send_message(pointer->type, pointer->clitable[k].cliconn, buff, 5); + } + else if ((sent == -1) && (errno == EAGAIN)) { + insertblnode(&(pointer->contable[numofcon].head), 0, n, buff); + pointer->contable[numofcon].state = S_STATE_STOPPED; + FD_SET(pointer->contable[numofcon].connfd, &wset); + buff[0] = AF_S_DONT_SEND; /* stopping transfer */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + aflog(3, " realm[%s]: TO user[%d]: BUFFERING MESSAGE STARTED (%d/%d)", + get_realmname(&config, j), get_username(pointer, numofcon), sent, n); + send_message(pointer->type, pointer->clitable[k].cliconn, buff, 5); + } + else if (sent == -1) { + aflog(1, " realm[%s]: user[%d]: CLOSED (write-tcp)", + get_realmname(&config, j), get_username(pointer, numofcon)); + aflog(2, " IP:%s PORT:%s", pointer->contable[numofcon].namebuf, + pointer->contable[numofcon].portbuf); + close(pointer->contable[numofcon].connfd); + FD_CLR(pointer->contable[numofcon].connfd, &allset); + FD_CLR(pointer->contable[numofcon].connfd, &wset); + pointer->contable[numofcon].state = S_STATE_CLOSING; + freebuflist(&pointer->contable[numofcon].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[k].cliconn, buff, 5); + } + } + } + else if (pointer->contable[numofcon].state == S_STATE_STOPPED) { + aflog(3, " realm[%s]: TO user[%d]: BUFFERING MESSAGE (%d)", + get_realmname(&config, j), get_username(pointer, numofcon), n); + if (TYPE_IS_UDP(pointer->type)) { /* udp */ + buff[1] = AF_S_LOGIN; + buff[2] = AF_S_MESSAGE; + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + insertblnode(&(pointer->contable[numofcon].head), 0, n+5, buff); + } + else { + insertblnode(&(pointer->contable[numofcon].head), 0, n, buff); + } + } + else if (pointer->contable[numofcon].state == S_STATE_CLOSING) { + aflog(3, " realm[%s]: TO user[%d]: IGNORED message length=%d", + get_realmname(&config, j), get_username(pointer, numofcon), n); + } + } + break; + } + case AF_S_LOGIN : { + if ((pointer->clitable[k].ready == 2) && (numofcon==(pointer->pass[0]*256+pointer->pass[1])) && + (length==(pointer->pass[2]*256+pointer->pass[3]))) { + if (k != pointer->clinum) { + pointer->clitable[k].ready = 3; + aflog(1, " realm[%s]: Client[%s]: pass ok - ACCESS GRANTED", + get_realmname(&config, j), get_clientname(pointer, k)); + buff[0] = AF_S_LOGIN; /* sending message */ + buff[1] = pointer->clitable[k].usernum >> 8;/* high bits of user number */ + buff[2] = pointer->clitable[k].usernum; /* low bits of user number */ + buff[3] = pointer->type; /* type of connection */ + send_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->clitable[k].cliconn, buff, 5); + manconnecting--; + if (pointer->baseport == 1) { + long tmp_val; + char tmp_tab[6]; + if (check_long(pointer->usrclitable[pointer->clitable[k].whatusrcli].lisportnum, &tmp_val)) { + aflog(1, " realm[%s]: INVALID listenport - removing Client[%s]", + get_realmname(&config, j), get_clientname(pointer, k)); + remove_client(pointer, k, &allset, &wset, &manconnecting); + break; + } + tmp_val = tmp_val%65536; + memset(tmp_tab, 0, 6); + sprintf(tmp_tab, "%d", (int)tmp_val); + ipfam = 0x01; +#ifdef AF_INET6 + if (TYPE_IS_IPV4(pointer->type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(pointer->type)) { + ipfam |= 0x04; + } +#endif + while (ip_listen(&(pointer->clitable[k].listenfd), pointer->hostname, + tmp_tab, (&(pointer->addrlen)), ipfam)) { + tmp_val = (tmp_val+1)%65536; + memset(tmp_tab, 0, 6); + sprintf(tmp_tab, "%d", (int)tmp_val); + } + FD_SET(pointer->clitable[k].listenfd, &allset); + maxfdp1 = (maxfdp1 > (pointer->clitable[k].listenfd+1)) ? + maxfdp1 : (pointer->clitable[k].listenfd+1); + aflog(1, " realm[%s]: Client[%s]: listenport=%s", + get_realmname(&config, j), get_clientname(pointer, k), tmp_tab); + } + } + else { + aflog(3, " realm[%s]: client limit EXCEEDED", get_realmname(&config, j)); + buff[0] = AF_S_CANT_OPEN; /* sending message */ + send_message(pointer->type | TYPE_SSL, pointer->clitable[k].cliconn, buff, 5); + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + } + else if ((pointer->clitable[k].ready == 3) && (numofcon == 0)) { + n = get_message(pointer->type, pointer->clitable[k].cliconn, buff, length); + buff[n] = 0; + aflog(1, " realm[%s]: Client[%s]: ID received: %s", + get_realmname(&config, j), get_clientname(pointer, k), buff); + if (pointer->clitable[k].clientid) { + free(pointer->clitable[k].clientid); + } + pointer->clitable[k].clientid = malloc(n+1); + if (pointer->clitable[k].clientid) { + memcpy(pointer->clitable[k].clientid, buff, n+1); + } + } + else { + aflog(1, " realm[%s]: Client[%s]: Wrong password - CLOSING", + get_realmname(&config, j), get_clientname(pointer, k)); + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + case AF_S_DONT_SEND: { + aflog(3, " realm[%s]: user[%d]: STOP READING", + get_realmname(&config, j), get_username(pointer, numofcon)); + FD_CLR(pointer->contable[numofcon].connfd, &allset); + break; + } + case AF_S_CAN_SEND: { + aflog(3, " realm[%s]: user[%d]: START READING", + get_realmname(&config, j), get_username(pointer, numofcon)); + FD_SET(pointer->contable[numofcon].connfd, &allset); + break; + } + case AF_S_WRONG: { + aflog(1, " realm[%s]: Client[%s]: Wrong message - CLOSING", + get_realmname(&config, j), get_clientname(pointer, k)); + remove_client(pointer, k, &allset, &wset, &manconnecting); + break; + } + case AF_S_ADMIN_LOGIN: { + if ((pointer->clitable[k].ready == 2) && (numofcon==(pointer->pass[0]*256+pointer->pass[1])) && + (length==(pointer->pass[2]*256+pointer->pass[3]))) { + aflog(1, " realm[%s]: Client[%s]: NEW remote admin -- pass OK", + get_realmname(&config, j), get_clientname(pointer, k)); + for (l = 0; l < pointer->raclinum; ++l) { + if (pointer->raclitable[l].ready == 0) { + pointer->raclitable[l].cliconn.commfd = pointer->clitable[k].cliconn.commfd; + pointer->raclitable[l].connecttime = pointer->clitable[k].connecttime; + pointer->raclitable[l].clientnum = pointer->clitable[k].clientnum; + memcpy(pointer->raclitable[l].namebuf, pointer->clitable[k].namebuf, 128); + memcpy(pointer->raclitable[l].portbuf, pointer->clitable[k].portbuf, 7); + tmp_ssl = pointer->raclitable[l].cliconn.ssl; + pointer->raclitable[l].cliconn.ssl = pointer->clitable[k].cliconn.ssl; + pointer->clitable[k].cliconn.ssl = tmp_ssl; + pointer->clitable[k].ready = 0; + break; + } + } + if (l != pointer->raclinum) { + pointer->raclitable[l].ready = 3; + pointer->raclicon++; + manconnecting--; + sprintf((char*) &buff[5], AF_VER("AFSERVER")); + n = strlen((char*) &buff[5]); + buff[0] = AF_S_ADMIN_LOGIN; /* sending message */ + buff[1] = pointer->type; /* type of connection */ + buff[2] = AF_RA_UNDEFINED; + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(pointer->type | TYPE_SSL, pointer->raclitable[l].cliconn, buff, n+5); + } + else { + aflog(1, " realm[%s]: Client[%s]: remote admin -- limit EXCEEDED", + get_realmname(&config, j), get_clientname(pointer, k)); + buff[0] = AF_S_CANT_OPEN; /* sending message */ + send_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->clitable[k].cliconn, buff, 5); + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + } + break; + } + default : { + aflog(1, " realm[%s]: Client[%s]: Unrecognized message - CLOSING", + get_realmname(&config, j), get_clientname(pointer, k)); + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + } + } + /* ------------------------------------ */ + for (k = 0; k < pointer->raclinum; ++k) + if ((pointer->raclitable[k].ready != 0) && (FD_ISSET(pointer->raclitable[k].cliconn.commfd, &rset))) { + if (pointer->raclitable[k].ready == 1) { + make_ssl_initialize(&(pointer->raclitable[k].cliconn)); + aflog(2, " realm[%s]: new Client[%s] (ra): SSL_accept", + get_realmname(&config, j), get_raclientname(pointer, k)); + switch (make_ssl_accept(&(pointer->raclitable[k].cliconn))) { + case 2: { + close (pointer->raclitable[k].cliconn.commfd); + FD_CLR(pointer->raclitable[k].cliconn.commfd, &allset); + SSL_clear(pointer->raclitable[k].cliconn.ssl); + pointer->raclitable[k].ready = 0; + manconnecting--; + pointer->clicon--; + aflog(1, " realm[%s]: new Client[%s] (ra): DENIED by SSL_accept", + get_realmname(&config, j), get_raclientname(pointer, k)); + } + case 1: { + continue; + } + default: { + aflog(1, " realm[%s]: new Client[%s] (ra): ACCEPTED by SSL_accept", + get_realmname(&config, j), get_raclientname(pointer, k)); + pointer->raclitable[k].ready = 2; + continue; + } + } + } + aflog(3, " realm[%s]: Client[%s] (ra): commfd: FD_ISSET", + get_realmname(&config, j), get_raclientname(pointer, k)); + n = get_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->raclitable[k].cliconn, buff, -5); + if (n == -1) { + if (errno == EAGAIN) { + aflog(4, " realm[%s]: Client[%s] (ra): commfd: EAGAIN", + get_realmname(&config, j), get_raclientname(pointer, k)); + continue; + } + else { + aflog(4, " realm[%s]: Client[%s] (ra): commfd: ERROR: %d", + get_realmname(&config, j), get_raclientname(pointer, k), errno); + n = 0; + } + } + else if (n != 5) { + if (n != 0) { + aflog(4, " realm[%s]: Client[%s] (ra): header length = %d --> closing client", + get_realmname(&config, j), get_raclientname(pointer, k), n); + } + n = 0; + } + if (n==0) { + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + aflog(1, " realm[%s]: Client[%s] (ra): commfd: CLOSED", + get_realmname(&config, j), get_raclientname(pointer, k)); + continue; + } + + numofcon = buff[1]; + numofcon = numofcon << 8; + numofcon += buff[2]; /* this is id of user */ + length = buff[3]; + length = length << 8; + length += buff[4]; /* this is length of message */ + + if (pointer->raclitable[k].ready<2) { + aflog(1, " realm[%s]: Client[%s] (ra): Impossible behaviour --> ignoring", + get_realmname(&config, j), get_raclientname(pointer, k)); + continue; + } + if ((pointer->raclitable[k].ready == 2) && (buff[0] != AF_S_LOGIN) && (buff[0] != AF_S_ADMIN_LOGIN)) { + buff[0] = AF_S_WRONG; + } + + switch (buff[0]) { + case AF_S_LOGIN : { + if ((pointer->raclitable[k].ready == 2) && (numofcon==(pointer->pass[0]*256+pointer->pass[1])) && + (length==(pointer->pass[2]*256+pointer->pass[3]))) { + for (l = 0; l < pointer->clinum; ++l) { + if (!(pointer->clitable[l].ready)) { + aflog(1, " realm[%s]: Client[%s] (ra) --> Client[%s]", + get_realmname(&config, j), get_raclientname(pointer, k), get_clientname(pointer, l)); + pointer->clitable[l].cliconn.commfd = pointer->raclitable[k].cliconn.commfd; + pointer->clitable[l].connecttime = pointer->raclitable[k].connecttime; + pointer->clitable[l].clientnum = pointer->raclitable[k].clientnum; + memcpy(pointer->clitable[l].namebuf, pointer->raclitable[k].namebuf, 128); + memcpy(pointer->clitable[l].portbuf, pointer->raclitable[k].portbuf, 7); + tmp_ssl = pointer->clitable[l].cliconn.ssl; + pointer->clitable[l].cliconn.ssl = pointer->raclitable[k].cliconn.ssl; + pointer->raclitable[k].cliconn.ssl = tmp_ssl; + pointer->clitable[l].whatusrcli = pointer->raclitable[k].whatusrcli; + pointer->raclitable[k].ready = 0; + break; + } + } + if (l != pointer->clinum) { + pointer->clitable[l].ready = 3; + aflog(1, " realm[%s]: Client[%s]: pass ok - ACCESS GRANTED", + get_realmname(&config, j), get_clientname(pointer, l)); + buff[0] = AF_S_LOGIN; /* sending message */ + buff[1] = pointer->clitable[l].usernum >> 8;/* high bits of user number */ + buff[2] = pointer->clitable[l].usernum; /* low bits of user number */ + buff[3] = pointer->type; /* type of connection */ + send_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->clitable[l].cliconn, buff, 5); + manconnecting--; + if (pointer->baseport == 1) { + long tmp_val; + char tmp_tab[6]; + if (check_long(pointer->usrclitable[pointer->clitable[l].whatusrcli].lisportnum, &tmp_val)) { + aflog(1, " realm[%s]: INVALID listenport - removing Client[%s]", + get_realmname(&config, j), get_clientname(pointer, l)); + remove_client(pointer, l, &allset, &wset, &manconnecting); + break; + } + tmp_val = tmp_val%65536; + memset(tmp_tab, 0, 6); + sprintf(tmp_tab, "%d", (int)tmp_val); + ipfam = 0x01; +#ifdef AF_INET6 + if (TYPE_IS_IPV4(pointer->type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(pointer->type)) { + ipfam |= 0x04; + } +#endif + while (ip_listen(&(pointer->clitable[l].listenfd), pointer->hostname, + tmp_tab, (&(pointer->addrlen)), ipfam)) { + tmp_val = (tmp_val+1)%65536; + memset(tmp_tab, 0, 6); + sprintf(tmp_tab, "%d", (int)tmp_val); + } + FD_SET(pointer->clitable[l].listenfd, &allset); + maxfdp1 = (maxfdp1 > (pointer->clitable[l].listenfd+1)) ? + maxfdp1 : (pointer->clitable[l].listenfd+1); + aflog(1, " realm[%s]: Client[%s]: listenport=%s", + get_realmname(&config, j), get_clientname(pointer, l), tmp_tab); + } + } + else { + aflog(3, " realm[%s]: client limit EXCEEDED", get_realmname(&config, j)); + buff[0] = AF_S_CANT_OPEN; /* sending message */ + send_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->raclitable[k].cliconn, buff, 5); + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + } + } + else if ((pointer->raclitable[k].ready == 3) && (numofcon == 0)) { + n = get_message(pointer->type, pointer->raclitable[k].cliconn, buff, length); + buff[n] = 0; + aflog(1, " realm[%s]: Client[%s] (ra): ID received: %s", + get_realmname(&config, j), get_raclientname(pointer, k), buff); + if (pointer->raclitable[k].clientid) { + free(pointer->raclitable[k].clientid); + } + pointer->raclitable[k].clientid = malloc(n+1); + if (pointer->raclitable[k].clientid) { + memcpy(pointer->raclitable[k].clientid, buff, n+1); + } + } + else { + aflog(1, " realm[%s]: Client[%s] (ra): Wrong password - CLOSING", + get_realmname(&config, j), get_raclientname(pointer, k)); + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + case AF_S_WRONG: { + aflog(1, " realm[%s]: Client[%s] (ra): Wrong message - CLOSING", + get_realmname(&config, j), get_raclientname(pointer, k)); + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + break; + } + case AF_S_ADMIN_LOGIN: { + if ((pointer->raclitable[k].ready == 2) && (numofcon==(pointer->pass[0]*256+pointer->pass[1])) && + (length==(pointer->pass[2]*256+pointer->pass[3]))) { + aflog(1, " realm[%s]: Client[%s] (ra): NEW remote admin -- pass OK", + get_realmname(&config, j), get_raclientname(pointer, k)); + pointer->raclitable[k].ready = 3; + pointer->raclicon++; + manconnecting--; + sprintf((char*) &buff[5], AF_VER("AFSERVER")); + n = strlen((char*) &buff[5]); + buff[0] = AF_S_ADMIN_LOGIN; /* sending message */ + buff[1] = pointer->type; /* type of connection */ + buff[2] = AF_RA_UNDEFINED; + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->raclitable[k].cliconn, buff, n+5); + } + break; + } + case AF_S_ADMIN_CMD: { + if (pointer->raclitable[k].ready == 3) { + if (serve_admin(&config, j, k, buff)) { + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + } + } + else { + aflog(1, " realm[%s]: Client[%s] (ra): remote admin -- security VIOLATION", + get_realmname(&config, j), get_raclientname(pointer, k)); + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + default : { + aflog(1, " realm[%s]: Client[%s] (ra): Unrecognized message - CLOSING", + get_realmname(&config, j), get_raclientname(pointer, k)); + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + } + } + } + /* ------------------------------------ */ + for (l = 0; l < pointer->usrclinum; ++l) { + if (FD_ISSET(pointer->usrclitable[l].managefd, &rset)) { + aflog(3, " realm[%s]: managefd: FD_ISSET", get_realmname(&config, j)); + len = pointer->addrlen; + sent = accept(pointer->usrclitable[l].managefd,pointer->cliaddr,&len); + flags = fcntl(sent, F_GETFL, 0); + fcntl(sent, F_SETFL, flags | O_NONBLOCK); + for (k = 0; k < pointer->clinum; ++k) { + if (!(pointer->clitable[k].ready)) { + pointer->clitable[k].clientnum = pointer->clientcounter; + ++(pointer->clientcounter); + aflog(2, " realm[%s]: new Client[%s]: CONNECTING", + get_realmname(&config, j), get_clientname(pointer, k)); + pointer->clitable[k].cliconn.commfd = sent; + pointer->clitable[k].whatusrcli = l; + time(&pointer->clitable[k].connecttime); + aflog(1, " realm[%s]: new Client[%s] IP:%s", get_realmname(&config, j), get_clientname(pointer, k), + sock_ntop(pointer->cliaddr, len, pointer->clitable[k].namebuf, + pointer->clitable[k].portbuf, pointer->dnslookups)); + FD_SET(pointer->clitable[k].cliconn.commfd, &allset); + maxfdp1 = (maxfdp1 > (pointer->clitable[k].cliconn.commfd+1)) ? + maxfdp1 : (pointer->clitable[k].cliconn.commfd+1); + pointer->clicon++; + pointer->clitable[k].tv.tv_sec = pointer->tmout; + manconnecting++; + pointer->clitable[k].ready = 1; + break; + } + } + if (k == pointer->clinum) { + for (k = 0; k < pointer->raclinum; ++k) { + if ((!pointer->raclitable[k].ready)) { + pointer->raclitable[k].clientnum = pointer->clientcounter; + ++(pointer->clientcounter); + aflog(2, " realm[%s]: new Client[%s] (ra): CONNECTING", + get_realmname(&config, j), get_raclientname(pointer, k)); + pointer->raclitable[k].cliconn.commfd = sent; + pointer->raclitable[k].whatusrcli = l; + time(&pointer->raclitable[k].connecttime); + aflog(1, " realm[%s]: new Client[%s] (ra) IP:%s", + get_realmname(&config, j), get_raclientname(pointer, k), + sock_ntop(pointer->cliaddr, len, pointer->raclitable[k].namebuf, + pointer->raclitable[k].portbuf, pointer->dnslookups)); + FD_SET(pointer->raclitable[k].cliconn.commfd, &allset); + maxfdp1 = (maxfdp1 > (pointer->raclitable[k].cliconn.commfd+1)) ? + maxfdp1 : (pointer->raclitable[k].cliconn.commfd+1); + pointer->clicon++; + pointer->raclitable[k].tv.tv_sec = pointer->tmout; + manconnecting++; + pointer->raclitable[k].ready = 1; + break; + } + } + if (k == pointer->raclinum) { + aflog(3, " realm[%s]: client limit EXCEEDED", get_realmname(&config, j)); + close(sent); + } + } + } + } + } /* realms loop */ + } +} + +static void +usage(char* info) +{ + printf("\n%s\n\n\n", info); + printf(" Basic options:\n\n"); + printf(" -n, --hostname - it's used when creating listening sockets\n"); + printf(" (default: '')\n"); + printf(" -l, --listenport - listening port number - users connect\n"); + printf(" to it (default: 50127)\n"); + printf(" -m, --manageport - manage port number - second part of the active\n"); + printf(" port forwarder connects to it (default: 50126)\n"); + printf(" -h, --help - prints this help\n\n"); + printf(" Authorization:\n\n"); + printf(" --pass - set the password used for client identification\n"); + printf(" (default: no password)\n\n"); + printf(" Configuration:\n\n"); + printf(" -c, --cerfile - the name of the file with certificate\n"); + printf(" (default: cacert.pem)\n"); + printf(" -k, --keyfile - the name of the file with RSA key (default: server.rsa)\n"); + printf(" -f, --cfgfile - the name of the file with the configuration for the\n"); + printf(" active forwarder (server)\n"); + printf(" -D, --dateformat - format of the date printed in logs (see 'man strftime'\n"); + printf(" for details) (default: %%d.%%m.%%Y %%H:%%M:%%S)\n\n"); + printf(" -t, --timeout - the timeout value for the client's connection\n"); + printf(" (default: 5)\n"); + printf(" -u, --users - the amount of users allowed to use this server\n"); + printf(" (default: 5)\n"); + printf(" -C, --clients - the number of allowed clients to use this server\n"); + printf(" (default: 1)\n"); + printf(" -r, --realm - set the realm name (default: none)\n"); + printf(" -R, --raclients - the number of allowed clients in remote administration\n"); + printf(" mode to use this server (default: 1)\n"); + printf(" -U, --usrpcli - the number of allowed users per client (default: $users)\n"); + printf(" -M, --climode - strategy used to connect users with clients (default: 1)\n"); + printf(" Available strategies:\n"); + printf(" 1. fill first client before go to next\n\n"); + printf(" -p, --proto - type of server (tcp|udp) - what protocol it will be\n"); + printf(" operating for (default: tcp)\n"); + printf(" -b, --baseport - listenports are temporary and differ for each client\n"); + printf(" --nossl - ssl is not used to transfer data (but it's still used\n"); + printf(" to establish a connection) (default: ssl is used)\n"); + printf(" --nozlib - zlib is not used to compress data (default: zlib is\n"); + printf(" used)\n"); + printf(" --dnslookups - try to obtain dns names of the computers rather than\n"); + printf(" their numeric IP\n\n"); + printf(" Logging:\n\n"); + printf(" -O, --heavylog - logging everything to a logfile\n"); + printf(" -o, --lightlog - logging some data to a logfile\n"); + printf(" -S, --heavysocklog - logging everything to a localport\n"); + printf(" -s, --lightsocklog - logging some data to a localport\n"); + printf(" -v, --verbose - to be verbose - program won't enter the daemon mode\n"); + printf(" (use several times for greater effect)\n\n"); +#ifdef AF_INET6 + printf(" IP family:\n\n"); + printf(" -4, --ipv4 - use ipv4 only\n"); + printf(" -6, --ipv6 - use ipv6 only\n\n"); +#endif + exit(0); +} + +static void +sig_int(int signo) +{ + int i, j; + unsigned char buff[5]; + for (j = 0; j < config.size; ++j) { + buff[0] = AF_S_CLOSING; /* closing */ + for (i = 0; i < config.realmtable[j].clinum+1; ++i) { + if (config.realmtable[j].clitable[i].ready == 3) { + if (config.realmtable[j].clinum == i) { + send_message(config.realmtable[j].type | TYPE_SSL, config.realmtable[j].clitable[i].cliconn, buff, 5); + } + else { + send_message(config.realmtable[j].type, config.realmtable[j].clitable[i].cliconn, buff, 5); + } + } + } + } + aflog(1, "SERVER CLOSED cg: %ld bytes", getcg()); + exit(0); +} + -- cgit v1.1