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