use $(LIBENSCVECTOR) instead of libensc_vector.a
[util-vserver.git] / util-vserver / src / rpm-fake.c
index b2f416c..8ffdbaf 100644 (file)
 #include <pwd.h>
 #include <grp.h>
 
+
+  // from selinux.h
+  // FIXME: add configure autodetection and include <selinux.h> directly
+int rpm_execcon(unsigned int verified,
+               const char *filename,
+               char *const argv[], char *const envp[]);
+
+
 #define ENSC_WRAPPERS_PREFIX   "rpm-fake.so: "
 #define ENSC_WRAPPERS_VSERVER  1
 #define ENSC_WRAPPERS_UNISTD   1
 #include <wrappers.h>
 
+#undef _POSIX_SOURCE
+#include "capability-compat.h"
+
 #ifndef CLONE_NEWNS
 #  define CLONE_NEWNS  0x00020000
 #endif
 #define INIT(FILE,FUNC)        FUNC##_func = ((__typeof__(FUNC) *) (xdlsym(FILE, #FUNC)))
 #define DECLARE(FUNC)  static __typeof__(FUNC) *       FUNC##_func = 0
 
+#define DEBUG 1
 
 #define DBG_INIT       0x0001
 #define DBG_VARIABLES  0x0002
 #define DBG_RESOLVER   0x0004
 #define DBG_EXECV      0x0008
+#define DBG_ENV                0x0010
 #define DBG_VERBOSE0   0x8000
 #define DBG_VERBOSE1   (0x4000 | DBG_VERBOSE0)
 #define DBG_VERBOSE2   (0x2000 | DBG_VERBOSE1)
@@ -87,7 +100,8 @@ static unsigned int  debug_level = 0;
 
 static bool            is_initialized = false;
 
-DECLARE(execv);
+  //DECLARE(rpm_execcon);
+  //DECLARE(execv);
 DECLARE(getpwnam);
 DECLARE(getgrnam);
 DECLARE(endpwent);
@@ -108,10 +122,10 @@ xdlsym(void *handle, const char *symbol)
   void *res = dlsym(handle, symbol);
   if (res==0) {
     char const *error = dlerror();
-    write(2, symbol, strlen(symbol));
-    write(2, ": ", 2);
-    write(2, error, strlen(error));
-    write(2, "\n", 2);
+    Vwrite(2, symbol, strlen(symbol));
+    Vwrite(2, ": ", 2);
+    Vwrite(2, error, strlen(error));
+    Vwrite(2, "\n", 2);
 
     _exit(255);
   }
@@ -155,17 +169,72 @@ showVersion()
   exit(0);
 }
 
+static void
+unsetPreloadEnv()
+{
+  char                 *env = getenv("LD_PRELOAD");
+  char                 *pos;
+
+    // the const <-> non-const assignment is not an issue since the following
+    // modifying operations will not be executed in the const-case
+  env = env ? env : "";
+  pos = strstr(env, LIBNAME);
+
+  if (pos!=0) {
+    char       *end_pos = pos + sizeof(LIBNAME);
+    bool       is_end = (end_pos[-1]=='\0');
+    char       *start_pos;
+
+    end_pos[-1] = '\0';
+    start_pos   = strrchr(env, ':');
+    if (start_pos==0) start_pos = env;
+    else if (!is_end) ++start_pos;
+
+    if (is_end) *start_pos = '\0';
+    else        memmove(start_pos, end_pos, strlen(end_pos)+1);
+  }
+
+#ifdef DEBUG
+  if (isDbgLevel(DBG_VERBOSE1|DBG_VARIABLES)) {
+    WRITE_MSG(2, "env='");
+    WRITE_STR(2, env);
+    WRITE_MSG(2, "'\n");
+  }
+#endif
+
+  if (*env=='\0') unsetenv("LD_PRELOAD");
+}
+
+static void
+clearEnv()
+{
+  if (isDbgLevel(DBG_ENV)) WRITE_MSG(2, "clearEnv()\n");
+  
+  unsetenv("RPM_FAKE_S_CONTEXT_REV");
+  unsetenv("RPM_FAKE_S_CONTEXT_NR");
+  unsetenv("RPM_FAKE_CTX");
+  unsetenv("RPM_FAKE_FLAGS");
+  unsetenv("RPM_FAKE_CHROOT");
+  unsetenv("RPM_FAKE_NAMESPACE_MOUNTS");
+
+  unsetenv("RPM_FAKE_RESOLVER_GID");
+  unsetenv("RPM_FAKE_RESOLVER_UID");
+  unsetenv("RPM_FAKE_RESOLVER");    
+  unsetenv("RPM_FAKE_PWSOCKET");
+
+  unsetenv("RPM_FAKE_DEBUG");
+
+  unsetPreloadEnv();
+}
+
 static int
