?? ftpd_c.txt
字號:
static void
myoob(void)
{
char *cp;
/* only process if transfer occurring */
if (!transflag)
return;
cp = tmpline;
if (getline(cp, 7, stdin) == 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");
}
if (strcmp(cp, "STAT\r\n") == 0) {
tmpline[0] = '\0';
if (file_size != (off_t) -1)
reply(213, "Status: %qd of %qd bytes transferred",
byte_count, file_size);
else
reply(213, "Status: %qd bytes transferred", byte_count);
}
}
/*
* Note: a response of 425 is not mentioned as a possible response to
* the PASV command in RFC959. However, it has been blessed as
* a legitimate response by Jon Postel in a telephone conversation
* with Rick Adams on 25 Jan 89.
*/
void
passive(void)
{
socklen_t len;
int on;
u_char *p, *a;
if (pw == NULL) {
reply(530, "Please login with USER and PASS");
return;
}
if (pdata >= 0)
close(pdata);
/*
* XXX
* At this point, it would be nice to have an algorithm that
* inserted a growing delay in an attack scenario. Such a thing
* would look like continual passive sockets being opened, but
* nothing serious being done with them. They're not used to
* move data; the entire attempt is just to use tcp FIN_WAIT
* resources.
*/
pdata = socket(AF_INET, SOCK_STREAM, 0);
if (pdata < 0) {
perror_reply(425, "Can't open passive connection");
return;
}
on = IP_PORTRANGE_HIGH;
if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
&on, sizeof(on)) < 0)
goto pasv_error;
pasv_addr = ctrl_addr;
pasv_addr.su_sin.sin_port = 0;
if (bind(pdata, (struct sockaddr *)&pasv_addr,
pasv_addr.su_len) < 0)
goto pasv_error;
len = sizeof(pasv_addr);
if (getsockname(pdata, (struct sockaddr *)&pasv_addr, &len) < 0)
goto pasv_error;
if (listen(pdata, 1) < 0)
goto pasv_error;
a = (u_char *)&pasv_addr.su_sin.sin_addr;
p = (u_char *)&pasv_addr.su_sin.sin_port;
reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
a[1], a[2], a[3], p[0], p[1]);
return;
pasv_error:
perror_reply(425, "Can't open passive connection");
(void) close(pdata);
pdata = -1;
return;
}
int
epsvproto2af(int proto)
{
switch (proto) {
case 1: return AF_INET;
#ifdef INET6
case 2: return AF_INET6;
#endif
default: return -1;
}
}
int
af2epsvproto(int af)
{
switch (af) {
case AF_INET: return 1;
#ifdef INET6
case AF_INET6: return 2;
#endif
default: return -1;
}
}
/*
* 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
* 229 Entering Extended Passive Mode (|||port|)
*/
void
long_passive(char *cmd, int pf)
{
socklen_t len;
int on;
u_char *p, *a;
if (!logged_in) {
syslog(LOG_NOTICE, "long passive but not logged in");
reply(503, "Login with USER first.");
return;
}
if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
/*
* XXX
* only EPRT/EPSV ready clients will understand this
*/
if (strcmp(cmd, "EPSV") != 0)
reply(501, "Network protocol mismatch"); /*XXX*/
else
epsv_protounsupp("Network protocol mismatch");
return;
}
if (pdata >= 0)
close(pdata);
/*
* XXX
* At this point, it would be nice to have an algorithm that
* inserted a growing delay in an attack scenario. Such a thing
* would look like continual passive sockets being opened, but
* nothing serious being done with them. They not used to move
* data; the entire attempt is just to use tcp FIN_WAIT
* resources.
*/
pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
if (pdata < 0) {
perror_reply(425, "Can't open passive connection");
return;
}
switch (ctrl_addr.su_family) {
case AF_INET:
on = IP_PORTRANGE_HIGH;
if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
&on, sizeof(on)) < 0)
goto pasv_error;
break;
case AF_INET6:
on = IPV6_PORTRANGE_HIGH;
if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
&on, sizeof(on)) < 0)
goto pasv_error;
break;
}
pasv_addr = ctrl_addr;
pasv_addr.su_port = 0;
if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0)
goto pasv_error;
len = pasv_addr.su_len;
if (getsockname(pdata, (struct sockaddr *)&pasv_addr, &len) < 0)
goto pasv_error;
if (listen(pdata, 1) < 0)
goto pasv_error;
p = (u_char *)&pasv_addr.su_port;
if (strcmp(cmd, "LPSV") == 0) {
switch (pasv_addr.su_family) {
case AF_INET:
a = (u_char *)&pasv_addr.su_sin.sin_addr;
reply(228,
"Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
return;
case AF_INET6:
a = (u_char *)&pasv_addr.su_sin6.sin6_addr;
reply(228,
"Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
"%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
6, 16, a[0], a[1], a[2], a[3], a[4],
a[5], a[6], a[7], a[8], a[9], a[10],
a[11], a[12], a[13], a[14], a[15],
2, p[0], p[1]);
return;
}
} else if (strcmp(cmd, "EPSV") == 0) {
switch (pasv_addr.su_family) {
case AF_INET:
case AF_INET6:
reply(229, "Entering Extended Passive Mode (|||%u|)",
ntohs(pasv_addr.su_port));
return;
}
} else {
/* more proper error code? */
}
pasv_error:
perror_reply(425, "Can't open passive connection");
(void) close(pdata);
pdata = -1;
return;
}
/*
* EPRT |proto|addr|port|
*/
int
extended_port(const char *arg)
{
char *tmp = NULL;
char *result[3];
char *p, *q;
char delim;
struct addrinfo hints;
struct addrinfo *res = NULL;
int i;
unsigned long proto;
if (epsvall) {
reply(501, "EPRT disallowed after EPSV ALL");
return -1;
}
usedefault = 0;
if (pdata >= 0) {
(void) close(pdata);
pdata = -1;
}
tmp = strdup(arg);
if (!tmp) {
fatal("not enough core.");
/*NOTREACHED*/
}
p = tmp;
delim = p[0];
p++;
memset(result, 0, sizeof(result));
for (i = 0; i < 3; i++) {
q = strchr(p, delim);
if (!q || *q != delim)
goto parsefail;
*q++ = '\0';
result[i] = p;
p = q;
}
/* some more sanity check */
p = NULL;
(void)strtoul(result[2], &p, 10);
if (!*result[2] || *p)
goto protounsupp;
p = NULL;
proto = strtoul(result[0], &p, 10);
if (!*result[0] || *p)
goto protounsupp;
memset(&hints, 0, sizeof(hints));
hints.ai_family = epsvproto2af((int)proto);
if (hints.ai_family < 0)
goto protounsupp;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST; /*no DNS*/
if (getaddrinfo(result[1], result[2], &hints, &res))
goto parsefail;
if (res->ai_next)
goto parsefail;
if (sizeof(data_dest) < res->ai_addrlen)
goto parsefail;
memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
if (his_addr.su_family == AF_INET6 &&
data_dest.su_family == AF_INET6) {
/* XXX more sanity checks! */
data_dest.su_sin6.sin6_scope_id =
his_addr.su_sin6.sin6_scope_id;
}
if (pdata >= 0) {
(void) close(pdata);
pdata = -1;
}
reply(200, "EPRT command successful.");
if (tmp)
free(tmp);
if (res)
freeaddrinfo(res);
return 0;
parsefail:
reply(500, "Invalid argument, rejected.");
usedefault = 1;
if (tmp)
free(tmp);
if (res)
freeaddrinfo(res);
return -1;
protounsupp:
epsv_protounsupp("Protocol not supported");
usedefault = 1;
if (tmp)
free(tmp);
if (res)
freeaddrinfo(res);
return -1;
}
/*
* 522 Protocol not supported (proto,...)
* as we assume address family for control and data connections are the same,
* we do not return the list of address families we support - instead, we
* return the address family of the control connection.
*/
void
epsv_protounsupp(const char *message)
{
int proto;
proto = af2epsvproto(ctrl_addr.su_family);
if (proto < 0)
reply(501, "%s", message); /*XXX*/
else
reply(522, "%s, use (%d)", message, proto);
}
/*
* Generate unique name for file with basename "local".
* The file named "local" is already known to exist.
* Generates failure reply on error.
*/
static int
guniquefd(char *local, char **nam)
{
static char new[MAXPATHLEN];
struct stat st;
int count, len, fd;
char *cp;
cp = strrchr(local, '/');
if (cp)
*cp = '\0';
if (stat(cp ? local : ".", &st) < 0) {
perror_reply(553, cp ? local : ".");
return (-1);
}
if (cp)
*cp = '/';
len = strlcpy(new, local, sizeof(new));
if (len+2+1 >= sizeof(new)-1)
return (-1);
cp = new + len;
*cp++ = '.';
for (count = 1; count < 100; count++) {
(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
if (fd == -1)
continue;
if (nam)
*nam = new;
return (fd);
}
reply(452, "Unique file name cannot be created.");
return (-1);
}
/*
* Format and send reply containing system error number.
*/
void
perror_reply(int code, char *string)
{
reply(code, "%s: %s.", string, strerror(errno));
}
static char *onefile[] = {
"",
0
};
void
send_file_list(char *whichf)
{
struct stat st;
DIR *dirp = NULL;
struct dirent *dir;
FILE *dout = NULL;
char **dirlist;
char *dirname;
int simple = 0;
volatile int freeglob = 0;
glob_t gl;
if (strpbrk(whichf, "~{[*?") != NULL) {
memset(&gl, 0, sizeof(gl));
freeglob = 1;
if (glob(whichf,
GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|GLOB_LIMIT,
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;
}
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) {
retrieve("/bin/ls %s", dirname);
goto out;
}
perror_reply(550, whichf);
if (dout != NULL) {
(void) 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++;
}
fprintf(dout, "%s%s\n", dirname,
type == TYPE_A ? "\r" : "");
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 (recvurg) {
myoob();
recvurg = 0;
transflag = 0;
goto out;
}
if (dir->d_name[0] == '.' && dir->d_namlen == 1)
continue;
if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
dir->d_namlen == 2)
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++;
}
if (nbuf[0] == '.' && nbuf[1] == '/')
fprintf(dout, "%s%s\n", &nbuf[2],
type == TYPE_A ? "\r" : "");
else
fprintf(dout, "%s%s\n", nbuf,
type == TYPE_A ? "\r" : "");
byte_count += strlen(nbuf) + 1;
}
}
(void) 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)
(void) fclose(dout);
else {
if (pdata >= 0)
close(pdata);
}
data = -1;
pdata = -1;
out:
if (freeglob) {
freeglob = 0;
globfree(&gl);
}
}
/*ARGSUSED*/
static void
reapchild(int signo)
{
int save_errno = errno;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -