--- AUTHORS +++ AUTHORS 2000/11/05 21:31:21 @@ -11,7 +11,7 @@ Documentation Marius Tomaschewski - Test environment + Test environment, programming Volker Wiegand General program design and programming --- common/Makefile.in +++ common/Makefile.in 2000/11/05 21:31:21 @@ -46,6 +46,8 @@ COM_LIB= libcommon.a TAGS= @TAGS@ +CTAGS= @CTAGS@ +CTAG_OPTS= @CTAG_OPTS@ COM_SRCS= com-config.c \ com-debug.c \ @@ -71,7 +73,7 @@ all: $(TAGS) $(COM_LIB) tags: $(COM_SRCS) $(COM_HDRS) - ctags -w $(COM_SRCS) $(COM_HDRS) + $(CTAGS) $(CTAG_OPTS) $(COM_SRCS) $(COM_HDRS) @echo "" $(COM_LIB): $(COM_LIB)($(COM_OBJS)) --- common/com-socket.c +++ common/com-socket.c 2000/11/07 17:13:44 @@ -69,12 +69,19 @@ #endif #include +#if defined(HAVE_SYS_FILIO_H) +#include +#endif #include -#include +#if defined(HAVE_NETINET_IN_SYSTM_H) +#include +#endif #include +#include #include #include +#include #if defined(HAVE_SYS_SOCKIO_H) # include @@ -248,7 +255,8 @@ static void socket_accept(void) { - char peer[PEER_LEN]; + char peer[PEER_LEN] = {0}; + char dest[PEER_LEN] = {0}; struct sockaddr_in saddr; int nsock, len; @@ -262,10 +270,16 @@ syslog_error("can't accept client"); return; } - strcpy(peer, inet_ntoa(saddr.sin_addr)); + strncpy(peer, inet_ntoa(saddr.sin_addr), sizeof(peer)-1); + *(peer+sizeof(peer)-1) = 0; + + if( !getsockname(nsock, (struct sockaddr *)&saddr, &len)) { + strncpy(dest, inet_ntoa(saddr.sin_addr), sizeof(dest)-1); + *(dest+sizeof(dest)-1) = 0; + } #if defined(COMPILE_DEBUG) - debug(2, "accepted %d=%s", nsock, peer); + debug(2, "accepted %d=%s wanting to go to %s", nsock, peer, NIL(dest)); #endif #if defined(HAVE_LIBWRAP) @@ -1111,7 +1125,7 @@ break; case 'n': case 'N': - if (getdomainname(tmp, sizeof(tmp)) < 0) + if (getfqdomainname(tmp, sizeof(tmp)) < 0) strcpy(tmp, "[unknown network]"); break; case 't': @@ -1475,6 +1489,174 @@ return (u_int32_t) ntohl(saddr.sin_addr.s_addr); } + +/* ------------------------------------------------------------ ** +** +** Function......: socket_chkladdr +** +** Parameters....: addr ip address to check +** +** Return........: 0 if not found, 1 if found, -1 on error +** +** Purpose.......: Check if IP address in addr is used on +** an local network interface. +** +** ------------------------------------------------------------ */ + +int socket_chkladdr(u_int32_t addr) +{ +/* #if defined(SIOCGIFCONF) */ +#define DEFAULT_IFNUM 512 + struct ifconf ifc; + int ifn = DEFAULT_IFNUM; + int i, sock; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if(-1 == sock) { +#if defined(COMPILE_DEBUG) + debug(2, "can not create socket: %s", NIL(strerror(errno))); +#endif + return -1; + } + +#if defined(SIOCGIFNUM) + if( ioctl(sock, SIOCGIFNUM, (char *) &ifn) < 0) { +#if defined(COMPILE_DEBUG) + debug(2, "ioctl SIOCGIFNUM failed: %s", NIL(strerror(errno))); +#endif + ifn = DEFAULT_IFNUM; /* ignore failure */ + } +#endif /* SIOCGIFNUM */ + + ifc.ifc_len = ifn * sizeof (struct ifreq); + ifc.ifc_buf = malloc(ifc.ifc_len); + if( !ifc.ifc_buf) { +#if defined(COMPILE_DEBUG) + debug(2, "malloc(ifc.ifc_len=%d) failed: %s", + ifc.ifc_len, NIL(strerror(errno))); +#endif + close(sock); + return -1; + } + memset(ifc.ifc_buf, 0, ifc.ifc_len); + + if( ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { +#if defined(COMPILE_DEBUG) + debug(2, "ioctl SIOCGIFCONF failed: %s", NIL(strerror(errno))); +#endif + free(ifc.ifc_buf); + close(sock); + return -1; + } + close(sock); + + for( i=0; iifr_addr; + + i += sizeof( *ifr); + + if(AF_INET != ifr->ifr_addr.sa_family + || INADDR_ANY == sa->sin_addr.s_addr + || INADDR_NONE == sa->sin_addr.s_addr) + continue; + +#if defined(COMPILE_DEBUG) + debug(4, "interface %s has ip-address: %s", + ifr->ifr_name, inet_ntoa(sa->sin_addr)); +#endif + + if( sa->sin_addr.s_addr == addr) { +#if defined(COMPILE_DEBUG) + debug(2, "found local ip addr: %s", + inet_ntoa(sa->sin_addr)); +#endif + free(ifc.ifc_buf); + return 1; + } + } + free(ifc.ifc_buf); + +/* #else */ /* SIOCGIFCONF */ +/* return -1; +#endif +*/ +#if defined(COMPILE_DEBUG) + debug(2, "requested ip addr is not a local one"); +#endif + return 0; +} + +/* ------------------------------------------------------------ ** +** +** Function......: getfqhostname +** +** Parameters....: fqhost buffer to store the host name +** n size of the buffer +** +** Return........: 0 on success, -1 on error +** +** Purpose.......: get the full qualified (resolved) +** host name of the current/local host +** +** ------------------------------------------------------------ */ + +int getfqhostname(char *fqhost, size_t n) +{ + char hname[MAXHOSTNAMELEN]; + struct hostent *hp; + + if( !(n > 0 && fqhost)) + return -1; + + memset(hname, 0, sizeof(hname)); + if( gethostname(hname, sizeof(hname)-1)) + return -1; + *(hname+sizeof(hname)-1) = 0; + + if( !(hp = gethostbyname(hname))) { + return -1; + } + strncpy(fqhost, hp->h_name, n-1); + *(fqhost+n-1) = 0; + + return 0; +} + +/* ------------------------------------------------------------ ** +** +** Function......: getfqdomainname +** +** Parameters....: fqhost buffer to store the domain name +** n size of the buffer +** +** Return........: 0 on success, -1 on error +** +** Purpose.......: get the full qualified (resolved) +** domain name of the current/local host +** +** ------------------------------------------------------------ */ + +int getfqdomainname(char *fqdomain, size_t n) +{ + char hname[MAXHOSTNAMELEN], *p; + + if( !(n > 0 && fqdomain)) + return -1; + + memset(hname, 0, sizeof(hname)); + if(getfqhostname(hname, sizeof(hname))) + return -1; + + p = strchr(hname, (int)'.'); + if(p && *(p+1)) { + strncpy(fqdomain, p+1, n-1); + *(fqdomain+n-1) = 0; + return 0; + } + + return -1; +} /* ------------------------------------------------------------ * $Log: com-socket.c,v $ --- common/com-socket.h +++ common/com-socket.h 2000/11/07 17:14:19 @@ -33,6 +33,19 @@ #define _COM_SOCKET_H_ /* ------------------------------------------------------------ */ +#if !defined(INADDR_NONE) +# if defined(INADDR_BROADCAST) +# define INADDR_NONE INADDR_BROADCAST +# else +# define INADDR_NONE ((uint32_t) 0xffffffffU) +# endif +#endif + +#if !defined(MAXHOSTNAMELEN) +# define MAXHOSTNAMELEN 256 +#endif + +/* ------------------------------------------------------------ */ #define SK_LISTEN 1 /* Kind: listening socket */ #define SK_CONTROL 2 /* Kind: control connection */ @@ -102,7 +115,10 @@ u_int16_t socket_str2port(char *name, u_int16_t dflt); char *socket_addr2str(u_int32_t addr); u_int32_t socket_sck2addr(int sock, int peer, u_int16_t *port); +int socket_chkladdr(u_int32_t addr); +int getfqhostname(char *fqhost, size_t n); +int getfqdomainname(char *fqdomain, size_t n); /* ------------------------------------------------------------ */ --- configure.in +++ configure.in 2000/11/07 21:04:39 @@ -134,11 +134,16 @@ AC_C_INLINE AC_C_CONST -AC_CHECK_PROG(CTAGS, ctags, ctags) +TAGS="" +AC_CHECK_PROG(CTAGS, gnuctags, gnuctags) if test -n "$CTAGS"; then TAGS="tags" + CTAG_OPTS="-w" else - TAGS="" + AC_CHECK_PROG(CTAGS, ctags, ctags) + if test -n "$CTAGS"; then + TAGS="tags" + fi fi @@ -168,6 +173,9 @@ AC_CHECK_HEADERS(fcntl.h) AC_CHECK_HEADERS(sys/fcntl.h) +AC_CHECK_HEADERS(sys/filio.h) +AC_CHECK_HEADERS(netinet/in_systm.h) + AC_HEADER_SYS_WAIT @@ -180,6 +188,7 @@ AC_CHECK_FUNCS(setsid) +dnl AC_CHECK_FUNCS(getdomainname) ############################################################ # check for types to be defined @@ -200,9 +209,10 @@ ############################################################ AC_CHECK_LIB(nsl, gethostent) +dnl AC_CHECK_LIB(resolv, gethostent) +AC_CHECK_LIB(resolv, gethostbyname) AC_CHECK_LIB(socket, connect) - ############################################################ # check whether to enable /proc modules ############################################################ @@ -302,11 +312,11 @@ yes) AC_MSG_RESULT(yes) AC_CHECK_FUNC(regcomp, - AC_DEFINE(HAVE_REGEX), - AC_CHECK_LIB(regex, regcomp, [ - LIB_REGEX="-lregex" - AC_DEFINE(HAVE_REGEX) ] - ) + AC_DEFINE(HAVE_REGEX) + ) + AC_CHECK_LIB(regex, regcomp, [ + LIB_REGEX="-lregex" + AC_DEFINE(HAVE_REGEX) ] ) ;; *) @@ -385,15 +395,21 @@ ;; yes) AC_MSG_RESULT(yes) - AC_CHECK_LIB(ldap, ldap_set_option, [ + AC_CHECK_LIB(ldap, ldap_get_lderrno, [ LIB_LDAP="-lldap" AC_DEFINE(HAVE_LIBLDAP) AC_DEFINE(HAVE_LDAP_NETSCAPE) ], - AC_CHECK_LIB(lber, ber_init, [ - LIB_LDAP="-lldap -llber" + AC_CHECK_LIB(ldap, ber_init, [ + LIB_LDAP="-lldap" AC_DEFINE(HAVE_LIBLDAP) - AC_DEFINE(HAVE_LDAP_UMICH) ] + AC_DEFINE(HAVE_LDAP_UMICH) + ], + AC_CHECK_LIB(lber, ber_init, [ + LIB_LDAP="-lldap -llber" + AC_DEFINE(HAVE_LIBLDAP) + AC_DEFINE(HAVE_LDAP_UMICH) ] + ) ) ) ;; @@ -435,6 +451,7 @@ AC_SUBST(CFLAGS) AC_SUBST(LDFLAGS) AC_SUBST(TAGS) +AC_SUBST(CTAG_OPTS) AC_SUBST(LIB_WRAP) AC_SUBST(LIB_LDAP) AC_SUBST(LIB_REGEX) --- doc/src/ftp-proxy.sgml +++ doc/src/ftp-proxy.sgml 2000/11/05 21:31:21 @@ -656,7 +656,7 @@ ), and

