xref: /original-bsd/sys/kern/kern_prot.c (revision 333da485)
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.6 (Berkeley) 01/21/94
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 	struct seteuid_args args;
358 
359 	/*
360 	 * we assume that the intent of setting ruid is to be able to get
361 	 * back ruid priviledge. So we make sure that we will be able to
362 	 * do so, but do not actually set the ruid.
363 	 */
364 	if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid &&
365 	    uap->ruid != pc->p_svuid)
366 		return (EPERM);
367 	if (uap->euid == (uid_t)-1)
368 		return (0);
369 	args.euid = uap->euid;
370 	return (seteuid(p, &args, retval));
371 }
372 
373 struct setregid_args {
374 	int	rgid;
375 	int	egid;
376 };
377 /* ARGSUSED */
378 osetregid(p, uap, retval)
379 	register struct proc *p;
380 	struct setregid_args *uap;
381 	int *retval;
382 {
383 	register struct pcred *pc = p->p_cred;
384 	struct setegid_args args;
385 
386 	/*
387 	 * we assume that the intent of setting rgid is to be able to get
388 	 * back rgid priviledge. So we make sure that we will be able to
389 	 * do so, but do not actually set the rgid.
390 	 */
391 	if (uap->rgid != (gid_t)-1 && uap->rgid != pc->p_rgid &&
392 	    uap->rgid != pc->p_svgid)
393 		return (EPERM);
394 	if (uap->egid == (gid_t)-1)
395 		return (0);
396 	args.egid = uap->egid;
397 	return (setegid(p, &args, retval));
398 }
399 #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */
400 
401 /*
402  * Check if gid is a member of the group set.
403  */
404 groupmember(gid, cred)
405 	gid_t gid;
406 	register struct ucred *cred;
407 {
408 	register gid_t *gp;
409 	gid_t *egp;
410 
411 	egp = &(cred->cr_groups[cred->cr_ngroups]);
412 	for (gp = cred->cr_groups; gp < egp; gp++)
413 		if (*gp == gid)
414 			return (1);
415 	return (0);
416 }
417 
418 /*
419  * Test whether the specified credentials imply "super-user"
420  * privilege; if so, and we have accounting info, set the flag
421  * indicating use of super-powers.
422  * Returns 0 or error.
423  */
424 suser(cred, acflag)
425 	struct ucred *cred;
426 	short *acflag;
427 {
428 	if (cred->cr_uid == 0) {
429 		if (acflag)
430 			*acflag |= ASU;
431 		return (0);
432 	}
433 	return (EPERM);
434 }
435 
436 /*
437  * Allocate a zeroed cred structure.
438  */
439 struct ucred *
440 crget()
441 {
442 	register struct ucred *cr;
443 
444 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
445 	bzero((caddr_t)cr, sizeof(*cr));
446 	cr->cr_ref = 1;
447 	return (cr);
448 }
449 
450 /*
451  * Free a cred structure.
452  * Throws away space when ref count gets to 0.
453  */
454 crfree(cr)
455 	struct ucred *cr;
456 {
457 	int s;
458 
459 	s = splimp();				/* ??? */
460 	if (--cr->cr_ref == 0)
461 		FREE((caddr_t)cr, M_CRED);
462 	(void) splx(s);
463 }
464 
465 /*
466  * Copy cred structure to a new one and free the old one.
467  */
468 struct ucred *
469 crcopy(cr)
470 	struct ucred *cr;
471 {
472 	struct ucred *newcr;
473 
474 	if (cr->cr_ref == 1)
475 		return (cr);
476 	newcr = crget();
477 	*newcr = *cr;
478 	crfree(cr);
479 	newcr->cr_ref = 1;
480 	return (newcr);
481 }
482 
483 /*
484  * Dup cred struct to a new held one.
485  */
486 struct ucred *
487 crdup(cr)
488 	struct ucred *cr;
489 {
490 	struct ucred *newcr;
491 
492 	newcr = crget();
493 	*newcr = *cr;
494 	newcr->cr_ref = 1;
495 	return (newcr);
496 }
497 
498 /*
499  * Get login name, if available.
500  */
501 struct getlogin_args {
502 	char	*namebuf;
503 	u_int	namelen;
504 };
505 /* ARGSUSED */
506 getlogin(p, uap, retval)
507 	struct proc *p;
508 	struct getlogin_args *uap;
509 	int *retval;
510 {
511 
512 	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
513 		uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
514 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
515 	    (caddr_t) uap->namebuf, uap->namelen));
516 }
517 
518 /*
519  * Set login name.
520  */
521 struct setlogin_args {
522 	char	*namebuf;
523 };
524 /* ARGSUSED */
525 setlogin(p, uap, retval)
526 	struct proc *p;
527 	struct setlogin_args *uap;
528 	int *retval;
529 {
530 	int error;
531 
532 	if (error = suser(p->p_ucred, &p->p_acflag))
533 		return (error);
534 	error = copyinstr((caddr_t) uap->namebuf,
535 	    (caddr_t) p->p_pgrp->pg_session->s_login,
536 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
537 	if (error == ENAMETOOLONG)
538 		error = EINVAL;
539 	return (error);
540 }
541