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