implement chown/chmod
Stefan Schuermans

Stefan Schuermans commited on 2020-08-23 12:37:57
Showing 17 changed files, with 195 additions and 8 deletions.

... ...
@@ -10,9 +10,6 @@
10 10
 /// configuration file
11 11
 class Config {
12 12
 public:
13
-  /// map of trees
14
-  typedef std::map<boost::filesystem::path, Tree> TreeMap;
15
-
16 13
   /**
17 14
    * @brief parse configuration file
18 15
    * @param[in] configFileName name of configuation file
... ...
@@ -23,6 +20,11 @@ public:
23 20
   /// return trees
24 21
   TreeMap const & getTrees() const;
25 22
 
23
+  /**
24
+   * @brief set owners and permissions of files in trees
25
+   */
26
+  void setPermissions() const;
27
+
26 28
 protected:
27 29
   TreeMap trees;
28 30
 };
... ...
@@ -1,6 +1,7 @@
1 1
 #ifndef PERMISSIONS_H
2 2
 #define PERMISSIONS_H
3 3
 
4
+#include <boost/filesystem.hpp>
4 5
 #include <cstdint>
5 6
 #include <string>
6 7
 
... ...
@@ -23,6 +24,16 @@ public:
23 24
    */
24 25
   void parseParams(std::string const &paramStr);
25 26
 
27
+  /**
28
+   * @brief apply paermissions to file or directory
29
+   * @param[in] path path to file or directory
30
+   */
31
+  void apply(boost::filesystem::path const &path) const;
32
+
33
+protected:
34
+  /// convert flags into boost filesystem permissions
35
+  static boost::filesystem::perms flags2perms(Flags flags);
36
+
26 37
 protected:
27 38
   Flags set = 0;       ///< permissions to set
28 39
   Flags setCond = 0;   ///< permissions to set conditionally on usrexec/dir
... ...
@@ -6,8 +6,12 @@
6 6
 #include <permissioner/User.h>
7 7
 
8 8
 #include <boost/filesystem.hpp>
9
+#include <map>
9 10
 #include <string>
10 11
 
12
+/// map of trees
13
+typedef std::map<boost::filesystem::path, class Tree> TreeMap;
14
+
11 15
 /// directory tree configuration
12 16
 class Tree {
13 17
 public:
... ...
@@ -30,6 +34,27 @@ public:
30 34
   /// get root path
31 35
   boost::filesystem::path const & getRoot() const;
32 36
 
37
+  /**
38
+   * @brief set owners and permissions of files in tree
39
+   * @param[in] exclude map of other trees that shall be excluded
40
+   */
41
+  void setPermissions(TreeMap const &exclude) const;
42
+
43
+protected:
44
+  /**
45
+   * @brief set owners and permissions of files in path and subtrees
46
+   * @param[in] path path to top of directory tree for which to set owner/perms
47
+   * @param[in] exclude map of other trees that shall be excluded
48
+   */
49
+  void setPermissionsInternal(boost::filesystem::path const &path,
50
+                              TreeMap const &exclude) const;
51
+
52
+  /**
53
+   * @brief set owners and permissions of one file or directory
54
+   * @param[in] path path to file or directory
55
+   */
56
+  void setPermissionsOne(boost::filesystem::path const &path) const;
57
+
33 58
 protected:
34 59
   User user;
35 60
   Group group;
... ...
@@ -43,6 +43,13 @@ void Config::parseFile(std::string const &configFileName) {
43 43
   }
44 44
 }
45 45
 
46
-Config::TreeMap const & Config::getTrees() const {
46
+TreeMap const & Config::getTrees() const {
47 47
   return trees;
48 48
 }
49
+
50
+void Config::setPermissions() const {
51
+  for (auto const & path_tree : trees) {
52
+    Tree const & tree = path_tree.second;
53
+    tree.setPermissions(trees); // exclude all other trees
54
+  }
55
+}
... ...
@@ -1,5 +1,6 @@
1 1
 #include <permissioner/Permissions.h>
2 2
 
3
+#include <boost/filesystem.hpp>
3 4
 #include <sstream>
4 5
 #include <stdexcept>
5 6
 #include <string>
... ...
@@ -77,3 +78,45 @@ void Permissions::parseParams(std::string const &paramStr) {
77 78
     }
78 79
   }
