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