?? ftpd_c.txt
字號:
}
/*
* Display a login message, if it exists.
* N.B. reply(230,) must follow the message.
*/
motd = login_getcapstr(lc, "welcome", NULL, NULL);
if ((fp = fopen(motd ? motd : _PATH_FTPLOGINMESG, "r")) != NULL) {
char line[LINE_MAX];
while (fgets(line, sizeof(line), fp) != NULL) {
line[strcspn(line, "\n")] = '\0';
lreply(230, "%s", line);
}
(void) fflush(stdout);
(void) fclose(fp);
}
if (motd != NULL)
free(motd);
if (guest) {
if (ident != NULL)
free(ident);
ident = strdup(passwd);
if (ident == NULL)
fatal("Ran out of memory.");
reply(230, "Guest login ok, access restrictions apply.");
#ifdef HASSETPROCTITLE
snprintf(proctitle, sizeof(proctitle),
"%s: anonymous/%.*s", remotehost,
(int)(sizeof(proctitle) - sizeof(remotehost) -
sizeof(": anonymous/")), passwd);
setproctitle("%s", proctitle);
#endif /* HASSETPROCTITLE */
if (logging)
syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
remotehost, passwd);
} else {
reply(230, "User %s logged in.", pw->pw_name);
#ifdef HASSETPROCTITLE
snprintf(proctitle, sizeof(proctitle),
"%s: %s", remotehost, pw->pw_name);
setproctitle("%s", proctitle);
#endif /* HASSETPROCTITLE */
if (logging)
syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
remotehost, pw->pw_name);
}
login_close(lc);
lc = NULL;
return (AUTH_SLAVE);
bad:
/* Forget all about it... */
login_close(lc);
lc = NULL;
end_login();
return (AUTH_FAILED);
}
void
retrieve(char *cmd, char *name)
{
FILE *fin, *dout;
struct stat st;
int (*closefunc)(FILE *);
time_t start;
if (cmd == 0) {
fin = fopen(name, "r"), closefunc = fclose;
st.st_size = 0;
} else {
char line[BUFSIZ];
(void) snprintf(line, sizeof(line), cmd, name);
name = line;
fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
st.st_size = -1;
st.st_blksize = BUFSIZ;
}
if (fin == NULL) {
if (errno != 0) {
perror_reply(550, name);
if (cmd == 0) {
LOGCMD("get", name);
}
}
return;
}
byte_count = -1;
if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
reply(550, "%s: not a plain file.", name);
goto done;
}
if (restart_point) {
if (type == TYPE_A) {
off_t i, n;
int c;
n = restart_point;
i = 0;
while (i++ < n) {
if ((c = getc(fin)) == EOF) {
if (ferror(fin)) {
perror_reply(550, name);
goto done;
} else
break;
}
if (c == '\n')
i++;
}
} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
perror_reply(550, name);
goto done;
}
}
dout = dataconn(name, st.st_size, "w");
if (dout == NULL)
goto done;
time(&start);
send_data(fin, dout, (off_t)st.st_blksize, st.st_size,
(restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)));
if ((cmd == 0) && stats)
logxfer(name, byte_count, start);
(void) fclose(dout);
data = -1;
done:
if (pdata >= 0)
(void) close(pdata);
pdata = -1;
if (cmd == 0)
LOGBYTES("get", name, byte_count);
(*closefunc)(fin);
}
void
store(char *name, char *mode, int unique)
{
FILE *fout, *din;
int (*closefunc)(FILE *);
struct stat st;
int fd;
if (restart_point && *mode != 'a')
mode = "r+";
if (unique && stat(name, &st) == 0) {
char *nam;
fd = guniquefd(name, &nam);
if (fd == -1) {
LOGCMD(*mode == 'w' ? "put" : "append", name);
return;
}
name = nam;
fout = fdopen(fd, mode);
} else
fout = fopen(name, mode);
closefunc = fclose;
if (fout == NULL) {
perror_reply(553, name);
LOGCMD(*mode == 'w' ? "put" : "append", name);
return;
}
byte_count = -1;
if (restart_point) {
if (type == TYPE_A) {
off_t i, n;
int c;
n = restart_point;
i = 0;
while (i++ < n) {
if ((c = getc(fout)) == EOF) {
if (ferror(fout)) {
perror_reply(550, name);
goto done;
} else
break;
}
if (c == '\n')
i++;
}
/*
* We must do this seek to "current" position
* because we are changing from reading to
* writing.
*/
if (fseek(fout, 0L, SEEK_CUR) < 0) {
perror_reply(550, name);
goto done;
}
} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
perror_reply(550, name);
goto done;
}
}
din = dataconn(name, (off_t)-1, "r");
if (din == NULL)
goto done;
if (receive_data(din, fout) == 0) {
if (unique)
reply(226, "Transfer complete (unique file name:%s).",
name);
else
reply(226, "Transfer complete.");
}
(void) fclose(din);
data = -1;
pdata = -1;
done:
LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
(*closefunc)(fout);
}
static FILE *
getdatasock(char *mode)
{
int on = 1, s, t, tries;
if (data >= 0)
return (fdopen(data, mode));
sigprocmask (SIG_BLOCK, &allsigs, NULL);
s = monitor_socket(ctrl_addr.su_family);
if (s < 0)
goto bad;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
&on, sizeof(on)) < 0)
goto bad;
/* anchor socket to avoid multi-homing problems */
data_source = ctrl_addr;
data_source.su_port = htons(20); /* ftp-data port */
for (tries = 1; ; tries++) {
if (monitor_bind(s, (struct sockaddr *)&data_source,
data_source.su_len) >= 0)
break;
if (errno != EADDRINUSE || tries > 10)
goto bad;
sleep((unsigned int)tries);
}
sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
#ifdef IP_TOS
if (ctrl_addr.su_family == AF_INET) {
on = IPTOS_THROUGHPUT;
if (setsockopt(s, IPPROTO_IP, IP_TOS, &on,
sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
}
#endif
#ifdef TCP_NOPUSH
/*
* Turn off push flag to keep sender TCP from sending short packets
* at the boundaries of each write(). Should probably do a SO_SNDBUF
* to set the send buffer size as well, but that may not be desirable
* in heavy-load situations.
*/
on = 1;
if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, &on, sizeof(on)) < 0)
syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
#endif
#ifdef SO_SNDBUF
on = 65536;
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &on, sizeof(on)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
#endif
return (fdopen(s, mode));
bad:
/* Return the real value of errno (close may change it) */
t = errno;
sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
if (s >= 0)
(void) close(s);
errno = t;
return (NULL);
}
static FILE *
dataconn(char *name, off_t size, char *mode)
{
char sizebuf[32];
FILE *file = NULL;
int retry = 0;
in_port_t *p;
u_char *fa, *ha;
size_t alen;
int error;
file_size = size;
byte_count = 0;
if (size != (off_t) -1) {
(void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
size);
} else
sizebuf[0] = '\0';
if (pdata >= 0) {
union sockunion from;
int s;
socklen_t fromlen = sizeof(from);
(void) alarm ((unsigned) timeout);
s = accept(pdata, (struct sockaddr *)&from, &fromlen);
(void) alarm (0);
if (s < 0) {
reply(425, "Can't open data connection.");
(void) close(pdata);
pdata = -1;
return (NULL);
}
switch (from.su_family) {
case AF_INET:
p = (in_port_t *)&from.su_sin.sin_port;
fa = (u_char *)&from.su_sin.sin_addr;
ha = (u_char *)&his_addr.su_sin.sin_addr;
alen = sizeof(struct in_addr);
break;
case AF_INET6:
p = (in_port_t *)&from.su_sin6.sin6_port;
fa = (u_char *)&from.su_sin6.sin6_addr;
ha = (u_char *)&his_addr.su_sin6.sin6_addr;
alen = sizeof(struct in6_addr);
break;
default:
reply(425, "Can't build data connection: "
"unknown address family");
(void) close(pdata);
(void) close(s);
pdata = -1;
return (NULL);
}
if (from.su_family != his_addr.su_family ||
ntohs(*p) < IPPORT_RESERVED) {
reply(425, "Can't build data connection: "
"address family or port error");
(void) close(pdata);
(void) close(s);
pdata = -1;
return (NULL);
}
if (portcheck && memcmp(fa, ha, alen) != 0) {
reply(435, "Can't build data connection: "
"illegal port number");
(void) close(pdata);
(void) close(s);
pdata = -1;
return (NULL);
}
(void) close(pdata);
pdata = s;
reply(150, "Opening %s mode data connection for '%s'%s.",
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
return (fdopen(pdata, mode));
}
if (data >= 0) {
reply(125, "Using existing data connection for '%s'%s.",
name, sizebuf);
usedefault = 1;
return (fdopen(data, mode));
}
if (usedefault)
data_dest = his_addr;
usedefault = 1;
do {
if (file != NULL)
(void) fclose(file);
file = getdatasock(mode);
if (file == NULL) {
char hbuf[MAXHOSTNAMELEN], pbuf[10];
error = getnameinfo((struct sockaddr *)&data_source,
data_source.su_len, hbuf, sizeof(hbuf), pbuf,
sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
if (error != 0)
reply(425, "Can't create data socket: %s.",
strerror(errno));
else
reply(425,
"Can't create data socket (%s,%s): %s.",
hbuf, pbuf, strerror(errno));
return (NULL);
}
/*
* attempt to connect to reserved port on client machine;
* this looks like an attack
*/
switch (data_dest.su_family) {
case AF_INET:
p = (in_port_t *)&data_dest.su_sin.sin_port;
fa = (u_char *)&data_dest.su_sin.sin_addr;
ha = (u_char *)&his_addr.su_sin.sin_addr;
alen = sizeof(struct in_addr);
break;
case AF_INET6:
p = (in_port_t *)&data_dest.su_sin6.sin6_port;
fa = (u_char *)&data_dest.su_sin6.sin6_addr;
ha = (u_char *)&his_addr.su_sin6.sin6_addr;
alen = sizeof(struct in6_addr);
break;
default:
reply(425, "Can't build data connection: "
"unknown address family");
(void) fclose(file);
pdata = -1;
return (NULL);
}
if (data_dest.su_family != his_addr.su_family ||
ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) { /* XXX */
reply(425, "Can't build data connection: "
"address family or port error");
(void) fclose(file);
return NULL;
}
if (portcheck && memcmp(fa, ha, alen) != 0) {
reply(435, "Can't build data connection: "
"illegal port number");
(void) fclose(file);
return NULL;
}
if (connect(fileno(file), (struct sockaddr *)&data_dest,
data_dest.su_len) == 0) {
reply(150, "Opening %s mode data connection for '%s'%s.",
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
data = fileno(file);
return (file);
}
if (errno != EADDRINUSE)
break;
sleep((unsigned) swaitint);
retry += swaitint;
} while (retry <= swaitmax);
perror_reply(425, "Can't build data connection");
(void) fclose(file);
return (NULL);
}
/*
* Transfer the contents of "instr" to "outstr" peer using the appropriate
* encapsulation of the data subject to Mode, Structure, and Type.
*
* NB: Form isn't handled.
*/
static int
send_data(FILE *instr, FILE *outstr, off_t blksize, off_t filesize, int isreg)
{
int c, cnt, filefd, netfd;
char *buf, *bp;
size_t len;
transflag++;
switch (type) {
case TYPE_A:
while ((c = getc(instr)) != EOF) {
if (recvurg)
goto got_oob;
byte_count++;
if (c == '\n') {
if (ferror(outstr))
goto data_err;
(void) putc('\r', outstr);
}
(void) putc(c, outstr);
}
fflush(outstr);
transflag = 0;
if (ferror(instr))
goto file_err;
if (ferror(outstr))
goto data_err;
reply(226, "Transfer complete.");
return(0);
case TYPE_I:
case TYPE_L:
/*
* isreg is only set if we are not doing restart and we
* are sending a regular file
*/
netfd = fileno(outstr);
filefd = fileno(instr);
if (isreg && filesize < (off_t)16 * 1024 * 1024) {
size_t fsize = (size_t)filesize;
buf = mmap(0, fsize, PROT_READ, MAP_SHARED, filefd,
(off_t)0);
if (buf == MAP_FAILED) {
syslog(LOG_WARNING, "mmap(%llu): %m",
(unsigned long long)fsize);
goto oldway;
}
bp = buf;
len = fsize;
do {
cnt = write(netfd, bp, len);
if (recvurg) {
munmap(buf, fsize);
goto got_oob;
}
len -= cnt;
bp += cnt;
if (cnt > 0)
byte_count += cnt;
} while(cnt > 0 && len > 0);
transflag = 0;
munmap(buf, fsize);
if (cnt < 0)
goto data_err;
reply(226, "Transfer complete.");
return(0);
}
oldway:
if ((buf = malloc((size_t)blksize)) == NULL) {
transflag = 0;
perror_reply(451, "Local resource failure: malloc");
return(-1);
}
while ((cnt = read(filefd, buf, (size_t)blksize)) > 0 &&
write(netfd, buf, cnt) == cnt)
byte_count += cnt;
transflag = 0;
(void)free(buf);
if (cnt != 0) {
if (cnt < 0)
goto file_err;
goto data_err;
}
reply(226, "Transfer complete.");
return(0);
default:
transflag = 0;
reply(550, "Unimplemented TYPE %d in send_data", type);
return(-1);
}
data_err:
transflag = 0;
reply(426, "Data connection");
return(-1);
file_err:
transflag = 0;
reply(551, "Error on input file");
return(-1);
got_oob:
myoob();
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -