--- linux/fs/Config.in	Mon Jun  7 09:48:58 1999
+++ linux/fs/Config.in	Mon Jun  7 09:49:36 1999
@@ -6,7 +6,9 @@
 
 bool	 'Quota support' CONFIG_QUOTA
 tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
-
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool ' Linux trustees (ACL) support  (EXPERIMENTAL)' CONFIG_TRUSTEES
+fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'ADFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS
--- linux/include/linux/fs.h	Mon Jun  7 09:48:58 1999
+++ linux/include/linux/fs.h	Mon Jun  7 09:59:28 1999
@@ -799,6 +799,11 @@
 extern int bmap(struct inode * inode,int block);
 extern int notify_change(struct dentry *, struct iattr *);
 extern int permission(struct inode * inode,int mask);
+#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 get_write_access(struct inode *inode);
 extern void put_write_access(struct inode *inode);
 extern struct dentry * open_namei(const char * pathname, int flag, int mode);
--- linux/fs/namei.c	Mon Jun  7 09:48:59 1999
+++ linux/fs/namei.c	Mon Jun  7 11:04:24 1999
@@ -10,6 +10,7 @@
 
 /* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname
  * lookup logic.
+ *  Linux Trustees support added (c) 1999 Vyacheslav Zavadsky
  */
 
 #include <linux/mm.h>
@@ -24,7 +25,9 @@
 #include <asm/pgtable.h>
 
 #include <asm/namei.h>
-
+#ifdef  CONFIG_TRUSTEES
+#include <linux/trustee.h>
+#endif
 /* This can be removed after the beta phase. */
 #define CACHE_SUPERVISE	/* debug the correctness of dcache entries */
 #undef DEBUG		/* some other debugging */
@@ -334,7 +337,7 @@
 		unsigned int flags;
 		unsigned int c;
 
-		err = permission(inode, MAY_EXEC);
+		err = permission_dentry(base, MAY_EXEC);
 		dentry = ERR_PTR(err);
  		if (err)
 			break;
@@ -500,7 +503,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))
@@ -531,7 +534,7 @@
 static inline int may_create(struct inode *dir, struct dentry *child) {
 	if (child->d_inode)
 		return -EEXIST;
-	return permission(dir,MAY_WRITE | MAY_EXEC);
+	return permission_dentry(child->d_parent,MAY_WRITE | MAY_EXEC);
 }
 
 static inline struct dentry *get_parent(struct dentry *dentry)
@@ -738,7 +741,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;
 
@@ -1265,7 +1268,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;
@@ -1404,3 +1407,95 @@
 	unlock_kernel();
 	return error;
 }
+
+
+/* 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,isdir;
+        int mode = dentry->d_inode->i_mode;
+        char namebuffer[PATH_MAX+NAME_MAX+1];
+	struct inode * inode=dentry->d_inode;
+	#ifdef TRUSTEE_DEBUG
+	if (current->fsuid != 500) {  return p; }
+	#endif
+
+	if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
+		 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
+		return -EROFS; /* Nobody gets write access to a read-only fs */
+	else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
+		return -EACCES; /* Nobody gets write access to an immutable file */
+	
+	isdir=S_ISDIR(mode);
+        trusteemask=get_trustee_mask_for_dentry(dentry,current->fsuid,namebuffer);
+	#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
+			return 0;
+		}
+        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
+				return 0;
+			}
+	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
+		return 0;
+	} /* 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
+			return 0;
+		}
+	
+	
+	return -EACCES;	 
+}
+#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	Mon Jun  7 09:48:59 1999
+++ linux/fs/open.c	Mon Jun  7 09:49:36 1999
@@ -2,6 +2,7 @@
  *  linux/fs/open.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Linux Trustees support added (c) 1999 Vyacheslav Zavadsky
  */
 
 #include <linux/mm.h>
@@ -105,7 +106,7 @@
 	if (S_ISDIR(inode->i_mode))
 		goto dput_and_out;
 
-	error = permission(inode,MAY_WRITE);
+	error = permission_dentry(dentry,MAY_WRITE);
 	if (error)
 		goto dput_and_out;
 
@@ -215,7 +216,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(dentry,MAY_WRITE)) != 0)
 			goto dput_and_out;
 	}
 	error = notify_change(dentry, &newattrs);
@@ -262,7 +263,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(dentry,MAY_WRITE)) != 0)
 			goto dput_and_out;
 	}
 	error = notify_change(dentry, &newattrs);
@@ -278,12 +279,19 @@
  * We do this by temporarily clearing all FS-related capabilities and
  * switching the fsuid/fsgid around to the real ones.
  */
-asmlinkage int sys_access(const char * filename, int mode)
+
+asmlinkage int sys_access_uid(const char * filename, int mode,uid_t uid,gid_t gid)
 {
 	struct dentry * dentry;
 	int old_fsuid, old_fsgid;
 	kernel_cap_t old_cap;
+	int group_ok=0;
 	int res = -EINVAL;
+	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:
 
 	lock_kernel();
 	if (mode != (mode & S_IRWXO))	/* where's F_OK, X_OK, W_OK, R_OK? */
@@ -292,11 +300,12 @@
 	old_fsgid = current->fsgid;
 	old_cap = current->cap_effective;
 
-	current->fsuid = current->uid;
-	current->fsgid = current->gid;
+	current->fsuid = uid;
+        if ((gid!=current->gid) && !capable(CAP_DAC_READ_SEARCH) && !in_group_p(gid) && !group_ok) goto out; 
+	current->fsgid = gid;
 
 	/* 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;
@@ -304,7 +313,7 @@
 	dentry = namei(filename);
 	res = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
-		res = permission(dentry->d_inode, mode);
+		res = permission_dentry(dentry, mode);
 		/* SuS v2 requires we report a read only fs too */
 		if(!res && (mode & S_IWOTH) && IS_RDONLY(dentry->d_inode))
 			res = -EROFS;
@@ -319,6 +328,11 @@
 	return res;
 }
 
