s!/etc/slackware-release!/etc/slackware-version! (reported by bubulak)
[util-vserver.git] / util-vserver / src / vcontext.c
index ca447ac..ac8016f 100644 (file)
@@ -23,8 +23,7 @@
 #include "util.h"
 #include "lib/internal.h"
 #include "lib_internal/jail.h"
-
-#include "linuxcaps.h"
+#include "lib_internal/sys_personality.h"
 
 #include <vserver.h>
 #include <getopt.h>
@@ -33,6 +32,9 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <assert.h>
+#include <signal.h>
+
+#include <linux/personality.h>
 
 #define ENSC_WRAPPERS_PREFIX   "vcontext: "
 #define ENSC_WRAPPERS_UNISTD   1
@@ -47,7 +49,7 @@
 #define CMD_XID                        0x4000
 #define CMD_CREATE             0x4001
 #define CMD_MIGRATE            0x4003
-#define CMD_FAKEINIT           0x4002
+#define CMD_INITPID            0x4002
 #define CMD_DISCONNECT         0x4004
 #define CMD_UID                        0x4005
 #define CMD_CHROOT             0x4006
@@ -57,6 +59,9 @@
 #define CMD_MIGRATESELF                0x400a
 #define CMD_ENDSETUP           0x400b
 #define CMD_SILENTEXIST                0x400c
+#define CMD_NAMESPACE          0x400d
+#define CMD_PERSTYPE           0x400e
+#define CMD_PERSFLAG           0x400f
 
 
 struct option const
@@ -68,15 +73,21 @@ CMDLINE_OPTIONS[] = {
   { "create",     no_argument,       0, CMD_CREATE },
   { "migrate",    no_argument,       0, CMD_MIGRATE },
   { "migrate-self", no_argument,               0, CMD_MIGRATESELF },
-  { "fakeinit",     no_argument,               0, CMD_FAKEINIT },
+  { "initpid",      no_argument,               0, CMD_INITPID },
   { "endsetup",     no_argument,        0, CMD_ENDSETUP },
   { "disconnect",   no_argument,       0, CMD_DISCONNECT },
   { "silent",       no_argument,               0, CMD_SILENT },
   { "silentexist",  no_argument,               0, CMD_SILENTEXIST },
   { "uid",          required_argument,  0, CMD_UID },
   { "chroot",       no_argument,               0, CMD_CHROOT },
+  { "namespace",    no_argument,               0, CMD_NAMESPACE },
   { "syncsock",     required_argument,         0, CMD_SYNCSOCK },
   { "syncmsg",      required_argument,         0, CMD_SYNCMSG },
+  { "personality-type",  required_argument, 0, CMD_PERSTYPE },
+  { "personality-flags", required_argument, 0, CMD_PERSFLAG },
+#if 1  
+  { "fakeinit",     no_argument,               0, CMD_INITPID },       // compatibility
+#endif  
   { 0,0,0,0 },
 };
 
@@ -86,8 +97,11 @@ struct Arguments {
     bool               do_migrateself;
     bool               do_disconnect;
     bool               do_endsetup;
-    bool               is_fakeinit;
+    bool               is_initpid;
     bool               is_silentexist;
+    bool               set_namespace;
+    uint_least32_t     personality_flags;
+    uint_least32_t     personality_type;
     int                        verbosity;
     bool               do_chroot;
     uid_t              uid;
@@ -111,11 +125,16 @@ showHelp(int fd, char const *cmd, int res)
            "\n"
            "<opts> can be:\n"
            "    --chroot        ...  chroot into current directory\n"
+           "    --namespace     ...  execute namespace management operations\n"
            "    --uid <uid>     ...  change uid\n"
-           "    --fakeinit      ...  set current process as general process reaper\n"
+           "    --initpid       ...  set current process as general process reaper\n"
            "                         for ctx (possible for --migrate only)\n"
            "    --endsetup      ...  clear the setup flag; usefully for migrate only\n"
            "    --disconnect    ...  start program in background\n"
+           "    --personality-type <type>\n"
+           "                    ...  execute <program> in the given execution domain\n"
+           "    --personality-flags <flags>+\n"
+           "                    ...  set special flags for the given execution domain\n"
            "    --silent        ...  be silent\n"
            "    --silentexist   ...  be silent when context exists already; usefully\n"
            "                         for '--create' only\n"
@@ -158,7 +177,7 @@ tellContext(xid_t ctx, bool do_it)
   l = utilvserver_fmt_long(buf,ctx);
 
   WRITE_MSG(1, "New security context is ");
-  write(1, buf, l);
+  Vwrite   (1, buf, l);
   WRITE_MSG(1, "\n");
 }
 
