From 32aff2b27ccc3b3e51fb6f0bd77fe0073827c527 Mon Sep 17 00:00:00 2001 From: Jakub Sławiński Date: Tue, 7 Jun 2005 12:06:18 +0200 Subject: v0.7 - Added: http proxy tunnels between afserver and afclient - Fixed: sigint interception with threads enabled (in http proxy mode) - Fixed: FATAL ERROR in afclient in some situations after close of afserver when http proxy mode is enabled - Added: afclients can connect directly to afserver with enabled proxy mode - Fixed: timeout routine in http proxy tunnels - Added: 'rshow' command in ra mode displays 'tunneltype' - Fixed: printing IP of clients when http proxy mode is enabled - Added: 'tunneltype' per client in ra mode after 'cshow' command - Fixed: closing connection when http proxy mode is enabled - Fixed: threads initialization - Fixed: afserver closing after sigint - Fixed: afclient threads initialization - Added: 'version' option to display program version number - Modified: establishing afclient<->afserver connection - Added: 'keep-alive' option - Fixed: using 'proxyport' without 'proxyname' - Added: auto-reconnect feature to afclient - Added: 'ar-tries' and 'ar-delay' options - Modified: http proxy logging - Fixed: closing connection with afclient after receiving id - Fixed: thread closing due to wrong initialization sequence - Fixed: small bug in initialization process - Heavily Modified: logging routines - Added: audit option - Modified: default dateformat is now ISO 8601 - Modified: printing usage - Fixed: bug in threads' initialization in afclient - Added: 'timeout' and 'dateformat' options in ra mode - Modified: empty dateformat disables printing '[] ' - Added: 'audit' and 'dnslookups' options in ra mode - Fixed: afserver freeze bug - Added: 'kuser' and 'kclient' options in ra mode - Fixed: bug in starting afclient in ra mode - Added: audit log printed also after kicking the client --- src/remoteadmin.c | 375 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 330 insertions(+), 45 deletions(-) (limited to 'src/remoteadmin.c') diff --git a/src/remoteadmin.c b/src/remoteadmin.c index 4e777c1..c2ada6e 100644 --- a/src/remoteadmin.c +++ b/src/remoteadmin.c @@ -18,11 +18,51 @@ * */ +#include + #include "remoteadmin.h" static char newmessage; static int +parse_int(unsigned char* buff, int* ret) +{ + int intarg, i; + char guard; + if (((i = sscanf((char*) &buff[*ret], "%d%c", &intarg, &guard)) == 2) || (i == 1)) { + if (i == 1) { + guard = ' '; + } + if (!isspace(guard)) { + return -1; + } + guard = 0; + i = (*ret); + while (buff[i] != 0) { + if (guard == 0) { + if (isspace(buff[i])) { + guard = 1; + } + } + else { + if (!isspace(buff[i])) { + break; + } + } + ++i; + } + if (buff[i] == '.') { + ++i; + } + (*ret) = i; + return intarg; + } + else { + return -1; + } +} + +static int parse_cmd(unsigned char* buff, int* ret) { int i, j, state; @@ -70,6 +110,12 @@ parse_cmd(unsigned char* buff, int* ret) if (strcmp(cmd, "cshow") == 0) { return 5; } if (strcmp(cmd, "ushow") == 0) { return 6; } if (strcmp(cmd, "quit") == 0) { return 7; } + if (strcmp(cmd, "timeout") == 0) { return 8; } + if (strcmp(cmd, "audit") == 0) { return 9; } + if (strcmp(cmd, "dnslookups") == 0) { return 10; } + if (strcmp(cmd, "dateformat") == 0) { return 11; } + if (strcmp(cmd, "kuser") == 0) { return 12; } + if (strcmp(cmd, "kclient") == 0) { return 13; } return 0; } @@ -134,12 +180,16 @@ serve_admin(ConfigurationT* config, int realm, int client, unsigned char* buff) { int length, n, i, j, ret; time_t now, tmp; + llnodeT* llptr; + alnodeT* alptr; + char olddf[51], newdf[51]; char type = config->realmtable[realm].type | TYPE_SSL | TYPE_ZLIB; clifd master = config->realmtable[realm].raclitable[client].cliconn; + olddf[50] = newdf[50] = 0; length = buff[3]; length = length << 8; - length += buff[4]; /* this is length of message */ + length += buff[4]; /* this is the length of a message */ time(&now); @@ -147,19 +197,26 @@ serve_admin(ConfigurationT* config, int realm, int client, unsigned char* buff) case AF_RA_CMD: { n = get_message(type, master, buff, length); buff[n] = 0; - aflog(2, " realm[%s]: admin: message length = %d [%s]", + aflog(LOG_T_MANAGE, LOG_I_INFO, + "realm[%s]: admin: message length = %d [%s]", get_realmname(config, realm), n, buff); switch (parse_cmd(buff, &ret)) { case 1: { /* help */ add_to_message(buff, AF_VER("AFSERVER")); add_to_message(buff, "\nValid commands are:"); - add_to_message(buff, " help display help"); - add_to_message(buff, " lcmd lists available commands"); - add_to_message(buff, " info prints info about server"); - add_to_message(buff, " rshow display realms"); - add_to_message(buff, " cshow X display clients in X realm"); - add_to_message(buff, " ushow X display users in X realm"); - add_to_message(buff, " quit quit connection"); + add_to_message(buff, " help display help"); + add_to_message(buff, " lcmd lists available commands"); + add_to_message(buff, " info prints info about server"); + add_to_message(buff, " rshow display realms"); + add_to_message(buff, " cshow X display clients in X realm"); + add_to_message(buff, " ushow X display users in X realm"); + add_to_message(buff, " quit quit connection"); + add_to_message(buff, " timeout N X set timeout value in X realm"); + add_to_message(buff, " audit {0|1} X set audit mode in X realm"); + add_to_message(buff, " dnslookups {0|1} X set dnslookups mode in X realm"); + add_to_message(buff, " dateformat S set dateformat"); + add_to_message(buff, " kuser S kick user named S"); + add_to_message(buff, " kclient N kick client with number N"); send_adm_message(type, master, buff, AF_RA_STATUS_OK); break; } @@ -171,6 +228,12 @@ serve_admin(ConfigurationT* config, int realm, int client, unsigned char* buff) add_to_message(buff, "cshow"); add_to_message(buff, "ushow"); add_to_message(buff, "quit"); + add_to_message(buff, "timeout"); + add_to_message(buff, "audit"); + add_to_message(buff, "dnslookups"); + add_to_message(buff, "dateformat"); + add_to_message(buff, "kuser"); + add_to_message(buff, "kclient"); send_adm_message(type, master, buff, AF_RA_STATUS_OK); break; } @@ -179,23 +242,17 @@ serve_admin(ConfigurationT* config, int realm, int client, unsigned char* buff) add_to_message(buff, "Realms: %d", config->size); add_to_message(buff, "Certificate: %s", config->certif); add_to_message(buff, "Key: %s", config->keys); - if (config->logging) { - add_to_message(buff, "logfile: %s (verbosity:%d)", - config->logfnam, config->logging); - } - else { - add_to_message(buff, "no logfile"); - } - if (config->socklogging) { - add_to_message(buff, "logsocket: %s (verbosity:%d)", - config->logsport, config->socklogging); - } - else { - add_to_message(buff, "no logsocket"); + llptr = getloglisthead(); + i = 0; + while (llptr) { + add_to_message(buff, "log[%d]: %s", i, llptr->cmdline); + llptr = llptr->next; + ++i; } tmp = now - config->starttime; add_uptime_to_message(buff, "Uptime", tmp); add_to_message(buff, "Cg: %ld B", getcg()); + add_to_message(buff, "Dateformat: %s", getdateformat()); send_adm_message(type, master, buff, AF_RA_STATUS_OK); break; } @@ -219,13 +276,30 @@ serve_admin(ConfigurationT* config, int realm, int client, unsigned char* buff) config->realmtable[i].usrclitable[j].manportnum); } add_to_message(buff, "climode: %s", config->realmtable[i].clim); - add_to_message(buff, "timeout: %s", config->realmtable[i].timeout); + add_to_message(buff, "timeout: %d", config->realmtable[i].tmout); add_to_message(buff, "baseport: %s", config->realmtable[i].baseport ? "yes" : "no"); + add_to_message(buff, "audit: %s", config->realmtable[i].audit ? + "yes" : "no"); + add_to_message(buff, "dnslookups: %s", config->realmtable[i].dnslookups ? + "yes" : "no"); add_to_message(buff, "ssl: %s, zlib: %s, mode: %s", (TYPE_IS_SSL(config->realmtable[i].type))?"yes":"no", (TYPE_IS_ZLIB(config->realmtable[i].type))?"yes":"no", (TYPE_IS_TCP(config->realmtable[i].type))?"tcp":"udp"); + switch (config->realmtable[i].tunneltype) { + case 0: { + add_to_message(buff, "tunneltype: direct"); + break; + } + case 1: { + add_to_message(buff, "tunneltype: http proxy"); + break; + } + default: { + add_to_message(buff, "tunneltype: UNKNOWN"); + } + } } send_adm_message(type, master, buff, AF_RA_STATUS_OK); break; @@ -264,15 +338,45 @@ serve_admin(ConfigurationT* config, int realm, int client, unsigned char* buff) add_to_message(buff, "Id: %s", (config->realmtable[n].clitable[i].clientid == NULL)?"": config->realmtable[n].clitable[i].clientid); + add_to_message(buff, "Number: %d", + config->realmtable[n].clitable[i].clientnum); add_to_message(buff, "IP: %s, port: %s", config->realmtable[n].clitable[i].namebuf, config->realmtable[n].clitable[i].portbuf); + switch (config->realmtable[n].clitable[i].tunneltype) { + case 0: { + add_to_message(buff, "tunneltype: direct"); + break; + } + case 1: { + add_to_message(buff, "tunneltype: http proxy"); + break; + } + default: { + add_to_message(buff, "tunneltype: UNKNOWN"); + } + } + if (config->realmtable[n].audit) { + add_to_message(buff, "auditlog:"); + alptr = config->realmtable[n].clitable[i].head; + while (alptr) { + add_to_message(buff, + "userid: %d ip: %s port: %s connected: %s duration: %s", + alptr->userid, + alptr->namebuf, + alptr->portbuf, + localdate(&(alptr->connecttime)), + timeperiod(alptr->duration)); + alptr = alptr->next; + } + } } } send_adm_message(type, master, buff, AF_RA_STATUS_OK); break; } add_to_message(buff, "Wrong realm name"); + add_to_message(buff, "Usage: cshow X , X - realm name"); send_adm_message(type, master, buff, AF_RA_FAILED); break; } @@ -318,18 +422,179 @@ serve_admin(ConfigurationT* config, int realm, int client, unsigned char* buff) break; } add_to_message(buff, "Wrong realm name"); + add_to_message(buff, "Usage: ushow X , X - realm name"); send_adm_message(type, master, buff, AF_RA_FAILED); break; } case 7: { /* quit */ - aflog(1, " realm[%s]: Client[%s] (ra): commfd: CLOSED", + aflog(LOG_T_MANAGE, LOG_I_INFO, + "realm[%s]: Client[%s] (ra): commfd: CLOSED", get_realmname(config, realm), get_raclientname(&(config->realmtable[realm]), client)); send_adm_message(type, master, buff, AF_RA_KICKED); return 1; } + case 8: { /* timeout */ + i = parse_int(buff, &ret); + if (i <= 0) { + add_to_message(buff, "Invalid timeout value"); + add_to_message(buff, + "Usage: timeout N X , N - new timeout value, X - realm name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + break; + } + n = get_realmnumber(config, (char*) &buff[ret]); + if ((n >= 0) && (n < config->size)) { + add_to_message(buff, "changed timeout: %d --> %d", + config->realmtable[n].tmout, i); + config->realmtable[n].tmout = i; + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + break; + } + add_to_message(buff, "Wrong realm name"); + add_to_message(buff, + "Usage: timeout N X , N - new timeout value, X - realm name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + break; + } + case 9: { /* audit */ + i = parse_int(buff, &ret); + if ((i != 0) && (i != 1)) { + add_to_message(buff, "Invalid audit value"); + add_to_message(buff, + "Usage: audit {0|1} X , N=0 off, N=1 on, X - realm name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + break; + } + n = get_realmnumber(config, (char*) &buff[ret]); + if ((n >= 0) && (n < config->size)) { + add_to_message(buff, "changed audit: %s --> %s", + config->realmtable[n].audit ? "yes" : "no", i ? "yes" : "no"); + config->realmtable[n].audit = i; + if (i == 0) { + for (i = 0; i < config->realmtable[n].clinum; ++i) { + freeauditlist(&(config->realmtable[n].clitable[i].head)); + } + } + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + break; + } + add_to_message(buff, "Wrong realm name"); + add_to_message(buff, + "Usage: audit {0|1} X , N=0 off, N=1 on, X - realm name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + break; + } + case 10: { /* dnslookups */ + i = parse_int(buff, &ret); + if ((i != 0) && (i != 1)) { + add_to_message(buff, "Invalid dnslookups value"); + add_to_message(buff, + "Usage: dnslookups {0|1} X , N=0 off, N=1 on, X - realm name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + break; + } + n = get_realmnumber(config, (char*) &buff[ret]); + if ((n >= 0) && (n < config->size)) { + add_to_message(buff, "changed dnslookups: %s --> %s", + config->realmtable[n].dnslookups ? "yes" : "no", i ? "yes" : "no"); + config->realmtable[n].dnslookups = i; + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + break; + } + add_to_message(buff, "Wrong realm name"); + add_to_message(buff, + "Usage: dnslookups {0|1} X , N=0 off, N=1 on, X - realm name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + break; + } + case 11: { /* dateformat */ + strncpy(olddf, getdateformat(), 50); + strncpy(newdf, (char*) &buff[ret], 50); + add_to_message(buff, "changed dateformat: %s --> %s", + olddf, newdf); + setdateformat(newdf); + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + break; + } + case 12: { /* kuser */ + i = parse_int(buff, &ret); + if (buff[ret] != 0) { + add_to_message(buff, "Invalid user name"); + add_to_message(buff, + "Usage: kuser S , S - user name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + break; + } + j = -1; + for (n = 0; n < config->size; ++n) { + j = get_usernumber(&(config->realmtable[n]), i); + if (j != (-1)) { + if ((config->realmtable[n].contable[j].state == S_STATE_OPEN) || + (config->realmtable[n].contable[j].state == S_STATE_STOPPED)) { + add_to_message(buff, "kicked: realm[%s] user[%d]", + get_realmname(config, n), get_username(&(config->realmtable[n]), i)); + close(config->realmtable[n].contable[j].connfd); + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + } + else { + add_to_message(buff, "Invalid user"); + add_to_message(buff, + "Usage: kuser S , S - user name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + } + break; + } + } + if (j == (-1)) { + add_to_message(buff, "Invalid user name"); + add_to_message(buff, + "Usage: kuser S , S - user name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + } + break; + } + case 13: { /* kclient */ + i = parse_int(buff, &ret); + if (buff[ret] != 0) { + add_to_message(buff, "Invalid client number"); + add_to_message(buff, + "Usage: kclient N , N - client number"); + send_adm_message(type, master, buff, AF_RA_FAILED); + break; + } + j = -1; + for (n = 0; n < config->size; ++n) { + j = get_clientnumber(&(config->realmtable[n]), i); + if (j != (-1)) { + if (config->realmtable[n].clitable[j].ready) { + add_to_message(buff, "kicked: realm[%s] client[%s]", + get_realmname(config, n), + get_clientname(&(config->realmtable[n]), j)); + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + return (i+2); + } + else { + add_to_message(buff, "Invalid client"); + add_to_message(buff, + "Usage: kclient N , N - client number"); + send_adm_message(type, master, buff, AF_RA_FAILED); + } + break; + } + } + if (j == (-1)) { + add_to_message(buff, "Invalid client number"); + add_to_message(buff, + "Usage: kclient N , N - client number"); + send_adm_message(type, master, buff, AF_RA_FAILED); + } + break; + + } default: { - aflog(2, " realm[%s]: admin: cmd ignored", get_realmname(config, realm)); + aflog(LOG_T_MANAGE, LOG_I_WARNING, + "realm[%s]: admin: cmd ignored", get_realmname(config, realm)); send_adm_message(type, master, buff, AF_RA_UNDEFINED); } } @@ -339,7 +604,8 @@ serve_admin(ConfigurationT* config, int realm, int client, unsigned char* buff) break; } default: { - aflog(1, "Unrecognized message from remote admin --> closing"); + aflog(LOG_T_MANAGE, LOG_I_ERR, + "Unrecognized message from remote admin --> closing"); return 1; } } @@ -359,24 +625,29 @@ client_admin(char type, clifd master, unsigned char* buff, int connectfd, char* get_message(type, master, buff, -5); if ( buff[0] == 0 ) { - aflog(0, "Wrong password"); + aflog(LOG_T_INIT, LOG_I_CRIT, + "Wrong password"); return 1; } if ( buff[0] == AF_S_CANT_OPEN ) { - aflog(0, "Server is full"); + aflog(LOG_T_INIT, LOG_I_CRIT, + "Server is full"); return 1; } if ( buff[0] != AF_S_ADMIN_LOGIN ) { - aflog(0, "Incompatible server type or server full"); + aflog(LOG_T_INIT, LOG_I_CRIT, + "Incompatible server type or server full"); return 1; } - aflog(1, "CLIENT STARTED mode: remote administration"); + aflog(LOG_T_MAIN, LOG_I_INFO, + "CLIENT STARTED mode: remote administration"); if (connectfd > 0) { outfp = fdopen(connectfd, "w"); if (outfp == NULL) { - aflog(0, "Error in opening file descriptor for writing"); + aflog(LOG_T_INIT, LOG_I_CRIT, + "Error in opening file descriptor for writing"); return 1; } infd = connectfd; @@ -387,7 +658,8 @@ client_admin(char type, clifd master, unsigned char* buff, int connectfd, char* } infp = fdopen(infd, "r"); if (infp == NULL) { - aflog(0, "Error in opening file descriptor for reading"); + aflog(LOG_T_INIT, LOG_I_CRIT, + "Error in opening file descriptor for reading"); return 1; } @@ -414,7 +686,8 @@ client_admin(char type, clifd master, unsigned char* buff, int connectfd, char* buff[3] = n >> 8; /* high bits of message length */ buff[4] = n; /* low bits of message length */ send_message(type, master, buff, n+5); - aflog(1, "ID SENT: %s", id); + aflog(LOG_T_MANAGE, LOG_I_INFO, + "ID SENT: %s", id); } while (1) { @@ -422,10 +695,12 @@ client_admin(char type, clifd master, unsigned char* buff, int connectfd, char* select(maxfdp1, &rset, NULL, NULL, NULL); if (FD_ISSET(master.commfd, &rset)) { - aflog(3, " masterfd: FD_ISSET"); + aflog(LOG_T_MANAGE, LOG_I_DEBUG, + "masterfd: FD_ISSET"); n = get_message(type, master, buff, 5); if (n != 5) { - aflog(2, " FATAL ERROR! (%d)", n); + aflog(LOG_T_MANAGE, LOG_I_ERR, + "FATAL ERROR! (%d)", n); if (n == -1) { if (TYPE_IS_SSL(type)) { get_ssl_error(&master, "FE", n); @@ -436,15 +711,18 @@ client_admin(char type, clifd master, unsigned char* buff, int connectfd, char* return 1; } if (n == 0) { /* server quits -> we do the same... */ - aflog(0, " SERVER: premature quit --> exiting..."); + aflog(LOG_T_MANAGE, LOG_I_CRIT, + "SERVER: premature quit --> exiting..."); return 1; } if (buff[0] == AF_S_CLOSING) { - aflog(0, " SERVER: CLOSED -> exiting... cg: %ld bytes", getcg()); + aflog(LOG_T_MANAGE, LOG_I_CRIT, + "SERVER: CLOSED -> exiting... cg: %ld bytes", getcg()); return 0; } if (buff[0] != AF_S_ADMIN_CMD) { - aflog(0, " SERVER: wrong message --> exiting"); + aflog(LOG_T_MANAGE, LOG_I_CRIT, + "SERVER: wrong message --> exiting"); return 1; } length = buff[3]; @@ -453,16 +731,19 @@ client_admin(char type, clifd master, unsigned char* buff, int connectfd, char* switch (buff[1]) { case AF_RA_STATUS_OK: { - aflog(1, " SERVER: cmd successful"); + aflog(LOG_T_MANAGE, LOG_I_INFO, + "SERVER: cmd successful"); } case AF_RA_FAILED: { if (buff[1] == AF_RA_FAILED) { - aflog(1, " SERVER: cmd failed"); + aflog(LOG_T_MANAGE, LOG_I_INFO, + "SERVER: cmd failed"); } } case AF_RA_UNDEFINED: { if (buff[1] == AF_RA_UNDEFINED) { - aflog(1, " SERVER: unknown cmd"); + aflog(LOG_T_MANAGE, LOG_I_WARNING, + "SERVER: unknown cmd"); } n = get_message(type, master, buff, length); buff[n] = 0; @@ -471,21 +752,25 @@ client_admin(char type, clifd master, unsigned char* buff, int connectfd, char* break; } case AF_RA_KICKED: { - aflog(0, " SERVER: kicked us -> exiting... cg: %ld bytes", getcg()); + aflog(LOG_T_MANAGE, LOG_I_ERR, + "SERVER: kicked us -> exiting... cg: %ld bytes", getcg()); return 1; break; } default: { - aflog(0, " SERVER: unrecognized message -> exiting... cg: %ld bytes", getcg()); + aflog(LOG_T_MANAGE, LOG_I_ERR, + "SERVER: unrecognized message -> exiting... cg: %ld bytes", getcg()); return 1; } } } if (FD_ISSET(infd, &rset)) { - aflog(3, " infd: FD_ISSET"); + aflog(LOG_T_MANAGE, LOG_I_DEBUG, + "infd: FD_ISSET"); if (fgets((char*) &buff[5], 8091, infp) == NULL) { /* client quits --> exiting */ - aflog(0, " CLIENT CLOSED cg: %ld bytes", getcg()); + aflog(LOG_T_MANAGE, LOG_I_NOTICE, + "CLIENT CLOSED cg: %ld bytes", getcg()); return 0; } n = strlen((char*) &buff[5]); -- cgit v1.1