+asmlinkage int sys_access(const char * filename, int mode) {
+	return sys_access_uid(filename,mode,current->uid,current->gid);
+}
+
+
 asmlinkage int sys_chdir(const char * filename)
 {
 	int error;
@@ -338,7 +352,7 @@
 	if (!S_ISDIR(inode->i_mode))
 		goto dput_and_out;
 
-	error = permission(inode,MAY_EXEC);
+	error = permission_dentry(dentry,MAY_EXEC);
 	if (error)
 		goto dput_and_out;
 
@@ -378,7 +392,7 @@
 	if (!S_ISDIR(inode->i_mode))
 		goto out_putf;
 
-	error = permission(inode, MAY_EXEC);
+	error = permission_dentry(dentry, MAY_EXEC);
 	if (!error) {
 		struct dentry *tmp = current->fs->pwd;
 		current->fs->pwd = dget(dentry);
@@ -410,7 +424,7 @@
 	if (!S_ISDIR(inode->i_mode))
 		goto dput_and_out;
 
-	error = permission(inode,MAY_EXEC);
+	error = permission_dentry(dentry,MAY_EXEC);
 	if (error)
 		goto dput_and_out;
 
--- linux/include/linux/trustee.h	Mon Jun  7 09:48:59 1999
+++ linux/include/linux/trustee.h	Mon Jun  7 09:49:36 1999
@@ -0,0 +1,51 @@
+/* 
+ *  (c) 1999 Vyacheslav Zavadsky
+ */
+
+#ifndef _LINUX_TRUSTEE_H
+#define _LINUX_TRUSTEE_H
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/dcache.h>
+#include <linux/trustee_struct.h>
+
+
+
+
+
+
+/* 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
+
+extern int  get_trustee_mask_for_name(char * name,uid_t user,int oldmask); 
+
+extern int get_trustee_mask_for_dentry(struct dentry * dentry,uid_t user,char * namebuffer);
+
+#define TRUSTEE_INITIAL_HASH_SIZE 4
+/* name & permission are ignored if command=TRUSTEE_COMMAND_REMOVE_ALL */ 
+/*  permission is ignored if command=TRUSTEE_COMMAND_REMOVE */ 
+extern int sys_set_trustee(const char * name, struct trustee_permission *  permission,int command); 
+
+/*#define TRUSTEE_DEBUG*/
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- linux/fs/trustee.c	Mon Jun  7 09:48:59 1999
+++ linux/fs/trustee.c	Mon Jun  7 11:04:18 1999
@@ -0,0 +1,352 @@
+/* 
+ *  (c) 1999 Vyacheslav Zavadsky
+ */
+
+#include <linux/fs.h>
+#include <linux/dcache.h>
+#include <linux/trustee.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/limits.h>
+#define IS_VFS_ROOT(DENTRY) (IS_ROOT(DENTRY) && (DENTRY->d_covers==DENTRY))
+struct permission_capsule {
+	struct pemission_capsule * next;
+	struct trustee_permission permission;
+};
+struct trustee_hash_element {
+	int usage; /* 0 -unused, 1- deleted, 2 - used */
+	char * 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_hash_element(struct trustee_hash_element  e) {
+	e.usage=1;
+	free_hash_element_list(e);
+	kfree(e.name);
+	
+       
+}
+
+static inline unsigned int hash(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 struct trustee_hash_element  * get_trustee_for_name(const char * 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, i is %d", name,i);
+		printk(" to %s\n",trustee_hash[i].name);
+		#endif
+		if (strcmp(trustee_hash[i].name,name)==0) return trustee_hash+i;
+	}
+	return NULL;
+
+}
+static struct trustee_hash_element  * getallocate_trustee_for_name(const char * name) {
+
+	struct trustee_hash_element  * r,*n;
+	unsigned int i,j,newsize;
+
+	lock_kernel();
+	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;i<trustee_hash_size;i++) trustee_hash[i].usage=0;
+	}
+	
+	if ((trustee_hash_size*3/4<trustee_hash_used) || (trustee_hash_size-2<trustee_hash_used)) { /*hash needed to be rebuilt, rebuilding hash */
+		newsize=(trustee_hash_deleted*3)>trustee_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;i<newsize;i++) n[i].usage=0;
+		trustee_hash_used=0;
+		for (i=0;i<trustee_hash_size;i++) {
+			if (trustee_hash[i].usage==2) {
+				for (j=hash(trustee_hash[i].name)%newsize;n[j].usage;j=(j+1)%newsize);
+				n[j]=trustee_hash[i];
+				trustee_hash_used++;
+			}
+		}
+		kfree(trustee_hash);
+                trustee_hash=n;
+                trustee_hash_size=newsize;
+		trustee_hash_deleted=0;
+				
+		
+			
+	}
+	for (j=hash(name)%trustee_hash_size;trustee_hash[j].usage==2;j=(j+1)%trustee_hash_size);
+	trustee_hash[j].name=kmalloc((strlen(name)+1)*sizeof(char),GFP_KERNEL);
+	if (trustee_hash[j].name==NULL) {
+#ifdef TRUSTEE_DEBUG
+		printk("Can not allocate memory for trustee hash\n");
+#endif
+		goto unlock_exit;
+	}
+	r=trustee_hash+j;
+	r->list=NULL;
+	strcpy(r->name,name);
+	r->usage=2;
+#ifdef TRUSTEE_DEBUG
+	printk("Added element to trustee hash: j %d, name : %s\n",j,r->name);
+#endif
+	trustee_hash_used++;
+	
+	
+ unlock_exit:
+	unlock_kernel();
+	return r;
+	
+
+}
+
+int  get_trustee_mask_for_name( char * name,uid_t user,int oldmask)
+{
+	struct trustee_hash_element * e;
+	int m;
+	struct permission_capsule * l;
+#ifdef TRUSTEE_DEBUG
+	printk("getting trustee mask for %s ", name);
+#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 ((!(l->permission.mask & TRUSTEE_IS_GROUP_MASK)) && (current->fsuid!=l->permission.u.uid)) continue;
+		if (((l->permission.mask & TRUSTEE_IS_GROUP_MASK)) && (!in_group_p(l->permission.u.gid))) 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,char * namebuffer)
+{
+	int oldmask;
+	/* debug */ if (namebuffer==NULL) {
+#ifdef TRUSTEE_DEBUG
+		printk("namebuffer is null");
+#endif
+		return trustee_default_acl;
+	}
+	/* 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;
+	}
+	
+	if (IS_VFS_ROOT(dentry)) {
+		oldmask=trustee_default_acl;
+		strcpy(namebuffer,"/");
+		#ifdef TRUSTEE_DEBUG
+		printk("\nRoot dentry reached: %s.",dentry->d_name.name);
+		if (dentry->d_mounts!=NULL) {
+			printk("Mounts is %s", dentry->d_mounts->d_name.name);
+		}
+		if (dentry->d_covers!=NULL) {
+			printk("Covers is %s, covers=dentry %d", dentry->d_covers->d_name.name, dentry->d_covers==dentry);
+		}
+		printk("\n");
+		#endif
+
+	} else {
+		if (IS_ROOT(dentry)) oldmask=get_trustee_mask_for_dentry(dentry->d_covers,user,namebuffer);
+		else
+			oldmask=get_trustee_mask_for_dentry(dentry->d_parent,user,namebuffer);
+		if (strlen(namebuffer)+strlen(dentry->d_name.name)+1>PATH_MAX+NAME_MAX) {
+			printk("PATH_MAX+NAME_MAX limit exceeded in trustee code for %s/%s",namebuffer,dentry->d_name.name);
+			return oldmask;
+		}
+		if (!IS_VFS_ROOT(dentry->d_parent)) strcat(namebuffer,"/");
+                strcat(namebuffer,dentry->d_name.name);
+	}
+	return get_trustee_mask_for_name(namebuffer,user,oldmask);
+     
+
+} 
+asmlinkage int sys_set_trustee(const char * name, struct trustee_permission * permission,int command) {
+	int r=-ENOSYS, i;
+	char * kname;
+	struct trustee_hash_element * e;
+	struct trustee_permission p;
+	struct permission_capsule * c;
+#ifdef TRUSTEE_DEBUG
+	printk("set trustee called, command %d", command);
+#endif
+	if ((current->euid!=0) && !capable(CAP_SYS_ADMIN)) return -EACCES;
+	lock_kernel();
+	switch (command) {
+	case TRUSTEE_COMMAND_REMOVE_ALL :
+		r=0;
+		if (trustee_hash==NULL) goto unlk;
+		for (i=0;i<trustee_hash_size;i++) {
+			if (trustee_hash[i].usage==2) free_hash_element(trustee_hash[i]);
+		}
+		kfree(trustee_hash);
+		trustee_hash=NULL;
+		goto unlk;
+	case TRUSTEE_COMMAND_REMOVE:
+		kname=kmalloc((strlen(name)+1)*sizeof(char),GFP_KERNEL);
+		if (!kname) {
+			printk("No memory to allocate for temporary buffer");
+			r=-ENOMEM;
+			goto unlk;
+		}
+		copy_from_user(kname,name,(strlen(name)+1)*sizeof(char));
+		e=get_trustee_for_name(kname);
+		if (e==NULL) {
+			r=-ENOENT;
+			kfree(kname);
+			goto unlk;
+		}
+		free_hash_element(*e);
+		trustee_hash_deleted++;
+		r=0;
+		goto unlk;
+	case TRUSTEE_COMMAND_REPLACE:
+		kname=kmalloc((strlen(name)+1)*sizeof(char),GFP_KERNEL);
+		if (!kname) {
+			printk("No memory to allocate for temporary buffer");
+			r=-ENOMEM;
+			goto unlk;
+		}
+		copy_from_user(kname,name,(strlen(name)+1)*sizeof(char));
+		e=getallocate_trustee_for_name(kname);
+		if (e==NULL) {
+			r=-ENOMEM;
+			kfree(kname);
+			goto unlk;
+		}
+		free_hash_element_list(*e);
+		copy_from_user(&p,permission,sizeof(p));
+		c=kmalloc(sizeof(struct permission_capsule),GFP_KERNEL);
+		c->permission=p;
+		c->next=e->list;
+		e->list=c;
+		r=0;
+		kfree(kname);
+		goto unlk;
+		
+	case TRUSTEE_COMMAND_ADD:
+		kname=kmalloc((strlen(name)+1)*sizeof(char),GFP_KERNEL);
+		if (!kname) {
+			printk("No memory to allocate for temporary buffer");
+			r=-ENOMEM;
+			goto unlk;
+		}
+		copy_from_user(kname,name,(strlen(name)+1)*sizeof(char));
+		e=getallocate_trustee_for_name(kname);
+		if (e==NULL) {
+			r=-ENOMEM;
+			kfree(kname);
+			goto unlk;
+		}
+		
+		copy_from_user(&p,permission,sizeof(p));
+		c=kmalloc(sizeof(struct permission_capsule),GFP_KERNEL);
+		c->permission=p;
+		c->next=e->list;
+		e->list=c;
+		r=0;
+		kfree(kname);
+		goto unlk;
+		
+		
+	}	
+ unlk:
+	unlock_kernel();
+	return r;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- linux/fs/Makefile	Mon Jun  7 09:48:59 1999
+++ linux/fs/Makefile	Mon Jun  7 09:49:36 1999
@@ -25,6 +25,9 @@
 else
 O_OBJS += noquot.o
 endif
+ifeq ($(CONFIG_TRUSTEES),y)
+O_OBJS += trustee.o
+endif
 
 ifeq ($(CONFIG_CODA_FS),y)
 SUB_DIRS += coda
--- linux/arch/i386/kernel/entry.S	Mon Jun  7 09:48:59 1999
+++ linux/arch/i386/kernel/entry.S	Mon Jun  7 09:49:36 1999
@@ -562,14 +562,15 @@
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams1 */
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams2 */
 	.long SYMBOL_NAME(sys_vfork)            /* 190 */
-
+        .long SYMBOL_NAME(sys_set_trustee)
+	.long SYMBOL_NAME(sys_access_uid)
 	/*
 	 * NOTE!! This doesn't have to be exact - we just have
 	 * to make sure we have _enough_ of the "sys_ni_syscall"
 	 * entries. Don't panic if you notice that this hasn't
 	 * been shrunk every time we add a new system call.
 	 */
-	.rept NR_syscalls-190
+	.rept NR_syscalls-192
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
 
--- linux/include/asm-i386/unistd.h	Mon Jun  7 09:48:59 1999
+++ linux/include/asm-i386/unistd.h	Mon Jun  7 09:49:36 1999
@@ -195,6 +195,9 @@
 #define __NR_getpmsg		188	/* some people actually want streams */
 #define __NR_putpmsg		189	/* some people actually want streams */
 #define __NR_vfork		190
+#define __NR_set_trustee        191
+#define __NR_access_uid         192
+
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */
 
--- linux/include/linux/trustee_struct.h	Mon Jun  7 09:48:59 1999
+++ linux/include/linux/trustee_struct.h	Mon Jun  7 09:49:36 1999
@@ -0,0 +1,50 @@
+/* 
+ *  (c) 1999 Vyacheslav Zavadsky
+ */
+
+#ifndef _LINUX_TRUSTEE_STRUCT_H
+
+#define _LINUX_TRUSTEE_STRUCT_H
+#include <linux/types.h>
+
+#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_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_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;
+
+};
+
+
+#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	Mon Jun  7 09:48:59 1999
+++ linux/Documentation/Configure.help	Mon Jun  7 09:49:36 1999
@@ -11668,6 +11668,10 @@
   This driver allows for devices which support the Abstract Control Model,
   including many USB-based modems, ISDN adapters, and network adapters.
 
