mars-nwe/src/trustee.c

949 lines
29 KiB
C

/* trustee.c 15-Apr-00 */
/* (C)opyright (C) 1998,2000 Martin Stover, Marburg, Germany
*
* 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 of the License, 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.
*/
/* Trusttee routines for mars_nwe */
/* history since 01-Jun-00
*
* mst:01-Jun-00: removed SIG_SEGV in get_eff_rights_by_trustees(),
* when stat error
* mst:01-Sep-00: pcz:added real unix rights patch from Przemyslaw Czerpak
*
*
*/
#include "net.h"
#include <dirent.h>
#include "unxfile.h"
#include "nwvolume.h"
#include "connect.h"
#include "trustee.h"
/* right access routines depending on unix rights */
static int un_nw_rights(int voloptions, uint8 *unixname, struct stat *stb)
/* returns eff rights of file/dir depending on unix rights only */
/* therefore only root gets TRUSTEE_S by this routine */
{
int rights=0xff; /* first all, pconsole needs TRUSTEE_O */
int is_pipe_command=(voloptions & VOL_OPTION_IS_PIPE)
&& !S_ISFIFO(stb->st_mode);
if (act_uid || is_pipe_command || (voloptions & VOL_OPTION_READONLY)) {
int is_dir = S_ISDIR(stb->st_mode);
int norights = TRUSTEE_A; /* no access control rights */
int acc;
int accp=0;
int isaccp=0;
struct stat stbp;
uint8 *p = unixname+strlen(unixname);
/* pcz:01-Sep-00 */
if (voloptions & VOL_OPTION_UNX_RIGHT)
acc=get_unix_access_rights(stb,unixname);
else
acc=get_unix_eff_rights(stb);
memset(&stbp, 0, sizeof(struct stat));
if (p > unixname){ /* now we must get parent rights */
--p;
while (p>unixname && *p=='/') --p; /* remove trailing slash */
while (p>unixname && *p!='/') --p; /* search for slash */
while (p>unixname && *p=='/') --p; /* and remove it */
if (p > unixname) { /* found subdir */
*(p+1)='\0';
if (stat(unixname, &stbp) ||
(stbp.st_dev==stb->st_dev && stbp.st_ino==stb->st_ino)
|| !S_ISDIR(stbp.st_mode) ){
/* something wrong here, clear rights */
errorp(0,"un_nw_rights", "wrong path=%s", unixname);
} else { /* pcz:01-Sep-00 */
if (voloptions & VOL_OPTION_UNX_RIGHT)
accp=get_unix_access_rights(&stbp,unixname);
else
accp=get_unix_eff_rights(&stbp);
isaccp=1;
}
*(p+1)='/';
} else if (!stat("/.", &stbp)) { /* pcz:01-Sep-00 */
if (voloptions & VOL_OPTION_UNX_RIGHT)
accp=get_unix_access_rights(&stbp,"/.");
else
accp=get_unix_eff_rights(&stbp);
isaccp=1;
}
}
if (isaccp == 0) { /* pcz:01-Sep-00 */
XDPRINTF((1,0, "no rights to parentdir of %s", unixname));
norights=rights;
} else {
if (!(accp & X_OK))
norights=rights;
else if (!(accp & W_OK)) {
norights |= TRUSTEE_E; /* no erase right */
norights |= TRUSTEE_M; /* no modify rights */
}
}
if (voloptions & VOL_OPTION_READONLY) {
norights |= TRUSTEE_E; /* no erase right */
norights |= TRUSTEE_M; /* no modify rights */
norights |= TRUSTEE_C; /* no creat rights */
} else if ((!acc||is_dir||is_pipe_command) && !(acc&X_OK)) {
norights = rights;
} else if (is_pipe_command) {
norights |= TRUSTEE_E; /* no erase right */
norights |= TRUSTEE_M; /* no modify rights */
norights |= TRUSTEE_C; /* no creat rights */
}
if (!(acc & 0x30)){ /* if not user and not in groups */
norights |= TRUSTEE_M; /* no modify rights */
}
if (!(acc & W_OK)) {
if (!(acc & 0x10) || (stb->st_uid == default_uid)){
norights |= TRUSTEE_M; /* no modify rights */
}
norights |= TRUSTEE_E; /* no erase */
norights |= TRUSTEE_C; /* no creat */
norights |= TRUSTEE_W; /* no write */
}
if (!(acc & R_OK)) {
norights |= TRUSTEE_R; /* No read rights for files */
if (is_dir)
norights |= TRUSTEE_F; /* no scan rights */
}
rights &= (~norights);
} else
rights |= TRUSTEE_S; /* Root always has all access rights */
return(rights);
}
#define MAX_TRUSTEES 100 /* max. trustee entries for one file/dir */
#define MAX_TRUSTEE_CACHE 50 /* max. trusttees in cache */
typedef struct {
int trustee;
uint32 id;
} IDS_TRUSTEE;
typedef struct {
int volume;
int dev;
int inode;
int idle; /* idle state */
int mode_flags; /*
* &0x01 is directory
* &0x02 is_root
* &0x04 is_symlink
* &0x08 dev changed, will be set by trustees scan
* &0x10 dev differs from volume's dev
* will be set by trustees scan
* is important to prevent trustee changes by
* normal user (not user 'root')
*/
int inherited_mask; /* for all users */
int eff_rights; /* for actual user */
/* trustees for this node */
int trustee_count;
IDS_TRUSTEE *trustees;
} FILE_TRUSTEE_NODE;
typedef struct {
int count;
FILE_TRUSTEE_NODE *tr[MAX_TRUSTEE_CACHE];
} TRUSTEE_CACHE;
static TRUSTEE_CACHE *tr_cache=NULL;
static void free_trustee_node(FILE_TRUSTEE_NODE *tn)
{
if (tn) {
xfree(tn->trustees);
xfree(tn);
}
}
void tru_free_cache(int volume)
/* free's cache for one volume or all volume's if volume == -1 */
{
if (tr_cache) {
int i=tr_cache->count;
while(i--) {
FILE_TRUSTEE_NODE *tr=tr_cache->tr[i];
if (tr && (volume == -1 || tr->volume == volume)){
free_trustee_node(tr);
tr_cache->tr[i]=NULL;
if (i+1 == tr_cache->count)
--tr_cache->count;
}
}
}
if (volume == -1)
xfree(tr_cache);
}
static void add_trustee_node(FILE_TRUSTEE_NODE *trn)
{
if (trn) {
int i;
int max_idle = 0;
int found_idle = -1;
int to_use = -1;
if (!tr_cache)
tr_cache=(TRUSTEE_CACHE*)xcmalloc(sizeof(TRUSTEE_CACHE));
for (i=0;i < tr_cache->count; i++) {
FILE_TRUSTEE_NODE *tr=tr_cache->tr[i];
if (!tr) {
if (to_use < 0) to_use=i;
} else {
if (tr->mode_flags&1) tr->idle++; /* dirs should not become idle so fast */
else tr->idle+=10; /* as files */
if (tr->idle > max_idle) {
found_idle=i;
max_idle=tr->idle;
}
}
}
if (to_use < 0) {
if (tr_cache->count < MAX_TRUSTEE_CACHE)
to_use=tr_cache->count++;
else {
to_use=found_idle;
free_trustee_node(tr_cache->tr[to_use]);
}
}
tr_cache->tr[to_use]=trn;
}
}
static FILE_TRUSTEE_NODE *find_trustee_node(int volume, int dev, int inode)
{
if (vol_trustees_were_changed(volume))
return(NULL);
if (tr_cache) {
int i=-1;
while (++i < tr_cache->count) {
FILE_TRUSTEE_NODE *tr=tr_cache->tr[i];
if (tr && tr->volume == volume && tr->dev == dev && tr->inode == inode){
tr->idle=0;
return(tr);
}
}
}
return(NULL);
}
static int find_id_trustee(FILE_TRUSTEE_NODE *tr, uint32 id)
{
int i=0;
IDS_TRUSTEE *ids=tr->trustees;
while (i++ < tr->trustee_count) {
if (ids->id == id)
return(ids->trustee);
ids++;
}
return(-1); /* not found */
}
static int grps_count=0;
static uint32 *grps_grps=NULL;
static int cmp_uint32(const void *e1, const void *e2)
{
if (*((uint32*)e1) < *((uint32*)e2)) return(-1);
if (*((uint32*)e1) > *((uint32*)e2)) return(1);
return(0);
}
static int grp_exist(uint32 grp_id)
/* returns 1 if grp_id exist */
{
return( (NULL == bsearch(&grp_id, grps_grps,
(size_t)grps_count, (size_t)sizeof(uint32), cmp_uint32))
? 0 : 1);
}
void tru_init_trustees(int count, uint32 *grps)
/* must be called after new loging */
{
tru_free_cache(-1);
xfree(grps_grps);
grps_count=count;
if (count) {
grps_grps=(uint32*)xmalloc(sizeof(uint32) * count);
memcpy(grps_grps, grps, sizeof(uint32) * count);
qsort(grps_grps, (size_t)grps_count, (size_t)sizeof(uint32), cmp_uint32);
}
}
static void creat_trustee_path(int volume, int dev, ino_t inode, uint8 *path)
/* is always called with uid = 0 */
{
char buf[256];
uint8 buf_uc[4];
char volname[100];
if (nw_get_volume_name(volume, volname, sizeof(volname) ) < 1) return;
U32_TO_BE32(inode, buf_uc);
slprintf(buf, sizeof(buf)-1, "%s/%s/%x/%x/%x/%x/n.%x", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3]);
unlink(buf);
if (symlink(path, buf)) {
XDPRINTF((0,0,"creat_trustee_path buf=`%s`, path=`%s` failed", buf, path));
}
}
static int put_trustee_to_disk(int volume, int dev, ino_t inode, uint32 id, int trustee)
/* is always called with uid = 0 */
/* if id=0, it means inherited_mask */
{
char buf[256];
char btrustee[256];
int l;
uint8 buf_uc[4];
char volname[100];
if (nw_get_volume_name(volume, volname, sizeof(volname) ) < 1) return(-0xff);
U32_TO_BE32(inode, buf_uc);
l=slprintf(buf, sizeof(buf)-1, "%s/%s/%x/%x/%x/%x/t.%x", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3]);
unx_xmkdir(buf, 0755);
slprintf(buf+l, sizeof(buf) -l -1, "/%x", (unsigned int) id);
unlink(buf);
l=slprintf(btrustee, sizeof(btrustee)-1, "%04x", (unsigned int) trustee);
return(symlink(btrustee, buf) ? -0xff : 0);
}
static int get_trustee_from_disk(int volume, int dev, ino_t inode, uint32 id, int *trustee)
/*
* if id=0, it means inherited_mask
* return 0 if 0, < 0 if error
*/
{
char buf[256];
char btrustee[256];
int l;
uint8 buf_uc[4];
char volname[100];
if (nw_get_volume_name(volume, volname, sizeof(volname) ) < 1)
return(-0xff);
U32_TO_BE32(inode, buf_uc);
slprintf(buf, sizeof(buf)-1, "%s/%s/%x/%x/%x/%x/t.%x/%x", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3],
(unsigned int)id);
l = readlink(buf, btrustee, 254);
if (l > 0) {
unsigned int utrustee=0;
btrustee[l]='\0';
if (1 == sscanf(btrustee, "%x", &utrustee)) {
*trustee = (int)utrustee;
return(0);
}
}
return(-0xff);
}
static int del_trustee_from_disk(int volume, int dev, ino_t inode, uint32 id)
/* removes users id trustee */
{
char buf[256];
int result=-0xfe; /* no such trustee */
uint8 buf_uc[4];
char volname[100];
if (nw_get_volume_name(volume, volname, sizeof(volname) ) < 1) return(result);
U32_TO_BE32(inode, buf_uc);
slprintf(buf, sizeof(buf)-1, "%s/%s/%x/%x/%x/%x/t.%x/%x", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3],
(unsigned int)id);
seteuid(0);
if (!unlink(buf))
result=0;
reseteuid();
return(result);
}
unsigned int tru_vol_sernum(int volume, int mode)
/* mode == 0, reads sernum, else change sernum, returns new sernum */
{
char volname[100];
char buf[256];
char buf1[20];
int len;
unsigned int sernum=0;
if (nw_get_volume_name(volume, volname, sizeof(volname) ) < 1) return(-1);
slprintf(buf, sizeof(buf)-1, "%s/%s/ts", path_trustees, volname);
len=readlink(buf, buf1, sizeof(buf1)-1);
if (len>0) {
buf1[len]='\0';
if (1!=sscanf(buf1,"%x", &sernum))
sernum=0;
}
if (mode) {
if (++sernum==MAX_U32) sernum=1;
seteuid(0);
unlink(buf);
slprintf(buf1, sizeof(buf1)-1, "%x", sernum);
if (symlink(buf1, buf))
errorp(0, "rw_trustee_sernum", "symlink %s %s failed", buf1, buf);
reseteuid();
tru_free_cache(volume);
}
return(sernum);
}
void tru_free_file_trustees_from_disk(int volume, int dev, ino_t inode)
/* is called if directory/file is removed */
{
char buf[256];
uint8 buf_uc[4];
int len;
char volname[100];
if (nw_get_volume_name(volume, volname, sizeof(volname) ) < 1) return;
U32_TO_BE32(inode, buf_uc);
len=slprintf(buf, sizeof(buf)-1, "%s/%s/%x/%x/%x/%x/", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2]);
slprintf(buf+len, sizeof(buf) - len -1, "t.%x", (int)buf_uc[3]);
seteuid(0);
unx_xrmdir(buf);
/* now we remove the name of the dir/file */
slprintf(buf+len, sizeof(buf) -len -1, "n.%x", (int)buf_uc[3]);
unlink(buf);
reseteuid();
}
int tru_del_trustee(int volume, uint8 *unixname, struct stat *stb, uint32 id)
{
int result=-0x85; /* we say no privileges */
int voloptions = get_volume_options(volume);
if ( (voloptions & VOL_OPTION_TRUSTEES) &&
( (tru_get_eff_rights(volume, unixname, stb) & TRUSTEE_A)
|| (act_id_flags&1)) ) {
result=del_trustee_from_disk(volume, stb->st_dev, stb->st_ino, id);
if (!result)
tru_vol_sernum(volume, 1); /* trustee sernum needs updated */
}
MDEBUG(D_TRUSTEES, {
xdprintf(1,0, "tru_del_trustee: id=%08lx, volume=%d, file=`%s`, result=-0x%x",
id, volume, unixname, -result);
})
return(result);
}
static FILE_TRUSTEE_NODE *create_trustee_node(int volume, int dev,
ino_t inode, int mode_flags)
/*
* mode_flags: &1=directory, &2=root, &4=symlink, &0x8 dev changes
* &0x10 dev differs from volumes dev.
*/
{
char buf[256];
int l;
uint8 buf_uc[4];
DIR *d;
char volname[100];
FILE_TRUSTEE_NODE *tr = (FILE_TRUSTEE_NODE*)xcmalloc(sizeof(FILE_TRUSTEE_NODE));
tr->volume = volume;
tr->dev = dev;
tr->inode = inode;
tr->mode_flags = mode_flags;
tr->inherited_mask = (mode_flags&0xe)
? 0 /* root dir or symlink no rights */
: MAX_TRUSTEE_MASK; /* default all allowed */
tr->eff_rights = -1; /* not yet set */
U32_TO_BE32(inode, buf_uc);
(void)nw_get_volume_name(volume, volname, sizeof(volname) );
l=slprintf(buf, sizeof(buf)-1, "%s/%s/%x/%x/%x/%x/t.%x", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3]);
if (NULL != (d= opendir(buf)) ) {
uint8 *p=buf+l;
struct dirent *dirbuff;
int trustee_count=0;
IDS_TRUSTEE trustees[MAX_TRUSTEES];
*p++ = '/';
while (trustee_count < MAX_TRUSTEES &&
(dirbuff = readdir(d)) != (struct dirent*)NULL){
if (dirbuff->d_ino && dirbuff->d_name[0] != '.') {
char btrustee[255];
int len;
unsigned int id;
if (1 == sscanf(dirbuff->d_name, "%x", &id)) {
len = (int)(p - (uint8*)buf);
strmaxcpy(p, dirbuff->d_name, sizeof(buf) - len -1);
len=readlink(buf, btrustee, 254);
if (len > 0) {
unsigned int utrustee=0;
btrustee[len]='\0';
if (1 == sscanf(btrustee, "%x", &utrustee)) {
if (id) {
trustees[trustee_count].id = (uint32) id;
trustees[trustee_count].trustee = (int) utrustee;
trustee_count++;
} else
tr->inherited_mask=(int)utrustee;
}
}
}
}
} /* while */
closedir(d);
tr->trustee_count=trustee_count;
if (trustee_count) {
tr->trustees=(IDS_TRUSTEE*)xcmalloc(sizeof(IDS_TRUSTEE)*trustee_count);
while (trustee_count--){
tr->trustees[trustee_count].id = trustees[trustee_count].id;
tr->trustees[trustee_count].trustee = trustees[trustee_count].trustee;
}
}
}
return(tr);
}
static FILE_TRUSTEE_NODE *find_creat_add_trustee_node(
int volume, uint8 *unixname, struct stat *stb)
{
FILE_TRUSTEE_NODE *tr=find_trustee_node(volume, stb->st_dev, stb->st_ino);
if (!tr) {
struct stat lstatbuf;
int mode_flags=S_ISDIR(stb->st_mode) ? 1:0;
if ( lstat(unixname, &lstatbuf)
|| (lstatbuf.st_dev != stb->st_dev)
|| (lstatbuf.st_ino != stb->st_ino)
|| S_ISLNK(lstatbuf.st_mode) ) {
mode_flags|=4;
}
tr=create_trustee_node(volume, stb->st_dev, stb->st_ino, mode_flags);
add_trustee_node(tr);
}
return(tr);
}
int tru_get_id_trustee(int volume, uint8 *unixname, struct stat *stb, uint32 id)
/* is called by vol_trustee_scan */
{
int voloptions=get_volume_options(volume);
if (voloptions&VOL_OPTION_TRUSTEES){
FILE_TRUSTEE_NODE *tr=find_creat_add_trustee_node(volume, unixname, stb);
return(find_id_trustee(tr, id));
}
return(-0x85);
}
static FILE_TRUSTEE_NODE *find_build_trustee_node(int volume, uint8 *unixname, struct stat *stb);
static int local_tru_add_trustee_set(int volume, uint8 *unixname,
struct stat *stb,
int count, NW_OIC *nwoic)
{
int voloptions = get_volume_options(volume);
int own_eff_rights;
int result=-0x85; /* we say no privileges */
if ( (voloptions & VOL_OPTION_TRUSTEES) &&
( ((own_eff_rights=tru_get_eff_rights(volume, unixname, stb)) & TRUSTEE_A)
|| (act_id_flags&1) )) {
/* FILE_TRUSTEE_NODE *tr=find_trustee_node(volume, stb->st_dev, stb->st_ino); */
/* mst:11-May-00 */
FILE_TRUSTEE_NODE *tr=find_build_trustee_node(volume, unixname, stb);
if (tr && (!(tr->mode_flags&0x18) || !act_uid)) {
int volumenamelen = get_volume_unixnamlen(volume);
uint8 ufnbuf[2];
uint8 *ufn;
seteuid(0);
while (count--) {
if (! ((own_eff_rights & TRUSTEE_S) || (act_id_flags&1)) ) {
/* only user with TRUSTEE_S are allowed to set TRUSTEE_S */
if (nwoic->trustee&TRUSTEE_S)
nwoic->trustee&=~TRUSTEE_S;
}
result=put_trustee_to_disk(volume, stb->st_dev, stb->st_ino, nwoic->id, nwoic->trustee);
MDEBUG(D_TRUSTEES, {
xdprintf(1,0, "tru_add_trustee_set: id=%08lx, trustee=0x%04x, volume=%d, file=`%s`, result=-0x%x",
nwoic->id, nwoic->trustee, volume, unixname, -result);
})
if (result){
reseteuid();
goto func_err;
}
nwoic++;
}
ufn=unixname+min(strlen(unixname), volumenamelen);
if (!*ufn) { /* is volume direct */
ufn=ufnbuf;
*ufn='.';
*(ufn+1)='\0';
}
creat_trustee_path(volume, stb->st_dev, stb->st_ino, ufn);
reseteuid();
#if 0 /* now in tru_add_trustee_set */
tru_vol_sernum(volume, 1); /* trustee sernum needs updated */
#endif
return(0);
}
}
func_err:
XDPRINTF((1,0, "user %08x tried to add trustees to %s, result=-0x%x",
act_obj_id, unixname, -result));
tru_free_cache(-1);
return(result); /* we say no privileges */
}
int tru_add_trustee_set(int volume, uint8 *unixname,
struct stat *stb,
int count, NW_OIC *nwoic)
{
int result = local_tru_add_trustee_set(volume, unixname, stb, count, nwoic);
if (!result) { /* mst: 13-Apr-00 */
int len = strlen(unixname);
int vollen = get_volume_unixnamlen(volume);
char *p = unixname+len;
char *volp = unixname+vollen;
seteuid(0);
while (--p > volp) {
if (*p == '/') {
struct stat statb;
*p='\0';
if (!stat(unixname, &statb)){
int i;
NW_OIC *poic=nwoic;
for (i=0; i < count; i++) {
int trustee = 0;
if (poic->id) {
get_trustee_from_disk(volume, statb.st_dev, statb.st_ino, poic->id, &trustee);
if ( !(trustee & (TRUSTEE_T|TRUSTEE_F)) ) {
trustee |= TRUSTEE_T;
put_trustee_to_disk(volume, statb.st_dev, statb.st_ino, poic->id, trustee);
}
}
poic++;
}
}
*p='/';
}
}
reseteuid();
tru_vol_sernum(volume, 1); /* trustee sernum needs updated */
}
return (result);
}
int tru_get_trustee_set(int volume, uint8 *unixname,
struct stat *stb,
int sequence,
int maxcount, uint32 *ids, int *trustees)
{
int voloptions = get_volume_options(volume);
if (voloptions & VOL_OPTION_TRUSTEES) {
int offset = sequence*maxcount;
int count = 0;
FILE_TRUSTEE_NODE *tr=find_creat_add_trustee_node(volume, unixname, stb);
while (offset < tr->trustee_count && count < maxcount) {
*ids=tr->trustees[offset].id;
ids++;
*trustees=tr->trustees[offset].trustee;
trustees++;
offset++;
count++;
}
if (count) return(count);
}
return(-0x9c); /* no more trustees */
}
int tru_set_inherited_mask(int volume, uint8 *unixname,
struct stat *stb, int new_mask)
/* sets inherited mask of directory */
{
int voloptions = get_volume_options(volume);
if ( (voloptions & VOL_OPTION_TRUSTEES) &&
( (tru_get_eff_rights(volume, unixname, stb) & TRUSTEE_A)
|| (act_id_flags&1)) ) {
FILE_TRUSTEE_NODE *tr=find_trustee_node(volume, stb->st_dev, stb->st_ino);
if (tr && (!(tr->mode_flags&0x1e) || !act_uid)) {
int result;
seteuid(0);
result=put_trustee_to_disk(volume, stb->st_dev, stb->st_ino, 0L, new_mask);
reseteuid();
if (!result)
tru_vol_sernum(volume, 1); /* trustee sernum needs updated */
return(result);
}
}
return(-0x85); /* we say no privileges */
}
int tru_get_inherited_mask(int volume, uint8 *unixname,
struct stat *stb)
/* returns inherited mask of directory */
{
int voloptions = get_volume_options(volume);
if (voloptions & VOL_OPTION_TRUSTEES){
FILE_TRUSTEE_NODE *tr=find_creat_add_trustee_node(volume, unixname, stb);
return(tr->inherited_mask);
}
return(0x01ff); /* default */
}
static int insert_ugid_trustee(IDS_TRUSTEE *ugid_trustees, int count,
uint32 id, int trustee)
/* return 1 if inserted, else 0 */
{
while (count--) {
if (ugid_trustees->id==id) {
ugid_trustees->trustee|=trustee;
return(0);
}
ugid_trustees++;
}
ugid_trustees->id=id;
ugid_trustees->trustee=trustee;
return(1);
}
static int build_trustee_rights(FILE_TRUSTEE_NODE *tr,
IDS_TRUSTEE *ugid_trustees, int count)
/* this routine must be called root to leaf */
{
if (tr) {
int i = tr->trustee_count;
IDS_TRUSTEE *trn = tr->trustees;
int k = count;
if (tr->mode_flags & (8|4|2)) {
/* dev changed or root volume or symlink */
if ( (tr->mode_flags&2) && (act_id_flags&1) ) {
/* root directory and supervisor equivalences */
/* get all trusttee rights */
if (insert_ugid_trustee(ugid_trustees, count,
act_obj_id, MAX_TRUSTEE_MASK))
count++;
} else {
/* trusteess will not be passed to childs */
while (k--) { /* first we set all to null */
(ugid_trustees+k)->trustee = 0;
}
}
/* inherited_mask will be 0 */
tr->inherited_mask=0;
} else {
while (k--) {
/* trusteess will be passed to childs but */
/* first we mask all with inherited_mask */
(ugid_trustees+k)->trustee &= tr->inherited_mask;
}
}
while (i--) { /* now we read all trustees for this node */
if (trn->id == act_obj_id || grp_exist(trn->id)){
if (insert_ugid_trustee(ugid_trustees, count,
trn->id, trn->trustee))
count++;
}
trn++;
} /* while */
/* now we build eff_rights for this node */
tr->eff_rights=0;
for (k=0; k < count; k++) {
tr->eff_rights |= (ugid_trustees+k)->trustee;
}
}
return(count);
}
static FILE_TRUSTEE_NODE *find_build_trustee_node(int volume, uint8 *unixname, struct stat *stb)
{
FILE_TRUSTEE_NODE *tr=find_creat_add_trustee_node(volume, unixname, stb);
if (tr->eff_rights < 0) { /* now we must rebuild eff rights */
int count=0;
IDS_TRUSTEE *ugid_trustees=
(IDS_TRUSTEE*)xcmalloc((grps_count+1)*sizeof(IDS_TRUSTEE));
struct stat stb1;
(void)get_volume_inode(volume, &stb1);
if (stb1.st_ino != stb->st_ino || stb1.st_dev != stb->st_dev) {
/* is not volumes root */
int volumenamelen = get_volume_unixnamlen(volume);
char *p = unixname+volumenamelen;
int last_dev = stb1.st_dev;
int volumes_dev = stb1.st_dev;
FILE_TRUSTEE_NODE *tr1=find_trustee_node(
volume, stb1.st_dev, stb1.st_ino);
if (!tr1) {
tr1=create_trustee_node(volume, stb1.st_dev, stb1.st_ino, 3);
add_trustee_node(tr1);
} else tr1->mode_flags|=3;
/* build trustees for unix volume */
count=build_trustee_rights(tr1, ugid_trustees, count);
while (*p=='/')++p;
while (NULL != (p=strchr(p, '/'))) {
*p = '\0';
if (!stat(unixname, &stb1)) {
if (stb1.st_ino != stb->st_ino || stb1.st_dev != stb->st_dev) {
int mode_flags=S_ISDIR(stb1.st_mode)?1:0;
tr1=find_trustee_node(volume, stb1.st_dev, stb1.st_ino);
if (last_dev != stb1.st_dev) {
last_dev = stb1.st_dev;
mode_flags |= 0x8;
}
if (volumes_dev != stb1.st_dev)
mode_flags|=0x10;
if (!tr1) {
struct stat lstatbuf;
if ( lstat(unixname, &lstatbuf)
|| (lstatbuf.st_dev != stb1.st_dev)
|| (lstatbuf.st_ino != stb1.st_ino)
|| S_ISLNK(lstatbuf.st_mode) ) {
mode_flags|=4;
}
tr1=create_trustee_node(volume, stb1.st_dev, stb1.st_ino,
mode_flags);
add_trustee_node(tr1);
} else
tr1->mode_flags|=mode_flags;
count=build_trustee_rights(tr1, ugid_trustees, count);
} else {
*p='/';
break;
}
} else {
errorp(10, "tru_get_eff_rights", "stat error `%s`", unixname);
*p='/';
xfree(ugid_trustees);
return(NULL);
}
*p='/';
while (*p=='/')++p;
} /* while */
if (last_dev != stb->st_dev)
tr->mode_flags|=0x8;
if (volumes_dev!=stb->st_dev)
tr->mode_flags|=0x10;
} else {
/* volumes directory */
tr->mode_flags|=(1|2);
}
count=build_trustee_rights(tr, ugid_trustees, count);
xfree(ugid_trustees);
} /* if eff_rights < 0 */
return(tr);
}
static int get_eff_rights_by_trustees(int volume, uint8 *unixname, struct stat *stb)
/* returns the eff. rights the actual user has as real trustees */
{
if ( (act_obj_id == 1) && (act_id_flags&1) ) /* supervisor */
return(MAX_TRUSTEE_MASK); /* all rights */
else {
FILE_TRUSTEE_NODE *tr = find_build_trustee_node(volume, unixname, stb);
return( (tr && tr->eff_rights > -1) ? tr->eff_rights : 0);
}
}
int tru_get_eff_rights(int volume, uint8 *unixname, struct stat *stb)
/* returns the eff. rights the actual user has */
{
int voloptions = get_volume_options(volume);
int rights = 0;
int rights1 = 0;
if (voloptions & VOL_OPTION_TRUSTEES){
rights=(get_eff_rights_by_trustees(volume, unixname, stb) & MAX_TRUSTEE_MASK);
}
if (!(voloptions & VOL_OPTION_IGNUNXRIGHT)){
rights1 = un_nw_rights(voloptions, unixname, stb);
}
MDEBUG(D_TRUSTEES, {
xdprintf(1,0, "eff_rights=%04x,%04x for`%s`",
rights, rights1, unixname);
})
return(rights|rights1);
}
int tru_eff_rights_exists(int volume, uint8 *unixname, struct stat *stb,
int lookfor)
/*
* returns 0 if lookfor right exist,
* otherwise returns the current rights
*/
{
int voloptions = get_volume_options(volume);
int rights = 0;
int rights1 = 0;
int result = -1;
if (voloptions & VOL_OPTION_TRUSTEES){
/* we look for trustee rights first */
rights=get_eff_rights_by_trustees(volume, unixname, stb);
if ((rights & TRUSTEE_S)||((rights&lookfor)==lookfor))
result = 0;
else if ((lookfor == TRUSTEE_T) && (rights&TRUSTEE_F) ) /* mst: 13-Apr-00 */
result=0;
}
if (result && !(voloptions & VOL_OPTION_IGNUNXRIGHT)){
rights1 = un_nw_rights(voloptions, unixname, stb);
}
MDEBUG(D_TRUSTEES, {
xdprintf(1,0, "lookfor=%04x, eff_rights_exists ? = %04x(tru),%04x(unx) for`%s`",
lookfor, rights, rights1, unixname);
})
if (!result) return(0);
rights |= rights1;
if ((lookfor == TRUSTEE_T) && (rights&TRUSTEE_F) ) /* mst: 13-Apr-00 */
return(0);
return(((rights & TRUSTEE_S)||((rights&lookfor)==lookfor)) ? 0 : -1);
}