creds.c revision 1.10 1 /* $NetBSD: creds.c,v 1.10 2007/06/06 01:55:00 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2006 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the Ulla Tuominen Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 #if !defined(lint)
32 __RCSID("$NetBSD: creds.c,v 1.10 2007/06/06 01:55:00 pooka Exp $");
33 #endif /* !lint */
34
35 /*
36 * Interface for dealing with credits.
37 */
38
39 #include <sys/types.h>
40 #include <sys/param.h>
41
42 #include <errno.h>
43 #include <puffs.h>
44 #include <string.h>
45
46 #define UUCCRED(a) (a->pcr_type == PUFFCRED_TYPE_UUC)
47 #define INTCRED(a) (a->pcr_type == PUFFCRED_TYPE_INTERNAL)
48
49 int
50 puffs_cred_getuid(const struct puffs_cred *pcr, uid_t *ruid)
51 {
52
53 if (!UUCCRED(pcr)) {
54 errno = EOPNOTSUPP;
55 return -1;
56 }
57 *ruid = pcr->pcr_uuc.cr_uid;
58
59 return 0;
60 }
61
62 int
63 puffs_cred_getgid(const struct puffs_cred *pcr, gid_t *rgid)
64 {
65
66 if (!UUCCRED(pcr)) {
67 errno = EOPNOTSUPP;
68 return -1;
69 }
70 *rgid = pcr->pcr_uuc.cr_gid;
71
72 return 0;
73 }
74
75 int
76 puffs_cred_getgroups(const struct puffs_cred *pcr, gid_t *rgids, short *ngids)
77 {
78 size_t ncopy;
79
80 if (!UUCCRED(pcr)) {
81 errno = EOPNOTSUPP;
82 return -1;
83 }
84
85 ncopy = MIN(*ngids, NGROUPS);
86 (void)memcpy(rgids, pcr->pcr_uuc.cr_groups, sizeof(gid_t) * ncopy);
87 *ngids = (short)ncopy;
88
89 return 0;
90 }
91
92 int
93 puffs_cred_isuid(const struct puffs_cred *pcr, uid_t uid)
94 {
95
96 return UUCCRED(pcr) && pcr->pcr_uuc.cr_uid == uid;
97 }
98
99 int
100 puffs_cred_hasgroup(const struct puffs_cred *pcr, gid_t gid)
101 {
102 short i;
103
104 if (!UUCCRED(pcr))
105 return 0;
106
107 if (pcr->pcr_uuc.cr_gid == gid)
108 return 1;
109 for (i = 0; i < pcr->pcr_uuc.cr_ngroups; i++)
110 if (pcr->pcr_uuc.cr_groups[i] == gid)
111 return 1;
112
113 return 0;
114 }
115
116 int
117 puffs_cred_isregular(const struct puffs_cred *pcr)
118 {
119
120 return UUCCRED(pcr);
121 }
122
123 int
124 puffs_cred_iskernel(const struct puffs_cred *pcr)
125 {
126
127 return INTCRED(pcr) && pcr->pcr_internal == PUFFCRED_CRED_NOCRED;
128 }
129
130 int
131 puffs_cred_isfs(const struct puffs_cred *pcr)
132 {
133
134 return INTCRED(pcr) && pcr->pcr_internal == PUFFCRED_CRED_FSCRED;
135 }
136
137 int
138 puffs_cred_isjuggernaut(const struct puffs_cred *pcr)
139 {
140
141 return puffs_cred_isuid(pcr, 0) || puffs_cred_iskernel(pcr)
142 || puffs_cred_isfs(pcr);
143 }
144
145 /*
146 * Gerneic routine for checking file access rights. Modeled after
147 * vaccess() in the kernel.
148 */
149 int
150 puffs_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid,
151 mode_t acc_mode, const struct puffs_cred *pcr)
152 {
153 mode_t mask;
154
155 /* megapower */
156 if (puffs_cred_iskernel(pcr) || puffs_cred_isfs(pcr))
157 return 0;
158
159 /* superuser, allow all except exec if *ALL* exec bits are unset */
160 if (puffs_cred_isuid(pcr, 0)) {
161 if ((acc_mode & PUFFS_VEXEC) && type != VDIR &&
162 (file_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)
163 return EACCES;
164 return 0;
165 }
166
167 mask = 0;
168 /* owner */
169 if (puffs_cred_isuid(pcr, uid)) {
170 if (acc_mode & PUFFS_VEXEC)
171 mask |= S_IXUSR;
172 if (acc_mode & PUFFS_VREAD)
173 mask |= S_IRUSR;
174 if (acc_mode & PUFFS_VWRITE)
175 mask |= S_IWUSR;
176 /* group */
177 } else if (puffs_cred_hasgroup(pcr, gid)) {
178 if (acc_mode & PUFFS_VEXEC)
179 mask |= S_IXGRP;
180 if (acc_mode & PUFFS_VREAD)
181 mask |= S_IRGRP;
182 if (acc_mode & PUFFS_VWRITE)
183 mask |= S_IWGRP;
184 /* other */
185 } else {
186 if (acc_mode & PUFFS_VEXEC)
187 mask |= S_IXOTH;
188 if (acc_mode & PUFFS_VREAD)
189 mask |= S_IROTH;
190 if (acc_mode & PUFFS_VWRITE)
191 mask |= S_IWOTH;
192 }
193
194 if ((file_mode & mask) == mask)
195 return 0;
196 else
197 return EACCES;
198 }
199
200 int
201 puffs_access_chown(uid_t owner, gid_t group, uid_t newowner, gid_t newgroup,
202 const struct puffs_cred *pcr)
203 {
204
205 if (newowner == (uid_t)PUFFS_VNOVAL)
206 newowner = owner;
207 if (newgroup == (gid_t)PUFFS_VNOVAL)
208 newgroup = group;
209
210 if ((!puffs_cred_isuid(pcr, owner) || newowner != owner ||
211 ((newgroup != group && !puffs_cred_hasgroup(pcr, newgroup))))
212 && !puffs_cred_isjuggernaut(pcr))
213 return EPERM;
214
215 return 0;
216 }
217
218 int
219 puffs_access_chmod(uid_t owner, gid_t group, enum vtype type, mode_t mode,
220 const struct puffs_cred *pcr)
221 {
222
223 if (!puffs_cred_isuid(pcr, owner) && !puffs_cred_isjuggernaut(pcr))
224 return EPERM;
225
226 if (!puffs_cred_isjuggernaut(pcr)) {
227 if (type != VDIR && (mode & S_ISTXT))
228 return EFTYPE;
229 if (!puffs_cred_hasgroup(pcr, group) && (mode & S_ISGID))
230 return EPERM;
231 }
232
233 return 0;
234 }
235
236 int
237 puffs_access_times(uid_t uid, gid_t gid, mode_t mode, int va_utimes_null,
238 const struct puffs_cred *pcr)
239 {
240
241 if (!puffs_cred_isuid(pcr, uid) && !puffs_cred_isjuggernaut(pcr)
242 && (va_utimes_null == 0
243 || puffs_access(VNON, mode, uid, gid, PUFFS_VWRITE, pcr) != 0))
244 return EPERM;
245
246 return 0;
247 }
248