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