This is extensions.c in view mode; [Download] [Up]
/* Copyright (c) 1993, 1994 Washington University in Saint Louis * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. 3. All advertising * materials mentioning features or use of this software must display the * following acknowledgement: This product includes software developed by the * Washington University in Saint Louis and its contributors. 4. Neither the * name of the University nor the names of its contributors may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY WASHINGTON UNIVERSITY AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASHINGTON * UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef lint static char rcsid[] = "@(#)$Id: extensions.c,v 1.18 1997/03/03 09:39:42 sob Exp sob $"; #endif /* not lint */ #include "config.h" #include <stdio.h> #include <errno.h> #include <string.h> #ifdef SYSSYSLOG #include <sys/syslog.h> #else #include <syslog.h> #endif #include <time.h> #include <pwd.h> #include <grp.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/file.h> #include <sys/param.h> #if defined(HAVE_STATVFS) #include <sys/statvfs.h> #elif defined(HAVE_SYS_VFS) #include <sys/vfs.h> #endif #include <arpa/ftp.h> #include "pathnames.h" #include "extensions.h" #if defined(HAVE_FTW) #include <ftw.h> #else #include "support/ftw.h" #endif /*#ifdef HAVE_REGEX_H #include <regex.h> #endif */ #if defined(REGEX) && defined(SVR4) && !(defined(__hpux)) #include <libgen.h> #endif extern int fnmatch(), type, transflag, authenticated, autospout_free, data, anonymous, guest; #ifdef __STDC__ extern char **ftpglob(register char *v), #else extern char **ftpglob(), #endif *globerr, remotehost[], hostname[], authuser[], *autospout, Shutdown[]; char shuttime[30], denytime[30], disctime[30]; #ifdef __STDC__ extern char *realpath(const char *pathname, char *result); #else extern char *realpath(); #endif #ifndef REGEX char *re_comp(); #elif defined(M_UNIX) extern char *regcmp(), *regex(); #endif #ifdef __STDC__ extern FILE *dataconn(char *name, off_t size, char *mode); #else extern FILE *dataconn(); #endif FILE *dout; time_t newer_time; int show_fullinfo; #ifdef __STDC__ check_newer(char *path, struct stat *st, int flag) #else check_newer(path,st,flag) char *path; struct stat *st; int flag; #endif { if (st->st_mtime > newer_time) { if (show_fullinfo != 0) { if (flag == FTW_F || flag == FTW_D) { fprintf(dout, "%s %d %d %s\n", flag == FTW_F ? "F" : "D", st->st_size, st->st_mtime, path); } } else if (flag == FTW_F) fprintf(dout, "%s\n", path); } return 0; } #if defined(HAVE_STATVFS) int getSize(s) char *s; { int c; struct statvfs buf; if (( c = statvfs(s, &buf)) != 0) return(0); return(buf.f_bavail * buf.f_frsize / 1024); } #elif defined(HAVE_SYS_VFS) int getSize(s) char *s; { int c; struct statfs buf; if (( c = statfs(s, &buf)) != 0) return(0); return(buf.f_bavail * buf.f_bsize / 1024); } #endif /*************************************************************************/ /* FUNCTION : msg_massage */ /* PURPOSE : Scan a message line for magic cookies, replacing them as */ /* needed. */ /* ARGUMENTS : pointer input and output buffers */ /*************************************************************************/ int #ifdef __STDC__ msg_massage(char *inbuf, char *outbuf) #else msg_massage(inbuf,outbuf) char *inbuf; char *outbuf; #endif { char *inptr = inbuf; char *outptr = outbuf; char buffer[MAXPATHLEN]; time_t curtime; int limit; extern struct passwd *pw; struct aclmember *entry = NULL; (void) time(&curtime); (void) acl_getclass(buffer); limit = acl_getlimit(buffer, NULL); while (*inptr) { if (*inptr != '%') *outptr++ = *inptr; else { switch (*++inptr) { case 'E': if ( (getaclentry("email", &entry)) && ARG0 ) sprintf(outptr, "%s", ARG0); break; case 'N': sprintf(outptr, "%d", acl_countusers(buffer)); break; case 'M': sprintf(outptr, "%d", limit); break; case 'T': strncpy(outptr, ctime(&curtime), 24); *(outptr + 24) = '\0'; break; case 'F': #if defined(HAVE_STATVFS) || defined(HAVE_SYS_VFS) sprintf(outptr, "%lu", getSize(".")); #endif break; case 'C': #ifdef HAVE_GETCWD (void) getcwd(outptr, MAXPATHLEN); #else (void) getwd(outptr); #endif break; case 'R': strcpy(outptr, remotehost); break; case 'L': strcpy(outptr, hostname); break; case 'U': strcpy(outptr, pw->pw_name); break; case 's': strncpy(outptr, shuttime, 24); *(outptr + 24) = '\0'; break; case 'd': strncpy(outptr, disctime, 24); *(outptr + 24) = '\0'; break; case 'r': strncpy(outptr, denytime, 24); *(outptr + 24) = '\0'; break; /* KH : cookie %u for RFC931 name */ case 'u': if (authenticated) strncpy(outptr, authuser, 24); else strcpy(outptr,"[unknown]"); *(outptr + 24) = '\0'; break; case '%': *outptr++ = '%'; *outptr = '\0'; break; default: *outptr++ = '%'; *outptr++ = '?'; *outptr = '\0'; break; } while (*outptr) outptr++; } inptr++; } *outptr = '\0'; } /*************************************************************************/ /* FUNCTION : cwd_beenhere */ /* PURPOSE : Return 1 if the user has already visited this directory */ /* via C_WD. */ /* ARGUMENTS : a power-of-two directory function code (README, MESSAGE) */ /*************************************************************************/ int #ifdef __STDC__ cwd_beenhere(int dircode) #else cwd_beenhere(dircode) int dircode; #endif { struct dirlist { struct dirlist *next; int dircode; char dirname[1]; }; static struct dirlist *head = NULL; struct dirlist *curptr; char cwd[MAXPATHLEN]; (void) realpath(".", cwd); for (curptr = head; curptr != NULL; curptr = curptr->next) if (strcmp(curptr->dirname, cwd) == 0) { if (!(curptr->dircode & dircode)) { curptr->dircode |= dircode; return (0); } return (1); } curptr = (struct dirlist *) malloc(strlen(cwd) + 1 + sizeof(struct dirlist)); if (curptr != NULL) { curptr->next = head; head = curptr; curptr->dircode = dircode; strcpy(curptr->dirname, cwd); } return (0); } /*************************************************************************/ /* FUNCTION : show_banner */ /* PURPOSE : Display a banner on the user's terminal before login */ /* ARGUMENTS : reply code to use */ /*************************************************************************/ void #ifdef __STDC__ show_banner(int msgcode) #else show_banner(msgcode) int msgcode; #endif { char *crptr, linebuf[1024], outbuf[1024]; struct aclmember *entry = NULL; FILE *infile; #ifdef VIRTUAL extern int virtual_mode; extern char virtual_banner[]; if (virtual_mode) { infile = fopen(virtual_banner, "r"); if (infile) { while (fgets(linebuf, 255, infile) != NULL) { if ((crptr = strchr(linebuf, '\n')) != NULL) *crptr = '\0'; msg_massage(linebuf, outbuf); lreply(msgcode, "%s", outbuf); } fclose(infile); lreply(msgcode, ""); } } else { #endif /* banner <path> */ while (getaclentry("banner", &entry)) { infile = fopen(ARG0, "r"); if (infile) { while (fgets(linebuf, 255, infile) != NULL) { if ((crptr = strchr(linebuf, '\n')) != NULL) *crptr = '\0'; msg_massage(linebuf, outbuf); lreply(msgcode, "%s", outbuf); } fclose(infile); lreply(msgcode, ""); } } #ifdef VIRTUAL } #endif } /*************************************************************************/ /* FUNCTION : show_message */ /* PURPOSE : Display a message on the user's terminal if the current */ /* conditions are right */ /* ARGUMENTS : reply code to use, LOG_IN|CMD */ /*************************************************************************/ void #ifdef __STDC__ show_message(int msgcode, int mode) #else show_message(msgcode,mode) int msgcode; int mode; #endif { char *crptr, linebuf[1024], outbuf[1024], class[MAXPATHLEN], cwd[MAXPATHLEN]; int show, which; struct aclmember *entry = NULL; FILE *infile; if (cwd_beenhere(1) != 0) return; #ifdef HAVE_GETCWD (void) getcwd(cwd,MAXPATHLEN-1); #else (void) getwd(cwd); #endif (void) acl_getclass(class); /* message <path> [<when> [<class>]] */ while (getaclentry("message", &entry)) { if (!ARG0) continue; show = 0; if (mode == LOG_IN && (!ARG1 || !strcasecmp(ARG1, "login"))) if (!ARG2) show++; else { for (which = 2; (which < MAXARGS) && ARG[which]; which++) if (strcasecmp(class, ARG[which]) == 0) show++; } if (mode == C_WD && ARG1 && !strncasecmp(ARG1, "cwd=", 4) && (!strcmp((ARG1) + 4, cwd) || *(ARG1 + 4) == '*' || !fnmatch((ARG1) + 4, cwd, FNM_PATHNAME))) if (!ARG2) show++; else { for (which = 2; (which < MAXARGS) && ARG[which]; which++) if (strcasecmp(class, ARG[which]) == 0) show++; } if (show && (int)strlen(ARG0) > 0) { infile = fopen(ARG0, "r"); if (infile) { while (fgets(linebuf, 255, infile) != NULL) { if ((crptr = strchr(linebuf, '\n')) != NULL) *crptr = '\0'; msg_massage(linebuf, outbuf); lreply(msgcode, "%s", outbuf); } fclose(infile); lreply(msgcode, ""); } } } } /*************************************************************************/ /* FUNCTION : show_readme */ /* PURPOSE : Display a message about a README file to the user if the */ /* current conditions are right */ /* ARGUMENTS : pointer to ACL buffer, reply code, LOG_IN|C_WD */ /*************************************************************************/ void #ifdef __STDC__ show_readme(int code, int mode) #else show_readme(code,mode) int code; int mode; #endif { char **filelist, class[MAXPATHLEN], cwd[MAXPATHLEN]; int show, which, days; time_t clock; struct stat buf; struct tm *tp; struct aclmember *entry = NULL; if (cwd_beenhere(2) != 0) return; #ifdef HAVE_GETCWD (void) getcwd(cwd,MAXPATHLEN-1); #else (void) getwd(cwd); #endif (void) acl_getclass(class); /* readme <path> {<when>} */ while (getaclentry("readme", &entry)) { if (!ARG0) continue; show = 0; if (mode == LOG_IN && (!ARG1 || !strcasecmp(ARG1, "login"))) if (!ARG2) show++; else { for (which = 2; (which < MAXARGS) && ARG[which]; which++) if (strcasecmp(class, ARG[which]) == 0) show++; } if (mode == C_WD && ARG1 && !strncasecmp(ARG1, "cwd=", 4) && (!strcmp((ARG1) + 4, cwd) || *(ARG1 + 4) == '*' || !fnmatch((ARG1) + 4, cwd, FNM_PATHNAME))) if (!ARG2) show++; else { for (which = 2; (which < MAXARGS) && ARG[which]; which++) if (strcasecmp(class, ARG[which]) == 0) show++; } if (show) { globerr = NULL; filelist = ftpglob(ARG0); if (!globerr) { while (filelist && *filelist) { errno = 0; if (!stat(*filelist, &buf) && (buf.st_mode & S_IFMT) == S_IFREG) { lreply(code, "Please read the file %s", *filelist); (void) time(&clock); tp = localtime(&clock); days = 365 * tp->tm_year + tp->tm_yday; tp = localtime((time_t *)&buf.st_mtime); days -= 365 * tp->tm_year + tp->tm_yday; /* if (days == 0) { lreply(code, " it was last modified on %.24s - Today", ctime((time_t *)&buf.st_mtime)); } else { */ lreply(code, " it was last modified on %.24s - %d day%s ago", ctime((time_t *)&buf.st_mtime), days, days == 1 ? "" : "s"); /* } */ } filelist++; } } } } } /*************************************************************************/ /* FUNCTION : deny_badxfertype */ /* PURPOSE : If user is in ASCII transfer mode and tries to retrieve a */ /* binary file, abort transfer and display appropriate error */ /* ARGUMENTS : message code to use for denial, path of file to check for */ /* binary contents or NULL to assume binary file */ /*************************************************************************/ int #ifdef __STDC__ deny_badasciixfer(int msgcode, char *filepath) #else deny_badasciixfer(msgcode,filepath) int msgcode; char *filepath; #endif { if (type == TYPE_A && !*filepath) { reply(msgcode, "This is a BINARY file, using ASCII mode to transfer will corrupt it."); return (1); } /* The hooks are here to prevent transfers of actual binary files, not * just TAR or COMPRESS mode files... */ return (0); } /*************************************************************************/ /* FUNCTION : is_shutdown */ /* PURPOSE : */ /* ARGUMENTS : */ /*************************************************************************/ int #ifdef __STDC__ is_shutdown(int quiet, int new) #else is_shutdown(quiet, new) int quiet; int new; #endif { static struct tm tmbuf; static struct stat s_last; static time_t last = 0, shut, deny, disc; static int valid; static char text[2048]; struct stat s_cur; FILE *fp; int deny_off, disc_off; time_t curtime = time(NULL); char buf[1024], linebuf[1024]; if (Shutdown[0] == '\0' || stat(Shutdown, &s_cur)) return (0); if (s_last.st_mtime != s_cur.st_mtime) { s_last = s_cur; valid = 0; fp = fopen(Shutdown, "r"); if (fp == NULL) return (0); fgets(buf, sizeof(buf), fp); if (sscanf(buf, "%d %d %d %d %d %d %d", &tmbuf.tm_year, &tmbuf.tm_mon, &tmbuf.tm_mday, &tmbuf.tm_hour, &tmbuf.tm_min, &deny, &disc) != 7) { (void) fclose(fp); return (0); } valid = 1; deny_off = 3600 * (deny / 100) + 60 * (deny % 100); disc_off = 3600 * (disc / 100) + 60 * (disc % 100); tmbuf.tm_year -= 1900; tmbuf.tm_isdst = -1; shut = mktime(&tmbuf); strcpy(shuttime, ctime(&shut)); disc = shut - disc_off; strcpy(disctime, ctime(&disc)); deny = shut - deny_off; strcpy(denytime, ctime(&deny)); text[0] = '\0'; while (fgets(buf, sizeof(buf), fp) != NULL) { msg_massage(buf, linebuf); if ((strlen(text) + strlen(linebuf)) < sizeof(text)) strcat(text, linebuf); } (void) fclose(fp); } if (!valid) return (0); /* if last == 0, then is_shutdown() only called with quiet == 1 so far */ if (last == 0 && !quiet) { autospout = text; /* warn them for the first time */ autospout_free = 0; last = curtime; } /* if a new connection and past deny time, tell caller to drop 'em */ if (new && curtime > deny) return (1); /* if past disconnect time, tell caller to drop 'em */ if (curtime > disc) return (1); /* if less than 60 seconds to disconnection, warn 'em continuously */ if (curtime > (disc - 60) && !quiet) { autospout = text; autospout_free = 0; last = curtime; } /* if less than 15 minutes to disconnection, warn 'em every 5 mins */ if (curtime > (disc - 60 * 15)) { if ((curtime - last) > (60 * 5) && !quiet) { autospout = text; autospout_free = 0; last = curtime; } } /* if less than 24 hours to disconnection, warn 'em every 30 mins */ if (curtime < (disc - 24 * 60 * 60) && !quiet) { if ((curtime - last) > (60 * 30)) { autospout = text; autospout_free = 0; last = curtime; } } /* if more than 24 hours to disconnection, warn 'em every 60 mins */ if (curtime > (disc - 24 * 60 * 60) && !quiet) { if ((curtime - last) >= (24 * 60 * 60)) { autospout = text; autospout_free = 0; last = curtime; } } return (0); } #ifdef __STDC__ newer(char *date, char *path, int showlots) #else newer(date,path,showlots) char *date; char *path; int showlots; #endif { struct tm tm; if (sscanf(date, "%04d%02d%02d%02d%02d%02d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) { tm.tm_year -= 1900; tm.tm_mon--; tm.tm_isdst = -1; newer_time = mktime(&tm); dout = dataconn("file list", (off_t) - 1, "w"); /* dout = dataconn("file list", (off_t)-1, "w", 0); */ transflag++; if (dout != NULL) { show_fullinfo = showlots; #if defined(HAVE_FTW) ftw(path, check_newer, -1); #else treewalk(path, check_newer, -1, NULL); #endif if (ferror(dout) != 0) perror_reply(550, "Data connection"); else reply(226, "Transfer complete."); (void) fclose(dout); data = -1; } } else reply(501, "Bad DATE format"); transflag = 0; } int #ifdef __STDC__ type_match(char *typelist) #else type_match(typelist) char *typelist; #endif { if (anonymous && strcasestr(typelist, "anonymous")) return (1); if (guest && strcasestr(typelist, "guest")) return (1); if (!guest && !anonymous && strcasestr(typelist, "real")) return (1); return (0); } int #ifdef __STDC__ path_compare(char *p1, char *p2) #else path_compare(p1,p2) char *p1; char *p2; #endif { if ( (*p1 == '*' && *(p1 + 1) == '\0') || fnmatch(p1, p2, FNM_PATHNAME) == 0 ) /* 0 means they matched */ return(strlen(p1)); else return(-2); } void #ifdef __STDC__ expand_id(void) #else expand_id() #endif { struct aclmember *entry = NULL; struct passwd *pwent; struct group *grent; char buf[BUFSIZ]; while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) { if (ARG3 && ARG4) { pwent = getpwnam(ARG3); grent = getgrnam(ARG4); if (pwent) sprintf(buf, "%d", pwent->pw_uid); else sprintf(buf, "%d", 0); ARG3 = (char *) malloc(strlen(buf) + 1); strcpy(ARG3, buf); if (grent) sprintf(buf, "%d", grent->gr_gid); else sprintf(buf, "%d", 0); ARG4 = (char *) malloc(strlen(buf) + 1); strcpy(ARG4, buf); endgrent(); } } } int #ifdef __STDC__ fn_check(char *name) #else fn_check(name) char *name; #endif { /* check to see if this is a valid file name... path-filter <type> * <message_file> <allowed_charset> <disallowed> */ struct aclmember *entry = NULL; int j; char *sp; char *path; #ifdef M_UNIX # ifdef REGEX char *regp; # endif #endif #ifdef REGEXEC regex_t regexbuf; regmatch_t regmatchbuf; #endif while (getaclentry("path-filter", &entry) && ARG0 != NULL) { if (type_match(ARG0) && ARG1 && ARG2) { /* * check *only* the basename */ if (path = strrchr(name, '/')) ++path; else path = name; /* is it in the allowed character set? */ #if defined(REGEXEC) if (regcomp(®exbuf, ARG2, REG_EXTENDED) != 0) { reply(553, "REGEX error"); #elif defined(REGEX) if ((sp = regcmp(ARG2, (char *) 0)) == NULL) { reply(553, "REGEX error"); #else if ((sp = re_comp(ARG2)) != 0) { perror_reply(553, sp); #endif return(0); } #if defined(REGEXEC) if (regexec(®exbuf, path, 1, ®matchbuf, 0) != 0) { #elif defined(REGEX) # ifdef M_UNIX regp = regex(sp, path); free(sp); if (regp == NULL) { # else if ((regex(sp, path)) == NULL) { # endif #else if ((re_exec(path)) != 1) { #endif pr_mesg(553, ARG1); reply(553, "%s: Permission denied. (Filename (accept))", name); return(0); } /* is it in any of the disallowed regexps */ for (j = 3; j < MAXARGS; ++j) { /* ARGj == entry->arg[j] */ if (entry->arg[j]) { #if defined(REGEXEC) if (regcomp(®exbuf, entry->arg[j], REG_EXTENDED) != 0) { reply(553, "REGEX error"); #elif defined(REGEX) if ((sp = regcmp(entry->arg[j], (char *) 0)) == NULL) { reply(553, "REGEX error"); #else if ((sp = re_comp(entry->arg[j])) != 0) { perror_reply(553, sp); #endif return(0); } #if defined(REGEXEC) if (regexec(®exbuf, path, 1, ®matchbuf, 0) == 0) { #elif defined(REGEX) # ifdef M_UNIX regp = regex(sp, path); free(sp); if (regp != NULL) { # else if ((regex(sp, path)) != NULL) { # endif #else if ((re_exec(path)) == 1) { #endif pr_mesg(553, ARG1); reply(553, "%s: Permission denied. (Filename (deny))", name); return(0); } } } } } return(1); } int #ifdef __STDC__ dir_check(char *name, uid_t *uid, gid_t *gid, int *valid) #else dir_check(name,uid,gid,valid) char *name; uid_t *uid; gid_t *gid; int *valid; #endif { struct aclmember *entry = NULL; int i, match_value = -1; char *ap2 = NULL, *ap3 = NULL, *ap4 = NULL, *ap6 = NULL; char cwdir[BUFSIZ]; char path[BUFSIZ]; char *sp; extern struct passwd *pw; *valid = 0; /* what's our current directory? */ strcpy(path, name); if (sp = strrchr(path, '/')) *sp = '\0'; else strcpy(path, "."); if ((realpath(path, cwdir)) == NULL) { perror_reply(553, "Could not determine cwdir"); return(-1); } while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) { if ( (!strcmp(ARG0, pw->pw_dir)) && ((i = path_compare(ARG1, cwdir)) >= match_value) ) { match_value = i; ap2 = ARG2; if (ARG3) ap3 = ARG3; else ap3 = NULL; if (ARG4) ap4 = ARG4; else ap4 = NULL; if (ARG6) ap6 = ARG6; else ap6 = NULL; } } if ( ((ap2 && !strcasecmp(ap2, "no")) && (ap3 && strcasecmp(ap3, "dirs"))) || (ap3 && !strcasecmp(ap3, "nodirs")) || (ap6 && !strcasecmp(ap6, "nodirs")) ) { reply(530, "%s: Permission denied. (Upload dirs)", name); return(0); } if (ap3) *uid = atoi(ap3); /* the uid */ if (ap4) { *gid = atoi(ap4); /* the gid */ *valid = 1; } return(1); } int #ifdef __STDC__ upl_check(char *name, uid_t *uid, gid_t *gid, int *f_mode, int *valid) #else upl_check(name,uid,gid,f_mode,valid) char *name; uid_t *uid; gid_t *gid; int *f_mode; int *valid; #endif { int match_value = -1; char cwdir[BUFSIZ]; char path[BUFSIZ]; char *sp; int i; char *ap1 = NULL, *ap2 = NULL, *ap3 = NULL, *ap4 = NULL, *ap5 = NULL; struct aclmember *entry = NULL; extern struct passwd *pw; *valid = 0; /* what's our current directory? */ strcpy(path, name); if (sp = strrchr(path, '/')) *sp = '\0'; else strcpy(path, "."); if ((realpath(path, cwdir)) == NULL) { perror_reply(553, "Could not determine cwdir"); return(-1); } /* we are doing a "best match"... ..so we keep track of what "match * value" we have received so far... */ while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) { if ( (!strcmp(ARG0, pw->pw_dir)) && ((i = path_compare(ARG1, cwdir)) >= match_value) ) { match_value = i; ap1 = ARG1; ap2 = ARG2; if (ARG3) ap3 = ARG3; else ap3 = NULL; if (ARG4) ap4 = ARG4; else ap4 = NULL; if (ARG5) ap5 = ARG5; else ap5 = NULL; } } if (ap3 && ( (!strcasecmp("dirs",ap3)) || (!strcasecmp("nodirs", ap3)) )) ap3 = NULL; /* if we did get matches... ..else don't do any of this stuff */ if (match_value >= 0) { if (!strcasecmp(ap2, "yes")) { if (ap3) *uid = atoi(ap3); /* the uid */ if (ap4) { *gid = atoi(ap4); /* the gid */ *valid = 1; } if (ap5) sscanf(ap5, "%o", f_mode); /* the mode */ } else { reply(553, "%s: Permission denied. (Upload)", name); return(-1); } } else { /* * upload defaults to "permitted" */ return(1); } return(match_value); } int #ifdef __STDC_ del_check(char *name) #else del_check(name) char *name; #endif { int pdelete = 1; struct aclmember *entry = NULL; while (getaclentry("delete", &entry) && ARG0 && ARG1 != NULL) { if (type_match(ARG1)) if (*ARG0 == 'n') pdelete = 0; } /* H* fix: no deletion, period. You put a file here, I get to look at it. */ #ifdef PARANOID pdelete = 0; #endif if (!pdelete) { reply(553, "%s: Permission denied. (Delete)", name); return(0); } else { return(1); } } /* The following is from the Debian add-ons. */ #define lbasename(x) (strrchr(x,'/')?1+strrchr(x,'/'):x) int #ifdef __STDC__ checknoretrieve (char *name) #else checknoretrieve (name) char *name; #endif { char cwd[MAXPATHLEN+1], realwd[MAXPATHLEN+1], realname[MAXPATHLEN+1]; int i; struct aclmember *entry = NULL; if (name == (char *)NULL || *name == '\0') return 0; #ifdef HAVE_GETCWD (void)getcwd (cwd, MAXPATHLEN); #else (void)getwd (cwd); #endif realpath (cwd, realwd); realpath (name, realname); while (getaclentry("noretrieve", &entry)) { if (ARG0 == (char *)NULL) continue; for (i = 0; i< MAXARGS && (entry->arg[i] != (char *)NULL) && (*(entry->arg[i]) !='\0'); i++) if (strcmp (((*(entry->arg[i]) == '/') ? realname : lbasename (realname)), entry->arg[i]) == 0) { reply (550, "%s is marked unretrievable", entry->arg[i]); return 1; } } return 0; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.