79 80
 }
81
+
82
+void Permissions::apply(boost::filesystem::path const &path) const {
83
+  // only process regular files and directories (especially no symlinks)
84
+  if (! boost::filesystem::is_regular_file(path) &&
85
+      ! boost::filesystem::is_directory(path)) {
86
+    return;
87
+  }
88
+
89
+  // get permissions
90
+  boost::filesystem::file_status st = boost::filesystem::status(path);
91
+  boost::filesystem::perms perms = st.permissions();
92
+
93
+  // compute updated permissions
94
+  Flags doSet = set, doClear = clear;
95
+  if (perms & boost::filesystem::perms::owner_exe) {
96
+    doSet |= setCond;
97
+    doClear |= clearCond;
98
+  }
99
+  perms &= boost::filesystem::perms::all_all ^ flags2perms(doClear);
100
+  perms |= flags2perms(doSet);
101
+
102
+  // set new permissions if they changed
103
+  if (perms != st.permissions()) {
104
+    boost::filesystem::permissions(path, perms);
105
+  }
106
+}
107
+
108
+boost::filesystem::perms Permissions::flags2perms(Flags flags) {
109
+  using fsp = boost::filesystem::perms;
110
+  fsp perms = fsp::no_perms;
111
+  if (flags & (flagUser * flagRead)) { perms |= fsp::owner_read; }
112
+  if (flags & (flagUser * flagWrite)) { perms |= fsp::owner_write; }
113
+  if (flags & (flagUser * flagExecute)) { perms |= fsp::owner_exe; }
114
+  if (flags & (flagGroup * flagRead)) { perms |= fsp::group_read; }
115
+  if (flags & (flagGroup * flagWrite)) { perms |= fsp::group_write; }
116
+  if (flags & (flagGroup * flagExecute)) { perms |= fsp::group_exe; }
117
+  if (flags & (flagOther * flagRead)) { perms |= fsp::others_read; }
118
+  if (flags & (flagOther * flagWrite)) { perms |= fsp::others_write; }
119
+  if (flags & (flagOther * flagExecute)) { perms |= fsp::others_exe; }
120
+  return perms;
121
+}
122
+
... ...
@@ -9,6 +9,7 @@
9 9
 #include <sstream>
10 10
 #include <stdexcept>
11 11
 #include <string>
12
+#include <unistd.h>
12 13
 #include <vector>
13 14
 
