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