|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
28: * The Regents of the University of California. All rights reserved.
29: * (c) UNIX System Laboratories, Inc.
30: * All or some portions of this file are derived from material licensed
31: * to the University of California by American Telephone and Telegraph
32: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33: * the permission of UNIX System Laboratories, Inc.
34: *
35: * Redistribution and use in source and binary forms, with or without
36: * modification, are permitted provided that the following conditions
37: * are met:
38: * 1. Redistributions of source code must retain the above copyright
39: * notice, this list of conditions and the following disclaimer.
40: * 2. Redistributions in binary form must reproduce the above copyright
41: * notice, this list of conditions and the following disclaimer in the
42: * documentation and/or other materials provided with the distribution.
43: * 3. All advertising materials mentioning features or use of this software
44: * must display the following acknowledgement:
45: * This product includes software developed by the University of
46: * California, Berkeley and its contributors.
47: * 4. Neither the name of the University nor the names of its contributors
48: * may be used to endorse or promote products derived from this software
49: * without specific prior written permission.
50: *
51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61: * SUCH DAMAGE.
62: *
63: * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
64: */
65:
66: /*
67: * System calls related to processes and protection
68: */
69:
70: #include <sys/param.h>
71: #include <sys/acct.h>
72: #include <sys/systm.h>
73: #include <sys/ucred.h>
74: #include <sys/proc.h>
75: #include <sys/timeb.h>
76: #include <sys/times.h>
77: #include <sys/malloc.h>
78:
79: #include <sys/mount.h>
80:
81: /*
82: * setprivexec: (dis)allow this process to hold
83: * task, thread, or execption ports of processes about to exec.
84: */
85: struct setprivexec_args {
86: int flag;
87: };
88: int
89: setprivexec(p, uap, retval)
90: struct proc *p;
91: register struct setprivexec_args *uap;
92: register_t *retval;
93: {
94: *retval = p->p_debugger;
95: p->p_debugger = (uap->flag != 0);
96: return(0);
97: }
98:
99: /* ARGSUSED */
100: getpid(p, uap, retval)
101: struct proc *p;
102: void *uap;
103: register_t *retval;
104: {
105:
106: *retval = p->p_pid;
107: #if COMPAT_43
108: retval[1] = p->p_pptr->p_pid;
109: #endif
110: return (0);
111: }
112:
113: /* ARGSUSED */
114: getppid(p, uap, retval)
115: struct proc *p;
116: void *uap;
117: register_t *retval;
118: {
119:
120: *retval = p->p_pptr->p_pid;
121: return (0);
122: }
123:
124: /* Get process group ID; note that POSIX getpgrp takes no parameter */
125: getpgrp(p, uap, retval)
126: struct proc *p;
127: void *uap;
128: register_t *retval;
129: {
130:
131: *retval = p->p_pgrp->pg_id;
132: return (0);
133: }
134:
135: /* ARGSUSED */
136: getuid(p, uap, retval)
137: struct proc *p;
138: void *uap;
139: register_t *retval;
140: {
141:
142: *retval = p->p_cred->p_ruid;
143: #if COMPAT_43
144: retval[1] = p->p_ucred->cr_uid;
145: #endif
146: return (0);
147: }
148:
149: /* ARGSUSED */
150: geteuid(p, uap, retval)
151: struct proc *p;
152: void *uap;
153: register_t *retval;
154: {
155:
156: *retval = p->p_ucred->cr_uid;
157: return (0);
158: }
159:
160: /* ARGSUSED */
161: getgid(p, uap, retval)
162: struct proc *p;
163: void *uap;
164: register_t *retval;
165: {
166:
167: *retval = p->p_cred->p_rgid;
168: #if COMPAT_43
169: retval[1] = p->p_ucred->cr_groups[0];
170: #endif
171: return (0);
172: }
173:
174: /*
175: * Get effective group ID. The "egid" is groups[0], and could be obtained
176: * via getgroups. This syscall exists because it is somewhat painful to do
177: * correctly in a library function.
178: */
179: /* ARGSUSED */
180: getegid(p, uap, retval)
181: struct proc *p;
182: void *uap;
183: register_t *retval;
184: {
185:
186: *retval = p->p_ucred->cr_groups[0];
187: return (0);
188: }
189:
190: struct getgroups_args {
191: u_int gidsetsize;
192: gid_t *gidset;
193: };
194: getgroups(p, uap, retval)
195: struct proc *p;
196: register struct getgroups_args *uap;
197: register_t *retval;
198: {
199: register struct pcred *pc = p->p_cred;
200: register u_int ngrp;
201: int error;
202:
203: if ((ngrp = uap->gidsetsize) == 0) {
204: *retval = pc->pc_ucred->cr_ngroups;
205: return (0);
206: }
207: if (ngrp < pc->pc_ucred->cr_ngroups)
208: return (EINVAL);
209: pcred_readlock(p);
210: ngrp = pc->pc_ucred->cr_ngroups;
211: if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
212: (caddr_t)uap->gidset, ngrp * sizeof(gid_t))) {
213: pcred_unlock(p);
214: return (error);
215: }
216: pcred_unlock(p);
217: *retval = ngrp;
218: return (0);
219: }
220:
221: /* ARGSUSED */
222: setsid(p, uap, retval)
223: register struct proc *p;
224: void *uap;
225: register_t *retval;
226: {
227:
228: if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
229: return (EPERM);
230: } else {
231: (void)enterpgrp(p, p->p_pid, 1);
232: *retval = p->p_pid;
233: return (0);
234: }
235: }
236:
237: /*
238: * set process group (setpgid/old setpgrp)
239: *
240: * caller does setpgid(targpid, targpgid)
241: *
242: * pid must be caller or child of caller (ESRCH)
243: * if a child
244: * pid must be in same session (EPERM)
245: * pid can't have done an exec (EACCES)
246: * if pgid != pid
247: * there must exist some pid in same session having pgid (EPERM)
248: * pid must not be session leader (EPERM)
249: */
250: struct setpgid_args {
251: int pid;
252: int pgid;
253: };
254: /* ARGSUSED */
255: setpgid(curp, uap, retval)
256: struct proc *curp;
257: register struct setpgid_args *uap;
258: register_t *retval;
259: {
260: register struct proc *targp; /* target process */
261: register struct pgrp *pgrp; /* target pgrp */
262:
263: if (uap->pid != 0 && uap->pid != curp->p_pid) {
264: if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
265: return (ESRCH);
266: if (targp->p_session != curp->p_session)
267: return (EPERM);
268: if (targp->p_flag & P_EXEC)
269: return (EACCES);
270: } else
271: targp = curp;
272: if (SESS_LEADER(targp))
273: return (EPERM);
274: if (uap->pgid == 0)
275: uap->pgid = targp->p_pid;
276: else if (uap->pgid != targp->p_pid)
277: if ((pgrp = pgfind(uap->pgid)) == 0 ||
278: pgrp->pg_session != curp->p_session)
279: return (EPERM);
280: return (enterpgrp(targp, uap->pgid, 0));
281: }
282:
283: struct setuid_args {
284: uid_t uid;
285: };
286: /* ARGSUSED */
287: setuid(p, uap, retval)
288: struct proc *p;
289: struct setuid_args *uap;
290: register_t *retval;
291: {
292: register struct pcred *pc = p->p_cred;
293: register uid_t uid;
294: int error;
295:
296: uid = uap->uid;
297: if (uid != pc->p_ruid &&
298: (error = suser(pc->pc_ucred, &p->p_acflag)))
299: return (error);
300: /*
301: * Everything's okay, do it.
302: * Transfer proc count to new user.
303: * Copy credentials so other references do not see our changes.
304: */
305: pcred_writelock(p);
306: (void)chgproccnt(pc->p_ruid, -1);
307: (void)chgproccnt(uid, 1);
308: pc->pc_ucred = crcopy(pc->pc_ucred);
309: pc->pc_ucred->cr_uid = uid;
310: pc->p_ruid = uid;
311: pc->p_svuid = uid;
312: pcred_unlock(p);
313: p->p_flag |= P_SUGID;
314: return (0);
315: }
316:
317: struct seteuid_args {
318: uid_t euid;
319: };
320: /* ARGSUSED */
321: seteuid(p, uap, retval)
322: struct proc *p;
323: struct seteuid_args *uap;
324: register_t *retval;
325: {
326: register struct pcred *pc = p->p_cred;
327: register uid_t euid;
328: int error;
329:
330: euid = uap->euid;
331: if (euid != pc->p_ruid && euid != pc->p_svuid &&
332: (error = suser(pc->pc_ucred, &p->p_acflag)))
333: return (error);
334: /*
335: * Everything's okay, do it. Copy credentials so other references do
336: * not see our changes.
337: */
338: pcred_writelock(p);
339: pc->pc_ucred = crcopy(pc->pc_ucred);
340: pc->pc_ucred->cr_uid = euid;
341: pcred_unlock(p);
342: p->p_flag |= P_SUGID;
343: return (0);
344: }
345:
346: struct setgid_args {
347: gid_t gid;
348: };
349: /* ARGSUSED */
350: setgid(p, uap, retval)
351: struct proc *p;
352: struct setgid_args *uap;
353: register_t *retval;
354: {
355: register struct pcred *pc = p->p_cred;
356: register gid_t gid;
357: int error;
358:
359: gid = uap->gid;
360: if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
361: return (error);
362: pcred_writelock(p);
363: pc->pc_ucred = crcopy(pc->pc_ucred);
364: pc->pc_ucred->cr_groups[0] = gid;
365: pc->p_rgid = gid;
366: pc->p_svgid = gid; /* ??? */
367: pcred_unlock(p);
368: p->p_flag |= P_SUGID;
369: return (0);
370: }
371:
372: struct setegid_args {
373: gid_t egid;
374: };
375: /* ARGSUSED */
376: setegid(p, uap, retval)
377: struct proc *p;
378: struct setegid_args *uap;
379: register_t *retval;
380: {
381: register struct pcred *pc = p->p_cred;
382: register gid_t egid;
383: int error;
384:
385: egid = uap->egid;
386: if (egid != pc->p_rgid && egid != pc->p_svgid &&
387: (error = suser(pc->pc_ucred, &p->p_acflag)))
388: return (error);
389: pcred_writelock(p);
390: pc->pc_ucred = crcopy(pc->pc_ucred);
391: pc->pc_ucred->cr_groups[0] = egid;
392: pcred_unlock(p);
393: p->p_flag |= P_SUGID;
394: return (0);
395: }
396:
397: struct setgroups_args{
398: u_int gidsetsize;
399: gid_t *gidset;
400: };
401:
402: /* ARGSUSED */
403: setgroups(p, uap, retval)
404: struct proc *p;
405: struct setgroups_args *uap;
406: register_t *retval;
407: {
408: register struct pcred *pc = p->p_cred;
409: struct ucred *new, *old;
410: register u_int ngrp;
411: int error;
412:
413: if (error = suser(pc->pc_ucred, &p->p_acflag))
414: return (error);
415: ngrp = uap->gidsetsize;
416: if (ngrp < 1 || ngrp > NGROUPS)
417: return (EINVAL);
418: new = crget();
419: error = copyin((caddr_t)uap->gidset,
420: (caddr_t)new->cr_groups, ngrp * sizeof(gid_t));
421: if (error) {
422: crfree(new);
423: return (error);
424: }
425: new->cr_ngroups = ngrp;
426: pcred_writelock(p);
427: old = pc->pc_ucred;
428: new->cr_uid = old->cr_uid;
429: pc->pc_ucred = new;
430: pcred_unlock(p);
431: p->p_flag |= P_SUGID;
432: if (old != NOCRED)
433: crfree(old);
434: return (0);
435: }
436:
437: #if COMPAT_43
438: struct osetreuid_args{
439: int ruid;
440: int euid;
441: };
442: /* ARGSUSED */
443: osetreuid(p, uap, retval)
444: register struct proc *p;
445: struct osetreuid_args *uap;
446: register_t *retval;
447: {
448: struct seteuid_args seuidargs;
449: struct setuid_args suidargs;
450:
451: /*
452: * There are five cases, and we attempt to emulate them in
453: * the following fashion:
454: * -1, -1: return 0. This is correct emulation.
455: * -1, N: call seteuid(N). This is correct emulation.
456: * N, -1: if we called setuid(N), our euid would be changed
457: * to N as well. the theory is that we don't want to
458: * revoke root access yet, so we call seteuid(N)
459: * instead. This is incorrect emulation, but often
460: * suffices enough for binary compatibility.
461: * N, N: call setuid(N). This is correct emulation.
462: * N, M: call setuid(N). This is close to correct emulation.
463: */
464: if (uap->ruid == (uid_t)-1) {
465: if (uap->euid == (uid_t)-1)
466: return (0); /* -1, -1 */
467: seuidargs.euid = uap->euid; /* -1, N */
468: return (seteuid(p, &seuidargs, retval));
469: }
470: if (uap->euid == (uid_t)-1) {
471: seuidargs.euid = uap->ruid; /* N, -1 */
472: return (seteuid(p, &seuidargs, retval));
473: }
474: suidargs.uid = uap->ruid; /* N, N and N, M */
475: return (setuid(p, &suidargs, retval));
476: }
477:
478: struct osetregid_args {
479: int rgid;
480: int egid;
481: };
482: /* ARGSUSED */
483: osetregid(p, uap, retval)
484: register struct proc *p;
485: struct osetregid_args *uap;
486: register_t *retval;
487: {
488: struct setegid_args segidargs;
489: struct setgid_args sgidargs;
490:
491: /*
492: * There are five cases, described above in osetreuid()
493: */
494: if (uap->rgid == (gid_t)-1) {
495: if (uap->egid == (gid_t)-1)
496: return (0); /* -1, -1 */
497: segidargs.egid = uap->egid; /* -1, N */
498: return (setegid(p, &segidargs, retval));
499: }
500: if (uap->egid == (gid_t)-1) {
501: segidargs.egid = uap->rgid; /* N, -1 */
502: return (setegid(p, &segidargs, retval));
503: }
504: sgidargs.gid = uap->rgid; /* N, N and N, M */
505: return (setgid(p, &sgidargs, retval));
506: }
507: #endif /* COMPAT_43 */
508:
509: /*
510: * Check if gid is a member of the group set.
511: */
512: groupmember(gid, cred)
513: gid_t gid;
514: register struct ucred *cred;
515: {
516: register gid_t *gp;
517: gid_t *egp;
518:
519: egp = &(cred->cr_groups[cred->cr_ngroups]);
520: for (gp = cred->cr_groups; gp < egp; gp++)
521: if (*gp == gid)
522: return (1);
523: return (0);
524: }
525:
526: /*
527: * Test whether the specified credentials imply "super-user"
528: * privilege; if so, and we have accounting info, set the flag
529: * indicating use of super-powers.
530: * Returns 0 or error.
531: */
532: suser(cred, acflag)
533: struct ucred *cred;
534: u_short *acflag;
535: {
536: #if DIAGNOSTIC
537: if (cred == NOCRED || cred == FSCRED)
538: panic("suser");
539: #endif
540: if (cred->cr_uid == 0) {
541: if (acflag)
542: *acflag |= ASU;
543: return (0);
544: }
545: return (EPERM);
546: }
547:
548: int
549: is_suser(void)
550: {
551: struct proc *p = current_thread()->task->proc;
552:
553: if (!p)
554: return (0);
555:
556: return (suser(p->p_ucred, &p->p_acflag) == 0);
557: }
558:
559: int
560: is_suser1(void)
561: {
562: struct proc *p = current_thread()->task->proc;
563:
564: if (!p)
565: return (0);
566:
567: return (suser(p->p_ucred, &p->p_acflag) == 0 ||
568: p->p_cred->p_ruid == 0 || p->p_cred->p_svuid == 0);
569: }
570:
571: /*
572: * Allocate a zeroed cred structure.
573: */
574: struct ucred *
575: crget()
576: {
577: register struct ucred *cr;
578:
579: MALLOC_ZONE(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
580: bzero((caddr_t)cr, sizeof(*cr));
581: cr->cr_ref = 1;
582: return (cr);
583: }
584:
585: /*
586: * Free a cred structure.
587: * Throws away space when ref count gets to 0.
588: */
589: void
590: crfree(cr)
591: struct ucred *cr;
592: {
593: #if DIAGNOSTIC
594: if (cr == NOCRED || cr == FSCRED)
595: panic("crfree");
596: #endif
597: if (--cr->cr_ref == 0)
598: FREE_ZONE((caddr_t)cr, sizeof *cr, M_CRED);
599: }
600:
601: /*
602: * Copy cred structure to a new one and free the old one.
603: */
604: struct ucred *
605: crcopy(cr)
606: struct ucred *cr;
607: {
608: struct ucred *newcr;
609:
610: #if DIAGNOSTIC
611: if (cr == NOCRED || cr == FSCRED)
612: panic("crcopy");
613: #endif
614: if (cr->cr_ref == 1)
615: return (cr);
616: newcr = crget();
617: *newcr = *cr;
618: crfree(cr);
619: newcr->cr_ref = 1;
620: return (newcr);
621: }
622:
623: /*
624: * Dup cred struct to a new held one.
625: */
626: struct ucred *
627: crdup(cr)
628: struct ucred *cr;
629: {
630: struct ucred *newcr;
631:
632: #if DIAGNOSTIC
633: if (cr == NOCRED || cr == FSCRED)
634: panic("crdup");
635: #endif
636: newcr = crget();
637: *newcr = *cr;
638: newcr->cr_ref = 1;
639: return (newcr);
640: }
641:
642: /*
643: * Get login name, if available.
644: */
645: struct getlogin_args {
646: char *namebuf;
647: u_int namelen;
648: };
649: /* ARGSUSED */
650: getlogin(p, uap, retval)
651: struct proc *p;
652: struct getlogin_args *uap;
653: register_t *retval;
654: {
655:
656: if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
657: uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
658: return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
659: (caddr_t)uap->namebuf, uap->namelen));
660: }
661:
662: /*
663: * Set login name.
664: */
665: struct setlogin_args {
666: char *namebuf;
667: };
668: /* ARGSUSED */
669: setlogin(p, uap, retval)
670: struct proc *p;
671: struct setlogin_args *uap;
672: register_t *retval;
673: {
674: int error;
675:
676: if (error = suser(p->p_ucred, &p->p_acflag))
677: return (error);
678: error = copyinstr((caddr_t) uap->namebuf,
679: (caddr_t) p->p_pgrp->pg_session->s_login,
680: sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
681: if (error == ENAMETOOLONG)
682: error = EINVAL;
683: return (error);
684: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.