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