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