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

📄 tftpd.c.test

📁 ks8695的SOHO应用中的tftp部分
💻 TEST
📖 第 1 页 / 共 2 页
字号:
/* tftp-hpa: $Id: tftpd.c.test,v 1.1.1.1 2004/05/06 19:43:41 hjia Exp $ */

/* $OpenBSD: tftpd.c,v 1.13 1999/06/23 17:01:36 deraadt Exp $	*/

/*
 * 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 lint
static const char *copyright =
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
 All rights reserved.\n";
/*static char sccsid[] = "from: @(#)tftpd.c	5.13 (Berkeley) 2/26/91";*/
/*static char rcsid[] = "$OpenBSD: tftpd.c,v 1.13 1999/06/23 17:01:36 deraadt Exp $: tftpd.c,v 1.6 1997/02/16 23:49:21 deraadt Exp $";*/
static const char *rcsid = "tftp-hpa $Id: tftpd.c.test,v 1.1.1.1 2004/05/06 19:43:41 hjia Exp $";
#endif /* not lint */

/*
 * Trivial file transfer protocol server.
 *
 * This version includes many modifications by Jim Guyton <guyton@rand-unix>
 */

#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.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>
#define __USE_GNU		/* Necessary for basename() on glibc systems */
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include <unistd.h>
#include <limits.h>
#include <sys/wait.h> 

#include "../config.h"
#include "tftpsubs.h"
#include "recvfrom.h"
#include "../../html/util.h"

#ifdef HAVE_TCPWRAPPERS
#include <tcpd.h>

int deny_severity	= LOG_WARNING;
int allow_severity	= -1;	/* Don't log at all */

struct request_info wrap_request;
#endif

void bsd_signal(int, void (*)(int));

#ifndef HAVE_SIGSETJMP
#define sigsetjmp(x,y)  setjmp(x)
#define siglongjmp(x,y) longjmp(x,y)
#define sigjmp_buf jmp_buf
#endif

#define	TIMEOUT 5		/* Default timeout (seconds) */
#define TRIES   4		/* Number of attempts to send each packet */
#define TIMEOUT_LIMIT (TRIES*(TRIES+1)/2)

#ifndef OACK
#define OACK	6
#endif
#ifndef EOPTNEG
#define EOPTNEG	8
#endif

extern	char *__progname;
int	peer;
int	timeout    = TIMEOUT;
int	rexmtval   = TIMEOUT;
int	maxtimeout = TIMEOUT_LIMIT*TIMEOUT;

#define	PKTSIZE	MAX_SEGSIZE+4
char	buf[PKTSIZE];
char	ackbuf[PKTSIZE];
struct	sockaddr_in from;
int	fromlen;
off_t	tsize;
int     tsize_ok;

int	ndirs;
char	**dirs;

int	secure = 0;
int	cancreate = 0;

struct formats;

int tftp(struct tftphdr *, int);
void nak(int);
void timer(int);
void justquit(int);
void do_opt(char *, char *, char **);

int set_blksize(char *, char **);
int set_blksize2(char *, char **);
int set_tsize(char *, char **);
int set_timeout(char *, char **);

struct options {
        char    *o_opt;
        int     (*o_fnc)(char *, char **);
} options[] = {
        { "blksize",    set_blksize  },
        { "blksize2",   set_blksize2  },
        { "tsize",      set_tsize },
	{ "timeout",	set_timeout  },
        { NULL,         NULL }
};



static void
usage(void)
{
	syslog(LOG_ERR, "Usage: %s [-c] [-u user] [-t timeout] [-r option...] [-s] [directory ...]",
	       __progname);
	exit(1);
}

/*
 * program starting, what need to initialize
 */
static void
doInit()
{
}

void signal_handler(int signum)
{
  //  printf("signum=%d\n",signum);
	if(signum == SIGCHLD)
	{
		while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
	}
	// don't comment out this line, other wise program will exit
	else if(signum == SIGHUP)
		doInit();
	else
	{
		while(waitpid(-1,NULL,WNOHANG) > 0);
		exit(0);
	}
}

