xref: /original-bsd/sys/kern/kern_prot.c (revision 38950d38)
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.25 (Berkeley) 07/10/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 	int	*gidset;		/* XXX not yet POSIX */
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 gid_t *gp;
129 	register int *lp;
130 	register u_int ngrp;
131 	int groups[NGROUPS];
132 	int error;
133 
134 	if ((ngrp = uap->gidsetsize) == 0) {
135 		*retval = pc->pc_ucred->cr_ngroups;
136 		return (0);
137 	}
138 	if (ngrp < pc->pc_ucred->cr_ngroups)
139 		return (EINVAL);
140 	ngrp = pc->pc_ucred->cr_ngroups;
141 	for (gp = pc->pc_ucred->cr_groups, lp = groups; lp < &groups[ngrp]; )
142 		*lp++ = *gp++;
143 	if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
144 	    ngrp * sizeof (groups[0])))
145 		return (error);
146 	*retval = ngrp;
147 	return (0);
148 }
149 
150 /* ARGSUSED */
151 setsid(p, uap, retval)
152 	register struct proc *p;
153 	struct args *uap;
154 	int *retval;
155 {
156 
157 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
158 		return (EPERM);
159 	} else {
160 		enterpgrp(p, p->p_pid, 1);
161 		*retval = p->p_pid;
162 		return (0);
163 	}
164 }
165 
166 /*
167  * set process group (setpgid/old setpgrp)
168  *
169  * caller does setpgid(targpid, targpgid)
170  *
171  * pid must be caller or child of caller (ESRCH)
172  * if a child
173  *	pid must be in same session (EPERM)
174  *	pid can't have done an exec (EACCES)
175  * if pgid != pid
176  * 	there must exist some pid in same session having pgid (EPERM)
177  * pid must not be session leader (EPERM)
178  */
179 struct setpgid_args {
180 	int	pid;	/* target process id */
181 	int	pgid;	/* target pgrp id */
182 };
183 /* ARGSUSED */
184 setpgid(curp, uap, retval)
185 	struct proc *curp;
186 	register struct setpgid_args *uap;
187 	int *retval;
188 {
189 	register struct proc *targp;		/* target process */
190 	register struct pgrp *pgrp;		/* target pgrp */
191 
192 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
193 		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
194 			return (ESRCH);
195 		if (targp->p_session != curp->p_session)
196 			return (EPERM);
197 		if (targp->p_flag&SEXEC)
198 			return (EACCES);
199 	} else
200 		targp = curp;
201 	if (SESS_LEADER(targp))
202 		return (EPERM);
203 	if (uap->pgid == 0)
204 		uap->pgid = targp->p_pid;
205 	else if (uap->pgid != targp->p_pid)
206 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
207 	            pgrp->pg_session != curp->p_session)
208 			return (EPERM);
209 	enterpgrp(targp, uap->pgid, 0);
210 	return (0);
211 }
212 
213 struct setuid_args {
214 	int	uid;
215 };
216 /* ARGSUSED */
217 setuid(p, uap, retval)
218 	struct proc *p;
219 	struct setuid_args *uap;
220 	int *retval;
221 {
222 	register struct pcred *pc = p->p_cred;
223 	register uid_t uid;
224 	int error;
225 
226 	uid = uap->uid;
227 	if (uid != pc->p_ruid &&
228 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
229 		return (error);
230 	/*
231 	 * Everything's okay, do it.  Copy credentials so other references do
232 	 * not see our changes.
233 	 */
234 	pc->pc_ucred = crcopy(pc->pc_ucred);
235 	pc->pc_ucred->cr_uid = uid;
236 	pc->p_ruid = uid;
237 	pc->p_svuid = uid;
238 	p->p_flag |= SUGID;
239 	return (0);
240 }
241 
242 struct seteuid_args {
243 	int	euid;
244 };
245 /* ARGSUSED */
246 seteuid(p, uap, retval)
247 	struct proc *p;
248 	struct seteuid_args *uap;
249 	int *retval;
250 {
251 	register struct pcred *pc = p->p_cred;
252 	register uid_t euid;
253 	int error;
254 
255 	euid = uap->euid;
256 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
257 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
258 		return (error);
259 	/*
260 	 * Everything's okay, do it.  Copy credentials so other references do
261 	 * not see our changes.
262 	 */
263 	pc->pc_ucred = crcopy(pc->pc_ucred);
264 	pc->pc_ucred->cr_uid = euid;
265 	p->p_flag |= SUGID;
266 	return (0);
267 }
268 
269 struct setgid_args {
270 	int	gid;
271 };
272 /* ARGSUSED */
273 setgid(p, uap, retval)
274 	struct proc *p;
275 	struct setgid_args *uap;
276 	int *retval;
277 {
278 	register struct pcred *pc = p->p_cred;
279 	register gid_t gid;
280 	int error;
281 
282 	gid = uap->gid;
283 	if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
284 		return (error);
285 	pc->pc_ucred = crcopy(pc->pc_ucred);
286 	pc->pc_ucred->cr_groups[0] = gid;
287 	pc->p_rgid = gid;
288 	pc->p_svgid = gid;		/* ??? */
289 	p->p_flag |= SUGID;
290 	return (0);
291 }
292 
293 struct setegid_args {
294 	int	egid;
295 };
296 /* ARGSUSED */
297 setegid(p, uap, retval)
298 	struct proc *p;
299 	struct setegid_args *uap;
300 	int *retval;
301 {
302 	register struct pcred *pc = p->p_cred;
303 	register gid_t egid;
304 	int error;
305 
306 	egid = uap->egid;
307 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
308 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
309 		return (error);
310 	pc->pc_ucred = crcopy(pc->pc_ucred);
311 	pc->pc_ucred->cr_groups[0] = egid;
312 	p->p_flag |= SUGID;
313 	return (0);
314 }
315 
316 struct setgroups_args {
317 	u_int	gidsetsize;
318 	int	*gidset;
319 };
320 /* ARGSUSED */
321 setgroups(p, uap, retval)
322 	struct proc *p;
323 	struct setgroups_args *uap;
324 	int *retval;
325 {
326 	register struct pcred *pc = p->p_cred;
327 	register gid_t *gp;
328 	register u_int ngrp;
329 	register int *lp;
330 	int error, groups[NGROUPS];
331 
332 	if (error = suser(pc->pc_ucred, &p->p_acflag))
333 		return (error);
334 	if ((ngrp = uap->gidsetsize) > NGROUPS)
335 		return (EINVAL);
336 	if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
337 	    ngrp * sizeof (groups[0])))
338 		return (error);
339 	pc->pc_ucred = crcopy(pc->pc_ucred);
340 	pc->pc_ucred->cr_ngroups = ngrp;
341 	/* convert from int's to gid_t's */
342 	for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; )
343 		*gp++ = *lp++;
344 	p->p_flag |= SUGID;
345 	return (0);
346 }
347 
348 /*
349  * Check if gid is a member of the group set.
350  */
351 groupmember(gid, cred)
352 	gid_t gid;
353 	register struct ucred *cred;
354 {
355 	register gid_t *gp;
356 	gid_t *egp;
357 
358 	egp = &(cred->cr_groups[cred->cr_ngroups]);
359 	for (gp = cred->cr_groups; gp < egp; gp++)
360 		if (*gp == gid)
361 			return (1);
362 	return (0);
363 }
364 
365 /*
366  * Test whether the specified credentials imply "super-user"
367  * privilege; if so, and we have accounting info, set the flag
368  * indicating use of super-powers.
369  * Returns 0 or error.
370  */
371 suser(cred, acflag)
372 	struct ucred *cred;
373 	short *acflag;
374 {
375 	if (cred->cr_uid == 0) {
376 		if (acflag)
377 			*acflag |= ASU;
378 		return (0);
379 	}
380 	return (EPERM);
381 }
382 
383 /*
384  * Allocate a zeroed cred structure.
385  */
386 struct ucred *
387 crget()
388 {
389 	register struct ucred *cr;
390 
391 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
392 	bzero((caddr_t)cr, sizeof(*cr));
393 	cr->cr_ref = 1;
394 	return (cr);
395 }
396 
397 /*
398  * Free a cred structure.
399  * Throws away space when ref count gets to 0.
400  */
401 crfree(cr)
402 	struct ucred *cr;
403 {
404 	int s = splimp();			/* ??? */
405 
406 	if (--cr->cr_ref != 0) {
407 		(void) splx(s);
408 		return;
409 	}
410 	FREE((caddr_t)cr, M_CRED);
411 	(void) splx(s);
412 }
413 
414 /*
415  * Copy cred structure to a new one and free the old one.
416  */
417 struct ucred *
418 crcopy(cr)
419 	struct ucred *cr;
420 {
421 	struct ucred *newcr;
422 
423 	if (cr->cr_ref == 1)
424 		return (cr);
425 	newcr = crget();
426 	*newcr = *cr;
427 	crfree(cr);
428 	newcr->cr_ref = 1;
429 	return (newcr);
430 }
431 
432 /*
433  * Dup cred struct to a new held one.
434  */
435 struct ucred *
436 crdup(cr)
437 	struct ucred *cr;
438 {
439 	struct ucred *newcr;
440 
441 	newcr = crget();
442 	*newcr = *cr;
443 	newcr->cr_ref = 1;
444 	return (newcr);
445 }
446 
447 /*
448  * Get login name, if available.
449  */
450 struct getlogin_args {
451 	char	*namebuf;
452 	u_int	namelen;
453 };
454 /* ARGSUSED */
455 getlogin(p, uap, retval)
456 	struct proc *p;
457 	struct getlogin_args *uap;
458 	int *retval;
459 {
460 
461 	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
462 		uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
463 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
464 	    (caddr_t) uap->namebuf, uap->namelen));
465 }
466 
467 /*
468  * Set login name.
469  */
470 struct setlogin_args {
471 	char	*namebuf;
472 };
473 /* ARGSUSED */
474 setlogin(p, uap, retval)
475 	struct proc *p;
476 	struct setlogin_args *uap;
477 	int *retval;
478 {
479 	int error;
480 
481 	if (error = suser(p->p_ucred, &p->p_acflag))
482 		return (error);
483 	error = copyinstr((caddr_t) uap->namebuf,
484 	    (caddr_t) p->p_pgrp->pg_session->s_login,
485 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
486 	if (error == ENAMETOOLONG)
487 		error = EINVAL;
488 	return (error);
489 }
490