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

📄 tftpd.c

📁 压缩包中包含LINUX下多个命令的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
 * 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. */intvalidate_access(char **filep, int mode){	struct stat stbuf;	int	fd;	struct dirlist *dirp;	static char *pathname = 0;	char *filename = *filep;	/*	 * Prevent tricksters from getting around the directory restrictions	 */	if (strstr(filename, "/../"))		return (EACCESS);	if (*filename == '/') {		/*		 * Allow the request if it's in one of the approved locations.		 * Special case: check the null prefix ("/") by looking		 * for length = 1 and relying on the arg. processing that		 * it's a /.		 */		for (dirp = dirs; dirp->name != NULL; dirp++) {			if (dirp->len == 1 ||			    (!strncmp(filename, dirp->name, dirp->len) &&			     filename[dirp->len] == '/'))				    break;		}		/* If directory list is empty, allow access to any file */		if (dirp->name == NULL && dirp != dirs)			return (EACCESS);		if (stat(filename, &stbuf) < 0)			return (errno == ENOENT ? ENOTFOUND : EACCESS);		if ((stbuf.st_mode & S_IFMT) != S_IFREG)			return (ENOTFOUND);		if (mode == RRQ) {			if ((stbuf.st_mode & S_IROTH) == 0)				return (EACCESS);		} else {			if ((stbuf.st_mode & S_IWOTH) == 0)				return (EACCESS);		}	} else {		int err;		/*		 * Relative file name: search the approved locations for it.		 * Don't allow write requests or ones that avoid directory		 * restrictions.		 */		if (mode != RRQ || !strncmp(filename, "../", 3))			return (EACCESS);		/*		 * If the file exists in one of the directories and isn't		 * readable, continue looking. However, change the error code		 * to give an indication that the file exists.		 */		err = ENOTFOUND;		for (dirp = dirs; dirp->name != NULL; dirp++) {			if (pathname)				free (pathname);			pathname = malloc (strlen (dirp->name)					   + 1 + strlen (filename) + 1);			if (! pathname)				return ENOMEM;			sprintf(pathname, "%s/%s", dirp->name, filename);			if (stat(pathname, &stbuf) == 0 &&			    (stbuf.st_mode & S_IFMT) == S_IFREG) {				if ((stbuf.st_mode & S_IROTH) != 0) {					break;				}				err = EACCESS;			}		}		if (dirp->name == NULL)			return (err);		*filep = filename = pathname;	}	fd = open(filename, mode == RRQ ? O_RDONLY : (O_WRONLY | O_TRUNC));	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(int sig){	timeout += rexmtval;	if (timeout >= maxtimeout)		exit(1);	longjmp(timeoutbuf, 1);}/* * Send the requested file. */voidsend_file(struct formats *pf){	struct tftphdr *dp, *r_init();	register struct tftphdr *ap;    /* ack packet */	register int size, n;	volatile int block;	signal(SIGALRM, timer);	dp = r_init();	ap = (struct tftphdr *)ackbuf;	block = 1;	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, (const char *)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 ((u_short)ap->th_block == (u_short)block)					break;				/* Re-synchronize with the other side */				(void) synchnet(peer);				if ((u_short)ap->th_block == (u_short)(block -1))					goto send_data;			}		}		block++;	} while (size == SEGSIZE);abort:	(void) fclose(file);}voidjustquit(int sig){	exit(0);}/* * Receive a file. */voidrecvfile(struct formats *pf){	struct tftphdr *dp, *w_init();	register struct tftphdr *ap;    /* ack buffer */	register int n, size;	volatile int block;	signal(SIGALRM, timer);	dp = w_init();	ap = (struct tftphdr *)ackbuf;	block = 0;	do {		timeout = 0;		ap->th_opcode = htons((u_short)ACK);		ap->th_block = htons((u_short)block);		block++;		(void) setjmp(timeoutbuf);send_ack:		if (send(peer, ackbuf, 4, 0) != 4) {			syslog(LOG_ERR, "tftpd: write: %m\n");			goto abort;		}		write_behind(file, pf->f_convert);		for ( ; ; ) {			alarm(rexmtval);			n = recv(peer, (char *)dp, PKTSIZE, 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->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, sizeof (buf), 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" },	{ -1,		0 }};static const char *errtomsg(int error){	static char buf[20];	register struct errmsg *pe;	if (error == 0)		return "success";	for (pe = errmsgs; pe->e_code >= 0; pe++)		if (pe->e_code == error)			return pe->e_msg;	sprintf(buf, "error %d", error);	return buf;}/* * Send a nak packet (error message). * Error code passed in is one of the * standard TFTP codes, or a UNIX errno * offset by 100. */static voidnak(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");}static const char *verifyhost(struct sockaddr_in *fromp){	struct hostent *hp;	hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (fromp->sin_addr),			    fromp->sin_family);	if (hp)		return hp->h_name;	else		return inet_ntoa(fromp->sin_addr);}

⌨️ 快捷键说明

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