diff -r --exclude=.svn -u -N jftpgw-0.13.5/arkoon.c arkoon-apps/proxies/ftp/jftpgw/arkoon.c diff -r --exclude=.svn -u -N jftpgw-0.13.5/bindport.c arkoon-apps/proxies/ftp/jftpgw/bindport.c --- jftpgw-0.13.5/bindport.c 2004-04-25 17:28:32.000000000 +0200 +++ arkoon-apps/proxies/ftp/jftpgw/bindport.c 2007-11-29 15:50:07.000000000 +0100 @@ -50,11 +50,20 @@ int maxfd; }; +struct listen_iface { + struct sockaddr_in sin; + struct listen_iface *next; +}; + +static struct listen_iface *listen_iface_list = NULL; + static int child_setup(int, struct clientinfo*); static struct descriptor_set listen_on_ifaces(const char*, struct clientinfo*); static int get_connecting_socket(struct descriptor_set); static int say_welcome(int); static char* prependcode(const char* s, int code); +static void listen_iface_add(const struct sockaddr_in *sin); +static void listen_iface_cleanup(void); /* bindport binds to the specified PORT on HOSTNAME (which may also be a * dot-notation IP and returns the socket descriptor @@ -138,6 +147,9 @@ return -1; } + /* keep listening interface address */ + listen_iface_add(&sin); + return shandle; } @@ -430,7 +442,7 @@ /* see if we are in transparent mode */ t_in = socketinfo_get_transparent_target_sin(sock_fd); - jlog(7, "Transparent target seems to be %s on port %d", + jlog(9, "Transparent target seems to be %s on port %d", inet_ntoa(t_in.sin_addr), ntohs(t_in.sin_port)); @@ -512,9 +524,15 @@ get_uint_peer_ip(sock_fd) == t_in.sin_addr.s_addr) { jlog(4, "proxy loop detected - machine connects to itself, disabling transparent proxy support"); } + if (config_get_bool("transparent-proxy")) { + jlog(9, "Transparent proxy on"); + } - jlog(9, "Proxy loop check: peer_ip: %s, t_in_ip: %s", - get_char_peer_ip(sock_fd), inet_ntoa(t_in.sin_addr)); + jlog(9, "Proxy loop check: peer_ip: %s, ", + get_char_peer_ip(sock_fd)); + /* Beware, inet_ntoa returns a pointer to a static buffer, and + get_char_peer_ip uses inet_ntoa too. */ + jlog(9, "t_in_ip: %s", inet_ntoa(t_in.sin_addr)); #ifdef HAVE_LINUX_NETFILTER_IPV4_H jlog(9, "HAVE_LINUX_NETFILTER_IPV4_H true, c_in_ip: %s, t_in_port: %d, " "c_in_port: %d", inet_ntoa(c_in.sin_addr), @@ -527,9 +545,9 @@ * configuration "in the wild". Is there? */ (!(get_uint_peer_ip(sock_fd) == t_in.sin_addr.s_addr) #ifdef HAVE_LINUX_NETFILTER_IPV4_H - && !(t_in.sin_addr.s_addr == c_in.sin_addr.s_addr + && !((t_in.sin_addr.s_addr == c_in.sin_addr.s_addr) && - t_in.sin_port == c_in.sin_port) + (t_in.sin_port == c_in.sin_port)) #endif )) { @@ -640,6 +658,9 @@ FD_ZERO(&d_set.set); d_set.maxfd = 0; + /* if we had already some listening interfaces listed, clear them. */ + listen_iface_cleanup(); + /* we have to make the string suitable for quotstrtok by appending a * WHITESPACE character */ hostnames2size = strlen(hostnames) + 2; @@ -801,4 +822,55 @@ } +static void listen_iface_cleanup(void) +{ + if (listen_iface_list) { + struct listen_iface *_if, *next; + for (_if = listen_iface_list; _if; _if = next) { + next = _if->next; + free(_if); + } + listen_iface_list = NULL; + } +} + + +static void listen_iface_add(const struct sockaddr_in *sin) +{ + struct listen_iface *_if; + + _if = malloc(sizeof(struct listen_iface)); + if (_if) { + _if->next = listen_iface_list; + listen_iface_list = _if; + memcpy(&(_if->sin), sin, sizeof(struct sockaddr_in)); + } +} + +int is_listen_iface(const struct sockaddr_in *sin) +{ + int ret=0; + struct listen_iface *_if; + + for (_if = listen_iface_list; _if; _if = _if->next) { + if ((sin->sin_addr.s_addr == _if->sin.sin_addr.s_addr) && + (sin->sin_port == _if->sin.sin_port)) { + ret = 1; + break; + } + } + return ret; +} + +struct sockaddr_in *find_local_listen_iface(void) +{ + struct listen_iface *_if; + + for (_if = listen_iface_list; _if; _if = _if->next) { + if (_if->sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { + return &(_if->sin); + } + } + return NULL; +} diff -r --exclude=.svn -u -N jftpgw-0.13.5/cmds.c arkoon-apps/proxies/ftp/jftpgw/cmds.c --- jftpgw-0.13.5/cmds.c 2004-01-08 22:49:27.000000000 +0100 +++ arkoon-apps/proxies/ftp/jftpgw/cmds.c 2007-11-29 15:50:07.000000000 +0100 @@ -21,6 +21,7 @@ #include #include /* for IAC, IP */ #include "jftpgw.h" +#include "arkoon.h" /* include the different command sets */ @@ -45,6 +46,7 @@ conn_info.lcs = &lcs; conn_info.clntinfo = clntinfo; clntinfo->cachefd = -1; + clntinfo->av_fd = -1; jlog(9, "setting dataclientsock to -1 (initial)"); clntinfo->dataclientsock = clntinfo->dataserversock = -1; clntinfo->dataport = socketinfo_get_local_port(clntinfo->clientsocket) - 1; @@ -520,10 +522,10 @@ #define TRANSMITBUFSIZE PIPE_BUF #endif int transfer_transmit(struct clientinfo *clntinfo) { - char* buffer = (char*) malloc(TRANSMITBUFSIZE); + char* buffer[2]; char* pbuf = 0; - int count = 0; - int nwritten = 0, cachewritten, totwritten, sret = 0, scret = 0; + int count[2] = {0, 0}; + int nwritten = 0, cachewritten, av_written, totwritten, sret = 0, scret = 0; int cachefail = 0; int cs = clntinfo->clientsocket; int n, ret, error = 0, aborted = 0; @@ -535,6 +537,10 @@ struct timeval writetime; time_t start, done, delay; sigset_t sigset, oldset; + int first = 1; /* first chunk of transmitted data */ + int begin; /* begin to write the current chunk */ + int last = 0; + int ir = 0, iw = 1; readtime.tv_sec = config_get_ioption("transfertimeout", 300); readtime.tv_usec = 0; @@ -542,13 +548,17 @@ writetime.tv_usec = 0; strictasciiconversion = config_get_bool("strictasciiconversion"); - enough_mem(buffer); + buffer[0] = (char*) malloc(TRANSMITBUFSIZE); + buffer[1] = (char*) malloc(TRANSMITBUFSIZE); + enough_mem(buffer[0]); + enough_mem(buffer[1]); FD_ZERO(&readset); FD_ZERO(&writeset); FD_ZERO(&exceptset); if (clntinfo->dataclientsock < 0) { - free(buffer); + free(buffer[0]); + free(buffer[1]); return 0; } @@ -588,7 +598,7 @@ readtime.tv_usec = 0; writetime.tv_sec = config_get_ioption("transfertimeout", 300); writetime.tv_usec = 0; - count = -1; /* choose a number != 0 for the check below the + count[ir] = -1; /* choose a number != 0 for the check below the while loop */ if (clntinfo->fromcache) { @@ -620,13 +630,13 @@ if (clntinfo->fromcache || FD_ISSET(clntinfo->dataserversock, &readset)) { - count = read(clntinfo->dataserversock, - buffer, TRANSMITBUFSIZE); - if (count == 0) { + count[ir] = read(clntinfo->dataserversock, + buffer[ir], TRANSMITBUFSIZE); + if (count[ir] == 0) { jlog(8, "Read 0 bytes at %s (%d)", __FILE__, __LINE__); - break; + last = 1; } - if (count < 0) { + if (count[ir] < 0) { int err = errno; jlog(3, "read error: %s", strerror(err)); set_errstr(strerror(err)); @@ -637,8 +647,16 @@ } /* comm */ - pbuf = buffer; + pbuf = buffer[iw]; + begin = 1; do { + /* let reader a buffer ahead */ + if (first) { + first = 0; + nwritten = 0; /* trick the test after the loop */ + scret = 1; + break; + } /* now write all the read data */ FD_ZERO(&writeset); FD_SET(clntinfo->dataclientsock, &writeset); @@ -671,46 +689,70 @@ break; } /* otherwise the descriptor must be ready */ - /* write to the cache first */ - if ( clntinfo->tocache && ! cachefail ) { - cachewritten = write(clntinfo->cachefd, - pbuf, count); - if (cachewritten != count) { - jlog(3, "Error writing to the " - "cache: %s", - strerror(errno)); - cachefail = 1; + + if (begin) { + /* some things we want to be done only once per chunk + of read data */ + begin = 0; + + /* write to the cache first */ + if ( clntinfo->tocache && ! cachefail ) { + cachewritten = write(clntinfo->cachefd, + pbuf, count[iw]); + if (cachewritten != count[iw]) { + jlog(3, "Error writing to the " + "cache: %s", + strerror(errno)); + cachefail = 1; + } } - } - /* convert if we have to */ - if (clntinfo->transfermode_havetoconvert - != CONV_NOTCONVERT - && clntinfo->serverlisting != 1) { - char* tmp; - if (clntinfo->transfermode_havetoconvert - == CONV_TOASCII) { - jlog(9, "Converting to ASCII"); - tmp = to_ascii(buffer, &count, - strictasciiconversion); - if (count > TRANSMITBUFSIZE) { - buffer = - realloc(buffer, count); + + /* if antivirus is on, write to temp file, and launch + analysis if this is the last chunk */ + if (clntinfo->virus_check && clntinfo->av_fd) { + av_written = write(clntinfo->av_fd, pbuf, count[iw]); + if (av_written != count[iw]) { + error = TRNSMT_ANALYZE_ERROR; + jlog(2, "Error writing to temporary file for antivirus check: %s", + strerror(errno)); + break; + } + if (last) { + error = jftpgw_akserver_av_check(clntinfo, &lcs); + if (error) break; } - memcpy((void*) buffer, - (void*) tmp, count); - free(tmp); } + + /* convert if we have to */ if (clntinfo->transfermode_havetoconvert + != CONV_NOTCONVERT + && clntinfo->serverlisting != 1) { + char* tmp; + if (clntinfo->transfermode_havetoconvert + == CONV_TOASCII) { + jlog(9, "Converting to ASCII"); + tmp = to_ascii(buffer[iw], &(count[iw]), + strictasciiconversion); + if (count[iw] > TRANSMITBUFSIZE) { + buffer[iw] = + realloc(buffer[iw], count[iw]); + } + memcpy((void*) buffer[iw], + (void*) tmp, count[iw]); + free(tmp); + } + if (clntinfo->transfermode_havetoconvert == CONV_FRMASCII) { - /* we don't convert from - * ascii, this case does not - * occur, jftpgw always - * reads in binary mode */ + /* we don't convert from + * ascii, this case does not + * occur, jftpgw always + * reads in binary mode */ + } + pbuf = buffer[iw]; } - pbuf = buffer; } nwritten = write(clntinfo->dataclientsock, - pbuf, count); + pbuf, count[iw]); if (nwritten < 0) { jlog(2, "Error writing (%s, %d): %s", __FILE__, __LINE__, @@ -733,9 +775,9 @@ sleep(delay); } } - if (nwritten != count) { + if (nwritten != count[iw]) { pbuf += nwritten; - count -= nwritten; + count[iw] -= nwritten; } else { pbuf = 0; } @@ -748,6 +790,14 @@ if (scret <= 0) { break; } + if (error || last) { + break; + } + /* add 1 mod 2 */ + ir++; + ir %= 2; + iw++; + iw %= 2; } if (FD_ISSET(cs, &exceptset) || FD_ISSET(cs, &readset)) { if (checkforabort(clntinfo)) { @@ -788,7 +838,7 @@ error = TRNSMT_NOERRORMSG; } /* count == 0 means correct end of transfer */ - if ((sret == 0 || scret == 0) && count != 0) { + if ((sret == 0 || scret == 0) && count[ir] != 0) { jlog(2, "Connection timed out in transfer_transmit(): %d, %d", readtime.tv_sec, writetime.tv_sec); jlog(9, "Sockets: dataserver: %d, dataclient: %d, client: %d", @@ -807,16 +857,22 @@ lcs.transferred = totwritten; jlog(7, "Transferred %d bytes", totwritten); - free(buffer); + free(buffer[0]) ; + free(buffer[1]) ; close(clntinfo->dataclientsock); close(clntinfo->dataserversock); if (clntinfo->cachefd >= 0) { close(clntinfo->cachefd); } + if (clntinfo->av_fd >= 0) { + close(clntinfo->av_fd); + } clntinfo->dataclientsock = -1; clntinfo->dataserversock = -1; clntinfo->cachefd = -1; + clntinfo->av_fd = -1; + clntinfo->virus_check = 0; if (aborted) { error = TRNSMT_ABORTED; diff -r --exclude=.svn -u -N jftpgw-0.13.5/config.c arkoon-apps/proxies/ftp/jftpgw/config.c --- jftpgw-0.13.5/config.c 2004-01-08 22:49:40.000000000 +0100 +++ arkoon-apps/proxies/ftp/jftpgw/config.c 2007-11-29 15:50:07.000000000 +0100 @@ -133,6 +133,8 @@ {"dnslookups", TAG_ALL, "yes", EM, WSP }, /* 8 hours */ {"hostcachetimeout", TAG_ALL, "28800", EM, WSP }, + {"arkoonantivirus", TAG_CONNECTED, "off", EM, WSP }, + {"arkoonallowciphered", TAG_CONNECTED, "off", EM, WSP }, { (char*) 0, 0, (char*) 0, 0, 0 } }; @@ -1159,6 +1164,7 @@ nstr = (char*) malloc( newsize ); enough_mem(nstr); snprintf(nstr, newsize, "%s%s", prefix, qstr); + free(qstr); return nstr; } --- jftpgw-0.13.5/configure.in 2004-04-25 02:12:33.000000000 +0200 +++ arkoon-apps/proxies/ftp/jftpgw/configure.in 2007-11-29 15:50:07.000000000 +0100 @@ -436,6 +436,7 @@ AC_SUBST(LIBSOCKET) AC_SUBST(all_libraries) AC_SUBST(all_includes) +AC_SUBST(ak_cb_ldflags) AC_OUTPUT(Makefile \ support/Makefile \ diff -r --exclude=.svn -u -N jftpgw-0.13.5/fw_auth_cmds.c arkoon-apps/proxies/ftp/jftpgw/fw_auth_cmds.c --- jftpgw-0.13.5/fw_auth_cmds.c 2004-01-08 22:49:47.000000000 +0100 +++ arkoon-apps/proxies/ftp/jftpgw/fw_auth_cmds.c 2007-11-29 15:50:07.000000000 +0100 @@ -145,6 +158,10 @@ free(c->before_forward.user); c->before_forward.user = (char*) 0; } + if (c->before_forward.real_user) { + free(c->before_forward.real_user); + c->before_forward.real_user = (char *) 0; + } if (c->before_forward.destination) { free(c->before_forward.destination); c->before_forward.destination = (char*) 0; @@ -205,7 +222,10 @@ if (strcmp(user, "*") == 0) { /* keep the old user name */ jlog(8, "no new user name - keeping old one: %s", - clntinfo->user); + clntinfo->before_forward.real_user); + free(clntinfo->user); + clntinfo->user = strdup(clntinfo->before_forward.real_user); + enough_mem(clntinfo->user); } else { free(clntinfo->user); clntinfo->user = strdup(user); @@ -434,6 +454,17 @@ /* joe@host */ /* joe,host,21,p */ + /* first time we store the complete user string */ + if (!clntinfo->before_forward.real_user) { + int tmpoffset = offset; + clntinfo->before_forward.real_user = + quotstrtok(buffer, " ", &tmpoffset); +#ifdef ARKOON_DEBUG + jlog(9, "[DEBUG][%s:%d] before_forward.real_user=\"%s\" ",__FILE__, + __LINE__,clntinfo->before_forward.real_user); +#endif + } + if (buffer[0] == '@') { user = (char*) 0; } else { @@ -443,6 +474,11 @@ port = quotstrtok(buffer, delimiters, &offset); mode = quotstrtok(buffer, delimiters, &offset); +#ifdef ARKOON_DEBUG + jlog(9, "[DEBUG][%s:%d] user : %s from string '%s'",__FILE__, + __LINE__,user, buffer); +#endif + if (fw_forward(user, host, clntinfo) != CMD_HANDLED) { free(user); free(host); free(port); free(mode); return CMD_ERROR; @@ -476,6 +512,16 @@ } else { delimiters = ""; } + +#ifdef ARKOON_DEBUG + jlog(9, "[DEBUG][%s:%d] delimiters=\"%s\", user=\"%s\", args=\"%s\" " , + __FILE__, + __LINE__, + delimiters, + conn_info->clntinfo->user, + args_copy); +#endif + if (set_userdest(args_copy, strlen("USER "), conn_info->clntinfo, delimiters) != CMD_HANDLED) { @@ -486,10 +532,10 @@ ret = cmds_after_user(conn_info); if (ret != CMD_HANDLED && ret != CMD_DONE) { - return CMD_ERROR; + return ret; } - jlog(7, "Client logged in: User: %s, Dest: %s:%d", + jlog(7, "Client USER message: User: %s, Dest: %s:%d", conn_info->clntinfo->user, conn_info->clntinfo->destination, conn_info->clntinfo->destinationport); @@ -519,7 +565,7 @@ char* buffer; ret = login(conn_info->clntinfo, LOGIN_ST_USER); - if (ret) { return CMD_ERROR; } + if (ret) { return ret; } if (conn_info->clntinfo->login.welcomemsg.fullmsg) { buffer = merge_responses( conn_info->clntinfo->login.welcomemsg.fullmsg, @@ -538,7 +584,7 @@ jlog(6, "Didn't get successful message after sending " "the user name: %s\n", conn_info->clntinfo->login.authresp.fullmsg); - return CMD_ERROR; + return CMD_ABORT; } /* Free the welcome message. The authentication * response is always free'ed in login_send_auth */ @@ -596,7 +642,7 @@ /* login failed - do not print an error * message */ /* conn_info->clntinfo->serversocket = ss = -1; */ - return CMD_ERROR; + return CMD_ABORT; } return CMD_HANDLED; } @@ -612,7 +658,7 @@ } else { say(conn_info->clntinfo->clientsocket, "530 Login failed.\r\n"); - return CMD_ERROR; + return CMD_ABORT; } return CMD_HANDLED; } @@ -730,7 +776,7 @@ } static -int fw_set_fwuser(const char* args, struct conn_info_st* conn_info) { +int fw_set_fwuser(const char* args, struct conn_info_st* conn_info) { /* just chop off the command and put everything in the user name */ char* space = (char*) 0; if (args) { @@ -787,23 +833,22 @@ } int fw_user_type7(const char* args, struct conn_info_st* conn_info) { - char* user, *fwuser, *destchar; + char* user, *fwuser, *destchar = NULL; int offset = strlen("USER "); struct destination_t destination; if (config_compare_option("logintime", "pass") == 0) { jlog(4, "logintime has to be \"pass\" with loginstyle 7"); say(conn_info->clntinfo->clientsocket, "550 Login incorrect\r\n"); - return CMD_ERROR; + return CMD_ABORT; } user = quotstrtok_prepend("USER ", args, "@", &offset); if ( fw_set_user(user, conn_info) != CMD_HANDLED) { - free(user); - return CMD_ERROR; + if (user) free(user); + return CMD_ABORT; } - free(user); fwuser = quotstrtok_prepend("USER ", args, "@", &offset); if ( !fwuser || fw_set_fwuser(fwuser, conn_info) != CMD_HANDLED) { @@ -811,19 +870,50 @@ say(conn_info->clntinfo->clientsocket, "550 USER not recognized\r\n"); } - free(fwuser); - return CMD_ERROR; + if (user) free(user); + if (fwuser) free(fwuser); + return CMD_ABORT; } - free(fwuser); + destchar = quotstrtok(args, "@\n", &offset); destination = fw_auth_parse_host_port(destchar); - free(destchar); if ( ! destination.hostname ) { + if (user) free(user); + if (fwuser) free(fwuser); + if (destchar) free(destchar); say(conn_info->clntinfo->clientsocket, "550 USER not recognized\r\n"); - return CMD_ERROR; + return CMD_ABORT; } + +#ifdef ARKOON_DEBUG + jlog(9,"[DEBUG][%s:%d] user=\"%s\",fwuser=\"%s\", destchar=\"%s\"", + __FILE__,__LINE__,user,fwuser,destchar); +#endif + /* first time we store the complete user string */ + if (!conn_info->clntinfo->before_forward.real_user) { + + int tmpoffset = strlen("USER "); + char *r_user = quotstrtok(user, " ", &tmpoffset); + if (r_user && destchar) { + /* real_user is user@destination */ + conn_info->clntinfo->before_forward.real_user = + malloc(strlen(r_user)+strlen(destchar)+2); + enough_mem(conn_info->clntinfo->before_forward.real_user); + snprintf(conn_info->clntinfo->before_forward.real_user + ,strlen(r_user)+strlen(destchar)+2, + "%s@%s",r_user,destchar); + } +#ifdef ARKOON_DEBUG + jlog(9, "[DEBUG][%s:%d] before_forward.real_user=\"%s\" ",__FILE__, + __LINE__,conn_info->clntinfo->before_forward.real_user); +#endif + } + if (user) free(user); + if (fwuser) free(fwuser); + if (destchar) free(destchar); + conn_info->clntinfo->destination = destination.hostname; conn_info->clntinfo->destinationport = destination.port; @@ -843,7 +933,7 @@ if (! last_at) { say(conn_info->clntinfo->clientsocket, "550 PASS not recognized\r\n"); - return CMD_ERROR; + return CMD_ABORT; } offset = 1; @@ -854,7 +944,7 @@ "550 PASS not recognized\r\n"); } free(fwpass); - return CMD_ERROR; + return CMD_ABORT; } free(fwpass); @@ -878,7 +968,7 @@ "550 PASS not recognized\r\n"); } free(pass); - return CMD_ERROR; + return CMD_ABORT; } free(pass); @@ -886,7 +976,7 @@ conn_info->clntinfo->fw_auth.pass) != 0) { say(conn_info->clntinfo->clientsocket, "550 Login incorrect\r\n"); - return CMD_ERROR; + return CMD_ABORT; } return cmds_after_pass(conn_info); } diff -r --exclude=.svn -u -N jftpgw-0.13.5/jftpgw.h arkoon-apps/proxies/ftp/jftpgw/jftpgw.h --- jftpgw-0.13.5/jftpgw.h 2004-01-08 22:51:19.000000000 +0100 +++ arkoon-apps/proxies/ftp/jftpgw/jftpgw.h 2007-11-29 15:50:07.000000000 +0100 @@ -115,6 +115,9 @@ #define TRNSMT_ERROR 1 #define TRNSMT_ABORTED 2 #define TRNSMT_NOERRORMSG 4 +#define TRNSMT_ANALYZE_ERROR 8 +#define TRNSMT_VIRUS 16 +#define TRNSMT_CIPHERED 32 #define SVR_LAUNCH_CMDLINE 0 #define SVR_LAUNCH_LOGFILES 1 @@ -145,6 +148,9 @@ int cachefd; int fromcache; int tocache; + int av_fd; + int virus_check; + char *av_tmp; int *waitforconnect; int transparent; int mode; @@ -188,6 +194,10 @@ char* pass; } fw_auth; struct { + /* the login name the ftp client sent, used for + the forward management + */ + char* real_user; char* user; unsigned long int dest_ip; char* destination; @@ -396,5 +406,8 @@ char* rel2abs(const char* path, const char* base, char* result, const size_t size); +/* from bindport.c */ +int is_listen_iface(const struct sockaddr_in *sin); +struct sockaddr_in *find_local_listen_iface(void); #endif /* __JFTPGW_H__ */ diff -r --exclude=.svn -u -N jftpgw-0.13.5/log.c arkoon-apps/proxies/ftp/jftpgw/log.c --- jftpgw-0.13.5/log.c 2004-04-25 09:25:56.000000000 +0200 +++ arkoon-apps/proxies/ftp/jftpgw/log.c 2007-11-29 15:50:07.000000000 +0100 @@ -446,6 +446,7 @@ strlen(replaced_line) + strlen(fragment) + 1); enough_mem(replaced_line); strcat(replaced_line, fragment); + free(fragment); } /* the key is at line[offset+1]; */ offset++; diff -r --exclude=.svn -u -N jftpgw-0.13.5/login.c arkoon-apps/proxies/ftp/jftpgw/login.c --- jftpgw-0.13.5/login.c 2004-04-25 09:23:12.000000000 +0200 +++ arkoon-apps/proxies/ftp/jftpgw/login.c 2007-11-29 15:50:07.000000000 +0100 @@ -165,6 +165,7 @@ * */ break; case CMD_ABORT: + free(buffer); return -1; break; } @@ -208,7 +209,7 @@ if ((ret = login_setforward_user(clntinfo)) < 0) { /* the error is logged and say()ed */ - return CMD_ERROR; + return ret; } if (! clntinfo->destination) { @@ -420,9 +421,12 @@ if (!allowed) { say(clntinfo->clientsocket, "531 You are not allowed to connect to that host.\r\n"); - jlog(8, "Not allowed to connect to %s", clntinfo->destination); + jlog(5, "%s was not allowed to connect to host %s:%d.", + conv_ip_to_char(clntinfo->client_ip), + clntinfo->destination, + clntinfo->destinationport); lcs.respcode = 531; - return CMD_ERROR; + return CMD_ABORT; } /* if the client was allowed, save the clients original IP */ if (!clntinfo->before_forward.user) { @@ -443,6 +447,16 @@ | TAG_TIME | TAG_SERVERTYPE | TAG_PROXYIP | TAG_PROXYPORT; + +#ifdef ARKOON_DEBUG + jlog(9, "[DEBUG][%s:%d] forward.login=\"%s\", user=\"%s\" " , + __FILE__, + __LINE__, + clntinfo->forward.login, + clntinfo->user + ); +#endif + /* this is already a forward */ if ( clntinfo->before_forward.user ) { return CMD_HANDLED; @@ -475,9 +489,11 @@ if (config_compare_option("access", "allow") == 0) { say(clntinfo->clientsocket, "531 You are not allowed to " "connect to that host. Goodbye.\r\n"); - jlog(5, "%s was not allowed to connect.", - conv_ip_to_char(clntinfo->client_ip)); - return CMD_ERROR; + jlog(5, "%s was not allowed to connect to host %s:%d.", + conv_ip_to_char(clntinfo->client_ip), + clntinfo->destination, + clntinfo->destinationport); + return CMD_ABORT; } /* see if there is an option for the forward */ @@ -485,7 +501,9 @@ if (! forward) { /* no forward */ + if (lcs.userlogin ) { free (lcs.userlogin); } lcs.userlogin = strnulldup(clntinfo->user); + if (lcs.usereffective ) { free (lcs.usereffective); } lcs.usereffective = strnulldup(clntinfo->user); if (lcs.userforwarded) { free(lcs.userforwarded); } lcs.userforwarded = strdup(""); @@ -529,6 +547,8 @@ forward_list->value[0] == '%' && forward_list->value[1] == '@') { /* no forward is being used */ + if (lcs.userlogin) { free (lcs.userlogin); } + if (lcs.usereffective) { free (lcs.usereffective); } lcs.userlogin = strnulldup(clntinfo->user); lcs.usereffective = strnulldup(clntinfo->user); if (lcs.userforwarded) { free(lcs.userforwarded); } @@ -610,6 +630,15 @@ /* passauth */ clntinfo->forward.passauth = 1; } +#ifdef ARKOON_DEBUG + jlog(9, "[DEBUG][%s:%d] forward.login=\"%s\", passauth=\"%d\", user=\"%s\" " , + __FILE__, + __LINE__, + clntinfo->forward.login, + clntinfo->forward.passauth, + clntinfo->user + ); +#endif /* If there is still no destination, see if we have a defaultforward * setting */ @@ -635,6 +664,10 @@ } /* set values for log info struct */ + if (lcs.userlogin ) { free (lcs.userlogin); } + if (lcs.usereffective ) { free (lcs.usereffective); } + if (lcs.userforwarded ) { free (lcs.userforwarded); } + lcs.userlogin = strnulldup(clntinfo->before_forward.user); lcs.usereffective = strnulldup(clntinfo->user); lcs.userforwarded = strnulldup(clntinfo->forward.login); @@ -758,7 +791,7 @@ buffer = ftp_readline(clntinfo->serversocket); if (!buffer) { if (timeout) { - jlog(1, "Timeout in %s line %d\n", __FILE__ ,__LINE__); + jlog(1, "Timeout after saying 'SYST'\n"); err_time_readline(clntinfo->clientsocket); return CMD_ABORT; } else { @@ -790,7 +823,7 @@ if (!clntinfo->login.welcomemsg.fullmsg) { /* an error occurred */ if (timeout) { - jlog(2, "Timeout in %s line %d\n", __FILE__ ,__LINE__); + jlog(2, "Timeout while reading the welcome line\n"); err_time_readline(clntinfo->clientsocket); } else { set_errstr("Server closed the connection"); @@ -802,7 +835,11 @@ jlog(9, "Connected to %s, got \"%s\" as welcome message", clntinfo->destination, clntinfo->login.welcomemsg.fullmsg); - if (!checkbegin(clntinfo->login.welcomemsg.lastmsg, "220 ")) { + /* ARKOON: Normaly, only 220 is an authorized return code for + the welcome line. But M>Wall FTP proxy always + says "230 ...." */ + if (!checkbegin(clntinfo->login.welcomemsg.lastmsg, "220 ") && + !checkbegin(clntinfo->login.welcomemsg.lastmsg, "230 ") ) { jlog(2, "Not a valid FTP server response (%s)", clntinfo->login.welcomemsg.fullmsg); say(clntinfo->clientsocket,clntinfo->login.welcomemsg.fullmsg); @@ -843,7 +880,7 @@ if (!clntinfo->login.authresp.fullmsg) { if (timeout) { - jlog(2, "Timeout in %s line %d\n", __FILE__ ,__LINE__); + jlog(2, "Timeout while sending auth user"); err_time_readline(clntinfo->clientsocket); } else { err_readline(clntinfo->clientsocket); @@ -926,6 +963,24 @@ return CMD_HANDLED; } +static unsigned long int _socketinfo_get_local_ip(int fd) { + struct sockaddr_in sin; + int i; +#ifdef HAVE_SOCKLEN_T + socklen_t slen; +#else + int slen; +#endif + + slen = sizeof(sin); + + i = getsockname(fd, (struct sockaddr*) &sin, &slen); + if (i != 0) { + jlog(2, "getsockname failed. Can't get the IP of the interface"); + return -1; + } + return sin.sin_addr.s_addr; +} static int login_loggedin_setup(struct clientinfo* clntinfo) { @@ -950,7 +1005,7 @@ clntinfo->throughput = config_get_foption("throughput", -1.0); clntinfo->addr_to_server = - socketinfo_get_local_ip(clntinfo->serversocket); + _socketinfo_get_local_ip(clntinfo->serversocket); lcs.ifipsvr = strdup(conv_ip_to_char(clntinfo->addr_to_server)); enough_mem(lcs.ifipsvr); @@ -988,8 +1043,7 @@ clntinfo->login.authresp = readall(clntinfo->serversocket); if (!clntinfo->login.authresp.fullmsg) { if (timeout) { - jlog(2, "Timeout in %s line %d\n", __FILE__, - __LINE__); + jlog(2, "Timeout while finishing login"); err_time_readline(clntinfo->clientsocket); } else { diff -r --exclude=.svn -u -N jftpgw-0.13.5/Makefile.am arkoon-apps/proxies/ftp/jftpgw/Makefile.am --- jftpgw-0.13.5/Makefile.am 2004-06-04 12:27:40.000000000 +0200 +++ arkoon-apps/proxies/ftp/jftpgw/Makefile.am 2007-11-29 15:50:07.000000000 +0100 @@ -13,9 +13,9 @@ jftpgw.c log.c login.c openport.c \ passive.c util.c ftpread.c std_cmds.c \ states.c cache.c rel2abs.c fw_auth_cmds.c \ - acconfig.h + acconfig.h arkoon.c -jftpgw_LDFLAGS = @all_libraries@ +jftpgw_LDFLAGS = @all_libraries@ @ak_cb_ldflags@ LIBS = @LIBS@ diff -r --exclude=.svn -u -N jftpgw-0.13.5/openport.c arkoon-apps/proxies/ftp/jftpgw/openport.c --- jftpgw-0.13.5/openport.c 2004-06-01 18:10:39.000000000 +0200 +++ arkoon-apps/proxies/ftp/jftpgw/openport.c 2007-11-29 15:50:07.000000000 +0100 @@ -247,7 +247,11 @@ memset((void*)&dp, 0, sizeof(dp)); dp.sin_family = AF_INET; - dp.sin_addr.s_addr = local_address; + if (local_address != htonl(INADDR_LOOPBACK)) { + /* Arkoon: use 0.0.0.0 instead of 127.0.0.1 for a redirected + * connection. */ + dp.sin_addr.s_addr = local_address; + } jlog(9, "Trying to get a free source port on address %s", inet_ntoa(dp.sin_addr)); @@ -439,6 +443,17 @@ #endif } else { i = getsockname(shandle, (struct sockaddr*) &sin, &slen); + /* Arkoon hack, due to modified getsockname() behaviour */ + if ((i == 0) && !is_listen_iface(&sin)) { + /* we are in transparent mode, then. */ + struct sockaddr_in *lsin = find_local_listen_iface(); + if (lsin) { + sin.sin_port = lsin->sin_port; + sin.sin_addr.s_addr = lsin->sin_addr.s_addr; + } else { + i = -1; + } + } } if (i != 0) { jlog(2, "getsockname failed. Can't get the IP of the interface"); diff -r --exclude=.svn -u -N jftpgw-0.13.5/passive.c arkoon-apps/proxies/ftp/jftpgw/passive.c --- jftpgw-0.13.5/passive.c 2004-01-08 22:49:59.000000000 +0100 +++ arkoon-apps/proxies/ftp/jftpgw/passive.c 2007-11-29 15:50:07.000000000 +0100 @@ -155,7 +155,9 @@ int pcsock; int cs = clntinfo->clientsocket; struct sockaddr_in pasvclientsin; + struct sockaddr_in sin; struct in_addr in; + unsigned int slen = sizeof(sin); clntinfo->clientmode = PASSIVE; @@ -186,7 +188,20 @@ clntinfo->waitforconnect = &clntinfo->dataclientsock; /* write the values to the client socket CS */ - in.s_addr = pasvclientsin.sin_addr.s_addr; + if (clntinfo->transparent == TRANSPARENT_YES) { + jlog(9, "Transparent mode."); + if (getsockname(cs, (struct sockaddr*) &sin, &slen) < 0) { + jlog(2, "getsockname() failed to determine original server address : %s", + strerror(errno)); + clntinfo->dataclientsock = -1; + clntinfo->waitforconnect = (int*) 0; + close(pcsock); + return -1; + } + in.s_addr = sin.sin_addr.s_addr; + } else { + in.s_addr = pasvclientsin.sin_addr.s_addr; + } saypasv(cs, inet_ntoa(in), htons(pasvclientsin.sin_port)); return 0; diff -r --exclude=.svn -u -N jftpgw-0.13.5/states.c arkoon-apps/proxies/ftp/jftpgw/states.c --- jftpgw-0.13.5/states.c 2004-01-08 22:50:51.000000000 +0100 +++ arkoon-apps/proxies/ftp/jftpgw/states.c 2007-11-29 15:50:07.000000000 +0100 @@ -277,13 +277,16 @@ } int passcmd_check(const char* cmd) { +#define ARKOON_PASSCMD 1 +#ifndef ARKOON_PASSCMD if (strcmp(config_get_option("passcmds"), "*") == 0) { /* this is a dummy and means "checking disabled". The "*" * is the standard value if there is no such option in the * configuration */ return 1; } +#endif if ( !passcmd_white_list ) { passcmd_white_list @@ -293,13 +296,31 @@ passcmd_black_list = passcmd_create_list(config_get_option("dontpasscmds")); } +#if ARKOON_PASSCMD + /** For Arkoon use, we consider that if a command is in the + whitelist it's OK, but first of all it must not be in the blacklist */ + if (slist_case_contains(passcmd_black_list, cmd) == 1) { + jlog(2,"%s is forbidden by configuration",cmd); + return 0; + } + if (slist_case_contains(passcmd_white_list, cmd)) { + return 1; + } else if (strcmp(config_get_option("passcmds"), "*") == 0) { + /* this is a dummy and means "checking disabled". The "*" + * is the standard value if there is no such option in the + * configuration */ + /* if the command isn't blacklisted and there is no whitelist defined, + let it go (we must accept at least some commands to be usefull !! */ + return 1; + } +#else if (slist_case_contains(passcmd_white_list, cmd) && !slist_case_contains(passcmd_black_list, cmd)) { - return 1; } +#endif return 0; } diff -r --exclude=.svn -u -N jftpgw-0.13.5/std_cmds.c arkoon-apps/proxies/ftp/jftpgw/std_cmds.c --- jftpgw-0.13.5/std_cmds.c 2004-04-25 01:50:50.000000000 +0200 +++ arkoon-apps/proxies/ftp/jftpgw/std_cmds.c 2007-11-29 15:50:07.000000000 +0100 @@ -16,6 +16,8 @@ * 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ +#include +#include #include "jftpgw.h" #include "cmds.h" @@ -31,6 +33,7 @@ int ret; char *t; time_t transfer_start; + char av_temp[32]; ret = transfer_negotiate(conn_info->clntinfo); if (ret == -1) { @@ -38,6 +41,22 @@ return 1; } + if ((ret == 0) && conn_info->clntinfo->virus_check) { + /* open a temporary file to store the transfered file to be analyzed */ + snprintf(av_temp, sizeof(av_temp), "/var/tmp/av_check_XXXXXX"); + conn_info->clntinfo->av_fd = mkstemp(av_temp); + if (conn_info->clntinfo->av_fd < 0) { + jlog(2, "Could not open temporary file to perform" + " antivirus analysis: %s", strerror(errno)); + ret = TRNSMT_ANALYZE_ERROR; + } else { + /* make this file readable by "other" */ + fchmod(conn_info->clntinfo->av_fd, S_IWUSR|S_IRUSR|S_IROTH); + conn_info->clntinfo->av_tmp = av_temp; + } + + } + if (ret == 0) { /* if there was no error, transfer the file or * listing */ @@ -48,7 +67,9 @@ /* there was an error in transfer_negotiate but it * was not dramatic */ - ret = 0; + if (ret != TRNSMT_ANALYZE_ERROR) { + ret = 0; + } } if (ret == TRNSMT_SUCCESS) { /* the transfer was okay */ @@ -65,24 +86,47 @@ free(t); } } else { - if (ret == TRNSMT_ABORTED) { + char *buf; + switch(ret) { + case TRNSMT_ABORTED: /* an aborted transfer, everything's fine */ - } - if (ret == TRNSMT_NOERRORMSG) { + break; + case TRNSMT_NOERRORMSG: /* do not generate an error message */ - } - if (ret == TRNSMT_ERROR) { + break; + case TRNSMT_ERROR: /* generate error message */ if (timeout) { - jlog(2, "Timeout in %s line %d\n", __FILE__ - ,__LINE__); + jlog(2, "Timeout while transmiting file"); err_time_readline( conn_info->clntinfo->clientsocket); } else { err_readline(conn_info->clntinfo->serversocket); } - return 1; - } + ret = 1; + break; + case TRNSMT_ANALYZE_ERROR: + sayf(conn_info->clntinfo->clientsocket, "500 Error during transfer\r\n"); + break; + case TRNSMT_VIRUS: + sayf(conn_info->clntinfo->clientsocket, "500 Virus Found in %s\r\n", + conn_info->lcs->filename); + /* ignore response from server */ + buf = readline(conn_info->clntinfo->serversocket); + free(buf); + break; + case TRNSMT_CIPHERED: + sayf(conn_info->clntinfo->clientsocket, "500 Antivirus can't analyse ciphered file %s\r\n", + conn_info->lcs->filename); + /* ignore response from server */ + buf = readline(conn_info->clntinfo->serversocket); + free(buf); + break; + } + } + if (conn_info->clntinfo->av_tmp) { + unlink(conn_info->clntinfo->av_tmp); + conn_info->clntinfo->av_tmp = NULL; } return ret; } @@ -226,6 +270,12 @@ if (conn_info->lcs->respcode != 125 && conn_info->lcs->respcode != 150) { return CMD_ERROR; } + + /* see if we should perform antivirus analyze */ + if (config_get_bool("arkoonantivirus")) { + conn_info->clntinfo->virus_check = 1; + } + if (transfer_initiate(conn_info, 0)) { return CMD_ERROR; } @@ -355,6 +405,7 @@ cache_delete(cfs, 1); } /* say(conn_info->clntinfo->clientsocket, last); */ + if (last) free(last); return CMD_ERROR; } } else { @@ -365,6 +416,11 @@ retrieve_from_cache = 1; } + /* see if we should perform antivirus analyze */ + if (config_get_bool("arkoonantivirus")) { + conn_info->clntinfo->virus_check = 1; + } + /* Okay, everything is fine, establish a connection */ ret = transfer_initiate(conn_info, retrieve_from_cache); @@ -396,6 +452,8 @@ } conn_info->clntinfo->fromcache = 0; conn_info->clntinfo->tocache = 0; + + if (last) free(last); return CMD_HANDLED; }