+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
+
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, 
--- linux/arch/alpha/kernel/entry.S	Mon Jun  7 09:48:59 1999
+++ linux/arch/alpha/kernel/entry.S	Mon Jun  7 09:49:36 1999
@@ -1143,3 +1143,7 @@
 	.quad sys_capget
 	.quad sys_capset
 	.quad sys_sendfile			/* 370 */
+        .quad sys_set_trustee
+	.quad sys_access_uid
+	
+         
--- linux/include/asm-alpha/unistd.h	Mon Jun  7 09:48:59 1999
+++ linux/include/asm-alpha/unistd.h	Mon Jun  7 09:49:36 1999
@@ -308,6 +308,8 @@
 #define __NR_capget			368
 #define __NR_capset			369
 #define __NR_sendfile			370
+#define __NR_set_trustee                371
+#define __NR_access_uid                 372
 
 #if defined(__LIBRARY__) && defined(__GNUC__)
 
--- linux/arch/arm/kernel/calls.S	Mon Jun  7 09:48:59 1999
+++ linux/arch/arm/kernel/calls.S	Mon Jun  7 09:49:36 1999
@@ -196,8 +196,12 @@
 		.long	SYMBOL_NAME(sys_capget)
 /* 185 */	.long	SYMBOL_NAME(sys_capset)
 		.long	SYMBOL_NAME(sys_sigaltstack_wrapper)