-getAndClearEnv(char const *key, int dflt)
+getDefaultEnv(char const *key, int dflt)
 {
   char         *env = getenv(key);
   int          res;
 
   if (env==0 || env[0]=='\0') res = dflt;
-  else {
-    res = atoi(env);
-    unsetenv(key);
-  }
+  else                        res = atoi(env);
 
   return res;
 }
@@ -244,7 +313,6 @@ initPwSocket()
       exit(255);
     }
   }
-  unsetenv("RPM_FAKE_PWSOCKET");
 }
 #else
 static void
@@ -284,6 +352,8 @@ initPwSocket()
       char const       *xid_str;
       char             flag_str[ sizeof(flags)*3 + 2];
       char             caps_str[ sizeof(caps)*3  + 2];
+
+      clearEnv();
       
       setsid();
       dup2(res_sock[1],  0);
@@ -302,10 +372,12 @@ initPwSocket()
       *ptr++ = resolver;
       *ptr++ = "-F"; *ptr++ = flag_str;
       *ptr++ = "-C"; *ptr++ = caps_str;
-      if (root)  { *ptr++ = "-r"; *ptr++ = root;  }
+      if (root)  { *ptr++ = "-r"; *ptr++ = ".";   }
       if (uid)   { *ptr++ = "-u"; *ptr++ = uid;   }
       if (gid)   { *ptr++ = "-g"; *ptr++ = gid;   }
 
+      if (root) Echdir(root);
+
       if (setupContext(ctx, &xid_str)) { *ptr++ = "-s"; }
       else if (xid_str)                { *ptr++ = "-c"; *ptr++ = xid_str; }
       
@@ -336,15 +408,35 @@ initPwSocket()
        exit(255);
       }
     }
-
-    unsetenv("RPM_FAKE_RESOLVER_GID");
-    unsetenv("RPM_FAKE_RESOLVER_UID");
-    unsetenv("RPM_FAKE_RESOLVER");    
   }
 }
 #endif
 
 static void
+reduceCapabilities()
+{
+  struct __user_cap_header_struct header;
+  struct __user_cap_data_struct user;
+  
+  header.version = _LINUX_CAPABILITY_VERSION;
+  header.pid     = 0;
+
+  if (capget(&header, &user)==-1) {
+    perror("capget()");
+    exit(wrapper_exit_code);
+  }
+
+  user.effective   &= ~(1<<CAP_MKNOD);
+  user.permitted   &= ~(1<<CAP_MKNOD);
+  user.inheritable &= ~(1<<CAP_MKNOD);
+
+  if (capset(&header, &user)==-1) {
+    perror("capset()");
+    exit(wrapper_exit_code);
+  }
+}
+
+static void
 initEnvironment()
 {
   int          syscall_rev;
@@ -352,8 +444,8 @@ initEnvironment()
   
   if (is_initialized) return;
 
-  syscall_rev = getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0);
-  syscall_nr  = getAndClearEnv("RPM_FAKE_S_CONTEXT_NR",  273);
+  syscall_rev = getDefaultEnv("RPM_FAKE_S_CONTEXT_REV", 0);
+  syscall_nr  = getDefaultEnv("RPM_FAKE_S_CONTEXT_NR",  273);
   
 #ifdef VC_ENABLE_API_LEGACY
   {
@@ -364,17 +456,19 @@ initEnvironment()
   }
 #endif
 
