kern_prot.c revision 1.39 1 /* $NetBSD: kern_prot.c,v 1.39 1997/03/27 06:14:03 mikel 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 int
61 sys_getpid(p, v, retval)
62 struct proc *p;
63 void *v;
64 register_t *retval;
65 {
66
67 *retval = p->p_pid;
68 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
69 defined(COMPAT_FREEBSD)
70 retval[1] = p->p_pptr->p_pid;
71 #endif
72 return (0);
73 }
74
75 /* ARGSUSED */
76 int
77 sys_getppid(p, v, retval)
78 struct proc *p;
79 void *v;
80 register_t *retval;
81 {
82
83 *retval = p->p_pptr->p_pid;
84 return (0);
85 }
86
87 /* Get process group ID; note that POSIX getpgrp takes no parameter */
88 int
89 sys_getpgrp(p, v, retval)
90 struct proc *p;
91 void *v;
92 register_t *retval;
93 {
94
95 *retval = p->p_pgrp->pg_id;
96 return (0);
97 }
98
99 int
100 sys_getpgid(p, v, retval)
101 struct proc *p;
102 void *v;
103 register_t *retval;
104 {
105 register struct sys_getpgid_args /* {
106 syscallarg(pid_t) pid;
107 } */ *uap = v;
108
109 if (SCARG(uap, pid) == 0)
110 goto found;
111 if ((p = pfind(SCARG(uap, pid))) == 0)
112 return (ESRCH);
113 found:
114 *retval = p->p_pgid;
115 return 0;
116 }
117
118 /* ARGSUSED */
119 int
120 sys_getuid(p, v, retval)
121 struct proc *p;
122 void *v;
123 register_t *retval;
124 {
125
126 *retval = p->p_cred->p_ruid;
127 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
128 defined(COMPAT_FREEBSD)
129 retval[1] = p->p_ucred->cr_uid;
130 #endif
131 return (0);
132 }
133
134 /* ARGSUSED */
135 int
136 sys_geteuid(p, v, retval)
137 struct proc *p;
138 void *v;
139 register_t *retval;
140 {
141
142 *retval = p->p_ucred->cr_uid;
143 return (0);
144 }
145
146 /* ARGSUSED */
147 int
148 sys_getgid(p, v, retval)
149 struct proc *p;
150 void *v;
151 register_t *retval;
152 {
153
154 *retval = p->p_cred->p_rgid;
155 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD)
156 retval[1] = p->p_ucred->cr_gid;
157 #endif
158 return (0);
159 }
160
161 /*
162 * Get effective group ID. The "egid" is groups[0], and could be obtained
163 * via getgroups. This syscall exists because it is somewhat painful to do
164 * correctly in a library function.
165 */
166 /* ARGSUSED */
167 int
168 sys_getegid(p, v, retval)
169 struct proc *p;
170 void *v;
171 register_t *retval;
172 {
173
174 *retval = p->p_ucred->cr_gid;
175 return (0);
176 }
177
178 int
179 sys_getgroups(p, v, retval)
180 struct proc *p;
181 void *v;
182 register_t *retval;
183 {
184 register struct sys_getgroups_args /* {
185 syscallarg(u_int) gidsetsize;
186 syscallarg(gid_t *) gidset;
187 } */ *uap = v;
188 register struct pcred *pc = p->p_cred;
189 register u_int ngrp;
190 int error;
191
192 if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
193 *retval = pc->pc_ucred->cr_ngroups;
194 return (0);
195 }
196 if (ngrp < pc->pc_ucred->cr_ngroups)
197 return (EINVAL);
198 ngrp = pc->pc_ucred->cr_ngroups;
199 error = copyout((caddr_t)pc->pc_ucred->cr_groups,
200 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
201 if (error)
202 return (error);
203 *retval = ngrp;
204 return (0);
205 }
206
207 /* ARGSUSED */
208 int
209 sys_setsid(p, v, retval)
210 register struct proc *p;
211 void *v;
212 register_t *retval;
213 {
214
215 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
216 return (EPERM);
217 } else {
218 (void)enterpgrp(p, p->p_pid, 1);
219 *retval = p->p_pid;
220 return (0);
221 }
222 }
223
224 /*
225 * set process group (setpgid/old setpgrp)
226 *
227 * caller does setpgid(targpid, targpgid)
228 *
229 * pgid must be in valid range (EINVAL)
230 * pid must be caller or child of caller (ESRCH)
231 * if a child
232 * pid must be in same session (EPERM)
233 * pid can't have done an exec (EACCES)
234 * if pgid != pid
235 * there must exist some pid in same session having pgid (EPERM)
236 * pid must not be session leader (EPERM)
237 */
238 /* ARGSUSED */
239 int
240 sys_setpgid(curp, v, retval)
241 struct proc *curp;
242 void *v;
243 register_t *retval;
244 {
245 register struct sys_setpgid_args /* {
246 syscallarg(int) pid;
247 syscallarg(int) pgid;
248 } */ *uap = v;
249 register struct proc *targp; /* target process */
250 register struct pgrp *pgrp; /* target pgrp */
251
252 #ifdef COMPAT_09
253 SCARG(uap, pid) = (short) SCARG(uap, pid); /* XXX */
254 SCARG(uap, pgid) = (short) SCARG(uap, pgid); /* XXX */
255 #endif
256
257 if (SCARG(uap, pgid) < 0)
258 return (EINVAL);
259
260 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
261 if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
262 return (ESRCH);
263 if (targp->p_session != curp->p_session)
264 return (EPERM);
265 if (targp->p_flag & P_EXEC)
266 return (EACCES);
267 } else
268 targp = curp;
269 if (SESS_LEADER(targp))
270 return (EPERM);
271 if (SCARG(uap, pgid) == 0)
272 SCARG(uap, pgid) = targp->p_pid;
273 else if (SCARG(uap, pgid) != targp->p_pid)
274 if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
275 pgrp->pg_session != curp->p_session)
276 return (EPERM);
277 return (enterpgrp(targp, SCARG(uap, pgid), 0));
278 }
279
280 /* ARGSUSED */
281 int
282 sys_setuid(p, v, retval)
283 struct proc *p;
284 void *v;
285 register_t *retval;
286 {
287 struct sys_setuid_args /* {
288 syscallarg(uid_t) uid;
289 } */ *uap = v;
290 register struct pcred *pc = p->p_cred;
291 register uid_t uid;
292 int error;
293
294 #ifdef COMPAT_09 /* XXX */
295 uid = (u_short)SCARG(uap, uid);
296 #else
297 uid = SCARG(uap, uid);
298 #endif
299 if (uid != pc->p_ruid &&
300 (error = suser(pc->pc_ucred, &p->p_acflag)))
301 return (error);
302 /*
303 * Everything's okay, do it.
304 * Transfer proc count to new user.
305 * Copy credentials so other references do not see our changes.
306 */
307 (void)chgproccnt(pc->p_ruid, -1);
308 (void)chgproccnt(uid, 1);
309 pc->pc_ucred = crcopy(pc->pc_ucred);
310 pc->pc_ucred->cr_uid = uid;
311 pc->p_ruid = uid;
312 pc->p_svuid = uid;
313 p->p_flag |= P_SUGID;
314 return (0);
315 }
316
317 /* ARGSUSED */
318 int
319 sys_seteuid(p, v, retval)
320 struct proc *p;
321 void *v;
322 register_t *retval;
323 {
324 struct sys_seteuid_args /* {
325 syscallarg(uid_t) euid;
326 } */ *uap = v;
327 register struct pcred *pc = p->p_cred;
328 register uid_t euid;
329 int error;
330
331 #ifdef COMPAT_09 /* XXX */
332 euid = (u_short)SCARG(uap, euid);
333 #else
334 euid = SCARG(uap, euid);
335 #endif
336 if (euid != pc->p_ruid && euid != pc->p_svuid &&
337 (error = suser(pc->pc_ucred, &p->p_acflag)))
338 return (error);
339 /*
340 * Everything's okay, do it. Copy credentials so other references do
341 * not see our changes.
342 */
343 pc->pc_ucred = crcopy(pc->pc_ucred);
344 pc->pc_ucred->cr_uid = euid;
345 p->p_flag |= P_SUGID;
346 return (0);
347 }
348
349 int
350 sys_setreuid(p, v, retval)
351 struct proc *p;
352 void *v;
353 register_t *retval;
354 {
355 struct sys_setreuid_args /* {
356 syscallarg(uid_t) ruid;
357 syscallarg(uid_t) euid;
358 } */ *uap = v;
359 register struct pcred *pc = p->p_cred;
360 register uid_t ruid, euid;
361 int error;
362
363 ruid = SCARG(uap, ruid);
364 euid = SCARG(uap, euid);
365
366 if (ruid != (uid_t)-1 &&
367 ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid &&
368 (error = suser(pc->pc_ucred, &p->p_acflag)))
369 return (error);
370
371 if (euid != (uid_t)-1 &&
372 euid != pc->p_ruid && euid != pc->pc_ucred->cr_uid &&
373 euid != pc->p_svuid &&
374 (error = suser(pc->pc_ucred, &p->p_acflag)))
375 return (error);
376
377 if (euid != (uid_t)-1) {
378 pc->pc_ucred = crcopy(pc->pc_ucred);
379 pc->pc_ucred->cr_uid = euid;
380 }
381
382 if (ruid != (uid_t)-1) {
383 (void)chgproccnt(pc->p_ruid, -1);
384 (void)chgproccnt(ruid, 1);
385 pc->p_ruid = ruid;
386 pc->p_svuid = pc->pc_ucred->cr_uid;
387 }
388
389 if (euid != (uid_t)-1 && ruid != (uid_t)-1)
390 p->p_flag |= P_SUGID;
391 return (0);
392 }
393
394 /* ARGSUSED */
395 int
396 sys_setgid(p, v, retval)
397 struct proc *p;
398 void *v;
399 register_t *retval;
400 {
401 struct sys_setgid_args /* {
402 syscallarg(gid_t) gid;
403 } */ *uap = v;
404 register struct pcred *pc = p->p_cred;
405 register gid_t gid;
406 int error;
407
408 #ifdef COMPAT_09 /* XXX */
409 gid = (u_short)SCARG(uap, gid);
410 #else
411 gid = SCARG(uap, gid);
412 #endif
413 if (gid != pc->p_rgid &&
414 (error = suser(pc->pc_ucred, &p->p_acflag)))
415 return (error);
416 pc->pc_ucred = crcopy(pc->pc_ucred);
417 pc->pc_ucred->cr_gid = gid;
418 pc->p_rgid = gid;
419 pc->p_svgid = gid;
420 p->p_flag |= P_SUGID;
421 return (0);
422 }
423
424 /* ARGSUSED */
425 int
426 sys_setegid(p, v, retval)
427 struct proc *p;
428 void *v;
429 register_t *retval;
430 {
431 struct sys_setegid_args /* {
432 syscallarg(gid_t) egid;
433 } */ *uap = v;
434 register struct pcred *pc = p->p_cred;
435 register gid_t egid;
436 int error;
437
438 #ifdef COMPAT_09 /* XXX */
439 egid = (u_short)SCARG(uap, egid);
440 #else
441 egid = SCARG(uap, egid);
442 #endif
443 if (egid != pc->p_rgid && egid != pc->p_svgid &&
444 (error = suser(pc->pc_ucred, &p->p_acflag)))
445 return (error);
446 pc->pc_ucred = crcopy(pc->pc_ucred);
447 pc->pc_ucred->cr_gid = egid;
448 p->p_flag |= P_SUGID;
449 return (0);
450 }
451
452 int
453 sys_setregid(p, v, retval)
454 struct proc *p;
455 void *v;
456 register_t *retval;
457 {
458 struct sys_setregid_args /* {
459 syscallarg(gid_t) rgid;
460 syscallarg(gid_t) egid;
461 } */ *uap = v;
462 register struct pcred *pc = p->p_cred;
463 register gid_t rgid, egid;
464 int error;
465
466 rgid = SCARG(uap, rgid);
467 egid = SCARG(uap, egid);
468
469 if (rgid != (gid_t)-1 &&
470 rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_gid &&
471 (error = suser(pc->pc_ucred, &p->p_acflag)))
472 return (error);
473
474 if (egid != (gid_t)-1 &&
475 egid != pc->p_rgid && egid != pc->pc_ucred->cr_gid &&
476 egid != pc->p_svgid &&
477 (error = suser(pc->pc_ucred, &p->p_acflag)))
478 return (error);
479
480 if (egid != (gid_t)-1) {
481 pc->pc_ucred = crcopy(pc->pc_ucred);
482 pc->pc_ucred->cr_gid = egid;
483 }
484
485 if (rgid != (gid_t)-1) {
486 pc->p_rgid = rgid;
487 pc->p_svgid = pc->pc_ucred->cr_gid;
488 }
489
490 if (egid != (gid_t)-1 && rgid != (gid_t)-1)
491 p->p_flag |= P_SUGID;
492 return (0);
493 }
494
495 /* ARGSUSED */
496 int
497 sys_setgroups(p, v, retval)
498 struct proc *p;
499 void *v;
500 register_t *retval;
501 {
502 struct sys_setgroups_args /* {
503 syscallarg(u_int) gidsetsize;
504 syscallarg(const gid_t *) gidset;
505 } */ *uap = v;
506 register struct pcred *pc = p->p_cred;
507 register u_int ngrp;
508 int error;
509
510 if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
511 return (error);
512 ngrp = SCARG(uap, gidsetsize);
513 if (ngrp > NGROUPS)
514 return (EINVAL);
515 pc->pc_ucred = crcopy(pc->pc_ucred);
516 error = copyin(SCARG(uap, gidset), pc->pc_ucred->cr_groups,
517 ngrp * sizeof(gid_t));
518 if (error)
519 return (error);
520 pc->pc_ucred->cr_ngroups = ngrp;
521 p->p_flag |= P_SUGID;
522 return (0);
523 }
524
525 /*
526 * Check if gid is a member of the group set.
527 */
528 int
529 groupmember(gid, cred)
530 gid_t gid;
531 register struct ucred *cred;
532 {
533 register gid_t *gp;
534 gid_t *egp;
535
536 egp = &(cred->cr_groups[cred->cr_ngroups]);
537 for (gp = cred->cr_groups; gp < egp; gp++)
538 if (*gp == gid)
539 return (1);
540 return (0);
541 }
542
543 /*
544 * Test whether the specified credentials imply "super-user"
545 * privilege; if so, and we have accounting info, set the flag
546 * indicating use of super-powers.
547 * Returns 0 or error.
548 */
549 int
550 suser(cred, acflag)
551 struct ucred *cred;
552 u_short *acflag;
553 {
554 if (cred->cr_uid == 0) {
555 if (acflag)
556 *acflag |= ASU;
557 return (0);
558 }
559 return (EPERM);
560 }
561
562 /*
563 * Allocate a zeroed cred structure.
564 */
565 struct ucred *
566 crget()
567 {
568 register struct ucred *cr;
569
570 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
571 bzero((caddr_t)cr, sizeof(*cr));
572 cr->cr_ref = 1;
573 return (cr);
574 }
575
576 /*
577 * Free a cred structure.
578 * Throws away space when ref count gets to 0.
579 */
580 void
581 crfree(cr)
582 struct ucred *cr;
583 {
584 int s;
585
586 s = splimp(); /* ??? */
587 if (--cr->cr_ref == 0)
588 FREE((caddr_t)cr, M_CRED);
589 (void) splx(s);
590 }
591
592 /*
593 * Copy cred structure to a new one and free the old one.
594 */
595 struct ucred *
596 crcopy(cr)
597 struct ucred *cr;
598 {
599 struct ucred *newcr;
600
601 if (cr->cr_ref == 1)
602 return (cr);
603 newcr = crget();
604 *newcr = *cr;
605 crfree(cr);
606 newcr->cr_ref = 1;
607 return (newcr);
608 }
609
610 /*
611 * Dup cred struct to a new held one.
612 */
613 struct ucred *
614 crdup(cr)
615 struct ucred *cr;
616 {
617 struct ucred *newcr;
618
619 newcr = crget();
620 *newcr = *cr;
621 newcr->cr_ref = 1;
622 return (newcr);
623 }
624
625 /*
626 * Get login name, if available.
627 */
628 /* ARGSUSED */
629 int
630 sys___getlogin(p, v, retval)
631 struct proc *p;
632 void *v;
633 register_t *retval;
634 {
635 struct sys___getlogin_args /* {
636 syscallarg(char *) namebuf;
637 syscallarg(u_int) namelen;
638 } */ *uap = v;
639
640 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
641 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
642 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
643 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
644 }
645
646 /*
647 * Set login name.
648 */
649 /* ARGSUSED */
650 int
651 sys_setlogin(p, v, retval)
652 struct proc *p;
653 void *v;
654 register_t *retval;
655 {
656 struct sys_setlogin_args /* {
657 syscallarg(const char *) namebuf;
658 } */ *uap = v;
659 int error;
660
661 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
662 return (error);
663 error = copyinstr(SCARG(uap, namebuf), p->p_pgrp->pg_session->s_login,
664 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
665 if (error == ENAMETOOLONG)
666 error = EINVAL;
667 return (error);
668 }
669