summaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
authorKris Kennaway <kris@FreeBSD.org>2001-03-05 11:14:50 +0000
committerKris Kennaway <kris@FreeBSD.org>2001-03-05 11:14:50 +0000
commit231e5a377dd9d63f7ca3efc4a3a96b71c6463bcb (patch)
tree3e61dfe60aa30c2537dbb63c52bc9ea30a7816be /libexec
parentd94b7beaf91d9e8c99c40caff1e4793869c72389 (diff)
downloadsrc-test2-231e5a377dd9d63f7ca3efc4a3a96b71c6463bcb.tar.gz
src-test2-231e5a377dd9d63f7ca3efc4a3a96b71c6463bcb.zip
Notes
Diffstat (limited to 'libexec')
-rw-r--r--libexec/ftpd/ftpcmd.y78
-rw-r--r--libexec/ftpd/ftpd.861
-rw-r--r--libexec/ftpd/ftpd.c90
3 files changed, 162 insertions, 67 deletions
diff --git a/libexec/ftpd/ftpcmd.y b/libexec/ftpd/ftpcmd.y
index 6da9f218e4a5..14ac1220a33a 100644
--- a/libexec/ftpd/ftpcmd.y
+++ b/libexec/ftpd/ftpcmd.y
@@ -90,6 +90,8 @@ extern char proctitle[];
extern int usedefault;
extern int transflag;
extern char tmpline[];
+extern int readonly;
+extern int noepsv;
off_t restart_point;
@@ -132,6 +134,8 @@ extern int epsvall;
%token <i> NUMBER
%type <i> check_login octal_number byte_size
+%type <i> check_login_ro octal_number byte_size
+%type <i> check_login_epsv octal_number byte_size
%type <i> struct_code mode_code type_code form_code
%type <s> pathstring pathname password username ext_arg
%type <s> ALL
@@ -318,7 +322,7 @@ cmd
else if ($2)
long_passive("LPSV", PF_UNSPEC);
}
- | EPSV check_login SP NUMBER CRLF
+ | EPSV check_login_epsv SP NUMBER CRLF
{
if ($2) {
int pf;
@@ -338,7 +342,7 @@ cmd
long_passive("EPSV", pf);
}
}
- | EPSV check_login SP ALL CRLF
+ | EPSV check_login_epsv SP ALL CRLF
{
if ($2) {
reply(200,
@@ -346,7 +350,7 @@ cmd
epsvall++;
}
}
- | EPSV check_login CRLF
+ | EPSV check_login_epsv CRLF
{
if ($2)
long_passive("EPSV", PF_UNSPEC);
@@ -435,14 +439,14 @@ cmd
if ($4 != NULL)
free($4);
}
- | STOR check_login SP pathname CRLF
+ | STOR check_login_ro SP pathname CRLF
{
if ($2 && $4 != NULL)
store($4, "w", 0);
if ($4 != NULL)
free($4);
}
- | APPE check_login SP pathname CRLF
+ | APPE check_login_ro SP pathname CRLF
{
if ($2 && $4 != NULL)
store($4, "a", 0);
@@ -486,14 +490,14 @@ cmd
statcmd();
}
}
- | DELE check_login SP pathname CRLF
+ | DELE check_login_ro SP pathname CRLF
{
if ($2 && $4 != NULL)
delete($4);
if ($4 != NULL)
free($4);
}
- | RNTO check_login SP pathname CRLF
+ | RNTO check_login_ro SP pathname CRLF
{
if ($2) {
if (fromname) {
@@ -513,8 +517,12 @@ cmd
}
| CWD check_login CRLF
{
- if ($2)
- cwd(pw->pw_dir);
+ if ($2) {
+ if (guest)
+ cwd("/");
+ else
+ cwd(pw->pw_dir);
+ }
}
| CWD check_login SP pathname CRLF
{
@@ -546,14 +554,14 @@ cmd
{
reply(200, "NOOP command successful.");
}
- | MKD check_login SP pathname CRLF
+ | MKD check_login_ro SP pathname CRLF
{
if ($2 && $4 != NULL)
makedir($4);
if ($4 != NULL)
free($4);
}
- | RMD check_login SP pathname CRLF
+ | RMD check_login_ro SP pathname CRLF
{
if ($2 && $4 != NULL)
removedir($4);
@@ -603,7 +611,7 @@ cmd
}
}
}
- | SITE SP CHMOD check_login SP octal_number SP pathname CRLF
+ | SITE SP CHMOD check_login_ro SP octal_number SP pathname CRLF
{
if ($4 && ($8 != NULL)) {
if ($6 > 0777)
@@ -640,7 +648,7 @@ cmd
}
}
}
- | STOU check_login SP pathname CRLF
+ | STOU check_login_ro SP pathname CRLF
{
if ($2 && $4 != NULL)
store($4, "w", 1);
@@ -719,7 +727,7 @@ cmd
}
;
rcmd
- : RNFR check_login SP pathname CRLF
+ : RNFR check_login_ro SP pathname CRLF
{
char *renamefrom();
@@ -970,12 +978,31 @@ octal_number
check_login
: /* empty */
{
- if (logged_in)
- $$ = 1;
- else {
- reply(530, "Please login with USER and PASS.");
- $$ = 0;
- }
+ $$ = check_login1();
+ }
+ ;
+
+check_login_epsv
+ : /* empty */
+ {
+ if (noepsv) {
+ reply(500, "EPSV command disabled");
+ $$ = 0;
+ }
+ else
+ $$ = check_login1();
+ }
+ ;
+
+check_login_ro
+ : /* empty */
+ {
+ if (readonly) {
+ reply(550, "Permission denied.");
+ $$ = 0;
+ }
+ else
+ $$ = check_login1();
}
;
@@ -1574,6 +1601,17 @@ port_check(pcmd)
return 0;
}
+static int
+check_login1()
+{
+ if (logged_in)
+ return 1;
+ else {
+ reply(530, "Please login with USER and PASS.");
+ return 0;
+ }
+}
+
#ifdef INET6
/* Return 1, if port check is done. Return 0, if not yet. */
static int
diff --git a/libexec/ftpd/ftpd.8 b/libexec/ftpd/ftpd.8
index f836d70c24d5..5d6e345dcb36 100644
--- a/libexec/ftpd/ftpd.8
+++ b/libexec/ftpd/ftpd.8
@@ -50,6 +50,8 @@ Internet File Transfer Protocol server
.Op Fl R
.Op Fl S
.Op Fl U
+.Op Fl r
+.Op Fl E
.Op Fl T Ar maxtimeout
.Op Fl t Ar timeout
.Op Fl a Ar address
@@ -86,8 +88,8 @@ configuration file.
With this option set,
.Nm
will detach and become a daemon, accepting connections on the FTP port and
-forking children processes to handle them. This is lower overhead than
-starting
+forking children processes to handle them.
+This is lower overhead than starting
.Nm
from
.Xr inetd 8
@@ -153,6 +155,12 @@ When
is not specified, accept IPv4 connection via AF_INET socket.
.It Fl A
Allow only anonymous ftp access.
+.It Fl r
+Put server in read-only mode.
+All commands which may modify the local filesystem are disabled.
+.It Fl E
+Disable the EPSV command.
+This is useful for servers behind older firewalls.
.El
.Pp
The file
@@ -178,20 +186,27 @@ relative to the login environment. This means the one in
in the anonymous user's case.
.Pp
The ftp server currently supports the following ftp requests.
-The case of the requests is ignored.
+The case of the requests is ignored. Requests marked [RW] are
+disabled if
+.Fl r
+is specified.
.Bl -column "Request" -offset indent
.It Sy Request Ta Sy "Description"
.It ABOR Ta "abort previous command"
.It ACCT Ta "specify account (ignored)"
.It ALLO Ta "allocate storage (vacuously)"
-.It APPE Ta "append to a file"
+.It APPE Ta "append to a file [RW]"
.It CDUP Ta "change to parent of current working directory"
.It CWD Ta "change working directory"
-.It DELE Ta "delete a file"
+.It DELE Ta "delete a file [RW]"
+.It EPRT Ta "specify data connection port, multiprotocol"
+.It EPSV Ta "prepare for server-to-server transfer, multiprotocol"
.It HELP Ta "give help information"
.It LIST Ta "give list files in a directory" Pq Dq Li "ls -lgA"
-.It MKD Ta "make a directory"
+.It LPRT Ta "specify data connection port, multiprotocol"
+.It LPSV Ta "prepare for server-to-server transfer, multiprotocol"
.It MDTM Ta "show last modification time of file"
+.It MKD Ta "make a directory [RW]"
.It MODE Ta "specify data transfer" Em mode
.It NLST Ta "give name list of files in directory"
.It NOOP Ta "do nothing"
@@ -202,27 +217,23 @@ The case of the requests is ignored.
.It QUIT Ta "terminate session"
.It REST Ta "restart incomplete transfer"
.It RETR Ta "retrieve a file"
-.It RMD Ta "remove a directory"
-.It RNFR Ta "specify rename-from file name"
-.It RNTO Ta "specify rename-to file name"
+.It RMD Ta "remove a directory [RW]"
+.It RNFR Ta "specify rename-from file name [RW]"
+.It RNTO Ta "specify rename-to file name [RW]"
.It SITE Ta "non-standard commands (see next section)"
.It SIZE Ta "return size of file"
.It STAT Ta "return status of server"
-.It STOR Ta "store a file"
-.It STOU Ta "store a file with a unique name"
+.It STOR Ta "store a file [RW]"
+.It STOU Ta "store a file with a unique name [RW]"
.It STRU Ta "specify data transfer" Em structure
.It SYST Ta "show operating system type of server system"
.It TYPE Ta "specify data transfer" Em type
.It USER Ta "specify user name"
.It XCUP Ta "change to parent of current working directory (deprecated)"
.It XCWD Ta "change working directory (deprecated)"
-.It XMKD Ta "make a directory (deprecated)"
+.It XMKD Ta "make a directory (deprecated) [RW]"
.It XPWD Ta "print the current working directory (deprecated)"
-.It XRMD Ta "remove a directory (deprecated)"
-.It LPSV Ta "prepare for server-to-server transfer, multiprotocol"
-.It LPRT Ta "specify data connection port, multiprotocol"
-.It EPSV Ta "prepare for server-to-server transfer, multiprotocol"
-.It EPRT Ta "specify data connection port, multiprotocol"
+.It XRMD Ta "remove a directory (deprecated) [RW]"
.El
.Pp
The following non-standard or
@@ -235,7 +246,7 @@ SITE request.
.It Sy Request Ta Sy Description
.It UMASK Ta change umask, e.g. ``SITE UMASK 002''
.It IDLE Ta set idle-timer, e.g. ``SITE IDLE 60''
-.It CHMOD Ta "change mode of a file, e.g. ``SITE CHMOD 755 filename''"
+.It CHMOD Ta "change mode of a file [RW], e.g. ``SITE CHMOD 755 filename''"
.It HELP Ta give help information
.El
.Pp
@@ -273,13 +284,15 @@ and not have a null password.
In this case a password must be provided by the client before any
file operations may be performed.
If the user has an S/Key key, the response from a successful USER
-command will include an S/Key challenge. The client may choose to respond
-with a PASS command giving either a standard password or an S/Key
-one-time password. The server will automatically determine which type of
-password it has been given and attempt to authenticate accordingly. See
+command will include an S/Key challenge.
+The client may choose to respond with a PASS command giving either
+a standard password or an S/Key one-time password.
+The server will automatically determine which type of
+password it has been given and attempt to authenticate accordingly.
+See
.Xr key 1
-for more information on S/Key authentication. S/Key is a Trademark of
-Bellcore.
+for more information on S/Key authentication.
+S/Key is a Trademark of Bellcore.
.It
The login name must not appear in the file
.Pa /etc/ftpusers .
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index 6065d256a258..55f175225199 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -51,11 +51,12 @@ static const char rcsid[] =
* FTP server.
*/
#include <sys/param.h>
-#include <sys/stat.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
#include <sys/wait.h>
-#include <sys/mman.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -147,6 +148,8 @@ int stru; /* avoid C keyword */
int mode;
int usedefault = 1; /* for data transfers */
int pdata = -1; /* for passive mode */
+int readonly=0; /* Server is in readonly mode. */
+int noepsv=0; /* EPSV command is disabled. */
sig_atomic_t transflag;
off_t file_size;
off_t byte_count;
@@ -289,7 +292,7 @@ main(argc, argv, envp)
#endif /* OLD_SETPROCTITLE */
- while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:46")) != -1) {
+ while ((ch = getopt(argc, argv, "AdlDESURrt:T:u:va:p:46")) != -1) {
switch (ch) {
case 'D':
daemon_mode++;
@@ -299,10 +302,18 @@ main(argc, argv, envp)
debug++;
break;
+ case 'E':
+ noepsv = 1;
+ break;
+
case 'l':
logging++; /* > 1 == extra logging */
break;
+ case 'r':
+ readonly = 1;
+ break;
+
case 'R':
paranoid = 0;
break;
@@ -1687,9 +1698,10 @@ send_data(instr, outstr, blksize, filesize, isreg)
off_t filesize;
int isreg;
{
- int c, cnt, filefd, netfd;
- char *buf, *bp;
+ int c, filefd, netfd;
+ char *buf;
size_t len;
+ off_t cnt;
transflag++;
if (setjmp(urgcatch)) {
@@ -1726,27 +1738,28 @@ send_data(instr, outstr, blksize, filesize, isreg)
netfd = fileno(outstr);
filefd = fileno(instr);
- if (isreg && filesize < (off_t)16 * 1024 * 1024) {
- buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
- (off_t)0);
- if (buf == MAP_FAILED) {
- syslog(LOG_WARNING, "mmap(%lu): %m",
- (unsigned long)filesize);
- goto oldway;
- }
- bp = buf;
+ if (isreg) {
+
+ off_t offset;
+ int err;
+
len = filesize;
- do {
- cnt = write(netfd, bp, len);
+ err = cnt = offset = 0;
+
+ while (err != -1 && cnt < filesize) {
+ err = sendfile(filefd, netfd, offset, len,
+ (struct sf_hdtr *) NULL, &cnt, 0);
+ offset += cnt;
len -= cnt;
- bp += cnt;
- if (cnt > 0) byte_count += cnt;
- } while(cnt > 0 && len > 0);
- transflag = 0;
- munmap(buf, (size_t)filesize);
- if (cnt < 0)
- goto data_err;
+ if (err == -1) {
+ if (!cnt)
+ goto oldway;
+
+ goto data_err;
+ }
+ }
+
reply(226, "Transfer complete.");
return;
}
@@ -2364,6 +2377,16 @@ passive()
goto pasv_error;
}
#endif
+#ifdef IPV6_PORTRANGE
+ if (ctrl_addr.su_family == AF_INET6) {
+ int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH
+ : IPV6_PORTRANGE_DEFAULT;
+
+ if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
+ (char *)&on, sizeof(on)) < 0)
+ goto pasv_error;
+ }
+#endif
pasv_addr = ctrl_addr;
pasv_addr.su_port = 0;
@@ -2478,6 +2501,27 @@ long_passive(cmd, pf)
}
#endif
+#ifdef IP_PORTRANGE
+ if (ctrl_addr.su_family == AF_INET) {
+ int on = restricted_data_ports ? IP_PORTRANGE_HIGH
+ : IP_PORTRANGE_DEFAULT;
+
+ if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
+ (char *)&on, sizeof(on)) < 0)
+ goto pasv_error;
+ }
+#endif
+#ifdef IPV6_PORTRANGE
+ if (ctrl_addr.su_family == AF_INET6) {
+ int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH
+ : IPV6_PORTRANGE_DEFAULT;
+
+ if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
+ (char *)&on, sizeof(on)) < 0)
+ goto pasv_error;
+ }
+#endif
+
if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0)
goto pasv_error;