xref: /csrg-svn/sys/kern/kern_prot.c (revision 55162)
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.26 (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 /*
339  * Check if gid is a member of the group set.
340  */
341 groupmember(gid, cred)
342 	gid_t gid;
343 	register struct ucred *cred;
344 {
345 	register gid_t *gp;
346 	gid_t *egp;
347 
348 	egp = &(cred->cr_groups[cred->cr_ngroups]);
349 	for (gp = cred->cr_groups; gp < egp; gp++)
350 		if (*gp == gid)
351 			return (1);
352 	return (0);
353 }
354 
355 /*
356  * Test whether the specified credentials imply "super-user"
357  * privilege; if so, and we have accounting info, set the flag
358  * indicating use of super-powers.
359  * Returns 0 or error.
360  */
361 suser(cred, acflag)
362 	struct ucred *cred;
363 	short *acflag;
364 {
365 	if (cred->cr_uid == 0) {
366 		if (acflag)
367 			*acflag |= ASU;
368 		return (0);
369 	}
370 	return (EPERM);
371 }
372 
373 /*
374  * Allocate a zeroed cred structure.
375  */
376 struct ucred *
377 crget()
378 {
379 	register struct ucred *cr;
380 
381 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
382 	bzero((caddr_t)cr, sizeof(*cr));
383 	cr->cr_ref = 1;
384 	return (cr);
385 }
386 
387 /*
388  * Free a cred structure.
389  * Throws away space when ref count gets to 0.
390  */
391 crfree(cr)
392 	struct ucred *cr;
393 {
394 	int s = splimp();			/* ??? */
395 
396 	if (--cr->cr_ref != 0) {
397 		(void) splx(s);
398 		return;
399 	}
400 	FREE((caddr_t)cr, M_CRED);
401 	(void) splx(s);
402 }
403 
404 /*
405  * Copy cred structure to a new one and free the old one.
406  */
407 struct ucred *
408 crcopy(cr)
409 	struct ucred *cr;
410 {
411 	struct ucred *newcr;
412 
413 	if (cr->cr_ref == 1)
414 		return (cr);
415 	newcr = crget();
416 	*newcr = *cr;
417 	crfree(cr);
418 	newcr->cr_ref = 1;
419 	return (newcr);
420 }
421 
422 /*
423  * Dup cred struct to a new held one.
424  */
425 struct ucred *
426 crdup(cr)
427 	struct ucred *cr;
428 {
429 	struct ucred *newcr;
430 
431 	newcr = crget();
432 	*newcr = *cr;
433 	newcr->cr_ref = 1;
434 	return (newcr);
435 }
436 
437 /*
438  * Get login name, if available.
439  */
440 struct getlogin_args {
441 	char	*namebuf;
442 	u_int	namelen;
443 };
444 /* ARGSUSED */
445 getlogin(p, uap, retval)
446 	struct proc *p;
447 	struct getlogin_args *uap;
448 	int *retval;
449 {
450 
451 	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
452 		uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
453 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
454 	    (caddr_t) uap->namebuf, uap->namelen));
455 }
456 
457 /*
458  * Set login name.
459  */
460 struct setlogin_args {
461 	char	*namebuf;
462 };
463 /* ARGSUSED */
464 setlogin(p, uap, retval)
465 	struct proc *p;
466 	struct setlogin_args *uap;
467 	int *retval;
468 {
469 	int error;
470 
471 	if (error = suser(p->p_ucred, &p->p_acflag))
472 		return (error);
473 	error = copyinstr((caddr_t) uap->namebuf,
474 	    (caddr_t) p->p_pgrp->pg_session->s_login,
475 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
476 	if (error == ENAMETOOLONG)
477 		error = EINVAL;
478 	return (error);
479 }
480