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

📄 tftpd.c

📁 unix下tftp服务器源码
💻 C
📖 第 1 页 / 共 3 页
字号:
    }    /* Daemonize this process */    {      pid_t f = fork();      int nfd;      if ( f > 0 )	exit(0);      if ( f < 0 ) {	syslog(LOG_ERR, "cannot fork: %m");	exit(EX_OSERR);      }      nfd = open("/dev/null", O_RDWR);      if ( nfd >= 3 ) {#ifdef HAVE_DUP2	dup2(nfd, 0);	dup2(nfd, 1);	dup2(nfd, 2);#else	close(0); dup(nfd);	close(1); dup(nfd);	close(2); dup(nfd);#endif	close(nfd);      } else if ( nfd < 0 ) {	close(0); close(1); close(2);      }#ifdef HAVE_SETSID      setsid();#endif    }  } else {    /* 0 is our socket descriptor */    close(1); close(2);  }  /* This means we don't want to wait() for children */#ifdef SA_NOCLDWAIT  set_signal(SIGCHLD, SIG_IGN, SA_NOCLDSTOP|SA_NOCLDWAIT);#else  set_signal(SIGCHLD, SIG_IGN, SA_NOCLDSTOP);#endif  /* Take SIGHUP and use it to set a variable.  This     is polled synchronously to make sure we don't     lose packets as a result. */  set_signal(SIGHUP, handle_sighup, 0);    while ( 1 ) {    fd_set readset;    struct timeval tv_waittime;    int rv;        if ( caught_sighup ) {      caught_sighup = 0;      if ( standalone ) {#ifdef HAVE_REGEX	if ( rewrite_file ) {	  freerules(rewrite_rules);	  rewrite_rules = read_remap_rules(rewrite_file);	}#endif      } else {	/* Return to inetd for respawn */	exit(0);      }    }        FD_ZERO(&readset);    FD_SET(fd, &readset);    tv_waittime.tv_sec = waittime;    tv_waittime.tv_usec = 0;    #ifdef __CYGWIN__    /* On Cygwin, select() on a nonblocking socket returns immediately,       with a rv of 0! */    set_socket_nonblock(fd, 0);#endif        /* Never time out if we're in standalone mode */    rv = select(fd+1, &readset, NULL, NULL, standalone ? NULL : &tv_waittime);    if ( rv == -1 && errno == EINTR )      continue;		/* Signal caught, reloop */    if ( rv == -1 ) {      syslog(LOG_ERR, "select loop: %m");      exit(EX_IOERR);    } else if ( rv == 0 ) {      exit(0);		/* Timeout, return to inetd */    }#ifdef __CYGWIN__    set_socket_nonblock(fd, 1);#endif            fromlen = sizeof (from);    n = myrecvfrom(fd, buf, sizeof (buf), 0,		   (struct sockaddr *)&from, &fromlen,		   &myaddr);    if ( n < 0 ) {      if ( E_WOULD_BLOCK(errno) || errno == EINTR ) {	continue;		/* Again, from the top */      } else {	syslog(LOG_ERR, "recvfrom: %m");	exit(EX_IOERR);      }    }    if ( from.sin_family != AF_INET ) {      syslog(LOG_ERR, "received address was not AF_INET, please check your inetd config");      exit(EX_PROTOCOL);    }    if ( standalone && myaddr.sin_addr.s_addr == INADDR_ANY ) {      /* myrecvfrom() didn't capture the source address; but we might	 have bound to a specific address, if so we should use it */      memcpy(&myaddr.sin_addr, &bindaddr.sin_addr, sizeof bindaddr.sin_addr);    }    /*     * Now that we have read the request packet from the UDP     * socket, we fork and go back to listening to the socket.     */    pid = fork();    if (pid < 0) {      syslog(LOG_ERR, "fork: %m");      exit(EX_OSERR);	/* Return to inetd, just in case */    } else if ( pid == 0 )      break;			/* Child exit, parent loop */  }    /* Child process: handle the actual request here */    /* Ignore SIGHUP */  set_signal(SIGHUP, SIG_IGN, 0);  #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(EX_NOPERM);	/* Access denied */  } else if ( allow_severity != -1 ) {    syslog(allow_severity, "connect from %s",	   inet_ntoa(from.sin_addr));  }#endif  /* Close file descriptors we don't need */  close(fd);    /* Get a socket.  This has to be done before the chroot(), since     some systems require access to /dev to create a socket. */    peer = socket(AF_INET, SOCK_DGRAM, 0);  if (peer < 0) {    syslog(LOG_ERR, "socket: %m");    exit(EX_IOERR);  }  /* Set up the supplementary group access list if possible */  /* /etc/group still need to be accessible at this point */#ifdef HAVE_INITGROUPS  setrv = initgroups(user, pw->pw_gid);  if ( setrv ) {    syslog(LOG_ERR, "cannot set groups for user %s", user);    exit(EX_OSERR);  }#else#ifdef HAVE_SETGROUPS  if ( setgroups(0, NULL) ) {    syslog(LOG_ERR, "cannot clear group list");  }#endif#endif  /* Chroot and drop privileges */  if (secure) {    if (chroot(".")) {      syslog(LOG_ERR, "chroot: %m");      exit(EX_OSERR);    }#ifdef __CYGWIN__    chdir("/");			/* Cygwin chroot() bug workaround */#endif  }#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(EX_OSERR);  }    /* Other basic setup */  from.sin_family = AF_INET;    /* Process the request... */    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(EX_IOERR);  }  if (connect(peer, (struct sockaddr *)&from, sizeof from) < 0) {    syslog(LOG_ERR, "connect: %m");    exit(EX_IOERR);  }  tp = (struct tftphdr *)buf;  tp_opcode = ntohs(tp->th_opcode);  if (tp_opcode == RRQ || tp_opcode == WRQ)    tftp(tp, n);  exit(0);}char   *rewrite_access(char *, int, const char **);int	validate_access(char *, int, struct formats *, const char **);void	tftp_sendfile(struct formats *, struct tftphdr *, int);void	tftp_recvfile(struct formats *, struct tftphdr *, int);struct formats {  const char *f_mode;  char	*(*f_rewrite)(char *, int, const char **);  int	(*f_validate)(char *, int, struct formats *, const char **);  void	(*f_send)(struct formats *, struct tftphdr *, int);  void	(*f_recv)(struct formats *, struct tftphdr *, int);  int	f_convert;} formats[] = {  { "netascii", rewrite_access, validate_access, tftp_sendfile, tftp_recvfile, 1 },  { "octet",	rewrite_access, validate_access, tftp_sendfile, tftp_recvfile, 0 },  { NULL, NULL, NULL, NULL, NULL, 0 }};/* * Handle initial connection protocol. */inttftp(struct tftphdr *tp, int size){  char *cp, *end;  int argn, ecode;  struct formats *pf = NULL;  char *origfilename;  char *filename, *mode = NULL;  const char *errmsgptr;  u_short tp_opcode = ntohs(tp->th_opcode);    char *val = NULL, *opt = NULL;  char *ap = ackbuf + 2;  ((struct tftphdr *)ackbuf)->th_opcode = htons(OACK);    origfilename = cp = (char *) &(tp->th_stuff);  argn = 0;    end = (char *)tp + size;  while ( cp < end && *cp ) {    do {      cp++;    } while (cp < end && *cp);        if ( *cp ) {      nak(EBADOP, "Request not null-terminated");      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, "Unknown mode");	exit(0);      }      if ( !(filename =	     (*pf->f_rewrite)(origfilename, tp_opcode, &errmsgptr)) ) {	nak(EACCESS, errmsgptr); /* File denied by mapping rule */	exit(0);      }      if ( verbosity >= 1 ) {	if ( filename == origfilename || !strcmp(filename, origfilename) )	  syslog(LOG_NOTICE, "%s from %s filename %s\n",		 tp_opcode == WRQ ? "WRQ" : "RRQ",		 inet_ntoa(from.sin_addr), filename);	else	  syslog(LOG_NOTICE, "%s from %s filename %s remapped to %s\n",		 tp_opcode == WRQ ? "WRQ" : "RRQ",		 inet_ntoa(from.sin_addr), origfilename, filename);      }		         ecode = (*pf->f_validate)(filename, tp_opcode, pf, &errmsgptr);      if (ecode) {	nak(ecode, errmsgptr);	exit(0);      }      opt = ++cp;    } else if ( argn & 1 ) {      val = ++cp;    } else {      do_opt(opt, val, &ap);      opt = ++cp;    }  }    if (!pf) {    nak(EBADOP, "Missing mode");    exit(0);  }    if ( ap != (ackbuf+2) ) {    if ( tp_opcode == WRQ )      (*pf->f_recv)(pf, (struct tftphdr *)ackbuf, ap-ackbuf);    else      (*pf->f_send)(pf, (struct tftphdr *)ackbuf, ap-ackbuf);  } else {    if (tp_opcode == WRQ)      (*pf->f_recv)(pf, NULL, 0);    else      (*pf->f_send)(pf, NULL, 0);  }  exit(0);			/* Request completed */}static int blksize_set;/* * Set a non-standard block size (c.f. RFC2348) */intset_blksize(char *val, char **ret){  static char b_ret[6];  unsigned int sz;  char *vend;    sz = (unsigned int)strtoul(val, &vend, 10);    if ( blksize_set || *vend )    return 0;    if (sz < 8)    return(0);  else if (sz > max_blksize)    sz = max_blksize;    segsize = sz;  sprintf(*ret = b_ret, "%u", sz);    blksize_set = 1;    return(1);}/* * Set a power-of-two block size (nonstandard) */intset_blksize2(char *val, char **ret){  static char b_ret[6];  unsigned int sz;  char *vend;    sz = (unsigned int)strtoul(val, &vend, 10);    if ( blksize_set || *vend )    return 0;    if (sz < 8)    return(0);  else if (sz > max_blksize)    sz = max_blksize;    /* 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. */intset_tsize(char *val, char **ret){  static char b_ret[sizeof(uintmax_t)*CHAR_BIT/3+2];  uintmax_t sz;  char *vend;  sz = strtoumax(val, &vend, 10);    if ( !tsize_ok || *vend )    return 0;    if (sz == 0)    sz = (uintmax_t)tsize;  sprintf(*ret = b_ret, "%"PRIuMAX, sz);  return(1);}/* * Set the timeout (c.f. RFC2349).  This is supposed * to be the (default) retransmission timeout, but being an * integer in seconds it seems a bit limited. */intset_timeout(char *val, char **ret){  static char b_ret[4];  unsigned long to;  char *vend;  to = strtoul(val, &vend, 10);  if ( to < 1 || to > 255 || *vend )    return 0;    rexmtval = timeout = to*1000000UL;  maxtimeout = rexmtval*TIMEOUT_LIMIT;    sprintf(*ret = b_ret, "%lu", to);  return(1);}/* Similar, but in microseconds.  We allow down to 10 ms. */intset_utimeout(char *val, char **ret){  static char b_ret[4];  unsigned long to;  char *vend;  to = strtoul(val, &vend, 10);

⌨️ 快捷键说明

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