xref: /original-bsd/sys/kern/kern_prot.c (revision 860e07fc)
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.28 (Berkeley) 07/19/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.
227 	 * Transfer proc count to new user.
228 	 * Copy credentials so other references do not see our changes.
229 	 */
230 	(void)chgproccnt(pc->p_ruid, -1);
231 	(void)chgproccnt(uid, 1);
232 	pc->pc_ucred = crcopy(pc->pc_ucred);
233 	pc->pc_ucred->cr_uid = uid;
234 	pc->p_ruid = uid;
235 	pc->p_svuid = uid;
236 	p->p_flag |= SUGID;
237 	return (0);
238 }
239 
240 struct seteuid_args {
241 	uid_t	euid;
242 };
243 /* ARGSUSED */
244 seteuid(p, uap, retval)
245 	struct proc *p;
246 	struct seteuid_args *uap;
247 	int *retval;
248 {
249 	register struct pcred *pc = p->p_cred;
250 	register uid_t euid;
251 	int error;
252 
253 	euid = uap->euid;
254 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
255 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
256 		return (error);
257 	/*
258 	 * Everything's okay, do it.  Copy credentials so other references do
259 	 * not see our changes.
260 	 */
261 	pc->pc_ucred = crcopy(pc->pc_ucred);
262 	pc->pc_ucred->cr_uid = euid;
263 	p->p_flag |= SUGID;
264 	return (0);
265 }
266 
267 struct setgid_args {
268 	gid_t	gid;
269 };
270 /* ARGSUSED */
271 setgid(p, uap, retval)
272 	struct proc *p;
273 	struct setgid_args *uap;
274 	int *retval;
275 {
276 	register struct pcred *pc = p->p_cred;
277 	register gid_t gid;
278 	int error;
279 
280 	gid = uap->gid;
281 	if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
282 		return (error);
283 	pc->pc_ucred = crcopy(pc->pc_ucred);
284 	pc->pc_ucred->cr_groups[0] = gid;
285 	pc->p_rgid = gid;
286 	pc->p_svgid = gid;		/* ??? */
287 	p->p_flag |= SUGID;
288 	return (0);
289 }
290 
291 struct setegid_args {
292 	gid_t	egid;
293 };
294 /* ARGSUSED */
295 setegid(p, uap, retval)
296 	struct proc *p;
297 	struct setegid_args *uap;
298 	int *retval;
299 {
300 	register struct pcred *pc = p->p_cred;
301 	register gid_t egid;
302 	int error;
303 
304 	egid = uap->egid;
305 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
306 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
307 		return (error);
308 	pc->pc_ucred = crcopy(pc->pc_ucred);
309 	pc->pc_ucred->cr_groups[0] = egid;
310 	p->p_flag |= SUGID;
311 	return (0);
312 }
313 
314 struct setgroups_args {
315 	u_int	gidsetsize;
316 	gid_t	*gidset;
317 };
318 /* ARGSUSED */
319 setgroups(p, uap, retval)
320 	struct proc *p;
321 	struct setgroups_args *uap;
322 	int *retval;
323 {
324 	register struct pcred *pc = p->p_cred;
325 	register u_int ngrp;
326 	int error;
327 
328 	if (error = suser(pc->pc_ucred, &p->p_acflag))
329 		return (error);
330 	if ((ngrp = uap->gidsetsize) > NGROUPS)
331 		return (EINVAL);
332 	pc->pc_ucred = crcopy(pc->pc_ucred);
333 	if (error = copyin((caddr_t)uap->gidset,
334 	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))
335 		return (error);
336 	pc->pc_ucred->cr_ngroups = ngrp;
337 	p->p_flag |= SUGID;
338 	return (0);
339 }
340 
341 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
342 struct setreuid_args {
343 	int	ruid;
344 	int	euid;
345 };
346 /* ARGSUSED */
347 osetreuid(p, uap, retval)
348 	register struct proc *p;
349 	struct setreuid_args *uap;
350 	int *retval;
351 {
352 	register struct pcred *pc = p->p_cred;
353 	struct seteuid_args args;
354 
355 	/*
356 	 * we assume that the intent of setting ruid is to be able to get
357 	 * back ruid priviledge. So we make sure that we will be able to
358 	 * do so, but do not actually set the ruid.
359 	 */
360 	if (uap->ruid != -1 && uap->ruid != pc->p_ruid &&
361 	    uap->ruid != pc->p_svuid)
362 		return (EPERM);
363 	if (uap->euid == -1)
364 		return (0);
365 	args.euid = uap->euid;
366 	return (seteuid(p, &args, retval));
367 }
368 
369 struct setregid_args {
370 	int	rgid;
371 	int	egid;
372 };
373 /* ARGSUSED */
374 osetregid(p, uap, retval)
375 	register struct proc *p;
376 	struct setregid_args *uap;
377 	int *retval;
378 {
379 	register struct pcred *pc = p->p_cred;
380 	struct setegid_args args;
381 
382 	/*
383 	 * we assume that the intent of setting rgid is to be able to get
384 	 * back rgid priviledge. So we make sure that we will be able to
385 	 * do so, but do not actually set the rgid.
386 	 */
387 	if (uap->rgid != -1 && uap->rgid != pc->p_rgid &&
388 	    uap->rgid != pc->p_svgid)
389 		return (EPERM);
390 	if (uap->egid == -1)
391 		return (0);
392 	args.egid = uap->egid;
393 	return (setegid(p, &args, retval));
394 }
395 #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */
396 
397 /*
398  * Check if gid is a member of the group set.
399  */
400 groupmember(gid, cred)
401 	gid_t gid;
402 	register struct ucred *cred;
403 {
404 	register gid_t *gp;
405 	gid_t *egp;
406 
407 	egp = &(cred->cr_groups[cred->cr_ngroups]);
408 	for (gp = cred->cr_groups; gp < egp; gp++)
409 		if (*gp == gid)
410 			return (1);
411 	return (0);
412 }
413 
414 /*
415  * Test whether the specified credentials imply "super-user"
416  * privilege; if so, and we have accounting info, set the flag
417  * indicating use of super-powers.
418  * Returns 0 or error.
419  */
420 suser(cred, acflag)
421 	struct ucred *cred;
422 	short *acflag;
423 {
424 	if (cred->cr_uid == 0) {
425 		if (acflag)
426 			*acflag |= ASU;
427 		return (0);
428 	}
429 	return (EPERM);
430 }
431 
432 /*
433  * Allocate a zeroed cred structure.
434  */
435 struct ucred *
436 crget()
437 {
438 	register struct ucred *cr;
439 
440 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
441 	bzero((caddr_t)cr, sizeof(*cr));
442 	cr->cr_ref = 1;
443 	return (cr);
444 }
445 
446 /*
447  * Free a cred structure.
448  * Throws away space when ref count gets to 0.
449  */
450 crfree(cr)
451 	struct ucred *cr;
452 {
453 	int s = splimp();			/* ??? */
454 
455 	if (--cr->cr_ref != 0) {
456 		(void) splx(s);
457 		return;
458 	}
459 	FREE((caddr_t)cr, M_CRED);
460 	(void) splx(s);
461 }
462 
463 /*
464  * Copy cred structure to a new one and free the old one.
465  */
466 struct ucred *
467 crcopy(cr)
468 	struct ucred *cr;
469 {
470 	struct ucred *newcr;
471 
472 	if (cr->cr_ref == 1)
473 		return (cr);
474 	newcr = crget();
475 	*newcr = *cr;
476 	crfree(cr);
477 	newcr->cr_ref = 1;
478 	return (newcr);
479 }
480 
481 /*
482  * Dup cred struct to a new held one.
483  */
484 struct ucred *
485 crdup(cr)
486 	struct ucred *cr;
487 {
488 	struct ucred *newcr;
489 
490 	newcr = crget();
491 	*newcr = *cr;
492 	newcr->cr_ref = 1;
493 	return (newcr);
494 }
495 
496 /*
497  * Get login name, if available.
498  */
499 struct getlogin_args {
500 	char	*namebuf;
501 	u_int	namelen;
502 };
503 /* ARGSUSED */
504 getlogin(p, uap, retval)
505 	struct proc *p;
506 	struct getlogin_args *uap;
507 	int *retval;
508 {
509 
510 	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
511 		uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
512 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
513 	    (caddr_t) uap->namebuf, uap->namelen));
514 }
515 
516 /*
517  * Set login name.
518  */
519 struct setlogin_args {
520 	char	*namebuf;
521 };
522 /* ARGSUSED */
523 setlogin(p, uap, retval)
524 	struct proc *p;
525 	struct setlogin_args *uap;
526 	int *retval;
527 {
528 	int error;
529 
530 	if (error = suser(p->p_ucred, &p->p_acflag))
531 		return (error);
532 	error = copyinstr((caddr_t) uap->namebuf,
533 	    (caddr_t) p->p_pgrp->pg_session->s_login,
534 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
535 	if (error == ENAMETOOLONG)
536 		error = EINVAL;
537 	return (error);
538 }
539