xref: /csrg-svn/sys/kern/kern_prot.c (revision 41379)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)kern_prot.c	7.10 (Berkeley) 05/04/90
18  */
19 
20 /*
21  * System calls related to processes and protection
22  */
23 
24 #include "param.h"
25 #include "acct.h"
26 #include "systm.h"
27 #include "user.h"
28 #include "proc.h"
29 #include "timeb.h"
30 #include "times.h"
31 #include "reboot.h"
32 #include "buf.h"
33 #include "../ufs/quota.h"
34 #include "malloc.h"
35 
36 #include "machine/reg.h"
37 
38 getpid()
39 {
40 
41 	u.u_r.r_val1 = u.u_procp->p_pid;
42 	u.u_r.r_val2 = u.u_procp->p_ppid;
43 }
44 
45 getpgrp()
46 {
47 	register struct a {
48 		int	pid;
49 	} *uap = (struct a *)u.u_ap;
50 	register struct proc *p;
51 
52 	if (uap->pid == 0)
53 		p = u.u_procp;
54 	else if ((p = pfind(uap->pid)) == 0) {
55 		u.u_error = ESRCH;
56 		return;
57 	}
58 	u.u_r.r_val1 = p->p_pgrp->pg_id;
59 }
60 
61 getuid()
62 {
63 
64 	u.u_r.r_val1 = u.u_procp->p_ruid;
65 	u.u_r.r_val2 = u.u_cred->cr_uid;
66 }
67 
68 getgid()
69 {
70 
71 	u.u_r.r_val1 = u.u_procp->p_rgid;
72 	u.u_r.r_val2 = u.u_cred->cr_groups[0];
73 }
74 
75 getgroups()
76 {
77 	register struct	a {
78 		u_int	gidsetsize;
79 		int	*gidset;
80 	} *uap = (struct a *)u.u_ap;
81 	register gid_t *gp;
82 	register int *lp;
83 	int groups[NGROUPS];
84 
85 	if (uap->gidsetsize == 0) {
86 		u.u_r.r_val1 = u.u_cred->cr_ngroups;
87 		return;
88 	}
89 	if (uap->gidsetsize < u.u_cred->cr_ngroups) {
90 		u.u_error = EINVAL;
91 		return;
92 	}
93 	uap->gidsetsize = u.u_cred->cr_ngroups;
94 	gp = u.u_cred->cr_groups;
95 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
96 		*lp++ = *gp++;
97 	u.u_error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
98 	    uap->gidsetsize * sizeof (groups[0]));
99 	if (u.u_error)
100 		return;
101 	u.u_r.r_val1 = uap->gidsetsize;
102 }
103 
104 setsid()
105 {
106 	register struct proc *p = u.u_procp;
107 
108 	if ((p->p_pgid == p->p_pid) || pgfind(p->p_pid))
109 		u.u_error = EPERM;
110 	else {
111 		pgmv(p, p->p_pid, 1);
112 		u.u_r.r_val1 = p->p_pid;
113 	}
114 	return;
115 }
116 
117 /*
118  * set process group
119  *
120  * caller does setpgrp(pid, pgid)
121  *
122  * pid must be caller or child of caller (ESRCH)
123  * if a child
124  *	pid must be in same session (EPERM)
125  *	pid can't have done an exec (EACCES)
126  * if pgid != pid
127  * 	there must exist some pid in same session having pgid (EPERM)
128  * pid must not be session leader (EPERM)
129  */
130 setpgrp()
131 {
132 	register struct a {
133 		int	pid;
134 		int	pgid;
135 	} *uap = (struct a *)u.u_ap;
136 	register struct proc *p;
137 	register struct pgrp *pgrp;
138 
139 	if (uap->pid == 0)
140 		p = u.u_procp;
141 	else if ((p = pfind(uap->pid)) == 0 || !inferior(p)) {
142 		u.u_error = ESRCH;
143 		return;
144 	}
145 	else if (p != u.u_procp) {
146 		if (p->p_session != u.u_procp->p_session) {
147 			u.u_error = EPERM;
148 			return;
149 		}
150 		if (p->p_flag&SEXEC) {
151 			u.u_error = EACCES;
152 			return;
153 		}
154 	}
155 	if (SESS_LEADER(p)) {
156 		u.u_error = EPERM;
157 		return;
158 	}
159 	if (uap->pgid == 0)
160 		uap->pgid = p->p_pid;
161 	else if ((uap->pgid != p->p_pid) &&
162 		(((pgrp = pgfind(uap->pgid)) == 0) ||
163 		   pgrp->pg_mem == NULL ||
164 	           pgrp->pg_session != u.u_procp->p_session)) {
165 		u.u_error = EPERM;
166 		return;
167 	}
168 	/*
169 	 * done checking, now doit
170 	 */
171 	pgmv(p, uap->pgid, 0);
172 }
173 
174 setreuid()
175 {
176 	struct a {
177 		int	ruid;
178 		int	euid;
179 	} *uap;
180 	register struct proc *p = u.u_procp;
181 	register int ruid, euid;
182 
183 	uap = (struct a *)u.u_ap;
184 	ruid = uap->ruid;
185 	if (ruid == -1)
186 		ruid = p->p_ruid;
187 #ifdef COMPAT_43
188 	if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ &&
189 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
190 #else
191 	if (ruid != p->p_ruid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
192 #endif
193 		return;
194 	euid = uap->euid;
195 	if (euid == -1)
196 		euid = u.u_cred->cr_uid;
197 	if (euid != u.u_cred->cr_uid && euid != p->p_ruid &&
198 	    euid != p->p_svuid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
199 		return;
200 	/*
201 	 * Everything's okay, do it.
202 	 * Copy credentials so other references do not
203 	 * see our changes.
204 	 */
205 	if (u.u_cred->cr_ref > 1)
206 		u.u_cred = crcopy(u.u_cred);
207 	u.u_cred->cr_uid = euid;
208 	p->p_uid = euid;
209 	p->p_ruid = ruid;
210 }
211 
212 setregid()
213 {
214 	register struct a {
215 		int	rgid;
216 		int	egid;
217 	} *uap;
218 	register int rgid, egid;
219 	register struct proc *p = u.u_procp;
220 
221 	uap = (struct a *)u.u_ap;
222 	rgid = uap->rgid;
223 	if (rgid == -1)
224 		rgid = p->p_rgid;
225 #ifdef COMPAT_43_XXX
226 	if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ &&
227 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
228 #else
229 	if (rgid != p->p_rgid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
230 #endif
231 		return;
232 	egid = uap->egid;
233 	if (egid == -1)
234 		egid = u.u_cred->cr_groups[0];
235 	if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid &&
236 	    egid != p->p_svgid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
237 		return;
238 	if (u.u_cred->cr_ref > 1)
239 		u.u_cred = crcopy(u.u_cred);
240 	p->p_rgid = rgid;
241 	u.u_cred->cr_groups[0] = egid;
242 }
243 
244 setgroups()
245 {
246 	register struct	a {
247 		u_int	gidsetsize;
248 		int	*gidset;
249 	} *uap = (struct a *)u.u_ap;
250 	register gid_t *gp;
251 	register int *lp;
252 	int ngrp, groups[NGROUPS];
253 
254 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
255 		return;
256 	ngrp = uap->gidsetsize;
257 	if (ngrp > NGROUPS) {
258 		u.u_error = EINVAL;
259 		return;
260 	}
261 	u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
262 	    uap->gidsetsize * sizeof (groups[0]));
263 	if (u.u_error)
264 		return;
265 	gp = u.u_cred->cr_groups;
266 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
267 		*gp++ = *lp++;
268 	u.u_cred->cr_ngroups = ngrp;
269 }
270 
271 /*
272  * Check if gid is a member of the group set.
273  */
274 groupmember(gid, cred)
275 	gid_t gid;
276 	register struct ucred *cred;
277 {
278 	register gid_t *gp;
279 	gid_t *egp;
280 
281 	egp = &(cred->cr_groups[cred->cr_ngroups]);
282 	for (gp = cred->cr_groups; gp < egp; gp++)
283 		if (*gp == gid)
284 			return (1);
285 	return (0);
286 }
287 
288 /*
289  * Test if the current user is the super user.
290  */
291 suser(cred, acflag)
292 	struct ucred *cred;
293 	short *acflag;
294 {
295 
296 	if (cred->cr_uid == 0) {
297 		if (acflag)
298 			*acflag |= ASU;
299 		return (0);
300 	}
301 	return (EPERM);
302 }
303 
304 /*
305  * Allocate a zeroed cred structure.
306  */
307 struct ucred *
308 crget()
309 {
310 	register struct ucred *cr;
311 
312 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
313 	bzero((caddr_t)cr, sizeof(*cr));
314 	cr->cr_ref = 1;
315 	return(cr);
316 }
317 
318 /*
319  * Free a cred structure.
320  * Throws away space when ref count gets to 0.
321  */
322 crfree(cr)
323 	struct ucred *cr;
324 {
325 	int	s = splimp();
326 
327 	if (--cr->cr_ref != 0) {
328 		(void) splx(s);
329 		return;
330 	}
331 	FREE((caddr_t)cr, M_CRED);
332 	(void) splx(s);
333 }
334 
335 /*
336  * Copy cred structure to a new one and free the old one.
337  */
338 struct ucred *
339 crcopy(cr)
340 	struct ucred *cr;
341 {
342 	struct ucred *newcr;
343 
344 	newcr = crget();
345 	*newcr = *cr;
346 	crfree(cr);
347 	newcr->cr_ref = 1;
348 	return(newcr);
349 }
350 
351 /*
352  * Dup cred struct to a new held one.
353  */
354 struct ucred *
355 crdup(cr)
356 	struct ucred *cr;
357 {
358 	struct ucred *newcr;
359 
360 	newcr = crget();
361 	*newcr = *cr;
362 	newcr->cr_ref = 1;
363 	return(newcr);
364 }
365 
366 /*
367  * Get login name, if available.
368  */
369 getlogin()
370 {
371 	struct a {
372 		char	*namebuf;
373 		u_int	namelen;
374 	} *uap = (struct a *)u.u_ap;
375 
376 	if (uap->namelen > sizeof (u.u_procp->p_logname))
377 		uap->namelen = sizeof (u.u_procp->p_logname);
378 	u.u_error = copyout((caddr_t)u.u_procp->p_logname,
379 			     (caddr_t)uap->namebuf, uap->namelen);
380 }
381 
382 /*
383  * Set login name.
384  */
385 setlogin()
386 {
387 	struct a {
388 		char	*namebuf;
389 	} *uap = (struct a *)u.u_ap;
390 	int error;
391 
392 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
393 		return;
394 	error = copyinstr((caddr_t)uap->namebuf, (caddr_t)u.u_procp->p_logname,
395 	    sizeof (u.u_procp->p_logname) - 1, (int *) 0);
396 	if (error == ENOENT)		/* name too long */
397 		error = EINVAL;
398 	u.u_error = error;
399 }
400