source: trunk/minix/servers/fs/protect.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 6.6 KB
Line 
1/* This file deals with protection in the file system. It contains the code
2 * for four system calls that relate to protection.
3 *
4 * The entry points into this file are
5 * do_chmod: perform the CHMOD system call
6 * do_chown: perform the CHOWN system call
7 * do_umask: perform the UMASK system call
8 * do_access: perform the ACCESS system call
9 * forbidden: check to see if a given access is allowed on a given inode
10 */
11
12#include "fs.h"
13#include <unistd.h>
14#include <minix/callnr.h>
15#include "buf.h"
16#include "file.h"
17#include "fproc.h"
18#include "inode.h"
19#include "param.h"
20#include "super.h"
21
22/*===========================================================================*
23 * do_chmod *
24 *===========================================================================*/
25PUBLIC int do_chmod()
26{
27/* Perform the chmod(name, mode) system call. */
28
29 register struct inode *rip;
30 register int r;
31
32 /* Temporarily open the file. */
33 if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
34 if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
35
36 /* Only the owner or the super_user may change the mode of a file.
37 * No one may change the mode of a file on a read-only file system.
38 */
39 if (rip->i_uid != fp->fp_effuid && !super_user)
40 r = EPERM;
41 else
42 r = read_only(rip);
43
44 /* If error, return inode. */
45 if (r != OK) {
46 put_inode(rip);
47 return(r);
48 }
49
50 /* Now make the change. Clear setgid bit if file is not in caller's grp */
51 rip->i_mode = (rip->i_mode & ~ALL_MODES) | (m_in.mode & ALL_MODES);
52 if (!super_user && rip->i_gid != fp->fp_effgid)rip->i_mode &= ~I_SET_GID_BIT;
53 rip->i_update |= CTIME;
54 rip->i_dirt = DIRTY;
55
56 put_inode(rip);
57 return(OK);
58}
59
60/*===========================================================================*
61 * do_chown *
62 *===========================================================================*/
63PUBLIC int do_chown()
64{
65/* Perform the chown(name, owner, group) system call. */
66
67 register struct inode *rip;
68 register int r;
69
70 /* Temporarily open the file. */
71 if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
72 if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
73
74 /* Not permitted to change the owner of a file on a read-only file sys. */
75 r = read_only(rip);
76 if (r == OK) {
77 /* FS is R/W. Whether call is allowed depends on ownership, etc. */
78 if (super_user) {
79 /* The super user can do anything. */
80 rip->i_uid = m_in.owner; /* others later */
81 } else {
82 /* Regular users can only change groups of their own files. */
83 if (rip->i_uid != fp->fp_effuid) r = EPERM;
84 if (rip->i_uid != m_in.owner) r = EPERM; /* no giving away */
85 if (fp->fp_effgid != m_in.group) r = EPERM;
86 }
87 }
88 if (r == OK) {
89 rip->i_gid = m_in.group;
90 rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT);
91 rip->i_update |= CTIME;
92 rip->i_dirt = DIRTY;
93 }
94
95 put_inode(rip);
96 return(r);
97}
98
99/*===========================================================================*
100 * do_umask *
101 *===========================================================================*/
102PUBLIC int do_umask()
103{
104/* Perform the umask(co_mode) system call. */
105 register mode_t r;
106
107 r = ~fp->fp_umask; /* set 'r' to complement of old mask */
108 fp->fp_umask = ~(m_in.co_mode & RWX_MODES);
109 return(r); /* return complement of old mask */
110}
111
112/*===========================================================================*
113 * do_access *
114 *===========================================================================*/
115PUBLIC int do_access()
116{
117/* Perform the access(name, mode) system call. */
118
119 struct inode *rip;
120 register int r;
121
122 /* First check to see if the mode is correct. */
123 if ( (m_in.mode & ~(R_OK | W_OK | X_OK)) != 0 && m_in.mode != F_OK)
124 return(EINVAL);
125
126 /* Temporarily open the file whose access is to be checked. */
127 if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
128 if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
129
130 /* Now check the permissions. */
131 r = forbidden(rip, (mode_t) m_in.mode);
132 put_inode(rip);
133 return(r);
134}
135
136/*===========================================================================*
137 * forbidden *
138 *===========================================================================*/
139PUBLIC int forbidden(register struct inode *rip, mode_t access_desired)
140{
141/* Given a pointer to an inode, 'rip', and the access desired, determine
142 * if the access is allowed, and if not why not. The routine looks up the
143 * caller's uid in the 'fproc' table. If access is allowed, OK is returned
144 * if it is forbidden, EACCES is returned.
145 */
146
147 register struct inode *old_rip = rip;
148 register struct super_block *sp;
149 register mode_t bits, perm_bits;
150 int r, shift, test_uid, test_gid, type;
151
152 if (rip->i_mount == I_MOUNT) /* The inode is mounted on. */
153 for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++)
154 if (sp->s_imount == rip) {
155 rip = get_inode(sp->s_dev, ROOT_INODE);
156 break;
157 } /* if */
158
159 /* Isolate the relevant rwx bits from the mode. */
160 bits = rip->i_mode;
161 test_uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid);
162 test_gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid);
163 if (test_uid == SU_UID) {
164 /* Grant read and write permission. Grant search permission for
165 * directories. Grant execute permission (for non-directories) if
166 * and only if one of the 'X' bits is set.
167 */
168 if ( (bits & I_TYPE) == I_DIRECTORY ||
169 bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT))
170 perm_bits = R_BIT | W_BIT | X_BIT;
171 else
172 perm_bits = R_BIT | W_BIT;
173 } else {
174 if (test_uid == rip->i_uid) shift = 6; /* owner */
175 else if (test_gid == rip->i_gid ) shift = 3; /* group */
176 else shift = 0; /* other */
177 perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
178 }
179
180 /* If access desired is not a subset of what is allowed, it is refused. */
181 r = OK;
182 if ((perm_bits | access_desired) != perm_bits) r = EACCES;
183
184 /* Check to see if someone is trying to write on a file system that is
185 * mounted read-only.
186 */
187 type = rip->i_mode & I_TYPE;
188 if (r == OK)
189 if (access_desired & W_BIT)
190 r = read_only(rip);
191
192 if (rip != old_rip) put_inode(rip);
193
194 return(r);
195}
196
197/*===========================================================================*
198 * read_only *
199 *===========================================================================*/
200PUBLIC int read_only(ip)
201struct inode *ip; /* ptr to inode whose file sys is to be cked */
202{
203/* Check to see if the file system on which the inode 'ip' resides is mounted
204 * read only. If so, return EROFS, else return OK.
205 */
206
207 register struct super_block *sp;
208
209 sp = ip->i_sp;
210 return(sp->s_rd_only ? EROFS : OK);
211}
Note: See TracBrowser for help on using the repository browser.