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