14 15
 void Tree::parseParams(std::string const &paramStr) {
... ...
@@ -25,6 +26,7 @@ void Tree::parseParams(std::string const &paramStr) {
25 26
     msg << "<root> field missing in \"" << paramStr << "\"";
26 27
     throw std::runtime_error(msg.str());
27 28
   }
29
+  rootStr = paramStr.substr(pos);
28 30
 
29 31
   try {
30 32
     user.parseUserName(userStr);
... ...
@@ -78,3 +80,42 @@ Permissions const & Tree::getPermissions() const {
78 80
 boost::filesystem::path const & Tree::getRoot() const {
79 81
   return root;
80 82
 }
83
+
84
+void Tree::setPermissions(TreeMap const &exclude) const {
85
+  setPermissionsInternal(root, exclude);
86
+}
87
+
88
+void Tree::setPermissionsInternal(boost::filesystem::path const &path,
89
+                                  TreeMap const &exclude) const {
90
+  try {
91
+    if (boost::filesystem::is_regular_file(path)) {
92
+      setPermissionsOne(path);
93
+    } else if (boost::filesystem::is_directory(path)) {
94
+      setPermissionsOne(path);
95
+      for (boost::filesystem::directory_entry entry :
96
+           boost::filesystem::directory_iterator(path)) {
97
+        if (exclude.find(entry) != exclude.end()) {
98
+          continue; // other tree -> skip here
99
+        }
100
+        setPermissionsInternal(entry, exclude); // recurse
101
+      }
102
+    }
103
+  } catch (boost::filesystem::filesystem_error const & e) {
104
+    // ignore filesystem errors for now, as this runs in a daemon in background
105
+    (void)e;
106
+  }
107
+}
108
+
109
+void Tree::setPermissionsOne(boost::filesystem::path const &path) const {
110
+  // change permissions
111
+  try {
112
+    permissions.apply(path);
113
+  } catch (boost::filesystem::filesystem_error const & e) {
114
+    // ignore filesystem errors for now, as this runs in a daemon in background
115
+    (void)e;
116
+  }
117
+
118
+  // change owner/group
119
+  lchown(path.string().c_str(), user.getUid(), group.getGid());
120
+  // ignore error for now, as this runs in a daemon in background
121
+}
... ...
@@ -1 +1,2 @@
1 1
 add_subdirectory(config)
2
+add_subdirectory(trees)
... ...
@@ -13,6 +13,7 @@ add_test(
13 13
   NAME
14 14
   testConfig
15 15
   COMMAND
16
-  ./testConfig
17
-  ${CMAKE_CURRENT_SOURCE_DIR}/test.cfg
16
+  ${CMAKE_CURRENT_BINARY_DIR}/testConfig test.cfg
17
+  WORKING_DIRECTORY
18
+  ${CMAKE_CURRENT_SOURCE_DIR}
18 19
 )
... ...
@@ -1,2 +1,2 @@
1
-tree nobody nogroup go+rX,go-w /some/dir
2
-tree - - a=rwx /some/other/dir
1
+tree nobody nogroup go+rX,go-w some/dir
2
+tree - - a=rwx some/other/dir
... ...
@@ -0,0 +1,17 @@
1
+add_executable(
2
+  testTrees
3
+  testTrees.cpp
4
+)
5
+
6
+target_link_libraries(
7
+  testTrees
8
+  PUBLIC
9
+  permissioner
10
+)
11
+
12
+add_test(
13
+  NAME
14
+  testTrees
15
+  COMMAND
16
+  ${CMAKE_CURRENT_SOURCE_DIR}/testTrees.bash
17
+)
... ...
@@ -0,0 +1,10 @@
1
+#! /bin/bash
2
+
3
+set -eux -o pipefail
4
+
5
+SCRIPT_DIR="$(readlink -f "$(dirname "$0")")"
6
+
7
+rm -rf work
8
+cp -a "$SCRIPT_DIR/work" work
9
+
10
+./testTrees "$SCRIPT_DIR/trees.cfg"
... ...
@@ -0,0 +1,27 @@
1
+#include <permissioner/Config.h>
2
+
3
+#include <cstdlib>
4
+#include <iostream> // DEBUG
5
+#include <unistd.h>
6
+#include <sys/stat.h>
7
+
8
+// mock version of lchown, to see if right files get right owners
9
+extern "C" int lchown(const char *pathname, uid_t owner, gid_t group) {
10
+  std::cout << "DEBUG lchown " << pathname << " owner " << owner
11
+            << " group " << group << std::endl;
12
+  return 0;
13
+}
14
+
15
+// mock version fo chmod, to see if right files get right permissions
16
+extern "C" int chmod(const char *pathname, mode_t mode) {
17
+  std::cout << "DEBUG chmod " << pathname << " mode " << mode << std::endl;
18
+  return 0;
19
+}
20
+
21
+int main(int argc, char const **argv) {
22
+  (void)argc;
23
+  Config config;
24
+  config.parseFile(argv[1]);
25
+  config.setPermissions();
26
+  return EXIT_SUCCESS;
27
+}
... ...
@@ -0,0 +1,2 @@
1
+tree nobody nogroup g+w work
2
+tree nobody nogroup o+w work/nested