int
main(int argc, char **argv)
{
	struct tftphdr *tp;
	struct passwd *pw;
	struct options *opt;
	struct sockaddr_in myaddr;
	struct sockaddr_in servaddr;
	int n = 0;
	int on = 1;
	int fd = 0;
	int pid, xx;
	int c;
	int setrv;
	int timeout = 900;	/* Default timeout */
	//	char *user = "nobody";	/* Default user */
	char *user = "root";	/* Default user */

	__progname = basename(argv[0]);

	openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);

	while ((c = getopt(argc, argv, "csu:r:t:")) != -1)
		switch (c) {
		case 'c':
			cancreate = 1;
			break;
		case 's':
			secure = 1;
			break;
		case 't':
		  timeout = atoi(optarg);
		  break;
		case 'u':
		  user = optarg;
		  break;
		case 'r':
		  for ( opt = options ; opt->o_opt ; opt++ ) {
		    if ( !strcasecmp(optarg, opt->o_opt) ) {
		      opt->o_opt = ""; /* Don't support this option */
		      break;
		    }
		  }
		  if ( !opt->o_opt ) {
		        syslog(LOG_ERR, "Unknown option: %s", optarg);
			exit(1);
		  }
		  break;

		default:
			usage();
			break;
		}

	for (; optind != argc; optind++) {
		if (dirs)
			dirs = realloc(dirs, (ndirs+2) * sizeof (char *));
		else
			dirs = calloc(ndirs+2, sizeof(char *));
		if (dirs == NULL) {
			syslog(LOG_ERR, "malloc: %m");
			exit(1);
		}			
		dirs[n++] = argv[optind];
		dirs[n] = NULL;
		ndirs++;
	}

	if (secure) {
		if (ndirs == 0) {
			syslog(LOG_ERR, "no -s directory");
			exit(1);
		}
		if (ndirs > 1) {
			syslog(LOG_ERR, "too many -s directories");
			exit(1);
		}
		if (chdir(dirs[0])) {
			syslog(LOG_ERR, "%s: %m", dirs[0]);
			exit(1);
		}
	}

	pw = getpwnam(user);
	if (!pw) {
		syslog(LOG_ERR, "no user %s: %m", user);
		exit(1);
	}

#if KAM_LATER   // not needed if not by inetd
	if (ioctl(fd, FIONBIO, &on) < 0) {
		syslog(LOG_ERR, "ioctl(FIONBIO): %m");
		exit(1);
	}
#else
	// bind to default tftp port
	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		kd_Log("tftpd:socket err");
		exit(1);
	}
	//printf("fd=%d\n",fd);

        on = 1;
        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on));
	                                      
	bzero(&servaddr, sizeof(servaddr));     /* zero the struct */
	servaddr.sin_family = AF_INET;         /* host byte order */
	servaddr.sin_port = htons(IPPORT_TFTP);/* short, network byte order */
	servaddr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */

	if (bind(fd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) == -1) 
	{
		kd_Log("tftpd:bind err");
	  	close(fd);
		exit(1);
	}
#endif
	/* This means we don't want to wait() for children */
	bsd_signal(SIGCHLD, SIG_IGN);

	
	// Set up signal handlers so we can clear up our child processes
	signal(SIGTERM, signal_handler);
	signal(SIGHUP, signal_handler);
	signal(SIGINT, signal_handler);
	signal(SIGCHLD, signal_handler);
	signal(SIGKILL, signal_handler);

	xx = fork();
		
	if(xx==-1)
	{
		kd_Log("tftpd:FATAL ERROR, Could not fork() tftpd\n");
		syslog(LOG_CRIT, "Could not fork() tftpd into background\n");
		closelog();
		close(fd);
		exit(1);
	}
	if(xx != 0) {	// Parent...
	  printf("tftp in background pid=%d\n",xx);
		exit(0);
	}

	do {
	  fromlen = sizeof (from);
	  //	  printf("recvfrom %d: ",fd);
#if KAM_LATER	  
	  n = myrecvfrom(fd, buf, sizeof (buf), 0,
			 (struct sockaddr *)&from, &fromlen,
			 &myaddr);
#else
	  bzero(&myaddr, sizeof(struct sockaddr_in));
	  myaddr.sin_family = AF_INET;
	  myaddr.sin_port   = htons(IPPORT_TFTP);
	  n = recvfrom(fd, buf, sizeof (buf), 0,
		       (struct sockaddr *)&from, &fromlen);
#endif
	  
	  if (n < 0) {
	    syslog(LOG_ERR, "recvfrom: %m");
	    exit(1);
	  }

	  //printf("%d bytes ",n);
#if KAM_LATER
//#ifdef HAVE_TCPWRAPPERS
	/* Verify if this was a legal request for us.  This has to be
	   done before the chroot, while /etc is still accessible. */
	  request_init(&wrap_request,
		       RQ_DAEMON, __progname,
		       RQ_FILE, fd,
		       RQ_CLIENT_SIN, &from,
		       RQ_SERVER_SIN, &myaddr,
		       0);
	  sock_methods(&wrap_request);
	  if ( hosts_access(&wrap_request) == 0 ) {
	    if ( deny_severity != -1 )
	      syslog(deny_severity, "connection refused from %s",
		     inet_ntoa(from.sin_addr));
	    exit(1);		/* Access denied */
	  } else if ( allow_severity != -1 ) {
	    syslog(allow_severity, "connect from %s",
		   inet_ntoa(from.sin_addr));
	  }
#endif
	/*
	 * Now that we have read the message out of the UDP
	 * socket, we fork and go back to listening to the
	 * socket.
	 */
	  pid = fork();
	  if (pid < 0) {
	    kd_Log("tftpd:fork fail\n");
	    syslog(LOG_ERR, "fork: %m");
	    exit(1);		/* Return to inetd, just in case */
	  }
	} while ( pid > 0 );	/* Parent process continues... */

	/* Child process: handle the actual request here */

	/* Chroot and drop privileges */

	if (secure && chroot(".")) {
		syslog(LOG_ERR, "chroot: %m");
		exit(1);
	}

#ifdef HAVE_SETREGID
	setrv = setregid(pw->pw_gid, pw->pw_gid);
#else
	setrv = setegid(pw->pw_gid) || setgid(pw->pw_gid);
#endif

#ifdef HAVE_SETREUID
	setrv = setrv || setreuid(pw->pw_uid, pw->pw_uid);
#else
	/* Important: setuid() must come first */
	setrv = setrv || setuid(pw->pw_uid) ||
	  (geteuid() != pw->pw_uid && seteuid(pw->pw_uid));
#endif

	if ( setrv ) {
	  syslog(LOG_ERR, "cannot drop privileges: %m");
	  exit(1);
	}

	/* Close file descriptors we don't need */

	from.sin_family = AF_INET;
	alarm(0);
#if KAM_LATER
	close(fd);
	close(1);
#endif

	/* Process the request... */

	peer = socket(AF_INET, SOCK_DGRAM, 0);
	if (peer < 0) {
		syslog(LOG_ERR, "socket: %m");
		exit(1);
	}
	myaddr.sin_port = htons(0); /* We want a new local port */
	if (bind(peer, (struct sockaddr *)&myaddr, sizeof (myaddr)) < 0) {
		syslog(LOG_ERR, "bind: %m");
		exit(1);
	}
	if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
		syslog(LOG_ERR, "connect: %m");
		exit(1);
	}
	tp = (struct tftphdr *)buf;
	tp->th_opcode = ntohs(tp->th_opcode);
	if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) {
	  kd_Log("tftp:%s %d %s",inet_ntoa(from.sin_addr),tp->th_opcode,
		 tp->th_stuff);
	  tftp(tp, n);
	}
	//printf("opcode %d peer=%d\n",tp->th_opcode, peer);
	exit(0);
}

int	validate_access(char *, int, struct formats *);
void	sendfile(struct formats *, struct tftphdr *, int);
void	recvfile(struct formats *, struct tftphdr *, int);

struct formats {
	char	*f_mode;
	int	(*f_validate)(char *, int, struct formats *);
	void	(*f_send)(struct formats *, struct tftphdr *, int);
	void	(*f_recv)(struct formats *, struct tftphdr *, int);
	int	f_convert;
        char    filename[128];
} formats[] = {
	{ "netascii",	validate_access,	sendfile,	recvfile, 1, "\0" },
	{ "octet",	validate_access,	sendfile,	recvfile, 0, "\0" },
	{ NULL, NULL, NULL, NULL, 0, "\0" }
};

/*
 * Handle initial connection protocol.
 */
int
tftp(struct tftphdr *tp, int size)
{
	char *cp;
	int argn, ecode;
	struct formats *pf = NULL;
	char *filename, *mode = NULL;

        char *val = NULL, *opt = NULL;
        char *ap = ackbuf + 2;

        ((struct tftphdr *)ackbuf)->th_opcode = ntohs(OACK);

	filename = cp = tp->th_stuff;
	argn = 0;

	while ( cp < buf + size && *cp ) {
	     do {
		  cp++;
	     } while (cp < buf + size && *cp);

	     if ( *cp ) {
		  nak(EBADOP);	/* Corrupt packet - no final NULL */
		  exit(0);
	     }

	     argn++;
	     if (argn == 1) {
		  mode = ++cp;
	     } else if (argn == 2) {
		  for (cp = mode; *cp; cp++)
			    *cp = tolower(*cp);
		  for (pf = formats; pf->f_mode; pf++) {
		       if (!strcmp(pf->f_mode, mode))
			    break;
		  }
		  if (!pf->f_mode) {
		       nak(EBADOP);
		       exit(0);
		  }
		  ecode = (*pf->f_validate)(filename, tp->th_opcode, pf);
		  if (ecode) {
		       nak(ecode);
		       exit(0);
		  }
		  opt = ++cp;
	     } else if ( argn & 1 ) {
		  val = ++cp;
	     } else {
		  do_opt(opt, val, &ap);
		  opt = ++cp;
	     }
	}

	if (!pf) {
	     nak(EBADOP);
	     exit(0);
	}

	if (strlen(filename) >= 128) {
	     nak(EBADOP);
	     exit(0);
	}
        strcpy(pf->filename, filename);

printf("tftp filename=%s\n",filename);
	if ( ap != (ackbuf+2) ) {
	     // doesn't come here
	     if ( tp->th_opcode == WRQ )
		  (*pf->f_recv)(pf, ackbuf, ap-ackbuf);
	     else
		  (*pf->f_send)(pf, ackbuf, ap-ackbuf);
	} else {
	     if (tp->th_opcode == WRQ)
		  (*pf->f_recv)(pf, NULL, 0);
	     else
		  (*pf->f_send)(pf, NULL, 0);
	}
	exit(1);
}

static int blksize_set;

/*
 * Set a non-standard block size (c.f. RFC2348)
 */
int
set_blksize(char *val, char **ret)
{
  	static char b_ret[6];
        unsigned int sz = atoi(val);

	if ( blksize_set )
	  return 0;

        if (sz < 8)
                return(0);
        else if (sz > MAX_SEGSIZE)
                sz = MAX_SEGSIZE;

        segsize = sz;
        sprintf(*ret = b_ret, "%u", sz);

	blksize_set = 1;

        return(1);
}

/*
 * Set a power-of-two block size (nonstandard)
 */
int
set_blksize2(char *val, char **ret)
{
  	static char b_ret[6];
        unsigned int sz = atoi(val);

	if ( blksize_set )
	  return 0;

        if (sz < 8)
                return(0);
        else if (sz > MAX_SEGSIZE)
	        sz = MAX_SEGSIZE;

	/* Convert to a power of two */
	if ( sz & (sz-1) ) {
	  unsigned int sz1 = 1;
	  /* Not a power of two - need to convert */
	  while ( sz >>= 1 )
	    sz1 <<= 1;
	  sz = sz1;
	}

        segsize = sz;
        sprintf(*ret = b_ret, "%u", sz);

	blksize_set = 1;

        return(1);
}

/*
 * Return a file size (c.f. RFC2349)
 * For netascii mode, we don't know the size ahead of time;
 * so reject the option.
 */
int
set_tsize(char *val, char **ret)
{
        static char b_ret[sizeof(off_t)*CHAR_BIT/3+2];
        off_t sz = atol(val);

	if ( !tsize_ok )
	  return 0;

        if (sz == 0)
                sz = tsize;
        sprintf(*ret = b_ret, "%lu", sz);
        return(1);
}

/*
 * Set the timeout (c.f. RFC2349)
 */
int
set_timeout(char *val, char **ret)

⌨️ 快捷键说明

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