1 /** $MirOS: src/sys/kern/kern_prot.c,v 1.3 2011/07/17 22:33:41 tg Exp $ */
2 /* $OpenBSD: kern_prot.c,v 1.26 2003/09/01 18:06:03 henning Exp $ */
3 /* + 1.39.4.1 */
4 /* $NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $ */
5
6 /*
7 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
8 * The Regents of the University of California. All rights reserved.
9 * (c) UNIX System Laboratories, Inc.
10 * All or some portions of this file are derived from material licensed
11 * to the University of California by American Telephone and Telegraph
12 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
13 * the permission of UNIX System Laboratories, Inc.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94
40 */
41
42 /*
43 * System calls related to processes and protection
44 */
45
46 #include <sys/param.h>
47 #include <sys/acct.h>
48 #include <sys/systm.h>
49 #include <sys/ucred.h>
50 #include <sys/proc.h>
51 #include <sys/timeb.h>
52 #include <sys/times.h>
53 #include <sys/malloc.h>
54 #include <sys/filedesc.h>
55 #include <sys/pool.h>
56
57 #include <sys/mount.h>
58 #include <sys/syscallargs.h>
59
60 /* ARGSUSED */
61 int
sys_getpid(p,v,retval)62 sys_getpid(p, v, retval)
63 struct proc *p;
64 void *v;
65 register_t *retval;
66 {
67
68 *retval = p->p_pid;
69 #if defined(COMPAT_43)
70 retval[1] = p->p_pptr->p_pid;
71 #endif
72 return (0);
73 }
74
75 /* ARGSUSED */
76 int
sys_getppid(p,v,retval)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
sys_getpgrp(p,v,retval)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 /*
100 * SysVR.4 compatible getpgid()
101 */
102 pid_t
sys_getpgid(curp,v,retval)103 sys_getpgid(curp, v, retval)
104 struct proc *curp;
105 void *v;
106 register_t *retval;
107 {
108 struct sys_getpgid_args /* {
109 syscallarg(pid_t) pid;
110 } */ *uap = v;
111 struct proc *targp = curp;
112
113 if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == curp->p_pid)
114 goto found;
115 if ((targp = pfind(SCARG(uap, pid))) == NULL)
116 return (ESRCH);
117 if (targp->p_session != curp->p_session)
118 return (EPERM);
119 found:
120 *retval = targp->p_pgid;
121 return (0);
122 }
123
124 pid_t
sys_getsid(curp,v,retval)125 sys_getsid(curp, v, retval)
126 struct proc *curp;
127 void *v;
128 register_t *retval;
129 {
130 struct sys_getsid_args /* {
131 syscallarg(pid_t) pid;
132 } */ *uap = v;
133 struct proc *targp = curp;
134
135 if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == curp->p_pid)
136 goto found;
137 if ((targp = pfind(SCARG(uap, pid))) == NULL)
138 return (ESRCH);
139 if (targp->p_session != curp->p_session)
140 return (EPERM);
141 found:
142 /* Skip exiting processes */
143 if (targp->p_pgrp->pg_session->s_leader == NULL)
144 return (ESRCH);
145 *retval = targp->p_pgrp->pg_session->s_leader->p_pid;
146 return (0);
147 }
148
149 /* ARGSUSED */
150 int
sys_getuid(p,v,retval)151 sys_getuid(p, v, retval)
152 struct proc *p;
153 void *v;
154 register_t *retval;
155 {
156
157 *retval = p->p_cred->p_ruid;
158 #if defined(COMPAT_43)
159 retval[1] = p->p_ucred->cr_uid;
160 #endif
161 return (0);
162 }
163
164 /* ARGSUSED */
165 int
sys_geteuid(p,v,retval)166 sys_geteuid(p, v, retval)
167 struct proc *p;
168 void *v;
169 register_t *retval;
170 {
171
172 *retval = p->p_ucred->cr_uid;
173 return (0);
174 }
175
176 /* ARGSUSED */
177 int
sys_issetugid(p,v,retval)178 sys_issetugid(p, v, retval)
179 struct proc *p;
180 void *v;
181 register_t *retval;
182 {
183 if (p->p_flag & P_SUGIDEXEC)
184 *retval = 1;
185 else
186 *retval = 0;
187 return (0);
188 }
189
190 /* ARGSUSED */
191 int
sys_getgid(p,v,retval)192 sys_getgid(p, v, retval)
193 struct proc *p;
194 void *v;
195 register_t *retval;
196 {
197
198 *retval = p->p_cred->p_rgid;
199 #if defined(COMPAT_43)
200 retval[1] = p->p_ucred->cr_gid;
201 #endif
202 return (0);
203 }
204
205 /*
206 * Get effective group ID. The "egid" is groups[0], and could be obtained
207 * via getgroups. This syscall exists because it is somewhat painful to do
208 * correctly in a library function.
209 */
210 /* ARGSUSED */
211 int
sys_getegid(p,v,retval)212 sys_getegid(p, v, retval)
213 struct proc *p;
214 void *v;
215 register_t *retval;
216 {
217
218 *retval = p->p_ucred->cr_gid;
219 return (0);
220 }
221
222 int
sys_getgroups(p,v,retval)223 sys_getgroups(p, v, retval)
224 struct proc *p;
225 void *v;
226 register_t *retval;
227 {
228 struct sys_getgroups_args /* {
229 syscallarg(int) gidsetsize;
230 syscallarg(gid_t *) gidset;
231 } */ *uap = v;
232 struct pcred *pc = p->p_cred;
233 u_int ngrp;
234 int error;
235
236 if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
237 *retval = pc->pc_ucred->cr_ngroups;
238 return (0);
239 }
240 if (ngrp < pc->pc_ucred->cr_ngroups)
241 return (EINVAL);
242 ngrp = pc->pc_ucred->cr_ngroups;
243 error = copyout((caddr_t)pc->pc_ucred->cr_groups,
244 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
245 if (error)
246 return (error);
247 *retval = ngrp;
248 return (0);
249 }
250
251 /* ARGSUSED */
252 int
sys_setsid(p,v,retval)253 sys_setsid(p, v, retval)
254 struct proc *p;
255 void *v;
256 register_t *retval;
257 {
258
259 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
260 return (EPERM);
261 } else {
262 (void)enterpgrp(p, p->p_pid, 1);
263 *retval = p->p_pid;
264 return (0);
265 }
266 }
267
268 /*
269 * set process group (setpgid/old setpgrp)
270 *
271 * caller does setpgid(targpid, targpgid)
272 *
273 * pid must be caller or child of caller (ESRCH)
274 * if a child
275 * pid must be in same session (EPERM)
276 * pid can't have done an exec (EACCES)
277 * if pgid != pid
278 * there must exist some pid in same session having pgid (EPERM)
279 * pid must not be session leader (EPERM)
280 */
281 /* ARGSUSED */
282 int
sys_setpgid(curp,v,retval)283 sys_setpgid(curp, v, retval)
284 struct proc *curp;
285 void *v;
286 register_t *retval;
287 {
288 struct sys_setpgid_args /* {
289 syscallarg(pid_t) pid;
290 syscallarg(int) pgid;
291 } */ *uap = v;
292 struct proc *targp; /* target process */
293 struct pgrp *pgrp; /* target pgrp */
294 pid_t pid;
295 int pgid;
296
297 pid = SCARG(uap, pid);
298 pgid = SCARG(uap, pgid);
299
300 if (pgid < 0)
301 return (EINVAL);
302
303 if (pid != 0 && pid != curp->p_pid) {
304 if ((targp = pfind(pid)) == 0 || !inferior(targp, curp))
305 return (ESRCH);
306 if (targp->p_session != curp->p_session)
307 return (EPERM);
308 if (targp->p_flag & P_EXEC)
309 return (EACCES);
310 } else
311 targp = curp;
312 if (SESS_LEADER(targp))
313 return (EPERM);
314 if (pgid == 0)
315 pgid = targp->p_pid;
316 else if (pgid != targp->p_pid)
317 if ((pgrp = pgfind(pgid)) == 0 ||
318 pgrp->pg_session != curp->p_session)
319 return (EPERM);
320 return (enterpgrp(targp, pgid, 0));
321 }
322
323 /* ARGSUSED */
324 int
sys_getresuid(p,v,retval)325 sys_getresuid(p, v, retval)
326 struct proc *p;
327 void *v;
328 register_t *retval;
329 {
330 struct sys_getresuid_args /* {
331 syscallarg(uid_t *) ruid;
332 syscallarg(uid_t *) euid;
333 syscallarg(uid_t *) suid;
334 } */ *uap = v;
335 struct pcred *pc = p->p_cred;
336 uid_t *ruid, *euid, *suid;
337 int error1 = 0, error2 = 0, error3 = 0;
338
339 ruid = SCARG(uap, ruid);
340 euid = SCARG(uap, euid);
341 suid = SCARG(uap, suid);
342
343 if (ruid != NULL)
344 error1 = copyout(&pc->p_ruid, ruid, sizeof(*ruid));
345 if (euid != NULL)
346 error2 = copyout(&pc->pc_ucred->cr_uid, euid, sizeof(*euid));
347 if (suid != NULL)
348 error3 = copyout(&pc->p_svuid, suid, sizeof(*suid));
349
350 return (error1 ? error1 : error2 ? error2 : error3);
351 }
352
353 /* ARGSUSED */
354 int
sys_setresuid(p,v,retval)355 sys_setresuid(p, v, retval)
356 struct proc *p;
357 void *v;
358 register_t *retval;
359 {
360 struct sys_setresuid_args /* {
361 syscallarg(uid_t) ruid;
362 syscallarg(uid_t) euid;
363 syscallarg(uid_t) suid;
364 } */ *uap = v;
365 struct pcred *pc = p->p_cred;
366 uid_t ruid, euid, suid;
367 int error;
368
369 ruid = SCARG(uap, ruid);
370 euid = SCARG(uap, euid);
371 suid = SCARG(uap, suid);
372
373 if ((ruid == -1 || ruid == pc->p_ruid) &&
374 (euid == -1 || euid == pc->pc_ucred->cr_uid) &&
375 (suid == -1 || suid == pc->p_svuid))
376 return (0); /* no change */
377
378 /*
379 * Any of the real, effective, and saved uids may be changed
380 * to the current value of one of the three (root is not limited).
381 */
382 if (ruid != (uid_t)-1 &&
383 ruid != pc->p_ruid &&
384 ruid != pc->pc_ucred->cr_uid &&
385 ruid != pc->p_svuid &&
386 (error = suser(p, 0)))
387 return (error);
388
389 if (euid != (uid_t)-1 &&
390 euid != pc->p_ruid &&
391 euid != pc->pc_ucred->cr_uid &&
392 euid != pc->p_svuid &&
393 (error = suser(p, 0)))
394 return (error);
395
396 if (suid != (uid_t)-1 &&
397 suid != pc->p_ruid &&
398 suid != pc->pc_ucred->cr_uid &&
399 suid != pc->p_svuid &&
400 (error = suser(p, 0)))
401 return (error);
402
403 /*
404 * Note that unlike the other set*uid() calls, each
405 * uid type is set independently of the others.
406 */
407 if (ruid != (uid_t)-1 && ruid != pc->p_ruid) {
408 /*
409 * Transfer proc count to new user.
410 */
411 (void)chgproccnt(pc->p_ruid, -1);
412 (void)chgproccnt(ruid, 1);
413 pc->p_ruid = ruid;
414 }
415 if (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid) {
416 /*
417 * Copy credentials so other references do not see our changes.
418 */
419 pc->pc_ucred = crcopy(pc->pc_ucred);
420 pc->pc_ucred->cr_uid = euid;
421 }
422 if (suid != (uid_t)-1 && suid != pc->p_svuid)
423 pc->p_svuid = suid;
424
425 p->p_flag |= P_SUGID;
426 return (0);
427 }
428
429 /* ARGSUSED */
430 int
sys_getresgid(p,v,retval)431 sys_getresgid(p, v, retval)
432 struct proc *p;
433 void *v;
434 register_t *retval;
435 {
436 struct sys_getresgid_args /* {
437 syscallarg(gid_t *) rgid;
438 syscallarg(gid_t *) egid;
439 syscallarg(gid_t *) sgid;
440 } */ *uap = v;
441 struct pcred *pc = p->p_cred;
442 gid_t *rgid, *egid, *sgid;
443 int error1 = 0, error2 = 0, error3 = 0;
444
445 rgid = SCARG(uap, rgid);
446 egid = SCARG(uap, egid);
447 sgid = SCARG(uap, sgid);
448
449 if (rgid != NULL)
450 error1 = copyout(&pc->p_rgid, rgid, sizeof(*rgid));
451 if (egid != NULL)
452 error2 = copyout(&pc->pc_ucred->cr_gid, egid, sizeof(*egid));
453 if (sgid != NULL)
454 error3 = copyout(&pc->p_svgid, sgid, sizeof(*sgid));
455
456 return (error1 ? error1 : error2 ? error2 : error3);
457 }
458
459 /* ARGSUSED */
460 int
sys_setresgid(p,v,retval)461 sys_setresgid(p, v, retval)
462 struct proc *p;
463 void *v;
464 register_t *retval;
465 {
466 struct sys_setresgid_args /* {
467 syscallarg(gid_t) rgid;
468 syscallarg(gid_t) egid;
469 syscallarg(gid_t) sgid;
470 } */ *uap = v;
471 struct pcred *pc = p->p_cred;
472 gid_t rgid, egid, sgid;
473 int error;
474
475 rgid = SCARG(uap, rgid);
476 egid = SCARG(uap, egid);
477 sgid = SCARG(uap, sgid);
478
479 if ((rgid == -1 || rgid == pc->p_rgid) &&
480 (egid == -1 || egid == pc->pc_ucred->cr_gid) &&
481 (sgid == -1 || sgid == pc->p_svgid))
482 return (0); /* no change */
483
484 /*
485 * Any of the real, effective, and saved gids may be changed
486 * to the current value of one of the three (root is not limited).
487 */
488 if (rgid != (gid_t)-1 &&
489 rgid != pc->p_rgid &&
490 rgid != pc->pc_ucred->cr_gid &&
491 rgid != pc->p_svgid &&
492 (error = suser(p, 0)))
493 return (error);
494
495 if (egid != (gid_t)-1 &&
496 egid != pc->p_rgid &&
497 egid != pc->pc_ucred->cr_gid &&
498 egid != pc->p_svgid &&
499 (error = suser(p, 0)))
500 return (error);
501
502 if (sgid != (gid_t)-1 &&
503 sgid != pc->p_rgid &&
504 sgid != pc->pc_ucred->cr_gid &&
505 sgid != pc->p_svgid &&
506 (error = suser(p, 0)))
507 return (error);
508
509 /*
510 * Note that unlike the other set*gid() calls, each
511 * gid type is set independently of the others.
512 */
513 if (rgid != (gid_t)-1)
514 pc->p_rgid = rgid;
515 if (egid != (gid_t)-1) {
516 /*
517 * Copy credentials so other references do not see our changes.
518 */
519 pc->pc_ucred = crcopy(pc->pc_ucred);
520 pc->pc_ucred->cr_gid = egid;
521 }
522 if (sgid != (gid_t)-1)
523 pc->p_svgid = sgid;
524
525 p->p_flag |= P_SUGID;
526 return (0);
527 }
528
529 /* ARGSUSED */
530 int
sys_setregid(p,v,retval)531 sys_setregid(p, v, retval)
532 struct proc *p;
533 void *v;
534 register_t *retval;
535 {
536 struct sys_setregid_args /* {
537 syscallarg(gid_t) rgid;
538 syscallarg(gid_t) egid;
539 } */ *uap = v;
540 struct pcred *pc = p->p_cred;
541 struct sys_setresgid_args sresgidargs;
542 gid_t rgid, egid;
543
544 rgid = SCARG(&sresgidargs, rgid) = SCARG(uap, rgid);
545 egid = SCARG(&sresgidargs, egid) = SCARG(uap, egid);
546
547 /*
548 * The saved gid presents a bit of a dilemma, as it did not
549 * exist when setregid(2) was conceived. We only set the saved
550 * gid when the real gid is specified and either its value would
551 * change, or where the saved and effective gids are different.
552 */
553 if (rgid != (gid_t)-1 && (rgid != pc->p_rgid ||
554 pc->p_svgid != (egid != (gid_t)-1 ? egid : pc->pc_ucred->cr_gid)))
555 SCARG(&sresgidargs, sgid) = rgid;
556 else
557 SCARG(&sresgidargs, sgid) = (gid_t)-1;
558
559 return (sys_setresgid(p, &sresgidargs, retval));
560 }
561
562 /* ARGSUSED */
563 int
sys_setreuid(p,v,retval)564 sys_setreuid(p, v, retval)
565 struct proc *p;
566 void *v;
567 register_t *retval;
568 {
569 struct sys_setreuid_args /* {
570 syscallarg(uid_t) ruid;
571 syscallarg(uid_t) euid;
572 } */ *uap = v;
573 struct pcred *pc = p->p_cred;
574 struct sys_setresuid_args sresuidargs;
575 uid_t ruid, euid;
576
577 ruid = SCARG(&sresuidargs, ruid) = SCARG(uap, ruid);
578 euid = SCARG(&sresuidargs, euid) = SCARG(uap, euid);
579
580 /*
581 * The saved uid presents a bit of a dilemma, as it did not
582 * exist when setreuid(2) was conceived. We only set the saved
583 * uid when the real uid is specified and either its value would
584 * change, or where the saved and effective uids are different.
585 */
586 if (ruid != (uid_t)-1 && (ruid != pc->p_ruid ||
587 pc->p_svuid != (euid != (uid_t)-1 ? euid : pc->pc_ucred->cr_uid)))
588 SCARG(&sresuidargs, suid) = ruid;
589 else
590 SCARG(&sresuidargs, suid) = (uid_t)-1;
591
592 return (sys_setresuid(p, &sresuidargs, retval));
593 }
594
595 /* ARGSUSED */
596 int
sys_setuid(p,v,retval)597 sys_setuid(p, v, retval)
598 struct proc *p;
599 void *v;
600 register_t *retval;
601 {
602 struct sys_setuid_args /* {
603 syscallarg(uid_t) uid;
604 } */ *uap = v;
605 struct pcred *pc = p->p_cred;
606 uid_t uid;
607 int error;
608
609 uid = SCARG(uap, uid);
610
611 if (pc->pc_ucred->cr_uid == uid &&
612 pc->p_ruid == uid &&
613 pc->p_svuid == uid)
614 return (0);
615
616 if (uid != pc->p_ruid &&
617 uid != pc->p_svuid &&
618 uid != pc->pc_ucred->cr_uid &&
619 (error = suser(p, 0)))
620 return (error);
621
622 /*
623 * Everything's okay, do it.
624 */
625 if (uid == pc->pc_ucred->cr_uid ||
626 suser(p, 0) == 0) {
627 /*
628 * Transfer proc count to new user.
629 */
630 if (uid != pc->p_ruid) {
631 (void)chgproccnt(pc->p_ruid, -1);
632 (void)chgproccnt(uid, 1);
633 }
634 pc->p_ruid = uid;
635 pc->p_svuid = uid;
636 }
637
638 /*
639 * Copy credentials so other references do not see our changes.
640 */
641 pc->pc_ucred = crcopy(pc->pc_ucred);
642 pc->pc_ucred->cr_uid = uid;
643 p->p_flag |= P_SUGID;
644 return (0);
645 }
646
647 /* ARGSUSED */
648 int
sys_seteuid(p,v,retval)649 sys_seteuid(p, v, retval)
650 struct proc *p;
651 void *v;
652 register_t *retval;
653 {
654 struct sys_seteuid_args /* {
655 syscallarg(uid_t) euid;
656 } */ *uap = v;
657 struct pcred *pc = p->p_cred;
658 uid_t euid;
659 int error;
660
661 euid = SCARG(uap, euid);
662
663 if (pc->pc_ucred->cr_uid == euid)
664 return (0);
665
666 if (euid != pc->p_ruid && euid != pc->p_svuid &&
667 (error = suser(p, 0)))
668 return (error);
669
670 /*
671 * Copy credentials so other references do not see our changes.
672 */
673 pc->pc_ucred = crcopy(pc->pc_ucred);
674 pc->pc_ucred->cr_uid = euid;
675 p->p_flag |= P_SUGID;
676 return (0);
677 }
678
679 /* ARGSUSED */
680 int
sys_setgid(p,v,retval)681 sys_setgid(p, v, retval)
682 struct proc *p;
683 void *v;
684 register_t *retval;
685 {
686 struct sys_setgid_args /* {
687 syscallarg(gid_t) gid;
688 } */ *uap = v;
689 struct pcred *pc = p->p_cred;
690 gid_t gid;
691 int error;
692
693 gid = SCARG(uap, gid);
694
695 if (pc->pc_ucred->cr_gid == gid &&
696 pc->p_rgid == gid &&
697 pc->p_svgid == gid)
698 return (0);
699
700 if (gid != pc->p_rgid &&
701 gid != pc->p_svgid &&
702 gid != pc->pc_ucred->cr_gid &&
703 (error = suser(p, 0)))
704 return (error);
705
706 if (gid == pc->pc_ucred->cr_gid ||
707 suser(p, 0) == 0) {
708 pc->p_rgid = gid;
709 pc->p_svgid = gid;
710 }
711
712 /*
713 * Copy credentials so other references do not see our changes.
714 */
715 pc->pc_ucred = crcopy(pc->pc_ucred);
716 pc->pc_ucred->cr_gid = gid;
717 p->p_flag |= P_SUGID;
718 return (0);
719 }
720
721 /* ARGSUSED */
722 int
sys_setegid(p,v,retval)723 sys_setegid(p, v, retval)
724 struct proc *p;
725 void *v;
726 register_t *retval;
727 {
728 struct sys_setegid_args /* {
729 syscallarg(gid_t) egid;
730 } */ *uap = v;
731 struct pcred *pc = p->p_cred;
732 gid_t egid;
733 int error;
734
735 egid = SCARG(uap, egid);
736
737 if (pc->pc_ucred->cr_gid == egid)
738 return (0);
739
740 if (egid != pc->p_rgid && egid != pc->p_svgid &&
741 (error = suser(p, 0)))
742 return (error);
743
744 /*
745 * Copy credentials so other references do not see our changes.
746 */
747 pc->pc_ucred = crcopy(pc->pc_ucred);
748 pc->pc_ucred->cr_gid = egid;
749 p->p_flag |= P_SUGID;
750 return (0);
751 }
752
753 /* ARGSUSED */
754 int
sys_setgroups(p,v,retval)755 sys_setgroups(p, v, retval)
756 struct proc *p;
757 void *v;
758 register_t *retval;
759 {
760 struct sys_setgroups_args /* {
761 syscallarg(int) gidsetsize;
762 syscallarg(const gid_t *) gidset;
763 } */ *uap = v;
764 struct pcred *pc = p->p_cred;
765 u_int ngrp;
766 int error;
767
768 if ((error = suser(p, 0)) != 0)
769 return (error);
770 ngrp = SCARG(uap, gidsetsize);
771 if (ngrp > NGROUPS)
772 return (EINVAL);
773 pc->pc_ucred = crcopy(pc->pc_ucred);
774 error = copyin((caddr_t)SCARG(uap, gidset),
775 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t));
776 if (error)
777 return (error);
778 pc->pc_ucred->cr_ngroups = ngrp;
779 p->p_flag |= P_SUGID;
780 return (0);
781 }
782
783 /*
784 * Check if gid is a member of the group set.
785 */
786 int
groupmember(gid,cred)787 groupmember(gid, cred)
788 gid_t gid;
789 struct ucred *cred;
790 {
791 gid_t *gp;
792 gid_t *egp;
793
794 egp = &(cred->cr_groups[cred->cr_ngroups]);
795 for (gp = cred->cr_groups; gp < egp; gp++)
796 if (*gp == gid)
797 return (1);
798 return (0);
799 }
800
801 /*
802 * Test whether this process has special user powers.
803 * Returns 0 or error.
804 */
805 int
suser(struct proc * p,u_int flags)806 suser(struct proc *p, u_int flags)
807 {
808 struct ucred *cred = p->p_ucred;
809
810 if (cred->cr_uid == 0) {
811 if (!(flags & SUSER_NOACCT))
812 p->p_acflag |= ASU;
813 return (0);
814 }
815 return (EPERM);
816 }
817
818 /*
819 * replacement for old suser, for callers who don't have a process
820 */
821 int
suser_ucred(struct ucred * cred)822 suser_ucred(struct ucred *cred)
823 {
824 if (cred->cr_uid == 0)
825 return (0);
826 return (EPERM);
827 }
828
829 /*
830 * Allocate a zeroed cred structure.
831 */
832 struct ucred *
crget()833 crget()
834 {
835 struct ucred *cr;
836
837 cr = pool_get(&ucred_pool, PR_WAITOK);
838 bzero((caddr_t)cr, sizeof(*cr));
839 cr->cr_ref = 1;
840 return (cr);
841 }
842
843 /*
844 * Free a cred structure.
845 * Throws away space when ref count gets to 0.
846 */
847 void
crfree(cr)848 crfree(cr)
849 struct ucred *cr;
850 {
851
852 if (--cr->cr_ref == 0)
853 pool_put(&ucred_pool, cr);
854 }
855
856 /*
857 * Copy cred structure to a new one and free the old one.
858 */
859 struct ucred *
crcopy(cr)860 crcopy(cr)
861 struct ucred *cr;
862 {
863 struct ucred *newcr;
864
865 if (cr->cr_ref == 1)
866 return (cr);
867 newcr = crget();
868 *newcr = *cr;
869 crfree(cr);
870 newcr->cr_ref = 1;
871 return (newcr);
872 }
873
874 /*
875 * Dup cred struct to a new held one.
876 */
877 struct ucred *
crdup(cr)878 crdup(cr)
879 struct ucred *cr;
880 {
881 struct ucred *newcr;
882
883 newcr = crget();
884 *newcr = *cr;
885 newcr->cr_ref = 1;
886 return (newcr);
887 }
888
889 /*
890 * Get login name, if available.
891 */
892 /* ARGSUSED */
893 int
sys_getlogin(p,v,retval)894 sys_getlogin(p, v, retval)
895 struct proc *p;
896 void *v;
897 register_t *retval;
898 {
899 struct sys_getlogin_args /* {
900 syscallarg(char *) namebuf;
901 syscallarg(u_int) namelen;
902 } */ *uap = v;
903
904 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
905 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
906 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
907 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
908 }
909
910 /*
911 * Set login name.
912 */
913 /* ARGSUSED */
914 int
sys_setlogin(p,v,retval)915 sys_setlogin(p, v, retval)
916 struct proc *p;
917 void *v;
918 register_t *retval;
919 {
920 struct sys_setlogin_args /* {
921 syscallarg(const char *) namebuf;
922 } */ *uap = v;
923 int error;
924
925 if ((error = suser(p, 0)) != 0)
926 return (error);
927 error = copyinstr((caddr_t) SCARG(uap, namebuf),
928 (caddr_t) p->p_pgrp->pg_session->s_login,
929 sizeof (p->p_pgrp->pg_session->s_login), (size_t *)0);
930 if (error == ENAMETOOLONG)
931 error = EINVAL;
932 return (error);
933 }
934
935 /*
936 * Check if a process is allowed to raise its privileges.
937 */
938 int
proc_cansugid(struct proc * p)939 proc_cansugid(struct proc *p)
940 {
941 /* ptrace(2)d processes shouldn't. */
942 if ((p->p_flag & P_TRACED) != 0)
943 return (0);
944
945 /* proceses with shared filedescriptors shouldn't. */
946 if (p->p_fd->fd_refcnt > 1)
947 return (0);
948
949 /* Allow. */
950 return (1);
951 }
952