⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tftpd.c

📁 This book was written to provide a single reference for network administration in a Linux environmen
💻 C
📖 第 1 页 / 共 2 页
字号:
			nak(EBADOP);			exit(1);		}		ecode = (*pf->f_validate)(filename, tp->th_opcode);		if (ecode) {			nak(ecode);			exit(1);		}		opt = ++cp;		if (cp < buf + size && *cp != '\000')			goto again;	} else {		*(argn & 1 ? &val : &opt) = ++cp;		if (argn & 1)			do_opt(opt, val, &ap);		if (cp < buf + size && *cp != '\000')			goto again;	}	if (pf == NULL || pf->f_mode == 0) {		nak(EBADOP);		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. * If we were invoked with arguments * from inetd then the file must also be * in one of the given directory prefixes. * 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, **dirp;	if (*filename != '/')		return (EACCESS);	/*	 * prevent tricksters from getting around the directory restrictions	 */	for (cp = filename + 1; *cp; cp++)		if(*cp == '.' && strncmp(cp-1, "/../", 4) == 0)			return(EACCESS);	for (dirp = dirs; *dirp; dirp++)		if (strncmp(filename, *dirp, strlen(*dirp)) == 0)			break;	if (*dirp==0 && dirp!=dirs)		return (EACCESS);	if (stat(filename, &stbuf) < 0)		return (errno == ENOENT ? ENOTFOUND : EACCESS);	if (mode == RRQ) {		if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)			return (EACCESS);		filesize = stbuf.st_size;	} else {		if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)			return (EACCESS);		filesize = 0;	}	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;voidtimer(){	timeout += rexmtval;	if (timeout >= maxtimeout)		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 block = 1, size, n;	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((u_short)ap->th_block);			if (ap->th_opcode == ERROR) {				syslog(LOG_ERR, "tftp: client does not accept "								"options\n");				goto abort;			}			if (ap->th_opcode == ACK) {				if (ap->th_block == 0)					break;				/* Resynchronize 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((u_short)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((u_short)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:	(void) fclose(file);}voidjustquit(){	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 block = 0, acksize, n, size;	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((u_short)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((u_short)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);	(void) fclose(file);            /* close data file */	ap = (struct tftphdr *)ackbuf;	ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */	ap->th_block = htons((u_short)(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;	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;	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 = strerror(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 (send(peer, buf, length, 0) != length)		syslog(LOG_ERR, "nak: %m\n");}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -