xref: /original-bsd/sys/kern/kern_prot.c (revision abe165e9)
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1990 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.11 (Berkeley) 06/21/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 "syscontext.h"
28 #include "proc.h"
29 #include "timeb.h"
30 #include "times.h"
31 #include "malloc.h"
32 
33 /* ARGSUSED */
34 getpid(p, uap, retval)
35 	struct proc *p;
36 	void *uap;
37 	int *retval;
38 {
39 
40 	*retval = p->p_pid;
41 #ifdef COMPAT_43
42 	retval[1] = p->p_ppid;
43 #endif
44 	RETURN (0);
45 }
46 
47 /* ARGSUSED */
48 getppid(p, uap, retval)
49 	struct proc *p;
50 	void *uap;
51 	int *retval;
52 {
53 
54 	*retval = p->p_ppid;
55 	RETURN (0);
56 }
57 
58 getpgrp(p, uap, retval)
59 	struct proc *p;
60 	struct args {
61 		int	pid;
62 	} *uap;
63 	int *retval;
64 {
65 
66 	if (uap->pid != 0 && (p = pfind(uap->pid)) == 0)
67 		RETURN (ESRCH);
68 	*retval = p->p_pgrp->pg_id;
69 	RETURN (0);
70 }
71 
72 /* ARGSUSED */
73 getuid(p, uap, retval)
74 	struct proc *p;
75 	void *uap;
76 	int *retval;
77 {
78 
79 	*retval = p->p_ruid;
80 #ifdef COMPAT_43
81 	retval[1] = u.u_cred->cr_uid;
82 #endif
83 	RETURN (0);
84 }
85 
86 /* ARGSUSED */
87 geteuid(p, uap, retval)
88 	struct proc *p;
89 	void *uap;
90 	int *retval;
91 {
92 
93 	*retval = u.u_cred->cr_uid;
94 	RETURN (0);
95 }
96 
97 /* ARGSUSED */
98 getgid(p, uap, retval)
99 	struct proc *p;
100 	void *uap;
101 	int *retval;
102 {
103 
104 	*retval = p->p_rgid;
105 #ifdef COMPAT_43
106 	retval[1] = u.u_cred->cr_groups[0];
107 #endif
108 	RETURN (0);
109 }
110 
111 /*
112  * Get effective group ID.
113  * The "egid" is groups[0], and thus could be obtained via getgroups;
114  * this is somewhat painful to do correctly in a library function,
115  * this the existence of this syscall.
116  */
117 /* ARGSUSED */
118 getegid(p, uap, retval)
119 	struct proc *p;
120 	void *uap;
121 	int *retval;
122 {
123 
124 	*retval = u.u_cred->cr_groups[0];
125 	RETURN (0);
126 }
127 
128 getgroups(p, uap, retval)
129 	struct proc *p;
130 	register struct	arg {
131 		u_int	gidsetsize;
132 		int	*gidset;		/* XXX not yet POSIX */
133 	} *uap;
134 	int *retval;
135 {
136 	register gid_t *gp;
137 	register int *lp;
138 	int groups[NGROUPS];
139 	int error;
140 
141 	if (uap->gidsetsize == 0) {
142 		*retval = u.u_cred->cr_ngroups;
143 		RETURN (0);
144 	}
145 	if (uap->gidsetsize < u.u_cred->cr_ngroups)
146 		RETURN (EINVAL);
147 	uap->gidsetsize = u.u_cred->cr_ngroups;
148 	gp = u.u_cred->cr_groups;
149 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
150 		*lp++ = *gp++;
151 	if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
152 	    uap->gidsetsize * sizeof (groups[0])))
153 		RETURN (error);
154 	*retval = uap->gidsetsize;
155 	RETURN (0);
156 }
157 
158 /* ARGSUSED */
159 setsid(p, uap, retval)
160 	struct proc *p;
161 	void *uap;
162 	int *retval;
163 {
164 
165 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
166 		RETURN (EPERM);
167 	} else {
168 		pgmv(p, p->p_pid, 1);
169 		*retval = p->p_pid;
170 		RETURN (0);
171 	}
172 }
173 
174 /*
175  * set process group (setpgrp/setpgid)
176  *
177  * caller does setpgrp(pid, pgid)
178  *
179  * pid must be caller or child of caller (ESRCH)
180  * if a child
181  *	pid must be in same session (EPERM)
182  *	pid can't have done an exec (EACCES)
183  * if pgid != pid
184  * 	there must exist some pid in same session having pgid (EPERM)
185  * pid must not be session leader (EPERM)
186  */
187 /* ARGSUSED */
188 setpgrp(cp, uap, retval)
189 	struct proc *cp;
190 	register struct args {
191 		int	pid;
192 		int	pgid;
193 	} *uap;
194 	int *retval;
195 {
196 	register struct proc *p;
197 	register struct pgrp *pgrp;
198 
199 	if (uap->pid != 0) {
200 		if ((p = pfind(uap->pid)) == 0 || !inferior(p))
201 			RETURN (ESRCH);
202 		if (p->p_session != cp->p_session)
203 			RETURN (EPERM);
204 		if (p->p_flag&SEXEC)
205 			RETURN (EACCES);
206 	} else
207 		p = cp;
208 	if (SESS_LEADER(p))
209 		RETURN (EPERM);
210 	if (uap->pgid == 0)
211 		uap->pgid = p->p_pid;
212 	else if ((uap->pgid != p->p_pid) &&
213 		(((pgrp = pgfind(uap->pgid)) == 0) ||
214 		   pgrp->pg_mem == NULL ||
215 	           pgrp->pg_session != u.u_procp->p_session))
216 		RETURN (EPERM);
217 	/*
218 	 * done checking, now do it
219 	 */
220 	pgmv(p, uap->pgid, 0);
221 	RETURN (0);
222 }
223 
224 /* ARGSUSED */
225 setuid(p, uap, retval)
226 	register struct proc *p;
227 	struct args {
228 		int	uid;
229 	} *uap;
230 	int *retval;
231 {
232 	register uid_t uid;
233 	int error;
234 
235 	uid = uap->uid;
236 	if (uid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag)))
237 		RETURN (error);
238 	/*
239 	 * Everything's okay, do it.
240 	 * Copy credentials so other references do not
241 	 * see our changes.
242 	 */
243 	if (u.u_cred->cr_ref > 1)
244 		u.u_cred = crcopy(u.u_cred);
245 	u.u_cred->cr_uid = uid;
246 	p->p_uid = uid;
247 	p->p_ruid = uid;
248 	p->p_svuid = uid;
249 	RETURN (0);
250 }
251 
252 /* ARGSUSED */
253 seteuid(p, uap, retval)
254 	register struct proc *p;
255 	struct args {
256 		int	euid;
257 	} *uap;
258 	int *retval;
259 {
260 	register uid_t euid;
261 	int error;
262 
263 	euid = uap->euid;
264 	if (euid != p->p_ruid && euid != p->p_svuid &&
265 	    (error = suser(u.u_cred, &u.u_acflag)))
266 		RETURN (error);
267 	/*
268 	 * Everything's okay, do it.
269 	 * Copy credentials so other references do not
270 	 * see our changes.
271 	 */
272 	if (u.u_cred->cr_ref > 1)
273 		u.u_cred = crcopy(u.u_cred);
274 	u.u_cred->cr_uid = euid;
275 	p->p_uid = euid;
276 	RETURN (0);
277 }
278 
279 /* ARGSUSED */
280 setgid(p, uap, retval)
281 	struct proc *p;
282 	struct args {
283 		int	gid;
284 	} *uap;
285 	int *retval;
286 {
287 	register gid_t gid;
288 	int error;
289 
290 	gid = uap->gid;
291 	if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag)))
292 		RETURN (error);
293 	if (u.u_cred->cr_ref > 1)
294 		u.u_cred = crcopy(u.u_cred);
295 	p->p_rgid = gid;
296 	u.u_cred->cr_groups[0] = gid;
297 	p->p_svgid = gid;		/* ??? */
298 	RETURN (0);
299 }
300 
301 /* ARGSUSED */
302 setegid(p, uap, retval)
303 	struct proc *p;
304 	struct args {
305 		int	egid;
306 	} *uap;
307 	int *retval;
308 {
309 	register gid_t egid;
310 	int error;
311 
312 	egid = uap->egid;
313 	if (egid != p->p_rgid && egid != p->p_svgid &&
314 	    (error = suser(u.u_cred, &u.u_acflag)))
315 		RETURN (error);
316 	if (u.u_cred->cr_ref > 1)
317 		u.u_cred = crcopy(u.u_cred);
318 	u.u_cred->cr_groups[0] = egid;
319 	RETURN (0);
320 }
321 
322 #ifdef COMPAT_43
323 /* ARGSUSED */
324 osetreuid(p, uap, retval)
325 	register struct proc *p;
326 	struct args {
327 		int	ruid;
328 		int	euid;
329 	} *uap;
330 	int *retval;
331 {
332 	register uid_t ruid, euid;
333 	int error;
334 
335 	if (uap->ruid == -1)
336 		ruid = p->p_ruid;
337 	else
338 		ruid = uap->ruid;
339 	/*
340 	 * Allow setting real uid to previous effective,
341 	 * for swapping real and effective.
342 	 * This should be:
343 	 *   if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag)))
344 	 */
345 	if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ &&
346 	    (error = suser(u.u_cred, &u.u_acflag)))
347 		RETURN (error);
348 	if (uap->euid == -1)
349 		euid = u.u_cred->cr_uid;
350 	else
351 		euid = uap->euid;
352 	if (euid != u.u_cred->cr_uid && euid != p->p_ruid &&
353 	    euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag)))
354 		RETURN (error);
355 	/*
356 	 * Everything's okay, do it.
357 	 * Copy credentials so other references do not
358 	 * see our changes.
359 	 */
360 	if (u.u_cred->cr_ref > 1)
361 		u.u_cred = crcopy(u.u_cred);
362 	u.u_cred->cr_uid = euid;
363 	p->p_uid = euid;
364 	p->p_ruid = ruid;
365 	RETURN (0);
366 }
367 
368 /* ARGSUSED */
369 osetregid(p, uap, retval)
370 	struct proc *p;
371 	struct args {
372 		int	rgid;
373 		int	egid;
374 	} *uap;
375 	int *retval;
376 {
377 	register gid_t rgid, egid;
378 	int error;
379 
380 	if (uap->rgid == -1)
381 		rgid = p->p_rgid;
382 	else
383 		rgid = uap->rgid;
384 	/*
385 	 * Allow setting real gid to previous effective,
386 	 * for swapping real and effective.  This didn't really work
387 	 * correctly in 4.[23], but is preserved so old stuff doesn't fail.
388 	 * This should be:
389 	 *  if (rgid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag)))
390 	 */
391 	if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ &&
392 	    (error = suser(u.u_cred, &u.u_acflag)))
393 		RETURN (error);
394 	if (uap->egid == -1)
395 		egid = u.u_cred->cr_groups[0];
396 	else
397 		egid = uap->egid;
398 	if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid &&
399 	    egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag)))
400 		RETURN (error);
401 	if (u.u_cred->cr_ref > 1)
402 		u.u_cred = crcopy(u.u_cred);
403 	p->p_rgid = rgid;
404 	u.u_cred->cr_groups[0] = egid;
405 	RETURN (0);
406 }
407 #endif
408 
409 /* ARGSUSED */
410 setgroups(p, uap, retval)
411 	struct proc *p;
412 	struct args {
413 		u_int	gidsetsize;
414 		int	*gidset;
415 	} *uap;
416 	int *retval;
417 {
418 	register gid_t *gp;
419 	register int *lp;
420 	int error, ngrp, groups[NGROUPS];
421 
422 	if (error = suser(u.u_cred, &u.u_acflag))
423 		RETURN (error);
424 	ngrp = uap->gidsetsize;
425 	if (ngrp > NGROUPS)
426 		RETURN (EINVAL);
427 	error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
428 	    uap->gidsetsize * sizeof (groups[0]));
429 	if (error)
430 		RETURN (error);
431 	gp = u.u_cred->cr_groups;
432 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
433 		*gp++ = *lp++;
434 	u.u_cred->cr_ngroups = ngrp;
435 	RETURN (0);
436 }
437 
438 /*
439  * Check if gid is a member of the group set.
440  */
441 groupmember(gid, cred)
442 	gid_t gid;
443 	register struct ucred *cred;
444 {
445 	register gid_t *gp;
446 	gid_t *egp;
447 
448 	egp = &(cred->cr_groups[cred->cr_ngroups]);
449 	for (gp = cred->cr_groups; gp < egp; gp++)
450 		if (*gp == gid)
451 			return (1);
452 	return (0);
453 }
454 
455 /*
456  * Test if the current user is the super user.
457  */
458 suser(cred, acflag)
459 	struct ucred *cred;
460 	short *acflag;
461 {
462 
463 	if (cred->cr_uid == 0) {
464 		if (acflag)
465 			*acflag |= ASU;
466 		return (0);
467 	}
468 	return (EPERM);
469 }
470 
471 /*
472  * Allocate a zeroed cred structure.
473  */
474 struct ucred *
475 crget()
476 {
477 	register struct ucred *cr;
478 
479 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
480 	bzero((caddr_t)cr, sizeof(*cr));
481 	cr->cr_ref = 1;
482 	return (cr);
483 }
484 
485 /*
486  * Free a cred structure.
487  * Throws away space when ref count gets to 0.
488  */
489 crfree(cr)
490 	struct ucred *cr;
491 {
492 	int s = splimp();
493 
494 	if (--cr->cr_ref != 0) {
495 		(void) splx(s);
496 		return;
497 	}
498 	FREE((caddr_t)cr, M_CRED);
499 	(void) splx(s);
500 }
501 
502 /*
503  * Copy cred structure to a new one and free the old one.
504  */
505 struct ucred *
506 crcopy(cr)
507 	struct ucred *cr;
508 {
509 	struct ucred *newcr;
510 
511 	newcr = crget();
512 	*newcr = *cr;
513 	crfree(cr);
514 	newcr->cr_ref = 1;
515 	return (newcr);
516 }
517 
518 /*
519  * Dup cred struct to a new held one.
520  */
521 struct ucred *
522 crdup(cr)
523 	struct ucred *cr;
524 {
525 	struct ucred *newcr;
526 
527 	newcr = crget();
528 	*newcr = *cr;
529 	newcr->cr_ref = 1;
530 	return (newcr);
531 }
532 
533 /*
534  * Get login name, if available.
535  */
536 /* ARGSUSED */
537 getlogin(p, uap, retval)
538 	struct proc *p;
539 	struct args {
540 		char	*namebuf;
541 		u_int	namelen;
542 	} *uap;
543 	int *retval;
544 {
545 
546 	if (uap->namelen > sizeof (p->p_logname))
547 		uap->namelen = sizeof (p->p_logname);
548 	RETURN (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf,
549 	    uap->namelen));
550 }
551 
552 /*
553  * Set login name.
554  */
555 /* ARGSUSED */
556 setlogin(p, uap, retval)
557 	struct proc *p;
558 	struct args {
559 		char	*namebuf;
560 	} *uap;
561 	int *retval;
562 {
563 	int error;
564 
565 	if (error = suser(u.u_cred, &u.u_acflag))
566 		RETURN (error);
567 	error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname,
568 	    sizeof (p->p_logname) - 1, (int *) 0);
569 	if (error == ENOENT)		/* name too long */
570 		error = EINVAL;
571 	RETURN (error);
572 }
573