1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate /**************************************************************************** 9*0Sstevel@tonic-gate 10*0Sstevel@tonic-gate Copyright (c) 1999,2000 WU-FTPD Development Group. 11*0Sstevel@tonic-gate All rights reserved. 12*0Sstevel@tonic-gate 13*0Sstevel@tonic-gate Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994 14*0Sstevel@tonic-gate The Regents of the University of California. 15*0Sstevel@tonic-gate Portions Copyright (c) 1993, 1994 Washington University in Saint Louis. 16*0Sstevel@tonic-gate Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc. 17*0Sstevel@tonic-gate Portions Copyright (c) 1989 Massachusetts Institute of Technology. 18*0Sstevel@tonic-gate Portions Copyright (c) 1998 Sendmail, Inc. 19*0Sstevel@tonic-gate Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P. Allman. 20*0Sstevel@tonic-gate Portions Copyright (c) 1997 by Stan Barber. 21*0Sstevel@tonic-gate Portions Copyright (c) 1997 by Kent Landfield. 22*0Sstevel@tonic-gate Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997 23*0Sstevel@tonic-gate Free Software Foundation, Inc. 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate Use and distribution of this software and its source code are governed 26*0Sstevel@tonic-gate by the terms and conditions of the WU-FTPD Software License ("LICENSE"). 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate If you did not receive a copy of the license, it may be obtained online 29*0Sstevel@tonic-gate at http://www.wu-ftpd.org/license.html. 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate $Id: extensions.c,v 1.48 2000/07/01 18:17:38 wuftpd Exp $ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate ****************************************************************************/ 34*0Sstevel@tonic-gate #include "config.h" 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate #include <stdio.h> 37*0Sstevel@tonic-gate #include <errno.h> 38*0Sstevel@tonic-gate #include <string.h> 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate #ifdef HAVE_SYS_SYSLOG_H 41*0Sstevel@tonic-gate #include <sys/syslog.h> 42*0Sstevel@tonic-gate #endif 43*0Sstevel@tonic-gate #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H)) 44*0Sstevel@tonic-gate #include <syslog.h> 45*0Sstevel@tonic-gate #endif 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate #ifdef TIME_WITH_SYS_TIME 48*0Sstevel@tonic-gate #include <time.h> 49*0Sstevel@tonic-gate #include <sys/time.h> 50*0Sstevel@tonic-gate #else 51*0Sstevel@tonic-gate #ifdef HAVE_SYS_TIME_H 52*0Sstevel@tonic-gate #include <sys/time.h> 53*0Sstevel@tonic-gate #else 54*0Sstevel@tonic-gate #include <time.h> 55*0Sstevel@tonic-gate #endif 56*0Sstevel@tonic-gate #endif 57*0Sstevel@tonic-gate #include <pwd.h> 58*0Sstevel@tonic-gate #include <setjmp.h> 59*0Sstevel@tonic-gate #include <grp.h> 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate #include <sys/types.h> 62*0Sstevel@tonic-gate #include <sys/stat.h> 63*0Sstevel@tonic-gate #include <sys/file.h> 64*0Sstevel@tonic-gate #include <sys/param.h> 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate #ifdef HAVE_SYS_FS_UFS_QUOTA_H 67*0Sstevel@tonic-gate #include <sys/fs/ufs_quota.h> 68*0Sstevel@tonic-gate #elif defined(HAVE_UFS_UFS_QUOTA_H) 69*0Sstevel@tonic-gate #include <ufs/ufs/quota.h> 70*0Sstevel@tonic-gate #elif defined(HAVE_UFS_QUOTA_H) 71*0Sstevel@tonic-gate #include <ufs/quota.h> 72*0Sstevel@tonic-gate #elif defined(HAVE_SYS_MNTENT_H) 73*0Sstevel@tonic-gate #include <sys/mntent.h> 74*0Sstevel@tonic-gate #elif defined(HAVE_SYS_MNTTAB_H) 75*0Sstevel@tonic-gate #include <sys/mnttab.h> 76*0Sstevel@tonic-gate #endif 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate #if defined(HAVE_STATVFS) 79*0Sstevel@tonic-gate #include <sys/statvfs.h> 80*0Sstevel@tonic-gate #elif defined(HAVE_SYS_VFS) 81*0Sstevel@tonic-gate #include <sys/vfs.h> 82*0Sstevel@tonic-gate #elif defined(HAVE_SYS_MOUNT) 83*0Sstevel@tonic-gate #include <sys/mount.h> 84*0Sstevel@tonic-gate #endif 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate #include <arpa/ftp.h> 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate #ifdef HAVE_PATHS_H 89*0Sstevel@tonic-gate #include <paths.h> 90*0Sstevel@tonic-gate #endif 91*0Sstevel@tonic-gate #include "pathnames.h" 92*0Sstevel@tonic-gate #include "extensions.h" 93*0Sstevel@tonic-gate #include "wu_fnmatch.h" 94*0Sstevel@tonic-gate #include "proto.h" 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate #if defined(HAVE_FTW) 97*0Sstevel@tonic-gate #include <ftw.h> 98*0Sstevel@tonic-gate #else 99*0Sstevel@tonic-gate #include "support/ftw.h" 100*0Sstevel@tonic-gate #endif 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate #ifdef QUOTA 103*0Sstevel@tonic-gate struct dqblk quota; 104*0Sstevel@tonic-gate char *time_quota(long curstate, long softlimit, long timelimit, char *timeleft); 105*0Sstevel@tonic-gate #endif 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate #ifdef HAVE_REGEX_H 108*0Sstevel@tonic-gate #include <regex.h> 109*0Sstevel@tonic-gate #endif 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate #if defined(HAVE_REGEX) && defined(SVR4) && ! (defined(NO_LIBGEN)) 112*0Sstevel@tonic-gate #include <libgen.h> 113*0Sstevel@tonic-gate #endif 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate extern int type, transflag, ftwflag, authenticated, autospout_free, data, 116*0Sstevel@tonic-gate pdata, anonymous, guest; 117*0Sstevel@tonic-gate extern char chroot_path[], guestpw[]; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate #ifdef TRANSFER_COUNT 120*0Sstevel@tonic-gate extern off_t data_count_in; 121*0Sstevel@tonic-gate extern off_t data_count_out; 122*0Sstevel@tonic-gate #ifdef TRANSFER_LIMIT 123*0Sstevel@tonic-gate extern off_t data_limit_raw_in; 124*0Sstevel@tonic-gate extern off_t data_limit_raw_out; 125*0Sstevel@tonic-gate extern off_t data_limit_raw_total; 126*0Sstevel@tonic-gate extern off_t data_limit_data_in; 127*0Sstevel@tonic-gate extern off_t data_limit_data_out; 128*0Sstevel@tonic-gate extern off_t data_limit_data_total; 129*0Sstevel@tonic-gate #ifdef RATIO /* 1998/08/06 K.Wakui */ 130*0Sstevel@tonic-gate #define TRUNC_KB(n) ((n)/1024+(((n)%1024)?1:0)) 131*0Sstevel@tonic-gate extern time_t login_time; 132*0Sstevel@tonic-gate extern time_t limit_time; 133*0Sstevel@tonic-gate extern off_t total_free_dl; 134*0Sstevel@tonic-gate extern int upload_download_rate; 135*0Sstevel@tonic-gate #endif /* RATIO */ 136*0Sstevel@tonic-gate #endif 137*0Sstevel@tonic-gate #endif 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate #ifdef OTHER_PASSWD 140*0Sstevel@tonic-gate #include "getpwnam.h" 141*0Sstevel@tonic-gate extern char _path_passwd[]; 142*0Sstevel@tonic-gate #endif 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate #ifdef LOG_FAILED 145*0Sstevel@tonic-gate extern char the_user[]; 146*0Sstevel@tonic-gate #endif 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate extern char *globerr, remotehost[]; 149*0Sstevel@tonic-gate #ifdef THROUGHPUT 150*0Sstevel@tonic-gate extern char remoteaddr[]; 151*0Sstevel@tonic-gate #endif 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate #ifndef HAVE_REGEX 154*0Sstevel@tonic-gate char *re_comp(const char *regex); 155*0Sstevel@tonic-gate int re_exec(const char *p1); 156*0Sstevel@tonic-gate #endif 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate char shuttime[30], denytime[30], disctime[30]; 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate FILE *dout; 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate time_t newer_time; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate int show_fullinfo; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate /* This always was a bug, because neither st_size nor time_t were required to 167*0Sstevel@tonic-gate be compatible with int, but needs fixing properly for C9X. */ 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate /* Some systems use one format, some another. This takes care of the garbage */ 170*0Sstevel@tonic-gate /* Do the system specific stuff only if we aren't autoconfed */ 171*0Sstevel@tonic-gate #if !defined(L_FORMAT) 172*0Sstevel@tonic-gate #if (defined(BSD) && (BSD >= 199103)) && !defined(LONGOFF_T) 173*0Sstevel@tonic-gate #define L_FORMAT "qd" 174*0Sstevel@tonic-gate #else 175*0Sstevel@tonic-gate #define L_FORMAT "d" 176*0Sstevel@tonic-gate #endif 177*0Sstevel@tonic-gate #endif 178*0Sstevel@tonic-gate #if !defined(T_FORMAT) 179*0Sstevel@tonic-gate #define T_FORMAT "d" 180*0Sstevel@tonic-gate #endif 181*0Sstevel@tonic-gate #if !defined(PW_UID_FORMAT) 182*0Sstevel@tonic-gate #define PW_UID_FORMAT "d" 183*0Sstevel@tonic-gate #endif 184*0Sstevel@tonic-gate #if !defined(GR_GID_FORMAT) 185*0Sstevel@tonic-gate #define GR_GID_FORMAT "d" 186*0Sstevel@tonic-gate #endif 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate int snprintf(char *str, size_t count, const char *fmt,...); 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate #ifdef SITE_NEWER 191*0Sstevel@tonic-gate int check_newer(const char *path, const struct stat *st, int flag) 192*0Sstevel@tonic-gate { 193*0Sstevel@tonic-gate if (st->st_mtime > newer_time) { 194*0Sstevel@tonic-gate if (show_fullinfo != 0) { 195*0Sstevel@tonic-gate if (flag == FTW_F || flag == FTW_D) { 196*0Sstevel@tonic-gate fprintf(dout, "%s %" L_FORMAT " %" T_FORMAT " %s\n", 197*0Sstevel@tonic-gate flag == FTW_F ? "F" : "D", 198*0Sstevel@tonic-gate st->st_size, st->st_mtime, path); 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate else if (flag == FTW_F) 202*0Sstevel@tonic-gate fprintf(dout, "%s\n", path); 203*0Sstevel@tonic-gate } 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate /* When an ABOR has been received (which sets ftwflag > 1) return a 206*0Sstevel@tonic-gate * non-zero value which causes ftw to stop tree traversal and return. 207*0Sstevel@tonic-gate */ 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate return (ftwflag > 1 ? 1 : 0); 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate #endif 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate #if defined(HAVE_STATVFS) 214*0Sstevel@tonic-gate long getSize(char *s) 215*0Sstevel@tonic-gate { 216*0Sstevel@tonic-gate struct statvfs buf; 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate if (statvfs(s, &buf) != 0) 219*0Sstevel@tonic-gate return (0); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate return (buf.f_bavail * buf.f_frsize / 1024); 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate #elif defined(HAVE_SYS_VFS) || defined (HAVE_SYS_MOUNT) 224*0Sstevel@tonic-gate long getSize(char *s) 225*0Sstevel@tonic-gate { 226*0Sstevel@tonic-gate struct statfs buf; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate if (statfs(s, &buf) != 0) 229*0Sstevel@tonic-gate return (0); 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate return (buf.f_bavail * buf.f_bsize / 1024); 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate #endif 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate /*************************************************************************/ 236*0Sstevel@tonic-gate /* FUNCTION : msg_massage */ 237*0Sstevel@tonic-gate /* PURPOSE : Scan a message line for magic cookies, replacing them as */ 238*0Sstevel@tonic-gate /* needed. */ 239*0Sstevel@tonic-gate /* ARGUMENTS : pointer input and output buffers */ 240*0Sstevel@tonic-gate /*************************************************************************/ 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate void msg_massage(const char *inbuf, char *outbuf, size_t outlen) 243*0Sstevel@tonic-gate { 244*0Sstevel@tonic-gate const char *inptr = inbuf; 245*0Sstevel@tonic-gate char *outptr = outbuf; 246*0Sstevel@tonic-gate #ifdef QUOTA 247*0Sstevel@tonic-gate char timeleft[80]; 248*0Sstevel@tonic-gate #endif 249*0Sstevel@tonic-gate char buffer[MAXPATHLEN]; 250*0Sstevel@tonic-gate time_t curtime; 251*0Sstevel@tonic-gate int limit; 252*0Sstevel@tonic-gate #ifndef LOG_FAILED 253*0Sstevel@tonic-gate extern struct passwd *pw; 254*0Sstevel@tonic-gate #endif 255*0Sstevel@tonic-gate struct aclmember *entry; 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate #ifdef VIRTUAL 258*0Sstevel@tonic-gate extern int virtual_mode; 259*0Sstevel@tonic-gate extern int virtual_ftpaccess; 260*0Sstevel@tonic-gate extern char virtual_email[]; 261*0Sstevel@tonic-gate #endif 262*0Sstevel@tonic-gate extern char hostname[]; 263*0Sstevel@tonic-gate extern char authuser[]; 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate (void) acl_getclass(buffer); 266*0Sstevel@tonic-gate limit = acl_getlimit(buffer, NULL); 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate while ((outlen > 1) && (*inptr != '\0')) { 269*0Sstevel@tonic-gate if (*inptr != '%') { 270*0Sstevel@tonic-gate *outptr++ = *inptr; 271*0Sstevel@tonic-gate outlen -= 1; 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate else { 274*0Sstevel@tonic-gate entry = NULL; 275*0Sstevel@tonic-gate switch (*++inptr) { 276*0Sstevel@tonic-gate case 'E': 277*0Sstevel@tonic-gate #ifdef VIRTUAL 278*0Sstevel@tonic-gate if (virtual_mode && !virtual_ftpaccess && virtual_email[0] != '\0') 279*0Sstevel@tonic-gate snprintf(outptr, outlen, "%s", virtual_email); 280*0Sstevel@tonic-gate else 281*0Sstevel@tonic-gate #endif 282*0Sstevel@tonic-gate if ((getaclentry("email", &entry)) && ARG0) 283*0Sstevel@tonic-gate snprintf(outptr, outlen, "%s", ARG0); 284*0Sstevel@tonic-gate else 285*0Sstevel@tonic-gate *outptr = '\0'; 286*0Sstevel@tonic-gate break; 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate case 'N': 289*0Sstevel@tonic-gate snprintf(outptr, outlen, "%d", acl_countusers(buffer)); 290*0Sstevel@tonic-gate break; 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate case 'M': 293*0Sstevel@tonic-gate if (limit == -1) 294*0Sstevel@tonic-gate strncpy(outptr, "unlimited", outlen); 295*0Sstevel@tonic-gate else 296*0Sstevel@tonic-gate snprintf(outptr, outlen, "%d", limit); 297*0Sstevel@tonic-gate break; 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate case 'T': 300*0Sstevel@tonic-gate (void) time(&curtime); 301*0Sstevel@tonic-gate strncpy(outptr, ctime(&curtime), outlen); 302*0Sstevel@tonic-gate if (outlen > 24) 303*0Sstevel@tonic-gate *(outptr + 24) = '\0'; 304*0Sstevel@tonic-gate break; 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate case 'F': 307*0Sstevel@tonic-gate #if defined(HAVE_STATVFS) || defined(HAVE_SYS_VFS) || defined(HAVE_SYS_MOUNT) 308*0Sstevel@tonic-gate snprintf(outptr, outlen, "%lu", (long) getSize(".")); 309*0Sstevel@tonic-gate #else 310*0Sstevel@tonic-gate *outptr = '\0'; 311*0Sstevel@tonic-gate #endif 312*0Sstevel@tonic-gate break; 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate case 'C': 315*0Sstevel@tonic-gate #ifdef HAVE_GETCWD 316*0Sstevel@tonic-gate (void) getcwd(outptr, outlen); 317*0Sstevel@tonic-gate #else 318*0Sstevel@tonic-gate #error wu-ftpd on this platform has security deficiencies!!! 319*0Sstevel@tonic-gate (void) getwd(outptr); 320*0Sstevel@tonic-gate #endif 321*0Sstevel@tonic-gate break; 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate case 'R': 324*0Sstevel@tonic-gate strncpy(outptr, remotehost, outlen); 325*0Sstevel@tonic-gate break; 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate case 'L': 328*0Sstevel@tonic-gate strncpy(outptr, hostname, outlen); 329*0Sstevel@tonic-gate break; 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate case 'U': 332*0Sstevel@tonic-gate if (xferdone && anonymous) 333*0Sstevel@tonic-gate strncpy(outptr, guestpw, outlen); 334*0Sstevel@tonic-gate else 335*0Sstevel@tonic-gate #ifdef LOG_FAILED 336*0Sstevel@tonic-gate strncpy(outptr, the_user, outlen); 337*0Sstevel@tonic-gate #else /* LOG_FAILED */ 338*0Sstevel@tonic-gate strncpy(outptr, 339*0Sstevel@tonic-gate (pw == NULL) ? "[unknown]" : pw->pw_name, outlen); 340*0Sstevel@tonic-gate #endif /* LOG_FAILED */ 341*0Sstevel@tonic-gate break; 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate case 's': 344*0Sstevel@tonic-gate strncpy(outptr, shuttime, outlen); 345*0Sstevel@tonic-gate if (outlen > 24) 346*0Sstevel@tonic-gate *(outptr + 24) = '\0'; 347*0Sstevel@tonic-gate break; 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate case 'd': 350*0Sstevel@tonic-gate strncpy(outptr, disctime, outlen); 351*0Sstevel@tonic-gate if (outlen > 24) 352*0Sstevel@tonic-gate *(outptr + 24) = '\0'; 353*0Sstevel@tonic-gate break; 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate case 'r': 356*0Sstevel@tonic-gate strncpy(outptr, denytime, outlen); 357*0Sstevel@tonic-gate if (outlen > 24) 358*0Sstevel@tonic-gate *(outptr + 24) = '\0'; 359*0Sstevel@tonic-gate break; 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* KH : cookie %u for RFC931 name */ 362*0Sstevel@tonic-gate case 'u': 363*0Sstevel@tonic-gate if (authenticated) 364*0Sstevel@tonic-gate strncpy(outptr, authuser, outlen); 365*0Sstevel@tonic-gate else { 366*0Sstevel@tonic-gate if (xferdone) 367*0Sstevel@tonic-gate snprintf(outptr, outlen, "%c", '*'); 368*0Sstevel@tonic-gate else 369*0Sstevel@tonic-gate strncpy(outptr, "[unknown]", outlen); 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate break; 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate #ifdef QUOTA 374*0Sstevel@tonic-gate case 'B': 375*0Sstevel@tonic-gate #ifdef QUOTA_BLOCKS /* 1024-blocks instead of 512-blocks */ 376*0Sstevel@tonic-gate snprintf(outptr, outlen, "%ld", quota.dqb_bhardlimit % 2 ? 377*0Sstevel@tonic-gate (long) (quota.dqb_bhardlimit / 2 + 1) : (long) (quota.dqb_bhardlimit / 2)); 378*0Sstevel@tonic-gate #else 379*0Sstevel@tonic-gate snprintf(outptr, outlen, "%ld", (long) quota.dqb_bhardlimit); 380*0Sstevel@tonic-gate #endif 381*0Sstevel@tonic-gate break; 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate case 'b': 384*0Sstevel@tonic-gate #ifdef QUOTA_BLOCKS /* 1024-blocks instead of 512-blocks */ 385*0Sstevel@tonic-gate snprintf(outptr, outlen, "%ld", quota.dqb_bsoftlimit % 2 ? 386*0Sstevel@tonic-gate (long) (quota.dqb_bsoftlimit / 2 + 1) : (long) (quota.dqb_bsoftlimit / 2)); 387*0Sstevel@tonic-gate #else 388*0Sstevel@tonic-gate snprintf(outptr, outlen, "%ld", (long) quota.dqb_bsoftlimit); 389*0Sstevel@tonic-gate #endif 390*0Sstevel@tonic-gate break; 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate case 'Q': 393*0Sstevel@tonic-gate #ifdef QUOTA_BLOCKS /* 1024-blocks instead of 512-blocks */ 394*0Sstevel@tonic-gate snprintf(outptr, outlen, "%ld", quota.dqb_curblocks % 2 ? 395*0Sstevel@tonic-gate (long) (quota.dqb_curblocks / 2 + 1) : (long) (quota.dqb_curblocks / 2)); 396*0Sstevel@tonic-gate #else 397*0Sstevel@tonic-gate snprintf(outptr, outlen, "%ld", quota.dqb_curblocks); 398*0Sstevel@tonic-gate #endif 399*0Sstevel@tonic-gate break; 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate case 'I': 402*0Sstevel@tonic-gate #if defined(QUOTA_INODE) 403*0Sstevel@tonic-gate snprintf(outptr, outlen, "%d", quota.dqb_ihardlimit); 404*0Sstevel@tonic-gate #else 405*0Sstevel@tonic-gate snprintf(outptr, outlen, "%ld", (long) quota.dqb_fhardlimit); 406*0Sstevel@tonic-gate #endif 407*0Sstevel@tonic-gate break; 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate case 'i': 410*0Sstevel@tonic-gate #if defined(QUOTA_INODE) 411*0Sstevel@tonic-gate snprintf(outptr, outlen, "%d", quota.dqb_isoftlimit); 412*0Sstevel@tonic-gate #else 413*0Sstevel@tonic-gate snprintf(outptr, outlen, "%ld", (long) quota.dqb_fsoftlimit); 414*0Sstevel@tonic-gate #endif 415*0Sstevel@tonic-gate break; 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate case 'q': 418*0Sstevel@tonic-gate #if defined(QUOTA_INODE) 419*0Sstevel@tonic-gate snprintf(outptr, outlen, "%d", quota.dqb_curinodes); 420*0Sstevel@tonic-gate #else 421*0Sstevel@tonic-gate snprintf(outptr, outlen, "%ld", (long) quota.dqb_curfiles); 422*0Sstevel@tonic-gate #endif 423*0Sstevel@tonic-gate break; 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate case 'H': 426*0Sstevel@tonic-gate time_quota(quota.dqb_curblocks, quota.dqb_bsoftlimit, 427*0Sstevel@tonic-gate #if defined(QUOTA_INODE) 428*0Sstevel@tonic-gate quota.dqb_btime, timeleft); 429*0Sstevel@tonic-gate #else 430*0Sstevel@tonic-gate quota.dqb_btimelimit, timeleft); 431*0Sstevel@tonic-gate #endif 432*0Sstevel@tonic-gate strncpy(outptr, timeleft, outlen); 433*0Sstevel@tonic-gate break; 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate case 'h': 436*0Sstevel@tonic-gate #if defined(QUOTA_INODE) 437*0Sstevel@tonic-gate time_quota(quota.dqb_curinodes, quota.dqb_isoftlimit, 438*0Sstevel@tonic-gate quota.dqb_itime, timeleft); 439*0Sstevel@tonic-gate #else 440*0Sstevel@tonic-gate time_quota(quota.dqb_curfiles, quota.dqb_fsoftlimit, 441*0Sstevel@tonic-gate quota.dqb_ftimelimit, timeleft); 442*0Sstevel@tonic-gate #endif 443*0Sstevel@tonic-gate strncpy(outptr, timeleft, outlen); 444*0Sstevel@tonic-gate break; 445*0Sstevel@tonic-gate #endif /* QUOTA */ 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate case '%': 448*0Sstevel@tonic-gate *outptr++ = '%'; 449*0Sstevel@tonic-gate outlen -= 1; 450*0Sstevel@tonic-gate *outptr = '\0'; 451*0Sstevel@tonic-gate break; 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate #ifdef TRANSFER_COUNT 454*0Sstevel@tonic-gate #ifdef TRANSFER_LIMIT 455*0Sstevel@tonic-gate #ifdef RATIO 456*0Sstevel@tonic-gate case 'x': 457*0Sstevel@tonic-gate switch (*++inptr) { 458*0Sstevel@tonic-gate case 'u': /* upload bytes */ 459*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_count_in) ); 460*0Sstevel@tonic-gate break; 461*0Sstevel@tonic-gate case 'd': /* download bytes */ 462*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_count_out) ); 463*0Sstevel@tonic-gate break; 464*0Sstevel@tonic-gate case 'R': /* rate 1:n */ 465*0Sstevel@tonic-gate if( upload_download_rate > 0 ) { 466*0Sstevel@tonic-gate sprintf(outptr,"%d", upload_download_rate ); 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate else { 469*0Sstevel@tonic-gate strcpy(outptr,"free"); 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate break; 472*0Sstevel@tonic-gate case 'c': /* credit bytes */ 473*0Sstevel@tonic-gate if( upload_download_rate > 0 ) { 474*0Sstevel@tonic-gate off_t credit=( data_count_in * upload_download_rate) - (data_count_out - total_free_dl); 475*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(credit) ); 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate else { 478*0Sstevel@tonic-gate strcpy(outptr,"unlimited"); 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate break; 481*0Sstevel@tonic-gate case 'T': /* time limit (minutes) */ 482*0Sstevel@tonic-gate if( limit_time > 0 ) { 483*0Sstevel@tonic-gate sprintf(outptr,"%d", limit_time ); 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate else { 486*0Sstevel@tonic-gate strcpy(outptr,"unlimited"); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate break; 489*0Sstevel@tonic-gate case 'E': /* elapsed time from loggedin (minutes) */ 490*0Sstevel@tonic-gate sprintf(outptr,"%d", (time(NULL)-login_time)/60 ); 491*0Sstevel@tonic-gate break; 492*0Sstevel@tonic-gate case 'L': /* times left until force logout (minutes) */ 493*0Sstevel@tonic-gate if( limit_time > 0 ) { 494*0Sstevel@tonic-gate sprintf(outptr,"%d", limit_time-(time(NULL)-login_time)/60 ); 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate else { 497*0Sstevel@tonic-gate strcpy(outptr,"unlimited"); 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate break; 500*0Sstevel@tonic-gate case 'U': /* upload limit */ 501*0Sstevel@tonic-gate if( data_limit_raw_in > 0 ) { 502*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_raw_in)); 503*0Sstevel@tonic-gate } 504*0Sstevel@tonic-gate else if( data_limit_data_in > 0 ) { 505*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_data_in)); 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate else if( data_limit_raw_total > 0 ) { 508*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_raw_total)); 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate else if( data_limit_data_total > 0 ) { 511*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_data_total)); 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate else { 514*0Sstevel@tonic-gate strcpy(outptr, "unlimited"); 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate break; 517*0Sstevel@tonic-gate case 'D': /* download limit */ 518*0Sstevel@tonic-gate if( data_limit_raw_out > 0 ) { 519*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_raw_out)); 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate else if( data_limit_data_out > 0 ) { 522*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_data_out)); 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate else if( data_limit_raw_total > 0 ) { 525*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_raw_total)); 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate else if( data_limit_data_total > 0 ) { 528*0Sstevel@tonic-gate sprintf(outptr,"%" L_FORMAT, TRUNC_KB(data_limit_data_total)); 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate else { 531*0Sstevel@tonic-gate strcpy(outptr, "unlimited"); 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate break; 534*0Sstevel@tonic-gate default: 535*0Sstevel@tonic-gate strcpy(outptr,"%??"); 536*0Sstevel@tonic-gate break; 537*0Sstevel@tonic-gate } 538*0Sstevel@tonic-gate break; 539*0Sstevel@tonic-gate #endif /* RATIO */ 540*0Sstevel@tonic-gate #endif 541*0Sstevel@tonic-gate #endif 542*0Sstevel@tonic-gate /* File transfer logging (xferlog) */ 543*0Sstevel@tonic-gate case 'X': 544*0Sstevel@tonic-gate if (xferdone) { /* only if a transfer has just occurred */ 545*0Sstevel@tonic-gate switch (*++inptr) { 546*0Sstevel@tonic-gate case 't': 547*0Sstevel@tonic-gate snprintf(outptr, outlen, "%d", xfervalues.transfer_time); 548*0Sstevel@tonic-gate break; 549*0Sstevel@tonic-gate case 's': 550*0Sstevel@tonic-gate snprintf(outptr, outlen, "%" L_FORMAT, xfervalues.filesize); 551*0Sstevel@tonic-gate break; 552*0Sstevel@tonic-gate case 'n': 553*0Sstevel@tonic-gate snprintf(outptr, outlen, "%" L_FORMAT, xfervalues.transfer_bytes); 554*0Sstevel@tonic-gate break; 555*0Sstevel@tonic-gate case 'P': /* absolute pathname */ 556*0Sstevel@tonic-gate /* FALLTHROUGH */ 557*0Sstevel@tonic-gate case 'p': /* chroot-relative pathname */ 558*0Sstevel@tonic-gate { 559*0Sstevel@tonic-gate char namebuf[MAXPATHLEN]; 560*0Sstevel@tonic-gate int loop; 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate if (*inptr == 'P') 563*0Sstevel@tonic-gate wu_realpath(xfervalues.filename, namebuf, chroot_path); 564*0Sstevel@tonic-gate else 565*0Sstevel@tonic-gate fb_realpath(xfervalues.filename, namebuf); 566*0Sstevel@tonic-gate for (loop = 0; namebuf[loop]; loop++) { 567*0Sstevel@tonic-gate if (isspace(namebuf[loop]) || iscntrl(namebuf[loop])) 568*0Sstevel@tonic-gate namebuf[loop] = '_'; 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate snprintf(outptr, outlen, "%s", namebuf); 571*0Sstevel@tonic-gate break; 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate case 'y': 574*0Sstevel@tonic-gate snprintf(outptr, outlen, "%c", xfervalues.transfer_type); 575*0Sstevel@tonic-gate break; 576*0Sstevel@tonic-gate case 'f': 577*0Sstevel@tonic-gate snprintf(outptr, outlen, "%s", xfervalues.special_action); 578*0Sstevel@tonic-gate break; 579*0Sstevel@tonic-gate case 'd': 580*0Sstevel@tonic-gate snprintf(outptr, outlen, "%c", xfervalues.transfer_direction); 581*0Sstevel@tonic-gate break; 582*0Sstevel@tonic-gate case 'm': 583*0Sstevel@tonic-gate snprintf(outptr, outlen, "%c", xfervalues.access_mode); 584*0Sstevel@tonic-gate break; 585*0Sstevel@tonic-gate case 'a': 586*0Sstevel@tonic-gate snprintf(outptr, outlen, "%d", xfervalues.auth); 587*0Sstevel@tonic-gate break; 588*0Sstevel@tonic-gate case 'r': 589*0Sstevel@tonic-gate snprintf(outptr, outlen, "%" L_FORMAT, xfervalues.restart_offset); 590*0Sstevel@tonic-gate break; 591*0Sstevel@tonic-gate case 'c': 592*0Sstevel@tonic-gate snprintf(outptr, outlen, "%c", xfervalues.completion); 593*0Sstevel@tonic-gate break; 594*0Sstevel@tonic-gate default: 595*0Sstevel@tonic-gate snprintf(outptr, outlen, "%%X%c", *inptr); 596*0Sstevel@tonic-gate break; 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate } 599*0Sstevel@tonic-gate else 600*0Sstevel@tonic-gate snprintf(outptr, outlen, "%%%c", *inptr); 601*0Sstevel@tonic-gate break; 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate default: 604*0Sstevel@tonic-gate *outptr++ = '%'; 605*0Sstevel@tonic-gate outlen -= 1; 606*0Sstevel@tonic-gate if (outlen > 1) { 607*0Sstevel@tonic-gate *outptr++ = *inptr; 608*0Sstevel@tonic-gate outlen -= 1; 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate *outptr = '\0'; 611*0Sstevel@tonic-gate break; 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate outptr[outlen - 1] = '\0'; 614*0Sstevel@tonic-gate while (*outptr) { 615*0Sstevel@tonic-gate outptr++; 616*0Sstevel@tonic-gate outlen -= 1; 617*0Sstevel@tonic-gate } 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate inptr++; 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate if (outlen > 0) 622*0Sstevel@tonic-gate *outptr = '\0'; 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate /*************************************************************************/ 626*0Sstevel@tonic-gate /* FUNCTION : cwd_beenhere */ 627*0Sstevel@tonic-gate /* PURPOSE : Return 1 if the user has already visited this directory */ 628*0Sstevel@tonic-gate /* via C_WD. */ 629*0Sstevel@tonic-gate /* ARGUMENTS : a power-of-two directory function code (README, MESSAGE) */ 630*0Sstevel@tonic-gate /*************************************************************************/ 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate int cwd_beenhere(int dircode) 633*0Sstevel@tonic-gate { 634*0Sstevel@tonic-gate struct dirlist { 635*0Sstevel@tonic-gate struct dirlist *next; 636*0Sstevel@tonic-gate int dircode; 637*0Sstevel@tonic-gate char dirname[1]; 638*0Sstevel@tonic-gate }; 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate static struct dirlist *head = NULL; 641*0Sstevel@tonic-gate struct dirlist *curptr; 642*0Sstevel@tonic-gate char cwd[MAXPATHLEN]; 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate (void) fb_realpath(".", cwd); 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate for (curptr = head; curptr != NULL; curptr = curptr->next) 647*0Sstevel@tonic-gate if (strcmp(curptr->dirname, cwd) == 0) { 648*0Sstevel@tonic-gate if (!(curptr->dircode & dircode)) { 649*0Sstevel@tonic-gate curptr->dircode |= dircode; 650*0Sstevel@tonic-gate return (0); 651*0Sstevel@tonic-gate } 652*0Sstevel@tonic-gate return (1); 653*0Sstevel@tonic-gate } 654*0Sstevel@tonic-gate curptr = (struct dirlist *) malloc(strlen(cwd) + 1 + sizeof(struct dirlist)); 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate if (curptr != NULL) { 657*0Sstevel@tonic-gate curptr->next = head; 658*0Sstevel@tonic-gate head = curptr; 659*0Sstevel@tonic-gate curptr->dircode = dircode; 660*0Sstevel@tonic-gate strcpy(curptr->dirname, cwd); 661*0Sstevel@tonic-gate } 662*0Sstevel@tonic-gate return (0); 663*0Sstevel@tonic-gate } 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate /*************************************************************************/ 666*0Sstevel@tonic-gate /* FUNCTION : show_banner */ 667*0Sstevel@tonic-gate /* PURPOSE : Display a banner on the user's terminal before login */ 668*0Sstevel@tonic-gate /* ARGUMENTS : reply code to use */ 669*0Sstevel@tonic-gate /*************************************************************************/ 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate void show_banner(int msgcode) 672*0Sstevel@tonic-gate { 673*0Sstevel@tonic-gate char *crptr, linebuf[1024], outbuf[1024]; 674*0Sstevel@tonic-gate struct aclmember *entry = NULL; 675*0Sstevel@tonic-gate FILE *infile; 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate #ifdef VIRTUAL 678*0Sstevel@tonic-gate extern int virtual_mode; 679*0Sstevel@tonic-gate extern int virtual_ftpaccess; 680*0Sstevel@tonic-gate extern char virtual_banner[]; 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate if (virtual_mode && !virtual_ftpaccess) { 683*0Sstevel@tonic-gate infile = fopen(virtual_banner, "r"); 684*0Sstevel@tonic-gate if (infile) { 685*0Sstevel@tonic-gate while (fgets(linebuf, sizeof(linebuf), infile) != NULL) { 686*0Sstevel@tonic-gate if ((crptr = strchr(linebuf, '\n')) != NULL) 687*0Sstevel@tonic-gate *crptr = '\0'; 688*0Sstevel@tonic-gate msg_massage(linebuf, outbuf, sizeof(outbuf)); 689*0Sstevel@tonic-gate lreply(msgcode, "%s", outbuf); 690*0Sstevel@tonic-gate } 691*0Sstevel@tonic-gate fclose(infile); 692*0Sstevel@tonic-gate #ifndef NO_SUCKING_NEWLINES 693*0Sstevel@tonic-gate lreply(msgcode, ""); 694*0Sstevel@tonic-gate #endif 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate else { 698*0Sstevel@tonic-gate #endif 699*0Sstevel@tonic-gate /* banner <path> */ 700*0Sstevel@tonic-gate while (getaclentry("banner", &entry)) { 701*0Sstevel@tonic-gate if (!ARG0) 702*0Sstevel@tonic-gate continue; 703*0Sstevel@tonic-gate infile = fopen(ARG0, "r"); 704*0Sstevel@tonic-gate if (infile) { 705*0Sstevel@tonic-gate while (fgets(linebuf, sizeof(linebuf), infile) != NULL) { 706*0Sstevel@tonic-gate if ((crptr = strchr(linebuf, '\n')) != NULL) 707*0Sstevel@tonic-gate *crptr = '\0'; 708*0Sstevel@tonic-gate msg_massage(linebuf, outbuf, sizeof(outbuf)); 709*0Sstevel@tonic-gate lreply(msgcode, "%s", outbuf); 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate fclose(infile); 712*0Sstevel@tonic-gate #ifndef NO_SUCKING_NEWLINES 713*0Sstevel@tonic-gate lreply(msgcode, ""); 714*0Sstevel@tonic-gate #endif 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate #ifdef VIRTUAL 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate #endif 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate /*************************************************************************/ 722*0Sstevel@tonic-gate /* FUNCTION : show_message */ 723*0Sstevel@tonic-gate /* PURPOSE : Display a message on the user's terminal if the current */ 724*0Sstevel@tonic-gate /* conditions are right */ 725*0Sstevel@tonic-gate /* ARGUMENTS : reply code to use, LOG_IN|CMD */ 726*0Sstevel@tonic-gate /*************************************************************************/ 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate void show_message(int msgcode, int mode) 729*0Sstevel@tonic-gate { 730*0Sstevel@tonic-gate char *crptr, linebuf[1024], outbuf[1024], class[MAXPATHLEN], cwd[MAXPATHLEN]; 731*0Sstevel@tonic-gate int show, which; 732*0Sstevel@tonic-gate struct aclmember *entry = NULL; 733*0Sstevel@tonic-gate FILE *infile; 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate if (mode == C_WD && cwd_beenhere(1) != 0) 736*0Sstevel@tonic-gate return; 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate #ifdef HAVE_GETCWD 739*0Sstevel@tonic-gate (void) getcwd(cwd, MAXPATHLEN - 1); 740*0Sstevel@tonic-gate #else 741*0Sstevel@tonic-gate (void) getwd(cwd); 742*0Sstevel@tonic-gate #endif 743*0Sstevel@tonic-gate (void) acl_getclass(class); 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate /* message <path> [<when> [<class>]] */ 746*0Sstevel@tonic-gate while (getaclentry("message", &entry)) { 747*0Sstevel@tonic-gate if (!ARG0) 748*0Sstevel@tonic-gate continue; 749*0Sstevel@tonic-gate show = 0; 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate if (mode == LOG_IN && (!ARG1 || !strcasecmp(ARG1, "login"))) 752*0Sstevel@tonic-gate if (!ARG2) 753*0Sstevel@tonic-gate show++; 754*0Sstevel@tonic-gate else { 755*0Sstevel@tonic-gate for (which = 2; (which < MAXARGS) && ARG[which]; which++) 756*0Sstevel@tonic-gate if (strcasecmp(class, ARG[which]) == 0) 757*0Sstevel@tonic-gate show++; 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate if (mode == C_WD && ARG1 && !strncasecmp(ARG1, "cwd=", 4) && 760*0Sstevel@tonic-gate (!strcmp((ARG1) + 4, cwd) || *(ARG1 + 4) == '*' || 761*0Sstevel@tonic-gate !wu_fnmatch((ARG1) + 4, cwd, FNM_PATHNAME))) 762*0Sstevel@tonic-gate if (!ARG2) 763*0Sstevel@tonic-gate show++; 764*0Sstevel@tonic-gate else { 765*0Sstevel@tonic-gate for (which = 2; (which < MAXARGS) && ARG[which]; which++) 766*0Sstevel@tonic-gate if (strcasecmp(class, ARG[which]) == 0) 767*0Sstevel@tonic-gate show++; 768*0Sstevel@tonic-gate } 769*0Sstevel@tonic-gate if (show && (int) strlen(ARG0) > 0) { 770*0Sstevel@tonic-gate infile = fopen(ARG0, "r"); 771*0Sstevel@tonic-gate if (infile) { 772*0Sstevel@tonic-gate while (fgets(linebuf, sizeof(linebuf), infile) != NULL) { 773*0Sstevel@tonic-gate if ((crptr = strchr(linebuf, '\n')) != NULL) 774*0Sstevel@tonic-gate *crptr = '\0'; 775*0Sstevel@tonic-gate msg_massage(linebuf, outbuf, sizeof(outbuf)); 776*0Sstevel@tonic-gate lreply(msgcode, "%s", outbuf); 777*0Sstevel@tonic-gate } 778*0Sstevel@tonic-gate fclose(infile); 779*0Sstevel@tonic-gate #ifndef NO_SUCKING_NEWLINES 780*0Sstevel@tonic-gate lreply(msgcode, ""); 781*0Sstevel@tonic-gate #endif 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate } 784*0Sstevel@tonic-gate } 785*0Sstevel@tonic-gate } 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate /*************************************************************************/ 788*0Sstevel@tonic-gate /* FUNCTION : show_readme */ 789*0Sstevel@tonic-gate /* PURPOSE : Display a message about a README file to the user if the */ 790*0Sstevel@tonic-gate /* current conditions are right */ 791*0Sstevel@tonic-gate /* ARGUMENTS : pointer to ACL buffer, reply code, LOG_IN|C_WD */ 792*0Sstevel@tonic-gate /*************************************************************************/ 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate void show_readme(int code, int mode) 795*0Sstevel@tonic-gate { 796*0Sstevel@tonic-gate char **filelist, **sfilelist, class[MAXPATHLEN], cwd[MAXPATHLEN]; 797*0Sstevel@tonic-gate int show, which, days; 798*0Sstevel@tonic-gate time_t clock; 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate struct stat buf; 801*0Sstevel@tonic-gate struct tm *tp; 802*0Sstevel@tonic-gate struct aclmember *entry = NULL; 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate if (cwd_beenhere(2) != 0) 805*0Sstevel@tonic-gate return; 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate #ifdef HAVE_GETCWD 808*0Sstevel@tonic-gate (void) getcwd(cwd, MAXPATHLEN - 1); 809*0Sstevel@tonic-gate #else 810*0Sstevel@tonic-gate (void) getwd(cwd); 811*0Sstevel@tonic-gate #endif 812*0Sstevel@tonic-gate (void) acl_getclass(class); 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate /* readme <path> {<when>} */ 815*0Sstevel@tonic-gate while (getaclentry("readme", &entry)) { 816*0Sstevel@tonic-gate if (!ARG0) 817*0Sstevel@tonic-gate continue; 818*0Sstevel@tonic-gate show = 0; 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate if (mode == LOG_IN && (!ARG1 || !strcasecmp(ARG1, "login"))) 821*0Sstevel@tonic-gate if (!ARG2) 822*0Sstevel@tonic-gate show++; 823*0Sstevel@tonic-gate else { 824*0Sstevel@tonic-gate for (which = 2; (which < MAXARGS) && ARG[which]; which++) 825*0Sstevel@tonic-gate if (strcasecmp(class, ARG[which]) == 0) 826*0Sstevel@tonic-gate show++; 827*0Sstevel@tonic-gate } 828*0Sstevel@tonic-gate if (mode == C_WD && ARG1 && !strncasecmp(ARG1, "cwd=", 4) 829*0Sstevel@tonic-gate && (!strcmp((ARG1) + 4, cwd) || *(ARG1 + 4) == '*' || 830*0Sstevel@tonic-gate !wu_fnmatch((ARG1) + 4, cwd, FNM_PATHNAME))) 831*0Sstevel@tonic-gate if (!ARG2) 832*0Sstevel@tonic-gate show++; 833*0Sstevel@tonic-gate else { 834*0Sstevel@tonic-gate for (which = 2; (which < MAXARGS) && ARG[which]; which++) 835*0Sstevel@tonic-gate if (strcasecmp(class, ARG[which]) == 0) 836*0Sstevel@tonic-gate show++; 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate if (show) { 839*0Sstevel@tonic-gate globerr = NULL; 840*0Sstevel@tonic-gate filelist = ftpglob(ARG0); 841*0Sstevel@tonic-gate sfilelist = filelist; /* save to free later */ 842*0Sstevel@tonic-gate if (!globerr) { 843*0Sstevel@tonic-gate while (filelist && *filelist) { 844*0Sstevel@tonic-gate errno = 0; 845*0Sstevel@tonic-gate if (!stat(*filelist, &buf) && 846*0Sstevel@tonic-gate (buf.st_mode & S_IFMT) == S_IFREG) { 847*0Sstevel@tonic-gate lreply(code, "Please read the file %s", *filelist); 848*0Sstevel@tonic-gate (void) time(&clock); 849*0Sstevel@tonic-gate tp = localtime(&clock); 850*0Sstevel@tonic-gate days = 365 * tp->tm_year + tp->tm_yday; 851*0Sstevel@tonic-gate tp = localtime((time_t *) & buf.st_mtime); 852*0Sstevel@tonic-gate days -= 365 * tp->tm_year + tp->tm_yday; 853*0Sstevel@tonic-gate /* 854*0Sstevel@tonic-gate if (days == 0) { 855*0Sstevel@tonic-gate lreply(code, " it was last modified on %.24s - Today", 856*0Sstevel@tonic-gate ctime((time_t *)&buf.st_mtime)); 857*0Sstevel@tonic-gate } else { 858*0Sstevel@tonic-gate */ 859*0Sstevel@tonic-gate lreply(code, 860*0Sstevel@tonic-gate " it was last modified on %.24s - %d day%s ago", 861*0Sstevel@tonic-gate ctime((time_t *) & buf.st_mtime), days, days == 1 ? "" : "s"); 862*0Sstevel@tonic-gate /* 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate */ 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate filelist++; 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate } 869*0Sstevel@tonic-gate if (sfilelist) { 870*0Sstevel@tonic-gate blkfree(sfilelist); 871*0Sstevel@tonic-gate free((char *) sfilelist); 872*0Sstevel@tonic-gate } 873*0Sstevel@tonic-gate } 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate } 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate /*************************************************************************/ 878*0Sstevel@tonic-gate /* FUNCTION : deny_badxfertype */ 879*0Sstevel@tonic-gate /* PURPOSE : If user is in ASCII transfer mode and tries to retrieve a */ 880*0Sstevel@tonic-gate /* binary file, abort transfer and display appropriate error */ 881*0Sstevel@tonic-gate /* ARGUMENTS : message code to use for denial, path of file to check for */ 882*0Sstevel@tonic-gate /* binary contents or NULL to assume binary file */ 883*0Sstevel@tonic-gate /*************************************************************************/ 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate int deny_badasciixfer(int msgcode, char *filepath) 886*0Sstevel@tonic-gate { 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate if (type == TYPE_A && !*filepath) { 889*0Sstevel@tonic-gate reply(msgcode, "This is a BINARY file, using ASCII mode to transfer will corrupt it."); 890*0Sstevel@tonic-gate return (1); 891*0Sstevel@tonic-gate } 892*0Sstevel@tonic-gate /* The hooks are here to prevent transfers of actual binary files, not 893*0Sstevel@tonic-gate * just TAR or COMPRESS mode files... */ 894*0Sstevel@tonic-gate return (0); 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate /*************************************************************************/ 898*0Sstevel@tonic-gate /* FUNCTION : is_shutdown */ 899*0Sstevel@tonic-gate /* PURPOSE : Check to see if the server is shutting down, if it is */ 900*0Sstevel@tonic-gate /* arrange for the shutdown message to be sent in the next */ 901*0Sstevel@tonic-gate /* reply to the user */ 902*0Sstevel@tonic-gate /* ARGUMENTS : whether to arrange for a shutdown message to be sent, new */ 903*0Sstevel@tonic-gate /* or existing connection */ 904*0Sstevel@tonic-gate /* RETURNS : 1 if shutting down, 0 if not */ 905*0Sstevel@tonic-gate /*************************************************************************/ 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate int is_shutdown(int quiet, int new) 908*0Sstevel@tonic-gate { 909*0Sstevel@tonic-gate static struct tm tmbuf; 910*0Sstevel@tonic-gate static struct stat s_last; 911*0Sstevel@tonic-gate static time_t last = 0, shut, deny, disc; 912*0Sstevel@tonic-gate static int valid; 913*0Sstevel@tonic-gate static char text[2048]; 914*0Sstevel@tonic-gate struct stat s_cur; 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate extern char *autospout, Shutdown[]; 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate FILE *fp; 919*0Sstevel@tonic-gate 920*0Sstevel@tonic-gate int deny_off, disc_off; 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate time_t curtime = time(NULL); 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate char buf[1024], linebuf[1024]; 925*0Sstevel@tonic-gate 926*0Sstevel@tonic-gate if (Shutdown[0] == '\0' || stat(Shutdown, &s_cur)) 927*0Sstevel@tonic-gate return (0); 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate if (s_last.st_mtime != s_cur.st_mtime) { 930*0Sstevel@tonic-gate valid = 0; 931*0Sstevel@tonic-gate 932*0Sstevel@tonic-gate fp = fopen(Shutdown, "r"); 933*0Sstevel@tonic-gate if (fp == NULL) 934*0Sstevel@tonic-gate return (0); 935*0Sstevel@tonic-gate s_last = s_cur; 936*0Sstevel@tonic-gate fgets(buf, sizeof(buf), fp); 937*0Sstevel@tonic-gate if (sscanf(buf, "%d %d %d %d %d %ld %ld", &tmbuf.tm_year, &tmbuf.tm_mon, 938*0Sstevel@tonic-gate &tmbuf.tm_mday, &tmbuf.tm_hour, &tmbuf.tm_min, &deny, &disc) != 7) { 939*0Sstevel@tonic-gate (void) fclose(fp); 940*0Sstevel@tonic-gate return (0); 941*0Sstevel@tonic-gate } 942*0Sstevel@tonic-gate valid = 1; 943*0Sstevel@tonic-gate deny_off = 3600 * (deny / 100) + 60 * (deny % 100); 944*0Sstevel@tonic-gate disc_off = 3600 * (disc / 100) + 60 * (disc % 100); 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate tmbuf.tm_year -= 1900; 947*0Sstevel@tonic-gate tmbuf.tm_isdst = -1; 948*0Sstevel@tonic-gate shut = mktime(&tmbuf); 949*0Sstevel@tonic-gate strcpy(shuttime, ctime(&shut)); 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate disc = shut - disc_off; 952*0Sstevel@tonic-gate strcpy(disctime, ctime(&disc)); 953*0Sstevel@tonic-gate 954*0Sstevel@tonic-gate deny = shut - deny_off; 955*0Sstevel@tonic-gate strcpy(denytime, ctime(&deny)); 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate text[0] = '\0'; 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate while (fgets(buf, sizeof(buf), fp) != NULL) { 960*0Sstevel@tonic-gate msg_massage(buf, linebuf, sizeof(linebuf)); 961*0Sstevel@tonic-gate if ((strlen(text) + strlen(linebuf)) < sizeof(text)) 962*0Sstevel@tonic-gate strcat(text, linebuf); 963*0Sstevel@tonic-gate } 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate (void) fclose(fp); 966*0Sstevel@tonic-gate } 967*0Sstevel@tonic-gate if (!valid) 968*0Sstevel@tonic-gate return (0); 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate /* if last == 0, then is_shutdown() only called with quiet == 1 so far */ 971*0Sstevel@tonic-gate if (last == 0 && !quiet) { 972*0Sstevel@tonic-gate autospout = text; /* warn them for the first time */ 973*0Sstevel@tonic-gate autospout_free = 0; 974*0Sstevel@tonic-gate last = curtime; 975*0Sstevel@tonic-gate } 976*0Sstevel@tonic-gate /* if a new connection and past deny time, tell caller to drop 'em */ 977*0Sstevel@tonic-gate if (new && curtime > deny) 978*0Sstevel@tonic-gate return (1); 979*0Sstevel@tonic-gate 980*0Sstevel@tonic-gate /* if past disconnect time, tell caller to drop 'em */ 981*0Sstevel@tonic-gate if (curtime > disc) 982*0Sstevel@tonic-gate return (1); 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate /* if less than 60 seconds to disconnection, warn 'em continuously */ 985*0Sstevel@tonic-gate if (curtime > (disc - 60) && !quiet) { 986*0Sstevel@tonic-gate autospout = text; 987*0Sstevel@tonic-gate autospout_free = 0; 988*0Sstevel@tonic-gate last = curtime; 989*0Sstevel@tonic-gate } 990*0Sstevel@tonic-gate /* if less than 15 minutes to disconnection, warn 'em every 5 mins */ 991*0Sstevel@tonic-gate if (curtime > (disc - 60 * 15)) { 992*0Sstevel@tonic-gate if ((curtime - last) > (60 * 5) && !quiet) { 993*0Sstevel@tonic-gate autospout = text; 994*0Sstevel@tonic-gate autospout_free = 0; 995*0Sstevel@tonic-gate last = curtime; 996*0Sstevel@tonic-gate } 997*0Sstevel@tonic-gate } 998*0Sstevel@tonic-gate /* if less than 24 hours to disconnection, warn 'em every 30 mins */ 999*0Sstevel@tonic-gate if (curtime < (disc - 24 * 60 * 60) && !quiet) { 1000*0Sstevel@tonic-gate if ((curtime - last) > (60 * 30)) { 1001*0Sstevel@tonic-gate autospout = text; 1002*0Sstevel@tonic-gate autospout_free = 0; 1003*0Sstevel@tonic-gate last = curtime; 1004*0Sstevel@tonic-gate } 1005*0Sstevel@tonic-gate } 1006*0Sstevel@tonic-gate /* if more than 24 hours to disconnection, warn 'em every 60 mins */ 1007*0Sstevel@tonic-gate if (curtime > (disc - 24 * 60 * 60) && !quiet) { 1008*0Sstevel@tonic-gate if ((curtime - last) >= (24 * 60 * 60)) { 1009*0Sstevel@tonic-gate autospout = text; 1010*0Sstevel@tonic-gate autospout_free = 0; 1011*0Sstevel@tonic-gate last = curtime; 1012*0Sstevel@tonic-gate } 1013*0Sstevel@tonic-gate } 1014*0Sstevel@tonic-gate return (0); 1015*0Sstevel@tonic-gate } 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate #ifdef SITE_NEWER 1018*0Sstevel@tonic-gate void newer(char *date, char *path, int showlots) 1019*0Sstevel@tonic-gate { 1020*0Sstevel@tonic-gate struct tm tm; 1021*0Sstevel@tonic-gate 1022*0Sstevel@tonic-gate if (sscanf(date, "%04d%02d%02d%02d%02d%02d", 1023*0Sstevel@tonic-gate &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 1024*0Sstevel@tonic-gate &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) { 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate tm.tm_year -= 1900; 1027*0Sstevel@tonic-gate tm.tm_mon--; 1028*0Sstevel@tonic-gate tm.tm_isdst = -1; 1029*0Sstevel@tonic-gate newer_time = mktime(&tm); 1030*0Sstevel@tonic-gate dout = dataconn("file list", (off_t) - 1, "w"); 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate if (dout != NULL) { 1033*0Sstevel@tonic-gate /* As ftw allocates storage it needs a chance to cleanup, setting 1034*0Sstevel@tonic-gate * ftwflag prevents myoob from calling longjmp, incrementing 1035*0Sstevel@tonic-gate * ftwflag instead which causes check_newer to return non-zero 1036*0Sstevel@tonic-gate * which makes ftw return. */ 1037*0Sstevel@tonic-gate ftwflag = 1; 1038*0Sstevel@tonic-gate transflag++; 1039*0Sstevel@tonic-gate show_fullinfo = showlots; 1040*0Sstevel@tonic-gate #if defined(HAVE_FTW) 1041*0Sstevel@tonic-gate ftw(path, check_newer, -1); 1042*0Sstevel@tonic-gate #else 1043*0Sstevel@tonic-gate treewalk(path, check_newer, -1, NULL); 1044*0Sstevel@tonic-gate #endif 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate /* don't send a reply if myoob has already replied */ 1047*0Sstevel@tonic-gate if (ftwflag == 1) { 1048*0Sstevel@tonic-gate if (ferror(dout) != 0) 1049*0Sstevel@tonic-gate perror_reply(550, "Data connection"); 1050*0Sstevel@tonic-gate else 1051*0Sstevel@tonic-gate reply(226, "Transfer complete."); 1052*0Sstevel@tonic-gate } 1053*0Sstevel@tonic-gate 1054*0Sstevel@tonic-gate (void) fclose(dout); 1055*0Sstevel@tonic-gate data = -1; 1056*0Sstevel@tonic-gate pdata = -1; 1057*0Sstevel@tonic-gate transflag = 0; 1058*0Sstevel@tonic-gate ftwflag = 0; 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate } 1061*0Sstevel@tonic-gate else 1062*0Sstevel@tonic-gate reply(501, "Bad DATE format"); 1063*0Sstevel@tonic-gate } 1064*0Sstevel@tonic-gate #endif 1065*0Sstevel@tonic-gate 1066*0Sstevel@tonic-gate int type_match(char *typelist) 1067*0Sstevel@tonic-gate { 1068*0Sstevel@tonic-gate char *start, *p; 1069*0Sstevel@tonic-gate int len; 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate if (typelist == NULL) 1072*0Sstevel@tonic-gate return (0); 1073*0Sstevel@tonic-gate 1074*0Sstevel@tonic-gate for (p = start = typelist; *start != '\0'; start = p) { 1075*0Sstevel@tonic-gate while (*p != '\0' && *p != ',') 1076*0Sstevel@tonic-gate p++; 1077*0Sstevel@tonic-gate len = p - start; 1078*0Sstevel@tonic-gate if (*p != '\0') 1079*0Sstevel@tonic-gate p++; 1080*0Sstevel@tonic-gate if (len == 9 && anonymous && strncasecmp(start, "anonymous", 9) == 0) 1081*0Sstevel@tonic-gate return (1); 1082*0Sstevel@tonic-gate if (len == 5 && guest && strncasecmp(start, "guest", 5) == 0) 1083*0Sstevel@tonic-gate return (1); 1084*0Sstevel@tonic-gate if (len == 4 && !guest && !anonymous && 1085*0Sstevel@tonic-gate strncasecmp(start, "real", 4) == 0) 1086*0Sstevel@tonic-gate return (1); 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate if (len > 6 && strncasecmp(start, "class=", 6) == 0) { 1089*0Sstevel@tonic-gate char class[1024]; 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate if ((acl_getclass(class) == 1) && (strlen(class) == len - 6) && 1092*0Sstevel@tonic-gate (strncasecmp(start + 6, class, len - 6) == 0)) 1093*0Sstevel@tonic-gate return (1); 1094*0Sstevel@tonic-gate } 1095*0Sstevel@tonic-gate } 1096*0Sstevel@tonic-gate return (0); 1097*0Sstevel@tonic-gate } 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate int path_compare(char *p1, char *p2) 1100*0Sstevel@tonic-gate { 1101*0Sstevel@tonic-gate if ((strcmp(p1, "*") == 0) || (wu_fnmatch(p1, p2, FNM_PATHNAME) == 0)) /* 0 means they matched */ 1102*0Sstevel@tonic-gate return (strlen(p1)); 1103*0Sstevel@tonic-gate else 1104*0Sstevel@tonic-gate return (-2); 1105*0Sstevel@tonic-gate } 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate void expand_id(void) 1108*0Sstevel@tonic-gate { 1109*0Sstevel@tonic-gate char class[1024]; 1110*0Sstevel@tonic-gate struct aclmember *entry = NULL; 1111*0Sstevel@tonic-gate (void) acl_getclass(class); 1112*0Sstevel@tonic-gate while (getaclentry("upload", &entry)) { 1113*0Sstevel@tonic-gate char *q; 1114*0Sstevel@tonic-gate int i = 0; 1115*0Sstevel@tonic-gate int options = 1; 1116*0Sstevel@tonic-gate int classfound = 0; 1117*0Sstevel@tonic-gate int classmatched = 0; 1118*0Sstevel@tonic-gate while (options 1119*0Sstevel@tonic-gate && (i < MAXARGS) 1120*0Sstevel@tonic-gate && ((q = entry->arg[i]) != (char *) NULL) 1121*0Sstevel@tonic-gate && (q[0] != '\0')) { 1122*0Sstevel@tonic-gate if (strcasecmp(q, "absolute") == 0) 1123*0Sstevel@tonic-gate i++; 1124*0Sstevel@tonic-gate else if (strcasecmp(q, "relative") == 0) 1125*0Sstevel@tonic-gate i++; 1126*0Sstevel@tonic-gate else if (strncasecmp(q, "class=", 6) == 0) { 1127*0Sstevel@tonic-gate i++; 1128*0Sstevel@tonic-gate classfound = 1; 1129*0Sstevel@tonic-gate if (strcasecmp(q + 6, class) == 0) 1130*0Sstevel@tonic-gate classmatched = 1; 1131*0Sstevel@tonic-gate } 1132*0Sstevel@tonic-gate else if (strcmp(q, "-") == 0) { 1133*0Sstevel@tonic-gate i++; 1134*0Sstevel@tonic-gate options = 0; 1135*0Sstevel@tonic-gate } 1136*0Sstevel@tonic-gate else 1137*0Sstevel@tonic-gate options = 0; 1138*0Sstevel@tonic-gate } 1139*0Sstevel@tonic-gate if (!classfound || classmatched) { 1140*0Sstevel@tonic-gate char buf[BUFSIZ]; 1141*0Sstevel@tonic-gate /* 1142*0Sstevel@tonic-gate * UID 1143*0Sstevel@tonic-gate */ 1144*0Sstevel@tonic-gate if (((i + 3) < MAXARGS) 1145*0Sstevel@tonic-gate && ((q = entry->arg[i + 3]) != (char *) NULL) 1146*0Sstevel@tonic-gate && (q[0] != '\0') 1147*0Sstevel@tonic-gate && (strcmp(q, "*") != 0)) { 1148*0Sstevel@tonic-gate if (q[0] == '%') 1149*0Sstevel@tonic-gate sprintf(buf, "%s", q + 1); 1150*0Sstevel@tonic-gate else { 1151*0Sstevel@tonic-gate struct passwd *pwent = getpwnam(q); 1152*0Sstevel@tonic-gate if (pwent) 1153*0Sstevel@tonic-gate sprintf(buf, "%" PW_UID_FORMAT, pwent->pw_uid); 1154*0Sstevel@tonic-gate else 1155*0Sstevel@tonic-gate sprintf(buf, "%d", 0); 1156*0Sstevel@tonic-gate } 1157*0Sstevel@tonic-gate entry->arg[i + 3] = (char *) malloc(strlen(buf) + 1); 1158*0Sstevel@tonic-gate if (entry->arg[i + 3] == NULL) { 1159*0Sstevel@tonic-gate syslog(LOG_ERR, "calloc error in expand_id"); 1160*0Sstevel@tonic-gate dologout(1); 1161*0Sstevel@tonic-gate } 1162*0Sstevel@tonic-gate strcpy(entry->arg[i + 3], buf); 1163*0Sstevel@tonic-gate } 1164*0Sstevel@tonic-gate /* 1165*0Sstevel@tonic-gate * GID 1166*0Sstevel@tonic-gate */ 1167*0Sstevel@tonic-gate if (((i + 4) < MAXARGS) 1168*0Sstevel@tonic-gate && ((q = entry->arg[i + 4]) != (char *) NULL) 1169*0Sstevel@tonic-gate && (q[0] != '\0') 1170*0Sstevel@tonic-gate && (strcmp(q, "*") != 0)) { 1171*0Sstevel@tonic-gate if (q[0] == '%') 1172*0Sstevel@tonic-gate sprintf(buf, "%s", q + 1); 1173*0Sstevel@tonic-gate else { 1174*0Sstevel@tonic-gate struct group *grent = getgrnam(q); 1175*0Sstevel@tonic-gate if (grent) 1176*0Sstevel@tonic-gate sprintf(buf, "%" GR_GID_FORMAT, grent->gr_gid); 1177*0Sstevel@tonic-gate else 1178*0Sstevel@tonic-gate sprintf(buf, "%d", 0); 1179*0Sstevel@tonic-gate endgrent(); 1180*0Sstevel@tonic-gate } 1181*0Sstevel@tonic-gate entry->arg[i + 4] = (char *) malloc(strlen(buf) + 1); 1182*0Sstevel@tonic-gate if (entry->arg[i + 4] == NULL) { 1183*0Sstevel@tonic-gate syslog(LOG_ERR, "calloc error in expand_id"); 1184*0Sstevel@tonic-gate dologout(1); 1185*0Sstevel@tonic-gate } 1186*0Sstevel@tonic-gate strcpy(entry->arg[i + 4], buf); 1187*0Sstevel@tonic-gate } 1188*0Sstevel@tonic-gate } 1189*0Sstevel@tonic-gate } 1190*0Sstevel@tonic-gate } 1191*0Sstevel@tonic-gate 1192*0Sstevel@tonic-gate int fn_check(char *name) 1193*0Sstevel@tonic-gate { 1194*0Sstevel@tonic-gate /* check to see if this is a valid file name... path-filter <type> 1195*0Sstevel@tonic-gate * <message_file> <allowed_charset> <disallowed> */ 1196*0Sstevel@tonic-gate 1197*0Sstevel@tonic-gate struct aclmember *entry = NULL; 1198*0Sstevel@tonic-gate int j; 1199*0Sstevel@tonic-gate char *path; 1200*0Sstevel@tonic-gate #if ! defined(HAVE_REGEXEC) 1201*0Sstevel@tonic-gate char *sp; 1202*0Sstevel@tonic-gate #endif 1203*0Sstevel@tonic-gate 1204*0Sstevel@tonic-gate #ifdef M_UNIX 1205*0Sstevel@tonic-gate #ifdef HAVE_REGEX 1206*0Sstevel@tonic-gate char *regp; 1207*0Sstevel@tonic-gate #endif 1208*0Sstevel@tonic-gate #endif 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate #ifdef HAVE_REGEXEC 1211*0Sstevel@tonic-gate regex_t regexbuf; 1212*0Sstevel@tonic-gate regmatch_t regmatchbuf; 1213*0Sstevel@tonic-gate int rval; 1214*0Sstevel@tonic-gate #endif 1215*0Sstevel@tonic-gate 1216*0Sstevel@tonic-gate #ifdef LINUX 1217*0Sstevel@tonic-gate re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; 1218*0Sstevel@tonic-gate #endif 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate while (getaclentry("path-filter", &entry) && ARG0 != NULL) { 1221*0Sstevel@tonic-gate if (type_match(ARG0) && ARG1 && ARG2) { 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate /* 1224*0Sstevel@tonic-gate * check *only* the basename 1225*0Sstevel@tonic-gate */ 1226*0Sstevel@tonic-gate 1227*0Sstevel@tonic-gate if ((path = strrchr(name, '/'))) 1228*0Sstevel@tonic-gate ++path; 1229*0Sstevel@tonic-gate else 1230*0Sstevel@tonic-gate path = name; 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate /* is it in the allowed character set? */ 1233*0Sstevel@tonic-gate #if defined(HAVE_REGEXEC) 1234*0Sstevel@tonic-gate if (regcomp(®exbuf, ARG2, REG_EXTENDED) != 0) { 1235*0Sstevel@tonic-gate reply(550, "HAVE_REGEX error"); 1236*0Sstevel@tonic-gate #elif defined(HAVE_REGEX) 1237*0Sstevel@tonic-gate if ((sp = regcmp(ARG2, (char *) 0)) == NULL) { 1238*0Sstevel@tonic-gate reply(550, "HAVE_REGEX error"); 1239*0Sstevel@tonic-gate #else 1240*0Sstevel@tonic-gate if ((sp = re_comp(ARG2)) != 0) { 1241*0Sstevel@tonic-gate perror_reply(550, sp); 1242*0Sstevel@tonic-gate #endif 1243*0Sstevel@tonic-gate return (0); 1244*0Sstevel@tonic-gate } 1245*0Sstevel@tonic-gate #if defined(HAVE_REGEXEC) 1246*0Sstevel@tonic-gate rval = regexec(®exbuf, path, 1, ®matchbuf, 0); 1247*0Sstevel@tonic-gate regfree(®exbuf); 1248*0Sstevel@tonic-gate if (rval != 0) { 1249*0Sstevel@tonic-gate #elif defined(HAVE_REGEX) 1250*0Sstevel@tonic-gate #ifdef M_UNIX 1251*0Sstevel@tonic-gate regp = regex(sp, path); 1252*0Sstevel@tonic-gate free(sp); 1253*0Sstevel@tonic-gate if (regp == NULL) { 1254*0Sstevel@tonic-gate #else 1255*0Sstevel@tonic-gate if ((regex(sp, path)) == NULL) { 1256*0Sstevel@tonic-gate #endif 1257*0Sstevel@tonic-gate #else 1258*0Sstevel@tonic-gate if ((re_exec(path)) != 1) { 1259*0Sstevel@tonic-gate #endif 1260*0Sstevel@tonic-gate pr_mesg(550, ARG1); 1261*0Sstevel@tonic-gate reply(550, "%s: Permission denied on server. (Filename (accept))", name); 1262*0Sstevel@tonic-gate return (0); 1263*0Sstevel@tonic-gate } 1264*0Sstevel@tonic-gate /* is it in any of the disallowed regexps */ 1265*0Sstevel@tonic-gate 1266*0Sstevel@tonic-gate for (j = 3; j < MAXARGS; ++j) { 1267*0Sstevel@tonic-gate /* ARGj == entry->arg[j] */ 1268*0Sstevel@tonic-gate if (entry->arg[j]) { 1269*0Sstevel@tonic-gate #if defined(HAVE_REGEXEC) 1270*0Sstevel@tonic-gate if (regcomp(®exbuf, entry->arg[j], REG_EXTENDED) != 0) { 1271*0Sstevel@tonic-gate reply(550, "HAVE_REGEX error"); 1272*0Sstevel@tonic-gate #elif defined(HAVE_REGEX) 1273*0Sstevel@tonic-gate if ((sp = regcmp(entry->arg[j], (char *) 0)) == NULL) { 1274*0Sstevel@tonic-gate reply(550, "HAVE_REGEX error"); 1275*0Sstevel@tonic-gate #else 1276*0Sstevel@tonic-gate if ((sp = re_comp(entry->arg[j])) != 0) { 1277*0Sstevel@tonic-gate perror_reply(550, sp); 1278*0Sstevel@tonic-gate #endif 1279*0Sstevel@tonic-gate return (0); 1280*0Sstevel@tonic-gate } 1281*0Sstevel@tonic-gate #if defined(HAVE_REGEXEC) 1282*0Sstevel@tonic-gate rval = regexec(®exbuf, path, 1, ®matchbuf, 0); 1283*0Sstevel@tonic-gate regfree(®exbuf); 1284*0Sstevel@tonic-gate if (rval == 0) { 1285*0Sstevel@tonic-gate #elif defined(HAVE_REGEX) 1286*0Sstevel@tonic-gate #ifdef M_UNIX 1287*0Sstevel@tonic-gate regp = regex(sp, path); 1288*0Sstevel@tonic-gate free(sp); 1289*0Sstevel@tonic-gate if (regp != NULL) { 1290*0Sstevel@tonic-gate #else 1291*0Sstevel@tonic-gate if ((regex(sp, path)) != NULL) { 1292*0Sstevel@tonic-gate #endif 1293*0Sstevel@tonic-gate #else 1294*0Sstevel@tonic-gate if ((re_exec(path)) == 1) { 1295*0Sstevel@tonic-gate #endif 1296*0Sstevel@tonic-gate pr_mesg(550, ARG1); 1297*0Sstevel@tonic-gate reply(550, "%s: Permission denied on server. (Filename (deny))", name); 1298*0Sstevel@tonic-gate return (0); 1299*0Sstevel@tonic-gate } 1300*0Sstevel@tonic-gate } 1301*0Sstevel@tonic-gate } 1302*0Sstevel@tonic-gate } 1303*0Sstevel@tonic-gate } 1304*0Sstevel@tonic-gate return (1); 1305*0Sstevel@tonic-gate } 1306*0Sstevel@tonic-gate 1307*0Sstevel@tonic-gate int dir_check(char *name, uid_t * uid, gid_t * gid, int *d_mode, int *valid) 1308*0Sstevel@tonic-gate { 1309*0Sstevel@tonic-gate struct aclmember *entry = NULL; 1310*0Sstevel@tonic-gate int match_value = -1; 1311*0Sstevel@tonic-gate char *ap2 = NULL; 1312*0Sstevel@tonic-gate char *ap3 = NULL; 1313*0Sstevel@tonic-gate char *ap4 = NULL; 1314*0Sstevel@tonic-gate char *ap5 = NULL; 1315*0Sstevel@tonic-gate char *ap6 = NULL; 1316*0Sstevel@tonic-gate char *ap7 = NULL; 1317*0Sstevel@tonic-gate char cwdir[MAXPATHLEN]; 1318*0Sstevel@tonic-gate char *pwdir; 1319*0Sstevel@tonic-gate char abspwdir[MAXPATHLEN]; 1320*0Sstevel@tonic-gate char relpwdir[MAXPATHLEN]; 1321*0Sstevel@tonic-gate char path[MAXPATHLEN]; 1322*0Sstevel@tonic-gate char *sp; 1323*0Sstevel@tonic-gate struct stat stbuf; 1324*0Sstevel@tonic-gate int stat_result = -1; 1325*0Sstevel@tonic-gate char class[1024]; 1326*0Sstevel@tonic-gate extern char *home; 1327*0Sstevel@tonic-gate 1328*0Sstevel@tonic-gate (void) acl_getclass(class); 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate *valid = 0; 1331*0Sstevel@tonic-gate /* what's our current directory? */ 1332*0Sstevel@tonic-gate 1333*0Sstevel@tonic-gate /* XXX We could use dynamic RAM to store this path, but I'd rather just bail 1334*0Sstevel@tonic-gate out with an error. The rest of wu is so crufy that a long path might 1335*0Sstevel@tonic-gate just blow up later */ 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate if ((strlen(name) + 1) > sizeof(path)) { 1338*0Sstevel@tonic-gate perror_reply(550, "Path too long"); 1339*0Sstevel@tonic-gate return (-1); 1340*0Sstevel@tonic-gate } 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gate strcpy(path, name); 1343*0Sstevel@tonic-gate sp = strrchr(path, '/'); 1344*0Sstevel@tonic-gate if (sp) 1345*0Sstevel@tonic-gate *sp = '\0'; 1346*0Sstevel@tonic-gate else 1347*0Sstevel@tonic-gate strcpy(path, "."); 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate if ((fb_realpath(path, cwdir)) == NULL) { 1350*0Sstevel@tonic-gate perror_reply(550, "Could not determine cwdir"); 1351*0Sstevel@tonic-gate return (-1); 1352*0Sstevel@tonic-gate } 1353*0Sstevel@tonic-gate 1354*0Sstevel@tonic-gate if ((fb_realpath(home, relpwdir)) == NULL) { 1355*0Sstevel@tonic-gate perror_reply(550, "Could not determine pwdir"); 1356*0Sstevel@tonic-gate return (-1); 1357*0Sstevel@tonic-gate } 1358*0Sstevel@tonic-gate 1359*0Sstevel@tonic-gate if ((wu_realpath(home, abspwdir, chroot_path)) == NULL) { 1360*0Sstevel@tonic-gate perror_reply(550, "Could not determine pwdir"); 1361*0Sstevel@tonic-gate return (-1); 1362*0Sstevel@tonic-gate } 1363*0Sstevel@tonic-gate 1364*0Sstevel@tonic-gate while (getaclentry("upload", &entry)) { 1365*0Sstevel@tonic-gate char *q; 1366*0Sstevel@tonic-gate int i = 0; 1367*0Sstevel@tonic-gate int options = 1; 1368*0Sstevel@tonic-gate int classfound = 0; 1369*0Sstevel@tonic-gate int classmatched = 0; 1370*0Sstevel@tonic-gate pwdir = abspwdir; 1371*0Sstevel@tonic-gate while (options 1372*0Sstevel@tonic-gate && (i < MAXARGS) 1373*0Sstevel@tonic-gate && ((q = entry->arg[i]) != (char *) NULL) 1374*0Sstevel@tonic-gate && (q[0] != '\0')) { 1375*0Sstevel@tonic-gate if (strcasecmp(q, "absolute") == 0) { 1376*0Sstevel@tonic-gate i++; 1377*0Sstevel@tonic-gate pwdir = abspwdir; 1378*0Sstevel@tonic-gate } 1379*0Sstevel@tonic-gate else if (strcasecmp(q, "relative") == 0) { 1380*0Sstevel@tonic-gate i++; 1381*0Sstevel@tonic-gate pwdir = relpwdir; 1382*0Sstevel@tonic-gate } 1383*0Sstevel@tonic-gate else if (strncasecmp(q, "class=", 6) == 0) { 1384*0Sstevel@tonic-gate i++; 1385*0Sstevel@tonic-gate classfound = 1; 1386*0Sstevel@tonic-gate if (strcasecmp(q + 6, class) == 0) 1387*0Sstevel@tonic-gate classmatched = 1; 1388*0Sstevel@tonic-gate } 1389*0Sstevel@tonic-gate else if (strcmp(q, "-") == 0) { 1390*0Sstevel@tonic-gate i++; 1391*0Sstevel@tonic-gate options = 0; 1392*0Sstevel@tonic-gate } 1393*0Sstevel@tonic-gate else 1394*0Sstevel@tonic-gate options = 0; 1395*0Sstevel@tonic-gate } 1396*0Sstevel@tonic-gate if (!classfound || classmatched) { 1397*0Sstevel@tonic-gate int j; 1398*0Sstevel@tonic-gate if (((i + 1) < MAXARGS) 1399*0Sstevel@tonic-gate && ((q = entry->arg[i]) != (char *) NULL) 1400*0Sstevel@tonic-gate && (q[0] != '\0') 1401*0Sstevel@tonic-gate && (0 < path_compare(q, pwdir)) 1402*0Sstevel@tonic-gate && ((j = path_compare(entry->arg[i + 1], cwdir)) >= match_value)) { 1403*0Sstevel@tonic-gate match_value = j; 1404*0Sstevel@tonic-gate 1405*0Sstevel@tonic-gate ap2 = NULL; 1406*0Sstevel@tonic-gate if (((i + 2) < MAXARGS) 1407*0Sstevel@tonic-gate && ((q = entry->arg[i + 2]) != (char *) NULL) 1408*0Sstevel@tonic-gate && (q[0] != '\0')) 1409*0Sstevel@tonic-gate ap2 = q; 1410*0Sstevel@tonic-gate 1411*0Sstevel@tonic-gate ap3 = NULL; 1412*0Sstevel@tonic-gate if (((i + 3) < MAXARGS) 1413*0Sstevel@tonic-gate && ((q = entry->arg[i + 3]) != (char *) NULL) 1414*0Sstevel@tonic-gate && (q[0] != '\0')) 1415*0Sstevel@tonic-gate ap3 = q; 1416*0Sstevel@tonic-gate 1417*0Sstevel@tonic-gate ap4 = NULL; 1418*0Sstevel@tonic-gate if (((i + 4) < MAXARGS) 1419*0Sstevel@tonic-gate && ((q = entry->arg[i + 4]) != (char *) NULL) 1420*0Sstevel@tonic-gate && (q[0] != '\0')) 1421*0Sstevel@tonic-gate ap4 = q; 1422*0Sstevel@tonic-gate 1423*0Sstevel@tonic-gate ap5 = NULL; 1424*0Sstevel@tonic-gate if (((i + 5) < MAXARGS) 1425*0Sstevel@tonic-gate && ((q = entry->arg[i + 5]) != (char *) NULL) 1426*0Sstevel@tonic-gate && (q[0] != '\0')) 1427*0Sstevel@tonic-gate ap5 = q; 1428*0Sstevel@tonic-gate 1429*0Sstevel@tonic-gate ap6 = NULL; 1430*0Sstevel@tonic-gate if (((i + 6) < MAXARGS) 1431*0Sstevel@tonic-gate && ((q = entry->arg[i + 6]) != (char *) NULL) 1432*0Sstevel@tonic-gate && (q[0] != '\0')) 1433*0Sstevel@tonic-gate ap6 = q; 1434*0Sstevel@tonic-gate 1435*0Sstevel@tonic-gate ap7 = NULL; 1436*0Sstevel@tonic-gate if (((i + 7) < MAXARGS) 1437*0Sstevel@tonic-gate && ((q = entry->arg[i + 7]) != (char *) NULL) 1438*0Sstevel@tonic-gate && (q[0] != '\0')) 1439*0Sstevel@tonic-gate ap7 = q; 1440*0Sstevel@tonic-gate } 1441*0Sstevel@tonic-gate } 1442*0Sstevel@tonic-gate } 1443*0Sstevel@tonic-gate 1444*0Sstevel@tonic-gate if (anonymous && (match_value < 0)) { 1445*0Sstevel@tonic-gate reply(550, "%s: Permission denied on server. (Upload dirs)", name); 1446*0Sstevel@tonic-gate return (0); 1447*0Sstevel@tonic-gate } 1448*0Sstevel@tonic-gate if ((ap2 && !strcasecmp(ap2, "no")) 1449*0Sstevel@tonic-gate || (ap3 && !strcasecmp(ap3, "nodirs")) 1450*0Sstevel@tonic-gate || (ap6 && !strcasecmp(ap6, "nodirs"))) { 1451*0Sstevel@tonic-gate reply(550, "%s: Permission denied on server. (Upload dirs)", name); 1452*0Sstevel@tonic-gate return (0); 1453*0Sstevel@tonic-gate } 1454*0Sstevel@tonic-gate if ((ap3 && *ap3 == '*') || (ap4 && *ap4 == '*')) 1455*0Sstevel@tonic-gate stat_result = stat(path, &stbuf); 1456*0Sstevel@tonic-gate if (ap3) { 1457*0Sstevel@tonic-gate if ((ap3[0] != '*') || (ap3[1] != '\0')) 1458*0Sstevel@tonic-gate *uid = atoi(ap3); /* the uid */ 1459*0Sstevel@tonic-gate else if (stat_result == 0) 1460*0Sstevel@tonic-gate *uid = stbuf.st_uid; 1461*0Sstevel@tonic-gate } 1462*0Sstevel@tonic-gate if (ap4) { 1463*0Sstevel@tonic-gate if ((ap4[0] != '*') || (ap4[1] != '\0')) 1464*0Sstevel@tonic-gate *gid = atoi(ap4); /* the gid */ 1465*0Sstevel@tonic-gate else if (stat_result == 0) 1466*0Sstevel@tonic-gate *gid = stbuf.st_gid; 1467*0Sstevel@tonic-gate } 1468*0Sstevel@tonic-gate if (ap7) { 1469*0Sstevel@tonic-gate sscanf(ap7, "%o", d_mode); 1470*0Sstevel@tonic-gate *valid = 1; 1471*0Sstevel@tonic-gate } 1472*0Sstevel@tonic-gate else if (ap5) { 1473*0Sstevel@tonic-gate sscanf(ap5, "%o", d_mode); 1474*0Sstevel@tonic-gate if (*d_mode & 0600) 1475*0Sstevel@tonic-gate *d_mode |= 0100; 1476*0Sstevel@tonic-gate if (*d_mode & 0060) 1477*0Sstevel@tonic-gate *d_mode |= 0010; 1478*0Sstevel@tonic-gate if (*d_mode & 0006) 1479*0Sstevel@tonic-gate *d_mode |= 0001; 1480*0Sstevel@tonic-gate *valid = 1; 1481*0Sstevel@tonic-gate } 1482*0Sstevel@tonic-gate return (1); 1483*0Sstevel@tonic-gate } 1484*0Sstevel@tonic-gate 1485*0Sstevel@tonic-gate int upl_check(char *name, uid_t * uid, gid_t * gid, int *f_mode, int *valid) 1486*0Sstevel@tonic-gate { 1487*0Sstevel@tonic-gate int match_value = -1; 1488*0Sstevel@tonic-gate char cwdir[MAXPATHLEN]; 1489*0Sstevel@tonic-gate char *pwdir; 1490*0Sstevel@tonic-gate char abspwdir[MAXPATHLEN]; 1491*0Sstevel@tonic-gate char relpwdir[MAXPATHLEN]; 1492*0Sstevel@tonic-gate char path[MAXPATHLEN]; 1493*0Sstevel@tonic-gate char *sp; 1494*0Sstevel@tonic-gate struct stat stbuf; 1495*0Sstevel@tonic-gate int stat_result = -1; 1496*0Sstevel@tonic-gate char *ap2 = NULL; 1497*0Sstevel@tonic-gate char *ap3 = NULL; 1498*0Sstevel@tonic-gate char *ap4 = NULL; 1499*0Sstevel@tonic-gate char *ap5 = NULL; 1500*0Sstevel@tonic-gate struct aclmember *entry = NULL; 1501*0Sstevel@tonic-gate char class[1024]; 1502*0Sstevel@tonic-gate extern char *home; 1503*0Sstevel@tonic-gate 1504*0Sstevel@tonic-gate *valid = 0; 1505*0Sstevel@tonic-gate (void) acl_getclass(class); 1506*0Sstevel@tonic-gate 1507*0Sstevel@tonic-gate /* what's our current directory? */ 1508*0Sstevel@tonic-gate 1509*0Sstevel@tonic-gate /* XXX We could use dynamic RAM to store this path, but I'd rather just bail 1510*0Sstevel@tonic-gate out with an error. The rest of wu is so crufy that a long path might 1511*0Sstevel@tonic-gate just blow up later */ 1512*0Sstevel@tonic-gate 1513*0Sstevel@tonic-gate if ((strlen(name) + 1) > sizeof(path)) { 1514*0Sstevel@tonic-gate perror_reply(553, "Path too long"); 1515*0Sstevel@tonic-gate return (-1); 1516*0Sstevel@tonic-gate } 1517*0Sstevel@tonic-gate 1518*0Sstevel@tonic-gate strcpy(path, name); 1519*0Sstevel@tonic-gate sp = strrchr(path, '/'); 1520*0Sstevel@tonic-gate if (sp) 1521*0Sstevel@tonic-gate *sp = '\0'; 1522*0Sstevel@tonic-gate else 1523*0Sstevel@tonic-gate strcpy(path, "."); 1524*0Sstevel@tonic-gate 1525*0Sstevel@tonic-gate if ((fb_realpath(path, cwdir)) == NULL) { 1526*0Sstevel@tonic-gate perror_reply(553, "Could not determine cwdir"); 1527*0Sstevel@tonic-gate return (-1); 1528*0Sstevel@tonic-gate } 1529*0Sstevel@tonic-gate 1530*0Sstevel@tonic-gate if ((wu_realpath(home, abspwdir, chroot_path)) == NULL) { 1531*0Sstevel@tonic-gate perror_reply(553, "Could not determine pwdir"); 1532*0Sstevel@tonic-gate return (-1); 1533*0Sstevel@tonic-gate } 1534*0Sstevel@tonic-gate 1535*0Sstevel@tonic-gate if ((fb_realpath(home, relpwdir)) == NULL) { 1536*0Sstevel@tonic-gate perror_reply(553, "Could not determine pwdir"); 1537*0Sstevel@tonic-gate return (-1); 1538*0Sstevel@tonic-gate } 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate /* 1541*0Sstevel@tonic-gate * we are doing a "best match"... ..so we keep track of what "match 1542*0Sstevel@tonic-gate * value" we have received so far... 1543*0Sstevel@tonic-gate */ 1544*0Sstevel@tonic-gate while (getaclentry("upload", &entry)) { 1545*0Sstevel@tonic-gate char *q; 1546*0Sstevel@tonic-gate int i = 0; 1547*0Sstevel@tonic-gate int options = 1; 1548*0Sstevel@tonic-gate int classfound = 0; 1549*0Sstevel@tonic-gate int classmatched = 0; 1550*0Sstevel@tonic-gate pwdir = abspwdir; 1551*0Sstevel@tonic-gate while (options 1552*0Sstevel@tonic-gate && (i < MAXARGS) 1553*0Sstevel@tonic-gate && ((q = entry->arg[i]) != (char *) NULL) 1554*0Sstevel@tonic-gate && (q[0] != '\0')) { 1555*0Sstevel@tonic-gate if (strcasecmp(q, "absolute") == 0) { 1556*0Sstevel@tonic-gate i++; 1557*0Sstevel@tonic-gate pwdir = abspwdir; 1558*0Sstevel@tonic-gate } 1559*0Sstevel@tonic-gate else if (strcasecmp(q, "relative") == 0) { 1560*0Sstevel@tonic-gate i++; 1561*0Sstevel@tonic-gate pwdir = relpwdir; 1562*0Sstevel@tonic-gate } 1563*0Sstevel@tonic-gate else if (strncasecmp(q, "class=", 6) == 0) { 1564*0Sstevel@tonic-gate i++; 1565*0Sstevel@tonic-gate classfound = 1; 1566*0Sstevel@tonic-gate if (strcasecmp(q + 6, class) == 0) 1567*0Sstevel@tonic-gate classmatched = 1; 1568*0Sstevel@tonic-gate } 1569*0Sstevel@tonic-gate else if (strcmp(q, "-") == 0) { 1570*0Sstevel@tonic-gate i++; 1571*0Sstevel@tonic-gate options = 0; 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate else 1574*0Sstevel@tonic-gate options = 0; 1575*0Sstevel@tonic-gate } 1576*0Sstevel@tonic-gate if (!classfound || classmatched) { 1577*0Sstevel@tonic-gate int j; 1578*0Sstevel@tonic-gate if (((i + 1) < MAXARGS) 1579*0Sstevel@tonic-gate && ((q = entry->arg[i]) != (char *) NULL) 1580*0Sstevel@tonic-gate && (q[0] != '\0') 1581*0Sstevel@tonic-gate && (0 < path_compare(q, pwdir)) 1582*0Sstevel@tonic-gate && ((j = path_compare(entry->arg[i + 1], cwdir)) >= match_value)) { 1583*0Sstevel@tonic-gate match_value = j; 1584*0Sstevel@tonic-gate 1585*0Sstevel@tonic-gate ap2 = NULL; 1586*0Sstevel@tonic-gate if (((i + 2) < MAXARGS) 1587*0Sstevel@tonic-gate && ((q = entry->arg[i + 2]) != (char *) NULL) 1588*0Sstevel@tonic-gate && (q[0] != '\0')) 1589*0Sstevel@tonic-gate ap2 = q; 1590*0Sstevel@tonic-gate 1591*0Sstevel@tonic-gate ap3 = NULL; 1592*0Sstevel@tonic-gate if (((i + 3) < MAXARGS) 1593*0Sstevel@tonic-gate && ((q = entry->arg[i + 3]) != (char *) NULL) 1594*0Sstevel@tonic-gate && (q[0] != '\0')) 1595*0Sstevel@tonic-gate ap3 = q; 1596*0Sstevel@tonic-gate 1597*0Sstevel@tonic-gate ap4 = NULL; 1598*0Sstevel@tonic-gate if (((i + 4) < MAXARGS) 1599*0Sstevel@tonic-gate && ((q = entry->arg[i + 4]) != (char *) NULL) 1600*0Sstevel@tonic-gate && (q[0] != '\0')) 1601*0Sstevel@tonic-gate ap4 = q; 1602*0Sstevel@tonic-gate 1603*0Sstevel@tonic-gate ap5 = NULL; 1604*0Sstevel@tonic-gate if (((i + 5) < MAXARGS) 1605*0Sstevel@tonic-gate && ((q = entry->arg[i + 5]) != (char *) NULL) 1606*0Sstevel@tonic-gate && (q[0] != '\0')) 1607*0Sstevel@tonic-gate ap5 = q; 1608*0Sstevel@tonic-gate } 1609*0Sstevel@tonic-gate } 1610*0Sstevel@tonic-gate } 1611*0Sstevel@tonic-gate 1612*0Sstevel@tonic-gate if (ap3 1613*0Sstevel@tonic-gate && ((!strcasecmp("dirs", ap3)) 1614*0Sstevel@tonic-gate || (!strcasecmp("nodirs", ap3)))) 1615*0Sstevel@tonic-gate ap3 = NULL; 1616*0Sstevel@tonic-gate 1617*0Sstevel@tonic-gate /* 1618*0Sstevel@tonic-gate * if we did get matches ... else don't do any of this stuff 1619*0Sstevel@tonic-gate */ 1620*0Sstevel@tonic-gate if (match_value >= 0) { 1621*0Sstevel@tonic-gate if (!strcasecmp(ap2, "yes")) { 1622*0Sstevel@tonic-gate if ((ap3 && *ap3 == '*') || (ap4 && *ap4 == '*')) 1623*0Sstevel@tonic-gate stat_result = stat(path, &stbuf); 1624*0Sstevel@tonic-gate if (ap3) { 1625*0Sstevel@tonic-gate if ((ap3[0] != '*') || (ap3[1] != '\0')) 1626*0Sstevel@tonic-gate *uid = atoi(ap3); /* the uid */ 1627*0Sstevel@tonic-gate else if (stat_result == 0) 1628*0Sstevel@tonic-gate *uid = stbuf.st_uid; 1629*0Sstevel@tonic-gate } 1630*0Sstevel@tonic-gate if (ap4) { 1631*0Sstevel@tonic-gate if ((ap4[0] != '*') || (ap4[1] != '\0')) 1632*0Sstevel@tonic-gate *gid = atoi(ap4); /* the gid */ 1633*0Sstevel@tonic-gate else if (stat_result == 0) 1634*0Sstevel@tonic-gate *gid = stbuf.st_gid; 1635*0Sstevel@tonic-gate *valid = 1; 1636*0Sstevel@tonic-gate } 1637*0Sstevel@tonic-gate if (ap5) 1638*0Sstevel@tonic-gate sscanf(ap5, "%o", f_mode); /* the mode */ 1639*0Sstevel@tonic-gate } 1640*0Sstevel@tonic-gate else { 1641*0Sstevel@tonic-gate reply(553, "%s: Permission denied on server. (Upload)", name); 1642*0Sstevel@tonic-gate return (-1); 1643*0Sstevel@tonic-gate } 1644*0Sstevel@tonic-gate } 1645*0Sstevel@tonic-gate else { 1646*0Sstevel@tonic-gate /* 1647*0Sstevel@tonic-gate * upload defaults to "permitted" 1648*0Sstevel@tonic-gate */ 1649*0Sstevel@tonic-gate /* Not if anonymous */ 1650*0Sstevel@tonic-gate if (anonymous) { 1651*0Sstevel@tonic-gate reply(553, "%s: Permission denied on server. (Upload)", name); 1652*0Sstevel@tonic-gate return (-1); 1653*0Sstevel@tonic-gate } 1654*0Sstevel@tonic-gate return (1); 1655*0Sstevel@tonic-gate } 1656*0Sstevel@tonic-gate 1657*0Sstevel@tonic-gate return (match_value); 1658*0Sstevel@tonic-gate } 1659*0Sstevel@tonic-gate 1660*0Sstevel@tonic-gate int del_check(char *name) 1661*0Sstevel@tonic-gate { 1662*0Sstevel@tonic-gate int pdelete = (anonymous ? 0 : 1); 1663*0Sstevel@tonic-gate struct aclmember *entry = NULL; 1664*0Sstevel@tonic-gate 1665*0Sstevel@tonic-gate while (getaclentry("delete", &entry) && ARG0 && ARG1 != NULL) { 1666*0Sstevel@tonic-gate if (type_match(ARG1)) 1667*0Sstevel@tonic-gate if (anonymous) { 1668*0Sstevel@tonic-gate if (*ARG0 == 'y') 1669*0Sstevel@tonic-gate pdelete = 1; 1670*0Sstevel@tonic-gate } 1671*0Sstevel@tonic-gate else if (*ARG0 == 'n') 1672*0Sstevel@tonic-gate pdelete = 0; 1673*0Sstevel@tonic-gate } 1674*0Sstevel@tonic-gate 1675*0Sstevel@tonic-gate /* H* fix: no deletion, period. You put a file here, I get to look at it. */ 1676*0Sstevel@tonic-gate #ifdef PARANOID 1677*0Sstevel@tonic-gate pdelete = 0; 1678*0Sstevel@tonic-gate #endif 1679*0Sstevel@tonic-gate 1680*0Sstevel@tonic-gate if (!pdelete) { 1681*0Sstevel@tonic-gate reply(553, "%s: Permission denied on server. (Delete)", name); 1682*0Sstevel@tonic-gate return (0); 1683*0Sstevel@tonic-gate } 1684*0Sstevel@tonic-gate else { 1685*0Sstevel@tonic-gate return (1); 1686*0Sstevel@tonic-gate } 1687*0Sstevel@tonic-gate } 1688*0Sstevel@tonic-gate 1689*0Sstevel@tonic-gate /* The following is from the Debian add-ons. */ 1690*0Sstevel@tonic-gate 1691*0Sstevel@tonic-gate #define lbasename(x) (strrchr(x,'/')?1+strrchr(x,'/'):x) 1692*0Sstevel@tonic-gate 1693*0Sstevel@tonic-gate int regexmatch(char *name, char *rgexp) 1694*0Sstevel@tonic-gate { 1695*0Sstevel@tonic-gate 1696*0Sstevel@tonic-gate #ifdef M_UNIX 1697*0Sstevel@tonic-gate #ifdef HAVE_REGEX 1698*0Sstevel@tonic-gate char *regp; 1699*0Sstevel@tonic-gate #endif 1700*0Sstevel@tonic-gate #endif 1701*0Sstevel@tonic-gate 1702*0Sstevel@tonic-gate #ifdef HAVE_REGEXEC 1703*0Sstevel@tonic-gate regex_t regexbuf; 1704*0Sstevel@tonic-gate regmatch_t regmatchbuf; 1705*0Sstevel@tonic-gate int rval; 1706*0Sstevel@tonic-gate #else 1707*0Sstevel@tonic-gate char *sp; 1708*0Sstevel@tonic-gate #endif 1709*0Sstevel@tonic-gate 1710*0Sstevel@tonic-gate #if defined(HAVE_REGEXEC) 1711*0Sstevel@tonic-gate if (regcomp(®exbuf, rgexp, REG_EXTENDED) != 0) { 1712*0Sstevel@tonic-gate reply(553, "HAVE_REGEX error"); 1713*0Sstevel@tonic-gate #elif defined(HAVE_REGEX) 1714*0Sstevel@tonic-gate if ((sp = regcmp(rgexp, (char *) 0)) == NULL) { 1715*0Sstevel@tonic-gate reply(553, "HAVE_REGEX error"); 1716*0Sstevel@tonic-gate #else 1717*0Sstevel@tonic-gate if ((sp = re_comp(rgexp)) != 0) { 1718*0Sstevel@tonic-gate perror_reply(553, sp); 1719*0Sstevel@tonic-gate #endif 1720*0Sstevel@tonic-gate return (0); 1721*0Sstevel@tonic-gate } 1722*0Sstevel@tonic-gate 1723*0Sstevel@tonic-gate #if defined(HAVE_REGEXEC) 1724*0Sstevel@tonic-gate rval = regexec(®exbuf, name, 1, ®matchbuf, 0); 1725*0Sstevel@tonic-gate regfree(®exbuf); 1726*0Sstevel@tonic-gate if (rval != 0) { 1727*0Sstevel@tonic-gate #elif defined(HAVE_REGEX) 1728*0Sstevel@tonic-gate #ifdef M_UNIX 1729*0Sstevel@tonic-gate regp = regex(sp, name); 1730*0Sstevel@tonic-gate free(sp); 1731*0Sstevel@tonic-gate if (regp == NULL) { 1732*0Sstevel@tonic-gate #else 1733*0Sstevel@tonic-gate if ((regex(sp, name)) == NULL) { 1734*0Sstevel@tonic-gate #endif 1735*0Sstevel@tonic-gate #else 1736*0Sstevel@tonic-gate if ((re_exec(name)) != 1) { 1737*0Sstevel@tonic-gate #endif 1738*0Sstevel@tonic-gate return (0); 1739*0Sstevel@tonic-gate } 1740*0Sstevel@tonic-gate return (1); 1741*0Sstevel@tonic-gate } 1742*0Sstevel@tonic-gate 1743*0Sstevel@tonic-gate static int allow_retrieve(char *name) 1744*0Sstevel@tonic-gate { 1745*0Sstevel@tonic-gate char realname[MAXPATHLEN + 1]; 1746*0Sstevel@tonic-gate char localname[MAXPATHLEN + 1]; 1747*0Sstevel@tonic-gate char *whichname; 1748*0Sstevel@tonic-gate int i; 1749*0Sstevel@tonic-gate struct aclmember *entry = NULL; 1750*0Sstevel@tonic-gate char *p, *q; 1751*0Sstevel@tonic-gate int options; 1752*0Sstevel@tonic-gate int classfound; 1753*0Sstevel@tonic-gate int classmatched; 1754*0Sstevel@tonic-gate char class[1024]; 1755*0Sstevel@tonic-gate 1756*0Sstevel@tonic-gate (void) acl_getclass(class); 1757*0Sstevel@tonic-gate if ((name == (char *) NULL) 1758*0Sstevel@tonic-gate || (*name == '\0')) 1759*0Sstevel@tonic-gate return 0; 1760*0Sstevel@tonic-gate fb_realpath(name, localname); 1761*0Sstevel@tonic-gate wu_realpath(name, realname, chroot_path); 1762*0Sstevel@tonic-gate while (getaclentry("allow-retrieve", &entry)) { 1763*0Sstevel@tonic-gate whichname = realname; 1764*0Sstevel@tonic-gate i = 0; 1765*0Sstevel@tonic-gate options = 1; 1766*0Sstevel@tonic-gate classfound = 0; 1767*0Sstevel@tonic-gate classmatched = 0; 1768*0Sstevel@tonic-gate while (options 1769*0Sstevel@tonic-gate && (i < MAXARGS) 1770*0Sstevel@tonic-gate && ((q = entry->arg[i]) != (char *) NULL) 1771*0Sstevel@tonic-gate && (q[0] != '\0')) { 1772*0Sstevel@tonic-gate if (strcasecmp(q, "absolute") == 0) { 1773*0Sstevel@tonic-gate i++; 1774*0Sstevel@tonic-gate whichname = realname; 1775*0Sstevel@tonic-gate } 1776*0Sstevel@tonic-gate else if (strcasecmp(q, "relative") == 0) { 1777*0Sstevel@tonic-gate i++; 1778*0Sstevel@tonic-gate whichname = localname; 1779*0Sstevel@tonic-gate } 1780*0Sstevel@tonic-gate else if (strncasecmp(q, "class=", 6) == 0) { 1781*0Sstevel@tonic-gate i++; 1782*0Sstevel@tonic-gate classfound = 1; 1783*0Sstevel@tonic-gate if (strcasecmp(q + 6, class) == 0) 1784*0Sstevel@tonic-gate classmatched = 1; 1785*0Sstevel@tonic-gate } 1786*0Sstevel@tonic-gate else if (strcmp(q, "-") == 0) { 1787*0Sstevel@tonic-gate i++; 1788*0Sstevel@tonic-gate options = 0; 1789*0Sstevel@tonic-gate } 1790*0Sstevel@tonic-gate else 1791*0Sstevel@tonic-gate options = 0; 1792*0Sstevel@tonic-gate } 1793*0Sstevel@tonic-gate if (!classfound || classmatched) { 1794*0Sstevel@tonic-gate for (; (i < MAXARGS) && ((q = entry->arg[i]) != (char *) NULL) && (q[0] != '\0'); i++) { 1795*0Sstevel@tonic-gate p = (q[0] == '/') ? whichname : lbasename(whichname); 1796*0Sstevel@tonic-gate if (!wu_fnmatch(q, p, FNM_PATHNAME | FNM_LEADING_DIR)) { 1797*0Sstevel@tonic-gate return 1; 1798*0Sstevel@tonic-gate } 1799*0Sstevel@tonic-gate } 1800*0Sstevel@tonic-gate } 1801*0Sstevel@tonic-gate } 1802*0Sstevel@tonic-gate return 0; 1803*0Sstevel@tonic-gate } 1804*0Sstevel@tonic-gate 1805*0Sstevel@tonic-gate int checknoretrieve(char *name) 1806*0Sstevel@tonic-gate { 1807*0Sstevel@tonic-gate char realname[MAXPATHLEN + 1]; 1808*0Sstevel@tonic-gate char localname[MAXPATHLEN + 1]; 1809*0Sstevel@tonic-gate char *whichname; 1810*0Sstevel@tonic-gate int i; 1811*0Sstevel@tonic-gate struct aclmember *entry = NULL; 1812*0Sstevel@tonic-gate char *p, *q; 1813*0Sstevel@tonic-gate int options; 1814*0Sstevel@tonic-gate int classfound; 1815*0Sstevel@tonic-gate int classmatched; 1816*0Sstevel@tonic-gate char class[1024]; 1817*0Sstevel@tonic-gate 1818*0Sstevel@tonic-gate extern struct passwd *pw; 1819*0Sstevel@tonic-gate extern char *remoteident; 1820*0Sstevel@tonic-gate 1821*0Sstevel@tonic-gate (void) acl_getclass(class); 1822*0Sstevel@tonic-gate if ((name == (char *) NULL) 1823*0Sstevel@tonic-gate || (*name == '\0')) 1824*0Sstevel@tonic-gate return 0; 1825*0Sstevel@tonic-gate fb_realpath(name, localname); 1826*0Sstevel@tonic-gate wu_realpath(name, realname, chroot_path); 1827*0Sstevel@tonic-gate while (getaclentry("noretrieve", &entry)) { 1828*0Sstevel@tonic-gate whichname = realname; 1829*0Sstevel@tonic-gate i = 0; 1830*0Sstevel@tonic-gate options = 1; 1831*0Sstevel@tonic-gate classfound = 0; 1832*0Sstevel@tonic-gate classmatched = 0; 1833*0Sstevel@tonic-gate while (options 1834*0Sstevel@tonic-gate && (i < MAXARGS) 1835*0Sstevel@tonic-gate && ((q = entry->arg[i]) != (char *) NULL) 1836*0Sstevel@tonic-gate && (q[0] != '\0')) { 1837*0Sstevel@tonic-gate if (strcasecmp(q, "absolute") == 0) { 1838*0Sstevel@tonic-gate i++; 1839*0Sstevel@tonic-gate whichname = realname; 1840*0Sstevel@tonic-gate } 1841*0Sstevel@tonic-gate else if (strcasecmp(q, "relative") == 0) { 1842*0Sstevel@tonic-gate i++; 1843*0Sstevel@tonic-gate whichname = localname; 1844*0Sstevel@tonic-gate } 1845*0Sstevel@tonic-gate else if (strncasecmp(q, "class=", 6) == 0) { 1846*0Sstevel@tonic-gate i++; 1847*0Sstevel@tonic-gate classfound = 1; 1848*0Sstevel@tonic-gate if (strcasecmp(q + 6, class) == 0) 1849*0Sstevel@tonic-gate classmatched = 1; 1850*0Sstevel@tonic-gate } 1851*0Sstevel@tonic-gate else if (strcmp(q, "-") == 0) { 1852*0Sstevel@tonic-gate i++; 1853*0Sstevel@tonic-gate options = 0; 1854*0Sstevel@tonic-gate } 1855*0Sstevel@tonic-gate else 1856*0Sstevel@tonic-gate options = 0; 1857*0Sstevel@tonic-gate } 1858*0Sstevel@tonic-gate if (!classfound || classmatched) { 1859*0Sstevel@tonic-gate for (; (i < MAXARGS) && ((q = entry->arg[i]) != (char *) NULL) && (q[0] != '\0'); i++) { 1860*0Sstevel@tonic-gate p = (q[0] == '/') ? whichname : lbasename(whichname); 1861*0Sstevel@tonic-gate if (!wu_fnmatch(q, p, FNM_PATHNAME | FNM_LEADING_DIR)) { 1862*0Sstevel@tonic-gate if (!allow_retrieve(name)) { 1863*0Sstevel@tonic-gate reply(550, "%s is marked unretrievable", localname); 1864*0Sstevel@tonic-gate return 1; 1865*0Sstevel@tonic-gate } 1866*0Sstevel@tonic-gate } 1867*0Sstevel@tonic-gate } 1868*0Sstevel@tonic-gate } 1869*0Sstevel@tonic-gate } 1870*0Sstevel@tonic-gate return 0; 1871*0Sstevel@tonic-gate } 1872*0Sstevel@tonic-gate 1873*0Sstevel@tonic-gate #ifdef QUOTA 1874*0Sstevel@tonic-gate 1875*0Sstevel@tonic-gate #ifndef MNTMAXSTR 1876*0Sstevel@tonic-gate #define MNTMAXSTR 2048 /* And hope it's enough */ 1877*0Sstevel@tonic-gate #endif 1878*0Sstevel@tonic-gate 1879*0Sstevel@tonic-gate #ifdef QUOTA_DEVICE 1880*0Sstevel@tonic-gate 1881*0Sstevel@tonic-gate int path_to_device(char *pathname, char *result) 1882*0Sstevel@tonic-gate { 1883*0Sstevel@tonic-gate FILE *fp; 1884*0Sstevel@tonic-gate #ifdef HAS_OLDSTYLE_GETMNTENT 1885*0Sstevel@tonic-gate struct mnttab static_mp; 1886*0Sstevel@tonic-gate struct mnttab *mp = &static_mp; 1887*0Sstevel@tonic-gate #else 1888*0Sstevel@tonic-gate struct mntent *mp; 1889*0Sstevel@tonic-gate #endif 1890*0Sstevel@tonic-gate struct mount_ent { 1891*0Sstevel@tonic-gate char mnt_fsname[MNTMAXSTR], mnt_dir[MNTMAXSTR]; 1892*0Sstevel@tonic-gate struct mount_ent *next; 1893*0Sstevel@tonic-gate } mountent; 1894*0Sstevel@tonic-gate struct mount_ent *current, *start, *new; 1895*0Sstevel@tonic-gate char path[1024], mnt_dir[1024], *pos; 1896*0Sstevel@tonic-gate int flag = 1; 1897*0Sstevel@tonic-gate 1898*0Sstevel@tonic-gate start = current = NULL; 1899*0Sstevel@tonic-gate #ifdef HAS_OLDSTYLE_GETMNTENT 1900*0Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 1901*0Sstevel@tonic-gate #else 1902*0Sstevel@tonic-gate fp = setmntent(MNTTAB, "r"); 1903*0Sstevel@tonic-gate #endif 1904*0Sstevel@tonic-gate if (fp == NULL) 1905*0Sstevel@tonic-gate return 0; 1906*0Sstevel@tonic-gate #ifdef HAS_OLDSTYLE_GETMNTENT 1907*0Sstevel@tonic-gate while (getmntent(fp, &static_mp) == 0) 1908*0Sstevel@tonic-gate #else 1909*0Sstevel@tonic-gate while (mp = getmntent(fp)) 1910*0Sstevel@tonic-gate #endif 1911*0Sstevel@tonic-gate { 1912*0Sstevel@tonic-gate if (!(new = (struct mount_ent *) malloc(sizeof(mountent)))) { 1913*0Sstevel@tonic-gate perror("malloc"); 1914*0Sstevel@tonic-gate flag = 0; 1915*0Sstevel@tonic-gate break; 1916*0Sstevel@tonic-gate } 1917*0Sstevel@tonic-gate 1918*0Sstevel@tonic-gate if (!start) 1919*0Sstevel@tonic-gate start = current = new; 1920*0Sstevel@tonic-gate else 1921*0Sstevel@tonic-gate current = current->next = new; 1922*0Sstevel@tonic-gate 1923*0Sstevel@tonic-gate #ifdef HAS_OLDSTYLE_GETMNTENT 1924*0Sstevel@tonic-gate strncpy(current->mnt_fsname, mp->mnt_special, strlen(mp->mnt_special) + 1); 1925*0Sstevel@tonic-gate strncpy(current->mnt_dir, mp->mnt_mountp, strlen(mp->mnt_mountp) + 1); 1926*0Sstevel@tonic-gate #else 1927*0Sstevel@tonic-gate strncpy(current->mnt_fsname, mp->mnt_fsname, strlen(mp->mnt_fsname) + 1); 1928*0Sstevel@tonic-gate strncpy(current->mnt_dir, mp->mnt_dir, strlen(mp->mnt_dir) + 1); 1929*0Sstevel@tonic-gate #endif 1930*0Sstevel@tonic-gate } 1931*0Sstevel@tonic-gate #ifdef HAS_OLDSTYLE_GETMNTENT 1932*0Sstevel@tonic-gate fclose(fp); 1933*0Sstevel@tonic-gate #else 1934*0Sstevel@tonic-gate endmntent(fp); 1935*0Sstevel@tonic-gate #endif 1936*0Sstevel@tonic-gate current->next = NULL; 1937*0Sstevel@tonic-gate 1938*0Sstevel@tonic-gate wu_realpath(pathname, path, chroot_path); 1939*0Sstevel@tonic-gate 1940*0Sstevel@tonic-gate while (*path && flag) { 1941*0Sstevel@tonic-gate current = start; 1942*0Sstevel@tonic-gate while (current && flag) { 1943*0Sstevel@tonic-gate if (strcmp(current->mnt_dir, "swap")) { 1944*0Sstevel@tonic-gate wu_realpath(current->mnt_dir, mnt_dir, chroot_path); 1945*0Sstevel@tonic-gate if (!strcmp(mnt_dir, path)) { 1946*0Sstevel@tonic-gate flag = 0; 1947*0Sstevel@tonic-gate /* no support for remote quota yet */ 1948*0Sstevel@tonic-gate if (!strchr(current->mnt_fsname, ':')) 1949*0Sstevel@tonic-gate strcpy(result, current->mnt_fsname); 1950*0Sstevel@tonic-gate } 1951*0Sstevel@tonic-gate } 1952*0Sstevel@tonic-gate current = current->next; 1953*0Sstevel@tonic-gate } 1954*0Sstevel@tonic-gate if (!((pos = strrchr(path, '/')) - path) && strlen(path) > 1) 1955*0Sstevel@tonic-gate strcpy(path, "/"); 1956*0Sstevel@tonic-gate else 1957*0Sstevel@tonic-gate path[pos - path] = '\0'; 1958*0Sstevel@tonic-gate } 1959*0Sstevel@tonic-gate while (current) { 1960*0Sstevel@tonic-gate new = current->next; 1961*0Sstevel@tonic-gate free(current); 1962*0Sstevel@tonic-gate current = new; 1963*0Sstevel@tonic-gate } 1964*0Sstevel@tonic-gate return 1; 1965*0Sstevel@tonic-gate } 1966*0Sstevel@tonic-gate #endif 1967*0Sstevel@tonic-gate 1968*0Sstevel@tonic-gate void get_quota(char *fs, int uid) 1969*0Sstevel@tonic-gate { 1970*0Sstevel@tonic-gate char mnt_fsname[MNTMAXSTR]; 1971*0Sstevel@tonic-gate #ifdef HAS_NO_QUOTACTL 1972*0Sstevel@tonic-gate int dirfd; 1973*0Sstevel@tonic-gate struct quotctl qp; 1974*0Sstevel@tonic-gate #endif 1975*0Sstevel@tonic-gate 1976*0Sstevel@tonic-gate /* 1977*0Sstevel@tonic-gate * Getting file system quota information can take a noticeable amount 1978*0Sstevel@tonic-gate * of time, so only get quota information for specified users. 1979*0Sstevel@tonic-gate * quota-info <uid-range> [<uid-range> ...] 1980*0Sstevel@tonic-gate */ 1981*0Sstevel@tonic-gate if (!uid_match("quota-info", uid)) 1982*0Sstevel@tonic-gate return; 1983*0Sstevel@tonic-gate 1984*0Sstevel@tonic-gate #ifdef HAS_NO_QUOTACTL 1985*0Sstevel@tonic-gate if (path_to_device(fs, mnt_fsname)) { 1986*0Sstevel@tonic-gate dirfd = open(fs, O_RDONLY); 1987*0Sstevel@tonic-gate qp.op = Q_GETQUOTA; 1988*0Sstevel@tonic-gate qp.uid = uid; 1989*0Sstevel@tonic-gate qp.addr = (char *) "a; 1990*0Sstevel@tonic-gate ioctl(dirfd, Q_QUOTACTL, &qp); 1991*0Sstevel@tonic-gate close(dirfd); 1992*0Sstevel@tonic-gate } 1993*0Sstevel@tonic-gate #else 1994*0Sstevel@tonic-gate #ifdef QUOTA_DEVICE 1995*0Sstevel@tonic-gate 1996*0Sstevel@tonic-gate if (path_to_device(fs, mnt_fsname)) 1997*0Sstevel@tonic-gate #ifdef QCMD 1998*0Sstevel@tonic-gate quotactl(QCMD(Q_GETQUOTA, USRQUOTA), mnt_fsname, uid, (char *) "a); 1999*0Sstevel@tonic-gate #else 2000*0Sstevel@tonic-gate quotactl(Q_GETQUOTA, mnt_fsname, uid, (char *) "a); 2001*0Sstevel@tonic-gate #endif 2002*0Sstevel@tonic-gate #else 2003*0Sstevel@tonic-gate quotactl(fs, QCMD(Q_GETQUOTA, USRQUOTA), uid, (char *) "a); 2004*0Sstevel@tonic-gate #endif 2005*0Sstevel@tonic-gate #endif /* HAS_NO_QUOTACTL */ 2006*0Sstevel@tonic-gate } 2007*0Sstevel@tonic-gate 2008*0Sstevel@tonic-gate char *time_quota(long curstate, long softlimit, long timelimit, char *timeleft) 2009*0Sstevel@tonic-gate { 2010*0Sstevel@tonic-gate struct timeval tv; 2011*0Sstevel@tonic-gate 2012*0Sstevel@tonic-gate gettimeofday(&tv, NULL); 2013*0Sstevel@tonic-gate if (softlimit && curstate >= softlimit) { 2014*0Sstevel@tonic-gate if (timelimit == 0) { 2015*0Sstevel@tonic-gate strcpy(timeleft, "NOT STARTED"); 2016*0Sstevel@tonic-gate } 2017*0Sstevel@tonic-gate else if (timelimit > tv.tv_sec) { 2018*0Sstevel@tonic-gate fmttime(timeleft, timelimit - tv.tv_sec); 2019*0Sstevel@tonic-gate } 2020*0Sstevel@tonic-gate else { 2021*0Sstevel@tonic-gate strcpy(timeleft, "EXPIRED"); 2022*0Sstevel@tonic-gate } 2023*0Sstevel@tonic-gate } 2024*0Sstevel@tonic-gate else { 2025*0Sstevel@tonic-gate timeleft[0] = '\0'; 2026*0Sstevel@tonic-gate } 2027*0Sstevel@tonic-gate return (timeleft); 2028*0Sstevel@tonic-gate } 2029*0Sstevel@tonic-gate 2030*0Sstevel@tonic-gate void fmttime(char *buf, register long time) 2031*0Sstevel@tonic-gate { 2032*0Sstevel@tonic-gate int i; 2033*0Sstevel@tonic-gate static struct { 2034*0Sstevel@tonic-gate int c_secs; /* conversion units in secs */ 2035*0Sstevel@tonic-gate char *c_str; /* unit string */ 2036*0Sstevel@tonic-gate } cunits[] = { 2037*0Sstevel@tonic-gate { 2038*0Sstevel@tonic-gate 60 *60 * 24 * 28, "months" 2039*0Sstevel@tonic-gate } , 2040*0Sstevel@tonic-gate { 2041*0Sstevel@tonic-gate 60 *60 * 24 * 7, "weeks" 2042*0Sstevel@tonic-gate } , 2043*0Sstevel@tonic-gate { 2044*0Sstevel@tonic-gate 60 *60 * 24, "days" 2045*0Sstevel@tonic-gate } , 2046*0Sstevel@tonic-gate { 2047*0Sstevel@tonic-gate 60 *60, "hours" 2048*0Sstevel@tonic-gate } , 2049*0Sstevel@tonic-gate { 2050*0Sstevel@tonic-gate 60, "mins" 2051*0Sstevel@tonic-gate } , 2052*0Sstevel@tonic-gate { 2053*0Sstevel@tonic-gate 1, "secs" 2054*0Sstevel@tonic-gate } 2055*0Sstevel@tonic-gate }; 2056*0Sstevel@tonic-gate 2057*0Sstevel@tonic-gate if (time <= 0) { 2058*0Sstevel@tonic-gate strcpy(buf, "EXPIRED"); 2059*0Sstevel@tonic-gate return; 2060*0Sstevel@tonic-gate } 2061*0Sstevel@tonic-gate for (i = 0; i < sizeof(cunits) / sizeof(cunits[0]); i++) { 2062*0Sstevel@tonic-gate if (time >= cunits[i].c_secs) 2063*0Sstevel@tonic-gate break; 2064*0Sstevel@tonic-gate } 2065*0Sstevel@tonic-gate sprintf(buf, "%.1f %s", (double) time / cunits[i].c_secs, cunits[i].c_str); 2066*0Sstevel@tonic-gate } 2067*0Sstevel@tonic-gate 2068*0Sstevel@tonic-gate #endif 2069*0Sstevel@tonic-gate 2070*0Sstevel@tonic-gate #ifdef THROUGHPUT 2071*0Sstevel@tonic-gate 2072*0Sstevel@tonic-gate int file_compare(char *patterns, char *file) 2073*0Sstevel@tonic-gate { 2074*0Sstevel@tonic-gate char buf[MAXPATHLEN+1]; 2075*0Sstevel@tonic-gate char *cp; 2076*0Sstevel@tonic-gate char *cp2; 2077*0Sstevel@tonic-gate int i; 2078*0Sstevel@tonic-gate int matches = 0; 2079*0Sstevel@tonic-gate 2080*0Sstevel@tonic-gate strncpy(buf, patterns, sizeof(buf) - 1); 2081*0Sstevel@tonic-gate buf[sizeof(buf) - 2] = '\0'; 2082*0Sstevel@tonic-gate i = strlen(buf); 2083*0Sstevel@tonic-gate buf[i++] = ','; 2084*0Sstevel@tonic-gate buf[i++] = '\0'; 2085*0Sstevel@tonic-gate 2086*0Sstevel@tonic-gate cp = buf; 2087*0Sstevel@tonic-gate while ((cp2 = strchr(cp, ',')) != NULL) { 2088*0Sstevel@tonic-gate *cp2++ = '\0'; 2089*0Sstevel@tonic-gate if (wu_fnmatch(cp, file, FNM_PATHNAME) == 0) { 2090*0Sstevel@tonic-gate matches = 1; 2091*0Sstevel@tonic-gate break; 2092*0Sstevel@tonic-gate } 2093*0Sstevel@tonic-gate cp = cp2; 2094*0Sstevel@tonic-gate } 2095*0Sstevel@tonic-gate return matches; 2096*0Sstevel@tonic-gate } 2097*0Sstevel@tonic-gate 2098*0Sstevel@tonic-gate int remote_compare(char *patterns) 2099*0Sstevel@tonic-gate { 2100*0Sstevel@tonic-gate char buf[MAXPATHLEN+1]; 2101*0Sstevel@tonic-gate char *cp; 2102*0Sstevel@tonic-gate char *cp2; 2103*0Sstevel@tonic-gate int i; 2104*0Sstevel@tonic-gate int matches = 0; 2105*0Sstevel@tonic-gate 2106*0Sstevel@tonic-gate strncpy(buf, patterns, sizeof(buf) - 1); 2107*0Sstevel@tonic-gate buf[sizeof(buf) - 2] = '\0'; 2108*0Sstevel@tonic-gate i = strlen(buf); 2109*0Sstevel@tonic-gate buf[i++] = ','; 2110*0Sstevel@tonic-gate buf[i++] = '\0'; 2111*0Sstevel@tonic-gate 2112*0Sstevel@tonic-gate cp = buf; 2113*0Sstevel@tonic-gate while ((cp2 = strchr(cp, ',')) != NULL) { 2114*0Sstevel@tonic-gate *cp2++ = '\0'; 2115*0Sstevel@tonic-gate if (hostmatch(cp, remoteaddr, remotehost)) { 2116*0Sstevel@tonic-gate matches = 1; 2117*0Sstevel@tonic-gate break; 2118*0Sstevel@tonic-gate } 2119*0Sstevel@tonic-gate cp = cp2; 2120*0Sstevel@tonic-gate } 2121*0Sstevel@tonic-gate return matches; 2122*0Sstevel@tonic-gate } 2123*0Sstevel@tonic-gate 2124*0Sstevel@tonic-gate void throughput_calc(char *name, int *bps, double *bpsmult) 2125*0Sstevel@tonic-gate { 2126*0Sstevel@tonic-gate int match_value = -1; 2127*0Sstevel@tonic-gate char cwdir[MAXPATHLEN]; 2128*0Sstevel@tonic-gate char pwdir[MAXPATHLEN]; 2129*0Sstevel@tonic-gate char path[MAXPATHLEN]; 2130*0Sstevel@tonic-gate char file[MAXPATHLEN]; 2131*0Sstevel@tonic-gate char *ap3 = NULL, *ap4 = NULL; 2132*0Sstevel@tonic-gate struct aclmember *entry = NULL; 2133*0Sstevel@tonic-gate extern char *home; 2134*0Sstevel@tonic-gate char *sp; 2135*0Sstevel@tonic-gate int i; 2136*0Sstevel@tonic-gate 2137*0Sstevel@tonic-gate /* default is maximum throughput */ 2138*0Sstevel@tonic-gate *bps = -1; 2139*0Sstevel@tonic-gate *bpsmult = 1.0; 2140*0Sstevel@tonic-gate 2141*0Sstevel@tonic-gate /* XXX We could use dynamic RAM to store this path, but I'd rather just bail 2142*0Sstevel@tonic-gate out with an error. The rest of wu is so crufy that a long path might 2143*0Sstevel@tonic-gate just blow up later */ 2144*0Sstevel@tonic-gate 2145*0Sstevel@tonic-gate if ((strlen(name) + 1) > sizeof(path)) { 2146*0Sstevel@tonic-gate return; 2147*0Sstevel@tonic-gate } 2148*0Sstevel@tonic-gate 2149*0Sstevel@tonic-gate /* what's our current directory? */ 2150*0Sstevel@tonic-gate strcpy(path, name); 2151*0Sstevel@tonic-gate if ((sp = strrchr(path, '/'))) 2152*0Sstevel@tonic-gate *sp = '\0'; 2153*0Sstevel@tonic-gate else 2154*0Sstevel@tonic-gate strcpy(path, "."); 2155*0Sstevel@tonic-gate if ((sp = strrchr(name, '/'))) 2156*0Sstevel@tonic-gate strcpy(file, sp + 1); 2157*0Sstevel@tonic-gate else 2158*0Sstevel@tonic-gate strcpy(file, name); 2159*0Sstevel@tonic-gate if ((fb_realpath(path, cwdir)) == NULL) { 2160*0Sstevel@tonic-gate return; 2161*0Sstevel@tonic-gate } 2162*0Sstevel@tonic-gate 2163*0Sstevel@tonic-gate wu_realpath(home, pwdir, chroot_path); 2164*0Sstevel@tonic-gate 2165*0Sstevel@tonic-gate /* find best matching entry */ 2166*0Sstevel@tonic-gate while (getaclentry("throughput", &entry) && ARG0 && ARG1 && ARG2 && ARG3 && ARG4 && ARG5 != NULL) { 2167*0Sstevel@tonic-gate if ((0 < path_compare(ARG0, pwdir)) 2168*0Sstevel@tonic-gate && ((i = path_compare(ARG1, cwdir)) >= match_value) 2169*0Sstevel@tonic-gate ) { 2170*0Sstevel@tonic-gate if (file_compare(ARG2, file)) { 2171*0Sstevel@tonic-gate if (remote_compare(ARG5)) { 2172*0Sstevel@tonic-gate match_value = i; 2173*0Sstevel@tonic-gate ap3 = ARG3; 2174*0Sstevel@tonic-gate ap4 = ARG4; 2175*0Sstevel@tonic-gate } 2176*0Sstevel@tonic-gate } 2177*0Sstevel@tonic-gate } 2178*0Sstevel@tonic-gate } 2179*0Sstevel@tonic-gate 2180*0Sstevel@tonic-gate /* if we did get matches */ 2181*0Sstevel@tonic-gate if (match_value >= 0) { 2182*0Sstevel@tonic-gate if (strcasecmp(ap3, "oo") == 0) 2183*0Sstevel@tonic-gate *bps = -1; 2184*0Sstevel@tonic-gate else 2185*0Sstevel@tonic-gate *bps = atoi(ap3); 2186*0Sstevel@tonic-gate if (strcmp(ap4, "-") == 0) 2187*0Sstevel@tonic-gate *bpsmult = 1.0; 2188*0Sstevel@tonic-gate else 2189*0Sstevel@tonic-gate *bpsmult = atof(ap4); 2190*0Sstevel@tonic-gate } 2191*0Sstevel@tonic-gate return; 2192*0Sstevel@tonic-gate } 2193*0Sstevel@tonic-gate 2194*0Sstevel@tonic-gate void throughput_adjust(char *name) 2195*0Sstevel@tonic-gate { 2196*0Sstevel@tonic-gate int match_value = -1; 2197*0Sstevel@tonic-gate char pwdir[MAXPATHLEN]; 2198*0Sstevel@tonic-gate char cwdir[MAXPATHLEN]; 2199*0Sstevel@tonic-gate char path[MAXPATHLEN]; 2200*0Sstevel@tonic-gate char file[MAXPATHLEN]; 2201*0Sstevel@tonic-gate char buf[MAXPATHLEN]; 2202*0Sstevel@tonic-gate char *ap3 = NULL, *ap4 = NULL; 2203*0Sstevel@tonic-gate char **pap; 2204*0Sstevel@tonic-gate struct aclmember *entry = NULL; 2205*0Sstevel@tonic-gate extern char *home; 2206*0Sstevel@tonic-gate char *sp; 2207*0Sstevel@tonic-gate int i; 2208*0Sstevel@tonic-gate 2209*0Sstevel@tonic-gate /* XXX We could use dynamic RAM to store this path, but I'd rather just bail 2210*0Sstevel@tonic-gate out with an error. The rest of wu is so crufy that a long path might 2211*0Sstevel@tonic-gate just blow up later */ 2212*0Sstevel@tonic-gate 2213*0Sstevel@tonic-gate if ((strlen(name) + 1) > sizeof(path)) { 2214*0Sstevel@tonic-gate return; 2215*0Sstevel@tonic-gate } 2216*0Sstevel@tonic-gate 2217*0Sstevel@tonic-gate /* what's our current directory? */ 2218*0Sstevel@tonic-gate strcpy(path, name); 2219*0Sstevel@tonic-gate if ((sp = strrchr(path, '/'))) 2220*0Sstevel@tonic-gate *sp = '\0'; 2221*0Sstevel@tonic-gate else 2222*0Sstevel@tonic-gate strcpy(path, "."); 2223*0Sstevel@tonic-gate if ((sp = strrchr(name, '/'))) 2224*0Sstevel@tonic-gate strcpy(file, sp + 1); 2225*0Sstevel@tonic-gate else 2226*0Sstevel@tonic-gate strcpy(file, name); 2227*0Sstevel@tonic-gate if ((fb_realpath(path, cwdir)) == NULL) { 2228*0Sstevel@tonic-gate return; 2229*0Sstevel@tonic-gate } 2230*0Sstevel@tonic-gate 2231*0Sstevel@tonic-gate wu_realpath(home, pwdir, chroot_path); 2232*0Sstevel@tonic-gate 2233*0Sstevel@tonic-gate /* find best matching entry */ 2234*0Sstevel@tonic-gate while (getaclentry("throughput", &entry) && ARG0 && ARG1 && ARG2 && ARG3 && ARG4 && ARG5 != NULL) { 2235*0Sstevel@tonic-gate if ((0 < path_compare(ARG0, pwdir)) 2236*0Sstevel@tonic-gate && ((i = path_compare(ARG1, cwdir)) >= match_value) 2237*0Sstevel@tonic-gate ) { 2238*0Sstevel@tonic-gate if (file_compare(ARG2, file)) { 2239*0Sstevel@tonic-gate if (remote_compare(ARG5)) { 2240*0Sstevel@tonic-gate match_value = i; 2241*0Sstevel@tonic-gate ap3 = ARG3; 2242*0Sstevel@tonic-gate pap = ARG; 2243*0Sstevel@tonic-gate ap4 = ARG4; 2244*0Sstevel@tonic-gate } 2245*0Sstevel@tonic-gate } 2246*0Sstevel@tonic-gate } 2247*0Sstevel@tonic-gate } 2248*0Sstevel@tonic-gate 2249*0Sstevel@tonic-gate /* if we did get matches */ 2250*0Sstevel@tonic-gate if (match_value >= 0) { 2251*0Sstevel@tonic-gate if (strcasecmp(ap3, "oo") != 0) { 2252*0Sstevel@tonic-gate if (strcmp(ap4, "-") != 0) { 2253*0Sstevel@tonic-gate sprintf(buf, "%.0f", atoi(ap3) * atof(ap4)); 2254*0Sstevel@tonic-gate pap[3] = (char *) malloc(strlen(buf) + 1); 2255*0Sstevel@tonic-gate if (pap[3] == NULL) { 2256*0Sstevel@tonic-gate syslog(LOG_ERR, "malloc error in throughput_adjust"); 2257*0Sstevel@tonic-gate dologout(1); 2258*0Sstevel@tonic-gate } 2259*0Sstevel@tonic-gate /* Use ARG6 to keep track of malloced memory */ 2260*0Sstevel@tonic-gate if (pap[6]) 2261*0Sstevel@tonic-gate free(pap[6]); 2262*0Sstevel@tonic-gate pap[6] = pap[3]; 2263*0Sstevel@tonic-gate strcpy(pap[3], buf); 2264*0Sstevel@tonic-gate } 2265*0Sstevel@tonic-gate } 2266*0Sstevel@tonic-gate } 2267*0Sstevel@tonic-gate return; 2268*0Sstevel@tonic-gate } 2269*0Sstevel@tonic-gate 2270*0Sstevel@tonic-gate #endif 2271*0Sstevel@tonic-gate 2272*0Sstevel@tonic-gate #ifdef SOLARIS_2 2273*0Sstevel@tonic-gate static int CheckMethod = 1; 2274*0Sstevel@tonic-gate #else 2275*0Sstevel@tonic-gate static int CheckMethod = 0; 2276*0Sstevel@tonic-gate #endif 2277*0Sstevel@tonic-gate 2278*0Sstevel@tonic-gate void SetCheckMethod(const char *method) 2279*0Sstevel@tonic-gate { 2280*0Sstevel@tonic-gate if ((strcasecmp(method, "md5") == 0) 2281*0Sstevel@tonic-gate || (strcasecmp(method, "rfc1321") == 0)) 2282*0Sstevel@tonic-gate CheckMethod = 0; 2283*0Sstevel@tonic-gate else if ((strcasecmp(method, "crc") == 0) 2284*0Sstevel@tonic-gate || (strcasecmp(method, "posix") == 0)) 2285*0Sstevel@tonic-gate CheckMethod = 1; 2286*0Sstevel@tonic-gate else { 2287*0Sstevel@tonic-gate reply(500, "Unrecognized checksum method"); 2288*0Sstevel@tonic-gate return; 2289*0Sstevel@tonic-gate } 2290*0Sstevel@tonic-gate switch (CheckMethod) { 2291*0Sstevel@tonic-gate default: 2292*0Sstevel@tonic-gate reply(200, "Checksum method is now: MD5 (RFC1321)"); 2293*0Sstevel@tonic-gate break; 2294*0Sstevel@tonic-gate case 1: 2295*0Sstevel@tonic-gate reply(200, "Checksum method is now: CRC (POSIX)"); 2296*0Sstevel@tonic-gate break; 2297*0Sstevel@tonic-gate } 2298*0Sstevel@tonic-gate } 2299*0Sstevel@tonic-gate 2300*0Sstevel@tonic-gate void ShowCheckMethod(void) 2301*0Sstevel@tonic-gate { 2302*0Sstevel@tonic-gate switch (CheckMethod) { 2303*0Sstevel@tonic-gate default: 2304*0Sstevel@tonic-gate reply(200, "Current checksum method: MD5 (RFC1321)"); 2305*0Sstevel@tonic-gate break; 2306*0Sstevel@tonic-gate case 1: 2307*0Sstevel@tonic-gate reply(200, "Current checksum method: CRC (POSIX)"); 2308*0Sstevel@tonic-gate break; 2309*0Sstevel@tonic-gate } 2310*0Sstevel@tonic-gate } 2311*0Sstevel@tonic-gate 2312*0Sstevel@tonic-gate void CheckSum(char *pathname) 2313*0Sstevel@tonic-gate { 2314*0Sstevel@tonic-gate char *cmd; 2315*0Sstevel@tonic-gate char buf[MAXPATHLEN]; 2316*0Sstevel@tonic-gate FILE *cmdf; 2317*0Sstevel@tonic-gate struct stat st; 2318*0Sstevel@tonic-gate 2319*0Sstevel@tonic-gate if (stat(pathname, &st) == 0) { 2320*0Sstevel@tonic-gate if ((st.st_mode & S_IFMT) != S_IFREG) { 2321*0Sstevel@tonic-gate reply(500, "%s: not a plain file.", pathname); 2322*0Sstevel@tonic-gate return; 2323*0Sstevel@tonic-gate } 2324*0Sstevel@tonic-gate } 2325*0Sstevel@tonic-gate else { 2326*0Sstevel@tonic-gate perror_reply(550, pathname); 2327*0Sstevel@tonic-gate return; 2328*0Sstevel@tonic-gate } 2329*0Sstevel@tonic-gate 2330*0Sstevel@tonic-gate switch (CheckMethod) { 2331*0Sstevel@tonic-gate default: 2332*0Sstevel@tonic-gate cmd = "/bin/md5sum"; 2333*0Sstevel@tonic-gate break; 2334*0Sstevel@tonic-gate case 1: 2335*0Sstevel@tonic-gate cmd = "/bin/cksum"; 2336*0Sstevel@tonic-gate break; 2337*0Sstevel@tonic-gate } 2338*0Sstevel@tonic-gate 2339*0Sstevel@tonic-gate if (strlen(cmd) + 1 + strlen(pathname) + 1 > sizeof(buf)) { 2340*0Sstevel@tonic-gate reply(500, "Pathname too long"); 2341*0Sstevel@tonic-gate return; 2342*0Sstevel@tonic-gate } 2343*0Sstevel@tonic-gate sprintf(buf, "%s %s", cmd, pathname); 2344*0Sstevel@tonic-gate 2345*0Sstevel@tonic-gate cmdf = ftpd_popen(buf, "r", 0); 2346*0Sstevel@tonic-gate if (!cmdf) { 2347*0Sstevel@tonic-gate perror_reply(550, cmd); 2348*0Sstevel@tonic-gate } 2349*0Sstevel@tonic-gate else { 2350*0Sstevel@tonic-gate if (fgets(buf, sizeof buf, cmdf)) { 2351*0Sstevel@tonic-gate char *crptr = strchr(buf, '\n'); 2352*0Sstevel@tonic-gate if (crptr != NULL) 2353*0Sstevel@tonic-gate *crptr = '\0'; 2354*0Sstevel@tonic-gate reply(200, "%s", buf); 2355*0Sstevel@tonic-gate } 2356*0Sstevel@tonic-gate ftpd_pclose(cmdf); 2357*0Sstevel@tonic-gate } 2358*0Sstevel@tonic-gate } 2359*0Sstevel@tonic-gate 2360*0Sstevel@tonic-gate void CheckSumLastFile(void) 2361*0Sstevel@tonic-gate { 2362*0Sstevel@tonic-gate extern char LastFileTransferred[]; 2363*0Sstevel@tonic-gate 2364*0Sstevel@tonic-gate if (LastFileTransferred[0] == '\0') 2365*0Sstevel@tonic-gate reply(500, "Nothing transferred yet"); 2366*0Sstevel@tonic-gate else 2367*0Sstevel@tonic-gate CheckSum(LastFileTransferred); 2368*0Sstevel@tonic-gate } 2369