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
15 #include <minix/callnr.h>
18 #include <minix/vfsif.h>
22 /*===========================================================================*
24 *===========================================================================*/
27 /* Perform the chmod(name, mode) and fchmod(fd, mode) system calls.
28 * syscall might provide 'name' embedded in the message.
36 char fullpath
[PATH_MAX
];
37 struct lookup resolve
;
42 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
43 resolve
.l_vmnt_lock
= VMNT_READ
;
44 resolve
.l_vnode_lock
= VNODE_WRITE
;
46 if (job_call_nr
== VFS_CHMOD
) {
47 new_mode
= job_m_in
.m_lc_vfs_path
.mode
;
48 /* Temporarily open the file */
49 if (copy_path(fullpath
, sizeof(fullpath
)) != OK
)
51 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
52 } else { /* call_nr == VFS_FCHMOD */
53 rfd
= job_m_in
.m_lc_vfs_fchmod
.fd
;
54 new_mode
= job_m_in
.m_lc_vfs_fchmod
.mode
;
55 /* File is already opened; get a pointer to vnode from filp. */
56 if ((flp
= get_filp(rfd
, VNODE_WRITE
)) == NULL
) return(err_code
);
64 /* Only the owner or the super_user may change the mode of a file.
65 * No one may change the mode of a file on a read-only file system.
67 if (vp
->v_uid
!= fp
->fp_effuid
&& fp
->fp_effuid
!= SU_UID
)
73 /* Now make the change. Clear setgid bit if file is not in caller's
75 if (fp
->fp_effuid
!= SU_UID
&& vp
->v_gid
!= fp
->fp_effgid
)
76 new_mode
&= ~I_SET_GID_BIT
;
78 r
= req_chmod(vp
->v_fs_e
, vp
->v_inode_nr
, new_mode
, &result_mode
);
80 vp
->v_mode
= result_mode
;
83 if (job_call_nr
== VFS_CHMOD
) {
86 } else { /* VFS_FCHMOD */
95 /*===========================================================================*
97 *===========================================================================*/
100 /* Perform the chown(path, owner, group) and fchmod(fd, owner, group) system
109 char fullpath
[PATH_MAX
];
110 struct lookup resolve
;
112 size_t vname1_length
;
115 uid
= job_m_in
.m_lc_vfs_chown
.owner
;
116 gid
= job_m_in
.m_lc_vfs_chown
.group
;
118 if (job_call_nr
== VFS_CHOWN
) {
119 vname1
= job_m_in
.m_lc_vfs_chown
.name
;
120 vname1_length
= job_m_in
.m_lc_vfs_chown
.len
;
122 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
123 resolve
.l_vmnt_lock
= VMNT_READ
;
124 resolve
.l_vnode_lock
= VNODE_WRITE
;
126 /* Temporarily open the file. */
127 if (fetch_name(vname1
, vname1_length
, fullpath
) != OK
)
129 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
130 } else { /* call_nr == VFS_FCHOWN */
131 rfd
= job_m_in
.m_lc_vfs_chown
.fd
;
133 /* File is already opened; get a pointer to the vnode from filp. */
134 if ((flp
= get_filp(rfd
, VNODE_WRITE
)) == NULL
)
142 /* FS is R/W. Whether call is allowed depends on ownership, etc. */
143 /* The super user can do anything, so check permissions only if we're
145 if (fp
->fp_effuid
!= SU_UID
) {
146 /* Regular users can only change groups of their own files. */
147 if (vp
->v_uid
!= fp
->fp_effuid
) r
= EPERM
;
148 if (vp
->v_uid
!= uid
) r
= EPERM
; /* no giving away */
149 if (fp
->fp_effgid
!= gid
) r
= EPERM
;
154 /* Do not change uid/gid if new uid/gid is -1. */
155 new_uid
= (uid
== (uid_t
)-1 ? vp
->v_uid
: uid
);
156 new_gid
= (gid
== (gid_t
)-1 ? vp
->v_gid
: gid
);
158 if (new_uid
> UID_MAX
|| new_gid
> GID_MAX
)
160 else if ((r
= req_chown(vp
->v_fs_e
, vp
->v_inode_nr
, new_uid
, new_gid
,
164 vp
->v_mode
= new_mode
;
168 if (job_call_nr
== VFS_CHOWN
) {
171 } else { /* VFS_FCHOWN */
179 /*===========================================================================*
181 *===========================================================================*/
184 /* Perform the umask(2) system call. */
185 mode_t complement
, new_umask
;
187 new_umask
= job_m_in
.m_lc_vfs_umask
.mask
;
189 complement
= ~fp
->fp_umask
; /* set 'r' to complement of old mask */
190 fp
->fp_umask
= ~(new_umask
& RWX_MODES
);
191 return(complement
); /* return complement of old mask */
195 /*===========================================================================*
197 *===========================================================================*/
200 /* Perform the access(name, mode) system call.
201 * syscall might provide 'name' embedded in the message.
206 char fullpath
[PATH_MAX
];
207 struct lookup resolve
;
210 access
= job_m_in
.m_lc_vfs_path
.mode
;
212 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
213 resolve
.l_vmnt_lock
= VMNT_READ
;
214 resolve
.l_vnode_lock
= VNODE_READ
;
216 /* First check to see if the mode is correct. */
217 if ( (access
& ~(R_OK
| W_OK
| X_OK
)) != 0 && access
!= F_OK
)
220 /* Temporarily open the file. */
221 if (copy_path(fullpath
, sizeof(fullpath
)) != OK
)
223 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
225 r
= forbidden(fp
, vp
, access
);
235 /*===========================================================================*
237 *===========================================================================*/
238 int forbidden(struct fproc
*rfp
, struct vnode
*vp
, mode_t access_desired
)
240 /* Given a pointer to an vnode, 'vp', and the access desired, determine
241 * if the access is allowed, and if not why not. The routine looks up the
242 * caller's uid in the 'fproc' table. If access is allowed, OK is returned
243 * if it is forbidden, EACCES is returned.
246 register mode_t bits
, perm_bits
;
251 if (vp
->v_uid
== (uid_t
) -1 || vp
->v_gid
== (gid_t
) -1) return(EACCES
);
253 /* Isolate the relevant rwx bits from the mode. */
255 uid
= (job_call_nr
== VFS_ACCESS
? rfp
->fp_realuid
: rfp
->fp_effuid
);
256 gid
= (job_call_nr
== VFS_ACCESS
? rfp
->fp_realgid
: rfp
->fp_effgid
);
259 /* Grant read and write permission. Grant search permission for
260 * directories. Grant execute permission (for non-directories) if
261 * and only if one of the 'X' bits is set.
263 if ( S_ISDIR(bits
) || bits
& ((X_BIT
<< 6) | (X_BIT
<< 3) | X_BIT
))
264 perm_bits
= R_BIT
| W_BIT
| X_BIT
;
266 perm_bits
= R_BIT
| W_BIT
;
268 if (uid
== vp
->v_uid
) shift
= 6; /* owner */
269 else if (gid
== vp
->v_gid
) shift
= 3; /* group */
270 else if (in_group(fp
, vp
->v_gid
) == OK
) shift
= 3; /* suppl. groups */
271 else shift
= 0; /* other */
272 perm_bits
= (bits
>> shift
) & (R_BIT
| W_BIT
| X_BIT
);
275 /* If access desired is not a subset of what is allowed, it is refused. */
277 if ((perm_bits
| access_desired
) != perm_bits
) r
= EACCES
;
279 /* Check to see if someone is trying to write on a file system that is
283 if (access_desired
& W_BIT
)
289 /*===========================================================================*
291 *===========================================================================*/
293 struct vnode
*vp
; /* ptr to inode whose file sys is to be cked */
295 /* Check to see if the file system on which the inode 'ip' resides is mounted
296 * read only. If so, return EROFS, else return OK.
299 return(vp
->v_vmnt
&& (vp
->v_vmnt
->m_flags
& VMNT_READONLY
) ? EROFS
: OK
);