summaryrefslogtreecommitdiffstats
path: root/crypto/heimdal/appl/ftp/ftpd/ftpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/heimdal/appl/ftp/ftpd/ftpd.c')
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/ftpd.c370
1 files changed, 198 insertions, 172 deletions
diff --git a/crypto/heimdal/appl/ftp/ftpd/ftpd.c b/crypto/heimdal/appl/ftp/ftpd/ftpd.c
index d769eaf..88bb4a1 100644
--- a/crypto/heimdal/appl/ftp/ftpd/ftpd.c
+++ b/crypto/heimdal/appl/ftp/ftpd/ftpd.c
@@ -38,7 +38,7 @@
#endif
#include "getarg.h"
-RCSID("$Id: ftpd.c,v 1.166.2.2 2004/03/14 17:16:39 lha Exp $");
+RCSID("$Id: ftpd.c,v 1.166.2.3 2004/08/20 15:16:37 lha Exp $");
static char version[] = "Version 6.00";
@@ -61,8 +61,6 @@ struct sockaddr_storage pasv_addr_ss;
struct sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss;
int data;
-jmp_buf errcatch, urgcatch;
-int oobflag;
int logged_in;
struct passwd *pw;
int debug = 0;
@@ -78,7 +76,9 @@ int stru; /* avoid C keyword */
int mode;
int usedefault = 1; /* for data transfers */
int pdata = -1; /* for passive mode */
-int transflag;
+int allow_insecure_oob = 1;
+static int transflag;
+static int urgflag;
off_t file_size;
off_t byte_count;
#if !defined(CMASK) || CMASK == 0
@@ -134,6 +134,7 @@ char proctitle[BUFSIZ]; /* initial part of title */
static void ack (char *);
static void myoob (int);
+static int handleoobcmd(void);
static int checkuser (char *, char *);
static int checkaccess (char *);
static FILE *dataconn (const char *, off_t, const char *);
@@ -223,6 +224,7 @@ struct getargs args[] = {
{ NULL, 'v', arg_flag, &debug, "enable debugging" },
{ "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" },
{ "good-chars", 0, arg_string, &good_chars, "allowed anonymous upload filename chars" },
+ { "insecure-oob", 'I', arg_negative_flag, &allow_insecure_oob, "don't allow insecure OOB ABOR/STAT" },
#ifdef KRB5
{ "gss-bindings", 0, arg_flag, &ftp_do_gss_bindings, "Require GSS-API bindings", NULL},
#endif
@@ -429,7 +431,6 @@ main(int argc, char **argv)
#endif
);
- setjmp(errcatch);
for (;;)
yyparse();
/* NOTREACHED */
@@ -1364,15 +1365,13 @@ send_data(FILE *instr, FILE *outstr)
static char *buf;
static size_t bufsize;
- transflag++;
- if (setjmp(urgcatch)) {
- transflag = 0;
- return;
- }
+ transflag = 1;
switch (type) {
case TYPE_A:
while ((c = getc(instr)) != EOF) {
+ if (urgflag && handleoobcmd())
+ return;
byte_count++;
if(c == '\n')
sec_putc('\r', outstr);
@@ -1380,6 +1379,7 @@ send_data(FILE *instr, FILE *outstr)
}
sec_fflush(outstr);
transflag = 0;
+ urgflag = 0;
if (ferror(instr))
goto file_err;
if (ferror(outstr))
@@ -1389,6 +1389,7 @@ send_data(FILE *instr, FILE *outstr)
case TYPE_I:
case TYPE_L:
+#if 0 /* XXX handle urg flag */
#if defined(HAVE_MMAP) && !defined(NO_MMAP)
#ifndef MAP_FAILED
#define MAP_FAILED (-1)
@@ -1412,10 +1413,12 @@ send_data(FILE *instr, FILE *outstr)
sec_fflush(outstr);
byte_count = cnt;
transflag = 0;
+ urgflag = 0;
}
}
}
#endif
+#endif
if(transflag) {
struct stat st;
@@ -1425,14 +1428,19 @@ send_data(FILE *instr, FILE *outstr)
fstat(filefd, &st) >= 0 ? &st : NULL);
if (buf == NULL) {
transflag = 0;
+ urgflag = 0;
perror_reply(451, "Local resource failure: malloc");
return;
}
while ((cnt = read(filefd, buf, bufsize)) > 0 &&
- sec_write(netfd, buf, cnt) == cnt)
+ sec_write(netfd, buf, cnt) == cnt) {
byte_count += cnt;
+ if (urgflag && handleoobcmd())
+ return;
+ }
sec_fflush(outstr); /* to end an encrypted stream */
transflag = 0;
+ urgflag = 0;
if (cnt != 0) {
if (cnt < 0)
goto file_err;
@@ -1443,17 +1451,20 @@ send_data(FILE *instr, FILE *outstr)
return;
default:
transflag = 0;
+ urgflag = 0;
reply(550, "Unimplemented TYPE %d in send_data", type);
return;
}
data_err:
transflag = 0;
+ urgflag = 0;
perror_reply(426, "Data connection");
return;
file_err:
transflag = 0;
+ urgflag = 0;
perror_reply(551, "Error on input file");
}
@@ -1471,16 +1482,13 @@ receive_data(FILE *instr, FILE *outstr)
static size_t bufsize;
struct stat st;
- transflag++;
- if (setjmp(urgcatch)) {
- transflag = 0;
- return (-1);
- }
+ transflag = 1;
buf = alloc_buffer (buf, &bufsize,
fstat(fileno(outstr), &st) >= 0 ? &st : NULL);
if (buf == NULL) {
transflag = 0;
+ urgflag = 0;
perror_reply(451, "Local resource failure: malloc");
return -1;
}
@@ -1493,15 +1501,19 @@ receive_data(FILE *instr, FILE *outstr)
if (write(fileno(outstr), buf, cnt) != cnt)
goto file_err;
byte_count += cnt;
+ if (urgflag && handleoobcmd())
+ return (-1);
}
if (cnt < 0)
goto data_err;
transflag = 0;
+ urgflag = 0;
return (0);
case TYPE_E:
reply(553, "TYPE E not implemented.");
transflag = 0;
+ urgflag = 0;
return (-1);
case TYPE_A:
@@ -1511,6 +1523,8 @@ receive_data(FILE *instr, FILE *outstr)
while ((cnt = sec_read(fileno(instr),
buf + cr_flag,
bufsize - cr_flag)) > 0){
+ if (urgflag && handleoobcmd())
+ return (-1);
byte_count += cnt;
cnt += cr_flag;
cr_flag = 0;
@@ -1542,6 +1556,7 @@ receive_data(FILE *instr, FILE *outstr)
if (ferror(outstr))
goto file_err;
transflag = 0;
+ urgflag = 0;
if (bare_lfs) {
lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
" File may not have transferred correctly.\r\n",
@@ -1552,16 +1567,19 @@ receive_data(FILE *instr, FILE *outstr)
default:
reply(550, "Unimplemented TYPE %d in receive_data", type);
transflag = 0;
+ urgflag = 0;
return (-1);
}
data_err:
transflag = 0;
+ urgflag = 0;
perror_reply(426, "Data Connection");
return (-1);
file_err:
transflag = 0;
+ urgflag = 0;
perror_reply(452, "Error writing file");
return (-1);
}
@@ -1731,17 +1749,6 @@ nack(char *s)
reply(502, "%s command not implemented.", s);
}
-/* ARGSUSED */
-void
-yyerror(char *s)
-{
- char *cp;
-
- if ((cp = strchr(cbuf,'\n')))
- *cp = '\0';
- reply(500, "'%s': command not understood.", cbuf);
-}
-
void
do_delete(char *name)
{
@@ -1880,6 +1887,7 @@ void
dologout(int status)
{
transflag = 0;
+ urgflag = 0;
if (logged_in) {
seteuid((uid_t)0);
ftpd_logwtmp(ttyline, "", "");
@@ -1897,51 +1905,72 @@ dologout(int status)
void abor(void)
{
+ if (!transflag)
+ return;
+ reply(426, "Transfer aborted. Data connection closed.");
+ reply(226, "Abort successful");
+ transflag = 0;
}
static void
myoob(int signo)
{
-#if 0
+ urgflag = 1;
+}
+
+static char *
+mec_space(char *p)
+{
+ while(isspace(*(unsigned char *)p))
+ p++;
+ return p;
+}
+
+static int
+handleoobcmd(void)
+{
char *cp;
-#endif
/* only process if transfer occurring */
if (!transflag)
- return;
+ return 0;
- /* This is all XXX */
- oobflag = 1;
- /* if the command resulted in a new command,
- parse that as well */
- do{
- yyparse();
- } while(ftp_command);
- oobflag = 0;
+ urgflag = 0;
-#if 0
cp = tmpline;
- if (ftpd_getline(cp, 7) == NULL) {
+ if (ftpd_getline(cp, sizeof(tmpline)) == NULL) {
reply(221, "You could at least say goodbye.");
dologout(0);
}
- upper(cp);
- if (strcmp(cp, "ABOR\r\n") == 0) {
- tmpline[0] = '\0';
- reply(426, "Transfer aborted. Data connection closed.");
- reply(226, "Abort successful");
- longjmp(urgcatch, 1);
+
+ if (strncasecmp("MIC", cp, 3) == 0) {
+ mec(mec_space(cp + 3), prot_safe);
+ } else if (strncasecmp("CONF", cp, 4) == 0) {
+ mec(mec_space(cp + 4), prot_confidential);
+ } else if (strncasecmp("ENC", cp, 3) == 0) {
+ mec(mec_space(cp + 3), prot_private);
+ } else if (!allow_insecure_oob) {
+ reply(533, "Command protection level denied "
+ "for paranoid reasons.");
+ goto out;
}
- if (strcmp(cp, "STAT\r\n") == 0) {
+
+ if (secure_command())
+ cp = ftp_command;
+
+ if (strcasecmp(cp, "ABOR\r\n") == 0) {
+ abor();
+ } else if (strcasecmp(cp, "STAT\r\n") == 0) {
if (file_size != (off_t) -1)
reply(213, "Status: %ld of %ld bytes transferred",
(long)byte_count,
(long)file_size);
else
- reply(213, "Status: %ld bytes transferred"
+ reply(213, "Status: %ld bytes transferred",
(long)byte_count);
}
-#endif
+out:
+ return (transflag == 0);
}
/*
@@ -2184,139 +2213,136 @@ list_file(char *file)
void
send_file_list(char *whichf)
{
- struct stat st;
- DIR *dirp = NULL;
- struct dirent *dir;
- FILE *dout = NULL;
- char **dirlist, *dirname;
- int simple = 0;
- int freeglob = 0;
- glob_t gl;
- char buf[MaxPathLen];
-
- if (strpbrk(whichf, "~{[*?") != NULL) {
- int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|
+ struct stat st;
+ DIR *dirp = NULL;
+ struct dirent *dir;
+ FILE *dout = NULL;
+ char **dirlist, *dirname;
+ int simple = 0;
+ int freeglob = 0;
+ glob_t gl;
+ char buf[MaxPathLen];
+
+ if (strpbrk(whichf, "~{[*?") != NULL) {
+ int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|
#ifdef GLOB_MAXPATH
- GLOB_MAXPATH
+ GLOB_MAXPATH
#else
- GLOB_LIMIT
+ GLOB_LIMIT
#endif
- ;
-
- memset(&gl, 0, sizeof(gl));
- freeglob = 1;
- if (glob(whichf, flags, 0, &gl)) {
- reply(550, "not found");
- goto out;
- } else if (gl.gl_pathc == 0) {
- errno = ENOENT;
- perror_reply(550, whichf);
- goto out;
- }
- dirlist = gl.gl_pathv;
- } else {
- onefile[0] = whichf;
- dirlist = onefile;
- simple = 1;
- }
+ ;
- if (setjmp(urgcatch)) {
- transflag = 0;
- goto out;
- }
- while ((dirname = *dirlist++)) {
- if (stat(dirname, &st) < 0) {
- /*
- * If user typed "ls -l", etc, and the client
- * used NLST, do what the user meant.
- */
- if (dirname[0] == '-' && *dirlist == NULL &&
- transflag == 0) {
- list_file(dirname);
- goto out;
- }
- perror_reply(550, whichf);
- if (dout != NULL) {
- fclose(dout);
- transflag = 0;
- data = -1;
- pdata = -1;
- }
- goto out;
+ memset(&gl, 0, sizeof(gl));
+ freeglob = 1;
+ if (glob(whichf, flags, 0, &gl)) {
+ reply(550, "not found");
+ goto out;
+ } else if (gl.gl_pathc == 0) {
+ errno = ENOENT;
+ perror_reply(550, whichf);
+ goto out;
+ }
+ dirlist = gl.gl_pathv;
+ } else {
+ onefile[0] = whichf;
+ dirlist = onefile;
+ simple = 1;
}
- if (S_ISREG(st.st_mode)) {
- if (dout == NULL) {
- dout = dataconn("file list", (off_t)-1, "w");
- if (dout == NULL)
- goto out;
- transflag++;
- }
- snprintf(buf, sizeof(buf), "%s%s\n", dirname,
- type == TYPE_A ? "\r" : "");
- sec_write(fileno(dout), buf, strlen(buf));
- byte_count += strlen(dirname) + 1;
- continue;
- } else if (!S_ISDIR(st.st_mode))
- continue;
-
- if ((dirp = opendir(dirname)) == NULL)
- continue;
-
- while ((dir = readdir(dirp)) != NULL) {
- char nbuf[MaxPathLen];
-
- if (!strcmp(dir->d_name, "."))
- continue;
- if (!strcmp(dir->d_name, ".."))
- continue;
-
- snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name);
-
- /*
- * We have to do a stat to insure it's
- * not a directory or special file.
- */
- if (simple || (stat(nbuf, &st) == 0 &&
- S_ISREG(st.st_mode))) {
- if (dout == NULL) {
- dout = dataconn("file list", (off_t)-1, "w");
- if (dout == NULL)
+ while ((dirname = *dirlist++)) {
+
+ if (urgflag && handleoobcmd())
+ goto out;
+
+ if (stat(dirname, &st) < 0) {
+ /*
+ * If user typed "ls -l", etc, and the client
+ * used NLST, do what the user meant.
+ */
+ if (dirname[0] == '-' && *dirlist == NULL &&
+ transflag == 0) {
+ list_file(dirname);
+ goto out;
+ }
+ perror_reply(550, whichf);
goto out;
- transflag++;
}
- if(strncmp(nbuf, "./", 2) == 0)
- snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2,
- type == TYPE_A ? "\r" : "");
- else
- snprintf(buf, sizeof(buf), "%s%s\n", nbuf,
- type == TYPE_A ? "\r" : "");
- sec_write(fileno(dout), buf, strlen(buf));
- byte_count += strlen(nbuf) + 1;
- }
+
+ if (S_ISREG(st.st_mode)) {
+ if (dout == NULL) {
+ dout = dataconn("file list", (off_t)-1, "w");
+ if (dout == NULL)
+ goto out;
+ transflag = 1;
+ }
+ snprintf(buf, sizeof(buf), "%s%s\n", dirname,
+ type == TYPE_A ? "\r" : "");
+ sec_write(fileno(dout), buf, strlen(buf));
+ byte_count += strlen(dirname) + 1;
+ continue;
+ } else if (!S_ISDIR(st.st_mode))
+ continue;
+
+ if ((dirp = opendir(dirname)) == NULL)
+ continue;
+
+ while ((dir = readdir(dirp)) != NULL) {
+ char nbuf[MaxPathLen];
+
+ if (urgflag && handleoobcmd())
+ goto out;
+
+ if (!strcmp(dir->d_name, "."))
+ continue;
+ if (!strcmp(dir->d_name, ".."))
+ continue;
+
+ snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name);
+
+ /*
+ * We have to do a stat to insure it's
+ * not a directory or special file.
+ */
+ if (simple || (stat(nbuf, &st) == 0 &&
+ S_ISREG(st.st_mode))) {
+ if (dout == NULL) {
+ dout = dataconn("file list", (off_t)-1, "w");
+ if (dout == NULL)
+ goto out;
+ transflag = 1;
+ }
+ if(strncmp(nbuf, "./", 2) == 0)
+ snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2,
+ type == TYPE_A ? "\r" : "");
+ else
+ snprintf(buf, sizeof(buf), "%s%s\n", nbuf,
+ type == TYPE_A ? "\r" : "");
+ sec_write(fileno(dout), buf, strlen(buf));
+ byte_count += strlen(nbuf) + 1;
+ }
+ }
+ closedir(dirp);
}
- closedir(dirp);
- }
- if (dout == NULL)
- reply(550, "No files found.");
- else if (ferror(dout) != 0)
- perror_reply(550, "Data connection");
- else
- reply(226, "Transfer complete.");
-
- transflag = 0;
- if (dout != NULL){
- sec_write(fileno(dout), buf, 0); /* XXX flush */
-
- fclose(dout);
- }
- data = -1;
- pdata = -1;
+ if (dout == NULL)
+ reply(550, "No files found.");
+ else if (ferror(dout) != 0)
+ perror_reply(550, "Data connection");
+ else
+ reply(226, "Transfer complete.");
+
out:
- if (freeglob) {
- freeglob = 0;
- globfree(&gl);
- }
+ transflag = 0;
+ if (dout != NULL){
+ sec_write(fileno(dout), buf, 0); /* XXX flush */
+
+ fclose(dout);
+ }
+ data = -1;
+ pdata = -1;
+ if (freeglob) {
+ freeglob = 0;
+ globfree(&gl);
+ }
}
OpenPOWER on IntegriCloud