|
|
1.1.1.2 root 1: /*
2: * linux/kernel/sys.c
3: *
4: * (C) 1991 Linus Torvalds
5: */
6:
1.1 root 7: #include <errno.h>
8:
9: #include <linux/sched.h>
10: #include <linux/tty.h>
11: #include <linux/kernel.h>
1.1.1.3 ! root 12: #include <linux/config.h>
1.1 root 13: #include <asm/segment.h>
14: #include <sys/times.h>
15: #include <sys/utsname.h>
1.1.1.3 ! root 16: #include <sys/param.h>
! 17: #include <sys/resource.h>
! 18: #include <string.h>
! 19:
! 20: /*
! 21: * The timezone where the local system is located. Used as a default by some
! 22: * programs who obtain this value by using gettimeofday.
! 23: */
! 24: struct timezone sys_tz = { 0, 0};
! 25:
! 26: extern int session_of_pgrp(int pgrp);
1.1 root 27:
28: int sys_ftime()
29: {
30: return -ENOSYS;
31: }
32:
33: int sys_break()
34: {
35: return -ENOSYS;
36: }
37:
38: int sys_ptrace()
39: {
40: return -ENOSYS;
41: }
42:
43: int sys_stty()
44: {
45: return -ENOSYS;
46: }
47:
48: int sys_gtty()
49: {
50: return -ENOSYS;
51: }
52:
53: int sys_rename()
54: {
55: return -ENOSYS;
56: }
57:
58: int sys_prof()
59: {
60: return -ENOSYS;
61: }
62:
1.1.1.3 ! root 63: /*
! 64: * This is done BSD-style, with no consideration of the saved gid, except
! 65: * that if you set the effective gid, it sets the saved gid too. This
! 66: * makes it possible for a setgid program to completely drop its privileges,
! 67: * which is often a useful assertion to make when you are doing a security
! 68: * audit over a program.
! 69: *
! 70: * The general idea is that a program which uses just setregid() will be
! 71: * 100% compatible with BSD. A program which uses just setgid() will be
! 72: * 100% compatible with POSIX w/ Saved ID's.
! 73: */
1.1.1.2 root 74: int sys_setregid(int rgid, int egid)
1.1 root 75: {
1.1.1.2 root 76: if (rgid>0) {
77: if ((current->gid == rgid) ||
78: suser())
79: current->gid = rgid;
80: else
81: return(-EPERM);
82: }
83: if (egid>0) {
84: if ((current->gid == egid) ||
85: (current->egid == egid) ||
1.1.1.3 ! root 86: suser()) {
1.1.1.2 root 87: current->egid = egid;
1.1.1.3 ! root 88: current->sgid = egid;
! 89: } else
1.1.1.2 root 90: return(-EPERM);
91: }
1.1 root 92: return 0;
93: }
94:
1.1.1.3 ! root 95: /*
! 96: * setgid() is implemeneted like SysV w/ SAVED_IDS
! 97: */
1.1.1.2 root 98: int sys_setgid(int gid)
99: {
1.1.1.3 ! root 100: if (suser())
! 101: current->gid = current->egid = current->sgid = gid;
! 102: else if ((gid == current->gid) || (gid == current->sgid))
! 103: current->egid = gid;
! 104: else
! 105: return -EPERM;
! 106: return 0;
1.1.1.2 root 107: }
108:
1.1 root 109: int sys_acct()
110: {
111: return -ENOSYS;
112: }
113:
114: int sys_phys()
115: {
116: return -ENOSYS;
117: }
118:
119: int sys_lock()
120: {
121: return -ENOSYS;
122: }
123:
124: int sys_mpx()
125: {
126: return -ENOSYS;
127: }
128:
129: int sys_ulimit()
130: {
131: return -ENOSYS;
132: }
133:
134: int sys_time(long * tloc)
135: {
136: int i;
137:
138: i = CURRENT_TIME;
139: if (tloc) {
140: verify_area(tloc,4);
141: put_fs_long(i,(unsigned long *)tloc);
142: }
143: return i;
144: }
145:
1.1.1.2 root 146: /*
147: * Unprivileged users may change the real user id to the effective uid
1.1.1.3 ! root 148: * or vice versa. (BSD-style)
! 149: *
! 150: * When you set the effective uid, it sets the saved uid too. This
! 151: * makes it possible for a setuid program to completely drop its privileges,
! 152: * which is often a useful assertion to make when you are doing a security
! 153: * audit over a program.
! 154: *
! 155: * The general idea is that a program which uses just setreuid() will be
! 156: * 100% compatible with BSD. A program which uses just setuid() will be
! 157: * 100% compatible with POSIX w/ Saved ID's.
1.1.1.2 root 158: */
159: int sys_setreuid(int ruid, int euid)
1.1 root 160: {
1.1.1.2 root 161: int old_ruid = current->uid;
162:
163: if (ruid>0) {
164: if ((current->euid==ruid) ||
165: (old_ruid == ruid) ||
166: suser())
167: current->uid = ruid;
1.1 root 168: else
1.1.1.2 root 169: return(-EPERM);
170: }
171: if (euid>0) {
172: if ((old_ruid == euid) ||
173: (current->euid == euid) ||
1.1.1.3 ! root 174: suser()) {
1.1.1.2 root 175: current->euid = euid;
1.1.1.3 ! root 176: current->suid = euid;
! 177: } else {
1.1.1.2 root 178: current->uid = old_ruid;
179: return(-EPERM);
180: }
181: }
1.1 root 182: return 0;
183: }
184:
1.1.1.3 ! root 185: /*
! 186: * setuid() is implemeneted like SysV w/ SAVED_IDS
! 187: *
! 188: * Note that SAVED_ID's is deficient in that a setuid root program
! 189: * like sendmail, for example, cannot set its uid to be a normal
! 190: * user and then switch back, because if you're root, setuid() sets
! 191: * the saved uid too. If you don't like this, blame the bright people
! 192: * in the POSIX commmittee and/or USG. Note that the BSD-style setreuid()
! 193: * will allow a root program to temporarily drop privileges and be able to
! 194: * regain them by swapping the real and effective uid.
! 195: */
1.1.1.2 root 196: int sys_setuid(int uid)
197: {
1.1.1.3 ! root 198: if (suser())
! 199: current->uid = current->euid = current->suid = uid;
! 200: else if ((uid == current->uid) || (uid == current->suid))
! 201: current->euid = uid;
! 202: else
! 203: return -EPERM;
! 204: return(0);
1.1.1.2 root 205: }
206:
1.1 root 207: int sys_stime(long * tptr)
208: {
1.1.1.2 root 209: if (!suser())
210: return -EPERM;
1.1 root 211: startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
1.1.1.3 ! root 212: jiffies_offset = 0;
1.1 root 213: return 0;
214: }
215:
216: int sys_times(struct tms * tbuf)
217: {
1.1.1.2 root 218: if (tbuf) {
219: verify_area(tbuf,sizeof *tbuf);
220: put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
221: put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
222: put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
223: put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
224: }
1.1 root 225: return jiffies;
226: }
227:
228: int sys_brk(unsigned long end_data_seg)
229: {
230: if (end_data_seg >= current->end_code &&
231: end_data_seg < current->start_stack - 16384)
232: current->brk = end_data_seg;
233: return current->brk;
234: }
235:
236: /*
237: * This needs some heave checking ...
238: * I just haven't get the stomach for it. I also don't fully
239: * understand sessions/pgrp etc. Let somebody who does explain it.
1.1.1.3 ! root 240: *
! 241: * OK, I think I have the protection semantics right.... this is really
! 242: * only important on a multi-user system anyway, to make sure one user
! 243: * can't send a signal to a process owned by another. -TYT, 12/12/91
1.1 root 244: */
245: int sys_setpgid(int pid, int pgid)
246: {
1.1.1.3 ! root 247: int i;
1.1 root 248:
249: if (!pid)
250: pid = current->pid;
251: if (!pgid)
1.1.1.2 root 252: pgid = current->pid;
1.1.1.3 ! root 253: if (pgid < 0)
! 254: return -EINVAL;
1.1 root 255: for (i=0 ; i<NR_TASKS ; i++)
1.1.1.3 ! root 256: if (task[i] && (task[i]->pid == pid) &&
! 257: ((task[i]->p_pptr == current) ||
! 258: (task[i] == current))) {
1.1 root 259: if (task[i]->leader)
260: return -EPERM;
1.1.1.3 ! root 261: if ((task[i]->session != current->session) ||
! 262: ((pgid != pid) &&
! 263: (session_of_pgrp(pgid) != current->session)))
1.1 root 264: return -EPERM;
265: task[i]->pgrp = pgid;
266: return 0;
267: }
268: return -ESRCH;
269: }
270:
271: int sys_getpgrp(void)
272: {
273: return current->pgrp;
274: }
275:
276: int sys_setsid(void)
277: {
1.1.1.2 root 278: if (current->leader && !suser())
1.1 root 279: return -EPERM;
280: current->leader = 1;
281: current->session = current->pgrp = current->pid;
282: current->tty = -1;
283: return current->pgrp;
284: }
285:
1.1.1.3 ! root 286: /*
! 287: * Supplementary group ID's
! 288: */
! 289: int sys_getgroups(int gidsetsize, gid_t *grouplist)
! 290: {
! 291: int i;
! 292:
! 293: if (gidsetsize)
! 294: verify_area(grouplist, sizeof(gid_t) * gidsetsize);
! 295:
! 296: for (i = 0; (i < NGROUPS) && (current->groups[i] != NOGROUP);
! 297: i++, grouplist++) {
! 298: if (gidsetsize) {
! 299: if (i >= gidsetsize)
! 300: return -EINVAL;
! 301: put_fs_word(current->groups[i], (short *) grouplist);
! 302: }
! 303: }
! 304: return(i);
! 305: }
! 306:
! 307: int sys_setgroups(int gidsetsize, gid_t *grouplist)
! 308: {
! 309: int i;
! 310:
! 311: if (!suser())
! 312: return -EPERM;
! 313: if (gidsetsize > NGROUPS)
! 314: return -EINVAL;
! 315: for (i = 0; i < gidsetsize; i++, grouplist++) {
! 316: current->groups[i] = get_fs_word((unsigned short *) grouplist);
! 317: }
! 318: if (i < NGROUPS)
! 319: current->groups[i] = NOGROUP;
! 320: return 0;
! 321: }
! 322:
! 323: int in_group_p(gid_t grp)
! 324: {
! 325: int i;
! 326:
! 327: if (grp == current->egid)
! 328: return 1;
! 329:
! 330: for (i = 0; i < NGROUPS; i++) {
! 331: if (current->groups[i] == NOGROUP)
! 332: break;
! 333: if (current->groups[i] == grp)
! 334: return 1;
! 335: }
! 336: return 0;
! 337: }
! 338:
! 339: static struct utsname thisname = {
! 340: UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, UTS_MACHINE
! 341: };
! 342:
1.1 root 343: int sys_uname(struct utsname * name)
344: {
345: int i;
346:
1.1.1.2 root 347: if (!name) return -ERROR;
1.1 root 348: verify_area(name,sizeof *name);
349: for(i=0;i<sizeof *name;i++)
350: put_fs_byte(((char *) &thisname)[i],i+(char *) name);
1.1.1.2 root 351: return 0;
1.1 root 352: }
353:
1.1.1.3 ! root 354: /*
! 355: * Only sethostname; gethostname can be implemented by calling uname()
! 356: */
! 357: int sys_sethostname(char *name, int len)
! 358: {
! 359: int i;
! 360:
! 361: if (!suser())
! 362: return -EPERM;
! 363: if (len > MAXHOSTNAMELEN)
! 364: return -EINVAL;
! 365: for (i=0; i < len; i++) {
! 366: if ((thisname.nodename[i] = get_fs_byte(name+i)) == 0)
! 367: break;
! 368: }
! 369: if (thisname.nodename[i]) {
! 370: thisname.nodename[i>MAXHOSTNAMELEN ? MAXHOSTNAMELEN : i] = 0;
! 371: }
! 372: return 0;
! 373: }
! 374:
! 375: int sys_getrlimit(int resource, struct rlimit *rlim)
! 376: {
! 377: if (resource >= RLIM_NLIMITS)
! 378: return -EINVAL;
! 379: verify_area(rlim,sizeof *rlim);
! 380: put_fs_long(current->rlim[resource].rlim_cur,
! 381: (unsigned long *) rlim);
! 382: put_fs_long(current->rlim[resource].rlim_max,
! 383: ((unsigned long *) rlim)+1);
! 384: return 0;
! 385: }
! 386:
! 387: int sys_setrlimit(int resource, struct rlimit *rlim)
! 388: {
! 389: struct rlimit new, *old;
! 390:
! 391: if (resource >= RLIM_NLIMITS)
! 392: return -EINVAL;
! 393: old = current->rlim + resource;
! 394: new.rlim_cur = get_fs_long((unsigned long *) rlim);
! 395: new.rlim_max = get_fs_long(((unsigned long *) rlim)+1);
! 396: if (((new.rlim_cur > old->rlim_max) ||
! 397: (new.rlim_max > old->rlim_max)) &&
! 398: !suser())
! 399: return -EPERM;
! 400: *old = new;
! 401: return 0;
! 402: }
! 403:
! 404: /*
! 405: * It would make sense to put struct rusuage in the task_struct,
! 406: * except that would make the task_struct be *really big*. After
! 407: * task_struct gets moved into malloc'ed memory, it would
! 408: * make sense to do this. It will make moving the rest of the information
! 409: * a lot simpler! (Which we're not doing right now because we're not
! 410: * measuring them yet).
! 411: */
! 412: int sys_getrusage(int who, struct rusage *ru)
! 413: {
! 414: struct rusage r;
! 415: unsigned long *lp, *lpend, *dest;
! 416:
! 417: if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
! 418: return -EINVAL;
! 419: verify_area(ru, sizeof *ru);
! 420: memset((char *) &r, 0, sizeof(r));
! 421: if (who == RUSAGE_SELF) {
! 422: r.ru_utime.tv_sec = CT_TO_SECS(current->utime);
! 423: r.ru_utime.tv_usec = CT_TO_USECS(current->utime);
! 424: r.ru_stime.tv_sec = CT_TO_SECS(current->stime);
! 425: r.ru_stime.tv_usec = CT_TO_USECS(current->stime);
! 426: } else {
! 427: r.ru_utime.tv_sec = CT_TO_SECS(current->cutime);
! 428: r.ru_utime.tv_usec = CT_TO_USECS(current->cutime);
! 429: r.ru_stime.tv_sec = CT_TO_SECS(current->cstime);
! 430: r.ru_stime.tv_usec = CT_TO_USECS(current->cstime);
! 431: }
! 432: lp = (unsigned long *) &r;
! 433: lpend = (unsigned long *) (&r+1);
! 434: dest = (unsigned long *) ru;
! 435: for (; lp < lpend; lp++, dest++)
! 436: put_fs_long(*lp, dest);
! 437: return(0);
! 438: }
! 439:
! 440: int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
! 441: {
! 442: if (tv) {
! 443: verify_area(tv, sizeof *tv);
! 444: put_fs_long(startup_time + CT_TO_SECS(jiffies+jiffies_offset),
! 445: (unsigned long *) tv);
! 446: put_fs_long(CT_TO_USECS(jiffies+jiffies_offset),
! 447: ((unsigned long *) tv)+1);
! 448: }
! 449: if (tz) {
! 450: verify_area(tz, sizeof *tz);
! 451: put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
! 452: put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
! 453: }
! 454: return 0;
! 455: }
! 456:
! 457: /*
! 458: * The first time we set the timezone, we will warp the clock so that
! 459: * it is ticking GMT time instead of local time. Presumably,
! 460: * if someone is setting the timezone then we are running in an
! 461: * environment where the programs understand about timezones.
! 462: * This should be done at boot time in the /etc/rc script, as
! 463: * soon as possible, so that the clock can be set right. Otherwise,
! 464: * various programs will get confused when the clock gets warped.
! 465: */
! 466: int sys_settimeofday(struct timeval *tv, struct timezone *tz)
! 467: {
! 468: static int firsttime = 1;
! 469: void adjust_clock();
! 470:
! 471: if (!suser())
! 472: return -EPERM;
! 473: if (tz) {
! 474: sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz);
! 475: sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1);
! 476: if (firsttime) {
! 477: firsttime = 0;
! 478: if (!tv)
! 479: adjust_clock();
! 480: }
! 481: }
! 482: if (tv) {
! 483: int sec, usec;
! 484:
! 485: sec = get_fs_long((unsigned long *)tv);
! 486: usec = get_fs_long(((unsigned long *)tv)+1);
! 487:
! 488: startup_time = sec - jiffies/HZ;
! 489: jiffies_offset = usec * HZ / 1000000 - jiffies%HZ;
! 490: }
! 491: return 0;
! 492: }
! 493:
! 494: /*
! 495: * Adjust the time obtained from the CMOS to be GMT time instead of
! 496: * local time.
! 497: *
! 498: * This is ugly, but preferable to the alternatives. Otherwise we
! 499: * would either need to write a program to do it in /etc/rc (and risk
! 500: * confusion if the program gets run more than once; it would also be
! 501: * hard to make the program warp the clock precisely n hours) or
! 502: * compile in the timezone information into the kernel. Bad, bad....
! 503: *
! 504: * XXX Currently does not adjust for daylight savings time. May not
! 505: * need to do anything, depending on how smart (dumb?) the BIOS
! 506: * is. Blast it all.... the best thing to do not depend on the CMOS
! 507: * clock at all, but get the time via NTP or timed if you're on a
! 508: * network.... - TYT, 1/1/92
! 509: */
! 510: void adjust_clock()
! 511: {
! 512: startup_time += sys_tz.tz_minuteswest*60;
! 513: }
! 514:
1.1 root 515: int sys_umask(int mask)
516: {
517: int old = current->umask;
518:
519: current->umask = mask & 0777;
520: return (old);
521: }
1.1.1.3 ! root 522:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.