xref: /original-bsd/sys/kern/kern_prot.c (revision 58b1b499)
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * %sccs.include.redist.c%
11  *
12  *	@(#)kern_prot.c	8.9 (Berkeley) 02/14/95
13  */
14 
15 /*
16  * System calls related to processes and protection
17  */
18 
19 #include <sys/param.h>
20 #include <sys/acct.h>
21 #include <sys/systm.h>
22 #include <sys/ucred.h>
23 #include <sys/proc.h>
24 #include <sys/timeb.h>
25 #include <sys/times.h>
26 #include <sys/malloc.h>
27 
28 #include <sys/mount.h>
29 #include <sys/syscallargs.h>
30 
31 /* ARGSUSED */
32 int
33 getpid(p, uap, retval)
34 	struct proc *p;
35 	void *uap;
36 	register_t *retval;
37 {
38 
39 	*retval = p->p_pid;
40 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
41 	retval[1] = p->p_pptr->p_pid;
42 #endif
43 	return (0);
44 }
45 
46 /* ARGSUSED */
47 int
48 getppid(p, uap, retval)
49 	struct proc *p;
50 	void *uap;
51 	register_t *retval;
52 {
53 
54 	*retval = p->p_pptr->p_pid;
55 	return (0);
56 }
57 
58 /* Get process group ID; note that POSIX getpgrp takes no parameter */
59 int
60 getpgrp(p, uap, retval)
61 	struct proc *p;
62 	void *uap;
63 	register_t *retval;
64 {
65 
66 	*retval = p->p_pgrp->pg_id;
67 	return (0);
68 }
69 
70 /* ARGSUSED */
71 int
72 getuid(p, uap, retval)
73 	struct proc *p;
74 	void *uap;
75 	register_t *retval;
76 {
77 
78 	*retval = p->p_cred->p_ruid;
79 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
80 	retval[1] = p->p_ucred->cr_uid;
81 #endif
82 	return (0);
83 }
84 
85 /* ARGSUSED */
86 int
87 geteuid(p, uap, retval)
88 	struct proc *p;
89 	void *uap;
90 	register_t *retval;
91 {
92 
93 	*retval = p->p_ucred->cr_uid;
94 	return (0);
95 }
96 
97 /* ARGSUSED */
98 int
99 getgid(p, uap, retval)
100 	struct proc *p;
101 	void *uap;
102 	register_t *retval;
103 {
104 
105 	*retval = p->p_cred->p_rgid;
106 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
107 	retval[1] = p->p_ucred->cr_groups[0];
108 #endif
109 	return (0);
110 }
111 
112 /*
113  * Get effective group ID.  The "egid" is groups[0], and could be obtained
114  * via getgroups.  This syscall exists because it is somewhat painful to do
115  * correctly in a library function.
116  */
117 /* ARGSUSED */
118 int
119 getegid(p, uap, retval)
120 	struct proc *p;
121 	void *uap;
122 	register_t *retval;
123 {
124 
125 	*retval = p->p_ucred->cr_groups[0];
126 	return (0);
127 }
128 
129 int
130 getgroups(p, uap, retval)
131 	struct proc *p;
132 	register struct getgroups_args /* {
133 		syscallarg(u_int) gidsetsize;
134 		syscallarg(gid_t *) gidset;
135 	} */ *uap;
136 	register_t *retval;
137 {
138 	register struct pcred *pc = p->p_cred;
139 	register u_int ngrp;
140 	int error;
141 
142 	if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
143 		*retval = pc->pc_ucred->cr_ngroups;
144 		return (0);
145 	}
146 	if (ngrp < pc->pc_ucred->cr_ngroups)
147 		return (EINVAL);
148 	ngrp = pc->pc_ucred->cr_ngroups;
149 	if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
150 	    (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)))
151 		return (error);
152 	*retval = ngrp;
153 	return (0);
154 }
155 
156 /* ARGSUSED */
157 int
158 setsid(p, uap, retval)
159 	register struct proc *p;
160 	void *uap;
161 	register_t *retval;
162 {
163 
164 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
165 		return (EPERM);
166 	} else {
167 		(void)enterpgrp(p, p->p_pid, 1);
168 		*retval = p->p_pid;
169 		return (0);
170 	}
171 }
172 
173 /*
174  * set process group (setpgid/old setpgrp)
175  *
176  * caller does setpgid(targpid, targpgid)
177  *
178  * pid must be caller or child of caller (ESRCH)
179  * if a child
180  *	pid must be in same session (EPERM)
181  *	pid can't have done an exec (EACCES)
182  * if pgid != pid
183  * 	there must exist some pid in same session having pgid (EPERM)
184  * pid must not be session leader (EPERM)
185  */
186 /* ARGSUSED */
187 int
188 setpgid(curp, uap, retval)
189 	struct proc *curp;
190 	register struct setpgid_args /* {
191 		syscallarg(int) pid;
192 		syscallarg(int) pgid;
193 	} */ *uap;
194 	register_t *retval;
195 {
196 	register struct proc *targp;		/* target process */
197 	register struct pgrp *pgrp;		/* target pgrp */
198 
199 	if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
200 		if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
201 			return (ESRCH);
202 		if (targp->p_session != curp->p_session)
203 			return (EPERM);
204 		if (targp->p_flag & P_EXEC)
205 			return (EACCES);
206 	} else
207 		targp = curp;
208 	if (SESS_LEADER(targp))
209 		return (EPERM);
210 	if (SCARG(uap, pgid) == 0)
211 		SCARG(uap, pgid) = targp->p_pid;
212 	else if (SCARG(uap, pgid) != targp->p_pid)
213 		if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
214 	            pgrp->pg_session != curp->p_session)
215 			return (EPERM);
216 	return (enterpgrp(targp, SCARG(uap, pgid), 0));
217 }
218 
219 /* ARGSUSED */
220 int
221 setuid(p, uap, retval)
222 	struct proc *p;
223 	struct setuid_args /* {
224 		syscallarg(uid_t) uid;
225 	} */ *uap;
226 	register_t *retval;
227 {
228 	register struct pcred *pc = p->p_cred;
229 	register uid_t uid;
230 	int error;
231 
232 	uid = SCARG(uap, uid);
233 	if (uid != pc->p_ruid &&
234 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
235 		return (error);
236 	/*
237 	 * Everything's okay, do it.
238 	 * Transfer proc count to new user.
239 	 * Copy credentials so other references do not see our changes.
240 	 */
241 	(void)chgproccnt(pc->p_ruid, -1);
242 	(void)chgproccnt(uid, 1);
243 	pc->pc_ucred = crcopy(pc->pc_ucred);
244 	pc->pc_ucred->cr_uid = uid;
245 	pc->p_ruid = uid;
246 	pc->p_svuid = uid;
247 	p->p_flag |= P_SUGID;
248 	return (0);
249 }
250 
251 /* ARGSUSED */
252 int
253 seteuid(p, uap, retval)
254 	struct proc *p;
255 	struct seteuid_args /* {
256 		syscallarg(uid_t) euid;
257 	} */ *uap;
258 	register_t *retval;
259 {
260 	register struct pcred *pc = p->p_cred;
261 	register uid_t euid;
262 	int error;
263 
264 	euid = SCARG(uap, euid);
265 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
266 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
267 		return (error);
268 	/*
269 	 * Everything's okay, do it.  Copy credentials so other references do
270 	 * not see our changes.
271 	 */
272 	pc->pc_ucred = crcopy(pc->pc_ucred);
273 	pc->pc_ucred->cr_uid = euid;
274 	p->p_flag |= P_SUGID;
275 	return (0);
276 }
277 
278 /* ARGSUSED */
279 int
280 setgid(p, uap, retval)
281 	struct proc *p;
282 	struct setgid_args /* {
283 		syscallarg(gid_t) gid;
284 	} */ *uap;
285 	register_t *retval;
286 {
287 	register struct pcred *pc = p->p_cred;
288 	register gid_t gid;
289 	int error;
290 
291 	gid = SCARG(uap, gid);
292 	if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
293 		return (error);
294 	pc->pc_ucred = crcopy(pc->pc_ucred);
295 	pc->pc_ucred->cr_groups[0] = gid;
296 	pc->p_rgid = gid;
297 	pc->p_svgid = gid;		/* ??? */
298 	p->p_flag |= P_SUGID;
299 	return (0);
300 }
301 
302 /* ARGSUSED */
303 int
304 setegid(p, uap, retval)
305 	struct proc *p;
306 	struct setegid_args /* {
307 		syscallarg(gid_t) egid;
308 	} */ *uap;
309 	register_t *retval;
310 {
311 	register struct pcred *pc = p->p_cred;
312 	register gid_t egid;
313 	int error;
314 
315 	egid = SCARG(uap, egid);
316 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
317 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
318 		return (error);
319 	pc->pc_ucred = crcopy(pc->pc_ucred);
320 	pc->pc_ucred->cr_groups[0] = egid;
321 	p->p_flag |= P_SUGID;
322 	return (0);
323 }
324 
325 /* ARGSUSED */
326 int
327 setgroups(p, uap, retval)
328 	struct proc *p;
329 	struct setgroups_args /* {
330 		syscallarg(u_int) gidsetsize;
331 		syscallarg(gid_t *) gidset;
332 	} */ *uap;
333 	register_t *retval;
334 {
335 	register struct pcred *pc = p->p_cred;
336 	register u_int ngrp;
337 	int error;
338 
339 	if (error = suser(pc->pc_ucred, &p->p_acflag))
340 		return (error);
341 	ngrp = SCARG(uap, gidsetsize);
342 	if (ngrp < 1 || ngrp > NGROUPS)
343 		return (EINVAL);
344 	pc->pc_ucred = crcopy(pc->pc_ucred);
345 	if (error = copyin((caddr_t)SCARG(uap, gidset),
346 	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))
347 		return (error);
348 	pc->pc_ucred->cr_ngroups = ngrp;
349 	p->p_flag |= P_SUGID;
350 	return (0);
351 }
352 
353 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
354 /* ARGSUSED */
355 int
356 compat_43_setreuid(p, uap, retval)
357 	register struct proc *p;
358 	struct compat_43_setreuid_args /* {
359 		syscallarg(int) ruid;
360 		syscallarg(int) euid;
361 	} */ *uap;
362 	register_t *retval;
363 {
364 	register struct pcred *pc = p->p_cred;
365 	union {
366 		struct setuid_args sa;
367 		struct seteuid_args ea;
368 	} args;
369 
370 	/*
371 	 * If ruid == euid then setreuid is being used to emulate setuid,
372 	 * just do it.
373 	 */
374 	if (SCARG(uap, ruid) != -1 && SCARG(uap, ruid) == SCARG(uap, euid)) {
375 		SCARG(&args.sa, uid) = SCARG(uap, ruid);
376 		return (setuid(p, &args.sa, retval));
377 	}
378 	/*
379 	 * Otherwise we assume that the intent of setting ruid is to be
380 	 * able to get back ruid priviledge (i.e. swapping ruid and euid).
381 	 * So we make sure that we will be able to do so, but do not
382 	 * actually set the ruid.
383 	 */
384 	if (SCARG(uap, ruid) != (uid_t)-1 && SCARG(uap, ruid) != pc->p_ruid &&
385 	    SCARG(uap, ruid) != pc->p_svuid)
386 		return (EPERM);
387 	if (SCARG(uap, euid) == (uid_t)-1)
388 		return (0);
389 	SCARG(&args.ea, euid) = SCARG(uap, euid);
390 	return (seteuid(p, &args.ea, retval));
391 }
392 
393 /* ARGSUSED */
394 int
395 compat_43_setregid(p, uap, retval)
396 	register struct proc *p;
397 	struct compat_43_setregid_args /* {
398 		syscallarg(int) rgid;
399 		syscallarg(int) egid;
400 	} */ *uap;
401 	register_t *retval;
402 {
403 	register struct pcred *pc = p->p_cred;
404 	union {
405 		struct setgid_args sa;
406 		struct setegid_args ea;
407 	} args;
408 
409 	/*
410 	 * If rgid == egid then setreuid is being used to emulate setgid,
411 	 * just do it.
412 	 */
413 	if (SCARG(uap, rgid) != -1 && SCARG(uap, rgid) == SCARG(uap, egid)) {
414 		SCARG(&args.sa, gid) = SCARG(uap, rgid);
415 		return (setgid(p, &args.sa, retval));
416 	}
417 	/*
418 	 * Otherwise we assume that the intent of setting rgid is to be
419 	 * able to get back rgid priviledge (i.e. swapping rgid and egid).
420 	 * So we make sure that we will be able to do so, but do not
421 	 * actually set the rgid.
422 	 */
423 	if (SCARG(uap, rgid) != (gid_t)-1 && SCARG(uap, rgid) != pc->p_rgid &&
424 	    SCARG(uap, rgid) != pc->p_svgid)
425 		return (EPERM);
426 	if (SCARG(uap, egid) == (gid_t)-1)
427 		return (0);
428 	SCARG(&args.ea, egid) = SCARG(uap, egid);
429 	return (setegid(p, &args.ea, retval));
430 }
431 #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */
432 
433 /*
434  * Check if gid is a member of the group set.
435  */
436 int
437 groupmember(gid, cred)
438 	gid_t gid;
439 	register struct ucred *cred;
440 {
441 	register gid_t *gp;
442 	gid_t *egp;
443 
444 	egp = &(cred->cr_groups[cred->cr_ngroups]);
445 	for (gp = cred->cr_groups; gp < egp; gp++)
446 		if (*gp == gid)
447 			return (1);
448 	return (0);
449 }
450 
451 /*
452  * Test whether the specified credentials imply "super-user"
453  * privilege; if so, and we have accounting info, set the flag
454  * indicating use of super-powers.
455  * Returns 0 or error.
456  */
457 int
458 suser(cred, acflag)
459 	struct ucred *cred;
460 	u_short *acflag;
461 {
462 	if (cred->cr_uid == 0) {
463 		if (acflag)
464 			*acflag |= ASU;
465 		return (0);
466 	}
467 	return (EPERM);
468 }
469 
470 /*
471  * Allocate a zeroed cred structure.
472  */
473 struct ucred *
474 crget()
475 {
476 	register struct ucred *cr;
477 
478 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
479 	bzero((caddr_t)cr, sizeof(*cr));
480 	cr->cr_ref = 1;
481 	return (cr);
482 }
483 
484 /*
485  * Free a cred structure.
486  * Throws away space when ref count gets to 0.
487  */
488 void
489 crfree(cr)
490 	struct ucred *cr;
491 {
492 	int s;
493 
494 	s = splimp();				/* ??? */
495 	if (--cr->cr_ref == 0)
496 		FREE((caddr_t)cr, M_CRED);
497 	(void) splx(s);
498 }
499 
500 /*
501  * Copy cred structure to a new one and free the old one.
502  */
503 struct ucred *
504 crcopy(cr)
505 	struct ucred *cr;
506 {
507 	struct ucred *newcr;
508 
509 	if (cr->cr_ref == 1)
510 		return (cr);
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 int
538 getlogin(p, uap, retval)
539 	struct proc *p;
540 	struct getlogin_args /* {
541 		syscallarg(char *) namebuf;
542 		syscallarg(u_int) namelen;
543 	} */ *uap;
544 	register_t *retval;
545 {
546 
547 	if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
548 		SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
549 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
550 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
551 }
552 
553 /*
554  * Set login name.
555  */
556 /* ARGSUSED */
557 int
558 setlogin(p, uap, retval)
559 	struct proc *p;
560 	struct setlogin_args /* {
561 		syscallarg(char *) namebuf;
562 	} */ *uap;
563 	register_t *retval;
564 {
565 	int error;
566 
567 	if (error = suser(p->p_ucred, &p->p_acflag))
568 		return (error);
569 	error = copyinstr((caddr_t) SCARG(uap, namebuf),
570 	    (caddr_t) p->p_pgrp->pg_session->s_login,
571 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
572 	if (error == ENAMETOOLONG)
573 		error = EINVAL;
574 	return (error);
575 }
576