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
newfile(char * fpath)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
remove_shutdown_file(char * path)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
main(int argc,char ** argv)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