xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/ftprestart.c (revision 0:68f95e015346)
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