📄 tftpd.c
字号:
/* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintchar copyright[] ="@(#) Copyright (c) 1983 Regents of the University of California.\n\ All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)tftpd.c 5.13 (Berkeley) 2/26/91";#endif /* not lint *//* * Trivial file transfer protocol server. * * This version includes many modifications by Jim Guyton <guyton@rand-unix> * * Further modifications by Markus Gutschke <gutschk@math.uni-muenster.de> * - RFC1782 option parsing * - RFC1783 extended blocksize * * Further modifications by Gero Kuhlmann <gero@gkminix.han.de> * - RFC1784 filesize option */#include <sys/types.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <signal.h>#include <fcntl.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/tftp.h>#include <netdb.h>#include <setjmp.h>#include <syslog.h>#include <stdio.h>#include <errno.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#define TIMEOUT 5#ifndef OACK#define OACK 6#endif#ifndef EOPTNEG#define EOPTNEG 8#endifextern int errno;struct sockaddr_in sockin = { AF_INET };int peer;int rexmtval = TIMEOUT;int maxtimeout = 5*TIMEOUT;#define PKTSIZE (1432 + 4)int segsize = SEGSIZE;char buf[PKTSIZE];char ackbuf[PKTSIZE];struct sockaddr_in from;int fromlen;off_t filesize;#define MAXARG 4char *dirs[MAXARG+1];main(ac, av) char **av;{ register struct tftphdr *tp; register int n = 0; int on = 1; ac--; av++; while (ac-- > 0 && n < MAXARG) dirs[n++] = *av++; openlog("tftpd", LOG_PID, LOG_DAEMON); if (ioctl(0, FIONBIO, &on) < 0) { syslog(LOG_ERR, "ioctl(FIONBIO): %m\n"); exit(1); } fromlen = sizeof (from); n = recvfrom(0, buf, segsize + 4, 0, (struct sockaddr *)&from, &fromlen); if (n < 0) { syslog(LOG_ERR, "recvfrom: %m\n"); exit(1); } /* * Now that we have read the message out of the UDP * socket, we fork and exit. Thus, inetd will go back * to listening to the tftp port, and the next request * to come in will start up a new instance of tftpd. * * We do this so that inetd can run tftpd in "wait" mode. * The problem with tftpd running in "nowait" mode is that * inetd may get one or more successful "selects" on the * tftp port before we do our receive, so more than one * instance of tftpd may be started up. Worse, if tftpd * break before doing the above "recvfrom", inetd would * spawn endless instances, clogging the system. */ { int pid; int i, j; for (i = 1; i < 20; i++) { pid = fork(); if (pid < 0) { sleep(i); /* * flush out to most recently sent request. * * This may drop some request, but those * will be resent by the clients when * they timeout. The positive effect of * this flush is to (try to) prevent more * than one tftpd being started up to service * a single request from a single client. */ j = sizeof from; i = recvfrom(0, buf, segsize + 4, 0, (struct sockaddr *)&from, &j); if (i > 0) { n = i; fromlen = j; } } else { break; } } if (pid < 0) { syslog(LOG_ERR, "fork: %m\n"); exit(1); } else if (pid != 0) { exit(0); } } from.sin_family = AF_INET; alarm(0); close(0); close(1); peer = socket(AF_INET, SOCK_DGRAM, 0); if (peer < 0) { syslog(LOG_ERR, "socket: %m\n"); exit(1); } if (bind(peer, (struct sockaddr *)&sockin, sizeof (sockin)) < 0) { syslog(LOG_ERR, "bind: %m\n"); exit(1); } if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) { syslog(LOG_ERR, "connect: %m\n"); exit(1); } tp = (struct tftphdr *)buf; tp->th_opcode = ntohs(tp->th_opcode); if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) tftp(tp, n); exit(1);}int validate_access();int sendfile(), recvfile();struct formats { char *f_mode; int (*f_validate)(); int (*f_send)(); int (*f_recv)(); int f_convert;} formats[] = { { "netascii", validate_access, sendfile, recvfile, 1 }, { "octet", validate_access, sendfile, recvfile, 0 },#ifdef notdef { "mail", validate_user, sendmail, recvmail, 1 },#endif { 0 }};int set_blksize();int set_filesize();struct options { char *o_opt; int (*o_fnc)();} options[] = { { "blksize", set_blksize }, { "tsize", set_filesize }, { NULL, NULL }};/* * Set a non-standard block size (c.f. RFC1783) */set_blksize(val, ret) char *val; char **ret;{ static char b_ret[5]; int sz = atoi(val); if (sz < 8) return(0); else if (sz > PKTSIZE - 4) sz = PKTSIZE - 4; segsize = sz; sprintf(*ret = b_ret, "%d", sz); return(1);}/* * Return a file size (c.f. RFC1784) */set_filesize(val, ret) char *val; char **ret;{ static char b_ret[10]; off_t sz = atol(val); if (sz == 0) sz = filesize; sprintf(*ret = b_ret, "%lu", sz); return(1);}/* * Parse RFC1782 style options */do_opt(opt, val, ap) char *opt; char *val; char **ap;{ struct options *po; char *ret; for (po = options; po->o_opt; po++) if (strcasecmp(po->o_opt, opt) == 0) { if (po->o_fnc(val, &ret)) { if (*ap + strlen(opt) + strlen(ret) + 2 >= ackbuf + sizeof(ackbuf)) { nak(ENOSPACE); exit(1); } *ap = strrchr(strcpy(strrchr(strcpy(*ap, opt), '\000') + 1, ret), '\000') + 1; } else { nak(EOPTNEG); exit(1); } break; } return;}/* * Handle initial connection protocol. */tftp(tp, size) struct tftphdr *tp; int size;{ register char *cp; int argn = 0, ecode; register struct formats *pf = NULL; char *filename, *mode; char *val, *opt; char *ap = ackbuf + 2; int isopts; ((struct tftphdr *)ackbuf)->th_opcode = ntohs(OACK); filename = cp = tp->th_stuff;again: while (cp < buf + size) { if (*cp == '\0') break; cp++; } if (*cp != '\0') { nak(EBADOP); exit(1); } if (!argn++) { mode = ++cp; goto again; } else if (argn == 2) { for (cp = mode; *cp; cp++) if (isupper(*cp)) *cp = tolower(*cp); for (pf = formats; pf->f_mode; pf++) if (strcmp(pf->f_mode, mode) == 0) break; if (pf->f_mode == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -