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

📄 tftpd.c

📁 unix下tftp服务器源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* tftp-hpa: $Id: tftpd.c,v 1.58 2004/09/14 22:38:46 hpa 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. */#include "config.h"		/* Must be included first */#include "tftpd.h"#ifndef lintstatic const char *copyright UNUSED ="@(#) 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 UNUSED ="tftp-hpa $Id: tftpd.c,v 1.58 2004/09/14 22:38:46 hpa Exp $";#endif /* not lint *//* * Trivial file transfer protocol server. * * This version includes many modifications by Jim Guyton <guyton@rand-unix> */#include <sys/ioctl.h>#include <signal.h>#include <netdb.h>#include <ctype.h>#include <pwd.h>#include <limits.h>#include <syslog.h>#include "tftpsubs.h"#include "recvfrom.h"#include "remap.h"#ifdef HAVE_SYS_FILIO_H#include <sys/filio.h>		/* Necessary for FIONBIO on Solaris */#endif#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#define	TIMEOUT 1000000		/* Default timeout (us) */#define TRIES   6		/* Number of attempts to send each packet */#define TIMEOUT_LIMIT ((1 << TRIES)-1)const char    *__progname;int	      peer;unsigned long timeout    = TIMEOUT;	/* Current timeout value */unsigned long rexmtval   = TIMEOUT;	/* Basic timeout value */unsigned long maxtimeout = TIMEOUT_LIMIT*TIMEOUT;int           timeout_quit = 0;sigjmp_buf    timeoutbuf;#define	PKTSIZE	MAX_SEGSIZE+4char		buf[PKTSIZE];char		ackbuf[PKTSIZE];unsigned int	max_blksize = MAX_SEGSIZE;struct	sockaddr_in from;int	fromlen;off_t	tsize;int     tsize_ok;int	ndirs;const char **dirs;int	secure = 0;int	cancreate = 0;int	unixperms = 0;int verbosity = 0;struct formats;#ifdef WITH_REGEXstatic struct rule *rewrite_rules = NULL;#endifint tftp(struct tftphdr *, int);static void nak(int, const char *);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 **);int set_utimeout(char *, char **);struct options {  const char    *o_opt;  int     (*o_fnc)(char *, char **);} options[] = {  { "blksize",    set_blksize  },  { "blksize2",   set_blksize2  },  { "tsize",      set_tsize },  { "timeout",	  set_timeout  },  { "utimeout",	  set_utimeout  },  { NULL,         NULL }};/* Simple handler for SIGHUP */static volatile sig_atomic_t caught_sighup = 0;static void handle_sighup(int sig){  (void)sig;			/* Suppress unused warning */  caught_sighup = 1;}/* Handle timeout signal or timeout event */voidtimer(int sig){  (void)sig;			/* Suppress unused warning */  timeout <<= 1;  if (timeout >= maxtimeout || timeout_quit)    exit(0);  siglongjmp(timeoutbuf, 1);}static voidusage(void){  syslog(LOG_ERR, "Usage: %s [-vcl][-a address][-m mappings][-u user][-t inetd_timeout][-T pkt_timeout][-r option...] [-s] [directory ...]",	 __progname);  exit(EX_USAGE);}#ifdef WITH_REGEXstatic struct rule *read_remap_rules(const char *file){  FILE *f;  struct rule *rulep;  f = fopen(file, "rt");  if ( !f ) {    syslog(LOG_ERR, "Cannot open map file: %s: %m", file);    exit(EX_NOINPUT);  }  rulep = parserulefile(f);  fclose(f);  return rulep;}#endifstatic inline voidset_socket_nonblock(int fd, int flag){  int err;  int flags;#if defined(HAVE_FCNTL) && defined(HAVE_O_NONBLOCK_DEFINITION)  /* Posixly correct */  err = ((flags = fcntl(fd, F_GETFL, 0)) < 0) ||    (fcntl(fd, F_SETFL, flag ? flags|O_NONBLOCK : flags&~O_NONBLOCK) < 0);#else  flags = flag ? 1 : 0;  err = (ioctl(fd, FIONBIO, &flags) < 0);#endif  if ( err ) {    syslog(LOG_ERR, "Cannot set nonblock flag on socket: %m");    exit(EX_OSERR);  }}/* * Receive packet with synchronous timeout; timeout is adjusted * to account for time spent waiting. */static int recv_time(int s, void *rbuf, int len, unsigned int flags,		     unsigned long *timeout_us_p){  fd_set fdset;  struct timeval tmv, t0, t1;  int rv, err;  unsigned long timeout_us = *timeout_us_p;  unsigned long timeout_left, dt;  gettimeofday(&t0, NULL);  timeout_left = timeout_us;  for ( ; ; ) {    FD_ZERO(&fdset);    FD_SET(s, &fdset);        do {      tmv.tv_sec  = timeout_left / 1000000;      tmv.tv_usec = timeout_left % 1000000;          rv = select(s+1, &fdset, NULL, NULL, &tmv);      err = errno;      gettimeofday(&t1, NULL);      dt = (t1.tv_sec - t0.tv_sec)*1000000 + (t1.tv_usec - t0.tv_usec);      *timeout_us_p = timeout_left = ( dt >= timeout_us ) ? 1 : (timeout_us - dt);    } while ( rv == -1 && err == EINTR );        if ( rv == 0 ) {      timer(0);			/* Should not return */      return -1;    }        set_socket_nonblock(s, 1);    rv = recv(s, rbuf, len, flags);    err = errno;    set_socket_nonblock(s, 0);        if ( rv < 0 ) {      if ( E_WOULD_BLOCK(err) || err == EINTR ) {	continue;		/* Once again, with feeling... */      } else {	errno = err;	return rv;      }    } else {      return rv;    }  }}intmain(int argc, char **argv){  struct tftphdr *tp;  struct passwd *pw;  struct options *opt;  struct sockaddr_in myaddr;  struct sockaddr_in bindaddr;  int n;  int fd = 0;  int standalone = 0;		/* Standalone (listen) mode */  char *address = NULL;		/* Address to listen to */  pid_t pid;  mode_t my_umask = 0;  int spec_umask = 0;  int c;  int setrv;  int waittime = 900;		/* Default time to wait for a connect*/  const char *user = "nobody";	/* Default user */  char *p, *ep;#ifdef WITH_REGEX  char *rewrite_file = NULL;#endif  u_short tp_opcode;  /* basename() is way too much of a pain from a portability standpoint */  p = strrchr(argv[0], '/');  __progname = (p && p[1]) ? p+1 : argv[0];    openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);    while ((c = getopt(argc, argv, "cspvVla:B:u:U:r:t:T:m:")) != -1)    switch (c) {    case 'c':      cancreate = 1;      break;    case 's':      secure = 1;      break;    case 'p':      unixperms = 1;      break;    case 'l':      standalone = 1;      break;    case 'a':      address = optarg;      break;    case 't':      waittime = atoi(optarg);      break;    case 'B':      {	char *vp;	max_blksize = (unsigned int)strtoul(optarg, &vp, 10);	if ( max_blksize < 512 || max_blksize > MAX_SEGSIZE || *vp ) {	  syslog(LOG_ERR, "Bad maximum blocksize value (range 512-%d): %s",		 MAX_SEGSIZE, optarg);	  exit(EX_USAGE);	}      }      break;    case 'T':      {	char *vp;	unsigned long tov = strtoul(optarg, &vp, 10);	if ( tov < 10000UL || tov > 255000000UL || *vp ) {	  syslog(LOG_ERR, "Bad timeout value: %s", optarg);	  exit(EX_USAGE);	}	rexmtval = timeout = tov;	maxtimeout = rexmtval*TIMEOUT_LIMIT;      }      break;    case 'u':      user = optarg;      break;    case 'U':      my_umask = strtoul(optarg, &ep, 8);      if ( *ep ) {	syslog(LOG_ERR, "Invalid umask: %s", optarg);	exit(EX_USAGE);      }      spec_umask = 1;      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(EX_USAGE);      }      break;#ifdef WITH_REGEX    case 'm':      if ( rewrite_file ) {	syslog(LOG_ERR, "Multiple -m options");	exit(EX_USAGE);      }      rewrite_file = optarg;      break;#endif    case 'v':      verbosity++;      break;    case 'V':      /* Print configuration to stdout and exit */      printf("%s\n", TFTPD_CONFIG_STR);      exit(0);      break;    default:      usage();      break;    }  dirs = xmalloc((argc-optind+1)*sizeof(char *));  for ( ndirs = 0 ; optind != argc ; optind++ )    dirs[ndirs++] = argv[optind];  dirs[ndirs] = NULL;    if (secure) {    if (ndirs == 0) {      syslog(LOG_ERR, "no -s directory");      exit(EX_USAGE);    }    if (ndirs > 1) {      syslog(LOG_ERR, "too many -s directories");      exit(EX_USAGE);    }    if (chdir(dirs[0])) {      syslog(LOG_ERR, "%s: %m", dirs[0]);      exit(EX_NOINPUT);    }  }    pw = getpwnam(user);  if (!pw) {    syslog(LOG_ERR, "no user %s: %m", user);    exit(EX_NOUSER);  }  if ( spec_umask || !unixperms )    umask(my_umask);    /* Note: on Cygwin, select() on a nonblocking socket becomes     a nonblocking select. */#ifndef __CYGWIN__  set_socket_nonblock(fd, 1);#endif#ifdef WITH_REGEX  if ( rewrite_file )    rewrite_rules = read_remap_rules(rewrite_file);#endif  /* If we're running standalone, set up the input port */  if ( standalone ) {    fd = socket(PF_INET, SOCK_DGRAM, 0);        memset(&bindaddr, 0, sizeof bindaddr);    bindaddr.sin_family = AF_INET;    bindaddr.sin_addr.s_addr = INADDR_ANY;    bindaddr.sin_port = htons(IPPORT_TFTP);    if ( address ) {      char *portptr, *eportptr;      struct hostent *hostent;      struct servent *servent;      unsigned long port;      address = tfstrdup(address);      portptr = strrchr(address, ':');      if ( portptr )	*portptr++ = '\0';            if ( *address ) {	hostent = gethostbyname(address);	if ( !hostent || hostent->h_addrtype != AF_INET ) {	  syslog(LOG_ERR, "cannot resolve local bind address: %s", address);	  exit(EX_NOINPUT);	}	memcpy(&bindaddr.sin_addr, hostent->h_addr, hostent->h_length);      } else {	/* Default to using INADDR_ANY */      }          if ( portptr && *portptr ) {	servent = getservbyname(portptr, "udp");	if ( servent ) {	  bindaddr.sin_port = servent->s_port;	} else if ( (port = strtoul(portptr, &eportptr, 0)) && !*eportptr ) {	  bindaddr.sin_port = htons(port);	} else if ( !strcmp(portptr, "tftp") ) {	  /* It's TFTP, we're OK */	} else {	  syslog(LOG_ERR, "cannot resolve local bind port: %s", portptr);	  exit(EX_NOINPUT);	}      }    }    if (bind(fd, (struct sockaddr *)&bindaddr, sizeof bindaddr) < 0) {      syslog(LOG_ERR, "cannot bind to local socket: %m");      exit(EX_OSERR);

⌨️ 快捷键说明

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