-  ctx       = getAndClearEnv("RPM_FAKE_CTX",  VC_DYNAMIC_XID);
-  caps      = getAndClearEnv("RPM_FAKE_CAP",  ~0x3404040f);
-  flags     = getAndClearEnv("RPM_FAKE_FLAGS", 0);
+  ctx       = getDefaultEnv("RPM_FAKE_CTX",  VC_DYNAMIC_XID);
+  caps      = getDefaultEnv("RPM_FAKE_CAP",  ~0x3404040f);
+  flags     = getDefaultEnv("RPM_FAKE_FLAGS", 0);
   root      = getenv("RPM_FAKE_CHROOT");
   mnts      = getenv("RPM_FAKE_NAMESPACE_MOUNTS");
   if (mnts && *mnts) mnts = strdup(mnts);
   else               mnts = 0;
 
-  unsetenv("RPM_FAKE_CHROOT");
-  unsetenv("RPM_FAKE_NAMESPACE_MOUNTS");
-
+#if DEBUG
+  if (isDbgLevel(DBG_VERBOSE1))
+    dprintf(2, "ctx=%u, caps=%016x, flags=%016x,\nroot='%s',\nmnts='%s'\n",
+           ctx, caps, flags, root, mnts);
+#endif
   
   is_initialized = true;
 }
@@ -382,60 +476,25 @@ initEnvironment()
 static void
 initSymbols()
 {
-  INIT(RTLD_NEXT, execv);
+    //INIT(RTLD_NEXT, rpm_execcon);
+    //INIT(RTLD_NEXT, execv);
   INIT(RTLD_NEXT, getgrnam);
   INIT(RTLD_NEXT, getpwnam);
   INIT(RTLD_NEXT, endpwent);
   INIT(RTLD_NEXT, endgrent);
 }
 
-static void
-fixPreloadEnv()
-{
-  char                 *env = getenv("LD_PRELOAD");
-  char                 *pos;
-
-    // the const <-> non-const assignment is not an issue since the following
-    // modifying operations will not be executed in the const-case
-  env = env ? env : "";
-  pos = strstr(env, LIBNAME);
-
-  if (pos!=0) {
-    char       *end_pos = pos + sizeof(LIBNAME);
-    bool       is_end = (end_pos[-1]=='\0');
-    char       *start_pos;
-
-    end_pos[-1] = '\0';
-    start_pos   = strrchr(env, ':');
-    if (start_pos==0) start_pos = env;
-    else if (!is_end) ++start_pos;
-
-    if (is_end) *start_pos = '\0';
-    else        memmove(start_pos, end_pos, strlen(end_pos)+1);
-  }
-
-#ifdef DEBUG
-  if (isDbgLevel(DBG_VERBOSE1|DBG_VARIABLES)) {
-    WRITE_MSG(2, "env='");
-    WRITE_STR(2, env);
-    WRITE_MSG(2, "'\n");
-  }
-#endif
-
-  if (*env=='\0') unsetenv("LD_PRELOAD");
-}
-
 void
 initRPMFake()
 {
   if (getenv("RPM_FAKE_VERSION")) showVersion();
   if (getenv("RPM_FAKE_HELP"))    showHelp();
   
-  debug_level = getAndClearEnv("RPM_FAKE_DEBUG", 0);
+  debug_level = getDefaultEnv("RPM_FAKE_DEBUG", 0);
 
   if (isDbgLevel(DBG_INIT)) WRITE_MSG(2, ">>>>> initRPMFake <<<<<\n");
   
-  fixPreloadEnv();
+  reduceCapabilities();
   initSymbols();
   initEnvironment();
   initPwSocket();
@@ -453,8 +512,8 @@ exitRPMFake()
   if (isDbgLevel(DBG_INIT)) WRITE_MSG(2, ">>>>> exitRPMFake <<<<<\n");
   if (pw_sock!=-1) {
     uint8_t    c;
-    read(sync_sock, &c, 1);
-    write(pw_sock, "Q", 1);
+    if (read(sync_sock, &c, 1)!=1) { /*...*/ }
+    if (write(pw_sock, "Q", 1)!=1) { /*...*/ }
   }
 }
 
