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

📄 tftpd.c

📁 linux下tftp服务器端的源码实现
💻 C
📖 第 1 页 / 共 2 页
字号:
 */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;      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 */	      synchnet (peer);	      if ((u_short) ap->th_block == (u_short) (block - 1))		goto send_data;	    }	}      block++;    }  while (size == SEGSIZE);abort:  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++;      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 */	      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);  fclose (file);		/* close data file */  ap->th_opcode = htons ((u_short) ACK);	/* send the "final" ack */  ap->th_block = htons ((u_short) (block));  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 */      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);}static const char usage_str[] =  "Usage: tftpd [OPTIONS...]\n"  "\n"  "Options are:\n"  "   -l                      Enable logging\n"  "   -n                      Supress negative acknowledgement of\n"  "                           requests for nonexistent relative filenames\n"  "       --help              Display usage instructions\n"  "       --version           Display program version\n";voidusage (void){  printf ("%s\n" "Send bug reports to <%s>\n", usage_str, PACKAGE_BUGREPORT);}

⌨️ 快捷键说明

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