Home | History | Annotate | Download | only in in.ftpd
      1 /*
      2  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      7 
      8 /****************************************************************************
      9 
     10   Copyright (c) 1999,2000 WU-FTPD Development Group.
     11   All rights reserved.
     12 
     13   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
     14     The Regents of the University of California.
     15   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
     16   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
     17   Portions Copyright (c) 1989 Massachusetts Institute of Technology.
     18   Portions Copyright (c) 1998 Sendmail, Inc.
     19   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman.
     20   Portions Copyright (c) 1997 by Stan Barber.
     21   Portions Copyright (c) 1997 by Kent Landfield.
     22   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
     23     Free Software Foundation, Inc.
     24 
     25   Use and distribution of this software and its source code are governed
     26   by the terms and conditions of the WU-FTPD Software License ("LICENSE").
     27 
     28   If you did not receive a copy of the license, it may be obtained online
     29   at http://www.wu-ftpd.org/license.html.
     30 
     31   $Id: ftprestart.c,v 1.7 2000/07/01 18:17:39 wuftpd Exp $
     32 
     33 ****************************************************************************/
     34 /* ftprestart
     35    **
     36    ** removes the ftpd shutdown files.
     37    **
     38    **  In the previous versions of the wu-ftpd server it was recommended to
     39    **  create a link in order for shutdown to work properly for real and
     40    **  anonymous user, e.g.  If you use ftpshut, it will create a message
     41    **  file at the location specified in the ftpaccess shutdown directive.
     42    **  ln -s /etc/shutmsg  ~ftp/etc/shutmsg
     43    **
     44    **  When ftp service is to be restarted after an ftpshut, the shutdown
     45    **  message files must be removed. This program reads the ftpaccess
     46    **  file and finds the location of the system shutdown file.  It
     47    **  then proceeds to construct a path to the anonymous ftp area with
     48    **  information found in the "ftp" account.  If virtual ftp servers
     49    **  are enabled, the shutdown message files within those directories
     50    **  are also removed.
     51    **
     52    **  Initial Author: Kent Landfield
     53  */
     54 #include "config.h"
     55 
     56 #include <errno.h>
     57 #include <stdio.h>
     58 #include <string.h>
     59 #include <ctype.h>
     60 #include <sys/stat.h>
     61 #include <sys/param.h>
     62 #include <pwd.h>
     63 #if defined(VIRTUAL) && defined(INET6)
     64 #include <netinet/in.h>
     65 #endif
     66 
     67 #include "pathnames.h"
     68 
     69 #define MAXVIRTUALS 512
     70 
     71 char *progname;
     72 char *msgfiles[MAXVIRTUALS];
     73 int numfiles = 0;
     74 
     75 #ifdef VIRTUAL
     76 extern int read_servers_line(FILE *, char *, size_t, char *, size_t);
     77 #endif
     78 
     79 void print_copyright(void);
     80 
     81 static int newfile(char *fpath)
     82 {
     83     int i;
     84     int fnd;
     85 
     86     /*
     87        ** Check to see if the message file path has already been
     88        ** seen. If so then there is no need to create it again.
     89      */
     90 
     91     fnd = 0;
     92     for (i = 0; i < numfiles; i++) {
     93 	if (strcmp(msgfiles[i], fpath) == 0) {
     94 	    fnd = 1;
     95 	    break;
     96 	}
     97     }
     98     if (!fnd) {
     99 	msgfiles[numfiles++] = strdup(fpath);
    100 	return (1);
    101     }
    102     return (0);
    103 }
    104 
    105 static int remove_shutdown_file(char *path)
    106 {
    107     struct stat stbuf;
    108     int rc = 1;			/* guilty until proven innocent */
    109 
    110     fprintf(stderr, "%s: %s ", progname, path);
    111 
    112     if (stat(path, &stbuf) == 0) {
    113 	if ((rc = unlink(path)) == 0)
    114 	    fprintf(stderr, "removed.\n");
    115 	else
    116 	    perror(path);
    117     }
    118     else
    119 	fprintf(stderr, "does not exist.\n");
    120 
    121     return (rc);
    122 }
    123 
    124 int main(int argc, char **argv)
    125 {
    126     int c;
    127 
    128     char *p;
    129     char *cp = NULL;
    130     char linebuf[BUFSIZ];
    131     char shutmsg[256];
    132     char anonpath[MAXPATHLEN];
    133     FILE *accessfile;
    134     struct passwd *pw;
    135 
    136 #if defined(VIRTUAL)
    137     FILE *svrfp;
    138     char *sp;
    139 #ifdef INET6
    140     char hostaddress[INET6_ADDRSTRLEN];
    141 #else
    142     char hostaddress[32];
    143 #endif
    144     char root[MAXPATHLEN];
    145     char configdir[MAXPATHLEN];
    146     char accesspath[MAXPATHLEN];
    147     char altmsgpath[MAXPATHLEN];
    148     struct stat finfo;
    149 #endif
    150 
    151     if ((progname = strrchr(argv[0], '/')))
    152 	++progname;
    153     else
    154 	progname = argv[0];
    155 
    156     if (argc > 1) {
    157 	while ((c = getopt(argc, argv, "V")) != EOF) {
    158 	    switch (c) {
    159 	    case 'V':
    160 		print_copyright();
    161 		exit(0);
    162 	    default:
    163 		fprintf(stderr, "usage: %s [-V]\n", progname);
    164 		exit(1);
    165 	    }
    166 	}
    167     }
    168 
    169     if ((accessfile = fopen(_PATH_FTPACCESS, "r")) == NULL) {
    170 	if (errno != ENOENT)
    171 	    fprintf(stderr, "%s: could not open access file %s: %s\n",
    172 		    progname, _PATH_FTPACCESS, strerror(errno));
    173 	exit(1);
    174     }
    175 
    176     /*
    177        ** Search the access file for the 'shutdown' directive.
    178      */
    179 
    180     while (fgets(linebuf, BUFSIZ, accessfile) != NULL) {
    181 	if (strncasecmp(linebuf, "shutdown", 8) == 0) {
    182 	    (void) strtok(linebuf, " \t");
    183 	    (void) strlcpy(shutmsg, strtok(NULL, " \t"), sizeof(shutmsg));
    184 	    cp = shutmsg;
    185 	    if ((p = strchr(cp, '\n')) != NULL)
    186 		*p = '\0';
    187 	}
    188     }
    189 
    190     if (cp == NULL) {
    191 	fprintf(stderr, "%s: no shutdown path defined in ftpaccess file %s.\n",
    192                 progname, _PATH_FTPACCESS);
    193 	exit(1);
    194     }
    195 
    196     msgfiles[numfiles++] = shutmsg;
    197 
    198     /*
    199        ** Get the location of the anonymous ftp area and check
    200        ** to see if there is a file shutdown file there as well.
    201        ** If so, remove it.
    202      */
    203     if ((pw = getpwnam("ftp")) != NULL) {
    204 	(void) snprintf(anonpath, sizeof(anonpath), "%s%s", pw->pw_dir,
    205 	    shutmsg);
    206 	if (newfile(anonpath))
    207 	    (void) remove_shutdown_file(anonpath);
    208     }
    209 
    210 #ifdef VIRTUAL
    211     /*
    212        ** Search the access file for virtual ftp servers.
    213        ** If found, check if there are links/shutdown
    214        ** message files files in the virtual server areas.
    215        ** If so, remove them.
    216      */
    217 
    218     rewind(accessfile);
    219 
    220     while (fgets(linebuf, sizeof(linebuf) - 1, accessfile) != NULL) {
    221 	if (strncasecmp(linebuf, "virtual", 7) == 0) {
    222 	    if ((p = strstr(linebuf, "root")) != NULL) {
    223 		p += 4;
    224 
    225 		if ((cp = strchr(linebuf, '\n')) != NULL)
    226 		    *cp = '\0';
    227 
    228 		/* skip to the path */
    229 
    230 		while (*p && isspace(*p))
    231 		    p++;
    232 		cp = p;
    233 		while (*p && isalnum(*p))
    234 		    p++;
    235 
    236 		(void) snprintf(altmsgpath, sizeof(altmsgpath), "%s%s", cp,
    237 		    shutmsg);
    238 		if (newfile(altmsgpath))
    239 		    (void) remove_shutdown_file(altmsgpath);
    240 	    }
    241 	}
    242     }
    243 
    244 
    245     /*
    246        ** Need to deal with the access files at the virtual domain directory
    247        ** locations specified in the ftpservers file.
    248      */
    249 
    250     if ((svrfp = fopen(_PATH_FTPSERVERS, "r")) != NULL) {
    251 	while (read_servers_line(svrfp, hostaddress, sizeof(hostaddress),
    252 	       configdir, sizeof(configdir)) == 1) {
    253 	    /* get rid of any trailing slash */
    254 	    sp = configdir + (strlen(configdir) - 1);
    255 	    if (*sp == '/')
    256 		*sp = '\0';
    257 
    258 	    /*
    259 	       ** check to see that a valid directory value was
    260 	       ** supplied and not something such as "INTERNAL"
    261 	       **
    262 	       ** It is valid to have a string such as "INTERNAL" in the
    263 	       ** ftpservers entry. This is not an error. Silently ignore it.
    264 	     */
    265 
    266 	    if ((stat(configdir, &finfo) < 0) ||
    267 		((finfo.st_mode & S_IFMT) != S_IFDIR))
    268 		continue;
    269 
    270 	    (void) snprintf(accesspath, sizeof(accesspath), "%s/ftpaccess",
    271 		configdir);
    272 
    273 	    (void) fclose(accessfile);
    274 
    275 	    if ((accessfile = fopen(accesspath, "r")) == NULL) {
    276 		if (errno != ENOENT) {
    277 		    fprintf(stderr, "%s: could not open access file %s: %s\n",
    278 			    progname, accesspath, strerror(errno));
    279 		    continue;
    280 		}
    281 	    }
    282 
    283 	    /* need to find the root path */
    284 
    285 	    while (fgets(linebuf, sizeof(linebuf) - 1, accessfile) != NULL) {
    286 		if ((sp = strstr(linebuf, "root")) != NULL) {
    287 		    if ((cp = strchr(sp, '\n')) != NULL)
    288 			*cp = '\0';	/* strip newline */
    289 		    sp += 4;	/* skip past "root" keyword */
    290 
    291 		    while (*sp && isspace(*sp))		/* skip whitespace to path */
    292 			sp++;
    293 		    cp = sp;
    294 		    while (*sp && !isspace(*sp))
    295 			sp++;
    296 		    *sp = '\0';	/* truncate blanks, comments etc. */
    297 		    (void) strlcpy(root, cp, sizeof(root));
    298 		    break;
    299 		}
    300 	    }
    301 
    302 	    rewind(accessfile);
    303 
    304 	    /* need to find the shutdown message file path */
    305 
    306 	    while (fgets(linebuf, sizeof(linebuf) - 1, accessfile) != NULL) {
    307 		if ((sp = strstr(linebuf, "shutdown")) != NULL) {
    308 		    if ((cp = strchr(sp, '\n')) != NULL)
    309 			*cp = '\0';	/* strip newline */
    310 		    sp += 8;	/* skip past "root" keyword */
    311 
    312 		    while (*sp && isspace(*sp))		/* skip whitespace to path */
    313 			sp++;
    314 		    cp = sp;
    315 		    while (*sp && !isspace(*sp))
    316 			sp++;
    317 		    *sp = '\0';	/* truncate blanks, comments etc. */
    318 		    break;
    319 		}
    320 	    }
    321 
    322 	    /*
    323 	       ** check to make sure the admin hasn't specified
    324 	       ** a complete path in the 'shutdown' directive.
    325 	     */
    326 	    if ((sp = strstr(cp, root)) == NULL)
    327 		(void) snprintf(altmsgpath, sizeof(altmsgpath), "%s%s", root,
    328 		    cp);
    329 
    330 	    if (newfile(altmsgpath))
    331 		(void) remove_shutdown_file(altmsgpath);
    332 	}
    333 	fclose(svrfp);
    334     }
    335 #endif /* VIRTUAL */
    336 
    337     fclose(accessfile);
    338 
    339     /*
    340        ** Time to remove the system wide shutdown file.
    341      */
    342     return (remove_shutdown_file(shutmsg));
    343 }
    344