xref: /386bsd/usr/src/kernel/kern/cred.c (revision a2142627)
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