1 /*
2 * Copyright (c) 1982, 1986, 1989, 1990, 1991 Regents of the University
3 * of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * $Id: cred.c,v 1.1 94/10/20 00:02:48 bill Exp $
34 */
35
36 /*
37 * System calls related to process protection
38 */
39
40 #include "sys/param.h"
41 #include "sys/errno.h"
42 #include "proc.h"
43 #include "privilege.h"
44 #include "malloc.h"
45 #include "prototypes.h"
46
47 /* if process credentials are to be modified, check if they need to unshare */
48 struct pcred *
modpcred(struct proc * p)49 modpcred(struct proc *p) {
50 struct pcred *pc = p->p_cred;
51
52 /* if not uniquely used, generate unique copy of process credentials */
53 if (pc->p_refcnt != 1) {
54 MALLOC(pc, struct pcred *, sizeof(struct pcred),
55 M_SUBPROC, M_WAITOK);
56 *pc = *p->p_cred;
57 pc->p_refcnt = 1;
58 p->p_cred->p_refcnt--;
59 p->p_cred = pc;
60
61 /* user credentials now referenced by both */
62 crhold(p->p_ucred);
63 }
64
65 /* need to generate an unshared copy of user credentials also ? */
66 if (pc->pc_ucred->cr_ref != 1) {
67 /* duplicate the old one */
68 struct ucred *newcr = crdup(pc->pc_ucred);
69
70 /* release the old reference */
71 crfree(pc->pc_ucred);
72 pc->pc_ucred = newcr;
73 }
74
75 return (pc);
76 }
77
78 /* POSIX get current processes real user ID */
79 int
getuid(p,uap,retval)80 getuid(p, uap, retval)
81 struct proc *p;
82 void *uap;
83 int *retval;
84 {
85
86 *retval = p->p_cred->p_ruid;
87 return (0);
88 }
89
90 /* POSIX get current processes effective user ID */
91 int
geteuid(p,uap,retval)92 geteuid(p, uap, retval)
93 struct proc *p;
94 void *uap;
95 int *retval;
96 {
97
98 *retval = p->p_ucred->cr_uid;
99 return (0);
100 }
101
102 /* POSIX get current processes real group ID */
103 int
getgid(p,uap,retval)104 getgid(p, uap, retval)
105 struct proc *p;
106 void *uap;
107 int *retval;
108 {
109
110 *retval = p->p_cred->p_rgid;
111 return (0);
112 }
113
114 /* POSIX get current processes effective group ID */
115 int
getegid(p,uap,retval)116 getegid(p, uap, retval)
117 struct proc *p;
118 void *uap;
119 int *retval;
120 {
121
122 *retval = p->p_ucred->cr_groups[0];
123 return (0);
124 }
125
126 /* BSD get supplimentary groups */
127 int
getgroups(p,uap,retval)128 getgroups(p, uap, retval)
129 struct proc *p;
130 struct arg {
131 u_int gidsetsize;
132 int *gidset; /* XXX not yet POSIX */
133 } *uap;
134 int *retval;
135 {
136 struct pcred *pc = p->p_cred;
137 gid_t *gp;
138 int *lp;
139 u_int ngrp;
140 int groups[NGROUPS_MAX];
141 int error;
142
143 /* inquiry for number of groups present in this process group set */
144 if ((ngrp = uap->gidsetsize) == 0) {
145 *retval = pc->pc_ucred->cr_ngroups;
146 return (0);
147 }
148
149 /* if the receiving buffer cannot contain all groups in full, fail */
150 if (ngrp < pc->pc_ucred->cr_ngroups)
151 return (EINVAL);
152
153 /* collect supplemental groups into an integer array buffer */
154 ngrp = pc->pc_ucred->cr_ngroups;
155 for (gp = pc->pc_ucred->cr_groups, lp = groups; lp < &groups[ngrp]; )
156 *lp++ = *gp++;
157
158 /* pass the array buffer back to the user process */
159 if (error = copyout(p, (caddr_t)groups, (caddr_t)uap->gidset,
160 ngrp * sizeof (groups[0])))
161 return (error);
162
163 /* return number of groups returned */
164 *retval = ngrp;
165 return (0);
166 }
167
168 /* POSIX set the real user id of the process */
169 int
setuid(p,uap,retval)170 setuid(p, uap, retval)
171 struct proc *p;
172 struct args {
173 int uid;
174 } *uap;
175 int *retval;
176 {
177 struct pcred *pc = p->p_cred;
178 uid_t uid = uap->uid;
179 int error;
180
181 /* privilege to change user id? */
182 if (uid != pc->p_ruid &&
183 (error = use_priv(pc->pc_ucred, PRV_SETUID, p)))
184 return (error);
185
186 /* modify process and user credentials to new real user id */
187 pc = modpcred(p);
188 pc->pc_ucred->cr_uid = uid;
189 pc->p_ruid = uid;
190 pc->p_svuid = uid;
191
192 return (0);
193 }
194
195 /* POSIX set the effective user id of the process */
196 int
seteuid(p,uap,retval)197 seteuid(p, uap, retval)
198 struct proc *p;
199 struct args {
200 int euid;
201 } *uap;
202 int *retval;
203 {
204 struct pcred *pc = p->p_cred;
205 uid_t euid = uap->euid;
206 int error;
207
208 /* privilege to change just effective user id? */
209 if (euid != pc->p_ruid && euid != pc->p_svuid &&
210 (error = use_priv(pc->pc_ucred, PRV_SETUID, p)))
211 return (error);
212
213 /* modify user credentials to new effective user id */
214 pc = modpcred(p);
215 pc->pc_ucred->cr_uid = euid;
216
217 return (0);
218 }
219
220 /* POSIX set the real group id of the process */
221 int
setgid(p,uap,retval)222 setgid(p, uap, retval)
223 struct proc *p;
224 struct args {
225 int gid;
226 } *uap;
227 int *retval;
228 {
229 struct pcred *pc = p->p_cred;
230 gid_t gid = uap->gid;
231 int error;
232
233 /* privilege to change group id? */
234 if (gid != pc->p_rgid &&
235 (error = use_priv(pc->pc_ucred, PRV_SETGID, p)))
236 return (error);
237
238 /* modify user and process credentials to new group id */
239 pc = modpcred(p);
240 pc->pc_ucred->cr_groups[0] = gid;
241 pc->p_rgid = gid;
242 pc->p_svgid = gid;
243
244 return (0);
245 }
246
247 /* POSIX set effective group id of the current process */
248 int
setegid(p,uap,retval)249 setegid(p, uap, retval)
250 struct proc *p;
251 struct args {
252 int egid;
253 } *uap;
254 int *retval;
255 {
256 struct pcred *pc = p->p_cred;
257 gid_t egid = uap->egid;
258 int error;
259
260 /* privilege to change just effective group id? */
261 if (egid != pc->p_rgid && egid != pc->p_svgid &&
262 (error = use_priv(pc->pc_ucred, PRV_SETGID, p)))
263 return (error);
264
265 /* modify user credentials to new effective group id */
266 pc = modpcred(p);
267 pc->pc_ucred->cr_groups[0] = egid;
268
269 return (0);
270 }
271
272 /* BSD set supplementary group set */
273 int
setgroups(p,uap,retval)274 setgroups(p, uap, retval)
275 struct proc *p;
276 struct args {
277 u_int gidsetsize;
278 int *gidset;
279 } *uap;
280 int *retval;
281 {
282 struct pcred *pc = p->p_cred;
283 gid_t *gp;
284 u_int ngrp;
285 int *lp, error, groups[NGROUPS_MAX];
286
287 /* privilege to set groups */
288 if (error = use_priv(pc->pc_ucred, PRV_SETGID, p))
289 return (error);
290
291 /* more groups than implemented? */
292 if ((ngrp = uap->gidsetsize) > NGROUPS_MAX)
293 return (EINVAL);
294
295 /* copy into temporary buffer array from user process */
296 if (error = copyin(p, (caddr_t)uap->gidset, (caddr_t)groups,
297 ngrp * sizeof (groups[0])))
298 return (error);
299
300 /* modify process credentials to suit */
301 pc = modpcred(p);
302 pc->pc_ucred->cr_ngroups = ngrp;
303
304 /* convert from int's to gid_t's */
305 for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; )
306 *gp++ = *lp++;
307
308 return (0);
309 }
310
311 /* check if gid is a member of this user credential. */
312 int
groupmember(gid_t gid,const struct ucred * cred)313 groupmember(gid_t gid, const struct ucred *cred)
314 {
315 gid_t *gp, *egp = &(cred->cr_groups[cred->cr_ngroups]);
316
317 /* sift through supplimental group set array in user credentials */
318 for (gp = cred->cr_groups; gp < egp; gp++)
319 if (*gp == gid)
320 return (1);
321
322 return (0);
323 }
324
325 /* allocate a fresh, zeroed set of credentials */
326 struct ucred *
crget()327 crget()
328 {
329 struct ucred *cr;
330
331 MALLOC(cr, struct ucred *, sizeof(struct ucred), M_CRED, M_WAITOK);
332 (void) memset((caddr_t)cr, 0, sizeof(*cr));
333 cr->cr_ref = 1;
334 return (cr);
335 }
336
337 /* release a reference on a user credential set, and free when unreferenced */
338 void
crfree(struct ucred * cr)339 crfree(struct ucred *cr)
340 {
341
342 if (--cr->cr_ref != 0)
343 return;
344 FREE((caddr_t)cr, M_CRED);
345 }
346
347 /* replicate a user credential set */
348 struct ucred *
crdup(const struct ucred * cr)349 crdup(const struct ucred *cr)
350 {
351 struct ucred *newcr;
352
353 newcr = crget();
354 *newcr = *cr;
355 newcr->cr_ref = 1;
356 return (newcr);
357 }
358
359 /* BSD get login name. */
360 int
getlogin(p,uap,retval)361 getlogin(p, uap, retval)
362 struct proc *p;
363 struct args {
364 char *namebuf;
365 u_int namelen;
366 } *uap;
367 const int *retval;
368 {
369
370 /* bounds limit string buffer to login buffer */
371 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
372 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
373
374 /* return string buffer, partial or all */
375 return (copyout(p, (caddr_t) p->p_pgrp->pg_session->s_login,
376 (caddr_t) uap->namebuf, uap->namelen));
377 }
378
379 /* BSD set login name. */
380 int
setlogin(p,uap,retval)381 setlogin(p, uap, retval)
382 struct proc *p;
383 struct args {
384 char *namebuf;
385 /* int role; */
386 } *uap;
387 int *retval;
388 {
389 int error;
390
391 /* privilege to set login id? */
392 if (error = use_priv(p->p_ucred, PRV_SETLOGIN, p))
393 return (error);
394
395 /* copy in variable length string into fixed length field */
396 error = copyinstr(p, (caddr_t) uap->namebuf,
397 (caddr_t) p->p_pgrp->pg_session->s_login,
398 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
399 if (error == ENAMETOOLONG)
400 error = EINVAL;
401
402 /* if successful, modify process credentials to assign role */
403 if (error == 0) {
404 struct pcred *pc = modpcred(p);
405
406 pc->pc_ucred->cr_role = 0 /*role */;
407 }
408 return (error);
409 }
410