-Marius Tomaschewski (test environment, +Marius Tomaschewski (test environment, programming, ). --- ftp-proxy/Makefile.in +++ ftp-proxy/Makefile.in 2000/11/05 21:31:21 @@ -61,6 +61,8 @@ FTP_MAN8= ftp-proxy.8 TAGS= @TAGS@ +CTAGS= @CTAGS@ +CTAG_OPTS= @CTAG_OPTS@ FTP_SRCS= ftp-client.c \ ftp-cmds.c \ @@ -91,7 +93,7 @@ all: $(TAGS) progs tags: $(FTP_SRCS) $(FTP_HDRS) - ctags -w $(FTP_SRCS) $(FTP_HDRS) ../common/*.[ch] + $(CTAGS) $(CTAG_OPTS) $(FTP_SRCS) $(FTP_HDRS) ../common/*.[ch] @echo "" progs: ftp-proxy $(PROC_FTP) --- ftp-proxy/ftp-cmds.c +++ ftp-proxy/ftp-cmds.c 2000/11/07 22:42:17 @@ -247,11 +247,11 @@ ** Scan the allow list and enable accordingly */ for (p = allow; *p != '\0'; ) { - while (*p != '\0' && isalpha(*p) == 0) + while (*p != '\0' && isalpha((int)*p) == 0) p++; if (*p == '\0') break; - for (q = p, i = 0; isalpha(*q); q++, i++) + for (q = p, i = 0; isalpha((int)*q); q++, i++) ; for (cmd = cmdlist; cmd->name; cmd++) { if (cmd->len != i) @@ -342,7 +342,7 @@ { char *p, *q; CMD *cmd; - int sock; + int sock, len; struct sockaddr_in saddr; u_int16_t lprt; @@ -387,13 +387,66 @@ } /* - ** Check for permission and existence of "magic" - ** destination address and port information + ** Check for permission and existence of "transparent proxy" + ** magic destination address and port from the client socket */ ctx->magic_addr = 0; ctx->magic_port = 0; - if (config_bool(NULL, "AllowMagicUser", 0) != 0 && - (p = strchr(arg, '@')) != NULL) { + len = sizeof(saddr); + memset(&saddr, 0, len); + if (config_bool(NULL, "AllowTransProxy", 0) && + !getsockname(ctx->cli_ctrl->sock, (struct sockaddr *)&saddr, &len)) + { + char dest[PEER_LEN] = {0}; + u_int32_t ip = saddr.sin_addr.s_addr; + int rc; + + strncpy(dest, inet_ntoa(saddr.sin_addr), sizeof(dest)-1); + *(dest+sizeof(dest)-1) = 0; + + /* syslog_write(U_INF, + "checking transparent proxy dest: %s", dest); */ + + if(ip == INADDR_ANY || ip == INADDR_NONE) + { + syslog_write(U_ERR, + "invalid transparent proxy dest: %s", dest); + client_respond(501, NULL, + "Invalid transparent proxy destination: %s", + dest); + return; + } + + rc = socket_chkladdr(ip); + switch( rc) { + case 0: + ctx->magic_addr = ntohl(ip); + ctx->magic_port = ntohs(saddr.sin_port); + syslog_write(U_INF, + "transparent proxy request to %s:%d from %s", + dest, ctx->magic_port, ctx->cli_ctrl->peer); + break; + case -1: + syslog_write(U_ERR, + "check of transparent proxy dest %s failed", + dest); + break; + default: + syslog_write(U_WRN, + "requested transparent proxy dest %s is local", + dest); + break; + } + } + + + /* + ** Check for permission and existence of "magic" + ** destination address and port information + */ + if(config_bool(NULL, "AllowMagicUser", 0) != 0 && + (p = strchr(arg, *config_str(NULL, "UseMagicChar", "@"))) != NULL) + { *p++ = '\0'; if ((q = strchr(p, ':')) != NULL) { *q++ = '\0'; @@ -415,16 +468,20 @@ /* ** Retrieve the relevant user information */ - ctx->username = misc_strdup(FL, arg); if (ctx->magic_addr != INADDR_ANY) { syslog_write(U_INF, "'USER %s' dest %s:%d from %s", arg, socket_addr2str(ctx->magic_addr), (int) ctx->magic_port, ctx->cli_ctrl->peer); + } else if(config_str(NULL, "DestinationAddress", NULL) == NULL) { + syslog_write(U_ERR, "Unknown destination address"); + client_respond(501, NULL,"Unknown destination address"); + return; } else { syslog_write(U_INF, "'USER %s' from %s", arg, ctx->cli_ctrl->peer); } + ctx->username = misc_strdup(FL, arg); ldap_setup_user(ctx); /* @@ -1087,7 +1144,7 @@ str[i++] = *ptr; continue; } - if (isxdigit(ptr[1]) && isxdigit(ptr[2])) { + if (isxdigit((int)ptr[1]) && isxdigit((int)ptr[2])) { sprintf(tmp, "%.2s", ptr + 1); sscanf(tmp, "%x", &c); str[i++] = (char) c; --- ftp-proxy/ftp-ldap.c +++ ftp-proxy/ftp-ldap.c 2000/11/07 22:28:31 @@ -88,7 +88,16 @@ #if defined(HAVE_LIBLDAP) # if defined(HAVE_LDAP_UMICH) -# define GET_LDERROR(ld) (ld)->ld_errno +# if defined __sun__ + /* + * there is only a forward definition of the LDAP + * connection handle struct in ldap.h on Solaris7, + * so we have no access to ld_errno. + */ +# define GET_LDERROR(ld) LDAP_OTHER +# else +# define GET_LDERROR(ld) (ld)->ld_errno +# endif # else # define GET_LDERROR(ld) ldap_get_lderrno((ld), NULL, NULL) # endif --- ftp-proxy/ftp-main.c +++ ftp-proxy/ftp-main.c 2000/11/05 21:31:21 @@ -248,11 +248,14 @@ /* ** Complain if no default DestinationAddress is given + ** while the AllowTransProxy feature is disabled. */ - if (config_str(NULL, "DestinationAddress", NULL) == NULL) { - syslog_error("can't run without default DestAddr"); - fprintf(stderr, "can't run without default DestAddr"); - exit(EXIT_FAILURE); + if (config_bool(NULL, "AllowTransProxy", 0) == 0) { + if (config_str(NULL, "DestinationAddress", NULL) == NULL) { + syslog_error("can't run without default DestAddr"); + fprintf(stderr, "can't run without default DestAddr"); + exit(EXIT_FAILURE); + } } /* --- ftp-proxy/ftp-proxy.conf.5.in +++ ftp-proxy/ftp-proxy.conf.5.in 2000/11/07 23:07:29 @@ -108,6 +108,14 @@ See also .B ActiveMaxDataPort. .TP +.B UseMagicChar +Global context only. Defines the character to use as separator +between user and host[:port] in the target setting of +.B AllowMagicUser +Default is the '@' character. This allows you to use E-Mail +addresses as usernames for login to the ftp server +(i.e. me@mydomain%ftp.server:21 if you set it to %). +.TP .B AllowMagicUser Global context only. Defines a flag that when set to .B yes, true, @@ -123,6 +131,19 @@ .B DestinationPort directive below. It should only be activated with "trusted" users, like in an outgoing FTP proxy scenario. +.TP +.B AllowTransProxy +Global context only. Defines a flag that when set to +.B yes, true, +or +.B on +allows to use the proxy as transparent proxy for outgoing ftp. +To get it working you also have to redirect client requests on +a gateway or firewall host (i.e. via ipchains) to the ftp-proxy. +It should only be activated with "trusted" users, like in an +outgoing FTP proxy scenario. You can combine this with the +.B AllowMagicUser +flag. .TP .B DenyMessage Global context only. Defines the name of a file which prevents --- ftp-proxy/ftp-proxy.conf.sample +++ ftp-proxy/ftp-proxy.conf.sample 2000/11/07 23:08:40 @@ -37,6 +37,14 @@ # ActiveMinDataPort 40000 # ActiveMaxDataPort 40999 +# Defines the character to use as separator between user +# and host[:port] in the target setting of AllowMagicUser +# Default is the '@' character. This allows you to use +# E-Mail addresses as usernames for login to the ftp server +# (i.e. me@mydomain%ftp.server:21 if you set it to %). +# +# UseMagicChar % + # The follwing flag is especially useful for outbound FTP # traffic. It allows to put some "magic" in the USER name. # If set, it enables the USER name to contain the target @@ -44,6 +52,14 @@ # the DestinationAddress (and DestinationPort) below. # # AllowMagicUser no + +# The follwing setting allows you to configure a so called +# transparent proxy for outgoing ftp. To get it working you +# also have to redirect client requests on a gateway or +# firewall host (i.e. via ipchains) to the ftp-proxy. +# You can combine this with the AllowMagicUser flag. +# +# AllowTransProxy no # This message prevents any login if a file with the given # name exists. Instead the contents of the file will be sent