?? tftp_server_linux.c
字號:
exit(1);
}
if (*filename != '/') {
if (debug)
syslog(LOG_ERR,
"Filename has to be absolute: %s\n",
filename);
nak(EACCESS);
exit(1);
}
filename = strcat(strcpy(cp, rootdir), filename);
}
ecode = (*pf->f_validate)(filename, tp->th_opcode);
if (ecode) {
nak(ecode, ERROR);
exit(1);
}
isopts = ap != (ackbuf+2);
(tp->th_opcode == WRQ ? *pf->f_recv : *pf->f_send)
(pf, isopts ? ackbuf : NULL, isopts ? ap-ackbuf : 0);
exit(0);
}
FILE *file;
/*
* Validate file access. Since we
* have no uid or gid, for now require
* file to exist and be publicly
* readable/writable.
* Note also, full path name must be
* given as we have no login directory.
*/
validate_access(filename, mode)
char *filename;
int mode;
{
struct stat stbuf;
int fd;
char *cp;
isfilter = 0;
if (mode == RRQ) {
struct filters *fp = filters;
for (; fp; fp = fp->next) {
if (!strcmp(fp->fname,
filename +
(rootdir ? strlen(rootdir) : 0))) {
if (debug)
syslog(LOG_INFO, "Opening input "
"filter: %s\n", filename);
if ((file = popen(filename, "r")) == NULL) {
syslog(LOG_ERR, "Failed to open input "
"filter\n");
return (EACCESS); }
fd = fileno(file);
isfilter = 1;
return (0);
}
}
}
if (*filename != '/') {
if (debug)
syslog(LOG_ERR, "Filename has to be absolute: %s\n",
filename);
return (EACCESS);
}
for (cp = filename; *cp; cp++)
if (*cp == '~' || *cp == '$' ||
(*cp == '/' && cp[1] == '.' && cp[2] == '.')) {
if (debug)
syslog(LOG_ERR, "Illegal filename: %s\n",
filename);
return (EACCESS);
}
if (debug)
syslog(LOG_INFO, "Validating \"%s\" for %sing\n",
filename, mode == RRQ ? "read" : "writ");
if (stat(filename, &stbuf) < 0)
return (errno == ENOENT ? ENOTFOUND : EACCESS);
if (mode == RRQ) {
if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
return (EACCESS);
} else {
if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
return (EACCESS);
}
fd = open(filename, mode == RRQ ? 0 : 1);
if (fd < 0)
return (errno + 100);
file = fdopen(fd, (mode == RRQ)? "r":"w");
if (file == NULL) {
return errno+100;
}
return (0);
}
int timeout;
jmp_buf timeoutbuf;
void timer(int sig)
{
timeout += rexmtval;
if (timeout >= maxtimeout) {
if (debug)
syslog(LOG_WARNING, "Timeout!\n");
exit(1);
}
longjmp(timeoutbuf, 1);
}
/*
* Send the requested file.
*/
sendfile(pf, oap, oacklen)
struct formats *pf;
struct tftphdr *oap;
int oacklen;
{
struct tftphdr *dp, *r_init();
register struct tftphdr *ap; /* ack packet */
register int size, n;
u_short block = 1;
signal(SIGALRM, timer);
ap = (struct tftphdr *)ackbuf;
if (oap) {
timeout = 0;
(void) setjmp(timeoutbuf);
oack:
if (send(peer, oap, oacklen, 0) != oacklen) {
syslog(LOG_ERR, "tftpd: write: %m\n");
goto abort;
}
for ( ; ; ) {
alarm(rexmtval);
n = recv(peer, ackbuf, sizeof (ackbuf), 0);
alarm(0);
if (n < 0) {
syslog(LOG_ERR, "tftpd: read: %m\n");
goto abort;
}
ap->th_opcode = ntohs((u_short)ap->th_opcode);
ap->th_block = ntohs(ap->th_block);
if (ap->th_opcode == ERROR) {
if (debug)
syslog(LOG_ERR, "Client does not "
"accept options\n");
goto abort; }
if (ap->th_opcode == ACK) {
if (ap->th_block == 0) {
if (debug)
syslog(LOG_DEBUG,
"RFC1782 option "
"negotiation "
"succeeded\n");
break;
}
/* Re-synchronize with the other side */
(void) synchnet(peer);
goto oack;
}
}
}
dp = r_init();
do {
size = readit(file, &dp, pf->f_convert);
if (size < 0) {
nak(errno + 100);
goto abort;
}
dp->th_opcode = htons((u_short)DATA);
dp->th_block = htons(block);
timeout = 0;
(void) setjmp(timeoutbuf);
send_data:
if (send(peer, dp, size + 4, 0) != size + 4) {
syslog(LOG_ERR, "tftpd: write: %m\n");
goto abort;
}
read_ahead(file, pf->f_convert);
for ( ; ; ) {
alarm(rexmtval); /* read the ack */
n = recv(peer, ackbuf, sizeof (ackbuf), 0);
alarm(0);
if (n < 0) {
syslog(LOG_ERR, "tftpd: read: %m\n");
goto abort;
}
ap->th_opcode = ntohs((u_short)ap->th_opcode);
ap->th_block = ntohs(ap->th_block);
if (ap->th_opcode == ERROR)
goto abort;
if (ap->th_opcode == ACK) {
if (ap->th_block == block) {
break;
}
/* Re-synchronize with the other side */
(void) synchnet(peer);
if (ap->th_block == (block -1)) {
goto send_data;
}
}
}
block++;
} while (size == segsize);
abort:
if (isfilter)
pclose(file);
else
(void) fclose(file);
isfilter = 0;
}
void justquit(int sig)
{
exit(0);
}
/*
* Receive a file.
*/
recvfile(pf, oap, oacklen)
struct formats *pf;
struct tftphdr *oap;
int oacklen;
{
struct tftphdr *dp, *w_init();
register struct tftphdr *ap; /* ack buffer */
register int acksize, n, size;
u_short block = 0;
signal(SIGALRM, timer);
dp = w_init();
do {
timeout = 0;
if (!block++ && oap) {
ap = (struct tftphdr *)oap;
acksize = oacklen;
} else {
ap = (struct tftphdr *)ackbuf;
ap->th_opcode = htons((u_short)ACK);
ap->th_block = htons(block-1);
acksize = 4;
}
(void) setjmp(timeoutbuf);
send_ack:
if (send(peer, (char *)ap, acksize, 0) != acksize) {
syslog(LOG_ERR, "tftpd: write: %m\n");
goto abort;
}
write_behind(file, pf->f_convert);
for ( ; ; ) {
alarm(rexmtval);
n = recv(peer, dp, segsize+4, 0);
alarm(0);
if (n < 0) { /* really? */
syslog(LOG_ERR, "tftpd: read: %m\n");
goto abort;
}
dp->th_opcode = ntohs((u_short)dp->th_opcode);
dp->th_block = ntohs(dp->th_block);
if (dp->th_opcode == ERROR)
goto abort;
if (dp->th_opcode == DATA) {
if (dp->th_block == block) {
break; /* normal */
}
/* Re-synchronize with the other side */
(void) synchnet(peer);
if (dp->th_block == (block-1))
goto send_ack; /* rexmit */
}
}
/* size = write(file, dp->th_data, n - 4); */
size = writeit(file, &dp, n - 4, pf->f_convert);
if (size != (n-4)) { /* ahem */
if (size < 0) nak(errno + 100);
else nak(ENOSPACE);
goto abort;
}
} while (size == segsize);
write_behind(file, pf->f_convert);
if (isfilter)
pclose(file);
else
(void) fclose(file); /* close data file */
isfilter = 0;
ap = (struct tftphdr *)ackbuf;
ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
ap->th_block = htons(block);
(void) send(peer, ackbuf, 4, 0);
signal(SIGALRM, justquit); /* just quit on timeout */
alarm(rexmtval);
n = recv(peer, buf, segsize, 0); /* normally times out and quits */
alarm(0);
if (n >= 4 && /* if read some data */
dp->th_opcode == DATA && /* and got a data block */
block == dp->th_block) { /* then my last ack was lost */
(void) send(peer, ackbuf, 4, 0); /* resend final ack */
}
abort:
return;
}
struct errmsg {
int e_code;
const char *e_msg;
} errmsgs[] = {
{ EUNDEF, "Undefined error code" },
{ ENOTFOUND, "File not found" },
{ EACCESS, "Access violation" },
{ ENOSPACE, "Disk full or allocation exceeded" },
{ EBADOP, "Illegal TFTP operation" },
{ EBADID, "Unknown transfer ID" },
{ EEXISTS, "File already exists" },
{ ENOUSER, "No such user" },
{ EOPTNEG, "Failure to negotiate RFC1782 options" },
{ -1, 0 }
};
/*
* Send a nak packet (error message).
* Error code passed in is one of the
* standard TFTP codes, or a UNIX errno
* offset by 100.
*/
nak(error)
int error;
{
register struct tftphdr *tp;
int length;
register struct errmsg *pe;
/* extern char *sys_errlist[]; */
tp = (struct tftphdr *)buf;
tp->th_opcode = htons((u_short)ERROR);
tp->th_code = htons((u_short)error);
for (pe = errmsgs; pe->e_code >= 0; pe++)
if (pe->e_code == error)
break;
if (pe->e_code < 0) {
pe->e_msg = sys_errlist[error -100];
tp->th_code = EUNDEF; /* set 'undef' errorcode */
}
strcpy(tp->th_msg, pe->e_msg);
length = strlen(pe->e_msg);
tp->th_msg[length] = '\0';
length += 5;
if (debug)
syslog(LOG_ERR, "Negative acknowledge: %s\n", tp->th_msg);
if (send(peer, buf, length, 0) != length)
syslog(LOG_ERR, "nak: %m\n");
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -