kern_prot.c revision 1.29 1 /* $NetBSD: kern_prot.c,v 1.29 1995/09/19 21:45:02 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94
41 */
42
43 /*
44 * System calls related to processes and protection
45 */
46
47 #include <sys/param.h>
48 #include <sys/acct.h>
49 #include <sys/systm.h>
50 #include <sys/ucred.h>
51 #include <sys/proc.h>
52 #include <sys/timeb.h>
53 #include <sys/times.h>
54 #include <sys/malloc.h>
55
56 #include <sys/mount.h>
57 #include <sys/syscallargs.h>
58
59 /* ARGSUSED */
60 getpid(p, uap, retval)
61 struct proc *p;
62 void *uap;
63 register_t *retval;
64 {
65
66 *retval = p->p_pid;
67 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2)
68 retval[1] = p->p_pptr->p_pid;
69 #endif
70 return (0);
71 }
72
73 /* ARGSUSED */
74 getppid(p, uap, retval)
75 struct proc *p;
76 void *uap;
77 register_t *retval;
78 {
79
80 *retval = p->p_pptr->p_pid;
81 return (0);
82 }
83
84 /* Get process group ID; note that POSIX getpgrp takes no parameter */
85 getpgrp(p, uap, retval)
86 struct proc *p;
87 void *uap;
88 register_t *retval;
89 {
90
91 *retval = p->p_pgrp->pg_id;
92 return (0);
93 }
94
95 /* ARGSUSED */
96 getuid(p, uap, retval)
97 struct proc *p;
98 void *uap;
99 register_t *retval;
100 {
101
102 *retval = p->p_cred->p_ruid;
103 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2)
104 retval[1] = p->p_ucred->cr_uid;
105 #endif
106 return (0);
107 }
108
109 /* ARGSUSED */
110 geteuid(p, uap, retval)
111 struct proc *p;
112 void *uap;
113 register_t *retval;
114 {
115
116 *retval = p->p_ucred->cr_uid;
117 return (0);
118 }
119
120 /* ARGSUSED */
121 getgid(p, uap, retval)
122 struct proc *p;
123 void *uap;
124 register_t *retval;
125 {
126
127 *retval = p->p_cred->p_rgid;
128 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
129 retval[1] = p->p_ucred->cr_gid;
130 #endif
131 return (0);
132 }
133
134 /*
135 * Get effective group ID. The "egid" is groups[0], and could be obtained
136 * via getgroups. This syscall exists because it is somewhat painful to do
137 * correctly in a library function.
138 */
139 /* ARGSUSED */
140 getegid(p, uap, retval)
141 struct proc *p;
142 void *uap;
143 register_t *retval;
144 {
145
146 *retval = p->p_ucred->cr_gid;
147 return (0);
148 }
149
150 getgroups(p, v, retval)
151 struct proc *p;
152 void *v;
153 register_t *retval;
154 {
155 register struct getgroups_args /* {
156 syscallarg(u_int) gidsetsize;
157 syscallarg(gid_t *) gidset;
158 } */ *uap = v;
159 register struct pcred *pc = p->p_cred;
160 register u_int ngrp;
161 int error;
162
163 if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
164 *retval = pc->pc_ucred->cr_ngroups;
165 return (0);
166 }
167 if (ngrp < pc->pc_ucred->cr_ngroups)
168 return (EINVAL);
169 ngrp = pc->pc_ucred->cr_ngroups;
170 if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
171 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)))
172 return (error);
173 *retval = ngrp;
174 return (0);
175 }
176
177 /* ARGSUSED */
178 setsid(p, uap, retval)
179 register struct proc *p;
180 void *uap;
181 register_t *retval;
182 {
183
184 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
185 return (EPERM);
186 } else {
187 (void)enterpgrp(p, p->p_pid, 1);
188 *retval = p->p_pid;
189 return (0);
190 }
191 }
192
193 /*
194 * set process group (setpgid/old setpgrp)
195 *
196 * caller does setpgid(targpid, targpgid)
197 *
198 * pid must be caller or child of caller (ESRCH)
199 * if a child
200 * pid must be in same session (EPERM)
201 * pid can't have done an exec (EACCES)
202 * if pgid != pid
203 * there must exist some pid in same session having pgid (EPERM)
204 * pid must not be session leader (EPERM)
205 */
206 /* ARGSUSED */
207 setpgid(curp, v, retval)
208 struct proc *curp;
209 void *v;
210 register_t *retval;
211 {
212 register struct setpgid_args /* {
213 syscallarg(int) pid;
214 syscallarg(int) pgid;
215 } */ *uap = v;
216 register struct proc *targp; /* target process */
217 register struct pgrp *pgrp; /* target pgrp */
218
219 #ifdef COMPAT_09
220 SCARG(uap, pid) = (short) SCARG(uap, pid); /* XXX */
221 SCARG(uap, pgid) = (short) SCARG(uap, pgid); /* XXX */
222 #endif
223
224 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
225 if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
226 return (ESRCH);
227 if (targp->p_session != curp->p_session)
228 return (EPERM);
229 if (targp->p_flag & P_EXEC)
230 return (EACCES);
231 } else
232 targp = curp;
233 if (SESS_LEADER(targp))
234 return (EPERM);
235 if (SCARG(uap, pgid) == 0)
236 SCARG(uap, pgid) = targp->p_pid;
237 else if (SCARG(uap, pgid) != targp->p_pid)
238 if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
239 pgrp->pg_session != curp->p_session)
240 return (EPERM);
241 return (enterpgrp(targp, SCARG(uap, pgid), 0));
242 }
243
244 /* ARGSUSED */
245 setuid(p, v, retval)
246 struct proc *p;
247 void *v;
248 register_t *retval;
249 {
250 struct setuid_args /* {
251 syscallarg(uid_t) uid;
252 } */ *uap = v;
253 register struct pcred *pc = p->p_cred;
254 register uid_t uid;
255 int error;
256
257 #ifdef COMPAT_09 /* XXX */
258 uid = (u_short)SCARG(uap, uid);
259 #else
260 uid = SCARG(uap, uid);
261 #endif
262 if (uid != pc->p_ruid &&
263 (error = suser(pc->pc_ucred, &p->p_acflag)))
264 return (error);
265 /*
266 * Everything's okay, do it.
267 * Transfer proc count to new user.
268 * Copy credentials so other references do not see our changes.
269 */
270 (void)chgproccnt(pc->p_ruid, -1);
271 (void)chgproccnt(uid, 1);
272 pc->pc_ucred = crcopy(pc->pc_ucred);
273 pc->pc_ucred->cr_uid = uid;
274 pc->p_ruid = uid;
275 pc->p_svuid = uid;
276 p->p_flag |= P_SUGID;
277 return (0);
278 }
279
280 /* ARGSUSED */
281 seteuid(p, v, retval)
282 struct proc *p;
283 void *v;
284 register_t *retval;
285 {
286 struct seteuid_args /* {
287 syscallarg(uid_t) euid;
288 } */ *uap = v;
289 register struct pcred *pc = p->p_cred;
290 register uid_t euid;
291 int error;
292
293 #ifdef COMPAT_09 /* XXX */
294 euid = (u_short)SCARG(uap, euid);
295 #else
296 euid = SCARG(uap, euid);
297 #endif
298 if (euid != pc->p_ruid && euid != pc->p_svuid &&
299 (error = suser(pc->pc_ucred, &p->p_acflag)))
300 return (error);
301 /*
302 * Everything's okay, do it. Copy credentials so other references do
303 * not see our changes.
304 */
305 pc->pc_ucred = crcopy(pc->pc_ucred);
306 pc->pc_ucred->cr_uid = euid;
307 p->p_flag |= P_SUGID;
308 return (0);
309 }
310
311 /* ARGSUSED */
312 setgid(p, v, retval)
313 struct proc *p;
314 void *v;
315 register_t *retval;
316 {
317 struct setgid_args /* {
318 syscallarg(gid_t) gid;
319 } */ *uap = v;
320 register struct pcred *pc = p->p_cred;
321 register gid_t gid;
322 int error;
323
324 #ifdef COMPAT_09 /* XXX */
325 gid = (u_short)SCARG(uap, gid);
326 #else
327 gid = SCARG(uap, gid);
328 #endif
329 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
330 return (error);
331 pc->pc_ucred = crcopy(pc->pc_ucred);
332 pc->pc_ucred->cr_gid = gid;
333 pc->p_rgid = gid;
334 pc->p_svgid = gid; /* ??? */
335 p->p_flag |= P_SUGID;
336 return (0);
337 }
338
339 /* ARGSUSED */
340 setegid(p, v, retval)
341 struct proc *p;
342 void *v;
343 register_t *retval;
344 {
345 struct setegid_args /* {
346 syscallarg(gid_t) egid;
347 } */ *uap = v;
348 register struct pcred *pc = p->p_cred;
349 register gid_t egid;
350 int error;
351
352 #ifdef COMPAT_09 /* XXX */
353 egid = (u_short)SCARG(uap, egid);
354 #else
355 egid = SCARG(uap, egid);
356 #endif
357 if (egid != pc->p_rgid && egid != pc->p_svgid &&
358 (error = suser(pc->pc_ucred, &p->p_acflag)))
359 return (error);
360 pc->pc_ucred = crcopy(pc->pc_ucred);
361 pc->pc_ucred->cr_gid = egid;
362 p->p_flag |= P_SUGID;
363 return (0);
364 }
365
366 /* ARGSUSED */
367 setgroups(p, v, retval)
368 struct proc *p;
369 void *v;
370 register_t *retval;
371 {
372 struct setgroups_args /* {
373 syscallarg(u_int) gidsetsize;
374 syscallarg(gid_t *) gidset;
375 } */ *uap = v;
376 register struct pcred *pc = p->p_cred;
377 register u_int ngrp;
378 int error;
379
380 if (error = suser(pc->pc_ucred, &p->p_acflag))
381 return (error);
382 ngrp = SCARG(uap, gidsetsize);
383 if (ngrp > NGROUPS)
384 return (EINVAL);
385 pc->pc_ucred = crcopy(pc->pc_ucred);
386 if (error = copyin((caddr_t)SCARG(uap, gidset),
387 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))
388 return (error);
389 pc->pc_ucred->cr_ngroups = ngrp;
390 p->p_flag |= P_SUGID;
391 return (0);
392 }
393
394 /*
395 * Check if gid is a member of the group set.
396 */
397 groupmember(gid, cred)
398 gid_t gid;
399 register struct ucred *cred;
400 {
401 register gid_t *gp;
402 gid_t *egp;
403
404 egp = &(cred->cr_groups[cred->cr_ngroups]);
405 for (gp = cred->cr_groups; gp < egp; gp++)
406 if (*gp == gid)
407 return (1);
408 return (0);
409 }
410
411 /*
412 * Test whether the specified credentials imply "super-user"
413 * privilege; if so, and we have accounting info, set the flag
414 * indicating use of super-powers.
415 * Returns 0 or error.
416 */
417 suser(cred, acflag)
418 struct ucred *cred;
419 u_short *acflag;
420 {
421 if (cred->cr_uid == 0) {
422 if (acflag)
423 *acflag |= ASU;
424 return (0);
425 }
426 return (EPERM);
427 }
428
429 /*
430 * Allocate a zeroed cred structure.
431 */
432 struct ucred *
433 crget()
434 {
435 register struct ucred *cr;
436
437 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
438 bzero((caddr_t)cr, sizeof(*cr));
439 cr->cr_ref = 1;
440 return (cr);
441 }
442
443 /*
444 * Free a cred structure.
445 * Throws away space when ref count gets to 0.
446 */
447 void
448 crfree(cr)
449 struct ucred *cr;
450 {
451 int s;
452
453 s = splimp(); /* ??? */
454 if (--cr->cr_ref == 0)
455 FREE((caddr_t)cr, M_CRED);
456 (void) splx(s);
457 }
458
459 /*
460 * Copy cred structure to a new one and free the old one.
461 */
462 struct ucred *
463 crcopy(cr)
464 struct ucred *cr;
465 {
466 struct ucred *newcr;
467
468 if (cr->cr_ref == 1)
469 return (cr);
470 newcr = crget();
471 *newcr = *cr;
472 crfree(cr);
473 newcr->cr_ref = 1;
474 return (newcr);
475 }
476
477 /*
478 * Dup cred struct to a new held one.
479 */
480 struct ucred *
481 crdup(cr)
482 struct ucred *cr;
483 {
484 struct ucred *newcr;
485
486 newcr = crget();
487 *newcr = *cr;
488 newcr->cr_ref = 1;
489 return (newcr);
490 }
491
492 /*
493 * Get login name, if available.
494 */
495 /* ARGSUSED */
496 getlogin(p, v, retval)
497 struct proc *p;
498 void *v;
499 register_t *retval;
500 {
501 struct getlogin_args /* {
502 syscallarg(char *) namebuf;
503 syscallarg(u_int) namelen;
504 } */ *uap = v;
505
506 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
507 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
508 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
509 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
510 }
511
512 /*
513 * Set login name.
514 */
515 /* ARGSUSED */
516 setlogin(p, v, retval)
517 struct proc *p;
518 void *v;
519 register_t *retval;
520 {
521 struct setlogin_args /* {
522 syscallarg(char *) namebuf;
523 } */ *uap = v;
524 int error;
525
526 if (error = suser(p->p_ucred, &p->p_acflag))
527 return (error);
528 error = copyinstr((caddr_t) SCARG(uap, namebuf),
529 (caddr_t) p->p_pgrp->pg_session->s_login,
530 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
531 if (error == ENAMETOOLONG)
532 error = EINVAL;
533 return (error);
534 }
535