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