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