xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/access.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2005 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: access.c,v 1.30 2000/07/01 18:17:38 wuftpd Exp $
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate ****************************************************************************/
34*0Sstevel@tonic-gate #include "config.h"
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate #include <stdio.h>
37*0Sstevel@tonic-gate #include <errno.h>
38*0Sstevel@tonic-gate #include <string.h>
39*0Sstevel@tonic-gate #include <stdlib.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #ifdef HAVE_SYS_SYSLOG_H
42*0Sstevel@tonic-gate #include <sys/syslog.h>
43*0Sstevel@tonic-gate #endif
44*0Sstevel@tonic-gate #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))
45*0Sstevel@tonic-gate #include <syslog.h>
46*0Sstevel@tonic-gate #endif
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #ifdef TIME_WITH_SYS_TIME
49*0Sstevel@tonic-gate #include <time.h>
50*0Sstevel@tonic-gate #include <sys/time.h>
51*0Sstevel@tonic-gate #elif defined(HAVE_SYS_TIME_H)
52*0Sstevel@tonic-gate #include <sys/time.h>
53*0Sstevel@tonic-gate #else
54*0Sstevel@tonic-gate #include <time.h>
55*0Sstevel@tonic-gate #endif
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate #include <ctype.h>
58*0Sstevel@tonic-gate #include <pwd.h>
59*0Sstevel@tonic-gate #include <grp.h>
60*0Sstevel@tonic-gate #include <limits.h>
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate #include <sys/types.h>
63*0Sstevel@tonic-gate #include <sys/stat.h>
64*0Sstevel@tonic-gate #include <sys/file.h>
65*0Sstevel@tonic-gate #include <sys/param.h>
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate #ifdef HAVE_PATHS_H
68*0Sstevel@tonic-gate #include <paths.h>
69*0Sstevel@tonic-gate #endif
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate #include "pathnames.h"
72*0Sstevel@tonic-gate #include "extensions.h"
73*0Sstevel@tonic-gate #include "proto.h"
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate #if defined(HAVE_FCNTL_H)
76*0Sstevel@tonic-gate #include <fcntl.h>
77*0Sstevel@tonic-gate #endif
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate #ifdef OTHER_PASSWD
80*0Sstevel@tonic-gate #include "getpwnam.h"
81*0Sstevel@tonic-gate extern char _path_passwd[];
82*0Sstevel@tonic-gate #ifdef SHADOW_PASSWORD
83*0Sstevel@tonic-gate extern char _path_shadow[];
84*0Sstevel@tonic-gate #endif
85*0Sstevel@tonic-gate #endif
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate #if defined(USE_PAM) && defined(OTHER_PASSWD)
88*0Sstevel@tonic-gate extern int use_pam;
89*0Sstevel@tonic-gate #endif
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate extern char remotehost[], remoteaddr[], *remoteident, *aclbuf;
92*0Sstevel@tonic-gate extern int nameserved, anonymous, guest, TCPwindowsize, use_accessfile;
93*0Sstevel@tonic-gate extern mode_t defumask;
94*0Sstevel@tonic-gate char Shutdown[MAXPATHLEN];
95*0Sstevel@tonic-gate int keepalive = 0;
96*0Sstevel@tonic-gate #define MAXLINE	80
97*0Sstevel@tonic-gate static char incline[MAXLINE];
98*0Sstevel@tonic-gate static int pidfd = -1;
99*0Sstevel@tonic-gate extern int Bypass_PID_Files;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate #ifndef HELP_CRACKERS
102*0Sstevel@tonic-gate extern char DelayedMessageFile[];
103*0Sstevel@tonic-gate #endif
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate #include "wu_fnmatch.h"
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate #define ACL_COUNT	0
108*0Sstevel@tonic-gate #define ACL_JOIN	1
109*0Sstevel@tonic-gate #define ACL_REMOVE	2
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate /*************************************************************************/
112*0Sstevel@tonic-gate /* FUNCTION  : parse_time                                                */
113*0Sstevel@tonic-gate /* PURPOSE   : Check a single valid-time-string against the current time */
114*0Sstevel@tonic-gate /*             and return whether or not a match occurs.                 */
115*0Sstevel@tonic-gate /* ARGUMENTS : a pointer to the time-string                              */
116*0Sstevel@tonic-gate /*************************************************************************/
117*0Sstevel@tonic-gate 
parsetime(char * whattime)118*0Sstevel@tonic-gate int parsetime(char *whattime)
119*0Sstevel@tonic-gate {
120*0Sstevel@tonic-gate     static char *days[] =
121*0Sstevel@tonic-gate     {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Wk"};
122*0Sstevel@tonic-gate     time_t clock;
123*0Sstevel@tonic-gate     struct tm *curtime;
124*0Sstevel@tonic-gate     int wday, start, stop, ltime, validday, loop, match;
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate     (void) time(&clock);
127*0Sstevel@tonic-gate     curtime = localtime(&clock);
128*0Sstevel@tonic-gate     wday = curtime->tm_wday;
129*0Sstevel@tonic-gate     validday = 0;
130*0Sstevel@tonic-gate     match = 1;
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate     while (match && isalpha(*whattime) && isupper(*whattime)) {
133*0Sstevel@tonic-gate 	match = 0;
134*0Sstevel@tonic-gate 	for (loop = 0; loop < 8; loop++) {
135*0Sstevel@tonic-gate 	    if (strncmp(days[loop], whattime, 2) == 0) {
136*0Sstevel@tonic-gate 		whattime += 2;
137*0Sstevel@tonic-gate 		match = 1;
138*0Sstevel@tonic-gate 		if ((wday == loop) || ((loop == 7) && wday && (wday < 6))) {
139*0Sstevel@tonic-gate 		    validday = 1;
140*0Sstevel@tonic-gate 		}
141*0Sstevel@tonic-gate 	    }
142*0Sstevel@tonic-gate 	}
143*0Sstevel@tonic-gate     }
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate     if (!validday) {
146*0Sstevel@tonic-gate 	if (strncmp(whattime, "Any", 3) == 0) {
147*0Sstevel@tonic-gate 	    validday = 1;
148*0Sstevel@tonic-gate 	    whattime += 3;
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 	else
151*0Sstevel@tonic-gate 	    return (0);
152*0Sstevel@tonic-gate     }
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate     if (sscanf(whattime, "%d-%d", &start, &stop) == 2) {
155*0Sstevel@tonic-gate 	ltime = curtime->tm_min + 100 * curtime->tm_hour;
156*0Sstevel@tonic-gate 	if ((start < stop) && ((ltime >= start) && ltime < stop))
157*0Sstevel@tonic-gate 	    return (1);
158*0Sstevel@tonic-gate 	if ((start > stop) && ((ltime >= start) || ltime < stop))
159*0Sstevel@tonic-gate 	    return (1);
160*0Sstevel@tonic-gate     }
161*0Sstevel@tonic-gate     else
162*0Sstevel@tonic-gate 	return (1);
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate     return (0);
165*0Sstevel@tonic-gate }
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate /*************************************************************************/
168*0Sstevel@tonic-gate /* FUNCTION  : validtime                                                 */
169*0Sstevel@tonic-gate /* PURPOSE   : Break apart a set of valid time-strings and pass them to  */
170*0Sstevel@tonic-gate /*             parse_time, returning whether or not ANY matches occurred */
171*0Sstevel@tonic-gate /* ARGUMENTS : a pointer to the time-string                              */
172*0Sstevel@tonic-gate /*************************************************************************/
173*0Sstevel@tonic-gate 
validtime(char * ptr)174*0Sstevel@tonic-gate int validtime(char *ptr)
175*0Sstevel@tonic-gate {
176*0Sstevel@tonic-gate     char *nextptr;
177*0Sstevel@tonic-gate     int good;
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate     while (1) {
180*0Sstevel@tonic-gate 	nextptr = strchr(ptr, '|');
181*0Sstevel@tonic-gate 	if (strchr(ptr, '|') == NULL)
182*0Sstevel@tonic-gate 	    return (parsetime(ptr));
183*0Sstevel@tonic-gate 	*nextptr = '\0';
184*0Sstevel@tonic-gate 	good = parsetime(ptr);
185*0Sstevel@tonic-gate 	/* gotta restore the | or things get skipped! */
186*0Sstevel@tonic-gate 	*nextptr++ = '|';
187*0Sstevel@tonic-gate 	if (good)
188*0Sstevel@tonic-gate 	    return (1);
189*0Sstevel@tonic-gate 	ptr = nextptr;
190*0Sstevel@tonic-gate     }
191*0Sstevel@tonic-gate }
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate #ifdef INET6
194*0Sstevel@tonic-gate /*************************************************************************/
195*0Sstevel@tonic-gate /* FUNCTION  : ipv6str                                                   */
196*0Sstevel@tonic-gate /* PURPOSE   : Convert an IPv6 address string with optional /CIDR suffix */
197*0Sstevel@tonic-gate /*             into an IPv6 address and a CIDR, which are returned in    */
198*0Sstevel@tonic-gate /*             the arguments pointed to by in6p and cidrp.               */
199*0Sstevel@tonic-gate /* ARGUMENTS : The IPv6 address string and pointers to in6_addr and CIDR */
200*0Sstevel@tonic-gate /* RETURNS   : 1 if addr is an IPv6 address string, 0 if not             */
201*0Sstevel@tonic-gate /*************************************************************************/
202*0Sstevel@tonic-gate 
ipv6str(char * addr,struct in6_addr * in6p,int * cidrp)203*0Sstevel@tonic-gate static int ipv6str(char *addr, struct in6_addr *in6p, int *cidrp)
204*0Sstevel@tonic-gate {
205*0Sstevel@tonic-gate     int cidr = 128;	/* IPv6 addresses are 128-bits long */
206*0Sstevel@tonic-gate     char *ptr;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate     if ((ptr = strstr(addr, "/")))
209*0Sstevel@tonic-gate 	*ptr = '\0';
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate     if (inet_pton(AF_INET6, addr, in6p) != 1) {
212*0Sstevel@tonic-gate 	if (ptr)
213*0Sstevel@tonic-gate 	    *ptr = '/';
214*0Sstevel@tonic-gate 	return 0;
215*0Sstevel@tonic-gate     }
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate     if (ptr) {
218*0Sstevel@tonic-gate 	*ptr++ = '/';
219*0Sstevel@tonic-gate 	cidr = atoi(ptr);
220*0Sstevel@tonic-gate 	if (cidr < 0)
221*0Sstevel@tonic-gate 	    cidr = 0;
222*0Sstevel@tonic-gate 	else if (cidr > 128)
223*0Sstevel@tonic-gate 	    cidr = 128;
224*0Sstevel@tonic-gate     }
225*0Sstevel@tonic-gate     *cidrp = cidr;
226*0Sstevel@tonic-gate     return 1;
227*0Sstevel@tonic-gate }
228*0Sstevel@tonic-gate #endif
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate /*************************************************************************/
231*0Sstevel@tonic-gate /* FUNCTION  : hostmatch                                                 */
232*0Sstevel@tonic-gate /* PURPOSE   : Match remote hostname or address against a glob string    */
233*0Sstevel@tonic-gate /* ARGUMENTS : The string to match, remote address, remote hostname      */
234*0Sstevel@tonic-gate /* RETURNS   : 0 if no match, 1 if a match occurs                        */
235*0Sstevel@tonic-gate /*************************************************************************/
236*0Sstevel@tonic-gate 
hostmatch(char * addr,char * remoteaddr,char * remotehost)237*0Sstevel@tonic-gate int hostmatch(char *addr, char *remoteaddr, char *remotehost)
238*0Sstevel@tonic-gate {
239*0Sstevel@tonic-gate     FILE *incfile;
240*0Sstevel@tonic-gate     char *ptr, junk, s[4][4];
241*0Sstevel@tonic-gate     int found = 1;
242*0Sstevel@tonic-gate     int not_found = 0;
243*0Sstevel@tonic-gate     int match = 0;
244*0Sstevel@tonic-gate     int i, a[4], m[4], r[4], cidr;
245*0Sstevel@tonic-gate #ifdef INET6
246*0Sstevel@tonic-gate     struct in6_addr addr_in6;
247*0Sstevel@tonic-gate #endif
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate     if (addr == NULL)
250*0Sstevel@tonic-gate 	return (0);
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate     if (*addr == '!') {
253*0Sstevel@tonic-gate 	found = 0;
254*0Sstevel@tonic-gate 	not_found = 1;
255*0Sstevel@tonic-gate 	addr++;
256*0Sstevel@tonic-gate     }
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate     if (sscanf(addr, "%d.%d.%d.%d/%d", a, a + 1, a + 2, a + 3, &cidr) == 5) {
259*0Sstevel@tonic-gate 	m[0] = 0;
260*0Sstevel@tonic-gate 	m[1] = 0;
261*0Sstevel@tonic-gate 	m[2] = 0;
262*0Sstevel@tonic-gate 	m[3] = 0;
263*0Sstevel@tonic-gate 	if (cidr < 0)
264*0Sstevel@tonic-gate 	    cidr = 0;
265*0Sstevel@tonic-gate 	else if (cidr > 32)
266*0Sstevel@tonic-gate 	    cidr = 32;
267*0Sstevel@tonic-gate 	for (i = 0; cidr > 8; i++) {
268*0Sstevel@tonic-gate 	    m[i] = 255;
269*0Sstevel@tonic-gate 	    cidr -= 8;
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 	switch (cidr) {
272*0Sstevel@tonic-gate 	case 8:
273*0Sstevel@tonic-gate 	    m[i] += 1;
274*0Sstevel@tonic-gate 	case 7:
275*0Sstevel@tonic-gate 	    m[i] += 2;
276*0Sstevel@tonic-gate 	case 6:
277*0Sstevel@tonic-gate 	    m[i] += 4;
278*0Sstevel@tonic-gate 	case 5:
279*0Sstevel@tonic-gate 	    m[i] += 8;
280*0Sstevel@tonic-gate 	case 4:
281*0Sstevel@tonic-gate 	    m[i] += 16;
282*0Sstevel@tonic-gate 	case 3:
283*0Sstevel@tonic-gate 	    m[i] += 32;
284*0Sstevel@tonic-gate 	case 2:
285*0Sstevel@tonic-gate 	    m[i] += 64;
286*0Sstevel@tonic-gate 	case 1:
287*0Sstevel@tonic-gate 	    m[i] += 128;
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 	/* make sure remoteaddr is an IPv4 address */
290*0Sstevel@tonic-gate 	if (sscanf(remoteaddr, "%d.%d.%d.%d", r, r + 1, r + 2, r + 3) != 4)
291*0Sstevel@tonic-gate 	    return not_found;
292*0Sstevel@tonic-gate 	for (i = 0; i < 4; i++)
293*0Sstevel@tonic-gate 	    if ((a[i] & m[i]) != (r[i] & m[i]))
294*0Sstevel@tonic-gate 		return not_found;
295*0Sstevel@tonic-gate 	return found;
296*0Sstevel@tonic-gate     }
297*0Sstevel@tonic-gate     else if (sscanf(addr, "%d.%d.%d.%d:%d.%d.%d.%d", a, a + 1, a + 2, a + 3, m, m + 1, m + 2, m + 3) == 8) {
298*0Sstevel@tonic-gate 	/* make sure remoteaddr is an IPv4 address */
299*0Sstevel@tonic-gate 	if (sscanf(remoteaddr, "%d.%d.%d.%d", r, r + 1, r + 2, r + 3) != 4)
300*0Sstevel@tonic-gate 	    return not_found;
301*0Sstevel@tonic-gate 	for (i = 0; i < 4; i++)
302*0Sstevel@tonic-gate 	    if ((a[i] & m[i]) != (r[i] & m[i]))
303*0Sstevel@tonic-gate 		return not_found;
304*0Sstevel@tonic-gate 	return found;
305*0Sstevel@tonic-gate     }
306*0Sstevel@tonic-gate     else if (sscanf(addr, "%3[0-9*].%3[0-9*].%3[0-9*].%3[0-9*]%c",
307*0Sstevel@tonic-gate 		    s[0], s[1], s[2], s[3], &junk) == 4 &&
308*0Sstevel@tonic-gate 	    (!strcmp(s[0],"*") || !strchr(s[0],'*')) &&
309*0Sstevel@tonic-gate 	    (!strcmp(s[1],"*") || !strchr(s[1],'*')) &&
310*0Sstevel@tonic-gate 	    (!strcmp(s[2],"*") || !strchr(s[2],'*')) &&
311*0Sstevel@tonic-gate 	    (!strcmp(s[3],"*") || !strchr(s[3],'*'))  ) {
312*0Sstevel@tonic-gate 	/* make sure remoteaddr is an IPv4 address */
313*0Sstevel@tonic-gate 	if (sscanf(remoteaddr, "%d.%d.%d.%d", r, r + 1, r + 2, r + 3) != 4)
314*0Sstevel@tonic-gate 	    return not_found;
315*0Sstevel@tonic-gate 	for (i = 0; i < 4; i++)
316*0Sstevel@tonic-gate 	    if ( (strcmp(s[i],"*")) && (atoi(s[i]) != r[i]) )
317*0Sstevel@tonic-gate 		return not_found;
318*0Sstevel@tonic-gate 	return found;
319*0Sstevel@tonic-gate     }
320*0Sstevel@tonic-gate #ifdef INET6
321*0Sstevel@tonic-gate     else if (ipv6str(addr, &addr_in6, &cidr)) {
322*0Sstevel@tonic-gate 	struct in6_addr rem_in6;
323*0Sstevel@tonic-gate 	uint32_t addr32[4], rem32[4];
324*0Sstevel@tonic-gate 	int bitstozero;
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	if (inet_pton6(remoteaddr, &rem_in6) != 1)
327*0Sstevel@tonic-gate 	    return not_found;
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	memcpy(addr32, addr_in6.s6_addr, sizeof(addr32));
330*0Sstevel@tonic-gate 	memcpy(rem32, rem_in6.s6_addr, sizeof(rem32));
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	/* IPv6 addresses are 128-bits long */
333*0Sstevel@tonic-gate 	bitstozero = 128 - cidr;
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	/* zero bits starting with the least significant */
336*0Sstevel@tonic-gate 	for (i = 3; (bitstozero > 0) && (i >= 0); i--, bitstozero -= 32) {
337*0Sstevel@tonic-gate 	    if (bitstozero >= 32)
338*0Sstevel@tonic-gate 		addr32[i] = rem32[i] = 0;
339*0Sstevel@tonic-gate 	    else {
340*0Sstevel@tonic-gate 		addr32[i] = (ntohl(addr32[i]) >> bitstozero) << bitstozero;
341*0Sstevel@tonic-gate 		rem32[i] = (ntohl(rem32[i]) >> bitstozero) << bitstozero;
342*0Sstevel@tonic-gate 	    }
343*0Sstevel@tonic-gate 	}
344*0Sstevel@tonic-gate 	if (memcmp(addr32, rem32, sizeof(addr32)))
345*0Sstevel@tonic-gate 	    return not_found;
346*0Sstevel@tonic-gate 	return found;
347*0Sstevel@tonic-gate     }
348*0Sstevel@tonic-gate #endif
349*0Sstevel@tonic-gate     else if (*addr == '/') {
350*0Sstevel@tonic-gate 	/*
351*0Sstevel@tonic-gate 	 * read addrglobs from named path using similar format as addrglobs
352*0Sstevel@tonic-gate 	 * in access file
353*0Sstevel@tonic-gate 	 */
354*0Sstevel@tonic-gate 	if ((incfile = fopen(addr, "r")) == NULL) {
355*0Sstevel@tonic-gate 	    if (errno != ENOENT)
356*0Sstevel@tonic-gate 		syslog(LOG_ERR,
357*0Sstevel@tonic-gate 		       "cannot open addrglob file %s: %m", addr);
358*0Sstevel@tonic-gate 	    return (0);
359*0Sstevel@tonic-gate 	}
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	while (!match && (fgets(incline, MAXLINE, incfile) != NULL)) {
362*0Sstevel@tonic-gate 	    ptr = strtok(incline, " \t\n");
363*0Sstevel@tonic-gate 	    if (ptr && hostmatch(ptr, remoteaddr, remotehost))
364*0Sstevel@tonic-gate 		match = 1;
365*0Sstevel@tonic-gate 	    while (!match && ((ptr = strtok(NULL, " \t\n")) != NULL)) {
366*0Sstevel@tonic-gate 		if (ptr && hostmatch(ptr, remoteaddr, remotehost))
367*0Sstevel@tonic-gate 		    match = 1;
368*0Sstevel@tonic-gate 	    }
369*0Sstevel@tonic-gate 	}
370*0Sstevel@tonic-gate 	fclose(incfile);
371*0Sstevel@tonic-gate 	return (match ? found : not_found);
372*0Sstevel@tonic-gate     }
373*0Sstevel@tonic-gate     else {			/* match a hostname or hostname glob */
374*0Sstevel@tonic-gate 	match = (!wu_fnmatch(addr, remotehost, FNM_CASEFOLD)) ||
375*0Sstevel@tonic-gate 		(!wu_fnmatch(addr, remoteaddr, 0));
376*0Sstevel@tonic-gate 	return (match ? found : not_found);
377*0Sstevel@tonic-gate     }
378*0Sstevel@tonic-gate }
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate /*************************************************************************/
381*0Sstevel@tonic-gate /* FUNCTION  : acl_guestgroup                                            */
382*0Sstevel@tonic-gate /* PURPOSE   : If the real user is a member of any of the listed groups, */
383*0Sstevel@tonic-gate /*             return 1.  Otherwise return 0.                            */
384*0Sstevel@tonic-gate /* ARGUMENTS : pw, a pointer to the passwd struct for the user           */
385*0Sstevel@tonic-gate /*************************************************************************/
386*0Sstevel@tonic-gate 
acl_guestgroup(struct passwd * pw)387*0Sstevel@tonic-gate int acl_guestgroup(struct passwd *pw)
388*0Sstevel@tonic-gate {
389*0Sstevel@tonic-gate     /*
390*0Sstevel@tonic-gate      * guestuser <name> [<name> ...]
391*0Sstevel@tonic-gate      *
392*0Sstevel@tonic-gate      * If name begins with '%' treat as numeric.
393*0Sstevel@tonic-gate      * Numeric names may be ranges.
394*0Sstevel@tonic-gate      *   %<uid>       A single numeric UID
395*0Sstevel@tonic-gate      *   %<uid>+      All UIDs greater or equal to UID
396*0Sstevel@tonic-gate      *   %<uid>-      All UIDs greater or equal to UID
397*0Sstevel@tonic-gate      *   %-<uid>      All UIDs less or equal to UID
398*0Sstevel@tonic-gate      *   %<uid>-<uid> All UIDs between the two (inclusive)
399*0Sstevel@tonic-gate      *   *            All UIDs
400*0Sstevel@tonic-gate      */
401*0Sstevel@tonic-gate     if (uid_match("guestuser", pw->pw_uid))
402*0Sstevel@tonic-gate 	return (1);
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate     /*
405*0Sstevel@tonic-gate      * guestgroup <group> [<group> ...]
406*0Sstevel@tonic-gate      *
407*0Sstevel@tonic-gate      * If group begins with '%' treat as numeric.
408*0Sstevel@tonic-gate      * Numeric groups may be ranges.
409*0Sstevel@tonic-gate      *   %<gid>       A single GID
410*0Sstevel@tonic-gate      *   %<gid>+      All GIDs greater or equal to GID
411*0Sstevel@tonic-gate      *   %<gid>-      All GIDs greater or equal to GID
412*0Sstevel@tonic-gate      *   %-<gid>      All GIDs less or equal to GID
413*0Sstevel@tonic-gate      *   %<gid>-<gid> All GIDs between the two (inclusive)
414*0Sstevel@tonic-gate      *   *            All GIDs
415*0Sstevel@tonic-gate      */
416*0Sstevel@tonic-gate     if (gid_match("guestgroup", pw->pw_gid, pw->pw_name))
417*0Sstevel@tonic-gate 	return (1);
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate     return (0);
420*0Sstevel@tonic-gate }
421*0Sstevel@tonic-gate 
acl_realgroup(struct passwd * pw)422*0Sstevel@tonic-gate int acl_realgroup(struct passwd *pw)
423*0Sstevel@tonic-gate {
424*0Sstevel@tonic-gate     /*
425*0Sstevel@tonic-gate      * realuser <name> [<name> ...]
426*0Sstevel@tonic-gate      *
427*0Sstevel@tonic-gate      * If name begins with '%' treat as numeric.
428*0Sstevel@tonic-gate      * Numeric names may be ranges.
429*0Sstevel@tonic-gate      *   %<uid>       A single numeric UID
430*0Sstevel@tonic-gate      *   %<uid>+      All UIDs greater or equal to UID
431*0Sstevel@tonic-gate      *   %<uid>-      All UIDs greater or equal to UID
432*0Sstevel@tonic-gate      *   %-<uid>      All UIDs less or equal to UID
433*0Sstevel@tonic-gate      *   %<uid>-<uid> All UIDs between the two (inclusive)
434*0Sstevel@tonic-gate      *   *            All UIDs
435*0Sstevel@tonic-gate      */
436*0Sstevel@tonic-gate     if (uid_match("realuser", pw->pw_uid))
437*0Sstevel@tonic-gate 	return (1);
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate     /*
440*0Sstevel@tonic-gate      * realgroup <group> [<group> ...]
441*0Sstevel@tonic-gate      *
442*0Sstevel@tonic-gate      * If group begins with '%' treat as numeric.
443*0Sstevel@tonic-gate      * Numeric groups may be ranges.
444*0Sstevel@tonic-gate      *   %<gid>       A single GID
445*0Sstevel@tonic-gate      *   %<gid>+      All GIDs greater or equal to GID
446*0Sstevel@tonic-gate      *   %<gid>-      All GIDs greater or equal to GID
447*0Sstevel@tonic-gate      *   %-<gid>      All GIDs less or equal to GID
448*0Sstevel@tonic-gate      *   %<gid>-<gid> All GIDs between the two (inclusive)
449*0Sstevel@tonic-gate      *   *            All GIDs
450*0Sstevel@tonic-gate      */
451*0Sstevel@tonic-gate     if (gid_match("realgroup", pw->pw_gid, pw->pw_name))
452*0Sstevel@tonic-gate 	return (1);
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate     return (0);
455*0Sstevel@tonic-gate }
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate /*************************************************************************/
458*0Sstevel@tonic-gate /* FUNCTION  : acl_autogroup                                             */
459*0Sstevel@tonic-gate /* PURPOSE   : If the guest user is a member of any of the classes in    */
460*0Sstevel@tonic-gate /*             the autogroup comment, cause a setegid() to the specified */
461*0Sstevel@tonic-gate /*             group.                                                    */
462*0Sstevel@tonic-gate /* ARGUMENTS : pw, a pointer to the passwd struct for the user           */
463*0Sstevel@tonic-gate /*************************************************************************/
464*0Sstevel@tonic-gate 
acl_autogroup(struct passwd * pw)465*0Sstevel@tonic-gate void acl_autogroup(struct passwd *pw)
466*0Sstevel@tonic-gate {
467*0Sstevel@tonic-gate     char class[BUFSIZ];
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
470*0Sstevel@tonic-gate     struct group *grp;
471*0Sstevel@tonic-gate     int which;
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate     (void) acl_getclass(class);
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate     /* autogroup <group> <class> [<class> ...] */
476*0Sstevel@tonic-gate     while (getaclentry("autogroup", &entry)) {
477*0Sstevel@tonic-gate 	if (!ARG0 || !ARG1)
478*0Sstevel@tonic-gate 	    continue;
479*0Sstevel@tonic-gate 	for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
480*0Sstevel@tonic-gate 	    if (!strcasecmp(ARG[which], class)) {
481*0Sstevel@tonic-gate 		if (ARG0[0] == '%')
482*0Sstevel@tonic-gate 		    pw->pw_gid = atoi(ARG0 + 1);
483*0Sstevel@tonic-gate 		else {
484*0Sstevel@tonic-gate 		    if ((grp = getgrnam(ARG0)))
485*0Sstevel@tonic-gate 			pw->pw_gid = grp->gr_gid;
486*0Sstevel@tonic-gate 		    else
487*0Sstevel@tonic-gate 			syslog(LOG_ERR, "autogroup: set group %s not found", ARG0);
488*0Sstevel@tonic-gate 		    endgrent();
489*0Sstevel@tonic-gate 		}
490*0Sstevel@tonic-gate 		return;
491*0Sstevel@tonic-gate 	    }
492*0Sstevel@tonic-gate 	}
493*0Sstevel@tonic-gate     }
494*0Sstevel@tonic-gate }
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate /*************************************************************************/
497*0Sstevel@tonic-gate /* FUNCTION  : acl_setfunctions                                          */
498*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer and determine what logging to perform */
499*0Sstevel@tonic-gate /*             for this user, and whether or not user is allowed to use  */
500*0Sstevel@tonic-gate /*             the automatic TAR and COMPRESS functions.  Also, set the  */
501*0Sstevel@tonic-gate /*             current process priority of this copy of the ftpd server  */
502*0Sstevel@tonic-gate /*             to a `nice' value value if this user is a member of a     */
503*0Sstevel@tonic-gate /*             group which the ftpaccess file says should be nice'd.     */
504*0Sstevel@tonic-gate /* ARGUMENTS : none                                                      */
505*0Sstevel@tonic-gate /*************************************************************************/
506*0Sstevel@tonic-gate 
acl_setfunctions(void)507*0Sstevel@tonic-gate void acl_setfunctions(void)
508*0Sstevel@tonic-gate {
509*0Sstevel@tonic-gate     char class[BUFSIZ];
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate     extern int log_incoming_xfers, log_outbound_xfers, mangleopts, log_commands,
512*0Sstevel@tonic-gate         log_security, syslogmsg, lgi_failure_threshold;
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate     int l_compress, l_tar, inbound = 0, outbound = 0, which, set;
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate     log_security = 0;
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate     /* Initialize to the logging value specified on the command line, can't
521*0Sstevel@tonic-gate        just use the current value as it may have been set by a previous call. */
522*0Sstevel@tonic-gate     log_incoming_xfers = (log_incoming_xfers & 2) ? 3 : 0;
523*0Sstevel@tonic-gate     log_outbound_xfers = (log_outbound_xfers & 2) ? 3 : 0;
524*0Sstevel@tonic-gate     log_commands = (log_commands & 2) ? 3 : 0;
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate     memset((void *) &class[0], 0, sizeof(class));
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate     (void) acl_getclass(class);
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
531*0Sstevel@tonic-gate     if (getaclentry("loginfails", &entry) && ARG0 != NULL) {
532*0Sstevel@tonic-gate 	lgi_failure_threshold = atoi(ARG0);
533*0Sstevel@tonic-gate     }
534*0Sstevel@tonic-gate #ifndef NO_PRIVATE
535*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
536*0Sstevel@tonic-gate     if (getaclentry("private", &entry) && ARG0 != NULL)
537*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "yes"))
538*0Sstevel@tonic-gate 	    priv_setup(_path_private);
539*0Sstevel@tonic-gate #endif /* !NO_PRIVATE */
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
542*0Sstevel@tonic-gate     set = 0;
543*0Sstevel@tonic-gate     while (!set && getaclentry("compress", &entry)) {
544*0Sstevel@tonic-gate 	if (!ARG0)
545*0Sstevel@tonic-gate 	    continue;
546*0Sstevel@tonic-gate 	l_compress = 0;
547*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "yes"))
548*0Sstevel@tonic-gate 	    l_compress = 1;
549*0Sstevel@tonic-gate 	for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
550*0Sstevel@tonic-gate 	    if (!wu_fnmatch(ARG[which], class, FNM_CASEFOLD)) {
551*0Sstevel@tonic-gate 		mangleopts |= l_compress * (O_COMPRESS | O_UNCOMPRESS);
552*0Sstevel@tonic-gate 		set = 1;
553*0Sstevel@tonic-gate 	    }
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate     }
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
558*0Sstevel@tonic-gate     set = 0;
559*0Sstevel@tonic-gate     while (!set && getaclentry("tar", &entry)) {
560*0Sstevel@tonic-gate 	if (!ARG0)
561*0Sstevel@tonic-gate 	    continue;
562*0Sstevel@tonic-gate 	l_tar = 0;
563*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "yes"))
564*0Sstevel@tonic-gate 	    l_tar = 1;
565*0Sstevel@tonic-gate 	for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
566*0Sstevel@tonic-gate 	    if (!wu_fnmatch(ARG[which], class, FNM_CASEFOLD)) {
567*0Sstevel@tonic-gate 		mangleopts |= l_tar * O_TAR;
568*0Sstevel@tonic-gate 		set = 1;
569*0Sstevel@tonic-gate 	    }
570*0Sstevel@tonic-gate 	}
571*0Sstevel@tonic-gate     }
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate     /* plan on expanding command syntax to include classes for each of these */
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
576*0Sstevel@tonic-gate     while (getaclentry("log", &entry)) {
577*0Sstevel@tonic-gate 	if (!ARG0)
578*0Sstevel@tonic-gate 	    continue;
579*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "commands")) {
580*0Sstevel@tonic-gate 	    if (!ARG1)
581*0Sstevel@tonic-gate 		continue;
582*0Sstevel@tonic-gate 	    if (anonymous && strcasestr(ARG1, "anonymous"))
583*0Sstevel@tonic-gate 		log_commands |= 1;
584*0Sstevel@tonic-gate 	    if (guest && strcasestr(ARG1, "guest"))
585*0Sstevel@tonic-gate 		log_commands |= 1;
586*0Sstevel@tonic-gate 	    if (!guest && !anonymous && strcasestr(ARG1, "real"))
587*0Sstevel@tonic-gate 		log_commands |= 1;
588*0Sstevel@tonic-gate 	}
589*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "transfers")) {
590*0Sstevel@tonic-gate 	    if (!ARG1 || !ARG2)
591*0Sstevel@tonic-gate 		continue;
592*0Sstevel@tonic-gate 	    set = 0;
593*0Sstevel@tonic-gate 	    if (strcasestr(ARG1, "anonymous") && anonymous)
594*0Sstevel@tonic-gate 		set = 1;
595*0Sstevel@tonic-gate 	    if (strcasestr(ARG1, "guest") && guest)
596*0Sstevel@tonic-gate 		set = 1;
597*0Sstevel@tonic-gate 	    if (strcasestr(ARG1, "real") && !guest && !anonymous)
598*0Sstevel@tonic-gate 		set = 1;
599*0Sstevel@tonic-gate 	    if (strcasestr(ARG2, "inbound"))
600*0Sstevel@tonic-gate 		inbound = 1;
601*0Sstevel@tonic-gate 	    if (strcasestr(ARG2, "outbound"))
602*0Sstevel@tonic-gate 		outbound = 1;
603*0Sstevel@tonic-gate 	    if (set)
604*0Sstevel@tonic-gate 		log_incoming_xfers |= inbound;
605*0Sstevel@tonic-gate 	    if (set)
606*0Sstevel@tonic-gate 		log_outbound_xfers |= outbound;
607*0Sstevel@tonic-gate 	}
608*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "security")) {
609*0Sstevel@tonic-gate 	    if (!ARG1)
610*0Sstevel@tonic-gate 		continue;
611*0Sstevel@tonic-gate 	    if (strcasestr(ARG1, "anonymous") && anonymous)
612*0Sstevel@tonic-gate 		log_security = 1;
613*0Sstevel@tonic-gate 	    if (strcasestr(ARG1, "guest") && guest)
614*0Sstevel@tonic-gate 		log_security = 1;
615*0Sstevel@tonic-gate 	    if (strcasestr(ARG1, "real") && !guest && !anonymous)
616*0Sstevel@tonic-gate 		log_security = 1;
617*0Sstevel@tonic-gate 	}
618*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "syslog"))
619*0Sstevel@tonic-gate 	    syslogmsg = 1;
620*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "xferlog"))
621*0Sstevel@tonic-gate 	    syslogmsg = 0;
622*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "syslog+xferlog")
623*0Sstevel@tonic-gate 	    || !strcasecmp(ARG0, "xferlog+syslog"))
624*0Sstevel@tonic-gate 	    syslogmsg = 2;
625*0Sstevel@tonic-gate     }
626*0Sstevel@tonic-gate }
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate /*************************************************************************/
629*0Sstevel@tonic-gate /* FUNCTION  : acl_getclass                                              */
630*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer and determine what class user is in   */
631*0Sstevel@tonic-gate /* ARGUMENTS : pointer to buffer to class name, pointer to ACL buffer    */
632*0Sstevel@tonic-gate /*************************************************************************/
633*0Sstevel@tonic-gate 
acl_getclass(char * classbuf)634*0Sstevel@tonic-gate int acl_getclass(char *classbuf)
635*0Sstevel@tonic-gate {
636*0Sstevel@tonic-gate     int which;
637*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate     while (getaclentry("class", &entry)) {
640*0Sstevel@tonic-gate 	if (ARG0)
641*0Sstevel@tonic-gate 	    strlcpy(classbuf, ARG0, BUFSIZ);
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	for (which = 2; (which < MAXARGS) && ARG[which]; which++) {
644*0Sstevel@tonic-gate 	    if (anonymous && strcasestr(ARG1, "anonymous") &&
645*0Sstevel@tonic-gate 		hostmatch(ARG[which], remoteaddr, remotehost))
646*0Sstevel@tonic-gate 		return (1);
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	    if (guest && strcasestr(ARG1, "guest") && hostmatch(ARG[which], remoteaddr, remotehost))
649*0Sstevel@tonic-gate 		return (1);
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 	    if (!guest && !anonymous && strcasestr(ARG1, "real") &&
652*0Sstevel@tonic-gate 		hostmatch(ARG[which], remoteaddr, remotehost))
653*0Sstevel@tonic-gate 		return (1);
654*0Sstevel@tonic-gate 	}
655*0Sstevel@tonic-gate     }
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate     *classbuf = (char) NULL;
658*0Sstevel@tonic-gate     return (0);
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate }
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate /*************************************************************************/
663*0Sstevel@tonic-gate /* FUNCTION  : acl_getlimit                                              */
664*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer and determine what limit applies to   */
665*0Sstevel@tonic-gate /*             the user                                                  */
666*0Sstevel@tonic-gate /* ARGUMENTS : pointer class name, pointer to ACL buffer                 */
667*0Sstevel@tonic-gate /*************************************************************************/
668*0Sstevel@tonic-gate 
acl_getlimit(char * class,char * msgpathbuf)669*0Sstevel@tonic-gate int acl_getlimit(char *class, char *msgpathbuf)
670*0Sstevel@tonic-gate {
671*0Sstevel@tonic-gate     int limit;
672*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate     if (msgpathbuf)
675*0Sstevel@tonic-gate 	*msgpathbuf = '\0';
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate     /* limit <class> <n> <times> [<message_file>] */
678*0Sstevel@tonic-gate     while (getaclentry("limit", &entry)) {
679*0Sstevel@tonic-gate 	if (!ARG0 || !ARG1 || !ARG2)
680*0Sstevel@tonic-gate 	    continue;
681*0Sstevel@tonic-gate 	if (!strcasecmp(class, ARG0)) {
682*0Sstevel@tonic-gate 	    limit = atoi(ARG1);
683*0Sstevel@tonic-gate 	    if (validtime(ARG2)) {
684*0Sstevel@tonic-gate 		if (ARG3 && msgpathbuf)
685*0Sstevel@tonic-gate 		    strcpy(msgpathbuf, ARG3);
686*0Sstevel@tonic-gate 		return (limit);
687*0Sstevel@tonic-gate 	    }
688*0Sstevel@tonic-gate 	}
689*0Sstevel@tonic-gate     }
690*0Sstevel@tonic-gate     return (-1);
691*0Sstevel@tonic-gate }
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate /*************************************************************************/
694*0Sstevel@tonic-gate /* FUNCTION  : acl_getnice                                               */
695*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer and determine what nice value applies */
696*0Sstevel@tonic-gate /*             to the user                                               */
697*0Sstevel@tonic-gate /* ARGUMENTS : pointer class name                                        */
698*0Sstevel@tonic-gate /*************************************************************************/
699*0Sstevel@tonic-gate 
acl_getnice(char * class)700*0Sstevel@tonic-gate int acl_getnice(char *class)
701*0Sstevel@tonic-gate {
702*0Sstevel@tonic-gate     int nice_delta_for_class_found = 0;
703*0Sstevel@tonic-gate     int nice_delta = 0;
704*0Sstevel@tonic-gate     int default_nice_delta = 0;
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate     /* nice <nice_delta> [<class>] */
709*0Sstevel@tonic-gate     while (getaclentry("nice", &entry)) {
710*0Sstevel@tonic-gate 	if (!ARG0)
711*0Sstevel@tonic-gate 	    continue;
712*0Sstevel@tonic-gate 	if (!ARG1)
713*0Sstevel@tonic-gate 	    default_nice_delta = atoi(ARG0);
714*0Sstevel@tonic-gate 	else if (!strcasecmp(class, ARG1)) {
715*0Sstevel@tonic-gate 	    nice_delta_for_class_found = 1;
716*0Sstevel@tonic-gate 	    nice_delta = atoi(ARG0);
717*0Sstevel@tonic-gate 	}
718*0Sstevel@tonic-gate     }
719*0Sstevel@tonic-gate     if (!nice_delta_for_class_found)
720*0Sstevel@tonic-gate 	nice_delta = default_nice_delta;
721*0Sstevel@tonic-gate     return nice_delta;
722*0Sstevel@tonic-gate }
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate /*************************************************************************/
726*0Sstevel@tonic-gate /* FUNCTION  : acl_getdefumask                                           */
727*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer to determine what umask value applies */
728*0Sstevel@tonic-gate /*             to the user                                               */
729*0Sstevel@tonic-gate /* ARGUMENTS : pointer to class name                                     */
730*0Sstevel@tonic-gate /*************************************************************************/
731*0Sstevel@tonic-gate 
acl_getdefumask(char * class)732*0Sstevel@tonic-gate void acl_getdefumask(char *class)
733*0Sstevel@tonic-gate {
734*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
735*0Sstevel@tonic-gate     char *ptr;
736*0Sstevel@tonic-gate     unsigned int val;
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate     /* defumask <umask> [<class>] */
739*0Sstevel@tonic-gate     while (getaclentry("defumask", &entry)) {
740*0Sstevel@tonic-gate 	if (!ARG0)
741*0Sstevel@tonic-gate 	    continue;
742*0Sstevel@tonic-gate 	if (!ARG1 || !strcasecmp(class, ARG1)) {
743*0Sstevel@tonic-gate 	    ptr = ARG0;
744*0Sstevel@tonic-gate 	    val = 0;
745*0Sstevel@tonic-gate 	    while (*ptr && *ptr >= '0' && *ptr <= '7')
746*0Sstevel@tonic-gate 		val = val * 8 + *ptr++ - '0';
747*0Sstevel@tonic-gate 	    if (!*ptr && val <= 0777) {
748*0Sstevel@tonic-gate 		defumask = val;
749*0Sstevel@tonic-gate 		if (ARG1)
750*0Sstevel@tonic-gate 		    break;
751*0Sstevel@tonic-gate 	    }
752*0Sstevel@tonic-gate 	    else
753*0Sstevel@tonic-gate 		syslog(LOG_WARNING, "bad umask in %s ignored: defumask %s",
754*0Sstevel@tonic-gate 		       _path_ftpaccess, ARG0);
755*0Sstevel@tonic-gate 	}
756*0Sstevel@tonic-gate     }
757*0Sstevel@tonic-gate     umask(defumask);
758*0Sstevel@tonic-gate }
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate /*************************************************************************/
761*0Sstevel@tonic-gate /* FUNCTION  : acl_tcpwindow                                             */
762*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer and determine what TCP window size to */
763*0Sstevel@tonic-gate /*             use based upon the class                                  */
764*0Sstevel@tonic-gate /* ARGUMENTS : pointer to class name                                     */
765*0Sstevel@tonic-gate /*************************************************************************/
766*0Sstevel@tonic-gate 
acl_tcpwindow(char * class)767*0Sstevel@tonic-gate void acl_tcpwindow(char *class)
768*0Sstevel@tonic-gate {
769*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate     /* tcpwindow <size> [<class>] */
772*0Sstevel@tonic-gate     while (getaclentry("tcpwindow", &entry)) {
773*0Sstevel@tonic-gate 	if (!ARG0)
774*0Sstevel@tonic-gate 	    continue;
775*0Sstevel@tonic-gate 	if (!ARG1)
776*0Sstevel@tonic-gate 	    TCPwindowsize = strtoul(ARG0, NULL, 0);
777*0Sstevel@tonic-gate 	else if (!strcasecmp(class, ARG1)) {
778*0Sstevel@tonic-gate 	    TCPwindowsize = strtoul(ARG0, NULL, 0);
779*0Sstevel@tonic-gate 	    break;
780*0Sstevel@tonic-gate 	}
781*0Sstevel@tonic-gate     }
782*0Sstevel@tonic-gate }
783*0Sstevel@tonic-gate 
784*0Sstevel@tonic-gate /*************************************************************************/
785*0Sstevel@tonic-gate /* FUNCTION  : acl_bufsize                                               */
786*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer and determine the send and receive    */
787*0Sstevel@tonic-gate /*             buffer sizes to use                                       */
788*0Sstevel@tonic-gate /* ARGUMENTS : None                                                      */
789*0Sstevel@tonic-gate /*************************************************************************/
790*0Sstevel@tonic-gate 
acl_bufsize()791*0Sstevel@tonic-gate static void acl_bufsize()
792*0Sstevel@tonic-gate {
793*0Sstevel@tonic-gate     struct aclmember *entry;
794*0Sstevel@tonic-gate     extern size_t sendbufsz, recvbufsz;
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate     /* sendbuf <size> [<typelist>] */
797*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
798*0Sstevel@tonic-gate     sendbufsz = 0;
799*0Sstevel@tonic-gate     while (getaclentry("sendbuf", &entry)) {
800*0Sstevel@tonic-gate 	if (!ARG0)
801*0Sstevel@tonic-gate 	    continue;
802*0Sstevel@tonic-gate 	if (!ARG1)
803*0Sstevel@tonic-gate 	    sendbufsz = strtoul(ARG0, NULL, 0);
804*0Sstevel@tonic-gate 	else if (type_match(ARG1)) {
805*0Sstevel@tonic-gate 	    sendbufsz = strtoul(ARG0, NULL, 0);
806*0Sstevel@tonic-gate 	    break;
807*0Sstevel@tonic-gate 	}
808*0Sstevel@tonic-gate     }
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate     /* recvbuf <size> [<typelist>] */
811*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
812*0Sstevel@tonic-gate     recvbufsz = 0;
813*0Sstevel@tonic-gate     while (getaclentry("recvbuf", &entry)) {
814*0Sstevel@tonic-gate 	if (!ARG0)
815*0Sstevel@tonic-gate 	    continue;
816*0Sstevel@tonic-gate 	if (!ARG1)
817*0Sstevel@tonic-gate 	    recvbufsz = strtoul(ARG0, NULL, 0);
818*0Sstevel@tonic-gate 	else if (type_match(ARG1)) {
819*0Sstevel@tonic-gate 	    recvbufsz = strtoul(ARG0, NULL, 0);
820*0Sstevel@tonic-gate 	    break;
821*0Sstevel@tonic-gate 	}
822*0Sstevel@tonic-gate     }
823*0Sstevel@tonic-gate }
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate #ifdef TRANSFER_COUNT
826*0Sstevel@tonic-gate #ifdef TRANSFER_LIMIT
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate /*************************************************************************/
829*0Sstevel@tonic-gate /* FUNCTION  : acl_filelimit                                             */
830*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer and determine what file limit to use  */
831*0Sstevel@tonic-gate /*             based upon the class                                      */
832*0Sstevel@tonic-gate /* ARGUMENTS : pointer to class name                                     */
833*0Sstevel@tonic-gate /*************************************************************************/
834*0Sstevel@tonic-gate 
acl_filelimit(char * class)835*0Sstevel@tonic-gate void acl_filelimit(char *class)
836*0Sstevel@tonic-gate {
837*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
838*0Sstevel@tonic-gate     int raw_in = 0;
839*0Sstevel@tonic-gate     int raw_out = 0;
840*0Sstevel@tonic-gate     int raw_total = 0;
841*0Sstevel@tonic-gate     int data_in = 0;
842*0Sstevel@tonic-gate     int data_out = 0;
843*0Sstevel@tonic-gate     int data_total = 0;
844*0Sstevel@tonic-gate     extern int file_limit_raw_in;
845*0Sstevel@tonic-gate     extern int file_limit_raw_out;
846*0Sstevel@tonic-gate     extern int file_limit_raw_total;
847*0Sstevel@tonic-gate     extern int file_limit_data_in;
848*0Sstevel@tonic-gate     extern int file_limit_data_out;
849*0Sstevel@tonic-gate     extern int file_limit_data_total;
850*0Sstevel@tonic-gate 
851*0Sstevel@tonic-gate     /* file-limit [<raw>] <in|out|total> <count> [<class>] */
852*0Sstevel@tonic-gate     while (getaclentry("file-limit", &entry)) {
853*0Sstevel@tonic-gate 	if (!ARG0 || !ARG1)
854*0Sstevel@tonic-gate 	    continue;
855*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "raw")) {
856*0Sstevel@tonic-gate 	    if (!ARG2)
857*0Sstevel@tonic-gate 		continue;
858*0Sstevel@tonic-gate 	    if (!strcasecmp(ARG1, "in")) {
859*0Sstevel@tonic-gate 		if (!ARG3) {
860*0Sstevel@tonic-gate 		    if (!raw_in)
861*0Sstevel@tonic-gate 			file_limit_raw_in = atoi(ARG2);
862*0Sstevel@tonic-gate 		}
863*0Sstevel@tonic-gate 		else if (!strcasecmp(class, ARG3)) {
864*0Sstevel@tonic-gate 		    raw_in = 1;
865*0Sstevel@tonic-gate 		    file_limit_raw_in = atoi(ARG2);
866*0Sstevel@tonic-gate 		}
867*0Sstevel@tonic-gate 	    }
868*0Sstevel@tonic-gate 	    else if (!strcasecmp(ARG1, "out")) {
869*0Sstevel@tonic-gate 		if (!ARG3) {
870*0Sstevel@tonic-gate 		    if (!raw_out)
871*0Sstevel@tonic-gate 			file_limit_raw_out = atoi(ARG2);
872*0Sstevel@tonic-gate 		}
873*0Sstevel@tonic-gate 		else if (!strcasecmp(class, ARG3)) {
874*0Sstevel@tonic-gate 		    raw_out = 1;
875*0Sstevel@tonic-gate 		    file_limit_raw_out = atoi(ARG2);
876*0Sstevel@tonic-gate 		}
877*0Sstevel@tonic-gate 	    }
878*0Sstevel@tonic-gate 	    else if (!strcasecmp(ARG1, "total")) {
879*0Sstevel@tonic-gate 		if (!ARG3) {
880*0Sstevel@tonic-gate 		    if (!raw_total)
881*0Sstevel@tonic-gate 			file_limit_raw_total = atoi(ARG2);
882*0Sstevel@tonic-gate 		}
883*0Sstevel@tonic-gate 		else if (!strcasecmp(class, ARG3)) {
884*0Sstevel@tonic-gate 		    raw_total = 1;
885*0Sstevel@tonic-gate 		    file_limit_raw_total = atoi(ARG2);
886*0Sstevel@tonic-gate 		}
887*0Sstevel@tonic-gate 	    }
888*0Sstevel@tonic-gate 	}
889*0Sstevel@tonic-gate 	else if (!strcasecmp(ARG0, "in")) {
890*0Sstevel@tonic-gate 	    if (!ARG2) {
891*0Sstevel@tonic-gate 		if (!data_in)
892*0Sstevel@tonic-gate 		    file_limit_data_in = atoi(ARG1);
893*0Sstevel@tonic-gate 	    }
894*0Sstevel@tonic-gate 	    else if (!strcasecmp(class, ARG2)) {
895*0Sstevel@tonic-gate 		data_in = 1;
896*0Sstevel@tonic-gate 		file_limit_data_in = atoi(ARG1);
897*0Sstevel@tonic-gate 	    }
898*0Sstevel@tonic-gate 	}
899*0Sstevel@tonic-gate 	else if (!strcasecmp(ARG0, "out")) {
900*0Sstevel@tonic-gate 	    if (!ARG2) {
901*0Sstevel@tonic-gate 		if (!data_out)
902*0Sstevel@tonic-gate 		    file_limit_data_out = atoi(ARG1);
903*0Sstevel@tonic-gate 	    }
904*0Sstevel@tonic-gate 	    else if (!strcasecmp(class, ARG2)) {
905*0Sstevel@tonic-gate 		data_out = 1;
906*0Sstevel@tonic-gate 		file_limit_data_out = atoi(ARG1);
907*0Sstevel@tonic-gate 	    }
908*0Sstevel@tonic-gate 	}
909*0Sstevel@tonic-gate 	else if (!strcasecmp(ARG0, "total")) {
910*0Sstevel@tonic-gate 	    if (!ARG2) {
911*0Sstevel@tonic-gate 		if (!data_total)
912*0Sstevel@tonic-gate 		    file_limit_data_total = atoi(ARG1);
913*0Sstevel@tonic-gate 	    }
914*0Sstevel@tonic-gate 	    else if (!strcasecmp(class, ARG2)) {
915*0Sstevel@tonic-gate 		data_total = 1;
916*0Sstevel@tonic-gate 		file_limit_data_total = atoi(ARG1);
917*0Sstevel@tonic-gate 	    }
918*0Sstevel@tonic-gate 	}
919*0Sstevel@tonic-gate     }
920*0Sstevel@tonic-gate }
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate /*************************************************************************/
923*0Sstevel@tonic-gate /* FUNCTION  : acl_datalimit                                             */
924*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer and determine what data limit to use  */
925*0Sstevel@tonic-gate /*             based upon the class                                      */
926*0Sstevel@tonic-gate /* ARGUMENTS : pointer to class name                                     */
927*0Sstevel@tonic-gate /*************************************************************************/
928*0Sstevel@tonic-gate 
acl_datalimit(char * class)929*0Sstevel@tonic-gate void acl_datalimit(char *class)
930*0Sstevel@tonic-gate {
931*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
932*0Sstevel@tonic-gate     int raw_in = 0;
933*0Sstevel@tonic-gate     int raw_out = 0;
934*0Sstevel@tonic-gate     int raw_total = 0;
935*0Sstevel@tonic-gate     int data_in = 0;
936*0Sstevel@tonic-gate     int data_out = 0;
937*0Sstevel@tonic-gate     int data_total = 0;
938*0Sstevel@tonic-gate     extern off_t data_limit_raw_in;
939*0Sstevel@tonic-gate     extern off_t data_limit_raw_out;
940*0Sstevel@tonic-gate     extern off_t data_limit_raw_total;
941*0Sstevel@tonic-gate     extern off_t data_limit_data_in;
942*0Sstevel@tonic-gate     extern off_t data_limit_data_out;
943*0Sstevel@tonic-gate     extern off_t data_limit_data_total;
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate     /* data-limit [<raw>] <in|out|total> <count> [<class>] */
946*0Sstevel@tonic-gate     while (getaclentry("data-limit", &entry)) {
947*0Sstevel@tonic-gate 	if (!ARG0 || !ARG1)
948*0Sstevel@tonic-gate 	    continue;
949*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "raw")) {
950*0Sstevel@tonic-gate 	    if (!ARG2)
951*0Sstevel@tonic-gate 		continue;
952*0Sstevel@tonic-gate 	    if (!strcasecmp(ARG1, "in")) {
953*0Sstevel@tonic-gate 		if (!ARG3) {
954*0Sstevel@tonic-gate 		    if (!raw_in)
955*0Sstevel@tonic-gate 			data_limit_raw_in = atoi(ARG2);
956*0Sstevel@tonic-gate 		}
957*0Sstevel@tonic-gate 		else if (!strcasecmp(class, ARG3)) {
958*0Sstevel@tonic-gate 		    raw_in = 1;
959*0Sstevel@tonic-gate 		    data_limit_raw_in = atoi(ARG2);
960*0Sstevel@tonic-gate 		}
961*0Sstevel@tonic-gate 	    }
962*0Sstevel@tonic-gate 	    else if (!strcasecmp(ARG1, "out")) {
963*0Sstevel@tonic-gate 		if (!ARG3) {
964*0Sstevel@tonic-gate 		    if (!raw_out)
965*0Sstevel@tonic-gate 			data_limit_raw_out = atoi(ARG2);
966*0Sstevel@tonic-gate 		}
967*0Sstevel@tonic-gate 		else if (!strcasecmp(class, ARG3)) {
968*0Sstevel@tonic-gate 		    raw_out = 1;
969*0Sstevel@tonic-gate 		    data_limit_raw_out = atoi(ARG2);
970*0Sstevel@tonic-gate 		}
971*0Sstevel@tonic-gate 	    }
972*0Sstevel@tonic-gate 	    else if (!strcasecmp(ARG1, "total")) {
973*0Sstevel@tonic-gate 		if (!ARG3) {
974*0Sstevel@tonic-gate 		    if (!raw_total)
975*0Sstevel@tonic-gate 			data_limit_raw_total = atoi(ARG2);
976*0Sstevel@tonic-gate 		}
977*0Sstevel@tonic-gate 		else if (!strcasecmp(class, ARG3)) {
978*0Sstevel@tonic-gate 		    raw_total = 1;
979*0Sstevel@tonic-gate 		    data_limit_raw_total = atoi(ARG2);
980*0Sstevel@tonic-gate 		}
981*0Sstevel@tonic-gate 	    }
982*0Sstevel@tonic-gate 	}
983*0Sstevel@tonic-gate 	else if (!strcasecmp(ARG0, "in")) {
984*0Sstevel@tonic-gate 	    if (!ARG2) {
985*0Sstevel@tonic-gate 		if (!data_in)
986*0Sstevel@tonic-gate 		    data_limit_data_in = atoi(ARG1);
987*0Sstevel@tonic-gate 	    }
988*0Sstevel@tonic-gate 	    else if (!strcasecmp(class, ARG2)) {
989*0Sstevel@tonic-gate 		data_in = 1;
990*0Sstevel@tonic-gate 		data_limit_data_in = atoi(ARG1);
991*0Sstevel@tonic-gate 	    }
992*0Sstevel@tonic-gate 	}
993*0Sstevel@tonic-gate 	else if (!strcasecmp(ARG0, "out")) {
994*0Sstevel@tonic-gate 	    if (!ARG2) {
995*0Sstevel@tonic-gate 		if (!data_out)
996*0Sstevel@tonic-gate 		    data_limit_data_out = atoi(ARG1);
997*0Sstevel@tonic-gate 	    }
998*0Sstevel@tonic-gate 	    else if (!strcasecmp(class, ARG2)) {
999*0Sstevel@tonic-gate 		data_out = 1;
1000*0Sstevel@tonic-gate 		data_limit_data_out = atoi(ARG1);
1001*0Sstevel@tonic-gate 	    }
1002*0Sstevel@tonic-gate 	}
1003*0Sstevel@tonic-gate 	else if (!strcasecmp(ARG0, "total")) {
1004*0Sstevel@tonic-gate 	    if (!ARG2) {
1005*0Sstevel@tonic-gate 		if (!data_total)
1006*0Sstevel@tonic-gate 		    data_limit_data_total = atoi(ARG1);
1007*0Sstevel@tonic-gate 	    }
1008*0Sstevel@tonic-gate 	    else if (!strcasecmp(class, ARG2)) {
1009*0Sstevel@tonic-gate 		data_total = 1;
1010*0Sstevel@tonic-gate 		data_limit_data_total = atoi(ARG1);
1011*0Sstevel@tonic-gate 	    }
1012*0Sstevel@tonic-gate 	}
1013*0Sstevel@tonic-gate     }
1014*0Sstevel@tonic-gate }
1015*0Sstevel@tonic-gate 
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate #ifdef RATIO
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate /*************************************************************************/
1020*0Sstevel@tonic-gate /* FUNCTION  : acl_downloadrate                                          */
1021*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer and determine what data limit to use  */
1022*0Sstevel@tonic-gate /*             based upon the class                                      */
1023*0Sstevel@tonic-gate /* ARGUMENTS : pointer to class name                                     */
1024*0Sstevel@tonic-gate /*************************************************************************/
1025*0Sstevel@tonic-gate 
acl_downloadrate(char * class)1026*0Sstevel@tonic-gate void acl_downloadrate(char *class)
1027*0Sstevel@tonic-gate {
1028*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
1029*0Sstevel@tonic-gate     extern int upload_download_rate;
1030*0Sstevel@tonic-gate     int which;
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate     /* ul-dl-rate <rate> [<class> ...] */
1033*0Sstevel@tonic-gate     while (getaclentry("ul-dl-rate", &entry)) {
1034*0Sstevel@tonic-gate 	if (!ARG0 )
1035*0Sstevel@tonic-gate 	    continue;
1036*0Sstevel@tonic-gate 
1037*0Sstevel@tonic-gate 	if (!ARG1) {
1038*0Sstevel@tonic-gate 	    upload_download_rate = atol(ARG0);
1039*0Sstevel@tonic-gate 	}
1040*0Sstevel@tonic-gate 	else {
1041*0Sstevel@tonic-gate 	    for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
1042*0Sstevel@tonic-gate 		if (!strcasecmp(ARG[which], class))
1043*0Sstevel@tonic-gate 		    upload_download_rate = atol(ARG0);
1044*0Sstevel@tonic-gate 	    }
1045*0Sstevel@tonic-gate 	}
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate     }
1048*0Sstevel@tonic-gate }
1049*0Sstevel@tonic-gate #endif /* RATIO */
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate #endif
1052*0Sstevel@tonic-gate #endif
1053*0Sstevel@tonic-gate 
1054*0Sstevel@tonic-gate /*************************************************************************/
1055*0Sstevel@tonic-gate /* FUNCTION  : acl_deny                                                  */
1056*0Sstevel@tonic-gate /* PURPOSE   : Scan the ACL buffer and determine if access is denied.    */
1057*0Sstevel@tonic-gate /* ARGUMENTS : Pointer to buffer into which the path of the message file */
1058*0Sstevel@tonic-gate /*             is copied.                                                */
1059*0Sstevel@tonic-gate /*************************************************************************/
1060*0Sstevel@tonic-gate 
acl_deny(char * msgpathbuf)1061*0Sstevel@tonic-gate int acl_deny(char *msgpathbuf)
1062*0Sstevel@tonic-gate {
1063*0Sstevel@tonic-gate     struct aclmember *entry = NULL;
1064*0Sstevel@tonic-gate 
1065*0Sstevel@tonic-gate     if (msgpathbuf)
1066*0Sstevel@tonic-gate 	*msgpathbuf = (char) NULL;
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate     /* deny <addrglob> [<message_file>] */
1069*0Sstevel@tonic-gate     while (getaclentry("deny", &entry)) {
1070*0Sstevel@tonic-gate 	if (!ARG0)
1071*0Sstevel@tonic-gate 	    continue;
1072*0Sstevel@tonic-gate 	if (strcasecmp(ARG0, "!nameserved") == 0) {
1073*0Sstevel@tonic-gate 	    if (!nameserved) {
1074*0Sstevel@tonic-gate 		if (ARG1)
1075*0Sstevel@tonic-gate 		    strcpy(msgpathbuf, entry->arg[1]);
1076*0Sstevel@tonic-gate 		return (1);
1077*0Sstevel@tonic-gate 	    }
1078*0Sstevel@tonic-gate 	}
1079*0Sstevel@tonic-gate 	else if (hostmatch(ARG0, remoteaddr, remotehost)) {
1080*0Sstevel@tonic-gate 	    if (ARG1)
1081*0Sstevel@tonic-gate 		strcpy(msgpathbuf, entry->arg[1]);
1082*0Sstevel@tonic-gate 	    return (1);
1083*0Sstevel@tonic-gate 	}
1084*0Sstevel@tonic-gate     }
1085*0Sstevel@tonic-gate     return (0);
1086*0Sstevel@tonic-gate }
1087*0Sstevel@tonic-gate 
1088*0Sstevel@tonic-gate /*************************************************************************/
1089*0Sstevel@tonic-gate /* FUNCTION  : lock_fd                                                   */
1090*0Sstevel@tonic-gate /* PURPOSE   : Lock a file.                                              */
1091*0Sstevel@tonic-gate /* ARGUMENTS : File descriptor of file to lock.                          */
1092*0Sstevel@tonic-gate /*************************************************************************/
1093*0Sstevel@tonic-gate 
lock_fd(int fd)1094*0Sstevel@tonic-gate static void lock_fd(int fd)
1095*0Sstevel@tonic-gate {
1096*0Sstevel@tonic-gate #if !defined(HAVE_FLOCK)
1097*0Sstevel@tonic-gate     struct flock arg;
1098*0Sstevel@tonic-gate #endif /* !defined(HAVE_FLOCK) */
1099*0Sstevel@tonic-gate 
1100*0Sstevel@tonic-gate #if defined(HAVE_FLOCK)
1101*0Sstevel@tonic-gate     while (flock(fd, LOCK_EX)) {
1102*0Sstevel@tonic-gate #  if !defined(NO_PID_SLEEP_MSGS)
1103*0Sstevel@tonic-gate 	syslog(LOG_ERR, "sleeping: flock of pid file failed: %m");
1104*0Sstevel@tonic-gate #  endif /* !defined(NO_PID_SLEEP_MSGS) */
1105*0Sstevel@tonic-gate #else /* !(defined(HAVE_FLOCK)) */
1106*0Sstevel@tonic-gate     arg.l_type = F_WRLCK;
1107*0Sstevel@tonic-gate     arg.l_whence = arg.l_start = arg.l_len = 0;
1108*0Sstevel@tonic-gate     while (-1 == fcntl(fd, F_SETLK, &arg)) {
1109*0Sstevel@tonic-gate #  if !defined(NO_PID_SLEEP_MSGS)
1110*0Sstevel@tonic-gate 	syslog(LOG_ERR, "sleeping: fcntl lock of pid file failed: %m");
1111*0Sstevel@tonic-gate #  endif /* !defined(NO_PID_SLEEP_MSGS) */
1112*0Sstevel@tonic-gate #endif /* !(defined(HAVE_FLOCK)) */
1113*0Sstevel@tonic-gate 	sleep(1);
1114*0Sstevel@tonic-gate     }
1115*0Sstevel@tonic-gate }
1116*0Sstevel@tonic-gate 
1117*0Sstevel@tonic-gate /*************************************************************************/
1118*0Sstevel@tonic-gate /* FUNCTION  : unlock_fd                                                 */
1119*0Sstevel@tonic-gate /* PURPOSE   : Unlock a file locked by lock_fd.                          */
1120*0Sstevel@tonic-gate /* ARGUMENTS : File descriptor of file to unlock.                        */
1121*0Sstevel@tonic-gate /*************************************************************************/
1122*0Sstevel@tonic-gate 
1123*0Sstevel@tonic-gate static void unlock_fd(int fd)
1124*0Sstevel@tonic-gate {
1125*0Sstevel@tonic-gate #if !defined(HAVE_FLOCK)
1126*0Sstevel@tonic-gate     struct flock arg;
1127*0Sstevel@tonic-gate #endif /* !defined(HAVE_FLOCK) */
1128*0Sstevel@tonic-gate 
1129*0Sstevel@tonic-gate #if defined(HAVE_FLOCK)
1130*0Sstevel@tonic-gate     flock(fd, LOCK_UN);
1131*0Sstevel@tonic-gate #else /* !(defined(HAVE_FLOCK)) */
1132*0Sstevel@tonic-gate     arg.l_type = F_UNLCK;
1133*0Sstevel@tonic-gate     arg.l_whence = arg.l_start = arg.l_len = 0;
1134*0Sstevel@tonic-gate     fcntl(fd, F_SETLK, &arg);
1135*0Sstevel@tonic-gate #endif /* !(defined(HAVE_FLOCK)) */
1136*0Sstevel@tonic-gate }
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate /*************************************************************************/
1139*0Sstevel@tonic-gate /* FUNCTION  : limit_op                                                  */
1140*0Sstevel@tonic-gate /* PURPOSE   : Carry out the specified limit operation, returning the    */
1141*0Sstevel@tonic-gate /*             number of users in the class or -1 on failure.            */
1142*0Sstevel@tonic-gate /* ARGUMENTS : Operation (ACL_COUNT/ACL_JOIN/ACL_REMOVE), user limit     */
1143*0Sstevel@tonic-gate /*************************************************************************/
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate static int limit_op(int operation, int limit)
1146*0Sstevel@tonic-gate {
1147*0Sstevel@tonic-gate     int i, j, n, count;
1148*0Sstevel@tonic-gate     int bit_changed, toomany, write_all_header;
1149*0Sstevel@tonic-gate     off_t offset;
1150*0Sstevel@tonic-gate     pid_t pid, procid;
1151*0Sstevel@tonic-gate     time_t now;
1152*0Sstevel@tonic-gate     struct pidfile_header hdr;
1153*0Sstevel@tonic-gate     unsigned char bits, buf[BUFSIZ];
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate     if (pidfd < 0)
1156*0Sstevel@tonic-gate 	return (-1);
1157*0Sstevel@tonic-gate 
1158*0Sstevel@tonic-gate     if (lseek(pidfd, (off_t)0, SEEK_SET) != 0)
1159*0Sstevel@tonic-gate 	return (-1);
1160*0Sstevel@tonic-gate 
1161*0Sstevel@tonic-gate     if (operation == ACL_COUNT) {
1162*0Sstevel@tonic-gate 	lock_fd(pidfd);
1163*0Sstevel@tonic-gate 	n = read(pidfd, (void *)&hdr.count, sizeof(hdr.count));
1164*0Sstevel@tonic-gate 	unlock_fd(pidfd);
1165*0Sstevel@tonic-gate 	if (n != sizeof(hdr.count))
1166*0Sstevel@tonic-gate 	    return (-1);
1167*0Sstevel@tonic-gate 	return (hdr.count);
1168*0Sstevel@tonic-gate     }
1169*0Sstevel@tonic-gate 
1170*0Sstevel@tonic-gate     toomany = 0;
1171*0Sstevel@tonic-gate     write_all_header = 0;
1172*0Sstevel@tonic-gate     lock_fd(pidfd);
1173*0Sstevel@tonic-gate     if (read(pidfd, (void *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
1174*0Sstevel@tonic-gate 	hdr.count = 0;
1175*0Sstevel@tonic-gate 	hdr.last_checked = 0;
1176*0Sstevel@tonic-gate     }
1177*0Sstevel@tonic-gate     now = time(NULL);
1178*0Sstevel@tonic-gate 
1179*0Sstevel@tonic-gate     /* check bitmap accuracy and re-calculate the count every 15 minutes */
1180*0Sstevel@tonic-gate     if ((now >= (hdr.last_checked + (15 * 60))) || (now < hdr.last_checked)) {
1181*0Sstevel@tonic-gate 	count = 0;
1182*0Sstevel@tonic-gate 	procid = 0;
1183*0Sstevel@tonic-gate 	bit_changed = 0;
1184*0Sstevel@tonic-gate 	while ((n = read(pidfd, (void *)buf, sizeof(buf))) > 0) {
1185*0Sstevel@tonic-gate 	    for (i = 0; i < n; i++) {
1186*0Sstevel@tonic-gate 		if (buf[i] == 0) {
1187*0Sstevel@tonic-gate 		    procid += CHAR_BIT;
1188*0Sstevel@tonic-gate 		}
1189*0Sstevel@tonic-gate 		else {
1190*0Sstevel@tonic-gate 		    bits = 1;
1191*0Sstevel@tonic-gate 		    for (j = 0; j < CHAR_BIT; j++) {
1192*0Sstevel@tonic-gate 			if ((buf[i] & bits) != 0) {
1193*0Sstevel@tonic-gate 			    if (kill(procid, 0) == 0) {
1194*0Sstevel@tonic-gate 				count++;
1195*0Sstevel@tonic-gate 			    }
1196*0Sstevel@tonic-gate 			    else {
1197*0Sstevel@tonic-gate 				bit_changed = 1;
1198*0Sstevel@tonic-gate 				buf[i] &= ~bits;
1199*0Sstevel@tonic-gate 			    }
1200*0Sstevel@tonic-gate 			}
1201*0Sstevel@tonic-gate 			bits <<= 1;
1202*0Sstevel@tonic-gate 			procid++;
1203*0Sstevel@tonic-gate 		    }
1204*0Sstevel@tonic-gate 		}
1205*0Sstevel@tonic-gate 	    }
1206*0Sstevel@tonic-gate 	    if (bit_changed) {
1207*0Sstevel@tonic-gate 		lseek(pidfd, (off_t)-n, SEEK_CUR);
1208*0Sstevel@tonic-gate 		write(pidfd, (void *)buf, n);
1209*0Sstevel@tonic-gate 		bit_changed = 0;
1210*0Sstevel@tonic-gate 	    }
1211*0Sstevel@tonic-gate 	}
1212*0Sstevel@tonic-gate 	if (hdr.count != count) {
1213*0Sstevel@tonic-gate 	    syslog(LOG_INFO, "pid file header count (%d) corrected to %d",
1214*0Sstevel@tonic-gate 		   hdr.count, count);
1215*0Sstevel@tonic-gate 	    hdr.count = count;
1216*0Sstevel@tonic-gate 	}
1217*0Sstevel@tonic-gate 	hdr.last_checked = time(NULL);
1218*0Sstevel@tonic-gate 	write_all_header = 1;
1219*0Sstevel@tonic-gate     }
1220*0Sstevel@tonic-gate 
1221*0Sstevel@tonic-gate     /* limit set to -1 when no limit defined */
1222*0Sstevel@tonic-gate     if ((operation == ACL_JOIN) && (limit != -1) && (hdr.count >= limit)) {
1223*0Sstevel@tonic-gate 	/* return if no need to update the header */
1224*0Sstevel@tonic-gate 	if (write_all_header == 0) {
1225*0Sstevel@tonic-gate 	    unlock_fd(pidfd);
1226*0Sstevel@tonic-gate 	    return (-1);
1227*0Sstevel@tonic-gate 	}
1228*0Sstevel@tonic-gate 	toomany = 1;
1229*0Sstevel@tonic-gate     }
1230*0Sstevel@tonic-gate     else {
1231*0Sstevel@tonic-gate 	/* update the count */
1232*0Sstevel@tonic-gate 	if (operation == ACL_JOIN)
1233*0Sstevel@tonic-gate 	    hdr.count++;
1234*0Sstevel@tonic-gate 	else if (hdr.count > 0) /* ACL_REMOVE */
1235*0Sstevel@tonic-gate 	    hdr.count--;
1236*0Sstevel@tonic-gate     }
1237*0Sstevel@tonic-gate 
1238*0Sstevel@tonic-gate     /* update the header */
1239*0Sstevel@tonic-gate     lseek(pidfd, (off_t)0, SEEK_SET);
1240*0Sstevel@tonic-gate     if (write_all_header)
1241*0Sstevel@tonic-gate 	write(pidfd, (void *)&hdr, sizeof(hdr));
1242*0Sstevel@tonic-gate     else
1243*0Sstevel@tonic-gate 	write(pidfd, (void *)&hdr.count, sizeof(hdr.count));
1244*0Sstevel@tonic-gate 
1245*0Sstevel@tonic-gate     /* return if no need to update the bitmap */
1246*0Sstevel@tonic-gate     if (toomany) {
1247*0Sstevel@tonic-gate 	unlock_fd(pidfd);
1248*0Sstevel@tonic-gate 	return (-1);
1249*0Sstevel@tonic-gate     }
1250*0Sstevel@tonic-gate 
1251*0Sstevel@tonic-gate     /* update the bitmap entry for the process */
1252*0Sstevel@tonic-gate     pid = getpid();
1253*0Sstevel@tonic-gate     offset = (off_t)(sizeof(hdr) + (pid/CHAR_BIT));
1254*0Sstevel@tonic-gate     lseek(pidfd, offset, SEEK_SET);
1255*0Sstevel@tonic-gate     if (read(pidfd, (void *)&bits, sizeof(bits)) != sizeof(bits))
1256*0Sstevel@tonic-gate 	bits = 0;
1257*0Sstevel@tonic-gate     if (operation == ACL_JOIN)
1258*0Sstevel@tonic-gate 	bits |= (1 << (pid%CHAR_BIT));
1259*0Sstevel@tonic-gate     else /* ACL_REMOVE */
1260*0Sstevel@tonic-gate 	bits &= ~(1 << (pid%CHAR_BIT));
1261*0Sstevel@tonic-gate     lseek(pidfd, offset, SEEK_SET);
1262*0Sstevel@tonic-gate     write(pidfd, (void *)&bits, sizeof(bits));
1263*0Sstevel@tonic-gate     unlock_fd(pidfd);
1264*0Sstevel@tonic-gate     return (hdr.count);
1265*0Sstevel@tonic-gate }
1266*0Sstevel@tonic-gate 
1267*0Sstevel@tonic-gate /*************************************************************************/
1268*0Sstevel@tonic-gate /* FUNCTION  : open_pidfile                                              */
1269*0Sstevel@tonic-gate /* PURPOSE   : Return a file descriptor of an opened PID file.           */
1270*0Sstevel@tonic-gate /* ARGUMENTS : Users class.                                              */
1271*0Sstevel@tonic-gate /*************************************************************************/
1272*0Sstevel@tonic-gate 
1273*0Sstevel@tonic-gate static int open_pidfile(char *class)
1274*0Sstevel@tonic-gate {
1275*0Sstevel@tonic-gate     int fd;
1276*0Sstevel@tonic-gate     mode_t oldmask;
1277*0Sstevel@tonic-gate     char pidfile[MAXPATHLEN];
1278*0Sstevel@tonic-gate 
1279*0Sstevel@tonic-gate     snprintf(pidfile, sizeof(pidfile), _PATH_PIDNAMES, class);
1280*0Sstevel@tonic-gate     oldmask = umask(0);
1281*0Sstevel@tonic-gate     fd = open(pidfile, O_RDWR | O_CREAT, 0644);
1282*0Sstevel@tonic-gate     (void) umask(oldmask);
1283*0Sstevel@tonic-gate     if (fd < 0)
1284*0Sstevel@tonic-gate 	    syslog(LOG_ERR, "cannot open pid file %s: %m", pidfile);
1285*0Sstevel@tonic-gate     return (fd);
1286*0Sstevel@tonic-gate }
1287*0Sstevel@tonic-gate 
1288*0Sstevel@tonic-gate /*************************************************************************/
1289*0Sstevel@tonic-gate /* FUNCTION  : acl_countusers                                            */
1290*0Sstevel@tonic-gate /* PURPOSE   : Return the number of users in the specified class.        */
1291*0Sstevel@tonic-gate /* ARGUMENTS : The name of the class to count.                           */
1292*0Sstevel@tonic-gate /*************************************************************************/
1293*0Sstevel@tonic-gate 
1294*0Sstevel@tonic-gate int acl_countusers(char *class)
1295*0Sstevel@tonic-gate {
1296*0Sstevel@tonic-gate     int count = 0, opidfd = pidfd;
1297*0Sstevel@tonic-gate 
1298*0Sstevel@tonic-gate     if (Bypass_PID_Files)
1299*0Sstevel@tonic-gate 	return (0);
1300*0Sstevel@tonic-gate 
1301*0Sstevel@tonic-gate     if (pidfd < 0) {
1302*0Sstevel@tonic-gate 	if ((pidfd = open_pidfile(class)) < 0)
1303*0Sstevel@tonic-gate 	    return (-1);
1304*0Sstevel@tonic-gate     }
1305*0Sstevel@tonic-gate 
1306*0Sstevel@tonic-gate     count = limit_op(ACL_COUNT, 0);
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate     /*
1309*0Sstevel@tonic-gate      * acl_countusers may be called from msg_massage before the correct class
1310*0Sstevel@tonic-gate      * is known, so close the pid file if we opened it.
1311*0Sstevel@tonic-gate      */
1312*0Sstevel@tonic-gate     if (opidfd < 0) {
1313*0Sstevel@tonic-gate 	close(pidfd);
1314*0Sstevel@tonic-gate 	pidfd = -1;
1315*0Sstevel@tonic-gate     }
1316*0Sstevel@tonic-gate     return (count);
1317*0Sstevel@tonic-gate }
1318*0Sstevel@tonic-gate 
1319*0Sstevel@tonic-gate /*************************************************************************/
1320*0Sstevel@tonic-gate /* FUNCTION  : acl_join                                                  */
1321*0Sstevel@tonic-gate /* PURPOSE   : Add the current process to the list of processes in the   */
1322*0Sstevel@tonic-gate /*             specified class.                                          */
1323*0Sstevel@tonic-gate /* ARGUMENTS : The name of the class to join, user limit for the class.  */
1324*0Sstevel@tonic-gate /* RETURNS   : 0 on success, -1 on failure                               */
1325*0Sstevel@tonic-gate /*************************************************************************/
1326*0Sstevel@tonic-gate 
1327*0Sstevel@tonic-gate int acl_join(char *class, int limit)
1328*0Sstevel@tonic-gate {
1329*0Sstevel@tonic-gate     if (Bypass_PID_Files)
1330*0Sstevel@tonic-gate 	return (0);
1331*0Sstevel@tonic-gate 
1332*0Sstevel@tonic-gate     if (pidfd < 0) {
1333*0Sstevel@tonic-gate 	if ((pidfd = open_pidfile(class)) < 0)
1334*0Sstevel@tonic-gate 	    return (-1);
1335*0Sstevel@tonic-gate     }
1336*0Sstevel@tonic-gate 
1337*0Sstevel@tonic-gate     if (limit_op(ACL_JOIN, limit) < 0) {
1338*0Sstevel@tonic-gate 	/* no need to leave the pid file open as we were not added to it */
1339*0Sstevel@tonic-gate 	close(pidfd);
1340*0Sstevel@tonic-gate 	pidfd = -1;
1341*0Sstevel@tonic-gate 	return (-1);
1342*0Sstevel@tonic-gate     }
1343*0Sstevel@tonic-gate     /* pidfd left open so can be updated after a chroot */
1344*0Sstevel@tonic-gate     return (0);
1345*0Sstevel@tonic-gate }
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate /*************************************************************************/
1348*0Sstevel@tonic-gate /* FUNCTION  : acl_remove                                                */
1349*0Sstevel@tonic-gate /* PURPOSE   : Remove the current process from the list of processes in  */
1350*0Sstevel@tonic-gate /*             our class.                                                */
1351*0Sstevel@tonic-gate /* ARGUMENTS : None.                                                     */
1352*0Sstevel@tonic-gate /*************************************************************************/
1353*0Sstevel@tonic-gate 
1354*0Sstevel@tonic-gate void acl_remove(void)
1355*0Sstevel@tonic-gate {
1356*0Sstevel@tonic-gate     if (pidfd < 0)
1357*0Sstevel@tonic-gate 	return;
1358*0Sstevel@tonic-gate     (void) limit_op(ACL_REMOVE, 0);
1359*0Sstevel@tonic-gate     close(pidfd);
1360*0Sstevel@tonic-gate     pidfd = -1;
1361*0Sstevel@tonic-gate }
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate /*************************************************************************/
1364*0Sstevel@tonic-gate /* FUNCTION  : pr_mesg                                                   */
1365*0Sstevel@tonic-gate /* PURPOSE   : Display a message to the user                             */
1366*0Sstevel@tonic-gate /* ARGUMENTS : message code, name of file to display                     */
1367*0Sstevel@tonic-gate /*************************************************************************/
1368*0Sstevel@tonic-gate 
1369*0Sstevel@tonic-gate void pr_mesg(int msgcode, char *msgfile)
1370*0Sstevel@tonic-gate {
1371*0Sstevel@tonic-gate     FILE *infile;
1372*0Sstevel@tonic-gate     char inbuf[BUFSIZ], outbuf[BUFSIZ], *cr;
1373*0Sstevel@tonic-gate 
1374*0Sstevel@tonic-gate     if (msgfile && (int) strlen(msgfile) > 0) {
1375*0Sstevel@tonic-gate 	infile = fopen(msgfile, "r");
1376*0Sstevel@tonic-gate 	if (infile) {
1377*0Sstevel@tonic-gate 	    while (fgets(inbuf, sizeof(inbuf), infile) != NULL) {
1378*0Sstevel@tonic-gate 		if ((cr = strchr(inbuf, '\n')) != NULL)
1379*0Sstevel@tonic-gate 		    *cr = '\0';
1380*0Sstevel@tonic-gate 		msg_massage(inbuf, outbuf, sizeof(outbuf));
1381*0Sstevel@tonic-gate 		lreply(msgcode, "%s", outbuf);
1382*0Sstevel@tonic-gate 	    }
1383*0Sstevel@tonic-gate 	    fclose(infile);
1384*0Sstevel@tonic-gate 	}
1385*0Sstevel@tonic-gate     }
1386*0Sstevel@tonic-gate }
1387*0Sstevel@tonic-gate 
1388*0Sstevel@tonic-gate /*************************************************************************/
1389*0Sstevel@tonic-gate /* FUNCTION  : access_init                                               */
1390*0Sstevel@tonic-gate /* PURPOSE   : Read and parse the access lists to set things up          */
1391*0Sstevel@tonic-gate /* ARGUMENTS : none                                                      */
1392*0Sstevel@tonic-gate /*************************************************************************/
1393*0Sstevel@tonic-gate 
1394*0Sstevel@tonic-gate void access_init(void)
1395*0Sstevel@tonic-gate {
1396*0Sstevel@tonic-gate     struct aclmember *entry;
1397*0Sstevel@tonic-gate     static struct stat sbuf_last;
1398*0Sstevel@tonic-gate     struct stat sbuf_cur;
1399*0Sstevel@tonic-gate 
1400*0Sstevel@tonic-gate     if (!use_accessfile)
1401*0Sstevel@tonic-gate 	return;
1402*0Sstevel@tonic-gate 
1403*0Sstevel@tonic-gate     if (stat(_path_ftpaccess, &sbuf_cur) != 0) {
1404*0Sstevel@tonic-gate 	syslog(LOG_ERR, "cannot stat access file %s: %s", _path_ftpaccess,
1405*0Sstevel@tonic-gate                strerror(errno));
1406*0Sstevel@tonic-gate 	return;
1407*0Sstevel@tonic-gate     }
1408*0Sstevel@tonic-gate     /* only reload the ftpaccess file if its changed */
1409*0Sstevel@tonic-gate     if ((sbuf_last.st_mtime == sbuf_cur.st_mtime) &&
1410*0Sstevel@tonic-gate 	(sbuf_last.st_ino == sbuf_cur.st_ino) &&
1411*0Sstevel@tonic-gate 	(sbuf_last.st_dev == sbuf_cur.st_dev))
1412*0Sstevel@tonic-gate 	return;
1413*0Sstevel@tonic-gate 
1414*0Sstevel@tonic-gate     sbuf_last = sbuf_cur;
1415*0Sstevel@tonic-gate 
1416*0Sstevel@tonic-gate #ifdef OTHER_PASSWD
1417*0Sstevel@tonic-gate     strcpy(_path_passwd, "/etc/passwd");
1418*0Sstevel@tonic-gate #ifdef SHADOW_PASSWORD
1419*0Sstevel@tonic-gate     strcpy(_path_shadow, "/etc/shadow");
1420*0Sstevel@tonic-gate #endif
1421*0Sstevel@tonic-gate #endif
1422*0Sstevel@tonic-gate #if defined(USE_PAM) && defined(OTHER_PASSWD)
1423*0Sstevel@tonic-gate     use_pam = 1;
1424*0Sstevel@tonic-gate #endif
1425*0Sstevel@tonic-gate     Shutdown[0] = '\0';
1426*0Sstevel@tonic-gate     keepalive = 0;
1427*0Sstevel@tonic-gate 
1428*0Sstevel@tonic-gate     if (!readacl(_path_ftpaccess))
1429*0Sstevel@tonic-gate 	return;
1430*0Sstevel@tonic-gate     (void) parseacl();
1431*0Sstevel@tonic-gate 
1432*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
1433*0Sstevel@tonic-gate     if (getaclentry("shutdown", &entry) && ARG0 != NULL)
1434*0Sstevel@tonic-gate 	(void) strncpy(Shutdown, ARG0, sizeof(Shutdown));
1435*0Sstevel@tonic-gate #ifdef OTHER_PASSWD
1436*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
1437*0Sstevel@tonic-gate     while (getaclentry("passwd", &entry) && ARG0 != NULL) {
1438*0Sstevel@tonic-gate 	    strcpy(_path_passwd, ARG0);
1439*0Sstevel@tonic-gate #ifdef USE_PAM
1440*0Sstevel@tonic-gate 	    use_pam = 0;
1441*0Sstevel@tonic-gate #endif
1442*0Sstevel@tonic-gate     }
1443*0Sstevel@tonic-gate #ifdef SHADOW_PASSWORD
1444*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
1445*0Sstevel@tonic-gate     while (getaclentry("shadow", &entry) && ARG0 != NULL) {
1446*0Sstevel@tonic-gate 	    strcpy(_path_shadow, ARG0);
1447*0Sstevel@tonic-gate #ifdef USE_PAM
1448*0Sstevel@tonic-gate 	    use_pam = 0;
1449*0Sstevel@tonic-gate #endif
1450*0Sstevel@tonic-gate     }
1451*0Sstevel@tonic-gate #endif
1452*0Sstevel@tonic-gate #endif
1453*0Sstevel@tonic-gate     entry = (struct aclmember *) NULL;
1454*0Sstevel@tonic-gate     if (getaclentry("keepalive", &entry) && ARG0 != NULL)
1455*0Sstevel@tonic-gate 	if (!strcasecmp(ARG0, "yes"))
1456*0Sstevel@tonic-gate 	    keepalive = 1;
1457*0Sstevel@tonic-gate }
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate /*************************************************************************/
1460*0Sstevel@tonic-gate /* FUNCTION  : access_ok                                                 */
1461*0Sstevel@tonic-gate /* PURPOSE   : Check the anonymous FTP access lists to see if this       */
1462*0Sstevel@tonic-gate /*             access is permitted.                                      */
1463*0Sstevel@tonic-gate /* ARGUMENTS : reply code to use                                         */
1464*0Sstevel@tonic-gate /*************************************************************************/
1465*0Sstevel@tonic-gate 
1466*0Sstevel@tonic-gate int access_ok(int msgcode)
1467*0Sstevel@tonic-gate {
1468*0Sstevel@tonic-gate     char class[BUFSIZ], msgfile[MAXPATHLEN];
1469*0Sstevel@tonic-gate     int limit;
1470*0Sstevel@tonic-gate     int nice_delta;
1471*0Sstevel@tonic-gate 
1472*0Sstevel@tonic-gate     if (!use_accessfile)
1473*0Sstevel@tonic-gate 	return (1);
1474*0Sstevel@tonic-gate 
1475*0Sstevel@tonic-gate     if (aclbuf == NULL) {
1476*0Sstevel@tonic-gate 	syslog(LOG_NOTICE,
1477*0Sstevel@tonic-gate 	       "ACCESS DENIED (error reading access file) TO %s",
1478*0Sstevel@tonic-gate 	       remoteident);
1479*0Sstevel@tonic-gate 	return (0);
1480*0Sstevel@tonic-gate     }
1481*0Sstevel@tonic-gate     if (acl_deny(msgfile)) {
1482*0Sstevel@tonic-gate #ifndef HELP_CRACKERS
1483*0Sstevel@tonic-gate 	memcpy(DelayedMessageFile, msgfile, sizeof(msgfile));
1484*0Sstevel@tonic-gate #else
1485*0Sstevel@tonic-gate 	pr_mesg(msgcode, msgfile);
1486*0Sstevel@tonic-gate #endif
1487*0Sstevel@tonic-gate 	syslog(LOG_NOTICE, "ACCESS DENIED (deny command) TO %s",
1488*0Sstevel@tonic-gate 	       remoteident);
1489*0Sstevel@tonic-gate 	return (0);
1490*0Sstevel@tonic-gate     }
1491*0Sstevel@tonic-gate     /* if user is not in any class, deny access */
1492*0Sstevel@tonic-gate     if (!acl_getclass(class)) {
1493*0Sstevel@tonic-gate 	syslog(LOG_NOTICE, "ACCESS DENIED (not in any class) TO %s",
1494*0Sstevel@tonic-gate 	       remoteident);
1495*0Sstevel@tonic-gate 	return (0);
1496*0Sstevel@tonic-gate     }
1497*0Sstevel@tonic-gate 
1498*0Sstevel@tonic-gate     limit = acl_getlimit(class, msgfile);
1499*0Sstevel@tonic-gate     if (acl_join(class, limit) < 0) {
1500*0Sstevel@tonic-gate #ifdef LOG_TOOMANY
1501*0Sstevel@tonic-gate 	syslog(LOG_NOTICE, "ACCESS DENIED (user limit %d; class %s) TO %s",
1502*0Sstevel@tonic-gate 	       limit, class, remoteident);
1503*0Sstevel@tonic-gate #endif
1504*0Sstevel@tonic-gate #ifndef HELP_CRACKERS
1505*0Sstevel@tonic-gate 	memcpy(DelayedMessageFile, msgfile, sizeof(msgfile));
1506*0Sstevel@tonic-gate #else
1507*0Sstevel@tonic-gate 	pr_mesg(msgcode, msgfile);
1508*0Sstevel@tonic-gate #endif
1509*0Sstevel@tonic-gate 	return (-1);
1510*0Sstevel@tonic-gate     }
1511*0Sstevel@tonic-gate 
1512*0Sstevel@tonic-gate     if ((nice_delta = acl_getnice(class))) {
1513*0Sstevel@tonic-gate 	if (nice_delta < 0)
1514*0Sstevel@tonic-gate 	    syslog(LOG_NOTICE, "Process nice value adjusted by %d", nice_delta);
1515*0Sstevel@tonic-gate 	nice(nice_delta);
1516*0Sstevel@tonic-gate     }
1517*0Sstevel@tonic-gate     acl_getdefumask(class);
1518*0Sstevel@tonic-gate     acl_tcpwindow(class);
1519*0Sstevel@tonic-gate #ifdef TRANSFER_COUNT
1520*0Sstevel@tonic-gate #ifdef TRANSFER_LIMIT
1521*0Sstevel@tonic-gate     acl_filelimit(class);
1522*0Sstevel@tonic-gate     acl_datalimit(class);
1523*0Sstevel@tonic-gate #ifdef RATIO
1524*0Sstevel@tonic-gate     acl_downloadrate(class);
1525*0Sstevel@tonic-gate #endif
1526*0Sstevel@tonic-gate #endif
1527*0Sstevel@tonic-gate #endif
1528*0Sstevel@tonic-gate     acl_bufsize();
1529*0Sstevel@tonic-gate     get_xferlog_format();
1530*0Sstevel@tonic-gate     return (1);
1531*0Sstevel@tonic-gate }
1532