@@ -181,21 +200,13 @@ connectExternalSync(char const *filename)
 static void
 setFlags(struct Arguments const *args, xid_t xid)
 {
-  struct vc_ctx_flags  flags = {
-    .mask     = 0,
-    .flagword = VC_VXF_STATE_INIT|VC_VXF_STATE_SETUP,
-  };
+  struct vc_ctx_flags  flags = { 0,0 };
 
-  if (args->is_fakeinit) {
-    flags.flagword &= ~VC_VXF_STATE_INIT;
-    flags.flagword |=  VC_VXF_INFO_INIT;
-    flags.mask     |=  VC_VXF_INFO_INIT|VC_VXF_STATE_INIT;
-  }
+  if (args->is_initpid)
+    flags.mask |=  VC_VXF_STATE_INIT;
 
-  if (args->do_endsetup) {
-    flags.flagword &= ~VC_VXF_STATE_SETUP;
-    flags.mask     |=  VC_VXF_STATE_SETUP;
-  }
+  if (args->do_endsetup)
+    flags.mask |=  VC_VXF_STATE_SETUP;
 
   if (flags.mask!=0) {
     DPRINTF("set_flags: mask=%08llx, flag=%08llx\n", flags.mask, flags.flagword);
@@ -215,7 +226,7 @@ doExternalSync(int fd, char const *msg)
 
   if (TEMP_FAILURE_RETRY(recv(fd, &c, 1, MSG_NOSIGNAL))!=0) {
     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "unexpected external synchronization event\n");
-    exit(255);
+    exit(wrapper_exit_code);
   }
 
   Eclose(fd);
@@ -231,7 +242,7 @@ doit(struct Arguments const *args, char *argv[])
     xid_t                      xid;
     int                                ext_sync_fd = connectExternalSync(args->sync_sock);
 
-    doSyncStage0(p, args->do_disconnect);
+    doSyncStage0(p, args->do_disconnect);  
     
     if (args->do_create) {
       xid = vc_ctx_create(args->xid);
@@ -251,8 +262,13 @@ doit(struct Arguments const *args, char *argv[])
     else
       xid = args->xid;
 
-    if (args->do_chroot)
+    if (args->do_chroot) {
       Echroot(".");
+      if (args->set_namespace) {
+       if (args->do_migrateself)  Evc_set_namespace();
+       else if (args->do_migrate) Evc_enter_namespace(xid);
+      }
+    }
 
     setFlags(args, xid);
 
@@ -263,10 +279,16 @@ doit(struct Arguments const *args, char *argv[])
       Esetuid(args->uid);
       if (getuid()!=args->uid) {
        WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "Something went wrong while changing the UID\n");
-       exit(255);
+       exit(wrapper_exit_code);
       }
     }
-    
+
+    if (args->personality_type!=VC_BAD_PERSONALITY &&
+       sys_personality(args->personality_type | args->personality_flags)==-1) {
+      perror(ENSC_WRAPPERS_PREFIX "personality()");
+      exit(wrapper_exit_code);
+    }  
+
     doExternalSync(ext_sync_fd, args->sync_msg);
     doSyncStage1(p, args->do_disconnect);
     DPRINTF("doit: pid=%u, ppid=%u\n", getpid(), getppid());
@@ -274,7 +296,7 @@ doit(struct Arguments const *args, char *argv[])
     doSyncStage2(p, args->do_disconnect);
 
     PERROR_Q(ENSC_WRAPPERS_PREFIX "execvp", argv[optind]);
-    exit(255);
+    exit(wrapper_exit_code);
   }
 
   assert(args->do_disconnect);
@@ -283,20 +305,51 @@ doit(struct Arguments const *args, char *argv[])
   return EXIT_SUCCESS;
 }
 
