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