diff -uNr linux-ftpd-0.17/ftpd/ftpd.c linux-ftpd-0.17.acme/ftpd/ftpd.c --- linux-ftpd-0.17/ftpd/ftpd.c Sun Jul 23 00:34:56 2000 +++ linux-ftpd-0.17.acme/ftpd/ftpd.c Sun Dec 2 03:07:07 2001 @@ -93,6 +93,10 @@ #include #include #else +#define AF_LLC 26 +#include +#include +#include #include /* for initgroups() */ /* #include * for L_SET et al. * <--- not used? */ /*typedef int64_t quad_t;*/ @@ -140,11 +144,17 @@ extern char cbuf[]; struct sockaddr_in server_addr; -struct sockaddr_in ctrl_addr; -struct sockaddr_in data_source; +static struct { + int addrlen; + union { + struct sockaddr sa; + struct sockaddr_in inet; + struct sockaddr_llc llc; + } addr; +} pasv_addr, ctrl_addr; struct sockaddr_in data_dest; struct sockaddr_in his_addr; -struct sockaddr_in pasv_addr; +struct sockaddr_in data_source; int daemon_mode = 0; int data; @@ -262,6 +272,18 @@ void logxfer __P((const char *, off_t, time_t)); +static int get_hwaddr(int skfd, char* ifname, unsigned char* dest) +{ + struct ifreq ifr; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) + memset(dest, 0, IFHWADDRLEN); + else + memcpy(dest, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN); +} + + #ifdef __linux__ static void warnx(const char *format, ...) { @@ -294,9 +316,11 @@ socklen_t addrlen; char *cp, line[LINE_MAX]; FILE *fd; - const char *argstr = "AdDhlMSt:T:u:UvP"; + const char *argstr = "AdDhlLMSt:T:u:UvP"; struct hostent *hp; + pasv_addr.addr.sa.sa_family = ctrl_addr.addr.sa.sa_family = AF_INET; + pasv_addr.addrlen = ctrl_addr.addrlen = sizeof(struct sockaddr_in); #ifdef __linux__ initsetproctitle(argc, argv, envp); srandom(time(NULL)^(getpid()<<8)); @@ -350,6 +374,12 @@ logging++; /* > 1 == extra logging */ break; + case 'L': + ctrl_addr.addr.sa.sa_family = + pasv_addr.addr.sa.sa_family = AF_LLC; + ctrl_addr.addrlen = + pasv_addr.addrlen = sizeof(struct sockaddr_llc); + break; case 'M': multihome = 1; break; @@ -492,8 +522,8 @@ if (signal(SIGURG, myoob) == SIG_ERR) syslog(LOG_ERR, "signal: %m"); - addrlen = sizeof(ctrl_addr); - if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { + addrlen = ctrl_addr.addrlen; + if (getsockname(0, (struct sockaddr *)&ctrl_addr.addr, &addrlen) < 0) { syslog(LOG_ERR, "getsockname (%s): %m", argv[0]); exit(1); } @@ -502,7 +532,7 @@ if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); #endif - data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); + data_source.sin_port = htons(ntohs(ctrl_addr.addr.inet.sin_port) - 1); /* Try to handle urgent data inline */ #ifdef SO_OOBINLINE @@ -555,13 +585,14 @@ strcpy(hostname, hp->h_name); if (multihome) { - hp = gethostbyaddr((char *) &ctrl_addr.sin_addr, + hp = gethostbyaddr((char *) &ctrl_addr.addr.inet.sin_addr, sizeof (struct in_addr), AF_INET); if (hp != NULL) { strcpy(dhostname, hp->h_name); } else { /* Default. */ - strcpy(dhostname, inet_ntoa(ctrl_addr.sin_addr)); + strcpy(dhostname, + inet_ntoa(ctrl_addr.addr.inet.sin_addr)); } } @@ -1178,7 +1209,7 @@ data_source.sin_len = sizeof(struct sockaddr_in); #endif data_source.sin_family = AF_INET; - data_source.sin_addr = ctrl_addr.sin_addr; + data_source.sin_addr = ctrl_addr.addr.inet.sin_addr; for (tries = 1; ; tries++) { if (bind(s, (struct sockaddr *)&data_source, sizeof(data_source)) >= 0) @@ -1241,7 +1272,7 @@ } else sizebuf[0] = '\0'; if (pdata >= 0) { - struct sockaddr_in from; + struct sockaddr_llc from; int s; socklen_t fromlen = sizeof(from); @@ -1255,6 +1286,7 @@ pdata = -1; return (NULL); } +#if 0 if (ntohs(from.sin_port) < IPPORT_RESERVED) { perror_reply(425, "Can't build data connection"); (void) close(pdata); @@ -1269,6 +1301,7 @@ pdata = -1; return (NULL); } +#endif (void) close(pdata); pdata = s; #ifdef IP_TOS @@ -1304,13 +1337,13 @@ */ if (ntohs(data_dest.sin_port) < IPPORT_RESERVED || ntohs(data_dest.sin_port) == 2049) { /* XXX */ - perror_reply(425, "Can't build data connection"); + perror_reply(425, "Can't build data connection 1"); (void) fclose(file); data = -1; return NULL; } if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) { - perror_reply(435, "Can't build data connection"); + perror_reply(435, "Can't build data connection 2"); (void) fclose(file); data = -1; return NULL; @@ -1322,7 +1355,7 @@ retry += swaitint; continue; } - perror_reply(425, "Can't build data connection"); + perror_reply(425, "Can't build data connection 3"); (void) fclose(file); data = -1; return (NULL); @@ -1343,6 +1376,7 @@ int c, cnt, filefd, netfd; char *buf, *bp; size_t len,size; + int error; transflag++; if (setjmp(urgcatch)) { @@ -1355,9 +1389,12 @@ while ((c = getc(instr)) != EOF) { byte_count++; if (c == '\n') { - if (ferror(outstr)) + if (ferror(outstr)) { + error = 111; goto data_err; + } (void) putc('\r', outstr); + fflush(outstr); } (void) putc(c, outstr); } @@ -1365,8 +1402,10 @@ transflag = 0; if (ferror(instr)) goto file_err; - if (ferror(outstr)) + if (ferror(outstr)) { + error = 222; goto data_err; + } reply(226, "Transfer complete."); return; @@ -1390,7 +1429,7 @@ bp = buf; len = filesize; do { - cnt = write(netfd, bp, len); + cnt = write(netfd, bp, 1400); len -= cnt; bp += cnt; if (cnt > 0) byte_count += cnt; @@ -1398,14 +1437,19 @@ transflag = 0; munmap(buf, (size_t)filesize); - if (cnt < 0) + if (cnt < 0) { + error = cnt; goto data_err; + } reply(226, "Transfer complete."); return; } oldway: - size = blksize * 16; + if (pasv_addr.addr.sa.sa_family == AF_LLC) + size = 1400; + else + size = blksize * 16; if ((buf = malloc(size)) == NULL) { transflag = 0; @@ -1434,6 +1478,7 @@ if (cnt != 0) { if (cnt < 0) goto file_err; + error = 444; goto data_err; } reply(226, "Transfer complete."); @@ -1446,7 +1491,7 @@ data_err: transflag = 0; - perror_reply(426, "Data connection"); + reply(426, "Data Connection %d %s", error, strerror(errno)); return; file_err: @@ -1462,7 +1507,7 @@ */ static int receive_data(FILE *instr, FILE *outstr) { - int c; + int c, error = 0; int cnt; volatile int bare_lfs = 0; char buf[BUFSIZ]; @@ -1480,7 +1525,7 @@ do { (void) alarm ((unsigned) timeout); - cnt = read(fileno(instr), buf, sizeof(buf)); + cnt = read(fileno(instr), buf, 1400); (void) alarm (0); if (cnt > 0) { @@ -1489,8 +1534,10 @@ byte_count += cnt; } } while (cnt > 0); - if (cnt < 0) + if (cnt < 0) { + error = 11; goto data_err; + } transflag = 0; return (0); @@ -1505,8 +1552,10 @@ if (c == '\n') bare_lfs++; while (c == '\r') { - if (ferror(outstr)) + if (ferror(outstr)) { + error = 22; goto data_err; + } if ((c = getc(instr)) != '\n') { (void) putc ('\r', outstr); if (c == '\0' || c == EOF) @@ -1517,8 +1566,10 @@ contin2: ; } fflush(outstr); - if (ferror(instr)) + if (ferror(instr)) { + error = 33; goto data_err; + } if (ferror(outstr)) goto file_err; transflag = 0; @@ -1537,7 +1588,7 @@ data_err: transflag = 0; - perror_reply(426, "Data Connection"); + reply(426, "Data Connection %d %s", error, strerror(errno)); return (-1); file_err: @@ -1611,7 +1662,7 @@ printf(" Data connection open\r\n"); else if (pdata != -1) { printf(" in Passive mode"); - sn = &pasv_addr; + sn = &pasv_addr.addr; goto printaddr; } else if (usedefault == 0) { printf(" PORT"); @@ -1922,7 +1973,7 @@ } if (pdata >= 0) close(pdata); - pdata = socket(AF_INET, SOCK_STREAM, 0); + pdata = socket(pasv_addr.addr.sa.sa_family, SOCK_STREAM, 0); if (pdata < 0) { perror_reply(425, "Can't open passive connection"); return; @@ -1938,10 +1989,10 @@ #define FTP_DATA_TOP 44999 if (high_data_ports) { for (port = FTP_DATA_BOTTOM; port <= FTP_DATA_TOP; port++) { - pasv_addr = ctrl_addr; - pasv_addr.sin_port = htons(port); - if (bind(pdata, (struct sockaddr *) &pasv_addr, - sizeof(pasv_addr)) == 0) + pasv_addr.addr = ctrl_addr.addr; + pasv_addr.addr.inet.sin_port = htons(port); + if (bind(pdata, (struct sockaddr *) &pasv_addr.addr, + pasv_addr.addrlen) == 0) break; if (errno != EADDRINUSE) goto pasv_error; @@ -1952,20 +2003,29 @@ else #endif { - pasv_addr = ctrl_addr; - pasv_addr.sin_port = 0; - if (bind(pdata, (struct sockaddr *)&pasv_addr, - sizeof(pasv_addr)) < 0) + pasv_addr.addr = ctrl_addr.addr; + if (pasv_addr.addr.sa.sa_family == AF_INET) + pasv_addr.addr.inet.sin_port = 0; + else if (pasv_addr.addr.sa.sa_family == AF_LLC) { + memset(&pasv_addr.addr.llc, 0, + sizeof(pasv_addr.addr.llc)); + pasv_addr.addr.sa.sa_family = AF_LLC; + pasv_addr.addr.llc.sllc_arphrd = ARPHRD_ETHER; + get_hwaddr(pdata, "eth0", pasv_addr.addr.llc.sllc_smac); + pasv_addr.addr.llc.sllc_ssap = 92; + } + if (bind(pdata, (struct sockaddr *)&pasv_addr.addr, + pasv_addr.addrlen) < 0) goto pasv_error; } - len = sizeof(pasv_addr); - if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) + len = pasv_addr.addrlen; + if (getsockname(pdata, (struct sockaddr *) &pasv_addr.addr, &len) < 0) goto pasv_error; if (listen(pdata, 1) < 0) goto pasv_error; - a = (char *) &pasv_addr.sin_addr; - p = (char *) &pasv_addr.sin_port; + a = (char *) &pasv_addr.addr.inet.sin_addr; + p = (char *) &pasv_addr.addr.inet.sin_port; #define UC(b) (((int) b) & 0xff)