+static uint_least32_t
+parsePersonalityType(char const *str)
+{
+  uint_least32_t       res = vc_str2personalitytype(str, 0);
+  if (res==VC_BAD_PERSONALITY) {
+    WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "bad personality type\n");
+    exit(wrapper_exit_code);
+  }
+
+  return res;
+}
+
+static uint_least32_t
+parsePersonalityFlags(char const *str)
+{
+  struct vc_err_listparser     err;
+  uint_least32_t               res;
+
+  if (vc_list2personalityflag(str, 0, &res, &err)==-1) {
+    WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "bad personality flag '");
+    Vwrite(2, err.ptr, err.len);
+    WRITE_MSG(2, "'\n");
+    exit(wrapper_exit_code);
+  }
+
+  return res;
+}
+
 int main (int argc, char *argv[])
 {
   struct Arguments             args = {
-    .do_create      = false,
-    .do_migrate     = false,
-    .do_migrateself = false,
-    .do_disconnect  = false,
-    .do_endsetup    = false,
-    .is_fakeinit    = false,
-    .is_silentexist = false,
-    .verbosity      = 1,
-    .uid            = -1,
-    .xid            = VC_DYNAMIC_XID,
-    .sync_msg       = "ok",
+    .do_create         = false,
+    .do_migrate        = false,
+    .do_migrateself    = false,
+    .do_disconnect     = false,
+    .do_endsetup       = false,
+    .is_initpid        = false,
+    .is_silentexist    = false,
+    .set_namespace     = false,
+    .verbosity         = 1,
+    .uid               = -1,
+    .xid               = VC_DYNAMIC_XID,
+    .personality_type  = VC_BAD_PERSONALITY,
+    .personality_flags = 0,
+    .sync_msg          = "ok",
   };
   
   while (1) {
@@ -310,14 +363,21 @@ int main (int argc, char *argv[])
       case CMD_MIGRATE         :  args.do_migrate     = true;   break;
       case CMD_DISCONNECT      :  args.do_disconnect  = true;   break;
       case CMD_ENDSETUP                :  args.do_endsetup    = true;   break;
-      case CMD_FAKEINIT                :  args.is_fakeinit    = true;   break;
+      case CMD_INITPID         :  args.is_initpid     = true;   break;
       case CMD_CHROOT          :  args.do_chroot      = true;   break;
+      case CMD_NAMESPACE       :  args.set_namespace  = true;   break;
       case CMD_SILENTEXIST     :  args.is_silentexist = true;   break;
       case CMD_SYNCSOCK                :  args.sync_sock      = optarg; break;
       case CMD_SYNCMSG         :  args.sync_msg       = optarg; break;
       case CMD_UID             :  args.uid = atol(optarg);      break;
       case CMD_XID             :  args.xid = Evc_xidopt2xid(optarg,true); break;
       case CMD_SILENT          :  --args.verbosity; break;
+      case CMD_PERSTYPE                :
+       args.personality_type   = parsePersonalityType(optarg);
+       break;
+      case CMD_PERSFLAG                :
+       args.personality_flags |= parsePersonalityFlags(optarg);
+       break;
       case CMD_MIGRATESELF     :
        args.do_migrate     = true;
        args.do_migrateself = true;
@@ -327,11 +387,13 @@ int main (int argc, char *argv[])
        WRITE_MSG(2, "Try '");
        WRITE_STR(2, argv[0]);
        WRITE_MSG(2, " --help\" for more information.\n");
-       return 255;
+       return wrapper_exit_code;
        break;
     }
   }
 
+  signal(SIGCHLD, SIG_DFL);
+  
   if (args.do_migrateself)
     args.xid = Evc_get_task_xid(0);
   
@@ -339,8 +401,8 @@ int main (int argc, char *argv[])
     WRITE_MSG(2, "Neither '--create' nor '--migrate specified; try '--help' for more information\n");
   else if (args.do_create  &&  args.do_migrate)
     WRITE_MSG(2, "Can not specify '--create' and '--migrate' at the same time; try '--help' for more information\n");
-  else if (!args.do_migrate && args.is_fakeinit)
-    WRITE_MSG(2, "'--fakeinit' is possible in combination with '--migrate' only\n");
+  else if (!args.do_migrate && args.is_initpid)
+    WRITE_MSG(2, "'--initpid' is possible in combination with '--migrate' only\n");
   else if (!args.do_create && args.xid==VC_DYNAMIC_XID)
     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "Can not migrate to an unknown context\n");
   else if (optind>=argc)
@@ -348,5 +410,5 @@ int main (int argc, char *argv[])
   else
     return doit(&args, argv);
 
-  return 255;
+  return wrapper_exit_code;
 }