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