/* 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);
}
syntax highlighted by Code2HTML, v. 0.9.1