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 }