xref: /csrg-svn/sys/kern/kern_prot.c (revision 40667)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)kern_prot.c	7.8 (Berkeley) 03/31/90
18  */
19 
20 /*
21  * System calls related to processes and protection
22  */
23 
24 #include "param.h"
25 #include "acct.h"
26 #include "systm.h"
27 #include "user.h"
28 #include "proc.h"
29 #include "timeb.h"
30 #include "times.h"
31 #include "reboot.h"
32 #include "mount.h"
33 #include "buf.h"
34 #include "../ufs/quota.h"
35 #include "malloc.h"
36 
37 #include "machine/reg.h"
38 
39 getpid()
40 {
41 
42 	u.u_r.r_val1 = u.u_procp->p_pid;
43 	u.u_r.r_val2 = u.u_procp->p_ppid;
44 }
45 
46 getpgrp()
47 {
48 	register struct a {
49 		int	pid;
50 	} *uap = (struct a *)u.u_ap;
51 	register struct proc *p;
52 
53 	if (uap->pid == 0)
54 		p = u.u_procp;
55 	else if ((p = pfind(uap->pid)) == 0) {
56 		u.u_error = ESRCH;
57 		return;
58 	}
59 	u.u_r.r_val1 = p->p_pgrp->pg_id;
60 }
61 
62 getuid()
63 {
64 
65 	u.u_r.r_val1 = u.u_procp->p_ruid;
66 	u.u_r.r_val2 = u.u_cred->cr_uid;
67 }
68 
69 getgid()
70 {
71 
72 	u.u_r.r_val1 = u.u_procp->p_rgid;
73 	u.u_r.r_val2 = u.u_cred->cr_groups[0];
74 }
75 
76 getgroups()
77 {
78 	register struct	a {
79 		u_int	gidsetsize;
80 		int	*gidset;
81 	} *uap = (struct a *)u.u_ap;
82 	register gid_t *gp;
83 	register int *lp;
84 	int groups[NGROUPS];
85 
86 	if (uap->gidsetsize == 0) {
87 		u.u_r.r_val1 = u.u_cred->cr_ngroups;
88 		return;
89 	}
90 	if (uap->gidsetsize < u.u_cred->cr_ngroups) {
91 		u.u_error = EINVAL;
92 		return;
93 	}
94 	uap->gidsetsize = u.u_cred->cr_ngroups;
95 	gp = u.u_cred->cr_groups;
96 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
97 		*lp++ = *gp++;
98 	u.u_error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
99 	    uap->gidsetsize * sizeof (groups[0]));
100 	if (u.u_error)
101 		return;
102 	u.u_r.r_val1 = uap->gidsetsize;
103 }
104 
105 setsid()
106 {
107 	register struct proc *p = u.u_procp;
108 
109 	if ((p->p_pgid == p->p_pid) || pgfind(p->p_pid))
110 		u.u_error = EPERM;
111 	else {
112 		pgmv(p, p->p_pid, 1);
113 		u.u_r.r_val1 = p->p_pid;
114 	}
115 	return;
116 }
117 
118 /*
119  * set process group
120  *
121  * caller does setpgrp(pid, pgid)
122  *
123  * pid must be caller or child of caller (ESRCH)
124  * if a child
125  *	pid must be in same session (EPERM)
126  *	pid can't have done an exec (EACCES)
127  * if pgid != pid
128  * 	there must exist some pid in same session having pgid (EPERM)
129  * pid must not be session leader (EPERM)
130  */
131 setpgrp()
132 {
133 	register struct a {
134 		int	pid;
135 		int	pgid;
136 	} *uap = (struct a *)u.u_ap;
137 	register struct proc *p;
138 	register struct pgrp *pgrp;
139 
140 	if (uap->pid == 0)
141 		p = u.u_procp;
142 	else if ((p = pfind(uap->pid)) == 0 || !inferior(p)) {
143 		u.u_error = ESRCH;
144 		return;
145 	}
146 	else if (p != u.u_procp) {
147 		if (p->p_session != u.u_procp->p_session) {
148 			u.u_error = EPERM;
149 			return;
150 		}
151 		if (p->p_flag&SEXEC) {
152 			u.u_error = EACCES;
153 			return;
154 		}
155 	}
156 	if (SESS_LEADER(p)) {
157 		u.u_error = EPERM;
158 		return;
159 	}
160 	if (uap->pgid == 0)
161 		uap->pgid = p->p_pid;
162 	else if ((uap->pgid != p->p_pid) &&
163 		(((pgrp = pgfind(uap->pgid)) == 0) ||
164 		   pgrp->pg_mem == NULL ||
165 	           pgrp->pg_session != u.u_procp->p_session)) {
166 		u.u_error = EPERM;
167 		return;
168 	}
169 	/*
170 	 * done checking, now doit
171 	 */
172 	pgmv(p, uap->pgid, 0);
173 }
174 
175 setreuid()
176 {
177 	struct a {
178 		int	ruid;
179 		int	euid;
180 	} *uap;
181 	register struct proc *p = u.u_procp;
182 	register int ruid, euid;
183 
184 	uap = (struct a *)u.u_ap;
185 	ruid = uap->ruid;
186 	if (ruid == -1)
187 		ruid = p->p_ruid;
188 #ifdef COMPAT_43
189 	if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ &&
190 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
191 #else
192 	if (ruid != p->p_ruid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
193 #endif
194 		return;
195 	euid = uap->euid;
196 	if (euid == -1)
197 		euid = u.u_cred->cr_uid;
198 	if (euid != u.u_cred->cr_uid && euid != p->p_ruid &&
199 	    euid != p->p_svuid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
200 		return;
201 	/*
202 	 * Everything's okay, do it.
203 	 * Copy credentials so other references do not
204 	 * see our changes.
205 	 */
206 #ifdef QUOTA
207 	if (u.u_quota->q_uid != ruid) {
208 		qclean();
209 		qstart(getquota((uid_t)ruid, 0, 0));
210 	}
211 #endif
212 	if (u.u_cred->cr_ref > 1)
213 		u.u_cred = crcopy(u.u_cred);
214 	u.u_cred->cr_uid = euid;
215 	p->p_uid = euid;
216 	p->p_ruid = ruid;
217 }
218 
219 setregid()
220 {
221 	register struct a {
222 		int	rgid;
223 		int	egid;
224 	} *uap;
225 	register int rgid, egid;
226 	register struct proc *p = u.u_procp;
227 
228 	uap = (struct a *)u.u_ap;
229 	rgid = uap->rgid;
230 	if (rgid == -1)
231 		rgid = p->p_rgid;
232 #ifdef COMPAT_43_XXX
233 	if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ &&
234 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
235 #else
236 	if (rgid != p->p_rgid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
237 #endif
238 		return;
239 	egid = uap->egid;
240 	if (egid == -1)
241 		egid = u.u_cred->cr_groups[0];
242 	if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid &&
243 	    egid != p->p_svgid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
244 		return;
245 	if (u.u_cred->cr_ref > 1)
246 		u.u_cred = crcopy(u.u_cred);
247 	p->p_rgid = rgid;
248 	u.u_cred->cr_groups[0] = egid;
249 }
250 
251 setgroups()
252 {
253 	register struct	a {
254 		u_int	gidsetsize;
255 		int	*gidset;
256 	} *uap = (struct a *)u.u_ap;
257 	register gid_t *gp;
258 	register int *lp;
259 	int ngrp, groups[NGROUPS];
260 
261 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
262 		return;
263 	ngrp = uap->gidsetsize;
264 	if (ngrp > NGROUPS) {
265 		u.u_error = EINVAL;
266 		return;
267 	}
268 	u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
269 	    uap->gidsetsize * sizeof (groups[0]));
270 	if (u.u_error)
271 		return;
272 	gp = u.u_cred->cr_groups;
273 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
274 		*gp++ = *lp++;
275 	u.u_cred->cr_ngroups = ngrp;
276 }
277 
278 /*
279  * Check if gid is a member of the group set.
280  */
281 groupmember(gid, cred)
282 	gid_t gid;
283 	register struct ucred *cred;
284 {
285 	register gid_t *gp;
286 	gid_t *egp;
287 
288 	egp = &(cred->cr_groups[cred->cr_ngroups]);
289 	for (gp = cred->cr_groups; gp < egp; gp++)
290 		if (*gp == gid)
291 			return (1);
292 	return (0);
293 }
294 
295 /*
296  * Test if the current user is the super user.
297  */
298 suser(cred, acflag)
299 	struct ucred *cred;
300 	short *acflag;
301 {
302 
303 	if (cred->cr_uid == 0) {
304 		if (acflag)
305 			*acflag |= ASU;
306 		return (0);
307 	}
308 	return (EPERM);
309 }
310 
311 /*
312  * Allocate a zeroed cred structure.
313  */
314 struct ucred *
315 crget()
316 {
317 	register struct ucred *cr;
318 
319 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
320 	bzero((caddr_t)cr, sizeof(*cr));
321 	cr->cr_ref = 1;
322 	return(cr);
323 }
324 
325 /*
326  * Free a cred structure.
327  * Throws away space when ref count gets to 0.
328  */
329 crfree(cr)
330 	struct ucred *cr;
331 {
332 	int	s = splimp();
333 
334 	if (--cr->cr_ref != 0) {
335 		(void) splx(s);
336 		return;
337 	}
338 	FREE((caddr_t)cr, M_CRED);
339 	(void) splx(s);
340 }
341 
342 /*
343  * Copy cred structure to a new one and free the old one.
344  */
345 struct ucred *
346 crcopy(cr)
347 	struct ucred *cr;
348 {
349 	struct ucred *newcr;
350 
351 	newcr = crget();
352 	*newcr = *cr;
353 	crfree(cr);
354 	newcr->cr_ref = 1;
355 	return(newcr);
356 }
357 
358 /*
359  * Dup cred struct to a new held one.
360  */
361 struct ucred *
362 crdup(cr)
363 	struct ucred *cr;
364 {
365 	struct ucred *newcr;
366 
367 	newcr = crget();
368 	*newcr = *cr;
369 	newcr->cr_ref = 1;
370 	return(newcr);
371 }
372 
373 /*
374  * Get login name, if available.
375  */
376 getlogin()
377 {
378 	struct a {
379 		char	*namebuf;
380 		u_int	namelen;
381 	} *uap = (struct a *)u.u_ap;
382 
383 	if (uap->namelen > sizeof (u.u_procp->p_logname))
384 		uap->namelen = sizeof (u.u_procp->p_logname);
385 	u.u_error = copyout((caddr_t)u.u_procp->p_logname,
386 			     (caddr_t)uap->namebuf, uap->namelen);
387 }
388 
389 /*
390  * Set login name.
391  */
392 setlogin()
393 {
394 	struct a {
395 		char	*namebuf;
396 	} *uap = (struct a *)u.u_ap;
397 	int error;
398 
399 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
400 		return;
401 	error = copyinstr((caddr_t)uap->namebuf, (caddr_t)u.u_procp->p_logname,
402 	    sizeof (u.u_procp->p_logname) - 1, (int *) 0);
403 	if (error == ENOENT)		/* name too long */
404 		error = EINVAL;
405 	u.u_error = error;
406 }
407