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

📄 tftpd.c

📁 linux下tftp服务器端的源码实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1983, 1993 *	The 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. * 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 lintstatic char copyright[] = "@(#) Copyright (c) 1983, 1993\n\	The Regents of the University of California.  All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)tftpd.c	8.1 (Berkeley) 6/4/93";#endif /* not lint *//* * Trivial file transfer protocol server. * * This version includes many modifications by Jim Guyton * <guyton@rand-unix>. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <sys/param.h>#include <sys/ioctl.h>#ifdef HAVE_SYS_FILIO_H#include <sys/filio.h>#endif#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/tftp.h>#include <arpa/inet.h>#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <getopt.h>#include <netdb.h>#include <setjmp.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <syslog.h>#include <unistd.h>#include "tftpsubs.h"void usage (void);#define	TIMEOUT		5#ifndef LOG_FTP#define LOG_FTP LOG_DAEMON	/* Use generic facility.  */#endifint peer;int rexmtval = TIMEOUT;int maxtimeout = 5 * TIMEOUT;#define	PKTSIZE	SEGSIZE+4char buf[PKTSIZE];char ackbuf[PKTSIZE];struct sockaddr_in from;int fromlen;void tftp (struct tftphdr *, int);/* * Null-terminated directory prefix list for absolute pathname requests and * search list for relative pathname requests. * * MAXDIRS should be at least as large as the number of arguments that * inetd allows (currently 20). */#define MAXDIRS	20static struct dirlist{  char *name;  int len;} dirs[MAXDIRS + 1];static int suppress_naks;static int logging;static const char *errtomsg (int);static void nak (int);static const char *verifyhost (struct sockaddr_in *);static const char *short_options = "hVln";static struct option long_options[] = {  {"help", no_argument, 0, 'h'},  {"version", no_argument, 0, 'V'},  {0}};intmain (int argc, char *argv[]){  register struct tftphdr *tp;  register int n;  int ch, on;  struct sockaddr_in sin;  openlog ("tftpd", LOG_PID, LOG_FTP);  while ((ch = getopt_long (argc, argv, short_options, long_options, NULL))	 != EOF)    {      switch (ch)	{	case 'l':	  logging = 1;	  break;	case 'n':	  suppress_naks = 1;	  break;	case 'V':	  printf ("tftpd (%s %s)\n", PACKAGE_NAME, PACKAGE_VERSION);	  exit (0);	case 'h':	  usage ();	  exit (0);	default:	  syslog (LOG_WARNING, "ignoring unknown option -%c", ch);	}    }  if (optind < argc)    {      struct dirlist *dirp;      /* Get list of directory prefixes. Skip relative pathnames. */      for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS]; optind++)	{	  if (argv[optind][0] == '/')	    {	      dirp->name = argv[optind];	      dirp->len = strlen (dirp->name);	      dirp++;	    }	}    }  on = 1;  if (ioctl (0, FIONBIO, &on) < 0)    {      syslog (LOG_ERR, "ioctl(FIONBIO): %m\n");      exit (1);    }  fromlen = sizeof (from);  n = recvfrom (0, buf, sizeof (buf), 0, (struct sockaddr *) &from, &fromlen);  if (n < 0)    {      syslog (LOG_ERR, "recvfrom: %m\n");      exit (1);    }  /*   * Now that we have read the message out of the UDP   * socket, we fork and exit.  Thus, inetd will go back   * to listening to the tftp port, and the next request   * to come in will start up a new instance of tftpd.   *   * We do this so that inetd can run tftpd in "wait" mode.   * The problem with tftpd running in "nowait" mode is that   * inetd may get one or more successful "selects" on the   * tftp port before we do our receive, so more than one   * instance of tftpd may be started up.  Worse, if tftpd   * break before doing the above "recvfrom", inetd would   * spawn endless instances, clogging the system.   */  {    int pid;    int i, j;    for (i = 1; i < 20; i++)      {	pid = fork ();	if (pid < 0)	  {	    sleep (i);	    /*	     * flush out to most recently sent request.	     *	     * This may drop some request, but those	     * will be resent by the clients when	     * they timeout.  The positive effect of	     * this flush is to (try to) prevent more	     * than one tftpd being started up to service	     * a single request from a single client.	     */	    j = sizeof from;	    i = recvfrom (0, buf, sizeof (buf), 0,			  (struct sockaddr *) &from, &j);	    if (i > 0)	      {		n = i;		fromlen = j;	      }	  }	else	  {	    break;	  }      }    if (pid < 0)      {	syslog (LOG_ERR, "fork: %m\n");	exit (1);      }    else if (pid != 0)      {	exit (0);      }  }  from.sin_family = AF_INET;  alarm (0);  close (0);  close (1);  peer = socket (AF_INET, SOCK_DGRAM, 0);  if (peer < 0)    {      syslog (LOG_ERR, "socket: %m\n");      exit (1);    }  memset (&sin, 0, sizeof (sin));  sin.sin_family = AF_INET;  if (bind (peer, (struct sockaddr *) &sin, sizeof (sin)) < 0)    {      syslog (LOG_ERR, "bind: %m\n");      exit (1);    }  if (connect (peer, (struct sockaddr *) &from, sizeof (from)) < 0)    {      syslog (LOG_ERR, "connect: %m\n");      exit (1);    }  tp = (struct tftphdr *) buf;  tp->th_opcode = ntohs (tp->th_opcode);  if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)    tftp (tp, n);  exit (1);}struct formats;int validate_access (char **, int);void send_file (struct formats *);void recvfile (struct formats *);struct formats{  char *f_mode;  int (*f_validate) (char **, int);  void (*f_send) (struct formats *);  void (*f_recv) (struct formats *);  int f_convert;} formats[] = {  {"netascii", validate_access, send_file, recvfile, 1},  {"octet", validate_access, send_file, recvfile, 0},#ifdef notdef  {"mail", validate_user, sendmail, recvmail, 1},#endif  {0}};/* * Handle initial connection protocol. */voidtftp (struct tftphdr *tp, int size){  register char *cp;  int first = 1, ecode;  register struct formats *pf;  char *filename, *mode;  filename = cp = tp->th_stuff;again:  while (cp < buf + size)    {      if (*cp == '\0')	break;      cp++;    }  if (*cp != '\0')    {      nak (EBADOP);      exit (1);    }  if (first)    {      mode = ++cp;      first = 0;      goto again;    }  for (cp = mode; *cp; cp++)    if (isupper (*cp))      *cp = tolower (*cp);  for (pf = formats; pf->f_mode; pf++)    if (strcmp (pf->f_mode, mode) == 0)      break;  if (pf->f_mode == 0)    {      nak (EBADOP);      exit (1);    }  ecode = (*pf->f_validate) (&filename, tp->th_opcode);  if (logging)    {      syslog (LOG_INFO, "%s: %s request for %s: %s",	      verifyhost (&from),	      tp->th_opcode == WRQ ? "write" : "read",	      filename, errtomsg (ecode));    }  if (ecode)    {      /*       * Avoid storms of naks to a RRQ broadcast for a relative       * bootfile pathname from a diskless Sun.       */      if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)	exit (0);      nak (ecode);      exit (1);    }  if (tp->th_opcode == WRQ)    (*pf->f_recv) (pf);  else    (*pf->f_send) (pf);  exit (0);}FILE *file;/* * Validate file access.  Since we * have no uid or gid, for now require * file to exist and be publicly * 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.

⌨️ 快捷键说明

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