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