--- linux/fs/Config.in Thu Jan 3 13:46:06 2002 +++ linux/fs/Config.in Thu Jan 3 13:46:30 2002 @@ -7,7 +7,7 @@ bool 'Quota support' CONFIG_QUOTA tristate 'Kernel automounter support' CONFIG_AUTOFS_FS tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS - +dep_bool ' Linux trustees (ACL) support (EXPERIMENTAL)' CONFIG_TRUSTEES $CONFIG_EXPERIMENTAL dep_tristate 'Reiserfs support' CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL dep_mbool ' Have reiserfs do extra internal checking' CONFIG_REISERFS_CHECK $CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL dep_mbool ' Stats in /proc/fs/reiserfs' CONFIG_REISERFS_PROC_INFO $CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL --- linux/include/linux/fs.h Thu Jan 3 13:46:06 2002 +++ linux/include/linux/fs.h Thu Jan 3 13:52:35 2002 @@ -764,6 +764,15 @@ * non-directories) are allowed, but not unconnected diretories. */ struct semaphore s_nfsd_free_path_sem; + + /* This field is internally used by linux trustees. + * I have no other ideas how to get device name from dentry + */ + #ifdef CONFIG_TRUSTEES + char * dev_name; + #endif + + }; /* @@ -1218,6 +1227,12 @@ extern int bmap(struct inode *, int); extern int notify_change(struct dentry *, struct iattr *); extern int permission(struct inode *, int); +extern int permission(struct inode *, int); +#ifdef CONFIG_TRUSTEES +extern int permission_dentry(struct dentry * dentry,int mask); +#else +#define permission_dentry(DENTRY,MASK) permission(DENTRY->d_inode,MASK) +#endif extern int vfs_permission(struct inode *, int); extern int get_write_access(struct inode *); extern int deny_write_access(struct file *); --- linux/fs/namei.c Thu Jan 3 13:46:06 2002 +++ linux/fs/namei.c Thu Jan 3 13:46:30 2002 @@ -10,6 +10,7 @@ /* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname * lookup logic. + * Linux Trustees support added (c) 1999-2000 Vyacheslav Zavadsky */ /* [Feb-Apr 2000, AV] Rewrite to the new namespace architecture. */ @@ -26,6 +27,11 @@ #include #include +#ifdef CONFIG_TRUSTEES +#include +#endif + + #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) /* [Feb-1997 T. Schoebel-Theuer] @@ -466,7 +472,7 @@ struct qstr this; unsigned int c; - err = permission(inode, MAY_EXEC); + err = permission_dentry(nd->dentry, MAY_EXEC); dentry = ERR_PTR(err); if (err) break; @@ -748,7 +754,7 @@ int err; inode = base->d_inode; - err = permission(inode, MAY_EXEC); + err = permission_dentry(base, MAY_EXEC); dentry = ERR_PTR(err); if (err) goto out; @@ -872,7 +878,7 @@ int error; if (!victim->d_inode || victim->d_parent->d_inode != dir) return -ENOENT; - error = permission(dir,MAY_WRITE | MAY_EXEC); + error = permission_dentry(victim->d_parent,MAY_WRITE | MAY_EXEC); if (error) return error; if (IS_APPEND(dir)) @@ -903,7 +909,7 @@ return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; - return permission(dir,MAY_WRITE | MAY_EXEC); + return permission_dentry(child->d_parent,MAY_WRITE | MAY_EXEC); } /* @@ -1074,7 +1080,7 @@ if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE)) goto exit; - error = permission(inode,acc_mode); + error = permission_dentry(dentry,acc_mode); if (error) goto exit; @@ -1723,7 +1729,7 @@ * we'll need to flip '..'. */ if (new_dir != old_dir) { - error = permission(old_dentry->d_inode, MAY_WRITE); + error = permission_dentry(old_dentry, MAY_WRITE); } if (error) return error; @@ -2032,3 +2038,102 @@ readlink: page_readlink, follow_link: page_follow_link, }; + + + + /* Begin Trustees code */ + + #ifdef CONFIG_TRUSTEES + static int inline trustee_mask_to_normal_mask(int mask, int isdir) { + int r=0; + if ((mask & TRUSTEE_READ_MASK) && !isdir) r |= S_IROTH; + if ((mask & TRUSTEE_READ_DIR_MASK) && isdir) r |= S_IROTH; + if (mask & TRUSTEE_WRITE_MASK) r |= S_IWOTH; + if ((mask & TRUSTEE_BROWSE_MASK) && isdir) r |= S_IXOTH; + if ((mask & TRUSTEE_EXECUTE_MASK) && !isdir) r |= S_IXOTH; + return r; + } + int permission_dentry(struct dentry * dentry,int mask) + { + int p=permission(dentry->d_inode,mask); + int trusteemask; + int mode = dentry->d_inode->i_mode; + struct inode * inode=dentry->d_inode; + int isdir=S_ISDIR(mode); + int res= -EACCES; + + #ifdef TRUSTEE_DEBUG + if (current->fsuid != TRUSTEE_DEBUG_USER) { return p; } + #endif + + if ((mask & S_IWOTH) && IS_RDONLY(inode) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) + { res= -EROFS; /* Nobody gets write access to a read-only fs */ + goto out; + } + else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode)) + {res= -EACCES; /* Nobody gets write access to an immutable file */ + goto out; + } + trusteemask=get_trustee_mask_for_dentry(dentry,current->fsuid); + #ifdef TRUSTEE_DEBUG + printk("dentry_permission is called for %s, trusteemask is %x, unix permission is %d, mask is %x, mode is %x\n", namebuffer, trusteemask,p,mask,mode); + #endif + /* grant superuser priveleges */ + if ( capable(CAP_DAC_OVERRIDE)) + { + #ifdef TRUSTEE_DEBUG + printk("Superuser write permission granted"); + #endif + res=0; + goto out; + } + if ((mask == S_IROTH) || + (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH)))) + if (capable(CAP_DAC_READ_SEARCH)) + { + #ifdef TRUSTEE_DEBUG + printk("Superuser read permission granted"); + #endif + res=0; + goto out; + } + if (trustee_mask_to_normal_mask(trusteemask >> TRUSTEE_NUM_ACL_BITS,isdir) & mask & S_IRWXO) { + #ifdef TRUSTEE_DEBUG + printk(" trustee access denied "); + #endif + return -EACCES;} /* no permission if denied */ + if ((!((trusteemask >> TRUSTEE_NUM_ACL_BITS) & TRUSTEE_USE_UNIX_MASK)) && (trusteemask & TRUSTEE_USE_UNIX_MASK) && (!p)) { + #ifdef TRUSTEE_DEBUG + printk("unix access granted"); + #endif + res=0; + goto out; + } /* grant ordinary unix permission */ + if (!(mode & S_IXOTH) && !((mode >> 3) & S_IXOTH) && !((mode >> 6) & S_IXOTH) && (!isdir) && (mask & S_IXOTH)) return -EACCES; /* execute permission for non-executable file can not be granted */ + if (((trustee_mask_to_normal_mask(trusteemask,isdir) & mask & S_IRWXO) == mask)) + { + #ifdef TRUSTEE_DEBUG + printk("trustee permission granted"); + #endif + res= 0; + goto out; + } + + out: + + return res; + } + #else /* dummy code for sys_set_trustee */ + asmlinkage int sys_set_trustee(const char * name, struct trustee_permission * permission,int command) { + return -ENOSYS; + } + #endif + + /* end trustees code */ + + + + + + --- linux/fs/open.c Thu Jan 3 13:46:06 2002 +++ linux/fs/open.c Thu Jan 3 13:46:30 2002 @@ -2,6 +2,7 @@ * linux/fs/open.c * * Copyright (C) 1991, 1992 Linus Torvalds + * Linux Trustees support added (c) 1999 Vyacheslav Zavadsky */ #include @@ -113,7 +114,7 @@ if (!S_ISREG(inode->i_mode)) goto dput_and_out; - error = permission(inode,MAY_WRITE); + error = permission_dentry(nd.dentry,MAY_WRITE); if (error) goto dput_and_out; @@ -257,7 +258,7 @@ newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { if (current->fsuid != inode->i_uid && - (error = permission(inode,MAY_WRITE)) != 0) + (error = permission_dentry(nd.dentry,MAY_WRITE)) != 0) goto dput_and_out; } error = notify_change(nd.dentry, &newattrs); @@ -301,7 +302,7 @@ newattrs.ia_mtime = times[1].tv_sec; newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { - if ((error = permission(inode,MAY_WRITE)) != 0) + if ((error = permission_dentry(nd.dentry,MAY_WRITE)) != 0) goto dput_and_out; } error = notify_change(nd.dentry, &newattrs); @@ -316,39 +317,45 @@ * We do this by temporarily clearing all FS-related capabilities and * switching the fsuid/fsgid around to the real ones. */ -asmlinkage long sys_access(const char * filename, int mode) +asmlinkage long asmlinkage long sys_access_uid(const char * filename, int mode,uid_t uid,gid_t gid) { struct nameidata nd; int old_fsuid, old_fsgid; kernel_cap_t old_cap; - int res; + int group_ok=0; + int res=-EINVAL; if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ return -EINVAL; - + /* Testing can the user do the operation requested */ + group_ok=capable(CAP_DAC_READ_SEARCH) || in_group_p(gid); + if (capable(CAP_DAC_READ_SEARCH)) goto can_do; + if ((uid==current->uid) || (uid==current->fsuid)) goto can_do; + return res; + can_do: old_fsuid = current->fsuid; old_fsgid = current->fsgid; old_cap = current->cap_effective; - - current->fsuid = current->uid; - current->fsgid = current->gid; + current->fsgid = gid; + current->fsuid = uid; + if ((gid!=current->gid) && !capable(CAP_DAC_READ_SEARCH) && !in_group_p(gid) && !group_ok) goto out; /* Clear the capabilities if we switch to a non-root user */ - if (current->uid) + if (uid) cap_clear(current->cap_effective); else current->cap_effective = current->cap_permitted; res = user_path_walk(filename, &nd); if (!res) { - res = permission(nd.dentry->d_inode, mode); + res = permission_dentry(nd.dentry, mode); /* SuS v2 requires we report a read only fs too */ if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) && !special_file(nd.dentry->d_inode->i_mode)) res = -EROFS; path_release(&nd); } - + out: current->fsuid = old_fsuid; current->fsgid = old_fsgid; current->cap_effective = old_cap; @@ -356,6 +363,11 @@ return res; } + asmlinkage int sys_access(const char * filename, int mode) { + return sys_access_uid(filename,mode,current->uid,current->gid); + } + + asmlinkage long sys_chdir(const char * filename) { int error; @@ -374,7 +386,7 @@ if (error) goto out; - error = permission(nd.dentry->d_inode,MAY_EXEC); + error = permission_dentry(nd.dentry,MAY_EXEC); if (error) goto dput_and_out; @@ -407,7 +419,7 @@ if (!S_ISDIR(inode->i_mode)) goto out_putf; - error = permission(inode, MAY_EXEC); + error = permission_dentry(dentry, MAY_EXEC); if (!error) set_fs_pwd(current->fs, mnt, dentry); out_putf: @@ -434,7 +446,7 @@ if (error) goto out; - error = permission(nd.dentry->d_inode,MAY_EXEC); + error = permission_dentry(nd.dentry,MAY_EXEC); if (error) goto dput_and_out; --- linux/include/linux/trustee.h Thu Jan 3 13:46:06 2002 +++ linux/include/linux/trustee.h Thu Jan 3 13:57:15 2002 @@ -0,0 +1,71 @@ +/* + * (c) 1999-2000 Vyacheslav Zavadsky + * GPLed + */ + +#ifndef _LINUX_TRUSTEE_H +#define _LINUX_TRUSTEE_H +#include +#include +#include +#include +#include + + + + + + + +/* this function evaluates the trustee mask applicable to given name for given user. it is does not checks the trustees for parent and higher levels + +result & TRUSTEE_ACL_MASK - allow mask +(result >> TRUSTEE_NUM_ACL_BITS) & TRUSTEE_ACL_MASK - deny mask +old_mask - the same mask for higher level +*/ +#define TRUSTEE_DEFAULT_MASK TRUSTEE_USE_UNIX_MASK + + +struct trustee_name { + kdev_t dev; + char * filename; + char * devname; /* ONLY if MAJOR(dev)==0 */ + + + +}; + + +extern int get_trustee_mask_for_name(const struct trustee_name * name,uid_t user,int oldmask,int height); + +extern int get_trustee_mask_for_dentry(struct dentry * dentry,uid_t user); + +#define TRUSTEE_INITIAL_HASH_SIZE 4 +#define TRUSTEE_INITIAL_NAME_BUFFER 256 + + +/* name & permission are ignored if command=TRUSTEE_COMMAND_REMOVE_ALL */ +/* permission is ignored if command=TRUSTEE_COMMAND_REMOVE */ + + + +extern int sys_set_trustee(const struct trustee_command * c); + +/*#define TRUSTEE_DEBUG 1*/ +#define TRUSTEE_DEBUG_USER 500 +#endif + + + + + + + + + + + + + + + --- linux/fs/trustee.c Thu Jan 3 13:46:06 2002 +++ linux/fs/trustee.c Thu Jan 3 13:46:30 2002 @@ -0,0 +1,444 @@ +/* + * (c) 1999-2000 Vyacheslav Zavadsky + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct permission_capsule { + struct pemission_capsule * next; + struct trustee_permission permission; +}; +struct trustee_hash_element { + int usage; /* 0 -unused, 1- deleted, 2 - used */ + struct trustee_name name; + struct permission_capsule * list; + +}; +static struct trustee_hash_element * trustee_hash=NULL; +static int trustee_hash_size=0, trustee_hash_used=0, trustee_hash_deleted=0; + + +static inline void free_hash_element_list(struct trustee_hash_element e) { + struct permission_capsule * l1, *l2; + l1=e.list; + while (l1!=NULL) { + l2=l1; + l1=l1->next; + kfree(l2); + } + e.list=NULL; + +} + + +static inline void free_trustee_name(struct trustee_name * name) { + kfree(name->filename); + if (TRUSTEE_HASDEVNAME(*name)) { + kfree(name->devname); + } + +} + + + +static inline void free_hash_element(struct trustee_hash_element e) { + e.usage=1; + free_hash_element_list(e); + free_trustee_name(&e.name); + + +} + +static inline unsigned int hash_string(const char * s) { + unsigned int v=1; + while (*s) { + + v = (v << 2) | (v >> (4*sizeof(v)-2)); + v = (v+(*s))^(*s); + s++; + } + return v; + +} + +static inline unsigned int hash(const struct trustee_name * name ) { + unsigned int v=hash_string(name->filename); + if (TRUSTEE_HASDEVNAME(*name)) { + v^=hash_string(name->devname); + } else { + v^=name->dev; + } + + return v; +} + +static inline int trustee_name_cmp(const struct trustee_name * n1, const struct trustee_name * n2) { + if (TRUSTEE_HASDEVNAME(*n1) && TRUSTEE_HASDEVNAME(*n2)) + return (strcmp(n1->devname,n2->devname)==0) && (strcmp(n1->filename,n2->filename)==0); + else if ((!TRUSTEE_HASDEVNAME(*n1)) && (!TRUSTEE_HASDEVNAME(*n2))) + return ((n1->dev==n2->dev) && (strcmp(n1->filename,n2->filename)==0)); + return 0; + +} + + +static struct trustee_hash_element * get_trustee_for_name(const struct trustee_name * name) { + unsigned int i; + if (trustee_hash==NULL) return NULL; + for (i=hash(name)%trustee_hash_size;trustee_hash[i].usage;i=(i+1)%trustee_hash_size) { + if (trustee_hash[i].usage==1) continue; + #ifdef TRUSTEE_DEBUG + printk("Comparing in get_trustee_for_name %s, dev %x i is %d", name->filename,(int)name->dev,i); + printk(" to %s\n",trustee_hash[i].name.filename); + #endif + if (trustee_name_cmp(&trustee_hash[i].name,name)) return trustee_hash+i; + } + return NULL; + +} + +/* This function does not allocate memory for filename and devname. It should be allocated at calling level */ +static struct trustee_hash_element * getallocate_trustee_for_name(const struct trustee_name * name, int * should_free) { + + struct trustee_hash_element * r,*n; + unsigned int i,j,newsize; + + + lock_kernel(); + *should_free=1; + r=get_trustee_for_name(name); + if (r!=NULL) goto unlock_exit; + + if (trustee_hash==NULL){ +#ifdef TRUSTEE_DEBUG + printk("Building new trustee hash\n"); +#endif + trustee_hash=kmalloc(sizeof(struct trustee_hash_element)*TRUSTEE_INITIAL_HASH_SIZE, GFP_KERNEL); + if (trustee_hash==NULL) { +#ifdef TRUSTEE_DEBUG + printk("Can not allocate memory for trustee hash\n"); +#endif + goto unlock_exit; + } + trustee_hash_size=TRUSTEE_INITIAL_HASH_SIZE; + trustee_hash_used=0; + trustee_hash_deleted=0; + for (i=0;itrustee_hash_size?trustee_hash_size:trustee_hash_size*2; +#ifdef TRUSTEE_DEBUG + printk("Rebuilding trustee hash, oldsize: %d, newsize %d, deleted %d\n",trustee_hash_size,newsize, trustee_hash_deleted); +#endif + n=kmalloc(sizeof(struct trustee_hash_element)*newsize, GFP_KERNEL); + if (n==NULL) { +#ifdef TRUSTEE_DEBUG + printk("Can not allocate memory for trustee hash\n"); +#endif + goto unlock_exit; + } + for (i=0;ilist=NULL; + r->usage=2; +#ifdef TRUSTEE_DEBUG + printk("Added element to trustee hash: j %d, name : %s\n",j,r->name.filename); +#endif + trustee_hash_used++; + + + unlock_exit: + unlock_kernel(); + return r; + + +} + +int get_trustee_mask_for_name( const struct trustee_name * name,uid_t user,int oldmask,int height) +{ + struct trustee_hash_element * e; + int m; + struct permission_capsule * l; + int appl; +#ifdef TRUSTEE_DEBUG + printk("getting trustee mask for %s ", name->filename); +#endif + e=get_trustee_for_name(name); + if (e==NULL) { +#ifdef TRUSTEE_DEBUG + printk("Not found, returning old trustee, %x\n",oldmask); +#endif + return oldmask; + } + for (l=e->list;l!=NULL;l=l->next) { + if ((height<0) && (l->permission.mask & TRUSTEE_ONE_LEVEL_MASK)) continue; + appl=((!(l->permission.mask & TRUSTEE_IS_GROUP_MASK)) && (current->fsuid==l->permission.u.uid)) + || + (((l->permission.mask & TRUSTEE_IS_GROUP_MASK)) && (in_group_p(l->permission.u.gid))) + || + (l->permission.mask & TRUSTEE_ALL_MASK); + if (l->permission.mask & TRUSTEE_NOT_MASK) appl=!appl; + if (!appl) continue; + m=l->permission.mask & TRUSTEE_ACL_MASK; +#ifdef TRUSTEE_DEBUG + printk("Found a suitable trustee, mask %x",l->permission.mask); +#endif + if (l->permission.mask & TRUSTEE_ALLOW_DENY_MASK) m <<= TRUSTEE_NUM_ACL_BITS; + oldmask=l->permission.mask & TRUSTEE_CLEAR_SET_MASK? oldmask & (~m):oldmask | m; + + } +#ifdef TRUSTEE_DEBUG + printk("The new trustee mask is %x\n",oldmask); +#endif + return oldmask; + +} + +int get_trustee_mask_for_dentry(struct dentry * dentry,uid_t user) { + int oldmask=trustee_default_acl; + char * namebuffer, * buf2; + int i,j,k; + char c; + int bufsize; + int slashes=1; + int slash=1; + struct trustee_name name; + struct list_head *pos; + struct vfsmount * mnt; + int isdir=S_ISDIR(dentry->d_inode->i_mode); +#ifdef TRUSTEE_DEBUG + if (user!= TRUSTEE_DEBUG_USER) return trustee_default_acl; +#endif + /* debug */ if (dentry->d_parent==NULL) { +#ifdef TRUSTEE_DEBUG + printk("d_parent is null"); +#endif + return trustee_default_acl; + } + /* debug */ if (dentry->d_name.name==NULL) { +#ifdef TRUSTEE_DEBUG + printk("name is null"); +#endif + return trustee_default_acl; + } + namebuffer=kmalloc(TRUSTEE_INITIAL_NAME_BUFFER,GFP_KERNEL); + if (!namebuffer) return trustee_default_acl; + bufsize=TRUSTEE_INITIAL_NAME_BUFFER; + *namebuffer='/'; + namebuffer[1]=0; + i=1; + for (;;) { + if (IS_ROOT(dentry)) break; + j=i+strlen(dentry->d_name.name); + if (j+1>=bufsize) { /*reallocating the buffer*/ + while (j+1>=bufsize) bufsize*=2; + buf2=kmalloc(bufsize,GFP_KERNEL); + if (!buf2) { + kfree(namebuffer); + return trustee_default_acl; + } + strcpy(buf2,namebuffer); + kfree(namebuffer); + namebuffer=buf2; + + } + for (k=0;dentry->d_name.name[k];k++) + namebuffer[j-1-k]=dentry->d_name.name[k]; + i=j; + namebuffer[i++]='/'; + slashes++; + dentry=dentry->d_parent; + } + namebuffer[i]=0; + // + // The path is found, reversing the buffer + // + for (j=0;jd_sb->s_dev; + name.devname=NULL; + + j=1; + for (;;) { + c=namebuffer[j]; + namebuffer[j]=0; + if (TRUSTEE_HASDEVNAME(name)) { + name.devname=dentry->d_sb->dev_name; + oldmask=get_trustee_mask_for_name(&name,user,oldmask,slash-slashes+!isdir); + } else + oldmask=get_trustee_mask_for_name(&name,user,oldmask,slash-slashes+!isdir); + slash++; + namebuffer[j]=c; + for (j++;(j=i) break; + } + kfree(namebuffer); + return oldmask; + +} + + + + +static int prepare_trustee_name(const struct trustee_command * c, struct trustee_name * name) { + name->dev=to_kdev_t(c->dev); + name->filename=kmalloc((strlen(c->filename)+1)*sizeof(char),GFP_KERNEL); + if (!name->filename) { + printk("No memory to allocate for temporary name buffer"); + return 0; + } + copy_from_user(name->filename,c->filename,(strlen(c->filename)+1)*sizeof(char)); + + if (TRUSTEE_HASDEVNAME(*name)) { + name->devname=kmalloc((strlen(c->devname)+1)*sizeof(char),GFP_KERNEL); + if (!name->devname) { + printk("No memory to allocate for temporary device buffer"); + kfree(name->filename); + + return 0; + } + copy_from_user(name->devname,c->devname,(strlen(c->devname)+1)*sizeof(char)); + } + return 1; +} +asmlinkage int sys_set_trustee(const struct trustee_command * command) { + int r=-ENOSYS, i; + struct trustee_name name; + struct trustee_hash_element * e; + struct permission_capsule * capsule; + int should_free; + struct trustee_command c; + copy_from_user(&c,command,sizeof(c)); +#ifdef TRUSTEE_DEBUG + printk("set trustee called, command %d", c.command); +#endif + if ((current->euid!=0) && !capable(CAP_SYS_ADMIN)) return -EACCES; + lock_kernel(); + switch (c.command) { + case TRUSTEE_COMMAND_REMOVE_ALL : + r=0; + if (trustee_hash==NULL) goto unlk; + for (i=0;ipermission=c.permission; + capsule->next=e->list; + e->list=capsule; + r=0; + if (should_free) free_trustee_name(&name); + + goto unlk; + + case TRUSTEE_COMMAND_ADD: + if (!prepare_trustee_name(&c,&name)) { + r=-ENOMEM; + goto unlk; + } + e=getallocate_trustee_for_name(&name,&should_free); + if (e==NULL) { + r=-ENOMEM; + if (should_free) free_trustee_name(&name); + goto unlk; + } + + capsule=kmalloc(sizeof(struct permission_capsule),GFP_KERNEL); + capsule->permission=c.permission; + capsule->next=e->list; + e->list=capsule; + r=0; + if (should_free) free_trustee_name(&name); + goto unlk; + + + } + unlk: + unlock_kernel(); + return r; +} + + + + + + + + + + + + + + + + + + + --- linux/fs/Makefile Thu Jan 3 13:46:06 2002 +++ linux/fs/Makefile Thu Jan 3 13:46:30 2002 @@ -21,6 +21,9 @@ else obj-y += noquot.o endif +ifeq ($(CONFIG_TRUSTEES),y) +obj-y += trustee.o +endif subdir-$(CONFIG_PROC_FS) += proc subdir-y += partitions --- linux/include/linux/trustee_struct.h Thu Jan 3 13:46:06 2002 +++ linux/include/linux/trustee_struct.h Thu Jan 3 13:57:15 2002 @@ -0,0 +1,86 @@ +/* + * (c) 1999-2000 Vyacheslav Zavadsky + */ + +#ifndef _LINUX_TRUSTEE_STRUCT_H + +#define _LINUX_TRUSTEE_STRUCT_H +#include + + + +#define TRUSTEE_EXECUTE_BIT 0 +#define TRUSTEE_READ_BIT 1 +#define TRUSTEE_WRITE_BIT 2 +#define TRUSTEE_BROWSE_BIT 3 +#define TRUSTEE_READ_DIR_BIT 4 +#define TRUSTEE_USE_UNIX_BIT 5 +#define TRUSTEE_NUM_ACL_BITS (TRUSTEE_USE_UNIX_BIT+1) +#define TRUSTEE_EXECUTE_MASK (1 << TRUSTEE_EXECUTE_BIT) +#define TRUSTEE_READ_MASK (1 << TRUSTEE_READ_BIT) +#define TRUSTEE_WRITE_MASK (1 << TRUSTEE_WRITE_BIT) +#define TRUSTEE_BROWSE_MASK (1 << TRUSTEE_BROWSE_BIT) +#define TRUSTEE_READ_DIR_MASK (1 << TRUSTEE_READ_DIR_BIT) +#define TRUSTEE_USE_UNIX_MASK (1 << TRUSTEE_USE_UNIX_BIT) +#define TRUSTEE_ACL_MASK ((1 << TRUSTEE_NUM_ACL_BITS)-1) + +#define TRUSTEE_ALLOW_DENY_BIT 7 +#define TRUSTEE_IS_GROUP_BIT 6 +#define TRUSTEE_CLEAR_SET_BIT 8 +#define TRUSTEE_ONE_LEVEL_BIT 9 +#define TRUSTEE_NOT_BIT 10 +#define TRUSTEE_ALL_BIT 11 +#define TRUSTEE_ALLOW_DENY_MASK (1 << TRUSTEE_ALLOW_DENY_BIT) /* set if deny */ +#define TRUSTEE_IS_GROUP_MASK (1 << TRUSTEE_IS_GROUP_BIT) +#define TRUSTEE_CLEAR_SET_MASK (1 << TRUSTEE_CLEAR_SET_BIT) /* set if clear */ +#define TRUSTEE_ONE_LEVEL_MASK (1 << TRUSTEE_ONE_LEVEL_BIT) +#define TRUSTEE_NOT_MASK (1 << TRUSTEE_NOT_BIT) +#define TRUSTEE_ALL_MASK (1 << TRUSTEE_ALL_BIT) + +#define trustee_acl __u16 +#define trustee_default_acl TRUSTEE_USE_UNIX_MASK + + + + +struct trustee_permission { + trustee_acl mask; + union { + __kernel_uid_t uid; + __kernel_gid_t gid; + } u; +}; + + + +struct trustee_command { + int command; + struct trustee_permission permission; + int dev; + char * filename; + char * devname; +}; + + + +#define TRUSTEE_HASDEVNAME(TNAME) (MAJOR((TNAME).dev)==0) + +#define TRUSTEE_COMMAND_ADD 1 +#define TRUSTEE_COMMAND_REPLACE 2 +#define TRUSTEE_COMMAND_REMOVE_ALL 3 +#define TRUSTEE_COMMAND_REMOVE 4 + +#endif + + + + + + + + + + + + + --- linux/Documentation/Configure.help Thu Jan 3 13:46:06 2002 +++ linux/Documentation/Configure.help Thu Jan 3 13:46:30 2002 @@ -19794,6 +19794,10 @@ "Area6" will work for most boards. For ADX, select "Area5". +Linux trustees (ACL) support +CONFIG_TRUSTEES + This code allow to use special objects "trustees" to manage rights to files and directories. See http://www.braysystems.com/linux/trustees.html + # # m68k-specific kernel options # Documented by Chris Lawrence et al. --- linux/CREDITS Thu Jan 3 13:46:06 2002 +++ linux/CREDITS Thu Jan 3 13:46:30 2002 @@ -3229,6 +3229,15 @@ S: Tokyo 153 S: Japan +N: Vyacheslav Zavadsky +E: zavadsky@bigfoot.com +D: Linux trustees code +S: 707-2995 Albion Rd North +S: Ottawa, ON, K1V8Z2 +S: Canada + + + N: Orest Zborowski E: orestz@eskimo.com D: XFree86 and kernel development --- linux/fs/exec.c Thu Jan 3 13:46:06 2002 +++ linux/fs/exec.c Thu Jan 3 13:46:30 2002 @@ -116,7 +116,7 @@ if (!S_ISREG(nd.dentry->d_inode->i_mode)) goto exit; - error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC); + error = permission_dentry(nd.dentry, MAY_READ | MAY_EXEC); if (error) goto exit; @@ -351,7 +351,7 @@ file = ERR_PTR(-EACCES); if (!(nd.mnt->mnt_flags & MNT_NOEXEC) && S_ISREG(inode->i_mode)) { - int err = permission(inode, MAY_EXEC); + int err = permission_dentry(nd.dentry, MAY_EXEC); if (!err && !(inode->i_mode & 0111)) err = -EACCES; file = ERR_PTR(err); @@ -569,7 +569,7 @@ de_thread(current); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || - permission(bprm->file->f_dentry->d_inode,MAY_READ)) + permission_dentry(bprm->file->f_dentry,MAY_READ)) current->mm->dumpable = 0; /* An exec changes our domain. We are no longer part of the thread --- linux/fs/nfsd/vfs.c Thu Jan 3 13:46:06 2002 +++ linux/fs/nfsd/vfs.c Thu Jan 3 13:46:30 2002 @@ -1546,11 +1546,11 @@ acc &= ~ MAY_OWNER_OVERRIDE; /* This bit is no longer needed, and gets in the way later */ - err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC)); + err = permission_dentry(dentry, acc & (MAY_READ|MAY_WRITE|MAY_EXEC)); /* Allow read access to binaries even when mode 111 */ if (err == -EACCES && S_ISREG(inode->i_mode) && acc == MAY_READ) - err = permission(inode, MAY_EXEC); + err = permission_dentry(dentry, MAY_EXEC); return err? nfserrno(err) : 0; } --- linux/fs/hpfs/namei.c Thu Jan 3 13:46:06 2002 +++ linux/fs/hpfs/namei.c Thu Jan 3 13:46:30 2002 @@ -334,7 +334,7 @@ goto ret; d_drop(dentry); if (atomic_read(&dentry->d_count) > 1 || - permission(inode, MAY_WRITE) || + permission_dentry(dentry, MAY_WRITE) || get_write_access(inode)) { d_rehash(dentry); goto ret; --- linux/fs/super.c Thu Jan 3 13:46:06 2002 +++ linux/fs/super.c Thu Jan 3 13:46:30 2002 @@ -282,8 +282,12 @@ static inline void __put_super(struct super_block *sb) { spin_lock(&sb_lock); - if (!--sb->s_count) + if (!--sb->s_count) { + #ifdef CONFIG_TRUSTEES + if (sb->dev_name) kfree(sb->dev_name); + #endif kfree(sb); + } spin_unlock(&sb_lock); } @@ -447,6 +451,7 @@ { struct super_block * s; s = alloc_super(); + /*printk("SLAVA: Reading superblock\n");*/ if (!s) goto out; s->s_dev = dev; @@ -863,8 +868,21 @@ mnt->mnt_root = dget(sb->s_root); mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; + #ifdef CONFIG_TRUSTEES + if (name && (!sb->dev_name)) { + sb->dev_name = kmalloc(strlen(name)+1, GFP_KERNEL); + if (sb->dev_name) + strcpy(sb->dev_name, name); + } + #endif up_write(&sb->s_umount); fs_out: + /* SLAVA + if (name != NULL) + printk("SLAVA: Mounting device %s , superblock is %x : %s\n",name,sb,sb->dev_name); + else + printk("SLAVA: Mounting unnamed superblock is %x\n",sb); + */ put_filesystem(fstype); return mnt; } --- linux/net/unix/af_unix.c Thu Jan 3 13:46:06 2002 +++ linux/net/unix/af_unix.c Thu Jan 3 13:46:30 2002 @@ -596,7 +596,7 @@ err = path_walk(sunname->sun_path, &nd); if (err) goto fail; - err = permission(nd.dentry->d_inode,MAY_WRITE); + err = permission_dentry(nd.dentry,MAY_WRITE); if (err) goto put_fail; --- linux/kernel/ksyms.c Thu Jan 3 13:46:06 2002 +++ linux/kernel/ksyms.c Thu Jan 3 13:46:30 2002 @@ -182,6 +182,9 @@ EXPORT_SYMBOL(fsync_no_super); EXPORT_SYMBOL(permission); EXPORT_SYMBOL(vfs_permission); +#ifdef CONFIG_TRUSTEES +EXPORT_SYMBOL(permission_dentry); +#endif EXPORT_SYMBOL(inode_setattr); EXPORT_SYMBOL(inode_change_ok); EXPORT_SYMBOL(write_inode_now); --- linux/fs/proc/root.c Thu Jan 3 13:46:06 2002 +++ linux/fs/proc/root.c Thu Jan 3 13:46:30 2002 @@ -61,6 +61,9 @@ #ifdef CONFIG_PPC_RTAS proc_rtas_init(); #endif +#ifdef CONFIG_TRUSTEES + proc_trustee_init(); +#endif proc_bus = proc_mkdir("bus", 0); } --- linux/fs/proc/trustee.c Thu Jan 3 13:46:06 2002 +++ linux/fs/proc/trustee.c Thu Jan 3 13:46:30 2002 @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + Daniel Podlejski , 2001.03.06 + trustee syscall number is now avaliable + in /proc/trustee/syscall + Vyacheslav Zavadsky - integration + Martin Devera, devik@cdi.cz - trustees syscall replacement +*/ + +/* + * The /proc/trustee directory inodes... + */ + +static struct proc_dir_entry *proc_trustee_syscall; + +/* + * This is the handler for /proc/trustee/syscall + */ + +static int trustee_syscall_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + strcpy (page,"0"); /* indicate no syscall available */ + return 1; + +} + +/* write to /proc/trustee/syscall replaces set_trustee syscall */ +static int trustee_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int rv; + if (count != sizeof(struct trustee_command)) return -EINVAL; + rv = sys_set_trustee ((struct trustee_command *)buffer); + if (rv < 0) return rv; + return count; +} + + +/* + * Called by proc_root_init() to initialize the /proc/trustee subtree + */ + +void __init proc_trustee_init(void) +{ + struct proc_dir_entry *ent; + + ent = create_proc_entry("trustee", S_IFDIR, 0); + if (!ent) return; + + ent = create_proc_entry("trustee/syscall", 0, 0); + ent->read_proc = trustee_syscall_read_proc; + ent->write_proc = trustee_write_proc; +} + + + + + + + + + + + + + --- linux/fs/proc/Makefile Thu Jan 3 13:46:06 2002 +++ linux/fs/proc/Makefile Thu Jan 3 13:46:30 2002 @@ -18,4 +18,8 @@ obj-y += proc_devtree.o endif +ifeq ($(CONFIG_TRUSTEES),y) +obj-y += trustee.o +endif + include $(TOPDIR)/Rules.make --- linux/fs/namespace.c Thu Jan 3 13:46:06 2002 +++ linux/fs/namespace.c Thu Jan 3 13:46:30 2002 @@ -418,7 +418,7 @@ if (current->uid != nd->dentry->d_inode->i_uid) return -EPERM; } - if (permission(nd->dentry->d_inode, MAY_WRITE)) + if (permission_dentry(nd->dentry, MAY_WRITE)) return -EPERM; return 0; #endif