1 /* This file deals with protection in the file system. It contains the code
2 * for four system calls that relate to protection.
4 * The entry points into this file are
5 * do_chmod: perform the CHMOD and FCHMOD system calls
6 * do_chown: perform the CHOWN and FCHOWN system calls
7 * do_umask: perform the UMASK system call
8 * do_access: perform the ACCESS system call
14 #include <minix/callnr.h>
19 #include <minix/vfsif.h>
23 /*===========================================================================*
25 *===========================================================================*/
28 /* Perform the chmod(name, mode) and fchmod(fd, mode) system calls.
29 * syscall might provide 'name' embedded in the message.
37 char fullpath
[PATH_MAX
];
38 struct lookup resolve
;
44 vname
= (vir_bytes
) job_m_in
.name
;
45 vname_length
= (size_t) job_m_in
.name_length
;
47 new_mode
= (mode_t
) job_m_in
.mode
;
49 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
50 resolve
.l_vmnt_lock
= VMNT_WRITE
;
51 resolve
.l_vnode_lock
= VNODE_WRITE
;
53 if (job_call_nr
== CHMOD
) {
54 /* Temporarily open the file */
55 if (copy_name(vname_length
, fullpath
) != OK
) {
56 /* Direct copy failed, try fetching from user space */
57 if (fetch_name(vname
, vname_length
, fullpath
) != OK
)
60 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
61 } else { /* call_nr == FCHMOD */
62 /* File is already opened; get a pointer to vnode from filp. */
63 if ((flp
= get_filp(rfd
, VNODE_WRITE
)) == NULL
) return(err_code
);
68 /* Only the owner or the super_user may change the mode of a file.
69 * No one may change the mode of a file on a read-only file system.
71 if (vp
->v_uid
!= fp
->fp_effuid
&& fp
->fp_effuid
!= SU_UID
)
77 /* Now make the change. Clear setgid bit if file is not in caller's
79 if (fp
->fp_effuid
!= SU_UID
&& vp
->v_gid
!= fp
->fp_effgid
)
80 new_mode
&= ~I_SET_GID_BIT
;
82 r
= req_chmod(vp
->v_fs_e
, vp
->v_inode_nr
, new_mode
, &result_mode
);
84 vp
->v_mode
= result_mode
;
87 if (job_call_nr
== CHMOD
) {
99 /*===========================================================================*
101 *===========================================================================*/
104 /* Perform the chown(path, owner, group) and fchmod(fd, owner, group) system
113 char fullpath
[PATH_MAX
];
114 struct lookup resolve
;
116 size_t vname1_length
;
119 vname1
= (vir_bytes
) job_m_in
.name1
;
120 vname1_length
= (size_t) job_m_in
.name1_length
;
122 uid
= job_m_in
.owner
;
123 gid
= job_m_in
.group
;
125 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
126 resolve
.l_vmnt_lock
= VMNT_WRITE
;
127 resolve
.l_vnode_lock
= VNODE_WRITE
;
129 if (job_call_nr
== CHOWN
) {
130 /* Temporarily open the file. */
131 if (fetch_name(vname1
, vname1_length
, fullpath
) != OK
)
133 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
134 } else { /* call_nr == FCHOWN */
135 /* File is already opened; get a pointer to the vnode from filp. */
136 if ((flp
= get_filp(rfd
, VNODE_WRITE
)) == NULL
)
144 /* FS is R/W. Whether call is allowed depends on ownership, etc. */
145 /* The super user can do anything, so check permissions only if we're
147 if (fp
->fp_effuid
!= SU_UID
) {
148 /* Regular users can only change groups of their own files. */
149 if (vp
->v_uid
!= fp
->fp_effuid
) r
= EPERM
;
150 if (vp
->v_uid
!= uid
) r
= EPERM
; /* no giving away */
151 if (fp
->fp_effgid
!= gid
) r
= EPERM
;
156 /* Do not change uid/gid if new uid/gid is -1. */
157 new_uid
= (uid
== (uid_t
)-1 ? vp
->v_uid
: uid
);
158 new_gid
= (gid
== (gid_t
)-1 ? vp
->v_gid
: gid
);
160 if (new_uid
> UID_MAX
|| new_gid
> GID_MAX
)
162 else if ((r
= req_chown(vp
->v_fs_e
, vp
->v_inode_nr
, new_uid
, new_gid
,
166 vp
->v_mode
= new_mode
;
170 if (job_call_nr
== CHOWN
) {
173 } else { /* FCHOWN */
181 /*===========================================================================*
183 *===========================================================================*/
186 /* Perform the umask(co_mode) system call. */
187 mode_t complement
, new_umask
;
189 new_umask
= job_m_in
.co_mode
;
191 complement
= ~fp
->fp_umask
; /* set 'r' to complement of old mask */
192 fp
->fp_umask
= ~(new_umask
& RWX_MODES
);
193 return(complement
); /* return complement of old mask */
197 /*===========================================================================*
199 *===========================================================================*/
202 /* Perform the access(name, mode) system call.
203 * syscall might provide 'name' embedded in the message.
208 char fullpath
[PATH_MAX
];
209 struct lookup resolve
;
214 vname
= (vir_bytes
) job_m_in
.name
;
215 vname_length
= (size_t) job_m_in
.name_length
;
216 access
= job_m_in
.mode
;
218 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
219 resolve
.l_vmnt_lock
= VMNT_READ
;
220 resolve
.l_vnode_lock
= VNODE_READ
;
222 /* First check to see if the mode is correct. */
223 if ( (access
& ~(R_OK
| W_OK
| X_OK
)) != 0 && access
!= F_OK
)
226 /* Temporarily open the file. */
227 if (copy_name(vname_length
, fullpath
) != OK
) {
228 /* Direct copy failed, try fetching from user space */
229 if (fetch_name(vname
, vname_length
, fullpath
) != OK
)
232 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
234 r
= forbidden(fp
, vp
, access
);
244 /*===========================================================================*
246 *===========================================================================*/
247 int forbidden(struct fproc
*rfp
, struct vnode
*vp
, mode_t access_desired
)
249 /* Given a pointer to an vnode, 'vp', and the access desired, determine
250 * if the access is allowed, and if not why not. The routine looks up the
251 * caller's uid in the 'fproc' table. If access is allowed, OK is returned
252 * if it is forbidden, EACCES is returned.
255 register mode_t bits
, perm_bits
;
260 if (vp
->v_uid
== (uid_t
) -1 || vp
->v_gid
== (gid_t
) -1) return(EACCES
);
262 /* Isolate the relevant rwx bits from the mode. */
264 uid
= (job_call_nr
== ACCESS
? rfp
->fp_realuid
: rfp
->fp_effuid
);
265 gid
= (job_call_nr
== ACCESS
? rfp
->fp_realgid
: rfp
->fp_effgid
);
268 /* Grant read and write permission. Grant search permission for
269 * directories. Grant execute permission (for non-directories) if
270 * and only if one of the 'X' bits is set.
272 if ( S_ISDIR(bits
) || bits
& ((X_BIT
<< 6) | (X_BIT
<< 3) | X_BIT
))
273 perm_bits
= R_BIT
| W_BIT
| X_BIT
;
275 perm_bits
= R_BIT
| W_BIT
;
277 if (uid
== vp
->v_uid
) shift
= 6; /* owner */
278 else if (gid
== vp
->v_gid
) shift
= 3; /* group */
279 else if (in_group(fp
, vp
->v_gid
) == OK
) shift
= 3; /* suppl. groups */
280 else shift
= 0; /* other */
281 perm_bits
= (bits
>> shift
) & (R_BIT
| W_BIT
| X_BIT
);
284 /* If access desired is not a subset of what is allowed, it is refused. */
286 if ((perm_bits
| access_desired
) != perm_bits
) r
= EACCES
;
288 /* Check to see if someone is trying to write on a file system that is
292 if (access_desired
& W_BIT
)
298 /*===========================================================================*
300 *===========================================================================*/
302 struct vnode
*vp
; /* ptr to inode whose file sys is to be cked */
304 /* Check to see if the file system on which the inode 'ip' resides is mounted
305 * read only. If so, return EROFS, else return OK.
307 return((vp
->v_vmnt
->m_flags
& VMNT_READONLY
) ? EROFS
: OK
);