Remove all traces of setjmp/longjmp.
Handle those command that is needed in oobhandler, those are ABOR, STAT, ENC, CONF, MIC. add options to turn off insecure OOB handling and document the option Changes inspired by openbsd and netbsd changes but quite diffrent is most places since the code no longer look and is structured the same way. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@14136 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
@@ -48,7 +48,6 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <setjmp.h>
|
|
||||||
#ifdef HAVE_PWD_H
|
#ifdef HAVE_PWD_H
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -129,10 +128,8 @@ extern struct passwd *pw;
|
|||||||
extern int guest;
|
extern int guest;
|
||||||
extern int logging;
|
extern int logging;
|
||||||
extern int type;
|
extern int type;
|
||||||
extern int oobflag;
|
|
||||||
extern off_t file_size;
|
extern off_t file_size;
|
||||||
extern off_t byte_count;
|
extern off_t byte_count;
|
||||||
extern jmp_buf urgcatch;
|
|
||||||
|
|
||||||
extern int form;
|
extern int form;
|
||||||
extern int debug;
|
extern int debug;
|
||||||
@@ -142,7 +139,6 @@ extern int pdata;
|
|||||||
extern char hostname[], remotehost[];
|
extern char hostname[], remotehost[];
|
||||||
extern char proctitle[];
|
extern char proctitle[];
|
||||||
extern int usedefault;
|
extern int usedefault;
|
||||||
extern int transflag;
|
|
||||||
extern char tmpline[];
|
extern char tmpline[];
|
||||||
|
|
||||||
#endif /* _EXTERN_H_ */
|
#endif /* _EXTERN_H_ */
|
||||||
|
@@ -47,6 +47,9 @@ RCSID("$Id$");
|
|||||||
|
|
||||||
off_t restart_point;
|
off_t restart_point;
|
||||||
|
|
||||||
|
static int hasyyerrored;
|
||||||
|
|
||||||
|
|
||||||
static int cmd_type;
|
static int cmd_type;
|
||||||
static int cmd_form;
|
static int cmd_form;
|
||||||
static int cmd_bytesz;
|
static int cmd_bytesz;
|
||||||
@@ -303,15 +306,6 @@ cmd
|
|||||||
}
|
}
|
||||||
| sTAT CRLF
|
| sTAT CRLF
|
||||||
{
|
{
|
||||||
if(oobflag){
|
|
||||||
if (file_size != (off_t) -1)
|
|
||||||
reply(213, "Status: %lu of %lu bytes transferred",
|
|
||||||
(unsigned long)byte_count,
|
|
||||||
(unsigned long)file_size);
|
|
||||||
else
|
|
||||||
reply(213, "Status: %lu bytes transferred",
|
|
||||||
(unsigned long)byte_count);
|
|
||||||
}else
|
|
||||||
statcmd();
|
statcmd();
|
||||||
}
|
}
|
||||||
| DELE SP pathname CRLF check_login_no_guest
|
| DELE SP pathname CRLF check_login_no_guest
|
||||||
@@ -337,13 +331,7 @@ cmd
|
|||||||
}
|
}
|
||||||
| ABOR CRLF
|
| ABOR CRLF
|
||||||
{
|
{
|
||||||
if(oobflag){
|
reply(225, "ABOR command successful.");
|
||||||
reply(426, "Transfer aborted. Data connection closed.");
|
|
||||||
reply(226, "Abort successful");
|
|
||||||
oobflag = 0;
|
|
||||||
longjmp(urgcatch, 1);
|
|
||||||
}else
|
|
||||||
reply(225, "ABOR command successful.");
|
|
||||||
}
|
}
|
||||||
| CWD CRLF check_login
|
| CWD CRLF check_login
|
||||||
{
|
{
|
||||||
@@ -914,8 +902,6 @@ check_secure : /* empty */
|
|||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
extern jmp_buf errcatch;
|
|
||||||
|
|
||||||
#define CMD 0 /* beginning of command */
|
#define CMD 0 /* beginning of command */
|
||||||
#define ARGS 1 /* expect miscellaneous arguments */
|
#define ARGS 1 /* expect miscellaneous arguments */
|
||||||
#define STR1 2 /* expect SP followed by STRING */
|
#define STR1 2 /* expect SP followed by STRING */
|
||||||
@@ -1034,15 +1020,13 @@ ftpd_getline(char *s, int n)
|
|||||||
char *cs;
|
char *cs;
|
||||||
|
|
||||||
cs = s;
|
cs = s;
|
||||||
/* tmpline may contain saved command from urgent mode interruption */
|
|
||||||
|
/* might still be data within the security MIC/CONF/ENC */
|
||||||
if(ftp_command){
|
if(ftp_command){
|
||||||
strlcpy(s, ftp_command, n);
|
strlcpy(s, ftp_command, n);
|
||||||
if (debug)
|
if (debug)
|
||||||
syslog(LOG_DEBUG, "command: %s", s);
|
syslog(LOG_DEBUG, "command: %s", s);
|
||||||
#ifdef XXX
|
return s;
|
||||||
fprintf(stderr, "%s\n", s);
|
|
||||||
#endif
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
while ((c = getc(stdin)) != EOF) {
|
while ((c = getc(stdin)) != EOF) {
|
||||||
c &= 0377;
|
c &= 0377;
|
||||||
@@ -1127,6 +1111,8 @@ yylex(void)
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
|
|
||||||
case CMD:
|
case CMD:
|
||||||
|
hasyyerrored = 0;
|
||||||
|
|
||||||
signal(SIGALRM, toolong);
|
signal(SIGALRM, toolong);
|
||||||
alarm((unsigned) ftpd_timeout);
|
alarm((unsigned) ftpd_timeout);
|
||||||
if (ftpd_getline(cbuf, sizeof(cbuf)-1) == NULL) {
|
if (ftpd_getline(cbuf, sizeof(cbuf)-1) == NULL) {
|
||||||
@@ -1154,8 +1140,8 @@ yylex(void)
|
|||||||
if (p != 0) {
|
if (p != 0) {
|
||||||
if (p->implemented == 0) {
|
if (p->implemented == 0) {
|
||||||
nack(p->name);
|
nack(p->name);
|
||||||
longjmp(errcatch,0);
|
hasyyerrored = 1;
|
||||||
/* NOTREACHED */
|
break;
|
||||||
}
|
}
|
||||||
state = p->state;
|
state = p->state;
|
||||||
yylval.s = p->name;
|
yylval.s = p->name;
|
||||||
@@ -1180,8 +1166,8 @@ yylex(void)
|
|||||||
if (p->implemented == 0) {
|
if (p->implemented == 0) {
|
||||||
state = CMD;
|
state = CMD;
|
||||||
nack(p->name);
|
nack(p->name);
|
||||||
longjmp(errcatch,0);
|
hasyyerrored = 1;
|
||||||
/* NOTREACHED */
|
break;
|
||||||
}
|
}
|
||||||
state = p->state;
|
state = p->state;
|
||||||
yylval.s = p->name;
|
yylval.s = p->name;
|
||||||
@@ -1329,12 +1315,27 @@ yylex(void)
|
|||||||
default:
|
default:
|
||||||
fatal("Unknown state in scanner.");
|
fatal("Unknown state in scanner.");
|
||||||
}
|
}
|
||||||
yyerror((char *) 0);
|
yyerror(NULL);
|
||||||
state = CMD;
|
state = CMD;
|
||||||
longjmp(errcatch,0);
|
return (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
|
void
|
||||||
|
yyerror(char *s)
|
||||||
|
{
|
||||||
|
char *cp;
|
||||||
|
|
||||||
|
if (hasyyerrored)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((cp = strchr(cbuf,'\n')))
|
||||||
|
*cp = '\0';
|
||||||
|
reply(500, "'%s': command not understood.", cbuf);
|
||||||
|
hasyyerrored = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
copy(char *s)
|
copy(char *s)
|
||||||
{
|
{
|
||||||
|
@@ -48,6 +48,7 @@
|
|||||||
.Op Fl T Ar maxtimeout
|
.Op Fl T Ar maxtimeout
|
||||||
.Op Fl t Ar timeout
|
.Op Fl t Ar timeout
|
||||||
.Op Fl -gss-bindings
|
.Op Fl -gss-bindings
|
||||||
|
.Op Fl I | Fl -no-insecure-oob
|
||||||
.Op Fl u Ar default umask
|
.Op Fl u Ar default umask
|
||||||
.Op Fl B | Fl -builtin-ls
|
.Op Fl B | Fl -builtin-ls
|
||||||
.Op Fl -good-chars= Ns Ar string
|
.Op Fl -good-chars= Ns Ar string
|
||||||
@@ -150,6 +151,13 @@ use built-in ls to list files
|
|||||||
.Fl -good-chars= Ns Ar string
|
.Fl -good-chars= Ns Ar string
|
||||||
.Xc
|
.Xc
|
||||||
allowed anonymous upload filename chars
|
allowed anonymous upload filename chars
|
||||||
|
.It Xo
|
||||||
|
.Fl I
|
||||||
|
.Fl -no-insecure-oob
|
||||||
|
.Xc
|
||||||
|
don't allow insecure out of band.
|
||||||
|
Heimdal ftp client before 0.7 doesn't support secure oob, so turning
|
||||||
|
on this options makes them no longer work.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The file
|
The file
|
||||||
|
@@ -61,8 +61,6 @@ struct sockaddr_storage pasv_addr_ss;
|
|||||||
struct sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss;
|
struct sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss;
|
||||||
|
|
||||||
int data;
|
int data;
|
||||||
jmp_buf errcatch, urgcatch;
|
|
||||||
int oobflag;
|
|
||||||
int logged_in;
|
int logged_in;
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
int debug = 0;
|
int debug = 0;
|
||||||
@@ -78,7 +76,9 @@ int stru; /* avoid C keyword */
|
|||||||
int mode;
|
int mode;
|
||||||
int usedefault = 1; /* for data transfers */
|
int usedefault = 1; /* for data transfers */
|
||||||
int pdata = -1; /* for passive mode */
|
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 file_size;
|
||||||
off_t byte_count;
|
off_t byte_count;
|
||||||
#if !defined(CMASK) || CMASK == 0
|
#if !defined(CMASK) || CMASK == 0
|
||||||
@@ -134,6 +134,7 @@ char proctitle[BUFSIZ]; /* initial part of title */
|
|||||||
|
|
||||||
static void ack (char *);
|
static void ack (char *);
|
||||||
static void myoob (int);
|
static void myoob (int);
|
||||||
|
static int handleoobcmd(void);
|
||||||
static int checkuser (char *, char *);
|
static int checkuser (char *, char *);
|
||||||
static int checkaccess (char *);
|
static int checkaccess (char *);
|
||||||
static FILE *dataconn (const char *, off_t, const char *);
|
static FILE *dataconn (const char *, off_t, const char *);
|
||||||
@@ -223,6 +224,7 @@ struct getargs args[] = {
|
|||||||
{ NULL, 'v', arg_flag, &debug, "enable debugging" },
|
{ NULL, 'v', arg_flag, &debug, "enable debugging" },
|
||||||
{ "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" },
|
{ "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" },
|
{ "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
|
#ifdef KRB5
|
||||||
{ "gss-bindings", 0, arg_flag, &ftp_do_gss_bindings, "Require GSS-API bindings", NULL},
|
{ "gss-bindings", 0, arg_flag, &ftp_do_gss_bindings, "Require GSS-API bindings", NULL},
|
||||||
#endif
|
#endif
|
||||||
@@ -429,7 +431,6 @@ main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
setjmp(errcatch);
|
|
||||||
for (;;)
|
for (;;)
|
||||||
yyparse();
|
yyparse();
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
@@ -1364,15 +1365,13 @@ send_data(FILE *instr, FILE *outstr)
|
|||||||
static char *buf;
|
static char *buf;
|
||||||
static size_t bufsize;
|
static size_t bufsize;
|
||||||
|
|
||||||
transflag++;
|
transflag = 1;
|
||||||
if (setjmp(urgcatch)) {
|
|
||||||
transflag = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
||||||
case TYPE_A:
|
case TYPE_A:
|
||||||
while ((c = getc(instr)) != EOF) {
|
while ((c = getc(instr)) != EOF) {
|
||||||
|
if (urgflag && handleoobcmd())
|
||||||
|
return;
|
||||||
byte_count++;
|
byte_count++;
|
||||||
if(c == '\n')
|
if(c == '\n')
|
||||||
sec_putc('\r', outstr);
|
sec_putc('\r', outstr);
|
||||||
@@ -1380,6 +1379,7 @@ send_data(FILE *instr, FILE *outstr)
|
|||||||
}
|
}
|
||||||
sec_fflush(outstr);
|
sec_fflush(outstr);
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
if (ferror(instr))
|
if (ferror(instr))
|
||||||
goto file_err;
|
goto file_err;
|
||||||
if (ferror(outstr))
|
if (ferror(outstr))
|
||||||
@@ -1389,6 +1389,7 @@ send_data(FILE *instr, FILE *outstr)
|
|||||||
|
|
||||||
case TYPE_I:
|
case TYPE_I:
|
||||||
case TYPE_L:
|
case TYPE_L:
|
||||||
|
#if 0 /* XXX handle urg flag */
|
||||||
#if defined(HAVE_MMAP) && !defined(NO_MMAP)
|
#if defined(HAVE_MMAP) && !defined(NO_MMAP)
|
||||||
#ifndef MAP_FAILED
|
#ifndef MAP_FAILED
|
||||||
#define MAP_FAILED (-1)
|
#define MAP_FAILED (-1)
|
||||||
@@ -1412,9 +1413,11 @@ send_data(FILE *instr, FILE *outstr)
|
|||||||
sec_fflush(outstr);
|
sec_fflush(outstr);
|
||||||
byte_count = cnt;
|
byte_count = cnt;
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
if(transflag) {
|
if(transflag) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@@ -1425,14 +1428,19 @@ send_data(FILE *instr, FILE *outstr)
|
|||||||
fstat(filefd, &st) >= 0 ? &st : NULL);
|
fstat(filefd, &st) >= 0 ? &st : NULL);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
perror_reply(451, "Local resource failure: malloc");
|
perror_reply(451, "Local resource failure: malloc");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while ((cnt = read(filefd, buf, bufsize)) > 0 &&
|
while ((cnt = read(filefd, buf, bufsize)) > 0 &&
|
||||||
sec_write(netfd, buf, cnt) == cnt)
|
sec_write(netfd, buf, cnt) == cnt) {
|
||||||
byte_count += cnt;
|
byte_count += cnt;
|
||||||
|
if (urgflag && handleoobcmd())
|
||||||
|
return;
|
||||||
|
}
|
||||||
sec_fflush(outstr); /* to end an encrypted stream */
|
sec_fflush(outstr); /* to end an encrypted stream */
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
if (cnt != 0) {
|
if (cnt != 0) {
|
||||||
if (cnt < 0)
|
if (cnt < 0)
|
||||||
goto file_err;
|
goto file_err;
|
||||||
@@ -1443,17 +1451,20 @@ send_data(FILE *instr, FILE *outstr)
|
|||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
reply(550, "Unimplemented TYPE %d in send_data", type);
|
reply(550, "Unimplemented TYPE %d in send_data", type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_err:
|
data_err:
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
perror_reply(426, "Data connection");
|
perror_reply(426, "Data connection");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
file_err:
|
file_err:
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
perror_reply(551, "Error on input file");
|
perror_reply(551, "Error on input file");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1471,16 +1482,13 @@ receive_data(FILE *instr, FILE *outstr)
|
|||||||
static size_t bufsize;
|
static size_t bufsize;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
transflag++;
|
transflag = 1;
|
||||||
if (setjmp(urgcatch)) {
|
|
||||||
transflag = 0;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = alloc_buffer (buf, &bufsize,
|
buf = alloc_buffer (buf, &bufsize,
|
||||||
fstat(fileno(outstr), &st) >= 0 ? &st : NULL);
|
fstat(fileno(outstr), &st) >= 0 ? &st : NULL);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
perror_reply(451, "Local resource failure: malloc");
|
perror_reply(451, "Local resource failure: malloc");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1493,15 +1501,19 @@ receive_data(FILE *instr, FILE *outstr)
|
|||||||
if (write(fileno(outstr), buf, cnt) != cnt)
|
if (write(fileno(outstr), buf, cnt) != cnt)
|
||||||
goto file_err;
|
goto file_err;
|
||||||
byte_count += cnt;
|
byte_count += cnt;
|
||||||
|
if (urgflag && handleoobcmd())
|
||||||
|
return (-1);
|
||||||
}
|
}
|
||||||
if (cnt < 0)
|
if (cnt < 0)
|
||||||
goto data_err;
|
goto data_err;
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
case TYPE_E:
|
case TYPE_E:
|
||||||
reply(553, "TYPE E not implemented.");
|
reply(553, "TYPE E not implemented.");
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
case TYPE_A:
|
case TYPE_A:
|
||||||
@@ -1511,6 +1523,8 @@ receive_data(FILE *instr, FILE *outstr)
|
|||||||
while ((cnt = sec_read(fileno(instr),
|
while ((cnt = sec_read(fileno(instr),
|
||||||
buf + cr_flag,
|
buf + cr_flag,
|
||||||
bufsize - cr_flag)) > 0){
|
bufsize - cr_flag)) > 0){
|
||||||
|
if (urgflag && handleoobcmd())
|
||||||
|
return (-1);
|
||||||
byte_count += cnt;
|
byte_count += cnt;
|
||||||
cnt += cr_flag;
|
cnt += cr_flag;
|
||||||
cr_flag = 0;
|
cr_flag = 0;
|
||||||
@@ -1542,6 +1556,7 @@ receive_data(FILE *instr, FILE *outstr)
|
|||||||
if (ferror(outstr))
|
if (ferror(outstr))
|
||||||
goto file_err;
|
goto file_err;
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
if (bare_lfs) {
|
if (bare_lfs) {
|
||||||
lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
|
lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
|
||||||
" File may not have transferred correctly.\r\n",
|
" File may not have transferred correctly.\r\n",
|
||||||
@@ -1552,16 +1567,19 @@ receive_data(FILE *instr, FILE *outstr)
|
|||||||
default:
|
default:
|
||||||
reply(550, "Unimplemented TYPE %d in receive_data", type);
|
reply(550, "Unimplemented TYPE %d in receive_data", type);
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
data_err:
|
data_err:
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
perror_reply(426, "Data Connection");
|
perror_reply(426, "Data Connection");
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
file_err:
|
file_err:
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
perror_reply(452, "Error writing file");
|
perror_reply(452, "Error writing file");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@@ -1731,17 +1749,6 @@ nack(char *s)
|
|||||||
reply(502, "%s command not implemented.", 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
|
void
|
||||||
do_delete(char *name)
|
do_delete(char *name)
|
||||||
{
|
{
|
||||||
@@ -1880,6 +1887,7 @@ void
|
|||||||
dologout(int status)
|
dologout(int status)
|
||||||
{
|
{
|
||||||
transflag = 0;
|
transflag = 0;
|
||||||
|
urgflag = 0;
|
||||||
if (logged_in) {
|
if (logged_in) {
|
||||||
seteuid((uid_t)0);
|
seteuid((uid_t)0);
|
||||||
ftpd_logwtmp(ttyline, "", "");
|
ftpd_logwtmp(ttyline, "", "");
|
||||||
@@ -1897,51 +1905,72 @@ dologout(int status)
|
|||||||
|
|
||||||
void abor(void)
|
void abor(void)
|
||||||
{
|
{
|
||||||
|
if (!transflag)
|
||||||
|
return;
|
||||||
|
reply(426, "Transfer aborted. Data connection closed.");
|
||||||
|
reply(226, "Abort successful");
|
||||||
|
transflag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
myoob(int signo)
|
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;
|
char *cp;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* only process if transfer occurring */
|
/* only process if transfer occurring */
|
||||||
if (!transflag)
|
if (!transflag)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
/* This is all XXX */
|
urgflag = 0;
|
||||||
oobflag = 1;
|
|
||||||
/* if the command resulted in a new command,
|
|
||||||
parse that as well */
|
|
||||||
do{
|
|
||||||
yyparse();
|
|
||||||
} while(ftp_command);
|
|
||||||
oobflag = 0;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
cp = tmpline;
|
cp = tmpline;
|
||||||
if (ftpd_getline(cp, 7) == NULL) {
|
if (ftpd_getline(cp, sizeof(tmpline)) == NULL) {
|
||||||
reply(221, "You could at least say goodbye.");
|
reply(221, "You could at least say goodbye.");
|
||||||
dologout(0);
|
dologout(0);
|
||||||
}
|
}
|
||||||
upper(cp);
|
|
||||||
if (strcmp(cp, "ABOR\r\n") == 0) {
|
if (strncasecmp("MIC", cp, 3) == 0) {
|
||||||
tmpline[0] = '\0';
|
mec(mec_space(cp + 3), prot_safe);
|
||||||
reply(426, "Transfer aborted. Data connection closed.");
|
} else if (strncasecmp("CONF", cp, 4) == 0) {
|
||||||
reply(226, "Abort successful");
|
mec(mec_space(cp + 4), prot_confidential);
|
||||||
longjmp(urgcatch, 1);
|
} 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)
|
if (file_size != (off_t) -1)
|
||||||
reply(213, "Status: %ld of %ld bytes transferred",
|
reply(213, "Status: %ld of %ld bytes transferred",
|
||||||
(long)byte_count,
|
(long)byte_count,
|
||||||
(long)file_size);
|
(long)file_size);
|
||||||
else
|
else
|
||||||
reply(213, "Status: %ld bytes transferred"
|
reply(213, "Status: %ld bytes transferred",
|
||||||
(long)byte_count);
|
(long)byte_count);
|
||||||
}
|
}
|
||||||
#endif
|
out:
|
||||||
|
return (transflag == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2184,139 +2213,136 @@ list_file(char *file)
|
|||||||
void
|
void
|
||||||
send_file_list(char *whichf)
|
send_file_list(char *whichf)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
DIR *dirp = NULL;
|
DIR *dirp = NULL;
|
||||||
struct dirent *dir;
|
struct dirent *dir;
|
||||||
FILE *dout = NULL;
|
FILE *dout = NULL;
|
||||||
char **dirlist, *dirname;
|
char **dirlist, *dirname;
|
||||||
int simple = 0;
|
int simple = 0;
|
||||||
int freeglob = 0;
|
int freeglob = 0;
|
||||||
glob_t gl;
|
glob_t gl;
|
||||||
char buf[MaxPathLen];
|
char buf[MaxPathLen];
|
||||||
|
|
||||||
if (strpbrk(whichf, "~{[*?") != NULL) {
|
if (strpbrk(whichf, "~{[*?") != NULL) {
|
||||||
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|
|
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|
|
||||||
#ifdef GLOB_MAXPATH
|
#ifdef GLOB_MAXPATH
|
||||||
GLOB_MAXPATH
|
GLOB_MAXPATH
|
||||||
#else
|
#else
|
||||||
GLOB_LIMIT
|
GLOB_LIMIT
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
memset(&gl, 0, sizeof(gl));
|
memset(&gl, 0, sizeof(gl));
|
||||||
freeglob = 1;
|
freeglob = 1;
|
||||||
if (glob(whichf, flags, 0, &gl)) {
|
if (glob(whichf, flags, 0, &gl)) {
|
||||||
reply(550, "not found");
|
reply(550, "not found");
|
||||||
goto out;
|
goto out;
|
||||||
} else if (gl.gl_pathc == 0) {
|
} else if (gl.gl_pathc == 0) {
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
perror_reply(550, whichf);
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
goto out;
|
goto out;
|
||||||
transflag++;
|
|
||||||
}
|
}
|
||||||
if(strncmp(nbuf, "./", 2) == 0)
|
dirlist = gl.gl_pathv;
|
||||||
snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2,
|
} else {
|
||||||
type == TYPE_A ? "\r" : "");
|
onefile[0] = whichf;
|
||||||
else
|
dirlist = onefile;
|
||||||
snprintf(buf, sizeof(buf), "%s%s\n", nbuf,
|
simple = 1;
|
||||||
type == TYPE_A ? "\r" : "");
|
|
||||||
sec_write(fileno(dout), buf, strlen(buf));
|
|
||||||
byte_count += strlen(nbuf) + 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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;
|
while ((dirname = *dirlist++)) {
|
||||||
if (dout != NULL){
|
|
||||||
sec_write(fileno(dout), buf, 0); /* XXX flush */
|
if (urgflag && handleoobcmd())
|
||||||
|
goto out;
|
||||||
fclose(dout);
|
|
||||||
}
|
if (stat(dirname, &st) < 0) {
|
||||||
data = -1;
|
/*
|
||||||
pdata = -1;
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (dout == NULL)
|
||||||
|
reply(550, "No files found.");
|
||||||
|
else if (ferror(dout) != 0)
|
||||||
|
perror_reply(550, "Data connection");
|
||||||
|
else
|
||||||
|
reply(226, "Transfer complete.");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (freeglob) {
|
transflag = 0;
|
||||||
freeglob = 0;
|
if (dout != NULL){
|
||||||
globfree(&gl);
|
sec_write(fileno(dout), buf, 0); /* XXX flush */
|
||||||
}
|
|
||||||
|
fclose(dout);
|
||||||
|
}
|
||||||
|
data = -1;
|
||||||
|
pdata = -1;
|
||||||
|
if (freeglob) {
|
||||||
|
freeglob = 0;
|
||||||
|
globfree(&gl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -111,7 +111,6 @@
|
|||||||
#ifdef HAVE_PWD_H
|
#ifdef HAVE_PWD_H
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#endif
|
#endif
|
||||||
#include <setjmp.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
Reference in New Issue
Block a user