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(®exbuf, 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(®exbuf, path, 1, ®matchbuf, 0);
12440Sstevel@tonic-gate regfree(®exbuf);
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(®exbuf, 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(®exbuf, path, 1, ®matchbuf, 0);
12800Sstevel@tonic-gate regfree(®exbuf);
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(®exbuf, 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(®exbuf, name, 1, ®matchbuf, 0);
17220Sstevel@tonic-gate regfree(®exbuf);
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 *) "a;
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 *) "a);
19960Sstevel@tonic-gate #else
19970Sstevel@tonic-gate quotactl(Q_GETQUOTA, mnt_fsname, uid, (char *) "a);
19980Sstevel@tonic-gate #endif
19990Sstevel@tonic-gate #else
20000Sstevel@tonic-gate quotactl(fs, QCMD(Q_GETQUOTA, USRQUOTA), uid, (char *) "a);
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