gentoo: use /var/run for new /run compatibility
[util-vserver.git] / src / secure-mount.c
index 6dc2c41..53863e3 100644 (file)
 typedef enum { rfsYES, rfsNO, rfsONLY }                RootFsOption;
 
 struct MountInfo {
-    char const *       src;
-    char const *       dst;
-    char const *       type;
+    char *             src;
+    char *             dst;
+    char *             name;
+    char *             type;
     unsigned long      flag;
     unsigned long      xflag;
     unsigned long      mask;
@@ -81,6 +82,7 @@ struct Options {
     bool               mount_all;
     RootFsOption       rootfs;
 
+    char               cur_dir_path[PATH_MAX];
     int                        cur_dir_fd;
     int                        cur_rootdir_fd;
 };
@@ -95,6 +97,8 @@ struct Options {
 #define OPTION_ROOTFS  1031
 
 #define XFLAG_NOAUTO   0x01
+#define XFLAG_FILE     0x02
+#define XFLAG_NOMTAB   0x04
 
 static struct option const
 CMDLINE_OPTIONS[] = {
@@ -112,7 +116,19 @@ CMDLINE_OPTIONS[] = {
 };
 
 #ifndef MS_REC
-#  define MS_REC       0x4000
+#define MS_REC         0x4000
+#endif
+#ifndef MS_UNBINDABLE
+#define MS_UNBINDABLE  (1<<17)
+#endif
+#ifndef MS_PRIVATE
+#define MS_PRIVATE     (1<<18)
+#endif
+#ifndef MS_SLAVE
+#define MS_SLAVE       (1<<19)
+#endif
+#ifndef MS_SHARED
+#define MS_SHARED      (1<<20)
 #endif
 
 static struct FstabOption {
@@ -153,6 +169,12 @@ static struct FstabOption {
   { "noauto",     0,              0,               XFLAG_NOAUTO, false },
   { "user",       0,              0,               0, false },
   { "nouser",     0,              0,               0, false },
+  { "rec",        MS_REC,         MS_REC,          0, false },
+  { "unbindable", MS_UNBINDABLE,  MS_UNBINDABLE,   0, false },
+  { "private",    MS_PRIVATE,     MS_PRIVATE,      0, false },
+  { "slave",      MS_SLAVE,       MS_SLAVE,        0, false },
+  { "shared",     MS_SHARED,      MS_SHARED,       0, false },
+  { "nomtab",     0,              0,               XFLAG_NOMTAB, false },
 };
 
 int                    wrapper_exit_code = 1;
@@ -287,6 +309,8 @@ updateMtab(struct MountInfo const *mnt, struct Options const *opt)
   if (writeStrX(fd, mnt->src)==-1 ||
       writeStrX(fd, " ")==-1 ||
       writeStrX(fd, mnt->dst)==-1 ||
+      writeStrX(fd, mnt->xflag & XFLAG_FILE ? "/" : "")==-1 ||
+      writeStrX(fd, mnt->xflag & XFLAG_FILE ? mnt->name : "")==-1 ||
       writeStrX(fd, " ")==-1 ||
       writeStrX(fd, getType(mnt))==-1 ||
       writeStrX(fd, " ")==-1 ||
@@ -341,7 +365,7 @@ callExternalMount(struct MountInfo const *mnt)
   }
 
   argv[idx++] = mnt->src;
-  argv[idx++] = ".";
+  argv[idx++] = mnt->name;
   argv[idx]   = 0;
 
   pid = fork();
@@ -413,6 +437,8 @@ canHandleInternal(struct MountInfo const *mnt)
   
   if (!mnt)                                 return false;
   else if ((mnt->flag & (MS_BIND|MS_MOVE))) return true;
+  else if ((mnt->flag & (MS_SHARED|MS_SLAVE|MS_PRIVATE|
+                        MS_UNBINDABLE)))   return true;
   else if (mnt->type==0)                    return false;
 
   for (i=FS+0; *i!=0; ++i)
@@ -422,7 +448,7 @@ canHandleInternal(struct MountInfo const *mnt)
 }
 
 static bool
-mountSingle(struct MountInfo const *mnt, struct Options const *opt)
+mountSingle(struct MountInfo const *mnt, struct Options *opt)
 {
   assert(mnt->dst!=0);
   
@@ -430,21 +456,31 @@ mountSingle(struct MountInfo const *mnt, struct Options const *opt)
     return false;
 
   if (canHandleInternal(mnt)) {
-    if (mount(mnt->src, ".",
+    if (mount(mnt->src, mnt->name,
              mnt->type ? mnt->type : "",
              mnt->flag,  mnt->data_parsed)==-1) {
       perror("secure-mount: mount()");
       return false;
     }
-    if ((mnt->flag & MS_BIND) &&
-       (mnt->flag & ~(MS_BIND|MS_REC))) {
+    if (strcmp(mnt->dst, "/") == 0) {
+      /* XXX: Hack */
+      if (chdir(opt->cur_dir_path) == -1) {
+       perror("secure-mount: chdir(.)");
+       return false;
+      }
+      close(opt->cur_dir_fd);
+      opt->cur_dir_fd = Eopen(".", O_RDONLY|O_DIRECTORY, 0);
+      Efcntl(opt->cur_dir_fd, F_SETFD, FD_CLOEXEC);
+    }
+    if (!vc_isSupported(vcFEATURE_BME) &&
+       (mnt->flag & MS_BIND) &&
+       (mnt->mask & ~(MS_BIND|MS_REC))) {
       /* This is needed to put us in the new mountpoint */
       if (!secureChdir(mnt->dst, opt))
        return false;
-      if (mount(mnt->src, ".",
+      if (mount(mnt->src, mnt->name,
                mnt->type ? mnt->type : "",
-               ((mnt->flag & ~(MS_BIND|MS_REC)) |
-               MS_REMOUNT), NULL) == -1 &&
+               (mnt->flag | MS_REMOUNT), NULL) == -1 &&
          errno != EBUSY) { /* Returned on older kernels */
        perror("secure-mount: mount()");
        return false;
@@ -454,7 +490,7 @@ mountSingle(struct MountInfo const *mnt, struct Options const *opt)
   else if (!callExternalMount(mnt))
     return false;
 
-  if (!opt->ignore_mtab &&
+  if (!opt->ignore_mtab && (mnt->xflag & XFLAG_NOMTAB)==0 &&
       updateMtab(mnt, opt)==-1) {
     WRITE_MSG(2, "Failed to update mtab-file\n");
       // no error
@@ -541,6 +577,7 @@ static enum {prDOIT, prFAIL, prIGNORE}
   info->flag  = MS_NODEV;
   info->mask  = 0;
   info->xflag = 0;
+  info->name = ".";
 
   if      (strcmp(info->type, "swap")  ==0) return prIGNORE;
   else if (strcmp(info->type, "none")  ==0) info->type  = 0;
@@ -571,9 +608,20 @@ showFstabPosition(int fd, char const *fname, size_t line_nr, size_t col_nr)
   Vwrite(fd, buf, len);
 }
 
+static void
+adjustFileMount(struct MountInfo *mnt)
+{
+  char *buf = strrchr(mnt->dst, '/');
+
+  if (buf)
+    *buf++ = 0;
+
+  mnt->name = buf;
+  mnt->xflag |= XFLAG_FILE;
+}
 
 static bool
-mountFstab(struct Options const *opt)
+mountFstab(struct Options *opt)
 {
   bool         res = false;
   int          fd;
@@ -623,9 +671,13 @@ mountFstab(struct Options const *opt)
          Echdir("/");
          if (( is_rootfs && opt->rootfs==rfsNO) ||
              (!is_rootfs && opt->rootfs==rfsONLY)) { /* ignore the entry */ }
-         else if (!mountSingle(&mnt, opt)) {
-           showFstabPosition(2, opt->fstab, line_nr, 1);
-           WRITE_MSG(2, ": failed to mount fstab-entry\n");
+         else {
+            if (utilvserver_isFile(mnt.dst, 0))
+              adjustFileMount(&mnt);
+            if (!mountSingle(&mnt, opt)) {
+             showFstabPosition(2, opt->fstab, line_nr, 1);
+             WRITE_MSG(2, ": failed to mount fstab-entry\n");
+            }
          }
          break;
        }
@@ -649,6 +701,11 @@ initFDs(struct Options *opt)
 
   Efcntl(opt->cur_dir_fd,     F_SETFD, FD_CLOEXEC);
   Efcntl(opt->cur_rootdir_fd, F_SETFD, FD_CLOEXEC);
+
+  if (getcwd(opt->cur_dir_path, sizeof(opt->cur_dir_path)) == NULL) {
+    perror("secure-mount: getcwd()");
+    exit(wrapper_exit_code);
+  }
 }
 
 static RootFsOption
@@ -670,6 +727,7 @@ int main(int argc, char *argv[])
   struct MountInfo     mnt = {
     .src         = 0,
     .dst         = 0,
+    .name        = ".",
     .type        = 0,
     .flag        = MS_NODEV,
     .xflag      = 0,
@@ -747,7 +805,10 @@ int main(int argc, char *argv[])
   mnt.src  = argv[optind++];
   mnt.dst  = argv[optind++];
 
-  if (!mountSingle(&mnt, &opt)) return EXIT_FAILURE;
+  if (utilvserver_isFile(mnt.dst, 0))
+    adjustFileMount(&mnt);
+  if (!mountSingle(&mnt, &opt))
+    return EXIT_FAILURE;
     
   return EXIT_SUCCESS;
 }