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