kern_prot.c revision 1.42 1 /* $NetBSD: kern_prot.c,v 1.42 1997/11/10 08:26:09 mycroft 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(int) gidsetsize;
186 syscallarg(gid_t *) gidset;
187 } */ *uap = v;
188 register struct pcred *pc = p->p_cred;
189 register int ngrp;
190 int error;
191
192 ngrp = SCARG(uap, gidsetsize);
193 if (ngrp == 0) {
194 *retval = pc->pc_ucred->cr_ngroups;
195 return (0);
196 }
197 if (ngrp < pc->pc_ucred->cr_ngroups)
198 return (EINVAL);
199 ngrp = pc->pc_ucred->cr_ngroups;
200 error = copyout((caddr_t)pc->pc_ucred->cr_groups,
201 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
202 if (error)
203 return (error);
204 *retval = ngrp;
205 return (0);
206 }
207
208 /* ARGSUSED */
209 int
210 sys_setsid(p, v, retval)
211 register struct proc *p;
212 void *v;
213 register_t *retval;
214 {
215
216 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
217 return (EPERM);
218 } else {
219 (void)enterpgrp(p, p->p_pid, 1);
220 *retval = p->p_pid;
221 return (0);
222 }
223 }
224
225 /*
226 * set process group (setpgid/old setpgrp)
227 *
228 * caller does setpgid(targpid, targpgid)
229 *
230 * pgid must be in valid range (EINVAL)
231 * pid must be caller or child of caller (ESRCH)
232 * if a child
233 * pid must be in same session (EPERM)
234 * pid can't have done an exec (EACCES)
235 * if pgid != pid
236 * there must exist some pid in same session having pgid (EPERM)
237 * pid must not be session leader (EPERM)
238 */
239 /* ARGSUSED */
240 int
241 sys_setpgid(curp, v, retval)
242 struct proc *curp;
243 void *v;
244 register_t *retval;
245 {
246 register struct sys_setpgid_args /* {
247 syscallarg(int) pid;
248 syscallarg(int) pgid;
249 } */ *uap = v;
250 register struct proc *targp; /* target process */
251 register struct pgrp *pgrp; /* target pgrp */
252
253 if (SCARG(uap, pgid) < 0)
254 return (EINVAL);
255
256 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
257 if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
258 return (ESRCH);
259 if (targp->p_session != curp->p_session)
260 return (EPERM);
261 if (targp->p_flag & P_EXEC)
262 return (EACCES);
263 } else
264 targp = curp;
265 if (SESS_LEADER(targp))
266 return (EPERM);
267 if (SCARG(uap, pgid) == 0)
268 SCARG(uap, pgid) = targp->p_pid;
269 else if (SCARG(uap, pgid) != targp->p_pid)
270 if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
271 pgrp->pg_session != curp->p_session)
272 return (EPERM);
273 return (enterpgrp(targp, SCARG(uap, pgid), 0));
274 }
275
276 /* ARGSUSED */
277 int
278 sys_setuid(p, v, retval)
279 struct proc *p;
280 void *v;
281 register_t *retval;
282 {
283 struct sys_setuid_args /* {
284 syscallarg(uid_t) uid;
285 } */ *uap = v;
286 register struct pcred *pc = p->p_cred;
287 register uid_t uid;
288 int error;
289
290 uid = SCARG(uap, uid);
291 if (uid != pc->p_ruid &&
292 (error = suser(pc->pc_ucred, &p->p_acflag)))
293 return (error);
294 /*
295 * Everything's okay, do it.
296 * Transfer proc count to new user.
297 * Copy credentials so other references do not see our changes.
298 */
299 (void)chgproccnt(pc->p_ruid, -1);
300 (void)chgproccnt(uid, 1);
301 pc->pc_ucred = crcopy(pc->pc_ucred);
302 pc->pc_ucred->cr_uid = uid;
303 pc->p_ruid = uid;
304 pc->p_svuid = uid;
305 p->p_flag |= P_SUGID;
306 return (0);
307 }
308
309 /* ARGSUSED */
310 int
311 sys_seteuid(p, v, retval)
312 struct proc *p;
313 void *v;
314 register_t *retval;
315 {
316 struct sys_seteuid_args /* {
317 syscallarg(uid_t) euid;
318 } */ *uap = v;
319 register struct pcred *pc = p->p_cred;
320 register uid_t euid;
321 int error;
322
323 euid = SCARG(uap, euid);
324 if (euid != pc->p_ruid && euid != pc->p_svuid &&
325 (error = suser(pc->pc_ucred, &p->p_acflag)))
326 return (error);
327 /*
328 * Everything's okay, do it. Copy credentials so other references do
329 * not see our changes.
330 */
331 pc->pc_ucred = crcopy(pc->pc_ucred);
332 pc->pc_ucred->cr_uid = euid;
333 p->p_flag |= P_SUGID;
334 return (0);
335 }
336
337 int
338 sys_setreuid(p, v, retval)
339 struct proc *p;
340 void *v;
341 register_t *retval;
342 {
343 struct sys_setreuid_args /* {
344 syscallarg(uid_t) ruid;
345 syscallarg(uid_t) euid;
346 } */ *uap = v;
347 register struct pcred *pc = p->p_cred;
348 register uid_t ruid, euid;
349 int error;
350
351 ruid = SCARG(uap, ruid);
352 euid = SCARG(uap, euid);
353
354 if (ruid != (uid_t)-1 &&
355 ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid &&
356 (error = suser(pc->pc_ucred, &p->p_acflag)))
357 return (error);
358
359 if (euid != (uid_t)-1 &&
360 euid != pc->p_ruid && euid != pc->pc_ucred->cr_uid &&
361 euid != pc->p_svuid &&
362 (error = suser(pc->pc_ucred, &p->p_acflag)))
363 return (error);
364
365 if (euid != (uid_t)-1) {
366 pc->pc_ucred = crcopy(pc->pc_ucred);
367 pc->pc_ucred->cr_uid = euid;
368 }
369
370 if (ruid != (uid_t)-1) {
371 (void)chgproccnt(pc->p_ruid, -1);
372 (void)chgproccnt(ruid, 1);
373 pc->p_ruid = ruid;
374 pc->p_svuid = pc->pc_ucred->cr_uid;
375 }
376
377 if (euid != (uid_t)-1 && ruid != (uid_t)-1)
378 p->p_flag |= P_SUGID;
379 return (0);
380 }
381
382 /* ARGSUSED */
383 int
384 sys_setgid(p, v, retval)
385 struct proc *p;
386 void *v;
387 register_t *retval;
388 {
389 struct sys_setgid_args /* {
390 syscallarg(gid_t) gid;
391 } */ *uap = v;
392 register struct pcred *pc = p->p_cred;
393 register gid_t gid;
394 int error;
395
396 gid = SCARG(uap, gid);
397 if (gid != pc->p_rgid &&
398 (error = suser(pc->pc_ucred, &p->p_acflag)))
399 return (error);
400 pc->pc_ucred = crcopy(pc->pc_ucred);
401 pc->pc_ucred->cr_gid = gid;
402 pc->p_rgid = gid;
403 pc->p_svgid = gid;
404 p->p_flag |= P_SUGID;
405 return (0);
406 }
407
408 /* ARGSUSED */
409 int
410 sys_setegid(p, v, retval)
411 struct proc *p;
412 void *v;
413 register_t *retval;
414 {
415 struct sys_setegid_args /* {
416 syscallarg(gid_t) egid;
417 } */ *uap = v;
418 register struct pcred *pc = p->p_cred;
419 register gid_t egid;
420 int error;
421
422 egid = SCARG(uap, egid);
423 if (egid != pc->p_rgid && egid != pc->p_svgid &&
424 (error = suser(pc->pc_ucred, &p->p_acflag)))
425 return (error);
426 pc->pc_ucred = crcopy(pc->pc_ucred);
427 pc->pc_ucred->cr_gid = egid;
428 p->p_flag |= P_SUGID;
429 return (0);
430 }
431
432 int
433 sys_setregid(p, v, retval)
434 struct proc *p;
435 void *v;
436 register_t *retval;
437 {
438 struct sys_setregid_args /* {
439 syscallarg(gid_t) rgid;
440 syscallarg(gid_t) egid;
441 } */ *uap = v;
442 register struct pcred *pc = p->p_cred;
443 register gid_t rgid, egid;
444 int error;
445
446 rgid = SCARG(uap, rgid);
447 egid = SCARG(uap, egid);
448
449 if (rgid != (gid_t)-1 &&
450 rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_gid &&
451 (error = suser(pc->pc_ucred, &p->p_acflag)))
452 return (error);
453
454 if (egid != (gid_t)-1 &&
455 egid != pc->p_rgid && egid != pc->pc_ucred->cr_gid &&
456 egid != pc->p_svgid &&
457 (error = suser(pc->pc_ucred, &p->p_acflag)))
458 return (error);
459
460 if (egid != (gid_t)-1) {
461 pc->pc_ucred = crcopy(pc->pc_ucred);
462 pc->pc_ucred->cr_gid = egid;
463 }
464
465 if (rgid != (gid_t)-1) {
466 pc->p_rgid = rgid;
467 pc->p_svgid = pc->pc_ucred->cr_gid;
468 }
469
470 if (egid != (gid_t)-1 && rgid != (gid_t)-1)
471 p->p_flag |= P_SUGID;
472 return (0);
473 }
474
475 /* ARGSUSED */
476 int
477 sys_setgroups(p, v, retval)
478 struct proc *p;
479 void *v;
480 register_t *retval;
481 {
482 struct sys_setgroups_args /* {
483 syscallarg(int) gidsetsize;
484 syscallarg(const gid_t *) gidset;
485 } */ *uap = v;
486 register struct pcred *pc = p->p_cred;
487 register int ngrp;
488 int error;
489
490 if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
491 return (error);
492 ngrp = SCARG(uap, gidsetsize);
493 if ((u_int)ngrp > NGROUPS)
494 return (EINVAL);
495 pc->pc_ucred = crcopy(pc->pc_ucred);
496 error = copyin(SCARG(uap, gidset), pc->pc_ucred->cr_groups,
497 ngrp * sizeof(gid_t));
498 if (error)
499 return (error);
500 pc->pc_ucred->cr_ngroups = ngrp;
501 p->p_flag |= P_SUGID;
502 return (0);
503 }
504
505 /*
506 * Check if gid is a member of the group set.
507 */
508 int
509 groupmember(gid, cred)
510 gid_t gid;
511 register struct ucred *cred;
512 {
513 register gid_t *gp;
514 gid_t *egp;
515
516 egp = &(cred->cr_groups[cred->cr_ngroups]);
517 for (gp = cred->cr_groups; gp < egp; gp++)
518 if (*gp == gid)
519 return (1);
520 return (0);
521 }
522
523 /*
524 * Test whether the specified credentials imply "super-user"
525 * privilege; if so, and we have accounting info, set the flag
526 * indicating use of super-powers.
527 * Returns 0 or error.
528 */
529 int
530 suser(cred, acflag)
531 struct ucred *cred;
532 u_short *acflag;
533 {
534 if (cred->cr_uid == 0) {
535 if (acflag)
536 *acflag |= ASU;
537 return (0);
538 }
539 return (EPERM);
540 }
541
542 /*
543 * Allocate a zeroed cred structure.
544 */
545 struct ucred *
546 crget()
547 {
548 register struct ucred *cr;
549
550 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
551 bzero((caddr_t)cr, sizeof(*cr));
552 cr->cr_ref = 1;
553 return (cr);
554 }
555
556 /*
557 * Free a cred structure.
558 * Throws away space when ref count gets to 0.
559 */
560 void
561 crfree(cr)
562 struct ucred *cr;
563 {
564 int s;
565
566 s = splimp(); /* ??? */
567 if (--cr->cr_ref == 0)
568 FREE((caddr_t)cr, M_CRED);
569 (void) splx(s);
570 }
571
572 /*
573 * Copy cred structure to a new one and free the old one.
574 */
575 struct ucred *
576 crcopy(cr)
577 struct ucred *cr;
578 {
579 struct ucred *newcr;
580
581 if (cr->cr_ref == 1)
582 return (cr);
583 newcr = crget();
584 *newcr = *cr;
585 crfree(cr);
586 newcr->cr_ref = 1;
587 return (newcr);
588 }
589
590 /*
591 * Dup cred struct to a new held one.
592 */
593 struct ucred *
594 crdup(cr)
595 struct ucred *cr;
596 {
597 struct ucred *newcr;
598
599 newcr = crget();
600 *newcr = *cr;
601 newcr->cr_ref = 1;
602 return (newcr);
603 }
604
605 /*
606 * Get login name, if available.
607 */
608 /* ARGSUSED */
609 int
610 sys___getlogin(p, v, retval)
611 struct proc *p;
612 void *v;
613 register_t *retval;
614 {
615 struct sys___getlogin_args /* {
616 syscallarg(char *) namebuf;
617 syscallarg(u_int) namelen;
618 } */ *uap = v;
619
620 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
621 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
622 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
623 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
624 }
625
626 /*
627 * Set login name.
628 */
629 /* ARGSUSED */
630 int
631 sys_setlogin(p, v, retval)
632 struct proc *p;
633 void *v;
634 register_t *retval;
635 {
636 struct sys_setlogin_args /* {
637 syscallarg(const char *) namebuf;
638 } */ *uap = v;
639 int error;
640
641 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
642 return (error);
643 error = copyinstr(SCARG(uap, namebuf), p->p_pgrp->pg_session->s_login,
644 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
645 if (error == ENAMETOOLONG)
646 error = EINVAL;
647 return (error);
648 }
649