xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/extensions.c (revision 12333:f835be4545bb)
10Sstevel@tonic-gate /*
2*12333SMilan.Jurik@Sun.COM  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate  */
40Sstevel@tonic-gate 
50Sstevel@tonic-gate /****************************************************************************
60Sstevel@tonic-gate 
70Sstevel@tonic-gate   Copyright (c) 1999,2000 WU-FTPD Development Group.
80Sstevel@tonic-gate   All rights reserved.
90Sstevel@tonic-gate 
100Sstevel@tonic-gate   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
110Sstevel@tonic-gate     The Regents of the University of California.
120Sstevel@tonic-gate   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
130Sstevel@tonic-gate   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
140Sstevel@tonic-gate   Portions Copyright (c) 1989 Massachusetts Institute of Technology.
150Sstevel@tonic-gate   Portions Copyright (c) 1998 Sendmail, Inc.
160Sstevel@tonic-gate   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman.
170Sstevel@tonic-gate   Portions Copyright (c) 1997 by Stan Barber.
180Sstevel@tonic-gate   Portions Copyright (c) 1997 by Kent Landfield.
190Sstevel@tonic-gate   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
200Sstevel@tonic-gate     Free Software Foundation, Inc.
210Sstevel@tonic-gate 
220Sstevel@tonic-gate   Use and distribution of this software and its source code are governed
230Sstevel@tonic-gate   by the terms and conditions of the WU-FTPD Software License ("LICENSE").
240Sstevel@tonic-gate 
250Sstevel@tonic-gate   If you did not receive a copy of the license, it may be obtained online
260Sstevel@tonic-gate   at http://www.wu-ftpd.org/license.html.
270Sstevel@tonic-gate 
280Sstevel@tonic-gate   $Id: extensions.c,v 1.48 2000/07/01 18:17:38 wuftpd Exp $
290Sstevel@tonic-gate 
300Sstevel@tonic-gate ****************************************************************************/
310Sstevel@tonic-gate #include "config.h"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <stdio.h>
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include <string.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #ifdef HAVE_SYS_SYSLOG_H
380Sstevel@tonic-gate #include <sys/syslog.h>
390Sstevel@tonic-gate #endif
400Sstevel@tonic-gate #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))
410Sstevel@tonic-gate #include <syslog.h>
420Sstevel@tonic-gate #endif
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #ifdef TIME_WITH_SYS_TIME
450Sstevel@tonic-gate #include <time.h>
460Sstevel@tonic-gate #include <sys/time.h>
470Sstevel@tonic-gate #else
480Sstevel@tonic-gate #ifdef HAVE_SYS_TIME_H
490Sstevel@tonic-gate #include <sys/time.h>
500Sstevel@tonic-gate #else
510Sstevel@tonic-gate #include <time.h>
520Sstevel@tonic-gate #endif
530Sstevel@tonic-gate #endif
540Sstevel@tonic-gate #include <pwd.h>
550Sstevel@tonic-gate #include <setjmp.h>
560Sstevel@tonic-gate #include <grp.h>
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #include <sys/types.h>
590Sstevel@tonic-gate #include <sys/stat.h>
600Sstevel@tonic-gate #include <sys/file.h>
610Sstevel@tonic-gate #include <sys/param.h>
620Sstevel@tonic-gate 
630Sstevel@tonic-gate #ifdef HAVE_SYS_FS_UFS_QUOTA_H
640Sstevel@tonic-gate #include <sys/fs/ufs_quota.h>
650Sstevel@tonic-gate #elif defined(HAVE_UFS_UFS_QUOTA_H)
660Sstevel@tonic-gate #include <ufs/ufs/quota.h>
670Sstevel@tonic-gate #elif defined(HAVE_UFS_QUOTA_H)
680Sstevel@tonic-gate #include <ufs/quota.h>
690Sstevel@tonic-gate #elif defined(HAVE_SYS_MNTENT_H)
700Sstevel@tonic-gate #include <sys/mntent.h>
710Sstevel@tonic-gate #elif defined(HAVE_SYS_MNTTAB_H)
720Sstevel@tonic-gate #include <sys/mnttab.h>
730Sstevel@tonic-gate #endif
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #if defined(HAVE_STATVFS)
760Sstevel@tonic-gate #include <sys/statvfs.h>
770Sstevel@tonic-gate #elif defined(HAVE_SYS_VFS)
780Sstevel@tonic-gate #include <sys/vfs.h>
790Sstevel@tonic-gate #elif defined(HAVE_SYS_MOUNT)
800Sstevel@tonic-gate #include <sys/mount.h>
810Sstevel@tonic-gate #endif
820Sstevel@tonic-gate 
830Sstevel@tonic-gate #include <arpa/ftp.h>
840Sstevel@tonic-gate 
850Sstevel@tonic-gate #ifdef HAVE_PATHS_H
860Sstevel@tonic-gate #include <paths.h>
870Sstevel@tonic-gate #endif
880Sstevel@tonic-gate #include "pathnames.h"
890Sstevel@tonic-gate #include "extensions.h"
900Sstevel@tonic-gate #include "wu_fnmatch.h"
910Sstevel@tonic-gate #include "proto.h"
920Sstevel@tonic-gate 
930Sstevel@tonic-gate #if defined(HAVE_FTW)
940Sstevel@tonic-gate #include <ftw.h>
950Sstevel@tonic-gate #else
960Sstevel@tonic-gate #include "support/ftw.h"
970Sstevel@tonic-gate #endif
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #ifdef QUOTA
1000Sstevel@tonic-gate struct dqblk quota;
1010Sstevel@tonic-gate char *time_quota(long curstate, long softlimit, long timelimit, char *timeleft);
1020Sstevel@tonic-gate #endif
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #ifdef HAVE_REGEX_H
1050Sstevel@tonic-gate #include <regex.h>
1060Sstevel@tonic-gate #endif
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate #if defined(HAVE_REGEX) && defined(SVR4) && ! (defined(NO_LIBGEN))
1090Sstevel@tonic-gate #include <libgen.h>
1100Sstevel@tonic-gate #endif
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate extern int type, transflag, ftwflag, authenticated, autospout_free, data,
1130Sstevel@tonic-gate     pdata, anonymous, guest;
1140Sstevel@tonic-gate extern char chroot_path[], guestpw[];
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate #ifdef TRANSFER_COUNT
1170Sstevel@tonic-gate extern off_t data_count_in;
1180Sstevel@tonic-gate extern off_t data_count_out;
1190Sstevel@tonic-gate #ifdef TRANSFER_LIMIT
1200Sstevel@tonic-gate extern off_t data_limit_raw_in;
1210Sstevel@tonic-gate extern off_t data_limit_raw_out;
1220Sstevel@tonic-gate extern off_t data_limit_raw_total;
1230Sstevel@tonic-gate extern off_t data_limit_data_in;
1240Sstevel@tonic-gate extern off_t data_limit_data_out;
1250Sstevel@tonic-gate extern off_t data_limit_data_total;
1260Sstevel@tonic-gate #ifdef RATIO /* 1998/08/06 K.Wakui */
1270Sstevel@tonic-gate #define TRUNC_KB(n)   ((n)/1024+(((n)%1024)?1:0))
1280Sstevel@tonic-gate extern time_t	login_time;
1290Sstevel@tonic-gate extern time_t	limit_time;
1300Sstevel@tonic-gate extern off_t    total_free_dl;
1310Sstevel@tonic-gate extern int      upload_download_rate;
1320Sstevel@tonic-gate #endif /* RATIO */
1330Sstevel@tonic-gate #endif
1340Sstevel@tonic-gate #endif
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate #ifdef OTHER_PASSWD
1370Sstevel@tonic-gate #include "getpwnam.h"
1380Sstevel@tonic-gate extern char _path_passwd[];
1390Sstevel@tonic-gate #endif
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate #ifdef LOG_FAILED
1420Sstevel@tonic-gate extern char the_user[];
1430Sstevel@tonic-gate #endif
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate extern char *globerr, remotehost[];
1460Sstevel@tonic-gate #ifdef THROUGHPUT
1470Sstevel@tonic-gate extern char remoteaddr[];
1480Sstevel@tonic-gate #endif
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate #ifndef HAVE_REGEX
1510Sstevel@tonic-gate char *re_comp(const char *regex);
1520Sstevel@tonic-gate int re_exec(const char *p1);
1530Sstevel@tonic-gate #endif
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate char shuttime[30], denytime[30], disctime[30];
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate FILE *dout;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate time_t newer_time;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate int show_fullinfo;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate /* This always was a bug, because neither st_size nor time_t were required to
1640Sstevel@tonic-gate    be compatible with int, but needs fixing properly for C9X. */
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /* Some systems use one format, some another.  This takes care of the garbage */
1670Sstevel@tonic-gate /* Do the system specific stuff only if we aren't autoconfed */
1680Sstevel@tonic-gate #if !defined(L_FORMAT)
1690Sstevel@tonic-gate #if (defined(BSD) && (BSD >= 199103)) && !defined(LONGOFF_T)
1700Sstevel@tonic-gate #define L_FORMAT "qd"
1710Sstevel@tonic-gate #else
1720Sstevel@tonic-gate #define L_FORMAT "d"
1730Sstevel@tonic-gate #endif
1740Sstevel@tonic-gate #endif
1750Sstevel@tonic-gate #if !defined(T_FORMAT)
1760Sstevel@tonic-gate #define T_FORMAT "d"
1770Sstevel@tonic-gate #endif
1780Sstevel@tonic-gate #if !defined(PW_UID_FORMAT)
1790Sstevel@tonic-gate #define PW_UID_FORMAT "d"
1800Sstevel@tonic-gate #endif
1810Sstevel@tonic-gate #if !defined(GR_GID_FORMAT)
1820Sstevel@tonic-gate #define GR_GID_FORMAT "d"
1830Sstevel@tonic-gate #endif
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate int snprintf(char *str, size_t count, const char *fmt,...);
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate #ifdef SITE_NEWER
check_newer(const char * path,const struct stat * st,int flag)1880Sstevel@tonic-gate int check_newer(const char *path, const struct stat *st, int flag)
1890Sstevel@tonic-gate {
1900Sstevel@tonic-gate     if (st->st_mtime > newer_time) {
1910Sstevel@tonic-gate 	if (show_fullinfo != 0) {
1920Sstevel@tonic-gate 	    if (flag == FTW_F || flag == FTW_D) {
1930Sstevel@tonic-gate 		fprintf(dout, "%s %" L_FORMAT " %" T_FORMAT " %s\n",
1940Sstevel@tonic-gate 			flag == FTW_F ? "F" : "D",
1950Sstevel@tonic-gate 			st->st_size, st->st_mtime, path);
1960Sstevel@tonic-gate 	    }
1970Sstevel@tonic-gate 	}
1980Sstevel@tonic-gate 	else if (flag == FTW_F)
1990Sstevel@tonic-gate 	    fprintf(dout, "%s\n", path);
2000Sstevel@tonic-gate     }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate     /* When an ABOR has been received (which sets ftwflag > 1) return a
2030Sstevel@tonic-gate      * non-zero value which causes ftw to stop tree traversal and return.
2040Sstevel@tonic-gate      */
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate     return (ftwflag > 1 ? 1 : 0);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate #endif
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate #if defined(HAVE_STATVFS)
getSize(char * s)2110Sstevel@tonic-gate long getSize(char *s)
2120Sstevel@tonic-gate {
2130Sstevel@tonic-gate     struct statvfs buf;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate     if (statvfs(s, &buf) != 0)
2160Sstevel@tonic-gate 	return (0);
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate     return (buf.f_bavail * buf.f_frsize / 1024);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate #elif defined(HAVE_SYS_VFS) || defined (HAVE_SYS_MOUNT)
getSize(char * s)2210Sstevel@tonic-gate long getSize(char *s)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate     struct statfs buf;
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate     if (statfs(s, &buf) != 0)
2260Sstevel@tonic-gate 	return (0);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate     return (buf.f_bavail * buf.f_bsize / 1024);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate #endif
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*************************************************************************/
2330Sstevel@tonic-gate /* FUNCTION  : msg_massage                                               */
2340Sstevel@tonic-gate /* PURPOSE   : Scan a message line for magic cookies, replacing them as  */
2350Sstevel@tonic-gate /*             needed.                                                   */
2360Sstevel@tonic-gate /* ARGUMENTS : pointer input and output buffers                          */
2370Sstevel@tonic-gate /*************************************************************************/
2380Sstevel@tonic-gate 
msg_massage(const char * inbuf,char * outbuf,size_t outlen)2390Sstevel@tonic-gate void msg_massage(const char *inbuf, char *outbuf, size_t outlen)
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate     const char *inptr = inbuf;
2420Sstevel@tonic-gate     char *outptr = outbuf;
2430Sstevel@tonic-gate #ifdef QUOTA
2440Sstevel@tonic-gate     char timeleft[80];
2450Sstevel@tonic-gate #endif
2460Sstevel@tonic-gate     char buffer[MAXPATHLEN];
2470Sstevel@tonic-gate     time_t curtime;
2480Sstevel@tonic-gate     int limit;
2490Sstevel@tonic-gate #ifndef LOG_FAILED
2500Sstevel@tonic-gate     extern struct passwd *pw;
2510Sstevel@tonic-gate #endif
2520Sstevel@tonic-gate     struct aclmember *entry;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate #ifdef VIRTUAL
2550Sstevel@tonic-gate     extern int virtual_mode;
2560Sstevel@tonic-gate     extern int virtual_ftpaccess;
2570Sstevel@tonic-gate     extern char virtual_email[];
2580Sstevel@tonic-gate #endif
2590Sstevel@tonic-gate     extern char hostname[];
2600Sstevel@tonic-gate     extern char authuser[];
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate     (void) acl_getclass(buffer);
2630Sstevel@tonic-gate     limit = acl_getlimit(buffer, NULL);
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate     while ((outlen > 1) && (*inptr != '\0')) {
2660Sstevel@tonic-gate 	if (*inptr != '%') {
2670Sstevel@tonic-gate 	    *outptr++ = *inptr;
2680Sstevel@tonic-gate 	    outlen -= 1;
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 	else {
2710Sstevel@tonic-gate 	    entry = NULL;
2720Sstevel@tonic-gate 	    switch (*++inptr) {
2730Sstevel@tonic-gate 	    case 'E':
2740Sstevel@tonic-gate #ifdef VIRTUAL
2750Sstevel@tonic-gate 		if (virtual_mode && !virtual_ftpaccess && virtual_email[0] != '\0')
2760Sstevel@tonic-gate 		    snprintf(outptr, outlen, "%s", virtual_email);
2770Sstevel@tonic-gate 		else
2780Sstevel@tonic-gate #endif
2790Sstevel@tonic-gate 		if ((getaclentry("email", &entry)) && ARG0)
2800Sstevel@tonic-gate 		    snprintf(outptr, outlen, "%s", ARG0);
2810Sstevel@tonic-gate 		else
2820Sstevel@tonic-gate 		    *outptr = '\0';
2830Sstevel@tonic-gate 		break;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	    case 'N':
2860Sstevel@tonic-gate 		snprintf(outptr, outlen, "%d", acl_countusers(buffer));
2870Sstevel@tonic-gate 		break;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	    case 'M':
2900Sstevel@tonic-gate 		if (limit == -1)
2910Sstevel@tonic-gate 		    strncpy(outptr, "unlimited", outlen);
2920Sstevel@tonic-gate 		else
2930Sstevel@tonic-gate 		    snprintf(outptr, outlen, "%d", limit);
2940Sstevel@tonic-gate 		break;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	    case 'T':
2970Sstevel@tonic-gate 		(void) time(&curtime);
2980Sstevel@tonic-gate 		strncpy(outptr, ctime(&curtime), outlen);
2990Sstevel@tonic-gate 		if (outlen > 24)
3000Sstevel@tonic-gate 		    *(outptr + 24) = '\0';
3010Sstevel@tonic-gate 		break;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	    case 'F':
3040Sstevel@tonic-gate #if defined(HAVE_STATVFS) || defined(HAVE_SYS_VFS) || defined(HAVE_SYS_MOUNT)
3050Sstevel@tonic-gate 		snprintf(outptr, outlen, "%lu", (long) getSize("."));
3060Sstevel@tonic-gate #else
3070Sstevel@tonic-gate 		*outptr = '\0';
3080Sstevel@tonic-gate #endif
3090Sstevel@tonic-gate 		break;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	    case 'C':
3120Sstevel@tonic-gate #ifdef HAVE_GETCWD
3130Sstevel@tonic-gate 		(void) getcwd(outptr, outlen);
3140Sstevel@tonic-gate #else
3150Sstevel@tonic-gate #error	wu-ftpd on this platform has security deficiencies!!!
3160Sstevel@tonic-gate 		(void) getwd(outptr);
3170Sstevel@tonic-gate #endif
3180Sstevel@tonic-gate 		break;
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	    case 'R':
3210Sstevel@tonic-gate 		strncpy(outptr, remotehost, outlen);
3220Sstevel@tonic-gate 		break;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	    case 'L':
3250Sstevel@tonic-gate 		strncpy(outptr, hostname, outlen);
3260Sstevel@tonic-gate 		break;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	    case 'U':
3290Sstevel@tonic-gate 		if (xferdone && anonymous)
3300Sstevel@tonic-gate 		    strncpy(outptr, guestpw, outlen);
3310Sstevel@tonic-gate 		else
3320Sstevel@tonic-gate #ifdef LOG_FAILED
3330Sstevel@tonic-gate 		    strncpy(outptr, the_user, outlen);
3340Sstevel@tonic-gate #else /* LOG_FAILED */
3350Sstevel@tonic-gate 		    strncpy(outptr,
3360Sstevel@tonic-gate 			    (pw == NULL) ? "[unknown]" : pw->pw_name, outlen);
3370Sstevel@tonic-gate #endif /* LOG_FAILED */
3380Sstevel@tonic-gate 		break;
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	    case 's':
3410Sstevel@tonic-gate 		strncpy(outptr, shuttime, outlen);
3420Sstevel@tonic-gate 		if (outlen > 24)
3430Sstevel@tonic-gate 		    *(outptr + 24) = '\0';
3440Sstevel@tonic-gate 		break;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	    case 'd':
3470Sstevel@tonic-gate 		strncpy(outptr, disctime, outlen);
3480Sstevel@tonic-gate 		if (outlen > 24)
3490Sstevel@tonic-gate 		    *(outptr + 24) = '\0';
3500Sstevel@tonic-gate 		break;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	    case 'r':
3530Sstevel@tonic-gate 		strncpy(outptr, denytime, outlen);
3540Sstevel@tonic-gate 		if (outlen > 24)
3550Sstevel@tonic-gate 		    *(outptr + 24) = '\0';
3560Sstevel@tonic-gate 		break;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate /* KH : cookie %u for RFC931 name */
3590Sstevel@tonic-gate 	    case 'u':
3600Sstevel@tonic-gate 		if (authenticated)
3610Sstevel@tonic-gate 		    strncpy(outptr, authuser, outlen);
3620Sstevel@tonic-gate 		else {
3630Sstevel@tonic-gate 		    if (xferdone)
3640Sstevel@tonic-gate 			snprintf(outptr, outlen, "%c", '*');
3650Sstevel@tonic-gate 		    else
3660Sstevel@tonic-gate 			strncpy(outptr, "[unknown]", outlen);
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 		break;
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate #ifdef QUOTA
3710Sstevel@tonic-gate 	    case 'B':
3720Sstevel@tonic-gate #ifdef QUOTA_BLOCKS		/* 1024-blocks instead of 512-blocks */
3730Sstevel@tonic-gate 		snprintf(outptr, outlen, "%ld", quota.dqb_bhardlimit % 2 ?
3740Sstevel@tonic-gate 			 (long) (quota.dqb_bhardlimit / 2 + 1) : (long) (quota.dqb_bhardlimit / 2));
3750Sstevel@tonic-gate #else
3760Sstevel@tonic-gate 		snprintf(outptr, outlen, "%ld", (long) quota.dqb_bhardlimit);
3770Sstevel@tonic-gate #endif
3780Sstevel@tonic-gate 		break;
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	    case 'b':
3810Sstevel@tonic-gate #ifdef QUOTA_BLOCKS		/* 1024-blocks instead of 512-blocks */
3820Sstevel@tonic-gate 		snprintf(outptr, outlen, "%ld", quota.dqb_bsoftlimit % 2 ?
3830Sstevel@tonic-gate 			 (long) (quota.dqb_bsoftlimit / 2 + 1) : (long) (quota.dqb_bsoftlimit / 2));
3840Sstevel@tonic-gate #else
3850Sstevel@tonic-gate 		snprintf(outptr, outlen, "%ld", (long) quota.dqb_bsoftlimit);
3860Sstevel@tonic-gate #endif
3870Sstevel@tonic-gate 		break;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	    case 'Q':
3900Sstevel@tonic-gate #ifdef QUOTA_BLOCKS		/* 1024-blocks instead of 512-blocks */
3910Sstevel@tonic-gate 		snprintf(outptr, outlen, "%ld", quota.dqb_curblocks % 2 ?
3920Sstevel@tonic-gate 			 (long) (quota.dqb_curblocks / 2 + 1) : (long) (quota.dqb_curblocks / 2));
3930Sstevel@tonic-gate #else
3940Sstevel@tonic-gate 		snprintf(outptr, outlen, "%ld", quota.dqb_curblocks);
3950Sstevel@tonic-gate #endif
3960Sstevel@tonic-gate 		break;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	    case 'I':
3990Sstevel@tonic-gate #if defined(QUOTA_INODE)
4000Sstevel@tonic-gate 		snprintf(outptr, outlen, "%d", quota.dqb_ihardlimit);
4010Sstevel@tonic-gate #else
4020Sstevel@tonic-gate 		snprintf(outptr, outlen, "%ld", (long) quota.dqb_fhardlimit);
4030Sstevel@tonic-gate #endif
4040Sstevel@tonic-gate 		break;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	    case 'i':
4070Sstevel@tonic-gate #if defined(QUOTA_INODE)
4080Sstevel@tonic-gate 		snprintf(outptr, outlen, "%d", quota.dqb_isoftlimit);
4090Sstevel@tonic-gate #else
4100Sstevel@tonic-gate 		snprintf(outptr, outlen, "%ld", (long) quota.dqb_fsoftlimit);
4110Sstevel@tonic-gate #endif
4120Sstevel@tonic-gate 		break;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	    case 'q':
4150Sstevel@tonic-gate #if defined(QUOTA_INODE)
4160Sstevel@tonic-gate 		snprintf(outptr, outlen, "%d", quota.dqb_curinodes);
4170Sstevel@tonic-gate #else
4180Sstevel@tonic-gate 		snprintf(outptr, outlen, "%ld", (long) quota.dqb_curfiles);
4190Sstevel@tonic-gate #endif
4200Sstevel@tonic-gate 		break;
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	    case 'H':
4230Sstevel@tonic-gate 		time_quota(quota.dqb_curblocks, quota.dqb_bsoftlimit,
4240Sstevel@tonic-gate #if defined(QUOTA_INODE)
4250Sstevel@tonic-gate 			   quota.dqb_btime, timeleft);
4260Sstevel@tonic-gate #else
4270Sstevel@tonic-gate 			   quota.dqb_btimelimit, timeleft);
4280Sstevel@tonic-gate #endif
4290Sstevel@tonic-gate 		strncpy(outptr, timeleft, outlen);
4300Sstevel@tonic-gate 		break;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	    case 'h':
4330Sstevel@tonic-gate #if defined(QUOTA_INODE)
4340Sstevel@tonic-gate 		time_quota(quota.dqb_curinodes, quota.dqb_isoftlimit,
4350Sstevel@tonic-gate 			   quota.dqb_itime, timeleft);
4360Sstevel@tonic-gate #else
4370Sstevel@tonic-gate 		time_quota(quota.dqb_curfiles, quota.dqb_fsoftlimit,
4380Sstevel@tonic-gate 			   quota.dqb_ftimelimit, timeleft);
4390Sstevel@tonic-gate #endif
4400Sstevel@tonic-gate 		strncpy(outptr, timeleft, outlen);
4410Sstevel@tonic-gate 		break;
4420Sstevel@tonic-gate #endif /* QUOTA */
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	    case '%':
4450Sstevel@tonic-gate 		*outptr++ = '%';
4460Sstevel@tonic-gate 		outlen -= 1;
4470Sstevel@tonic-gate 		*outptr = '\0';
4480Sstevel@tonic-gate 		break;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate #ifdef TRANSFER_COUNT
4510Sstevel@tonic-gate #ifdef TRANSFER_LIMIT
4520Sstevel@tonic-gate #ifdef RATIO
4530Sstevel@tonic-gate             case 'x':
4540Sstevel@tonic-gate                 switch (*++inptr) {
4550Sstevel@tonic-gate                 case 'u':       /* upload bytes */
4560Sstevel@tonic-gate                     sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_count_in) );
4570Sstevel@tonic-gate                     break;
4580Sstevel@tonic-gate                 case 'd':       /* download bytes */
4590Sstevel@tonic-gate                     sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_count_out) );
4600Sstevel@tonic-gate                     break;
4610Sstevel@tonic-gate                 case 'R':       /* rate 1:n */
4620Sstevel@tonic-gate                     if( upload_download_rate > 0 ) {
4630Sstevel@tonic-gate                         sprintf(outptr,"%d", upload_download_rate );
4640Sstevel@tonic-gate                     }
4650Sstevel@tonic-gate                     else {
4660Sstevel@tonic-gate                         strcpy(outptr,"free");
4670Sstevel@tonic-gate                     }
4680Sstevel@tonic-gate                     break;
4690Sstevel@tonic-gate                 case 'c':       /* credit bytes */
4700Sstevel@tonic-gate                     if( upload_download_rate > 0 ) {
4710Sstevel@tonic-gate                         off_t credit=( data_count_in * upload_download_rate) - (data_count_out - total_free_dl);
4720Sstevel@tonic-gate                         sprintf(outptr,"%" L_FORMAT, TRUNC_KB(credit) );
4730Sstevel@tonic-gate                     }
4740Sstevel@tonic-gate                     else {
4750Sstevel@tonic-gate                         strcpy(outptr,"unlimited");
4760Sstevel@tonic-gate                     }
4770Sstevel@tonic-gate                     break;
4780Sstevel@tonic-gate                 case 'T':       /* time limit (minutes) */
4790Sstevel@tonic-gate                     if( limit_time > 0 ) {
4800Sstevel@tonic-gate                         sprintf(outptr,"%d", limit_time );
4810Sstevel@tonic-gate                     }
4820Sstevel@tonic-gate                     else {
4830Sstevel@tonic-gate                         strcpy(outptr,"unlimited");
4840Sstevel@tonic-gate                     }
4850Sstevel@tonic-gate                     break;
4860Sstevel@tonic-gate                 case 'E':       /* elapsed time from loggedin (minutes) */
4870Sstevel@tonic-gate                     sprintf(outptr,"%d", (time(NULL)-login_time)/60 );
4880Sstevel@tonic-gate                     break;
4890Sstevel@tonic-gate                 case 'L':       /* times left until force logout (minutes) */
4900Sstevel@tonic-gate                     if( limit_time > 0 ) {
4910Sstevel@tonic-gate                         sprintf(outptr,"%d", limit_time-(time(NULL)-login_time)/60 );
4920Sstevel@tonic-gate                     }
4930Sstevel@tonic-gate                     else {
4940Sstevel@tonic-gate                         strcpy(outptr,"unlimited");
4950Sstevel@tonic-gate                     }
4960Sstevel@tonic-gate                     break;
4970Sstevel@tonic-gate                 case 'U':       /* upload limit */
4980Sstevel@tonic-gate 		    if( data_limit_raw_in > 0 ) {
4990Sstevel@tonic-gate 			sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_raw_in));
5000Sstevel@tonic-gate 		    }
5010Sstevel@tonic-gate 		    else if( data_limit_data_in > 0 ) {
5020Sstevel@tonic-gate 			sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_data_in));
5030Sstevel@tonic-gate 		    }
5040Sstevel@tonic-gate 		    else if( data_limit_raw_total > 0 ) {
5050Sstevel@tonic-gate 			sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_raw_total));
5060Sstevel@tonic-gate 		    }
5070Sstevel@tonic-gate 		    else if( data_limit_data_total > 0 ) {
5080Sstevel@tonic-gate 			sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_data_total));
5090Sstevel@tonic-gate 		    }
5100Sstevel@tonic-gate 		    else {
5110Sstevel@tonic-gate 			strcpy(outptr, "unlimited");
5120Sstevel@tonic-gate 		    }
5130Sstevel@tonic-gate                     break;
5140Sstevel@tonic-gate                 case 'D':       /* download limit */
5150Sstevel@tonic-gate 		    if( data_limit_raw_out > 0 ) {
5160Sstevel@tonic-gate 			sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_raw_out));
5170Sstevel@tonic-gate 		    }
5180Sstevel@tonic-gate 		    else if( data_limit_data_out > 0 ) {
5190Sstevel@tonic-gate 			sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_data_out));
5200Sstevel@tonic-gate 		    }
5210Sstevel@tonic-gate 		    else if( data_limit_raw_total > 0 ) {
5220Sstevel@tonic-gate 			sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_raw_total));
5230Sstevel@tonic-gate 		    }
5240Sstevel@tonic-gate 		    else if( data_limit_data_total > 0 ) {
5250Sstevel@tonic-gate 			sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_data_total));
5260Sstevel@tonic-gate 		    }
5270Sstevel@tonic-gate 		    else {
5280Sstevel@tonic-gate 			strcpy(outptr, "unlimited");
5290Sstevel@tonic-gate 		    }
5300Sstevel@tonic-gate                     break;
5310Sstevel@tonic-gate                 default:
5320Sstevel@tonic-gate                     strcpy(outptr,"%??");
5330Sstevel@tonic-gate                     break;
5340Sstevel@tonic-gate                 }
5350Sstevel@tonic-gate                 break;
5360Sstevel@tonic-gate #endif /* RATIO */
5370Sstevel@tonic-gate #endif
5380Sstevel@tonic-gate #endif
5390Sstevel@tonic-gate 		/* File transfer logging (xferlog) */
5400Sstevel@tonic-gate 		case 'X':
5410Sstevel@tonic-gate 		    if (xferdone) {  /* only if a transfer has just occurred */
5420Sstevel@tonic-gate 			switch (*++inptr) {
5430Sstevel@tonic-gate 			case 't':
5440Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%d", xfervalues.transfer_time);
5450Sstevel@tonic-gate 			    break;
5460Sstevel@tonic-gate 			case 's':
5470Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%" L_FORMAT, xfervalues.filesize);
5480Sstevel@tonic-gate 			    break;
5490Sstevel@tonic-gate 			case 'n':
5500Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%" L_FORMAT, xfervalues.transfer_bytes);
5510Sstevel@tonic-gate 			    break;
5520Sstevel@tonic-gate 			case 'P': /* absolute pathname */
5530Sstevel@tonic-gate 			    /* FALLTHROUGH */
5540Sstevel@tonic-gate 			case 'p': /* chroot-relative pathname */
5550Sstevel@tonic-gate 			{
5560Sstevel@tonic-gate 			    char namebuf[MAXPATHLEN];
5570Sstevel@tonic-gate 			    int loop;
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 			    if (*inptr == 'P')
5600Sstevel@tonic-gate 				wu_realpath(xfervalues.filename, namebuf, chroot_path);
5610Sstevel@tonic-gate 			    else
5620Sstevel@tonic-gate 				fb_realpath(xfervalues.filename, namebuf);
5630Sstevel@tonic-gate 			    for (loop = 0; namebuf[loop]; loop++) {
5640Sstevel@tonic-gate 				if (isspace(namebuf[loop]) || iscntrl(namebuf[loop]))
5650Sstevel@tonic-gate 				    namebuf[loop] = '_';
5660Sstevel@tonic-gate 			    }
5670Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%s", namebuf);
5680Sstevel@tonic-gate 			    break;
5690Sstevel@tonic-gate 			}
5700Sstevel@tonic-gate 			case 'y':
5710Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%c", xfervalues.transfer_type);
5720Sstevel@tonic-gate 			    break;
5730Sstevel@tonic-gate 			case 'f':
5740Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%s", xfervalues.special_action);
5750Sstevel@tonic-gate 			    break;
5760Sstevel@tonic-gate 			case 'd':
5770Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%c", xfervalues.transfer_direction);
5780Sstevel@tonic-gate 			    break;
5790Sstevel@tonic-gate 			case 'm':
5800Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%c", xfervalues.access_mode);
5810Sstevel@tonic-gate 			    break;
5820Sstevel@tonic-gate 			case 'a':
5830Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%d", xfervalues.auth);
5840Sstevel@tonic-gate 			    break;
5850Sstevel@tonic-gate 			case 'r':
5860Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%" L_FORMAT, xfervalues.restart_offset);
5870Sstevel@tonic-gate 			    break;
5880Sstevel@tonic-gate 			case 'c':
5890Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%c", xfervalues.completion);
5900Sstevel@tonic-gate 			    break;
5910Sstevel@tonic-gate 			default:
5920Sstevel@tonic-gate 			    snprintf(outptr, outlen, "%%X%c", *inptr);
5930Sstevel@tonic-gate 			    break;
5940Sstevel@tonic-gate 			}
5950Sstevel@tonic-gate 		    }
5960Sstevel@tonic-gate 		    else
5970Sstevel@tonic-gate 			snprintf(outptr, outlen, "%%%c", *inptr);
5980Sstevel@tonic-gate 		    break;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	    default:
6010Sstevel@tonic-gate 		*outptr++ = '%';
6020Sstevel@tonic-gate 		outlen -= 1;
6030Sstevel@tonic-gate 		if (outlen > 1) {
6040Sstevel@tonic-gate 		    *outptr++ = *inptr;
6050Sstevel@tonic-gate 		    outlen -= 1;
6060Sstevel@tonic-gate 		}
6070Sstevel@tonic-gate 		*outptr = '\0';
6080Sstevel@tonic-gate 		break;
6090Sstevel@tonic-gate 	    }
6100Sstevel@tonic-gate 	    outptr[outlen - 1] = '\0';
6110Sstevel@tonic-gate 	    while (*outptr) {
6120Sstevel@tonic-gate 		outptr++;
6130Sstevel@tonic-gate 		outlen -= 1;
6140Sstevel@tonic-gate 	    }
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate 	inptr++;
6170Sstevel@tonic-gate     }
6180Sstevel@tonic-gate     if (outlen > 0)
6190Sstevel@tonic-gate 	*outptr = '\0';
6200Sstevel@tonic-gate }
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate /*************************************************************************/
6230Sstevel@tonic-gate /* FUNCTION  : cwd_beenhere                                              */
6240Sstevel@tonic-gate /* PURPOSE   : Return 1 if the user has already visited this directory   */
6250Sstevel@tonic-gate /*             via C_WD.                                                 */
6260Sstevel@tonic-gate /* ARGUMENTS : a power-of-two directory function code (README, MESSAGE)  */
6270Sstevel@tonic-gate /*************************************************************************/
6280Sstevel@tonic-gate 
cwd_beenhere(int dircode)6290Sstevel@tonic-gate int cwd_beenhere(int dircode)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate     struct dirlist {
6320Sstevel@tonic-gate 	struct dirlist *next;
6330Sstevel@tonic-gate 	int dircode;
6340Sstevel@tonic-gate 	char dirname[1];
6350Sstevel@tonic-gate     };
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate     static struct dirlist *head = NULL;
6380Sstevel@tonic-gate     struct dirlist *curptr;
6390Sstevel@tonic-gate     char cwd[MAXPATHLEN];
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate     (void) fb_realpath(".", cwd);
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate     for (curptr = head; curptr != NULL; curptr = curptr->next)
6440Sstevel@tonic-gate 	if (strcmp(curptr->dirname, cwd) == 0) {
6450Sstevel@tonic-gate 	    if (!(curptr->dircode & dircode)) {
6460Sstevel@tonic-gate 		curptr->dircode |= dircode;
6470Sstevel@tonic-gate 		return (0);
6480Sstevel@tonic-gate 	    }
6490Sstevel@tonic-gate 	    return (1);
6500Sstevel@tonic-gate 	}
6510Sstevel@tonic-gate     curptr = (struct dirlist *) malloc(strlen(cwd) + 1 + sizeof(struct dirlist));
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate     if (curptr != NULL) {
6540Sstevel@tonic-gate 	curptr->next = head;
6550Sstevel@tonic-gate 	head = curptr;
6560Sstevel@tonic-gate 	curptr->dircode = dircode;
6570Sstevel@tonic-gate 	strcpy(curptr->dirname, cwd);
6580Sstevel@tonic-gate     }
6590Sstevel@tonic-gate     return (0);
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate /*************************************************************************/
6630Sstevel@tonic-gate /* FUNCTION  : show_banner                                               */
6640Sstevel@tonic-gate /* PURPOSE   : Display a banner on the user's terminal before login      */
6650Sstevel@tonic-gate /* ARGUMENTS : reply code to use                                         */
6660Sstevel@tonic-gate /*************************************************************************/
6670Sstevel@tonic-gate 
show_banner(int msgcode)6680Sstevel@tonic-gate void show_banner(int msgcode)
6690Sstevel@tonic-gate {
6700Sstevel@tonic-gate     char *crptr, linebuf[1024], outbuf[1024];
6710Sstevel@tonic-gate     struct aclmember *entry = NULL;
6720Sstevel@tonic-gate     FILE *infile;
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate #ifdef VIRTUAL
6750Sstevel@tonic-gate     extern int virtual_mode;
6760Sstevel@tonic-gate     extern int virtual_ftpaccess;
6770Sstevel@tonic-gate     extern char virtual_banner[];
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate     if (virtual_mode && !virtual_ftpaccess) {
6800Sstevel@tonic-gate 	infile = fopen(virtual_banner, "r");
6810Sstevel@tonic-gate 	if (infile) {
6820Sstevel@tonic-gate 	    while (fgets(linebuf, sizeof(linebuf), infile) != NULL) {
6830Sstevel@tonic-gate 		if ((crptr = strchr(linebuf, '\n')) != NULL)
6840Sstevel@tonic-gate 		    *crptr = '\0';
6850Sstevel@tonic-gate 		msg_massage(linebuf, outbuf, sizeof(outbuf));
6860Sstevel@tonic-gate 		lreply(msgcode, "%s", outbuf);
6870Sstevel@tonic-gate 	    }
6880Sstevel@tonic-gate 	    fclose(infile);
6890Sstevel@tonic-gate #ifndef NO_SUCKING_NEWLINES
6900Sstevel@tonic-gate 	    lreply(msgcode, "");
6910Sstevel@tonic-gate #endif
6920Sstevel@tonic-gate 	}
6930Sstevel@tonic-gate     }
6940Sstevel@tonic-gate     else {
6950Sstevel@tonic-gate #endif
6960Sstevel@tonic-gate 	/* banner <path> */
6970Sstevel@tonic-gate 	while (getaclentry("banner", &entry)) {
6980Sstevel@tonic-gate 	    if (!ARG0)
6990Sstevel@tonic-gate 		continue;
7000Sstevel@tonic-gate 	    infile = fopen(ARG0, "r");
7010Sstevel@tonic-gate 	    if (infile) {
7020Sstevel@tonic-gate 		while (fgets(linebuf, sizeof(linebuf), infile) != NULL) {
7030Sstevel@tonic-gate 		    if ((crptr = strchr(linebuf, '\n')) != NULL)
7040Sstevel@tonic-gate 			*crptr = '\0';
7050Sstevel@tonic-gate 		    msg_massage(linebuf, outbuf, sizeof(outbuf));
7060Sstevel@tonic-gate 		    lreply(msgcode, "%s", outbuf);
7070Sstevel@tonic-gate 		}
7080Sstevel@tonic-gate 		fclose(infile);
7090Sstevel@tonic-gate #ifndef NO_SUCKING_NEWLINES
7100Sstevel@tonic-gate 		lreply(msgcode, "");
7110Sstevel@tonic-gate #endif
7120Sstevel@tonic-gate 	    }
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate #ifdef VIRTUAL
7150Sstevel@tonic-gate     }
7160Sstevel@tonic-gate #endif
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate /*************************************************************************/
7190Sstevel@tonic-gate /* FUNCTION  : show_message                                              */
7200Sstevel@tonic-gate /* PURPOSE   : Display a message on the user's terminal if the current   */
7210Sstevel@tonic-gate /*             conditions are right                                      */
7220Sstevel@tonic-gate /* ARGUMENTS : reply code to use, LOG_IN|CMD                             */
7230Sstevel@tonic-gate /*************************************************************************/
7240Sstevel@tonic-gate 
show_message(int msgcode,int mode)7250Sstevel@tonic-gate void show_message(int msgcode, int mode)
7260Sstevel@tonic-gate {
7270Sstevel@tonic-gate     char *crptr, linebuf[1024], outbuf[1024], class[MAXPATHLEN], cwd[MAXPATHLEN];
7280Sstevel@tonic-gate     int show, which;
7290Sstevel@tonic-gate     struct aclmember *entry = NULL;
7300Sstevel@tonic-gate     FILE *infile;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate     if (mode == C_WD && cwd_beenhere(1) != 0)
7330Sstevel@tonic-gate 	return;
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate #ifdef HAVE_GETCWD
7360Sstevel@tonic-gate     (void) getcwd(cwd, MAXPATHLEN - 1);
7370Sstevel@tonic-gate #else
7380Sstevel@tonic-gate     (void) getwd(cwd);
7390Sstevel@tonic-gate #endif
7400Sstevel@tonic-gate     (void) acl_getclass(class);
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate     /* message <path> [<when> [<class>]] */
7430Sstevel@tonic-gate     while (getaclentry("message", &entry)) {
7440Sstevel@tonic-gate 	if (!ARG0)
7450Sstevel@tonic-gate 	    continue;
7460Sstevel@tonic-gate 	show = 0;
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	if (mode == LOG_IN && (!ARG1 || !strcasecmp(ARG1, "login")))
7490Sstevel@tonic-gate 	    if (!ARG2)
7500Sstevel@tonic-gate 		show++;
7510Sstevel@tonic-gate 	    else {
7520Sstevel@tonic-gate 		for (which = 2; (which < MAXARGS) && ARG[which]; which++)
7530Sstevel@tonic-gate 		    if (strcasecmp(class, ARG[which]) == 0)
7540Sstevel@tonic-gate 			show++;
7550Sstevel@tonic-gate 	    }
7560Sstevel@tonic-gate 	if (mode == C_WD && ARG1 && !strncasecmp(ARG1, "cwd=", 4) &&
7570Sstevel@tonic-gate 	    (!strcmp((ARG1) + 4, cwd) || *(ARG1 + 4) == '*' ||
7580Sstevel@tonic-gate 	     !wu_fnmatch((ARG1) + 4, cwd, FNM_PATHNAME)))
7590Sstevel@tonic-gate 	    if (!ARG2)
7600Sstevel@tonic-gate 		show++;
7610Sstevel@tonic-gate 	    else {
7620Sstevel@tonic-gate 		for (which = 2; (which < MAXARGS) && ARG[which]; which++)
7630Sstevel@tonic-gate 		    if (strcasecmp(class, ARG[which]) == 0)
7640Sstevel@tonic-gate 			show++;
7650Sstevel@tonic-gate 	    }
7660Sstevel@tonic-gate 	if (show && (int) strlen(ARG0) > 0) {
7670Sstevel@tonic-gate 	    infile = fopen(ARG0, "r");
7680Sstevel@tonic-gate 	    if (infile) {
7690Sstevel@tonic-gate 		while (fgets(linebuf, sizeof(linebuf), infile) != NULL) {
7700Sstevel@tonic-gate 		    if ((crptr = strchr(linebuf, '\n')) != NULL)
7710Sstevel@tonic-gate 			*crptr = '\0';
7720Sstevel@tonic-gate 		    msg_massage(linebuf, outbuf, sizeof(outbuf));
7730Sstevel@tonic-gate 		    lreply(msgcode, "%s", outbuf);
7740Sstevel@tonic-gate 		}
7750Sstevel@tonic-gate 		fclose(infile);
7760Sstevel@tonic-gate #ifndef NO_SUCKING_NEWLINES
7770Sstevel@tonic-gate 		lreply(msgcode, "");
7780Sstevel@tonic-gate #endif
7790Sstevel@tonic-gate 	    }
7800Sstevel@tonic-gate 	}
7810Sstevel@tonic-gate     }
7820Sstevel@tonic-gate }
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate /*************************************************************************/
7850Sstevel@tonic-gate /* FUNCTION  : show_readme                                               */
7860Sstevel@tonic-gate /* PURPOSE   : Display a message about a README file to the user if the  */
7870Sstevel@tonic-gate /*             current conditions are right                              */
7880Sstevel@tonic-gate /* ARGUMENTS : pointer to ACL buffer, reply code, LOG_IN|C_WD            */
7890Sstevel@tonic-gate /*************************************************************************/
7900Sstevel@tonic-gate 
show_readme(int code,int mode)7910Sstevel@tonic-gate void show_readme(int code, int mode)
7920Sstevel@tonic-gate {
7930Sstevel@tonic-gate     char **filelist, **sfilelist, class[MAXPATHLEN], cwd[MAXPATHLEN];
7940Sstevel@tonic-gate     int show, which, days;
7950Sstevel@tonic-gate     time_t clock;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate     struct stat buf;
7980Sstevel@tonic-gate     struct tm *tp;
7990Sstevel@tonic-gate     struct aclmember *entry = NULL;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate     if (cwd_beenhere(2) != 0)
8020Sstevel@tonic-gate 	return;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate #ifdef HAVE_GETCWD
8050Sstevel@tonic-gate     (void) getcwd(cwd, MAXPATHLEN - 1);
8060Sstevel@tonic-gate #else
8070Sstevel@tonic-gate     (void) getwd(cwd);
8080Sstevel@tonic-gate #endif
8090Sstevel@tonic-gate     (void) acl_getclass(class);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate     /* readme  <path> {<when>} */
8120Sstevel@tonic-gate     while (getaclentry("readme", &entry)) {
8130Sstevel@tonic-gate 	if (!ARG0)
8140Sstevel@tonic-gate 	    continue;
8150Sstevel@tonic-gate 	show = 0;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	if (mode == LOG_IN && (!ARG1 || !strcasecmp(ARG1, "login")))
8180Sstevel@tonic-gate 	    if (!ARG2)
8190Sstevel@tonic-gate 		show++;
8200Sstevel@tonic-gate 	    else {
8210Sstevel@tonic-gate 		for (which = 2; (which < MAXARGS) && ARG[which]; which++)
8220Sstevel@tonic-gate 		    if (strcasecmp(class, ARG[which]) == 0)
8230Sstevel@tonic-gate 			show++;
8240Sstevel@tonic-gate 	    }
8250Sstevel@tonic-gate 	if (mode == C_WD && ARG1 && !strncasecmp(ARG1, "cwd=", 4)
8260Sstevel@tonic-gate 	    && (!strcmp((ARG1) + 4, cwd) || *(ARG1 + 4) == '*' ||
8270Sstevel@tonic-gate 		!wu_fnmatch((ARG1) + 4, cwd, FNM_PATHNAME)))
8280Sstevel@tonic-gate 	    if (!ARG2)
8290Sstevel@tonic-gate 		show++;
8300Sstevel@tonic-gate 	    else {
8310Sstevel@tonic-gate 		for (which = 2; (which < MAXARGS) && ARG[which]; which++)
8320Sstevel@tonic-gate 		    if (strcasecmp(class, ARG[which]) == 0)
8330Sstevel@tonic-gate 			show++;
8340Sstevel@tonic-gate 	    }
8350Sstevel@tonic-gate 	if (show) {
8360Sstevel@tonic-gate 	    globerr = NULL;
837*12333SMilan.Jurik@Sun.COM 	    filelist = ftpglob(ARG0, B_TRUE);
8380Sstevel@tonic-gate 	    sfilelist = filelist;	/* save to free later */
8390Sstevel@tonic-gate 	    if (!globerr) {
8400Sstevel@tonic-gate 		while (filelist && *filelist) {
8410Sstevel@tonic-gate 		    errno = 0;
8420Sstevel@tonic-gate 		    if (!stat(*filelist, &buf) &&
8430Sstevel@tonic-gate 			(buf.st_mode & S_IFMT) == S_IFREG) {
8440Sstevel@tonic-gate 			lreply(code, "Please read the file %s", *filelist);
8450Sstevel@tonic-gate 			(void) time(&clock);
8460Sstevel@tonic-gate 			tp = localtime(&clock);
8470Sstevel@tonic-gate 			days = 365 * tp->tm_year + tp->tm_yday;
8480Sstevel@tonic-gate 			tp = localtime((time_t *) & buf.st_mtime);
8490Sstevel@tonic-gate 			days -= 365 * tp->tm_year + tp->tm_yday;
8500Sstevel@tonic-gate /*
8510Sstevel@tonic-gate    if (days == 0) {
8520Sstevel@tonic-gate    lreply(code, "  it was last modified on %.24s - Today",
8530Sstevel@tonic-gate    ctime((time_t *)&buf.st_mtime));
8540Sstevel@tonic-gate    } else {
8550Sstevel@tonic-gate  */
8560Sstevel@tonic-gate 			lreply(code,
8570Sstevel@tonic-gate 			   "  it was last modified on %.24s - %d day%s ago",
8580Sstevel@tonic-gate 			       ctime((time_t *) & buf.st_mtime), days, days == 1 ? "" : "s");
8590Sstevel@tonic-gate /*
8600Sstevel@tonic-gate    }
8610Sstevel@tonic-gate  */
8620Sstevel@tonic-gate 		    }
8630Sstevel@tonic-gate 		    filelist++;
8640Sstevel@tonic-gate 		}
8650Sstevel@tonic-gate 	    }
8660Sstevel@tonic-gate 	    if (sfilelist) {
8670Sstevel@tonic-gate 		blkfree(sfilelist);
8680Sstevel@tonic-gate 		free((char *) sfilelist);
8690Sstevel@tonic-gate 	    }
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate     }
8720Sstevel@tonic-gate }
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate /*************************************************************************/
8750Sstevel@tonic-gate /* FUNCTION  : deny_badxfertype                                          */
8760Sstevel@tonic-gate /* PURPOSE   : If user is in ASCII transfer mode and tries to retrieve a */
8770Sstevel@tonic-gate /*             binary file, abort transfer and display appropriate error */
8780Sstevel@tonic-gate /* ARGUMENTS : message code to use for denial, path of file to check for */
8790Sstevel@tonic-gate /*             binary contents or NULL to assume binary file             */
8800Sstevel@tonic-gate /*************************************************************************/
8810Sstevel@tonic-gate 
deny_badasciixfer(int msgcode,char * filepath)8820Sstevel@tonic-gate int deny_badasciixfer(int msgcode, char *filepath)
8830Sstevel@tonic-gate {
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate     if (type == TYPE_A && !*filepath) {
8860Sstevel@tonic-gate 	reply(msgcode, "This is a BINARY file, using ASCII mode to transfer will corrupt it.");
8870Sstevel@tonic-gate 	return (1);
8880Sstevel@tonic-gate     }
8890Sstevel@tonic-gate     /* The hooks are here to prevent transfers of actual binary files, not
8900Sstevel@tonic-gate      * just TAR or COMPRESS mode files... */
8910Sstevel@tonic-gate     return (0);
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate /*************************************************************************/
8950Sstevel@tonic-gate /* FUNCTION  : is_shutdown                                               */
8960Sstevel@tonic-gate /* PURPOSE   : Check to see if the server is shutting down, if it is     */
8970Sstevel@tonic-gate /*             arrange for the shutdown message to be sent in the next   */
8980Sstevel@tonic-gate /*             reply to the user                                         */
8990Sstevel@tonic-gate /* ARGUMENTS : whether to arrange for a shutdown message to be sent, new */
9000Sstevel@tonic-gate /*             or existing connection                                    */
9010Sstevel@tonic-gate /* RETURNS   : 1 if shutting down, 0 if not                              */
9020Sstevel@tonic-gate /*************************************************************************/
9030Sstevel@tonic-gate 
is_shutdown(int quiet,int new)9040Sstevel@tonic-gate int is_shutdown(int quiet, int new)
9050Sstevel@tonic-gate {
9060Sstevel@tonic-gate     static struct tm tmbuf;
9070Sstevel@tonic-gate     static struct stat s_last;
9080Sstevel@tonic-gate     static time_t last = 0, shut, deny, disc;
9090Sstevel@tonic-gate     static int valid;
9100Sstevel@tonic-gate     static char text[2048];
9110Sstevel@tonic-gate     struct stat s_cur;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate     extern char *autospout, Shutdown[];
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate     FILE *fp;
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate     int deny_off, disc_off;
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate     time_t curtime = time(NULL);
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate     char buf[1024], linebuf[1024];
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate     if (Shutdown[0] == '\0' || stat(Shutdown, &s_cur))
9240Sstevel@tonic-gate 	return (0);
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate     if (s_last.st_mtime != s_cur.st_mtime) {
9270Sstevel@tonic-gate 	valid = 0;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	fp = fopen(Shutdown, "r");
9300Sstevel@tonic-gate 	if (fp == NULL)
9310Sstevel@tonic-gate 	    return (0);
9320Sstevel@tonic-gate 	s_last = s_cur;
9330Sstevel@tonic-gate 	fgets(buf, sizeof(buf), fp);
9340Sstevel@tonic-gate 	if (sscanf(buf, "%d %d %d %d %d %ld %ld", &tmbuf.tm_year, &tmbuf.tm_mon,
9350Sstevel@tonic-gate 	&tmbuf.tm_mday, &tmbuf.tm_hour, &tmbuf.tm_min, &deny, &disc) != 7) {
9360Sstevel@tonic-gate 	    (void) fclose(fp);
9370Sstevel@tonic-gate 	    return (0);
9380Sstevel@tonic-gate 	}
9390Sstevel@tonic-gate 	valid = 1;
9400Sstevel@tonic-gate 	deny_off = 3600 * (deny / 100) + 60 * (deny % 100);
9410Sstevel@tonic-gate 	disc_off = 3600 * (disc / 100) + 60 * (disc % 100);
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	tmbuf.tm_year -= 1900;
9440Sstevel@tonic-gate 	tmbuf.tm_isdst = -1;
9450Sstevel@tonic-gate 	shut = mktime(&tmbuf);
9460Sstevel@tonic-gate 	strcpy(shuttime, ctime(&shut));
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	disc = shut - disc_off;
9490Sstevel@tonic-gate 	strcpy(disctime, ctime(&disc));
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	deny = shut - deny_off;
9520Sstevel@tonic-gate 	strcpy(denytime, ctime(&deny));
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	text[0] = '\0';
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	while (fgets(buf, sizeof(buf), fp) != NULL) {
9570Sstevel@tonic-gate 	    msg_massage(buf, linebuf, sizeof(linebuf));
9580Sstevel@tonic-gate 	    if ((strlen(text) + strlen(linebuf)) < sizeof(text))
9590Sstevel@tonic-gate 		strcat(text, linebuf);
9600Sstevel@tonic-gate 	}
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	(void) fclose(fp);
9630Sstevel@tonic-gate     }
9640Sstevel@tonic-gate     if (!valid)
9650Sstevel@tonic-gate 	return (0);
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate     /* if last == 0, then is_shutdown() only called with quiet == 1 so far */
9680Sstevel@tonic-gate     if (last == 0 && !quiet) {
9690Sstevel@tonic-gate 	autospout = text;	/* warn them for the first time */
9700Sstevel@tonic-gate 	autospout_free = 0;
9710Sstevel@tonic-gate 	last = curtime;
9720Sstevel@tonic-gate     }
9730Sstevel@tonic-gate     /* if a new connection and past deny time, tell caller to drop 'em */
9740Sstevel@tonic-gate     if (new && curtime > deny)
9750Sstevel@tonic-gate 	return (1);
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate     /* if past disconnect time, tell caller to drop 'em */
9780Sstevel@tonic-gate     if (curtime > disc)
9790Sstevel@tonic-gate 	return (1);
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate     /* if less than 60 seconds to disconnection, warn 'em continuously */
9820Sstevel@tonic-gate     if (curtime > (disc - 60) && !quiet) {
9830Sstevel@tonic-gate 	autospout = text;
9840Sstevel@tonic-gate 	autospout_free = 0;
9850Sstevel@tonic-gate 	last = curtime;
9860Sstevel@tonic-gate     }
9870Sstevel@tonic-gate     /* if less than 15 minutes to disconnection, warn 'em every 5 mins */
9880Sstevel@tonic-gate     if (curtime > (disc - 60 * 15)) {
9890Sstevel@tonic-gate 	if ((curtime - last) > (60 * 5) && !quiet) {
9900Sstevel@tonic-gate 	    autospout = text;
9910Sstevel@tonic-gate 	    autospout_free = 0;
9920Sstevel@tonic-gate 	    last = curtime;
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate     }
9950Sstevel@tonic-gate     /* if less than 24 hours to disconnection, warn 'em every 30 mins */
9960Sstevel@tonic-gate     if (curtime < (disc - 24 * 60 * 60) && !quiet) {
9970Sstevel@tonic-gate 	if ((curtime - last) > (60 * 30)) {
9980Sstevel@tonic-gate 	    autospout = text;
9990Sstevel@tonic-gate 	    autospout_free = 0;
10000Sstevel@tonic-gate 	    last = curtime;
10010Sstevel@tonic-gate 	}
10020Sstevel@tonic-gate     }
10030Sstevel@tonic-gate     /* if more than 24 hours to disconnection, warn 'em every 60 mins */
10040Sstevel@tonic-gate     if (curtime > (disc - 24 * 60 * 60) && !quiet) {
10050Sstevel@tonic-gate 	if ((curtime - last) >= (24 * 60 * 60)) {
10060Sstevel@tonic-gate 	    autospout = text;
10070Sstevel@tonic-gate 	    autospout_free = 0;
10080Sstevel@tonic-gate 	    last = curtime;
10090Sstevel@tonic-gate 	}
10100Sstevel@tonic-gate     }
10110Sstevel@tonic-gate     return (0);
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate #ifdef SITE_NEWER
newer(char * date,char * path,int showlots)10150Sstevel@tonic-gate void newer(char *date, char *path, int showlots)
10160Sstevel@tonic-gate {
10170Sstevel@tonic-gate     struct tm tm;
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate     if (sscanf(date, "%04d%02d%02d%02d%02d%02d",
10200Sstevel@tonic-gate 	       &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
10210Sstevel@tonic-gate 	       &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) {
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	tm.tm_year -= 1900;
10240Sstevel@tonic-gate 	tm.tm_mon--;
10250Sstevel@tonic-gate 	tm.tm_isdst = -1;
10260Sstevel@tonic-gate 	newer_time = mktime(&tm);
10270Sstevel@tonic-gate 	dout = dataconn("file list", (off_t) - 1, "w");
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	if (dout != NULL) {
10300Sstevel@tonic-gate 	    /* As ftw allocates storage it needs a chance to cleanup, setting
10310Sstevel@tonic-gate 	     * ftwflag prevents myoob from calling longjmp, incrementing
10320Sstevel@tonic-gate 	     * ftwflag instead which causes check_newer to return non-zero
10330Sstevel@tonic-gate 	     * which makes ftw return. */
10340Sstevel@tonic-gate 	    ftwflag = 1;
10350Sstevel@tonic-gate 	    transflag++;
10360Sstevel@tonic-gate 	    show_fullinfo = showlots;
10370Sstevel@tonic-gate #if defined(HAVE_FTW)
10380Sstevel@tonic-gate 	    ftw(path, check_newer, -1);
10390Sstevel@tonic-gate #else
10400Sstevel@tonic-gate 	    treewalk(path, check_newer, -1, NULL);
10410Sstevel@tonic-gate #endif
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	    /* don't send a reply if myoob has already replied */
10440Sstevel@tonic-gate 	    if (ftwflag == 1) {
10450Sstevel@tonic-gate 		if (ferror(dout) != 0)
10460Sstevel@tonic-gate 		    perror_reply(550, "Data connection");
10470Sstevel@tonic-gate 		else
10480Sstevel@tonic-gate 		    reply(226, "Transfer complete.");
10490Sstevel@tonic-gate 	    }
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	    (void) fclose(dout);
10520Sstevel@tonic-gate 	    data = -1;
10530Sstevel@tonic-gate 	    pdata = -1;
10540Sstevel@tonic-gate 	    transflag = 0;
10550Sstevel@tonic-gate 	    ftwflag = 0;
10560Sstevel@tonic-gate 	}
10570Sstevel@tonic-gate     }
10580Sstevel@tonic-gate     else
10590Sstevel@tonic-gate 	reply(501, "Bad DATE format");
10600Sstevel@tonic-gate }
10610Sstevel@tonic-gate #endif
10620Sstevel@tonic-gate 
type_match(char * typelist)10630Sstevel@tonic-gate int type_match(char *typelist)
10640Sstevel@tonic-gate {
10650Sstevel@tonic-gate     char *start, *p;
10660Sstevel@tonic-gate     int len;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate     if (typelist == NULL)
10690Sstevel@tonic-gate 	return (0);
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate     for (p = start = typelist; *start != '\0'; start = p) {
10720Sstevel@tonic-gate 	while (*p != '\0' && *p != ',')
10730Sstevel@tonic-gate 	    p++;
10740Sstevel@tonic-gate 	len = p - start;
10750Sstevel@tonic-gate 	if (*p != '\0')
10760Sstevel@tonic-gate 	    p++;
10770Sstevel@tonic-gate 	if (len == 9 && anonymous && strncasecmp(start, "anonymous", 9) == 0)
10780Sstevel@tonic-gate 	    return (1);
10790Sstevel@tonic-gate 	if (len == 5 && guest && strncasecmp(start, "guest", 5) == 0)
10800Sstevel@tonic-gate 	    return (1);
10810Sstevel@tonic-gate 	if (len == 4 && !guest && !anonymous &&
10820Sstevel@tonic-gate 	    strncasecmp(start, "real", 4) == 0)
10830Sstevel@tonic-gate 	    return (1);
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	if (len > 6 && strncasecmp(start, "class=", 6) == 0) {
10860Sstevel@tonic-gate 	    char class[1024];
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	    if ((acl_getclass(class) == 1) && (strlen(class) == len - 6) &&
10890Sstevel@tonic-gate 		(strncasecmp(start + 6, class, len - 6) == 0))
10900Sstevel@tonic-gate 		return (1);
10910Sstevel@tonic-gate 	}
10920Sstevel@tonic-gate     }
10930Sstevel@tonic-gate     return (0);
10940Sstevel@tonic-gate }
10950Sstevel@tonic-gate 
path_compare(char * p1,char * p2)10960Sstevel@tonic-gate int path_compare(char *p1, char *p2)
10970Sstevel@tonic-gate {
10980Sstevel@tonic-gate     if ((strcmp(p1, "*") == 0) || (wu_fnmatch(p1, p2, FNM_PATHNAME) == 0))	/* 0 means they matched */
10990Sstevel@tonic-gate 	return (strlen(p1));
11000Sstevel@tonic-gate     else
11010Sstevel@tonic-gate 	return (-2);
11020Sstevel@tonic-gate }
11030Sstevel@tonic-gate 
expand_id(void)11040Sstevel@tonic-gate void expand_id(void)
11050Sstevel@tonic-gate {
11060Sstevel@tonic-gate     char class[1024];
11070Sstevel@tonic-gate     struct aclmember *entry = NULL;
11080Sstevel@tonic-gate     (void) acl_getclass(class);
11090Sstevel@tonic-gate     while (getaclentry("upload", &entry)) {
11100Sstevel@tonic-gate 	char *q;
11110Sstevel@tonic-gate 	int i = 0;
11120Sstevel@tonic-gate 	int options = 1;
11130Sstevel@tonic-gate 	int classfound = 0;
11140Sstevel@tonic-gate 	int classmatched = 0;
11150Sstevel@tonic-gate 	while (options
11160Sstevel@tonic-gate 	       && (i < MAXARGS)
11170Sstevel@tonic-gate 	       && ((q = entry->arg[i]) != (char *) NULL)
11180Sstevel@tonic-gate 	       && (q[0] != '\0')) {
11190Sstevel@tonic-gate 	    if (strcasecmp(q, "absolute") == 0)
11200Sstevel@tonic-gate 		i++;
11210Sstevel@tonic-gate 	    else if (strcasecmp(q, "relative") == 0)
11220Sstevel@tonic-gate 		i++;
11230Sstevel@tonic-gate 	    else if (strncasecmp(q, "class=", 6) == 0) {
11240Sstevel@tonic-gate 		i++;
11250Sstevel@tonic-gate 		classfound = 1;
11260Sstevel@tonic-gate 		if (strcasecmp(q + 6, class) == 0)
11270Sstevel@tonic-gate 		    classmatched = 1;
11280Sstevel@tonic-gate 	    }
11290Sstevel@tonic-gate 	    else if (strcmp(q, "-") == 0) {
11300Sstevel@tonic-gate 		i++;
11310Sstevel@tonic-gate 		options = 0;
11320Sstevel@tonic-gate 	    }
11330Sstevel@tonic-gate 	    else
11340Sstevel@tonic-gate 		options = 0;
11350Sstevel@tonic-gate 	}
11360Sstevel@tonic-gate 	if (!classfound || classmatched) {
11370Sstevel@tonic-gate 	    char buf[BUFSIZ];
11380Sstevel@tonic-gate 	    /*
11390Sstevel@tonic-gate 	       *  UID
11400Sstevel@tonic-gate 	     */
11410Sstevel@tonic-gate 	    if (((i + 3) < MAXARGS)
11420Sstevel@tonic-gate 		&& ((q = entry->arg[i + 3]) != (char *) NULL)
11430Sstevel@tonic-gate 		&& (q[0] != '\0')
11440Sstevel@tonic-gate 		&& (strcmp(q, "*") != 0)) {
11450Sstevel@tonic-gate 		if (q[0] == '%')
11460Sstevel@tonic-gate 		    sprintf(buf, "%s", q + 1);
11470Sstevel@tonic-gate 		else {
11480Sstevel@tonic-gate 		    struct passwd *pwent = getpwnam(q);
11490Sstevel@tonic-gate 		    if (pwent)
11500Sstevel@tonic-gate 			sprintf(buf, "%" PW_UID_FORMAT, pwent->pw_uid);
11510Sstevel@tonic-gate 		    else
11520Sstevel@tonic-gate 			sprintf(buf, "%d", 0);
11530Sstevel@tonic-gate 		}
11540Sstevel@tonic-gate 		entry->arg[i + 3] = (char *) malloc(strlen(buf) + 1);
11550Sstevel@tonic-gate 		if (entry->arg[i + 3] == NULL) {
11560Sstevel@tonic-gate 		    syslog(LOG_ERR, "calloc error in expand_id");
11570Sstevel@tonic-gate 		    dologout(1);
11580Sstevel@tonic-gate 		}
11590Sstevel@tonic-gate 		strcpy(entry->arg[i + 3], buf);
11600Sstevel@tonic-gate 	    }
11610Sstevel@tonic-gate 	    /*
11620Sstevel@tonic-gate 	       *  GID
11630Sstevel@tonic-gate 	     */
11640Sstevel@tonic-gate 	    if (((i + 4) < MAXARGS)
11650Sstevel@tonic-gate 		&& ((q = entry->arg[i + 4]) != (char *) NULL)
11660Sstevel@tonic-gate 		&& (q[0] != '\0')
11670Sstevel@tonic-gate 		&& (strcmp(q, "*") != 0)) {
11680Sstevel@tonic-gate 		if (q[0] == '%')
11690Sstevel@tonic-gate 		    sprintf(buf, "%s", q + 1);
11700Sstevel@tonic-gate 		else {
11710Sstevel@tonic-gate 		    struct group *grent = getgrnam(q);
11720Sstevel@tonic-gate 		    if (grent)
11730Sstevel@tonic-gate 			sprintf(buf, "%" GR_GID_FORMAT, grent->gr_gid);
11740Sstevel@tonic-gate 		    else
11750Sstevel@tonic-gate 			sprintf(buf, "%d", 0);
11760Sstevel@tonic-gate 		    endgrent();
11770Sstevel@tonic-gate 		}
11780Sstevel@tonic-gate 		entry->arg[i + 4] = (char *) malloc(strlen(buf) + 1);
11790Sstevel@tonic-gate 		if (entry->arg[i + 4] == NULL) {
11800Sstevel@tonic-gate 		    syslog(LOG_ERR, "calloc error in expand_id");
11810Sstevel@tonic-gate 		    dologout(1);
11820Sstevel@tonic-gate 		}
11830Sstevel@tonic-gate 		strcpy(entry->arg[i + 4], buf);
11840Sstevel@tonic-gate 	    }
11850Sstevel@tonic-gate 	}
11860Sstevel@tonic-gate     }
11870Sstevel@tonic-gate }
11880Sstevel@tonic-gate 
fn_check(char * name)11890Sstevel@tonic-gate int fn_check(char *name)
11900Sstevel@tonic-gate {
11910Sstevel@tonic-gate     /* check to see if this is a valid file name... path-filter <type>
11920Sstevel@tonic-gate      * <message_file> <allowed_charset> <disallowed> */
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate     struct aclmember *entry = NULL;
11950Sstevel@tonic-gate     int j;
11960Sstevel@tonic-gate     char *path;
11970Sstevel@tonic-gate #if ! defined(HAVE_REGEXEC)
11980Sstevel@tonic-gate     char *sp;
11990Sstevel@tonic-gate #endif
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate #ifdef M_UNIX
12020Sstevel@tonic-gate #ifdef HAVE_REGEX
12030Sstevel@tonic-gate     char *regp;
12040Sstevel@tonic-gate #endif
12050Sstevel@tonic-gate #endif
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate #ifdef HAVE_REGEXEC
12080Sstevel@tonic-gate     regex_t regexbuf;
12090Sstevel@tonic-gate     regmatch_t regmatchbuf;
12100Sstevel@tonic-gate     int rval;
12110Sstevel@tonic-gate #endif
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate #ifdef LINUX
12140Sstevel@tonic-gate     re_syntax_options = RE_SYNTAX_POSIX_EXTENDED;
12150Sstevel@tonic-gate #endif
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate     while (getaclentry("path-filter", &entry) && ARG0 != NULL) {
12180Sstevel@tonic-gate 	if (type_match(ARG0) && ARG1 && ARG2) {
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 	    /*
12210Sstevel@tonic-gate 	     * check *only* the basename
12220Sstevel@tonic-gate 	     */
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	    if ((path = strrchr(name, '/')))
12250Sstevel@tonic-gate 		++path;
12260Sstevel@tonic-gate 	    else
12270Sstevel@tonic-gate 		path = name;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	    /* is it in the allowed character set? */
12300Sstevel@tonic-gate #if defined(HAVE_REGEXEC)
12310Sstevel@tonic-gate 	    if (regcomp(&regexbuf, ARG2, REG_EXTENDED) != 0) {
12320Sstevel@tonic-gate 		reply(550, "HAVE_REGEX error");
12330Sstevel@tonic-gate #elif defined(HAVE_REGEX)
12340Sstevel@tonic-gate 		if ((sp = regcmp(ARG2, (char *) 0)) == NULL) {
12350Sstevel@tonic-gate 		    reply(550, "HAVE_REGEX error");
12360Sstevel@tonic-gate #else
12370Sstevel@tonic-gate 	    if ((sp = re_comp(ARG2)) != 0) {
12380Sstevel@tonic-gate 		perror_reply(550, sp);
12390Sstevel@tonic-gate #endif
12400Sstevel@tonic-gate 		return (0);
12410Sstevel@tonic-gate 	    }
12420Sstevel@tonic-gate #if defined(HAVE_REGEXEC)
12430Sstevel@tonic-gate 	    rval = regexec(&regexbuf, path, 1, &regmatchbuf, 0);
12440Sstevel@tonic-gate 	    regfree(&regexbuf);
12450Sstevel@tonic-gate 	    if (rval != 0) {
12460Sstevel@tonic-gate #elif defined(HAVE_REGEX)
12470Sstevel@tonic-gate #ifdef M_UNIX
12480Sstevel@tonic-gate 		regp = regex(sp, path);
12490Sstevel@tonic-gate 		free(sp);
12500Sstevel@tonic-gate 		if (regp == NULL) {
12510Sstevel@tonic-gate #else
12520Sstevel@tonic-gate 		if ((regex(sp, path)) == NULL) {
12530Sstevel@tonic-gate #endif
12540Sstevel@tonic-gate #else
12550Sstevel@tonic-gate 	    if ((re_exec(path)) != 1) {
12560Sstevel@tonic-gate #endif
12570Sstevel@tonic-gate 		pr_mesg(550, ARG1);
12580Sstevel@tonic-gate 		reply(550, "%s: Permission denied on server. (Filename (accept))", name);
12590Sstevel@tonic-gate 		return (0);
12600Sstevel@tonic-gate 	    }
12610Sstevel@tonic-gate 	    /* is it in any of the disallowed regexps */
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	    for (j = 3; j < MAXARGS; ++j) {
12640Sstevel@tonic-gate 		/* ARGj == entry->arg[j] */
12650Sstevel@tonic-gate 		if (entry->arg[j]) {
12660Sstevel@tonic-gate #if defined(HAVE_REGEXEC)
12670Sstevel@tonic-gate 		    if (regcomp(&regexbuf, entry->arg[j], REG_EXTENDED) != 0) {
12680Sstevel@tonic-gate 			reply(550, "HAVE_REGEX error");
12690Sstevel@tonic-gate #elif defined(HAVE_REGEX)
12700Sstevel@tonic-gate 			if ((sp = regcmp(entry->arg[j], (char *) 0)) == NULL) {
12710Sstevel@tonic-gate 			    reply(550, "HAVE_REGEX error");
12720Sstevel@tonic-gate #else
12730Sstevel@tonic-gate 		    if ((sp = re_comp(entry->arg[j])) != 0) {
12740Sstevel@tonic-gate 			perror_reply(550, sp);
12750Sstevel@tonic-gate #endif
12760Sstevel@tonic-gate 			return (0);
12770Sstevel@tonic-gate 		    }
12780Sstevel@tonic-gate #if defined(HAVE_REGEXEC)
12790Sstevel@tonic-gate 		    rval = regexec(&regexbuf, path, 1, &regmatchbuf, 0);
12800Sstevel@tonic-gate 		    regfree(&regexbuf);
12810Sstevel@tonic-gate 		    if (rval == 0) {
12820Sstevel@tonic-gate #elif defined(HAVE_REGEX)
12830Sstevel@tonic-gate #ifdef M_UNIX
12840Sstevel@tonic-gate 			regp = regex(sp, path);
12850Sstevel@tonic-gate 			free(sp);
12860Sstevel@tonic-gate 			if (regp != NULL) {
12870Sstevel@tonic-gate #else
12880Sstevel@tonic-gate 			if ((regex(sp, path)) != NULL) {
12890Sstevel@tonic-gate #endif
12900Sstevel@tonic-gate #else
12910Sstevel@tonic-gate 		    if ((re_exec(path)) == 1) {
12920Sstevel@tonic-gate #endif
12930Sstevel@tonic-gate 			pr_mesg(550, ARG1);
12940Sstevel@tonic-gate 			reply(550, "%s: Permission denied on server. (Filename (deny))", name);
12950Sstevel@tonic-gate 			return (0);
12960Sstevel@tonic-gate 		    }
12970Sstevel@tonic-gate 		}
12980Sstevel@tonic-gate 	    }
12990Sstevel@tonic-gate 	}
13000Sstevel@tonic-gate     }
13010Sstevel@tonic-gate     return (1);
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate int dir_check(char *name, uid_t * uid, gid_t * gid, int *d_mode, int *valid)
13050Sstevel@tonic-gate {
13060Sstevel@tonic-gate     struct aclmember *entry = NULL;
13070Sstevel@tonic-gate     int match_value = -1;
13080Sstevel@tonic-gate     char *ap2 = NULL;
13090Sstevel@tonic-gate     char *ap3 = NULL;
13100Sstevel@tonic-gate     char *ap4 = NULL;
13110Sstevel@tonic-gate     char *ap5 = NULL;
13120Sstevel@tonic-gate     char *ap6 = NULL;
13130Sstevel@tonic-gate     char *ap7 = NULL;
13140Sstevel@tonic-gate     char cwdir[MAXPATHLEN];
13150Sstevel@tonic-gate     char *pwdir;
13160Sstevel@tonic-gate     char abspwdir[MAXPATHLEN];
13170Sstevel@tonic-gate     char relpwdir[MAXPATHLEN];
13180Sstevel@tonic-gate     char path[MAXPATHLEN];
13190Sstevel@tonic-gate     char *sp;
13200Sstevel@tonic-gate     struct stat stbuf;
13210Sstevel@tonic-gate     int stat_result = -1;
13220Sstevel@tonic-gate     char class[1024];
13230Sstevel@tonic-gate     extern char *home;
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate     (void) acl_getclass(class);
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate     *valid = 0;
13280Sstevel@tonic-gate     /* what's our current directory? */
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate     /* XXX We could use dynamic RAM to store this path, but I'd rather just bail
13310Sstevel@tonic-gate        out with an error. The rest of wu is so crufy that a long path might
13320Sstevel@tonic-gate        just blow up later */
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate     if ((strlen(name) + 1) > sizeof(path)) {
13350Sstevel@tonic-gate 	perror_reply(550, "Path too long");
13360Sstevel@tonic-gate 	return (-1);
13370Sstevel@tonic-gate     }
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate     strcpy(path, name);
13400Sstevel@tonic-gate     sp = strrchr(path, '/');
13410Sstevel@tonic-gate     if (sp)
13420Sstevel@tonic-gate 	*sp = '\0';
13430Sstevel@tonic-gate     else
13440Sstevel@tonic-gate 	strcpy(path, ".");
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate     if ((fb_realpath(path, cwdir)) == NULL) {
13470Sstevel@tonic-gate 	perror_reply(550, "Could not determine cwdir");
13480Sstevel@tonic-gate 	return (-1);
13490Sstevel@tonic-gate     }
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate     if ((fb_realpath(home, relpwdir)) == NULL) {
13520Sstevel@tonic-gate 	perror_reply(550, "Could not determine pwdir");
13530Sstevel@tonic-gate 	return (-1);
13540Sstevel@tonic-gate     }
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate     if ((wu_realpath(home, abspwdir, chroot_path)) == NULL) {
13570Sstevel@tonic-gate 	perror_reply(550, "Could not determine pwdir");
13580Sstevel@tonic-gate 	return (-1);
13590Sstevel@tonic-gate     }
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate     while (getaclentry("upload", &entry)) {
13620Sstevel@tonic-gate 	char *q;
13630Sstevel@tonic-gate 	int i = 0;
13640Sstevel@tonic-gate 	int options = 1;
13650Sstevel@tonic-gate 	int classfound = 0;
13660Sstevel@tonic-gate 	int classmatched = 0;
13670Sstevel@tonic-gate 	pwdir = abspwdir;
13680Sstevel@tonic-gate 	while (options
13690Sstevel@tonic-gate 	       && (i < MAXARGS)
13700Sstevel@tonic-gate 	       && ((q = entry->arg[i]) != (char *) NULL)
13710Sstevel@tonic-gate 	       && (q[0] != '\0')) {
13720Sstevel@tonic-gate 	    if (strcasecmp(q, "absolute") == 0) {
13730Sstevel@tonic-gate 		i++;
13740Sstevel@tonic-gate 		pwdir = abspwdir;
13750Sstevel@tonic-gate 	    }
13760Sstevel@tonic-gate 	    else if (strcasecmp(q, "relative") == 0) {
13770Sstevel@tonic-gate 		i++;
13780Sstevel@tonic-gate 		pwdir = relpwdir;
13790Sstevel@tonic-gate 	    }
13800Sstevel@tonic-gate 	    else if (strncasecmp(q, "class=", 6) == 0) {
13810Sstevel@tonic-gate 		i++;
13820Sstevel@tonic-gate 		classfound = 1;
13830Sstevel@tonic-gate 		if (strcasecmp(q + 6, class) == 0)
13840Sstevel@tonic-gate 		    classmatched = 1;
13850Sstevel@tonic-gate 	    }
13860Sstevel@tonic-gate 	    else if (strcmp(q, "-") == 0) {
13870Sstevel@tonic-gate 		i++;
13880Sstevel@tonic-gate 		options = 0;
13890Sstevel@tonic-gate 	    }
13900Sstevel@tonic-gate 	    else
13910Sstevel@tonic-gate 		options = 0;
13920Sstevel@tonic-gate 	}
13930Sstevel@tonic-gate 	if (!classfound || classmatched) {
13940Sstevel@tonic-gate 	    int j;
13950Sstevel@tonic-gate 	    if (((i + 1) < MAXARGS)
13960Sstevel@tonic-gate 		&& ((q = entry->arg[i]) != (char *) NULL)
13970Sstevel@tonic-gate 		&& (q[0] != '\0')
13980Sstevel@tonic-gate 		&& (0 < path_compare(q, pwdir))
13990Sstevel@tonic-gate 		&& ((j = path_compare(entry->arg[i + 1], cwdir)) >= match_value)) {
14000Sstevel@tonic-gate 		match_value = j;
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate 		ap2 = NULL;
14030Sstevel@tonic-gate 		if (((i + 2) < MAXARGS)
14040Sstevel@tonic-gate 		    && ((q = entry->arg[i + 2]) != (char *) NULL)
14050Sstevel@tonic-gate 		    && (q[0] != '\0'))
14060Sstevel@tonic-gate 		    ap2 = q;
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 		ap3 = NULL;
14090Sstevel@tonic-gate 		if (((i + 3) < MAXARGS)
14100Sstevel@tonic-gate 		    && ((q = entry->arg[i + 3]) != (char *) NULL)
14110Sstevel@tonic-gate 		    && (q[0] != '\0'))
14120Sstevel@tonic-gate 		    ap3 = q;
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 		ap4 = NULL;
14150Sstevel@tonic-gate 		if (((i + 4) < MAXARGS)
14160Sstevel@tonic-gate 		    && ((q = entry->arg[i + 4]) != (char *) NULL)
14170Sstevel@tonic-gate 		    && (q[0] != '\0'))
14180Sstevel@tonic-gate 		    ap4 = q;
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 		ap5 = NULL;
14210Sstevel@tonic-gate 		if (((i + 5) < MAXARGS)
14220Sstevel@tonic-gate 		    && ((q = entry->arg[i + 5]) != (char *) NULL)
14230Sstevel@tonic-gate 		    && (q[0] != '\0'))
14240Sstevel@tonic-gate 		    ap5 = q;
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 		ap6 = NULL;
14270Sstevel@tonic-gate 		if (((i + 6) < MAXARGS)
14280Sstevel@tonic-gate 		    && ((q = entry->arg[i + 6]) != (char *) NULL)
14290Sstevel@tonic-gate 		    && (q[0] != '\0'))
14300Sstevel@tonic-gate 		    ap6 = q;
14310Sstevel@tonic-gate 
14320Sstevel@tonic-gate 		ap7 = NULL;
14330Sstevel@tonic-gate 		if (((i + 7) < MAXARGS)
14340Sstevel@tonic-gate 		    && ((q = entry->arg[i + 7]) != (char *) NULL)
14350Sstevel@tonic-gate 		    && (q[0] != '\0'))
14360Sstevel@tonic-gate 		    ap7 = q;
14370Sstevel@tonic-gate 	    }
14380Sstevel@tonic-gate 	}
14390Sstevel@tonic-gate     }
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate     if (anonymous && (match_value < 0)) {
14420Sstevel@tonic-gate 	reply(550, "%s: Permission denied on server. (Upload dirs)", name);
14430Sstevel@tonic-gate 	return (0);
14440Sstevel@tonic-gate     }
14450Sstevel@tonic-gate     if ((ap2 && !strcasecmp(ap2, "no"))
14460Sstevel@tonic-gate 	|| (ap3 && !strcasecmp(ap3, "nodirs"))
14470Sstevel@tonic-gate 	|| (ap6 && !strcasecmp(ap6, "nodirs"))) {
14480Sstevel@tonic-gate 	reply(550, "%s: Permission denied on server. (Upload dirs)", name);
14490Sstevel@tonic-gate 	return (0);
14500Sstevel@tonic-gate     }
14510Sstevel@tonic-gate     if ((ap3 && *ap3 == '*') || (ap4 && *ap4 == '*'))
14520Sstevel@tonic-gate 	stat_result = stat(path, &stbuf);
14530Sstevel@tonic-gate     if (ap3) {
14540Sstevel@tonic-gate 	if ((ap3[0] != '*') || (ap3[1] != '\0'))
14550Sstevel@tonic-gate 	    *uid = atoi(ap3);	/* the uid  */
14560Sstevel@tonic-gate 	else if (stat_result == 0)
14570Sstevel@tonic-gate 	    *uid = stbuf.st_uid;
14580Sstevel@tonic-gate     }
14590Sstevel@tonic-gate     if (ap4) {
14600Sstevel@tonic-gate 	if ((ap4[0] != '*') || (ap4[1] != '\0'))
14610Sstevel@tonic-gate 	    *gid = atoi(ap4);	/* the gid */
14620Sstevel@tonic-gate 	else if (stat_result == 0)
14630Sstevel@tonic-gate 	    *gid = stbuf.st_gid;
14640Sstevel@tonic-gate     }
14650Sstevel@tonic-gate     if (ap7) {
14660Sstevel@tonic-gate 	sscanf(ap7, "%o", d_mode);
14670Sstevel@tonic-gate 	*valid = 1;
14680Sstevel@tonic-gate     }
14690Sstevel@tonic-gate     else if (ap5) {
14700Sstevel@tonic-gate 	sscanf(ap5, "%o", d_mode);
14710Sstevel@tonic-gate 	if (*d_mode & 0600)
14720Sstevel@tonic-gate 	    *d_mode |= 0100;
14730Sstevel@tonic-gate 	if (*d_mode & 0060)
14740Sstevel@tonic-gate 	    *d_mode |= 0010;
14750Sstevel@tonic-gate 	if (*d_mode & 0006)
14760Sstevel@tonic-gate 	    *d_mode |= 0001;
14770Sstevel@tonic-gate 	*valid = 1;
14780Sstevel@tonic-gate     }
14790Sstevel@tonic-gate     return (1);
14800Sstevel@tonic-gate }
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate int upl_check(char *name, uid_t * uid, gid_t * gid, int *f_mode, int *valid)
14830Sstevel@tonic-gate {
14840Sstevel@tonic-gate     int match_value = -1;
14850Sstevel@tonic-gate     char cwdir[MAXPATHLEN];
14860Sstevel@tonic-gate     char *pwdir;
14870Sstevel@tonic-gate     char abspwdir[MAXPATHLEN];
14880Sstevel@tonic-gate     char relpwdir[MAXPATHLEN];
14890Sstevel@tonic-gate     char path[MAXPATHLEN];
14900Sstevel@tonic-gate     char *sp;
14910Sstevel@tonic-gate     struct stat stbuf;
14920Sstevel@tonic-gate     int stat_result = -1;
14930Sstevel@tonic-gate     char *ap2 = NULL;
14940Sstevel@tonic-gate     char *ap3 = NULL;
14950Sstevel@tonic-gate     char *ap4 = NULL;
14960Sstevel@tonic-gate     char *ap5 = NULL;
14970Sstevel@tonic-gate     struct aclmember *entry = NULL;
14980Sstevel@tonic-gate     char class[1024];
14990Sstevel@tonic-gate     extern char *home;
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate     *valid = 0;
15020Sstevel@tonic-gate     (void) acl_getclass(class);
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate     /* what's our current directory? */
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate     /* XXX We could use dynamic RAM to store this path, but I'd rather just bail
15070Sstevel@tonic-gate        out with an error. The rest of wu is so crufy that a long path might
15080Sstevel@tonic-gate        just blow up later */
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate     if ((strlen(name) + 1) > sizeof(path)) {
15110Sstevel@tonic-gate 	perror_reply(553, "Path too long");
15120Sstevel@tonic-gate 	return (-1);
15130Sstevel@tonic-gate     }
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate     strcpy(path, name);
15160Sstevel@tonic-gate     sp = strrchr(path, '/');
15170Sstevel@tonic-gate     if (sp)
15180Sstevel@tonic-gate 	*sp = '\0';
15190Sstevel@tonic-gate     else
15200Sstevel@tonic-gate 	strcpy(path, ".");
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate     if ((fb_realpath(path, cwdir)) == NULL) {
15230Sstevel@tonic-gate 	perror_reply(553, "Could not determine cwdir");
15240Sstevel@tonic-gate 	return (-1);
15250Sstevel@tonic-gate     }
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate     if ((wu_realpath(home, abspwdir, chroot_path)) == NULL) {
15280Sstevel@tonic-gate 	perror_reply(553, "Could not determine pwdir");
15290Sstevel@tonic-gate 	return (-1);
15300Sstevel@tonic-gate     }
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate     if ((fb_realpath(home, relpwdir)) == NULL) {
15330Sstevel@tonic-gate 	perror_reply(553, "Could not determine pwdir");
15340Sstevel@tonic-gate 	return (-1);
15350Sstevel@tonic-gate     }
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate     /*
15380Sstevel@tonic-gate        *  we are doing a "best match"... ..so we keep track of what "match
15390Sstevel@tonic-gate        *  value" we have received so far...
15400Sstevel@tonic-gate      */
15410Sstevel@tonic-gate     while (getaclentry("upload", &entry)) {
15420Sstevel@tonic-gate 	char *q;
15430Sstevel@tonic-gate 	int i = 0;
15440Sstevel@tonic-gate 	int options = 1;
15450Sstevel@tonic-gate 	int classfound = 0;
15460Sstevel@tonic-gate 	int classmatched = 0;
15470Sstevel@tonic-gate 	pwdir = abspwdir;
15480Sstevel@tonic-gate 	while (options
15490Sstevel@tonic-gate 	       && (i < MAXARGS)
15500Sstevel@tonic-gate 	       && ((q = entry->arg[i]) != (char *) NULL)
15510Sstevel@tonic-gate 	       && (q[0] != '\0')) {
15520Sstevel@tonic-gate 	    if (strcasecmp(q, "absolute") == 0) {
15530Sstevel@tonic-gate 		i++;
15540Sstevel@tonic-gate 		pwdir = abspwdir;
15550Sstevel@tonic-gate 	    }
15560Sstevel@tonic-gate 	    else if (strcasecmp(q, "relative") == 0) {
15570Sstevel@tonic-gate 		i++;
15580Sstevel@tonic-gate 		pwdir = relpwdir;
15590Sstevel@tonic-gate 	    }
15600Sstevel@tonic-gate 	    else if (strncasecmp(q, "class=", 6) == 0) {
15610Sstevel@tonic-gate 		i++;
15620Sstevel@tonic-gate 		classfound = 1;
15630Sstevel@tonic-gate 		if (strcasecmp(q + 6, class) == 0)
15640Sstevel@tonic-gate 		    classmatched = 1;
15650Sstevel@tonic-gate 	    }
15660Sstevel@tonic-gate 	    else if (strcmp(q, "-") == 0) {
15670Sstevel@tonic-gate 		i++;
15680Sstevel@tonic-gate 		options = 0;
15690Sstevel@tonic-gate 	    }
15700Sstevel@tonic-gate 	    else
15710Sstevel@tonic-gate 		options = 0;
15720Sstevel@tonic-gate 	}
15730Sstevel@tonic-gate 	if (!classfound || classmatched) {
15740Sstevel@tonic-gate 	    int j;
15750Sstevel@tonic-gate 	    if (((i + 1) < MAXARGS)
15760Sstevel@tonic-gate 		&& ((q = entry->arg[i]) != (char *) NULL)
15770Sstevel@tonic-gate 		&& (q[0] != '\0')
15780Sstevel@tonic-gate 		&& (0 < path_compare(q, pwdir))
15790Sstevel@tonic-gate 		&& ((j = path_compare(entry->arg[i + 1], cwdir)) >= match_value)) {
15800Sstevel@tonic-gate 		match_value = j;
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 		ap2 = NULL;
15830Sstevel@tonic-gate 		if (((i + 2) < MAXARGS)
15840Sstevel@tonic-gate 		    && ((q = entry->arg[i + 2]) != (char *) NULL)
15850Sstevel@tonic-gate 		    && (q[0] != '\0'))
15860Sstevel@tonic-gate 		    ap2 = q;
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 		ap3 = NULL;
15890Sstevel@tonic-gate 		if (((i + 3) < MAXARGS)
15900Sstevel@tonic-gate 		    && ((q = entry->arg[i + 3]) != (char *) NULL)
15910Sstevel@tonic-gate 		    && (q[0] != '\0'))
15920Sstevel@tonic-gate 		    ap3 = q;
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 		ap4 = NULL;
15950Sstevel@tonic-gate 		if (((i + 4) < MAXARGS)
15960Sstevel@tonic-gate 		    && ((q = entry->arg[i + 4]) != (char *) NULL)
15970Sstevel@tonic-gate 		    && (q[0] != '\0'))
15980Sstevel@tonic-gate 		    ap4 = q;
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate 		ap5 = NULL;
16010Sstevel@tonic-gate 		if (((i + 5) < MAXARGS)
16020Sstevel@tonic-gate 		    && ((q = entry->arg[i + 5]) != (char *) NULL)
16030Sstevel@tonic-gate 		    && (q[0] != '\0'))
16040Sstevel@tonic-gate 		    ap5 = q;
16050Sstevel@tonic-gate 	    }
16060Sstevel@tonic-gate 	}
16070Sstevel@tonic-gate     }
16080Sstevel@tonic-gate 
16090Sstevel@tonic-gate     if (ap3
16100Sstevel@tonic-gate 	&& ((!strcasecmp("dirs", ap3))
16110Sstevel@tonic-gate 	    || (!strcasecmp("nodirs", ap3))))
16120Sstevel@tonic-gate 	ap3 = NULL;
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate     /*
16150Sstevel@tonic-gate        *  if we did get matches ... else don't do any of this stuff
16160Sstevel@tonic-gate      */
16170Sstevel@tonic-gate     if (match_value >= 0) {
16180Sstevel@tonic-gate 	if (!strcasecmp(ap2, "yes")) {
16190Sstevel@tonic-gate 	    if ((ap3 && *ap3 == '*') || (ap4 && *ap4 == '*'))
16200Sstevel@tonic-gate 		stat_result = stat(path, &stbuf);
16210Sstevel@tonic-gate 	    if (ap3) {
16220Sstevel@tonic-gate 		if ((ap3[0] != '*') || (ap3[1] != '\0'))
16230Sstevel@tonic-gate 		    *uid = atoi(ap3);	/* the uid  */
16240Sstevel@tonic-gate 		else if (stat_result == 0)
16250Sstevel@tonic-gate 		    *uid = stbuf.st_uid;
16260Sstevel@tonic-gate 	    }
16270Sstevel@tonic-gate 	    if (ap4) {
16280Sstevel@tonic-gate 		if ((ap4[0] != '*') || (ap4[1] != '\0'))
16290Sstevel@tonic-gate 		    *gid = atoi(ap4);	/* the gid  */
16300Sstevel@tonic-gate 		else if (stat_result == 0)
16310Sstevel@tonic-gate 		    *gid = stbuf.st_gid;
16320Sstevel@tonic-gate 		*valid = 1;
16330Sstevel@tonic-gate 	    }
16340Sstevel@tonic-gate 	    if (ap5)
16350Sstevel@tonic-gate 		sscanf(ap5, "%o", f_mode);	/* the mode */
16360Sstevel@tonic-gate 	}
16370Sstevel@tonic-gate 	else {
16380Sstevel@tonic-gate 	    reply(553, "%s: Permission denied on server. (Upload)", name);
16390Sstevel@tonic-gate 	    return (-1);
16400Sstevel@tonic-gate 	}
16410Sstevel@tonic-gate     }
16420Sstevel@tonic-gate     else {
16430Sstevel@tonic-gate 	/*
16440Sstevel@tonic-gate 	   *  upload defaults to "permitted"
16450Sstevel@tonic-gate 	 */
16460Sstevel@tonic-gate 	/* Not if anonymous */
16470Sstevel@tonic-gate 	if (anonymous) {
16480Sstevel@tonic-gate 	    reply(553, "%s: Permission denied on server. (Upload)", name);
16490Sstevel@tonic-gate 	    return (-1);
16500Sstevel@tonic-gate 	}
16510Sstevel@tonic-gate 	return (1);
16520Sstevel@tonic-gate     }
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate     return (match_value);
16550Sstevel@tonic-gate }
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate int del_check(char *name)
16580Sstevel@tonic-gate {
16590Sstevel@tonic-gate     int pdelete = (anonymous ? 0 : 1);
16600Sstevel@tonic-gate     struct aclmember *entry = NULL;
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate     while (getaclentry("delete", &entry) && ARG0 && ARG1 != NULL) {
16630Sstevel@tonic-gate 	if (type_match(ARG1))
16640Sstevel@tonic-gate 	    if (anonymous) {
16650Sstevel@tonic-gate 		if (*ARG0 == 'y')
16660Sstevel@tonic-gate 		    pdelete = 1;
16670Sstevel@tonic-gate 	    }
16680Sstevel@tonic-gate 	    else if (*ARG0 == 'n')
16690Sstevel@tonic-gate 		pdelete = 0;
16700Sstevel@tonic-gate     }
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate /* H* fix: no deletion, period. You put a file here, I get to look at it. */
16730Sstevel@tonic-gate #ifdef PARANOID
16740Sstevel@tonic-gate     pdelete = 0;
16750Sstevel@tonic-gate #endif
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate     if (!pdelete) {
16780Sstevel@tonic-gate 	reply(553, "%s: Permission denied on server. (Delete)", name);
16790Sstevel@tonic-gate 	return (0);
16800Sstevel@tonic-gate     }
16810Sstevel@tonic-gate     else {
16820Sstevel@tonic-gate 	return (1);
16830Sstevel@tonic-gate     }
16840Sstevel@tonic-gate }
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate /* The following is from the Debian add-ons. */
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate #define lbasename(x) (strrchr(x,'/')?1+strrchr(x,'/'):x)
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate int regexmatch(char *name, char *rgexp)
16910Sstevel@tonic-gate {
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate #ifdef M_UNIX
16940Sstevel@tonic-gate #ifdef HAVE_REGEX
16950Sstevel@tonic-gate     char *regp;
16960Sstevel@tonic-gate #endif
16970Sstevel@tonic-gate #endif
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate #ifdef HAVE_REGEXEC
17000Sstevel@tonic-gate     regex_t regexbuf;
17010Sstevel@tonic-gate     regmatch_t regmatchbuf;
17020Sstevel@tonic-gate     int rval;
17030Sstevel@tonic-gate #else
17040Sstevel@tonic-gate     char *sp;
17050Sstevel@tonic-gate #endif
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate #if defined(HAVE_REGEXEC)
17080Sstevel@tonic-gate     if (regcomp(&regexbuf, rgexp, REG_EXTENDED) != 0) {
17090Sstevel@tonic-gate 	reply(553, "HAVE_REGEX error");
17100Sstevel@tonic-gate #elif defined(HAVE_REGEX)
17110Sstevel@tonic-gate 	if ((sp = regcmp(rgexp, (char *) 0)) == NULL) {
17120Sstevel@tonic-gate 	    reply(553, "HAVE_REGEX error");
17130Sstevel@tonic-gate #else
17140Sstevel@tonic-gate     if ((sp = re_comp(rgexp)) != 0) {
17150Sstevel@tonic-gate 	perror_reply(553, sp);
17160Sstevel@tonic-gate #endif
17170Sstevel@tonic-gate 	return (0);
17180Sstevel@tonic-gate     }
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate #if defined(HAVE_REGEXEC)
17210Sstevel@tonic-gate     rval = regexec(&regexbuf, name, 1, &regmatchbuf, 0);
17220Sstevel@tonic-gate     regfree(&regexbuf);
17230Sstevel@tonic-gate     if (rval != 0) {
17240Sstevel@tonic-gate #elif defined(HAVE_REGEX)
17250Sstevel@tonic-gate #ifdef M_UNIX
17260Sstevel@tonic-gate 	regp = regex(sp, name);
17270Sstevel@tonic-gate 	free(sp);
17280Sstevel@tonic-gate 	if (regp == NULL) {
17290Sstevel@tonic-gate #else
17300Sstevel@tonic-gate 	if ((regex(sp, name)) == NULL) {
17310Sstevel@tonic-gate #endif
17320Sstevel@tonic-gate #else
17330Sstevel@tonic-gate     if ((re_exec(name)) != 1) {
17340Sstevel@tonic-gate #endif
17350Sstevel@tonic-gate 	return (0);
17360Sstevel@tonic-gate     }
17370Sstevel@tonic-gate     return (1);
17380Sstevel@tonic-gate }
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate static int allow_retrieve(char *name)
17410Sstevel@tonic-gate {
17420Sstevel@tonic-gate     char realname[MAXPATHLEN + 1];
17430Sstevel@tonic-gate     char localname[MAXPATHLEN + 1];
17440Sstevel@tonic-gate     char *whichname;
17450Sstevel@tonic-gate     int i;
17460Sstevel@tonic-gate     struct aclmember *entry = NULL;
17470Sstevel@tonic-gate     char *p, *q;
17480Sstevel@tonic-gate     int options;
17490Sstevel@tonic-gate     int classfound;
17500Sstevel@tonic-gate     int classmatched;
17510Sstevel@tonic-gate     char class[1024];
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate     (void) acl_getclass(class);
17540Sstevel@tonic-gate     if ((name == (char *) NULL)
17550Sstevel@tonic-gate 	|| (*name == '\0'))
17560Sstevel@tonic-gate 	return 0;
17570Sstevel@tonic-gate     fb_realpath(name, localname);
17580Sstevel@tonic-gate     wu_realpath(name, realname, chroot_path);
17590Sstevel@tonic-gate     while (getaclentry("allow-retrieve", &entry)) {
17600Sstevel@tonic-gate 	whichname = realname;
17610Sstevel@tonic-gate 	i = 0;
17620Sstevel@tonic-gate 	options = 1;
17630Sstevel@tonic-gate 	classfound = 0;
17640Sstevel@tonic-gate 	classmatched = 0;
17650Sstevel@tonic-gate 	while (options
17660Sstevel@tonic-gate 	       && (i < MAXARGS)
17670Sstevel@tonic-gate 	       && ((q = entry->arg[i]) != (char *) NULL)
17680Sstevel@tonic-gate 	       && (q[0] != '\0')) {
17690Sstevel@tonic-gate 	    if (strcasecmp(q, "absolute") == 0) {
17700Sstevel@tonic-gate 		i++;
17710Sstevel@tonic-gate 		whichname = realname;
17720Sstevel@tonic-gate 	    }
17730Sstevel@tonic-gate 	    else if (strcasecmp(q, "relative") == 0) {
17740Sstevel@tonic-gate 		i++;
17750Sstevel@tonic-gate 		whichname = localname;
17760Sstevel@tonic-gate 	    }
17770Sstevel@tonic-gate 	    else if (strncasecmp(q, "class=", 6) == 0) {
17780Sstevel@tonic-gate 		i++;
17790Sstevel@tonic-gate 		classfound = 1;
17800Sstevel@tonic-gate 		if (strcasecmp(q + 6, class) == 0)
17810Sstevel@tonic-gate 		    classmatched = 1;
17820Sstevel@tonic-gate 	    }
17830Sstevel@tonic-gate 	    else if (strcmp(q, "-") == 0) {
17840Sstevel@tonic-gate 		i++;
17850Sstevel@tonic-gate 		options = 0;
17860Sstevel@tonic-gate 	    }
17870Sstevel@tonic-gate 	    else
17880Sstevel@tonic-gate 		options = 0;
17890Sstevel@tonic-gate 	}
17900Sstevel@tonic-gate 	if (!classfound || classmatched) {
17910Sstevel@tonic-gate 	    for (; (i < MAXARGS) && ((q = entry->arg[i]) != (char *) NULL) && (q[0] != '\0'); i++) {
17920Sstevel@tonic-gate 		p = (q[0] == '/') ? whichname : lbasename(whichname);
17930Sstevel@tonic-gate 		if (!wu_fnmatch(q, p, FNM_PATHNAME | FNM_LEADING_DIR)) {
17940Sstevel@tonic-gate 		    return 1;
17950Sstevel@tonic-gate 		}
17960Sstevel@tonic-gate 	    }
17970Sstevel@tonic-gate 	}
17980Sstevel@tonic-gate     }
17990Sstevel@tonic-gate     return 0;
18000Sstevel@tonic-gate }
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate int checknoretrieve(char *name)
18030Sstevel@tonic-gate {
18040Sstevel@tonic-gate     char realname[MAXPATHLEN + 1];
18050Sstevel@tonic-gate     char localname[MAXPATHLEN + 1];
18060Sstevel@tonic-gate     char *whichname;
18070Sstevel@tonic-gate     int i;
18080Sstevel@tonic-gate     struct aclmember *entry = NULL;
18090Sstevel@tonic-gate     char *p, *q;
18100Sstevel@tonic-gate     int options;
18110Sstevel@tonic-gate     int classfound;
18120Sstevel@tonic-gate     int classmatched;
18130Sstevel@tonic-gate     char class[1024];
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate     extern struct passwd *pw;
18160Sstevel@tonic-gate     extern char *remoteident;
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate     (void) acl_getclass(class);
18190Sstevel@tonic-gate     if ((name == (char *) NULL)
18200Sstevel@tonic-gate 	|| (*name == '\0'))
18210Sstevel@tonic-gate 	return 0;
18220Sstevel@tonic-gate     fb_realpath(name, localname);
18230Sstevel@tonic-gate     wu_realpath(name, realname, chroot_path);
18240Sstevel@tonic-gate     while (getaclentry("noretrieve", &entry)) {
18250Sstevel@tonic-gate 	whichname = realname;
18260Sstevel@tonic-gate 	i = 0;
18270Sstevel@tonic-gate 	options = 1;
18280Sstevel@tonic-gate 	classfound = 0;
18290Sstevel@tonic-gate 	classmatched = 0;
18300Sstevel@tonic-gate 	while (options
18310Sstevel@tonic-gate 	       && (i < MAXARGS)
18320Sstevel@tonic-gate 	       && ((q = entry->arg[i]) != (char *) NULL)
18330Sstevel@tonic-gate 	       && (q[0] != '\0')) {
18340Sstevel@tonic-gate 	    if (strcasecmp(q, "absolute") == 0) {
18350Sstevel@tonic-gate 		i++;
18360Sstevel@tonic-gate 		whichname = realname;
18370Sstevel@tonic-gate 	    }
18380Sstevel@tonic-gate 	    else if (strcasecmp(q, "relative") == 0) {
18390Sstevel@tonic-gate 		i++;
18400Sstevel@tonic-gate 		whichname = localname;
18410Sstevel@tonic-gate 	    }
18420Sstevel@tonic-gate 	    else if (strncasecmp(q, "class=", 6) == 0) {
18430Sstevel@tonic-gate 		i++;
18440Sstevel@tonic-gate 		classfound = 1;
18450Sstevel@tonic-gate 		if (strcasecmp(q + 6, class) == 0)
18460Sstevel@tonic-gate 		    classmatched = 1;
18470Sstevel@tonic-gate 	    }
18480Sstevel@tonic-gate 	    else if (strcmp(q, "-") == 0) {
18490Sstevel@tonic-gate 		i++;
18500Sstevel@tonic-gate 		options = 0;
18510Sstevel@tonic-gate 	    }
18520Sstevel@tonic-gate 	    else
18530Sstevel@tonic-gate 		options = 0;
18540Sstevel@tonic-gate 	}
18550Sstevel@tonic-gate 	if (!classfound || classmatched) {
18560Sstevel@tonic-gate 	    for (; (i < MAXARGS) && ((q = entry->arg[i]) != (char *) NULL) && (q[0] != '\0'); i++) {
18570Sstevel@tonic-gate 		p = (q[0] == '/') ? whichname : lbasename(whichname);
18580Sstevel@tonic-gate 		if (!wu_fnmatch(q, p, FNM_PATHNAME | FNM_LEADING_DIR)) {
18590Sstevel@tonic-gate 		    if (!allow_retrieve(name)) {
18600Sstevel@tonic-gate 			reply(550, "%s is marked unretrievable", localname);
18610Sstevel@tonic-gate 			return 1;
18620Sstevel@tonic-gate 		    }
18630Sstevel@tonic-gate 		}
18640Sstevel@tonic-gate 	    }
18650Sstevel@tonic-gate 	}
18660Sstevel@tonic-gate     }
18670Sstevel@tonic-gate     return 0;
18680Sstevel@tonic-gate }
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate #ifdef QUOTA
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate #ifndef MNTMAXSTR
18730Sstevel@tonic-gate #define MNTMAXSTR 2048		/* And hope it's enough */
18740Sstevel@tonic-gate #endif
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate #ifdef QUOTA_DEVICE
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate int path_to_device(char *pathname, char *result)
18790Sstevel@tonic-gate {
18800Sstevel@tonic-gate     FILE *fp;
18810Sstevel@tonic-gate #ifdef HAS_OLDSTYLE_GETMNTENT
18820Sstevel@tonic-gate     struct mnttab static_mp;
18830Sstevel@tonic-gate     struct mnttab *mp = &static_mp;
18840Sstevel@tonic-gate #else
18850Sstevel@tonic-gate     struct mntent *mp;
18860Sstevel@tonic-gate #endif
18870Sstevel@tonic-gate     struct mount_ent {
18880Sstevel@tonic-gate 	char mnt_fsname[MNTMAXSTR], mnt_dir[MNTMAXSTR];
18890Sstevel@tonic-gate 	struct mount_ent *next;
18900Sstevel@tonic-gate     } mountent;
18910Sstevel@tonic-gate     struct mount_ent *current, *start, *new;
18920Sstevel@tonic-gate     char path[1024], mnt_dir[1024], *pos;
18930Sstevel@tonic-gate     int flag = 1;
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate     start = current = NULL;
18960Sstevel@tonic-gate #ifdef HAS_OLDSTYLE_GETMNTENT
18970Sstevel@tonic-gate     fp = fopen(MNTTAB, "r");
18980Sstevel@tonic-gate #else
18990Sstevel@tonic-gate     fp = setmntent(MNTTAB, "r");
19000Sstevel@tonic-gate #endif
19010Sstevel@tonic-gate     if (fp == NULL)
19020Sstevel@tonic-gate 	return 0;
19030Sstevel@tonic-gate #ifdef HAS_OLDSTYLE_GETMNTENT
19040Sstevel@tonic-gate     while (getmntent(fp, &static_mp) == 0)
19050Sstevel@tonic-gate #else
19060Sstevel@tonic-gate     while (mp = getmntent(fp))
19070Sstevel@tonic-gate #endif
19080Sstevel@tonic-gate     {
19090Sstevel@tonic-gate 	if (!(new = (struct mount_ent *) malloc(sizeof(mountent)))) {
19100Sstevel@tonic-gate 	    perror("malloc");
19110Sstevel@tonic-gate 	    flag = 0;
19120Sstevel@tonic-gate 	    break;
19130Sstevel@tonic-gate 	}
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 	if (!start)
19160Sstevel@tonic-gate 	    start = current = new;
19170Sstevel@tonic-gate 	else
19180Sstevel@tonic-gate 	    current = current->next = new;
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate #ifdef HAS_OLDSTYLE_GETMNTENT
19210Sstevel@tonic-gate 	strncpy(current->mnt_fsname, mp->mnt_special, strlen(mp->mnt_special) + 1);
19220Sstevel@tonic-gate 	strncpy(current->mnt_dir, mp->mnt_mountp, strlen(mp->mnt_mountp) + 1);
19230Sstevel@tonic-gate #else
19240Sstevel@tonic-gate 	strncpy(current->mnt_fsname, mp->mnt_fsname, strlen(mp->mnt_fsname) + 1);
19250Sstevel@tonic-gate 	strncpy(current->mnt_dir, mp->mnt_dir, strlen(mp->mnt_dir) + 1);
19260Sstevel@tonic-gate #endif
19270Sstevel@tonic-gate     }
19280Sstevel@tonic-gate #ifdef HAS_OLDSTYLE_GETMNTENT
19290Sstevel@tonic-gate     fclose(fp);
19300Sstevel@tonic-gate #else
19310Sstevel@tonic-gate     endmntent(fp);
19320Sstevel@tonic-gate #endif
19330Sstevel@tonic-gate     current->next = NULL;
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate     wu_realpath(pathname, path, chroot_path);
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate     while (*path && flag) {
19380Sstevel@tonic-gate 	current = start;
19390Sstevel@tonic-gate 	while (current && flag) {
19400Sstevel@tonic-gate 	    if (strcmp(current->mnt_dir, "swap")) {
19410Sstevel@tonic-gate 		wu_realpath(current->mnt_dir, mnt_dir, chroot_path);
19420Sstevel@tonic-gate 		if (!strcmp(mnt_dir, path)) {
19430Sstevel@tonic-gate 		    flag = 0;
19440Sstevel@tonic-gate 		    /* no support for remote quota yet */
19450Sstevel@tonic-gate 		    if (!strchr(current->mnt_fsname, ':'))
19460Sstevel@tonic-gate 			strcpy(result, current->mnt_fsname);
19470Sstevel@tonic-gate 		}
19480Sstevel@tonic-gate 	    }
19490Sstevel@tonic-gate 	    current = current->next;
19500Sstevel@tonic-gate 	}
19510Sstevel@tonic-gate 	if (!((pos = strrchr(path, '/')) - path) && strlen(path) > 1)
19520Sstevel@tonic-gate 	    strcpy(path, "/");
19530Sstevel@tonic-gate 	else
19540Sstevel@tonic-gate 	    path[pos - path] = '\0';
19550Sstevel@tonic-gate     }
19560Sstevel@tonic-gate     while (current) {
19570Sstevel@tonic-gate 	new = current->next;
19580Sstevel@tonic-gate 	free(current);
19590Sstevel@tonic-gate 	current = new;
19600Sstevel@tonic-gate     }
19610Sstevel@tonic-gate     return 1;
19620Sstevel@tonic-gate }
19630Sstevel@tonic-gate #endif
19640Sstevel@tonic-gate 
19650Sstevel@tonic-gate void get_quota(char *fs, int uid)
19660Sstevel@tonic-gate {
19670Sstevel@tonic-gate     char mnt_fsname[MNTMAXSTR];
19680Sstevel@tonic-gate #ifdef HAS_NO_QUOTACTL
19690Sstevel@tonic-gate     int dirfd;
19700Sstevel@tonic-gate     struct quotctl qp;
19710Sstevel@tonic-gate #endif
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate     /*
19740Sstevel@tonic-gate      * Getting file system quota information can take a noticeable amount
19750Sstevel@tonic-gate      * of time, so only get quota information for specified users.
19760Sstevel@tonic-gate      * quota-info <uid-range> [<uid-range> ...]
19770Sstevel@tonic-gate      */
19780Sstevel@tonic-gate     if (!uid_match("quota-info", uid))
19790Sstevel@tonic-gate 	return;
19800Sstevel@tonic-gate 
19810Sstevel@tonic-gate #ifdef HAS_NO_QUOTACTL
19820Sstevel@tonic-gate     if (path_to_device(fs, mnt_fsname)) {
19830Sstevel@tonic-gate 	dirfd = open(fs, O_RDONLY);
19840Sstevel@tonic-gate 	qp.op = Q_GETQUOTA;
19850Sstevel@tonic-gate 	qp.uid = uid;
19860Sstevel@tonic-gate 	qp.addr = (char *) &quota;
19870Sstevel@tonic-gate 	ioctl(dirfd, Q_QUOTACTL, &qp);
19880Sstevel@tonic-gate 	close(dirfd);
19890Sstevel@tonic-gate     }
19900Sstevel@tonic-gate #else
19910Sstevel@tonic-gate #ifdef QUOTA_DEVICE
19920Sstevel@tonic-gate 
19930Sstevel@tonic-gate     if (path_to_device(fs, mnt_fsname))
19940Sstevel@tonic-gate #ifdef QCMD
19950Sstevel@tonic-gate 	quotactl(QCMD(Q_GETQUOTA, USRQUOTA), mnt_fsname, uid, (char *) &quota);
19960Sstevel@tonic-gate #else
19970Sstevel@tonic-gate 	quotactl(Q_GETQUOTA, mnt_fsname, uid, (char *) &quota);
19980Sstevel@tonic-gate #endif
19990Sstevel@tonic-gate #else
20000Sstevel@tonic-gate     quotactl(fs, QCMD(Q_GETQUOTA, USRQUOTA), uid, (char *) &quota);
20010Sstevel@tonic-gate #endif
20020Sstevel@tonic-gate #endif /* HAS_NO_QUOTACTL */
20030Sstevel@tonic-gate }
20040Sstevel@tonic-gate 
20050Sstevel@tonic-gate char *time_quota(long curstate, long softlimit, long timelimit, char *timeleft)
20060Sstevel@tonic-gate {
20070Sstevel@tonic-gate     struct timeval tv;
20080Sstevel@tonic-gate 
20090Sstevel@tonic-gate     gettimeofday(&tv, NULL);
20100Sstevel@tonic-gate     if (softlimit && curstate >= softlimit) {
20110Sstevel@tonic-gate 	if (timelimit == 0) {
20120Sstevel@tonic-gate 	    strcpy(timeleft, "NOT STARTED");
20130Sstevel@tonic-gate 	}
20140Sstevel@tonic-gate 	else if (timelimit > tv.tv_sec) {
20150Sstevel@tonic-gate 	    fmttime(timeleft, timelimit - tv.tv_sec);
20160Sstevel@tonic-gate 	}
20170Sstevel@tonic-gate 	else {
20180Sstevel@tonic-gate 	    strcpy(timeleft, "EXPIRED");
20190Sstevel@tonic-gate 	}
20200Sstevel@tonic-gate     }
20210Sstevel@tonic-gate     else {
20220Sstevel@tonic-gate 	timeleft[0] = '\0';
20230Sstevel@tonic-gate     }
20240Sstevel@tonic-gate     return (timeleft);
20250Sstevel@tonic-gate }
20260Sstevel@tonic-gate 
20270Sstevel@tonic-gate void fmttime(char *buf, register long time)
20280Sstevel@tonic-gate {
20290Sstevel@tonic-gate     int i;
20300Sstevel@tonic-gate     static struct {
20310Sstevel@tonic-gate 	int c_secs;		/* conversion units in secs */
20320Sstevel@tonic-gate 	char *c_str;		/* unit string */
20330Sstevel@tonic-gate     } cunits[] = {
20340Sstevel@tonic-gate 	{
20350Sstevel@tonic-gate 	    60 *60 * 24 * 28, "months"
20360Sstevel@tonic-gate 	} ,
20370Sstevel@tonic-gate 	{
20380Sstevel@tonic-gate 	    60 *60 * 24 * 7, "weeks"
20390Sstevel@tonic-gate 	} ,
20400Sstevel@tonic-gate 	{
20410Sstevel@tonic-gate 	    60 *60 * 24, "days"
20420Sstevel@tonic-gate 	} ,
20430Sstevel@tonic-gate 	{
20440Sstevel@tonic-gate 	    60 *60, "hours"
20450Sstevel@tonic-gate 	} ,
20460Sstevel@tonic-gate 	{
20470Sstevel@tonic-gate 	    60, "mins"
20480Sstevel@tonic-gate 	} ,
20490Sstevel@tonic-gate 	{
20500Sstevel@tonic-gate 	    1, "secs"
20510Sstevel@tonic-gate 	}
20520Sstevel@tonic-gate     };
20530Sstevel@tonic-gate 
20540Sstevel@tonic-gate     if (time <= 0) {
20550Sstevel@tonic-gate 	strcpy(buf, "EXPIRED");
20560Sstevel@tonic-gate 	return;
20570Sstevel@tonic-gate     }
20580Sstevel@tonic-gate     for (i = 0; i < sizeof(cunits) / sizeof(cunits[0]); i++) {
20590Sstevel@tonic-gate 	if (time >= cunits[i].c_secs)
20600Sstevel@tonic-gate 	    break;
20610Sstevel@tonic-gate     }
20620Sstevel@tonic-gate     sprintf(buf, "%.1f %s", (double) time / cunits[i].c_secs, cunits[i].c_str);
20630Sstevel@tonic-gate }
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate #endif
20660Sstevel@tonic-gate 
20670Sstevel@tonic-gate #ifdef THROUGHPUT
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate int file_compare(char *patterns, char *file)
20700Sstevel@tonic-gate {
20710Sstevel@tonic-gate     char buf[MAXPATHLEN+1];
20720Sstevel@tonic-gate     char *cp;
20730Sstevel@tonic-gate     char *cp2;
20740Sstevel@tonic-gate     int i;
20750Sstevel@tonic-gate     int matches = 0;
20760Sstevel@tonic-gate 
20770Sstevel@tonic-gate     strncpy(buf, patterns, sizeof(buf) - 1);
20780Sstevel@tonic-gate     buf[sizeof(buf) - 2] = '\0';
20790Sstevel@tonic-gate     i = strlen(buf);
20800Sstevel@tonic-gate     buf[i++] = ',';
20810Sstevel@tonic-gate     buf[i++] = '\0';
20820Sstevel@tonic-gate 
20830Sstevel@tonic-gate     cp = buf;
20840Sstevel@tonic-gate     while ((cp2 = strchr(cp, ',')) != NULL) {
20850Sstevel@tonic-gate 	*cp2++ = '\0';
20860Sstevel@tonic-gate 	if (wu_fnmatch(cp, file, FNM_PATHNAME) == 0) {
20870Sstevel@tonic-gate 	    matches = 1;
20880Sstevel@tonic-gate 	    break;
20890Sstevel@tonic-gate 	}
20900Sstevel@tonic-gate 	cp = cp2;
20910Sstevel@tonic-gate     }
20920Sstevel@tonic-gate     return matches;
20930Sstevel@tonic-gate }
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate int remote_compare(char *patterns)
20960Sstevel@tonic-gate {
20970Sstevel@tonic-gate     char buf[MAXPATHLEN+1];
20980Sstevel@tonic-gate     char *cp;
20990Sstevel@tonic-gate     char *cp2;
21000Sstevel@tonic-gate     int i;
21010Sstevel@tonic-gate     int matches = 0;
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate     strncpy(buf, patterns, sizeof(buf) - 1);
21040Sstevel@tonic-gate     buf[sizeof(buf) - 2] = '\0';
21050Sstevel@tonic-gate     i = strlen(buf);
21060Sstevel@tonic-gate     buf[i++] = ',';
21070Sstevel@tonic-gate     buf[i++] = '\0';
21080Sstevel@tonic-gate 
21090Sstevel@tonic-gate     cp = buf;
21100Sstevel@tonic-gate     while ((cp2 = strchr(cp, ',')) != NULL) {
21110Sstevel@tonic-gate 	*cp2++ = '\0';
21120Sstevel@tonic-gate 	if (hostmatch(cp, remoteaddr, remotehost)) {
21130Sstevel@tonic-gate 	    matches = 1;
21140Sstevel@tonic-gate 	    break;
21150Sstevel@tonic-gate 	}
21160Sstevel@tonic-gate 	cp = cp2;
21170Sstevel@tonic-gate     }
21180Sstevel@tonic-gate     return matches;
21190Sstevel@tonic-gate }
21200Sstevel@tonic-gate 
21210Sstevel@tonic-gate void throughput_calc(char *name, int *bps, double *bpsmult)
21220Sstevel@tonic-gate {
21230Sstevel@tonic-gate     int match_value = -1;
21240Sstevel@tonic-gate     char cwdir[MAXPATHLEN];
21250Sstevel@tonic-gate     char pwdir[MAXPATHLEN];
21260Sstevel@tonic-gate     char path[MAXPATHLEN];
21270Sstevel@tonic-gate     char file[MAXPATHLEN];
21280Sstevel@tonic-gate     char *ap3 = NULL, *ap4 = NULL;
21290Sstevel@tonic-gate     struct aclmember *entry = NULL;
21300Sstevel@tonic-gate     extern char *home;
21310Sstevel@tonic-gate     char *sp;
21320Sstevel@tonic-gate     int i;
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate     /* default is maximum throughput */
21350Sstevel@tonic-gate     *bps = -1;
21360Sstevel@tonic-gate     *bpsmult = 1.0;
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate     /* XXX We could use dynamic RAM to store this path, but I'd rather just bail
21390Sstevel@tonic-gate        out with an error. The rest of wu is so crufy that a long path might
21400Sstevel@tonic-gate        just blow up later */
21410Sstevel@tonic-gate 
21420Sstevel@tonic-gate     if ((strlen(name) + 1) > sizeof(path)) {
21430Sstevel@tonic-gate 	return;
21440Sstevel@tonic-gate     }
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate     /* what's our current directory? */
21470Sstevel@tonic-gate     strcpy(path, name);
21480Sstevel@tonic-gate     if ((sp = strrchr(path, '/')))
21490Sstevel@tonic-gate 	*sp = '\0';
21500Sstevel@tonic-gate     else
21510Sstevel@tonic-gate 	strcpy(path, ".");
21520Sstevel@tonic-gate     if ((sp = strrchr(name, '/')))
21530Sstevel@tonic-gate 	strcpy(file, sp + 1);
21540Sstevel@tonic-gate     else
21550Sstevel@tonic-gate 	strcpy(file, name);
21560Sstevel@tonic-gate     if ((fb_realpath(path, cwdir)) == NULL) {
21570Sstevel@tonic-gate 	return;
21580Sstevel@tonic-gate     }
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate     wu_realpath(home, pwdir, chroot_path);
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate     /* find best matching entry */
21630Sstevel@tonic-gate     while (getaclentry("throughput", &entry) && ARG0 && ARG1 && ARG2 && ARG3 && ARG4 && ARG5 != NULL) {
21640Sstevel@tonic-gate 	if ((0 < path_compare(ARG0, pwdir))
21650Sstevel@tonic-gate 	    && ((i = path_compare(ARG1, cwdir)) >= match_value)
21660Sstevel@tonic-gate 	    ) {
21670Sstevel@tonic-gate 	    if (file_compare(ARG2, file)) {
21680Sstevel@tonic-gate 		if (remote_compare(ARG5)) {
21690Sstevel@tonic-gate 		    match_value = i;
21700Sstevel@tonic-gate 		    ap3 = ARG3;
21710Sstevel@tonic-gate 		    ap4 = ARG4;
21720Sstevel@tonic-gate 		}
21730Sstevel@tonic-gate 	    }
21740Sstevel@tonic-gate 	}
21750Sstevel@tonic-gate     }
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate     /* if we did get matches */
21780Sstevel@tonic-gate     if (match_value >= 0) {
21790Sstevel@tonic-gate 	if (strcasecmp(ap3, "oo") == 0)
21800Sstevel@tonic-gate 	    *bps = -1;
21810Sstevel@tonic-gate 	else
21820Sstevel@tonic-gate 	    *bps = atoi(ap3);
21830Sstevel@tonic-gate 	if (strcmp(ap4, "-") == 0)
21840Sstevel@tonic-gate 	    *bpsmult = 1.0;
21850Sstevel@tonic-gate 	else
21860Sstevel@tonic-gate 	    *bpsmult = atof(ap4);
21870Sstevel@tonic-gate     }
21880Sstevel@tonic-gate     return;
21890Sstevel@tonic-gate }
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate void throughput_adjust(char *name)
21920Sstevel@tonic-gate {
21930Sstevel@tonic-gate     int match_value = -1;
21940Sstevel@tonic-gate     char pwdir[MAXPATHLEN];
21950Sstevel@tonic-gate     char cwdir[MAXPATHLEN];
21960Sstevel@tonic-gate     char path[MAXPATHLEN];
21970Sstevel@tonic-gate     char file[MAXPATHLEN];
21980Sstevel@tonic-gate     char buf[MAXPATHLEN];
21990Sstevel@tonic-gate     char *ap3 = NULL, *ap4 = NULL;
22000Sstevel@tonic-gate     char **pap;
22010Sstevel@tonic-gate     struct aclmember *entry = NULL;
22020Sstevel@tonic-gate     extern char *home;
22030Sstevel@tonic-gate     char *sp;
22040Sstevel@tonic-gate     int i;
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate     /* XXX We could use dynamic RAM to store this path, but I'd rather just bail
22070Sstevel@tonic-gate        out with an error. The rest of wu is so crufy that a long path might
22080Sstevel@tonic-gate        just blow up later */
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate     if ((strlen(name) + 1) > sizeof(path)) {
22110Sstevel@tonic-gate 	return;
22120Sstevel@tonic-gate     }
22130Sstevel@tonic-gate 
22140Sstevel@tonic-gate     /* what's our current directory? */
22150Sstevel@tonic-gate     strcpy(path, name);
22160Sstevel@tonic-gate     if ((sp = strrchr(path, '/')))
22170Sstevel@tonic-gate 	*sp = '\0';
22180Sstevel@tonic-gate     else
22190Sstevel@tonic-gate 	strcpy(path, ".");
22200Sstevel@tonic-gate     if ((sp = strrchr(name, '/')))
22210Sstevel@tonic-gate 	strcpy(file, sp + 1);
22220Sstevel@tonic-gate     else
22230Sstevel@tonic-gate 	strcpy(file, name);
22240Sstevel@tonic-gate     if ((fb_realpath(path, cwdir)) == NULL) {
22250Sstevel@tonic-gate 	return;
22260Sstevel@tonic-gate     }
22270Sstevel@tonic-gate 
22280Sstevel@tonic-gate     wu_realpath(home, pwdir, chroot_path);
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate     /* find best matching entry */
22310Sstevel@tonic-gate     while (getaclentry("throughput", &entry) && ARG0 && ARG1 && ARG2 && ARG3 && ARG4 && ARG5 != NULL) {
22320Sstevel@tonic-gate 	if ((0 < path_compare(ARG0, pwdir))
22330Sstevel@tonic-gate 	    && ((i = path_compare(ARG1, cwdir)) >= match_value)
22340Sstevel@tonic-gate 	    ) {
22350Sstevel@tonic-gate 	    if (file_compare(ARG2, file)) {
22360Sstevel@tonic-gate 		if (remote_compare(ARG5)) {
22370Sstevel@tonic-gate 		    match_value = i;
22380Sstevel@tonic-gate 		    ap3 = ARG3;
22390Sstevel@tonic-gate 		    pap = ARG;
22400Sstevel@tonic-gate 		    ap4 = ARG4;
22410Sstevel@tonic-gate 		}
22420Sstevel@tonic-gate 	    }
22430Sstevel@tonic-gate 	}
22440Sstevel@tonic-gate     }
22450Sstevel@tonic-gate 
22460Sstevel@tonic-gate     /* if we did get matches */
22470Sstevel@tonic-gate     if (match_value >= 0) {
22480Sstevel@tonic-gate 	if (strcasecmp(ap3, "oo") != 0) {
22490Sstevel@tonic-gate 	    if (strcmp(ap4, "-") != 0) {
22500Sstevel@tonic-gate 		sprintf(buf, "%.0f", atoi(ap3) * atof(ap4));
22510Sstevel@tonic-gate 		pap[3] = (char *) malloc(strlen(buf) + 1);
22520Sstevel@tonic-gate 		if (pap[3] == NULL) {
22530Sstevel@tonic-gate 		    syslog(LOG_ERR, "malloc error in throughput_adjust");
22540Sstevel@tonic-gate 		    dologout(1);
22550Sstevel@tonic-gate 		}
22560Sstevel@tonic-gate 		/* Use ARG6 to keep track of malloced memory */
22570Sstevel@tonic-gate 		if (pap[6])
22580Sstevel@tonic-gate 		    free(pap[6]);
22590Sstevel@tonic-gate 		pap[6] = pap[3];
22600Sstevel@tonic-gate 		strcpy(pap[3], buf);
22610Sstevel@tonic-gate 	    }
22620Sstevel@tonic-gate 	}
22630Sstevel@tonic-gate     }
22640Sstevel@tonic-gate     return;
22650Sstevel@tonic-gate }
22660Sstevel@tonic-gate 
22670Sstevel@tonic-gate #endif
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate #ifdef SOLARIS_2
22700Sstevel@tonic-gate static int CheckMethod = 1;
22710Sstevel@tonic-gate #else
22720Sstevel@tonic-gate static int CheckMethod = 0;
22730Sstevel@tonic-gate #endif
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate void SetCheckMethod(const char *method)
22760Sstevel@tonic-gate {
22770Sstevel@tonic-gate     if ((strcasecmp(method, "md5") == 0)
22780Sstevel@tonic-gate 	|| (strcasecmp(method, "rfc1321") == 0))
22790Sstevel@tonic-gate 	CheckMethod = 0;
22800Sstevel@tonic-gate     else if ((strcasecmp(method, "crc") == 0)
22810Sstevel@tonic-gate 	     || (strcasecmp(method, "posix") == 0))
22820Sstevel@tonic-gate 	CheckMethod = 1;
22830Sstevel@tonic-gate     else {
22840Sstevel@tonic-gate 	reply(500, "Unrecognized checksum method");
22850Sstevel@tonic-gate 	return;
22860Sstevel@tonic-gate     }
22870Sstevel@tonic-gate     switch (CheckMethod) {
22880Sstevel@tonic-gate     default:
22890Sstevel@tonic-gate 	reply(200, "Checksum method is now: MD5 (RFC1321)");
22900Sstevel@tonic-gate 	break;
22910Sstevel@tonic-gate     case 1:
22920Sstevel@tonic-gate 	reply(200, "Checksum method is now: CRC (POSIX)");
22930Sstevel@tonic-gate 	break;
22940Sstevel@tonic-gate     }
22950Sstevel@tonic-gate }
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate void ShowCheckMethod(void)
22980Sstevel@tonic-gate {
22990Sstevel@tonic-gate     switch (CheckMethod) {
23000Sstevel@tonic-gate     default:
23010Sstevel@tonic-gate 	reply(200, "Current checksum method: MD5 (RFC1321)");
23020Sstevel@tonic-gate 	break;
23030Sstevel@tonic-gate     case 1:
23040Sstevel@tonic-gate 	reply(200, "Current checksum method: CRC (POSIX)");
23050Sstevel@tonic-gate 	break;
23060Sstevel@tonic-gate     }
23070Sstevel@tonic-gate }
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate void CheckSum(char *pathname)
23100Sstevel@tonic-gate {
23110Sstevel@tonic-gate     char *cmd;
23120Sstevel@tonic-gate     char buf[MAXPATHLEN];
23130Sstevel@tonic-gate     FILE *cmdf;
23140Sstevel@tonic-gate     struct stat st;
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate     if (stat(pathname, &st) == 0) {
23170Sstevel@tonic-gate 	if ((st.st_mode & S_IFMT) != S_IFREG) {
23180Sstevel@tonic-gate 	    reply(500, "%s: not a plain file.", pathname);
23190Sstevel@tonic-gate 	    return;
23200Sstevel@tonic-gate 	}
23210Sstevel@tonic-gate     }
23220Sstevel@tonic-gate     else {
23230Sstevel@tonic-gate 	perror_reply(550, pathname);
23240Sstevel@tonic-gate 	return;
23250Sstevel@tonic-gate     }
23260Sstevel@tonic-gate 
23270Sstevel@tonic-gate     switch (CheckMethod) {
23280Sstevel@tonic-gate     default:
23290Sstevel@tonic-gate 	cmd = "/bin/md5sum";
23300Sstevel@tonic-gate 	break;
23310Sstevel@tonic-gate     case 1:
23320Sstevel@tonic-gate 	cmd = "/bin/cksum";
23330Sstevel@tonic-gate 	break;
23340Sstevel@tonic-gate     }
23350Sstevel@tonic-gate 
23360Sstevel@tonic-gate     if (strlen(cmd) + 1 + strlen(pathname) + 1 > sizeof(buf)) {
23370Sstevel@tonic-gate 	reply(500, "Pathname too long");
23380Sstevel@tonic-gate 	return;
23390Sstevel@tonic-gate     }
23400Sstevel@tonic-gate     sprintf(buf, "%s %s", cmd, pathname);
23410Sstevel@tonic-gate 
23420Sstevel@tonic-gate     cmdf = ftpd_popen(buf, "r", 0);
23430Sstevel@tonic-gate     if (!cmdf) {
23440Sstevel@tonic-gate 	perror_reply(550, cmd);
23450Sstevel@tonic-gate     }
23460Sstevel@tonic-gate     else {
23470Sstevel@tonic-gate 	if (fgets(buf, sizeof buf, cmdf)) {
23480Sstevel@tonic-gate 	    char *crptr = strchr(buf, '\n');
23490Sstevel@tonic-gate 	    if (crptr != NULL)
23500Sstevel@tonic-gate 		*crptr = '\0';
23510Sstevel@tonic-gate 	    reply(200, "%s", buf);
23520Sstevel@tonic-gate 	}
23530Sstevel@tonic-gate 	ftpd_pclose(cmdf);
23540Sstevel@tonic-gate     }
23550Sstevel@tonic-gate }
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate void CheckSumLastFile(void)
23580Sstevel@tonic-gate {
23590Sstevel@tonic-gate     extern char LastFileTransferred[];
23600Sstevel@tonic-gate 
23610Sstevel@tonic-gate     if (LastFileTransferred[0] == '\0')
23620Sstevel@tonic-gate 	reply(500, "Nothing transferred yet");
23630Sstevel@tonic-gate     else
23640Sstevel@tonic-gate 	CheckSum(LastFileTransferred);
23650Sstevel@tonic-gate }
2366