xref: /minix3/minix/fs/ext2/protect.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1 /* Created (MFS based):
2  *   February 2010 (Evgeniy Ivanov)
3  */
4 
5 #include "fs.h"
6 #include "inode.h"
7 #include "super.h"
8 #include <minix/vfsif.h>
9 
10 static int in_group(gid_t grp);
11 
12 
13 /*===========================================================================*
14  *				fs_chmod				     *
15  *===========================================================================*/
16 int fs_chmod()
17 {
18 /* Perform the chmod(name, mode) system call. */
19 
20   register struct inode *rip;
21   mode_t mode;
22 
23   mode = fs_m_in.m_vfs_fs_chmod.mode;
24 
25   /* Temporarily open the file. */
26   if( (rip = get_inode(fs_dev, fs_m_in.m_vfs_fs_chmod.inode)) == NULL)
27 	  return(EINVAL);
28 
29   /* Now make the change. Clear setgid bit if file is not in caller's grp */
30   rip->i_mode = (rip->i_mode & ~ALL_MODES) | (mode & ALL_MODES);
31   rip->i_update |= CTIME;
32   rip->i_dirt = IN_DIRTY;
33 
34   /* Return full new mode to caller. */
35   fs_m_out.m_fs_vfs_chmod.mode = rip->i_mode;
36 
37   put_inode(rip);
38   return(OK);
39 }
40 
41 
42 /*===========================================================================*
43  *				fs_chown				     *
44  *===========================================================================*/
45 int fs_chown()
46 {
47   register struct inode *rip;
48   register int r;
49 
50   /* Temporarily open the file. */
51   if( (rip = get_inode(fs_dev, fs_m_in.m_vfs_fs_chown.inode)) == NULL)
52 	  return(EINVAL);
53 
54   /* Not permitted to change the owner of a file on a read-only file sys. */
55   r = read_only(rip);
56   if (r == OK) {
57 	  rip->i_uid = fs_m_in.m_vfs_fs_chown.uid;
58 	  rip->i_gid = fs_m_in.m_vfs_fs_chown.gid;
59 	  rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT);
60 	  rip->i_update |= CTIME;
61 	  rip->i_dirt = IN_DIRTY;
62   }
63 
64   /* Update caller on current mode, as it may have changed. */
65   fs_m_out.m_fs_vfs_chown.mode = rip->i_mode;
66   put_inode(rip);
67 
68   return(r);
69 }
70 
71 
72 /*===========================================================================*
73  *				forbidden				     *
74  *===========================================================================*/
75 int forbidden(struct inode *rip, mode_t access_desired)
76 {
77 /* Given a pointer to an inode, 'rip', and the access desired, determine
78  * if the access is allowed, and if not why not.  The routine looks up the
79  * caller's uid in the 'fproc' table.  If access is allowed, OK is returned
80  * if it is forbidden, EACCES is returned.
81  */
82 
83   register struct inode *old_rip = rip;
84   mode_t bits, perm_bits;
85   int r, shift;
86 
87   /* Isolate the relevant rwx bits from the mode. */
88   bits = rip->i_mode;
89   if (caller_uid == SU_UID) {
90 	/* Grant read and write permission.  Grant search permission for
91 	 * directories.  Grant execute permission (for non-directories) if
92 	 * and only if one of the 'X' bits is set.
93 	 */
94 	if ( (bits & I_TYPE) == I_DIRECTORY ||
95 	     bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT))
96 		perm_bits = R_BIT | W_BIT | X_BIT;
97 	else
98 		perm_bits = R_BIT | W_BIT;
99   } else {
100 	if (caller_uid == rip->i_uid) shift = 6;	/* owner */
101 	else if (caller_gid == rip->i_gid) shift = 3;	/* group */
102 	else if (in_group(rip->i_gid) == OK) shift = 3;	/* other groups */
103 	else shift = 0;					/* other */
104 	perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
105   }
106 
107   /* If access desired is not a subset of what is allowed, it is refused. */
108   r = OK;
109   if ((perm_bits | access_desired) != perm_bits) r = EACCES;
110 
111   /* Check to see if someone is trying to write on a file system that is
112    * mounted read-only.
113    */
114   if (r == OK) {
115 	if (access_desired & W_BIT) {
116 		r = read_only(rip);
117 	}
118   }
119 
120   if (rip != old_rip) put_inode(rip);
121 
122   return(r);
123 }
124 
125 
126 /*===========================================================================*
127  *				in_group				     *
128  *===========================================================================*/
129 static int in_group(gid_t grp)
130 {
131   int i;
132 
133   if (credentials.vu_ngroups > NGROUPS_MAX)
134 	return(EINVAL);
135 
136   for (i = 0; i < credentials.vu_ngroups; i++)
137 	if (credentials.vu_sgroups[i] == grp)
138 		return(OK);
139 
140   return(EINVAL);
141 }
142 
143 
144 /*===========================================================================*
145  *				read_only				     *
146  *===========================================================================*/
147 int read_only(ip)
148 struct inode *ip;		/* ptr to inode whose file sys is to be cked */
149 {
150 /* Check to see if the file system on which the inode 'ip' resides is mounted
151  * read only.  If so, return EROFS, else return OK.
152  */
153 
154   register struct super_block *sp;
155 
156   sp = ip->i_sp;
157   return(sp->s_rd_only ? EROFS : OK);
158 }
159