-
-		.rept	NR_syscalls-186
-			.long	SYMBOL_NAME(sys_ni_syscall)
+                .long   SYMBOL_NAME(sys_set_trustee)
+	        .long   SYMBOL_NAME(sys_access_uid)
+		.rept	NR_syscalls-188
+			.long	SYMBOL_NAME(sys_access_uid)
 		.endr
 #endif
+
+
+
--- linux/include/asm-arm/unistd.h	Mon Jun  7 09:48:59 1999
+++ linux/include/asm-arm/unistd.h	Mon Jun  7 09:49:36 1999
@@ -195,8 +195,9 @@
 #define __NR_capset			(__NR_SYSCALL_BASE+185)
 #define __NR_sigaltstack		(__NR_SYSCALL_BASE+186)
 #define __NR_sendfile			(__NR_SYSCALL_BASE+187)
-					/* 188 reserved */
-					/* 189 reserved */
+#define __NR_set_trustee                (__NR_SYSCALL_BASE+187)
+#define __NR_access_uid                 (__NR_SYSCALL_BASE+188)
+
 #define __NR_vfork			(__NR_SYSCALL_BASE+190)
 
 #define __sys2(x) #x
--- linux/arch/m68k/kernel/entry.S	Mon Jun  7 09:48:59 1999
+++ linux/arch/m68k/kernel/entry.S	Mon Jun  7 09:49:36 1999
@@ -609,7 +609,9 @@
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams1 */
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams2 */
 	.long SYMBOL_NAME(sys_vfork)            /* 190 */
