creds.c revision 1.5 1 /* $NetBSD: creds.c,v 1.5 2007/03/21 19:55:55 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.5 2007/03/21 19:55:55 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 <puffs.h>
46 #include <errno.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 return EINVAL;
58 *ruid = pcr->pcr_uuc.cr_uid;
59
60 return 0;
61 }
62
63 int
64 puffs_cred_getgid(const struct puffs_cred *pcr, gid_t *rgid)
65 {
66
67 if (!UUCCRED(pcr))
68 return EINVAL;
69 *rgid = pcr->pcr_uuc.cr_gid;
70
71 return 0;
72 }
73
74 int
75 puffs_cred_getgroups(const struct puffs_cred *pcr, gid_t *rgids, short *ngids)
76 {
77 size_t ncopy;
78
79 if (!UUCCRED(pcr))
80 return EINVAL;
81
82 ncopy = MIN(*ngids, NGROUPS);
83 (void)memcpy(rgids, pcr->pcr_uuc.cr_groups, ncopy);
84 *ngids = (short)ncopy;
85
86 return 0;
87 }
88
89 int
90 puffs_cred_isuid(const struct puffs_cred *pcr, uid_t uid)
91 {
92
93 return UUCCRED(pcr) && pcr->pcr_uuc.cr_uid == uid;
94 }
95
96 int
97 puffs_cred_hasgroup(const struct puffs_cred *pcr, gid_t gid)
98 {
99 short i;
100
101 if (!UUCCRED(pcr))
102 return 0;
103
104 if (pcr->pcr_uuc.cr_gid == gid)
105 return 1;
106 for (i = 0; i < pcr->pcr_uuc.cr_ngroups; i++)
107 if (pcr->pcr_uuc.cr_groups[i] == gid)
108 return 1;
109
110 return 0;
111 }
112
113 int
114 puffs_cred_iskernel(const struct puffs_cred *pcr)
115 {
116
117 return INTCRED(pcr) && pcr->pcr_internal == PUFFCRED_CRED_NOCRED;
118 }
119
120 int
121 puffs_cred_isfs(const struct puffs_cred *pcr)
122 {
123
124 return INTCRED(pcr) && pcr->pcr_internal == PUFFCRED_CRED_FSCRED;
125 }
126
127 int
128 puffs_cred_isjuggernaut(const struct puffs_cred *pcr)
129 {
130
131 return puffs_cred_isuid(pcr, 0) || puffs_cred_iskernel(pcr)
132 || puffs_cred_isfs(pcr);
133 }
134
135 /*
136 * Gerneic routine for checking file access rights. Modeled after
137 * vaccess() in the kernel.
138 */
139 int
140 puffs_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid,
141 mode_t acc_mode, const struct puffs_cred *pcr)
142 {
143 mode_t mask;
144
145 /* megapower */
146 if (puffs_cred_iskernel(pcr) || puffs_cred_isfs(pcr))
147 return 0;
148
149 /* superuser, allow all except exec if *ALL* exec bits are unset */
150 if (puffs_cred_isuid(pcr, 0)) {
151 if ((acc_mode & PUFFS_VEXEC) && type != VDIR &&
152 (file_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)
153 return EACCES;
154 return 0;
155 }
156
157 mask = 0;
158 /* owner */
159 if (puffs_cred_isuid(pcr, uid)) {
160 if (acc_mode & PUFFS_VEXEC)
161 mask |= S_IXUSR;
162 if (acc_mode & PUFFS_VREAD)
163 mask |= S_IRUSR;
164 if (acc_mode & PUFFS_VWRITE)
165 mask |= S_IWUSR;
166 /* group */
167 } else if (puffs_cred_hasgroup(pcr, gid)) {
168 if (acc_mode & PUFFS_VEXEC)
169 mask |= S_IXGRP;
170 if (acc_mode & PUFFS_VREAD)
171 mask |= S_IRGRP;
172 if (acc_mode & PUFFS_VWRITE)
173 mask |= S_IWGRP;
174 /* other */
175 } else {
176 if (acc_mode & PUFFS_VEXEC)
177 mask |= S_IXOTH;
178 if (acc_mode & PUFFS_VREAD)
179 mask |= S_IROTH;
180 if (acc_mode & PUFFS_VWRITE)
181 mask |= S_IWOTH;
182 }
183
184 if ((file_mode & mask) == mask)
185 return 0;
186 else
187 return EACCES;
188 }
189
190 int
191 puffs_access_chown(const struct puffs_cred *pcr, uid_t owner, gid_t group,
192 uid_t newowner, gid_t newgroup)
193 {
194
195 if (newowner == (uid_t)PUFFS_VNOVAL)
196 newowner = owner;
197 if (newgroup == (gid_t)PUFFS_VNOVAL)
198 newgroup = group;
199
200 if ((!puffs_cred_isuid(pcr, owner) || newowner != owner ||
201 ((newgroup != group && !puffs_cred_hasgroup(pcr, newgroup))))
202 && !puffs_cred_isjuggernaut(pcr))
203 return EPERM;
204
205 return 0;
206 }
207
208 int
209 puffs_access_chmod(const struct puffs_cred *pcr, uid_t owner, gid_t group,
210 enum vtype type, mode_t mode)
211 {
212
213 if (!puffs_cred_isuid(pcr, owner) && !puffs_cred_isuid(pcr, 0))
214 return EPERM;
215
216 if (!puffs_cred_isuid(pcr, 0)) {
217 if (type != VDIR && (mode & S_ISTXT))
218 return EFTYPE;
219 if (!puffs_cred_hasgroup(pcr, group) && (mode & S_ISGID))
220 return EPERM;
221 }
222
223 return 0;
224 }
225
226 int
227 puffs_access_times(const struct puffs_cred *pcr, uid_t uid, gid_t gid,
228 mode_t mode, int va_utimes_null)
229 {
230
231 if (!puffs_cred_isuid(pcr, uid) && !puffs_cred_isuid(pcr, 0)
232 && (va_utimes_null == 0
233 || puffs_access(VNON, mode, uid, gid, PUFFS_VWRITE, pcr) != 0))
234 return EPERM;
235
236 return 0;
237 }
238