If PARANOID is set, do not allow PORT commands to remote ports less than 1024
or addresses other than the requestor's address. This violates the FTP protocol (hmm...as I write this, I'm going to change this to a run-time var.) Require login before PASV and RNTO commands. Close unused PASV ports so they don't hang around forever. Do not allow file overwrites via rename or STOR when anonymous (suspenders). Clean up buffer utilization. My code, but heavily inspired by Hobbit's changes to wu-ftpd as pointed out by Mike Prettejohn and Kit Knox.
This commit is contained in:
parent
7b2dfbf801
commit
61f891a6df
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=17433
@ -4,7 +4,7 @@ PROG= ftpd
|
||||
MAN8= ftpd.8
|
||||
SRCS= ftpd.c ftpcmd.c logwtmp.c popen.c skey-stuff.c
|
||||
|
||||
CFLAGS+=-DSETPROCTITLE -DSKEY -DSTATS
|
||||
CFLAGS+=-DSETPROCTITLE -DSKEY -DSTATS -DPARANOID
|
||||
|
||||
LDADD= -lskey -lmd -lcrypt -lutil
|
||||
DPADD= ${LIBSKEY} ${LIBMD} ${LIBCRYPT} ${LIBUTIL}
|
||||
|
@ -65,3 +65,7 @@ void store __P((char *, char *, int));
|
||||
void upper __P((char *));
|
||||
void user __P((char *));
|
||||
void yyerror __P((char *));
|
||||
int yyparse __P((void));
|
||||
#if defined(SKEY) && defined(_PWD_H_) /* XXX evil */
|
||||
char *skey_challenge __P((char *, struct passwd *, int));
|
||||
#endif
|
||||
|
@ -67,7 +67,7 @@ static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94";
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
extern struct sockaddr_in data_dest;
|
||||
extern struct sockaddr_in data_dest, his_addr;
|
||||
extern int logged_in;
|
||||
extern struct passwd *pw;
|
||||
extern int guest;
|
||||
@ -149,18 +149,35 @@ cmd
|
||||
pass($3);
|
||||
free($3);
|
||||
}
|
||||
| PORT SP host_port CRLF
|
||||
| PORT check_login SP host_port CRLF
|
||||
{
|
||||
usedefault = 0;
|
||||
if (pdata >= 0) {
|
||||
(void) close(pdata);
|
||||
pdata = -1;
|
||||
if ($2) {
|
||||
#ifdef PARANOID
|
||||
if ((ntohs(data_dest.sin_port) <
|
||||
IPPORT_RESERVED) ||
|
||||
memcmp(&data_dest.sin_addr,
|
||||
&his_addr.sin_addr,
|
||||
sizeof(data_dest.sin_addr)))
|
||||
{
|
||||
usedefault = 1;
|
||||
reply(500,
|
||||
"Illegal PORT range rejected.");
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
usedefault = 0;
|
||||
if (pdata >= 0) {
|
||||
(void) close(pdata);
|
||||
pdata = -1;
|
||||
}
|
||||
reply(200, "PORT command successful.");
|
||||
}
|
||||
}
|
||||
reply(200, "PORT command successful.");
|
||||
}
|
||||
| PASV CRLF
|
||||
| PASV check_login CRLF
|
||||
{
|
||||
passive();
|
||||
if ($2)
|
||||
passive();
|
||||
}
|
||||
| TYPE SP type_code CRLF
|
||||
{
|
||||
@ -292,16 +309,18 @@ cmd
|
||||
if ($4 != NULL)
|
||||
free($4);
|
||||
}
|
||||
| RNTO SP pathname CRLF
|
||||
| RNTO check_login SP pathname CRLF
|
||||
{
|
||||
if (fromname) {
|
||||
renamecmd(fromname, $3);
|
||||
free(fromname);
|
||||
fromname = (char *) 0;
|
||||
} else {
|
||||
reply(503, "Bad sequence of commands.");
|
||||
if ($2) {
|
||||
if (fromname) {
|
||||
renamecmd(fromname, $4);
|
||||
free(fromname);
|
||||
fromname = (char *) 0;
|
||||
} else {
|
||||
reply(503, "Bad sequence of commands.");
|
||||
}
|
||||
}
|
||||
free($3);
|
||||
free($4);
|
||||
}
|
||||
| ABOR CRLF
|
||||
{
|
||||
|
@ -30,7 +30,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ftpd.c,v 1.16 1996/04/11 10:22:16 davidg Exp $
|
||||
* $Id: ftpd.c,v 1.17 1996/05/31 03:10:25 peter Exp $
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
@ -202,6 +202,9 @@ static struct passwd *
|
||||
sgetpwnam __P((char *));
|
||||
static char *sgetsave __P((char *));
|
||||
static void reapchild __P((int));
|
||||
#ifdef STATS
|
||||
static void logxfer __P((char *, long, long));
|
||||
#endif
|
||||
|
||||
static char *
|
||||
curdir()
|
||||
@ -380,7 +383,7 @@ main(argc, argv, envp)
|
||||
syslog(LOG_ERR, "signal: %m");
|
||||
|
||||
#ifdef SKEY
|
||||
strcpy(addr_string, inet_ntoa(his_addr.sin_addr));
|
||||
strncpy(addr_string, inet_ntoa(his_addr.sin_addr), sizeof(addr_string));
|
||||
#endif
|
||||
addrlen = sizeof(ctrl_addr);
|
||||
if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
|
||||
@ -739,7 +742,10 @@ pass(passwd)
|
||||
|
||||
if (ident != NULL)
|
||||
free(ident);
|
||||
ident = (char *) copy(passwd);
|
||||
ident = strdup(passwd);
|
||||
if (ident == NULL)
|
||||
fatal("Ran out of memory.");
|
||||
|
||||
#endif
|
||||
reply(230, "Guest login ok, access restrictions apply.");
|
||||
#ifdef SETPROCTITLE
|
||||
@ -836,7 +842,7 @@ retrieve(cmd, name)
|
||||
restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode));
|
||||
#ifdef STATS
|
||||
if (cmd == 0 && guest && stats)
|
||||
logxfer( name, st.st_size, start);
|
||||
logxfer(name, st.st_size, start);
|
||||
#endif
|
||||
(void) fclose(dout);
|
||||
data = -1;
|
||||
@ -856,7 +862,7 @@ store(name, mode, unique)
|
||||
struct stat st;
|
||||
int (*closefunc) __P((FILE *));
|
||||
|
||||
if (unique && stat(name, &st) == 0 &&
|
||||
if ((unique || guest) && stat(name, &st) == 0 &&
|
||||
(name = gunique(name)) == NULL) {
|
||||
LOGCMD(*mode == 'w' ? "put" : "append", name);
|
||||
return;
|
||||
@ -1181,7 +1187,7 @@ receive_data(instr, outstr)
|
||||
FILE *instr, *outstr;
|
||||
{
|
||||
int c;
|
||||
int cnt, bare_lfs = 0;
|
||||
int cnt, bare_lfs;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
transflag++;
|
||||
@ -1189,6 +1195,9 @@ receive_data(instr, outstr)
|
||||
transflag = 0;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
bare_lfs = 0;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case TYPE_I:
|
||||
@ -1521,8 +1530,15 @@ void
|
||||
renamecmd(from, to)
|
||||
char *from, *to;
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
LOGCMD2("rename", from, to);
|
||||
|
||||
if (guest && (stat(to, &st) == 0)) {
|
||||
reply(550, "%s: permission denied", to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rename(from, to) < 0)
|
||||
perror_reply(550, "rename");
|
||||
else
|
||||
@ -1607,35 +1623,31 @@ void
|
||||
passive()
|
||||
{
|
||||
int len, on;
|
||||
u_short port;
|
||||
char *p, *a;
|
||||
|
||||
if (pw == NULL) {
|
||||
reply(530, "Please login with USER and PASS");
|
||||
return;
|
||||
}
|
||||
if (pdata >= 0) /* close old port if one set */
|
||||
close(pdata);
|
||||
|
||||
pdata = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (pdata < 0) {
|
||||
perror_reply(425, "Can't open passive connection");
|
||||
return;
|
||||
}
|
||||
|
||||
on = restricted_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
|
||||
(void) seteuid((uid_t)0);
|
||||
|
||||
on = restricted_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
|
||||
if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
|
||||
(char *)&on, sizeof(on)) < 0) {
|
||||
(void) seteuid((uid_t)pw->pw_uid);
|
||||
goto pasv_error;
|
||||
}
|
||||
|
||||
pasv_addr = ctrl_addr;
|
||||
pasv_addr.sin_port = 0;
|
||||
(void) seteuid((uid_t)0);
|
||||
if (bind(pdata, (struct sockaddr *)&pasv_addr,
|
||||
sizeof(pasv_addr)) < 0) {
|
||||
(void) seteuid((uid_t)pw->pw_uid);
|
||||
sizeof(pasv_addr)) < 0)
|
||||
goto pasv_error;
|
||||
}
|
||||
|
||||
(void) seteuid((uid_t)pw->pw_uid);
|
||||
|
||||
len = sizeof(pasv_addr);
|
||||
@ -1653,6 +1665,7 @@ passive()
|
||||
return;
|
||||
|
||||
pasv_error:
|
||||
(void) seteuid((uid_t)pw->pw_uid);
|
||||
(void) close(pdata);
|
||||
pdata = -1;
|
||||
perror_reply(425, "Can't open passive connection");
|
||||
@ -1682,7 +1695,7 @@ gunique(local)
|
||||
}
|
||||
if (cp)
|
||||
*cp = '/';
|
||||
(void) strcpy(new, local);
|
||||
(void) snprintf(new, sizeof(new), "%s", local);
|
||||
cp = new + strlen(new);
|
||||
*cp++ = '.';
|
||||
for (count = 1; count < 100; count++) {
|
||||
@ -1894,6 +1907,7 @@ setproctitle(fmt, va_alist)
|
||||
#endif /* OLD_SETPROCTITLE */
|
||||
|
||||
#ifdef STATS
|
||||
static void
|
||||
logxfer(name, size, start)
|
||||
char *name;
|
||||
long size;
|
||||
@ -1905,23 +1919,10 @@ logxfer(name, size, start)
|
||||
|
||||
if (statfd >= 0 && getwd(path) != NULL) {
|
||||
time(&now);
|
||||
sprintf(buf, "%.20s!%s!%s!%s/%s!%ld!%ld\n",
|
||||
snprintf(buf, sizeof(buf), "%.20s!%s!%s!%s/%s!%ld!%ld\n",
|
||||
ctime(&now)+4, ident, remotehost,
|
||||
path, name, size, now - start + (now == start));
|
||||
write(statfd, buf, strlen(buf));
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
copy(s)
|
||||
char *s;
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = malloc((unsigned) strlen(s) + 1);
|
||||
if (p == NULL)
|
||||
fatal("Ran out of memory.");
|
||||
(void) strcpy(p, s);
|
||||
return (p);
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user