+        .long SYMBOL_NAME(sys_set_trustee)
+	.long SYMBOL_NAME(sys_access_uid)
 
 	.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
-		.long SYMBOL_NAME(sys_ni_syscall)
+		.long SYMBOL_NAME(sys_access_uid)
 	.endr
--- linux/include/asm-m68k/unistd.h	Mon Jun  7 09:48:59 1999
+++ linux/include/asm-m68k/unistd.h	Mon Jun  7 09:49:36 1999
@@ -194,6 +194,9 @@
 #define __NR_getpmsg		188	/* some people actually want streams */
 #define __NR_putpmsg		189	/* some people actually want streams */
 #define __NR_vfork		190
+#define __NR_set_trustee        191
+#define __NR_access_uid         192
+
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
--- linux/arch/mips/kernel/syscalls.h	Mon Jun  7 09:48:59 1999
+++ linux/arch/mips/kernel/syscalls.h	Mon Jun  7 09:49:36 1999
@@ -225,3 +225,5 @@
 SYS(sys_sendfile, 3)
 SYS(sys_ni_syscall, 0)
 SYS(sys_ni_syscall, 0)
+SYS(sys_set_trustee,3)           /* 4210 */
+SYS(sys_access_uid,4)
--- linux/include/asm-mips/unistd.h	Mon Jun  7 09:48:59 1999
+++ linux/include/asm-mips/unistd.h	Mon Jun  7 09:49:36 1999
@@ -263,6 +263,8 @@
 #define __NR_SVR4_CDC_reserved18	(__NR_SVR4 + 238)
 #define __NR_SVR4_CDC_reserved19	(__NR_SVR4 + 239)
 #define __NR_SVR4_CDC_reserved20	(__NR_SVR4 + 240)
