xref: /original-bsd/sys/kern/kern_prot.c (revision ee109830)
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.14 (Berkeley) 07/23/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 u_int ngrps;
410 	register int *lp;
411 	int error, groups[NGROUPS];
412 
413 	if (error = suser(u.u_cred, &u.u_acflag))
414 		return (error);
415 	if ((ngrps = uap->gidsetsize) > NGROUPS)
416 		return (EINVAL);
417 	if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
418 	    ngrps * sizeof (groups[0])))
419 		return (error);
420 	u.u_cred->cr_ngroups = ngrps;
421 	/* convert from int's to gid_t's */
422 	for (gp = u.u_cred->cr_groups, lp = groups; ngrps--; *gp++ = *lp++)
423 		/* void */;
424 	return (0);
425 }
426 
427 /*
428  * Check if gid is a member of the group set.
429  */
430 groupmember(gid, cred)
431 	gid_t gid;
432 	register struct ucred *cred;
433 {
434 	register gid_t *gp;
435 	gid_t *egp;
436 
437 	egp = &(cred->cr_groups[cred->cr_ngroups]);
438 	for (gp = cred->cr_groups; gp < egp; gp++)
439 		if (*gp == gid)
440 			return (1);
441 	return (0);
442 }
443 
444 /*
445  * Test if the current user is the super user.
446  */
447 suser(cred, acflag)
448 	struct ucred *cred;
449 	short *acflag;
450 {
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 crfree(cr)
479 	struct ucred *cr;
480 {
481 	int s = splimp();
482 
483 	if (--cr->cr_ref != 0) {
484 		(void) splx(s);
485 		return;
486 	}
487 	FREE((caddr_t)cr, M_CRED);
488 	(void) splx(s);
489 }
490 
491 /*
492  * Copy cred structure to a new one and free the old one.
493  */
494 struct ucred *
495 crcopy(cr)
496 	struct ucred *cr;
497 {
498 	struct ucred *newcr;
499 
500 	newcr = crget();
501 	*newcr = *cr;
502 	crfree(cr);
503 	newcr->cr_ref = 1;
504 	return (newcr);
505 }
506 
507 /*
508  * Dup cred struct to a new held one.
509  */
510 struct ucred *
511 crdup(cr)
512 	struct ucred *cr;
513 {
514 	struct ucred *newcr;
515 
516 	newcr = crget();
517 	*newcr = *cr;
518 	newcr->cr_ref = 1;
519 	return (newcr);
520 }
521 
522 /*
523  * Get login name, if available.
524  */
525 /* ARGSUSED */
526 getlogin(p, uap, retval)
527 	struct proc *p;
528 	struct args {
529 		char	*namebuf;
530 		u_int	namelen;
531 	} *uap;
532 	int *retval;
533 {
534 
535 	if (uap->namelen > sizeof (p->p_logname))
536 		uap->namelen = sizeof (p->p_logname);
537 	return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf,
538 	    uap->namelen));
539 }
540 
541 /*
542  * Set login name.
543  */
544 /* ARGSUSED */
545 setlogin(p, uap, retval)
546 	struct proc *p;
547 	struct args {
548 		char	*namebuf;
549 	} *uap;
550 	int *retval;
551 {
552 	int error;
553 
554 	if (error = suser(u.u_cred, &u.u_acflag))
555 		return (error);
556 	error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname,
557 	    sizeof (p->p_logname) - 1, (int *) 0);
558 	if (error == ENOENT)		/* name too long */
559 		error = EINVAL;
560 	return (error);
561 }
562