/* Copyright (C) 1999 Beau Kuiper This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "ftpd.h" ACLLIST *acllist_create(void) { ACLLIST *newlist = mallocwrapper(sizeof(ACLLIST)); newlist->aclcount = 0; newlist->acls = NULL; return(newlist); } int getaclattr(char *instr) { int result = 0; if (strcasecmp(instr, "ALL") == 0) return(ACL_ADD | ACL_READ | ACL_LIST | ACL_DELETE | ACL_MKDIR | ACL_RMDIR | ACL_WRITE | ACL_CHMOD | ACL_CHDIR | ACL_REPLACE ); else if (strcasecmp(instr, "NONE") == 0) return(0); while(*instr != 0) { /* make sure character is upper case! */ char aclchar = *instr & (255 - 32); switch (aclchar) { case 'A': { result |= ACL_ADD ; break ; } case 'R': { result |= ACL_READ ; break ; } case 'L': { result |= ACL_LIST ; break ; } case 'X': { result |= ACL_REPLACE ; break ; } case 'D': { result |= ACL_DELETE ; break ; } case 'M': { result |= ACL_MKDIR ; break ; } case 'I': { result |= ACL_RMDIR ; break ; } case 'W': { result |= ACL_WRITE ; break ; } case 'H': { result |= ACL_CHMOD ; break ; } case 'C': { result |= ACL_CHDIR ; break ; } default : { log_giveentry(MYLOG_INFO, 0, safe_snprintf("Unknown ACL char %c", aclchar)); } } instr++; } return(result); } /* this assumes ret is at least 10 chars long */ char *acllist_makepermstr(ACLLIST *acl, int cnt, char *ret) { char refchars[10] = { "RALXDMIWHC" }; int count, xcount = 1; strcpy(ret, ""); for (count = 0; count < strlen(refchars); count++) { if (acl->acls[cnt].attr & xcount) strncat(ret, refchars + count, 1); xcount *= 2; } return(ret); } void acllist_add(ACLLIST *acl, char *dir, char *attribs, int is_regexp) { int count; int attr = getaclattr(attribs); /* see if this directory already has an ACL. If it does, combine the ACL attributes if allowed to */ debuglog("adding acl: %s %s", dir, attribs); for (count = 0; count < acl->aclcount; count++) { if (strcmp(acl->acls[count].dir, dir) == 0) { if (!(acl->acls[count].attr & ACL_REPLACE)) acl->acls[count].attr |= attr; return; } } /* if there isn't an ACL yet for this directory, create it here */ reallocwrapper(sizeof(ACL) * (acl->aclcount+1), (void **)&(acl->acls)); acl->acls[acl->aclcount].dir = strdupwrapper(dir); acl->acls[acl->aclcount].regexp = is_regexp; acl->acls[acl->aclcount].attr = attr; acl->aclcount++; } /* void acllist_tokendo(ACLLIST *acl, TOKENSET *tset) { int count; for (count = 0; count < acl->aclcount; count++) acl->acls[count].dir = tokenset_apply(tset, acl->acls[count].dir); } */ int acllist_check(ACLLIST *acl, char *dir, int attr) { int result = 0; char *mydir = strdupwrapper(dir); int len = strlen(dir); int count; debuglog("inacl : %s", dir); /* go through the list and find and test any regexp acls */ for (count = 0; count < acl->aclcount; count++) { if ( acl->acls[count].regexp ) { debuglog( "regexp acl %s, %s\n", mydir, acl->acls[count].dir); if (my_fnmatch( acl->acls[count].dir, mydir, acl->acls[count].regexp == 2 ? FNM_PATHNAME : 0 ) == 0) { result = acl->acls[count].attr; goto gotmatch; } } } /* now do regular dir matches */ while( mydir[0] != 0 ) { char *tmp; debuglog("acl breakdown : %s", mydir); for (count = 0; count < acl->aclcount; count++) { debuglog( "%s, %s\n", mydir, acl->acls[count].dir); if (strcmp( mydir, acl->acls[count].dir ) == 0) { result = acl->acls[count].attr; goto gotmatch; } } if (mydir[len - 1] == '/') len--; mydir[len] = 0; tmp = strrchr(mydir, '/'); if (tmp != NULL) { tmp++; *tmp = 0; len = tmp - mydir; } } result = 0; gotmatch: freewrapper(mydir); if ((result & attr) == attr) return(TRUE); return(FALSE); } void acllist_dest(ACLLIST *acl) { int count; if (acl->aclcount > 0) { for (count = 0; count < acl->aclcount; count++) freewrapper(acl->acls[count].dir); freewrapper(acl->acls); } freewrapper(acl); } int check_acl(FTPSTATE *peer, char *path, int perm) { int ok; ok = acllist_check(peer->acldata, dir_getvirtual(peer, path), perm); errno = 0; if (ok) return(0); else errno = EACCES; return(-1); }