+#define __NR_SVR4_set_trustee           (__NR_SVR4 + 210)
+#define __NR_SVR4_access_uid            (__NR_SVR4 + 211)
 
 /*
  * SYS V syscalls are in the range from 1000 to 1999
--- linux/arch/ppc/kernel/misc.S	Mon Jun  7 09:48:59 1999
+++ linux/arch/ppc/kernel/misc.S	Mon Jun  7 09:49:36 1999
@@ -888,4 +888,7 @@
 	.long sys_ni_syscall		/* streams1 */
 	.long sys_ni_syscall		/* streams2 */
 	.long sys_vfork
+        .long sys_set_trustee /* 190 */
+	.long  sys_access_uid
+
 	.space (NR_syscalls-183)*4
--- linux/include/asm-ppc/unistd.h	Mon Jun  7 09:48:59 1999
+++ linux/include/asm-ppc/unistd.h	Mon Jun  7 09:49:36 1999
@@ -194,6 +194,8 @@
 #define __NR_getpmsg		187	/* some people actually want streams */
 #define __NR_putpmsg		188	/* some people actually want streams */
 #define __NR_vfork		189
+#define __NR_set_trustee        190
+#define __NR_access_uid         191
 
 #define __NR(n)	#n
 
--- linux/arch/sparc/kernel/systbls.S	Mon Jun  7 09:48:59 1999
+++ linux/arch/sparc/kernel/systbls.S	Mon Jun  7 09:49:36 1999
@@ -68,7 +68,7 @@
 /*240*/	.long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 /*245*/	.long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-/*255*/	.long sys_aplib, sys_nis_syscall
+/*255*/	.long sys_aplib, sys_nis_syscall, sys_set_trustee, sys_access_uid
 
 	/* Now the SunOS syscall table. */
 
@@ -162,3 +162,12 @@
 	.long sunos_nosys, sunos_nosys
 /*250*/	.long sunos_nosys, sunos_nosys, sunos_nosys
 	.long sunos_nosys, sunos_nosys, sys_aplib
+
+
+
+
+
+
+
+
+
--- linux/include/asm-sparc/unistd.h	Mon Jun  7 09:48:59 1999
+++ linux/include/asm-sparc/unistd.h	Mon Jun  7 09:49:36 1999
@@ -271,6 +271,8 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
+#define __NR_set_trustee        257
+#define __NR_access_uid         258
 
 #define _syscall0(type,name) \
 type name(void) \
--- linux/arch/sparc64/kernel/systbls.S	Mon Jun  7 09:48:59 1999
+++ linux/arch/sparc64/kernel/systbls.S	Mon Jun  7 09:49:36 1999
@@ -127,7 +127,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-	.word sys_aplib
+	.word sys_aplib, sys_set_trustee, sys_access_uid
 
 	/* Now the 32-bit SunOS syscall table. */
 
--- linux/include/asm-sparc64/unistd.h	Mon Jun  7 09:48:59 1999
+++ linux/include/asm-sparc64/unistd.h	Mon Jun  7 09:49:36 1999
@@ -271,6 +271,8 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
+#define __NR_set_trustee        256
+#define __NR_access_uid         257
 
 #define _syscall0(type,name) \
 type name(void) \
--- linux/CREDITS	Mon Jun  7 09:48:59 1999
+++ linux/CREDITS	Mon Jun  7 11:06:41 1999
@@ -2262,6 +2262,15 @@
 S: Tokyo 153
 S: Japan
 
+N: Vyacheslav Zavadsky
+E: zavadsky@braysystems.com
+D: Linux trustees code
+S: Vasnetcova 11-43
+S: Minsk, 220107
+S: BELARUS
+
+
+
 N: Orest Zborowski
 E: orestz@eskimo.com
 D: XFree86 and kernel development
