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 }