@@ -465,20 +524,18 @@ exitRPMFake()
 static bool
 doPwStringRequest(uint32_t *result, char style, char const *name)
 {
-  uint32_t     len = strlen(name);
+  size_t       len = strlen(name);
   uint8_t      code;
   uint8_t      c;
 
-    // read the token...
-  read(sync_sock, &c, 1);
-
-  write(pw_sock, &style, 1);
-  write(pw_sock, &len,   sizeof len);
-  write(pw_sock, name,   len);
-  read (pw_sock, &code,  sizeof code);
-  read (pw_sock, result, sizeof *result);
-
-  return code!=0;
+  return (TEMP_FAILURE_RETRY(read (sync_sock, &c, 1))==1 &&
+         
+         TEMP_FAILURE_RETRY(write(pw_sock, &style, 1))==1 &&
+         TEMP_FAILURE_RETRY(write(pw_sock, &len,   sizeof len))==sizeof(len) &&
+         TEMP_FAILURE_RETRY(write(pw_sock, name,   len))==(ssize_t)(len) &&
+         TEMP_FAILURE_RETRY(read (pw_sock, &code,  sizeof code))==sizeof(code) &&
+         TEMP_FAILURE_RETRY(read (pw_sock, result, sizeof *result))==sizeof(*result) &&
+         code!=0);
 }
 
 struct passwd *
@@ -532,21 +589,24 @@ endpwent()
 
 
 static int
-execvWorker(char const *path, char * const argv[])
+execvWorker(char const *path, char * const argv[], char * const envp[])
 {
   int          res = -1;
 
   if (vc_isSupported(vcFEATURE_MIGRATE))
     res = vc_ctx_migrate(ctx);
-  else
+  else {
 #ifdef VC_ENABLE_API_COMPAT  
     res = vc_new_s_context(ctx,caps,flags);
 #else
     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "can not change context: migrate kernel feature missing and 'compat' API disabled\n");
 #endif
+  }
+
+  clearEnv();    
     
   if (res!=-1)
-    res=execv_func(path, argv);
+    res=execve(path, argv, envp);
 
   return res;
 }
@@ -555,6 +615,7 @@ struct ExecvParams
 {
     char const *       path;
     char * const *     argv;
+    char * const *     envp;
     char const *       mnts;
 };
 
@@ -577,13 +638,14 @@ removeNamespaceMountsChild(struct ExecvParams const *params)
     ptr = strtok(0, ":");
   }
 
-  return execvWorker(params->path, params->argv);
+  return execvWorker(params->path, params->argv, params->envp);
 }
 
 static int
-removeNamespaceMounts(char const *path, char * const argv[])
+removeNamespaceMounts(char const *path,
+                     char * const argv[], char * const envp[])
 {
-  if (mnts==0) return execvWorker(path, argv);
+  if (mnts==0) return execvWorker(path, argv, envp);
 
   {
     int                                status;
@@ -592,6 +654,7 @@ removeNamespaceMounts(char const *path, char * const argv[])
 
     params.path = path;
     params.argv = argv;
+    params.envp = envp;
     params.mnts = mnts;
 
       // the rpmlib signal-handler is still active; use the default one to
@@ -626,5 +689,33 @@ removeNamespaceMounts(char const *path, char * const argv[])
 int
 execv(char const *path, char * const argv[])
 {
-  return removeNamespaceMounts(path, argv);
+  extern char **environ;
+
+  if (isDbgLevel(DBG_EXECV)) {
+    WRITE_MSG(2, "execv('");
+    WRITE_STR(2, path);
+    WRITE_MSG(2, "', ...)\n");
+  }
+
+  return removeNamespaceMounts(path, argv, environ);
+}
+
+int
+rpm_execcon(unsigned int UNUSED verified,
+           const char *filename,
+           char *const argv[], char *const envp[])
+{
+  if (isDbgLevel(DBG_EXECV)) {
+    WRITE_MSG(2, "rpm_execcon(..., '");
+    WRITE_STR(2, filename);
+    WRITE_MSG(2, "', ...)\n");
+  }
+
+  return removeNamespaceMounts(filename, argv, envp);
+}
+
+int
+is_selinux_enabled()
+{
+  return 0;
 }