📄 tftpd.c
字号:
} 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 + -