patch-2.6.6-vs1.9.0
[linux-2.6.git] / kernel / sys.c
index 4d414d9..9523213 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mman.h>
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
+#include <linux/kmod.h>
 #include <linux/reboot.h>
 #include <linux/prctl.h>
 #include <linux/init.h>
@@ -339,7 +340,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
                        if (!who)
                                user = current->user;
                        else
-                               user = find_user(who);
+                               user = find_user(vx_current_xid(), who);
 
                        if (!user)
                                goto out_unlock;
@@ -398,7 +399,7 @@ asmlinkage long sys_getpriority(int which, int who)
                        if (!who)
                                user = current->user;
                        else
-                               user = find_user(who);
+                               user = find_user(vx_current_xid(), who);
 
                        if (!user)
                                goto out_unlock;
@@ -418,6 +419,72 @@ out_unlock:
        return retval;
 }
 
+/*
+ *      vshelper path is set via /proc/sys
+ *      invoked by vserver sys_reboot(), with
+ *      the following arguments
+ *
+ *      argv [0] = vshelper_path;
+ *      argv [1] = action: "restart", "halt", "poweroff", ...
+ *      argv [2] = context identifier
+ *      argv [3] = additional argument (restart2)
+ *
+ *      envp [*] = type-specific parameters
+ */
+char vshelper_path[255] = "/sbin/vshelper";
+
+long vs_reboot(unsigned int cmd, void * arg)
+{
+       char id_buf[8], cmd_buf[32];
+       char uid_buf[32], pid_buf[32];
+       char buffer[256];
+
+       char *argv[] = {vshelper_path, NULL, id_buf, NULL, 0};
+       char *envp[] = {"HOME=/", "TERM=linux",
+                       "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+                       uid_buf, pid_buf, cmd_buf, 0};
+
+       snprintf(id_buf, sizeof(id_buf)-1, "%d", vx_current_xid());
+
+       snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd);
+       snprintf(uid_buf, sizeof(uid_buf)-1, "VS_UID=%d", current->uid);
+       snprintf(pid_buf, sizeof(pid_buf)-1, "VS_PID=%d", current->pid);
+
+       switch (cmd) {
+       case LINUX_REBOOT_CMD_RESTART:
+               argv[1] = "restart";
+               break;  
+
+       case LINUX_REBOOT_CMD_HALT:
+               argv[1] = "halt";
+               break;  
+
+       case LINUX_REBOOT_CMD_POWER_OFF:
+               argv[1] = "poweroff";
+               break;  
+
+       case LINUX_REBOOT_CMD_SW_SUSPEND:
+               argv[1] = "swsusp";
+               break;  
+
+       case LINUX_REBOOT_CMD_RESTART2:
+               if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0)
+                       return -EFAULT;
+               argv[3] = buffer;
+       default:
+               argv[1] = "restart2";
+               break;  
+       }
+
+       /* maybe we should wait ? */
+       if (call_usermodehelper(*argv, argv, envp, 0)) {
+               printk( KERN_WARNING
+                       "vs_reboot(): failed to exec (%s %s %s %s)\n",
+                       vshelper_path, argv[1], argv[2], argv[3]);
+               return -EPERM;
+       }
+       return 0;
+}
 
 /*
  * Reboot system call: for obvious reasons only root may call it,
@@ -443,6 +510,9 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
                        magic2 != LINUX_REBOOT_MAGIC2C))
                return -EINVAL;
 
+       if (!vx_check(0, VX_ADMIN|VX_WATCH))
+               return vs_reboot(cmd, arg);
+
        lock_kernel();
        switch (cmd) {
        case LINUX_REBOOT_CMD_RESTART:
@@ -637,7 +707,7 @@ static int set_user(uid_t new_ruid, int dumpclear)
 {
        struct user_struct *new_user;
 
-       new_user = alloc_uid(new_ruid);
+       new_user = alloc_uid(vx_current_xid(), new_ruid);
        if (!new_user)
                return -EAGAIN;
 
@@ -1376,7 +1446,7 @@ asmlinkage long sys_newuname(struct new_utsname __user * name)
        int errno = 0;
 
        down_read(&uts_sem);
-       if (copy_to_user(name,&system_utsname,sizeof *name))
+       if (copy_to_user(name, vx_new_utsname(), sizeof *name))
                errno = -EFAULT;
        up_read(&uts_sem);
        return errno;
@@ -1387,15 +1457,17 @@ asmlinkage long sys_sethostname(char __user *name, int len)
        int errno;
        char tmp[__NEW_UTS_LEN];
 
-       if (!capable(CAP_SYS_ADMIN))
+       if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SET_UTSNAME))
                return -EPERM;
        if (len < 0 || len > __NEW_UTS_LEN)
                return -EINVAL;
        down_write(&uts_sem);
        errno = -EFAULT;
        if (!copy_from_user(tmp, name, len)) {
-               memcpy(system_utsname.nodename, tmp, len);
-               system_utsname.nodename[len] = 0;
+               char *ptr = vx_new_uts(nodename);
+
+               memcpy(ptr, tmp, len);
+               ptr[len] = 0;
                errno = 0;
        }
        up_write(&uts_sem);
@@ -1405,15 +1477,17 @@ asmlinkage long sys_sethostname(char __user *name, int len)
 asmlinkage long sys_gethostname(char __user *name, int len)
 {
        int i, errno;
+       char *ptr;
 
        if (len < 0)
                return -EINVAL;
        down_read(&uts_sem);
-       i = 1 + strlen(system_utsname.nodename);
+       ptr = vx_new_uts(nodename);
+       i = 1 + strlen(ptr);
        if (i > len)
                i = len;
        errno = 0;
-       if (copy_to_user(name, system_utsname.nodename, i))
+       if (copy_to_user(name, ptr, i))
                errno = -EFAULT;
        up_read(&uts_sem);
        return errno;
@@ -1428,7 +1502,7 @@ asmlinkage long sys_setdomainname(char __user *name, int len)
        int errno;
        char tmp[__NEW_UTS_LEN];
 
-       if (!capable(CAP_SYS_ADMIN))
+       if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SET_UTSNAME))
                return -EPERM;
        if (len < 0 || len > __NEW_UTS_LEN)
                return -EINVAL;
@@ -1436,8 +1510,10 @@ asmlinkage long sys_setdomainname(char __user *name, int len)
        down_write(&uts_sem);
        errno = -EFAULT;
        if (!copy_from_user(tmp, name, len)) {
-               memcpy(system_utsname.domainname, tmp, len);
-               system_utsname.domainname[len] = 0;
+               char *ptr = vx_new_uts(domainname);
+
+               memcpy(ptr, tmp, len);
+               ptr[len] = 0;
                errno = 0;
        }
        up_write(&uts_sem);
@@ -1489,7 +1565,7 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
        old_rlim = current->rlim + resource;
        if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
             (new_rlim.rlim_max > old_rlim->rlim_max)) &&
-           !capable(CAP_SYS_RESOURCE))
+           !capable(CAP_SYS_RESOURCE) && vx_ccaps(VXC_SET_RLIMIT))
                return -EPERM;
        if (resource == RLIMIT_NOFILE) {
                if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)