Stefan Schuermans commited on 2020-08-16 16:14:27
Showing 17 changed files, with 344 additions and 0 deletions.
... | ... |
@@ -0,0 +1 @@ |
1 |
+/build/ |
... | ... |
@@ -0,0 +1,31 @@ |
1 |
+cmake_minimum_required(VERSION 3.10) |
|
2 |
+project(permissioner) |
|
3 |
+ |
|
4 |
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror") |
|
5 |
+ |
|
6 |
+find_package( |
|
7 |
+ Boost |
|
8 |
+ COMPONENTS |
|
9 |
+ filesystem |
|
10 |
+) |
|
11 |
+ |
|
12 |
+enable_testing() |
|
13 |
+ |
|
14 |
+add_custom_command( |
|
15 |
+ OUTPUT |
|
16 |
+ ${CMAKE_CURRENT_BINARY_DIR}/exports |
|
17 |
+ DEPENDS |
|
18 |
+ ${CMAKE_CURRENT_SOURCE_DIR}/exports |
|
19 |
+ COMMAND |
|
20 |
+ cp -a ${CMAKE_CURRENT_SOURCE_DIR}/exports ${CMAKE_CURRENT_BINARY_DIR}/exports |
|
21 |
+) |
|
22 |
+ |
|
23 |
+add_custom_target( |
|
24 |
+ copy_exports |
|
25 |
+ ALL |
|
26 |
+ DEPENDS |
|
27 |
+ exports |
|
28 |
+) |
|
29 |
+ |
|
30 |
+add_subdirectory(permissionerd) |
|
31 |
+add_subdirectory(tests) |
... | ... |
@@ -0,0 +1,11 @@ |
1 |
+if [[ -v BASH_VERSION ]] |
|
2 |
+then |
|
3 |
+ export PERMISSIONER_HOME="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")")" |
|
4 |
+elif [[ -v ZSH_VERSION ]] |
|
5 |
+then |
|
6 |
+ export PERMISSIONER_HOME="$(readlink -f "$(dirname "${(%):-%x}")")" |
|
7 |
+else |
|
8 |
+ echo "Unsupported shell, only bash and zsh are supported." >&2 |
|
9 |
+ return 2 |
|
10 |
+fi |
|
11 |
+export PATH="$PERMISSIONER_HOME/bin${PATH:+:${PATH}}" |
... | ... |
@@ -0,0 +1,18 @@ |
1 |
+add_executable( |
|
2 |
+ permissionerd |
|
3 |
+ src/Config.cpp |
|
4 |
+ src/Config.h |
|
5 |
+ src/permissionerd.cpp |
|
6 |
+ src/Permissions.cpp |
|
7 |
+ src/Permissions.h |
|
8 |
+ src/StringUtils.cpp |
|
9 |
+ src/StringUtils.h |
|
10 |
+ src/Tree.cpp |
|
11 |
+ src/Tree.h |
|
12 |
+) |
|
13 |
+ |
|
14 |
+target_link_libraries( |
|
15 |
+ permissionerd |
|
16 |
+ PUBLIC |
|
17 |
+ Boost::filesystem |
|
18 |
+) |
... | ... |
@@ -0,0 +1,43 @@ |
1 |
+#include "Config.h" |
|
2 |
+#include "StringUtils.h" |
|
3 |
+ |
|
4 |
+#include "Tree.h" |
|
5 |
+ |
|
6 |
+#include <boost/filesystem.hpp> |
|
7 |
+#include <fstream> |
|
8 |
+#include <map> |
|
9 |
+#include <sstream> |
|
10 |
+#include <stdexcept> |
|
11 |
+#include <string> |
|
12 |
+ |
|
13 |
+void Config::parseFile(std::string const &configFileName) { |
|
14 |
+ std::ifstream configFile(configFileName, std::ios::in); |
|
15 |
+ if (! configFile.is_open()) { |
|
16 |
+ std::stringstream msg; |
|
17 |
+ msg << "cannot open file \"" << configFileName << "\" for reading"; |
|
18 |
+ throw std::runtime_error(msg.str()); |
|
19 |
+ } |
|
20 |
+ |
|
21 |
+ for (std::string line; std::getline(configFile, line); ) { |
|
22 |
+ std::string::size_type pos = 0; |
|
23 |
+ std::string typeStr; |
|
24 |
+ try { |
|
25 |
+ StringUtils::getNextField(line, pos, typeStr, "config line type"); |
|
26 |
+ } catch (std::exception const &e) { |
|
27 |
+ continue; // empty line -> ignore |
|
28 |
+ } |
|
29 |
+ if (typeStr == "#") { |
|
30 |
+ continue; // comment line -> ignore |
|
31 |
+ } |
|
32 |
+ // actual consfiguration lines |
|
33 |
+ if (typeStr == "tree") { |
|
34 |
+ Tree tree; |
|
35 |
+ tree.parseParams(line.substr(pos)); |
|
36 |
+ continue; |
|
37 |
+ } |
|
38 |
+ // unknown configuration line |
|
39 |
+ std::stringstream msg; |
|
40 |
+ msg << "unknown configuration type \"" << typeStr << "\""; |
|
41 |
+ throw std::runtime_error(msg.str()); |
|
42 |
+ } |
|
43 |
+} |
... | ... |
@@ -0,0 +1,24 @@ |
1 |
+#ifndef CONFIG_H |
|
2 |
+#define CONFIG_H |
|
3 |
+ |
|
4 |
+#include "Tree.h" |
|
5 |
+ |
|
6 |
+#include <boost/filesystem.hpp> |
|
7 |
+#include <map> |
|
8 |
+#include <string> |
|
9 |
+ |
|
10 |
+/// configuration file |
|
11 |
+class Config { |
|
12 |
+public: |
|
13 |
+ /** |
|
14 |
+ * @brief parse configuration file |
|
15 |
+ * @param[in] configFileName name of configuation file |
|
16 |
+ * @throws std::exception if something goes wrong |
|
17 |
+ */ |
|
18 |
+ void parseFile(std::string const &configFileName); |
|
19 |
+ |
|
20 |
+protected: |
|
21 |
+ std::map<boost::filesystem::path, Tree> trees; |
|
22 |
+}; |
|
23 |
+ |
|
24 |
+#endif // #ifndef CONFIG_H |
... | ... |
@@ -0,0 +1,20 @@ |
1 |
+#ifndef PERMISSIONS_H |
|
2 |
+#define PERMISSIONS_H |
|
3 |
+ |
|
4 |
+#include <string> |
|
5 |
+ |
|
6 |
+/// permissions configuration |
|
7 |
+class Permissions { |
|
8 |
+public: |
|
9 |
+ /** |
|
10 |
+ * @brief parse permissions parameters |
|
11 |
+ * @param[in] parmStr parameter string |
|
12 |
+ * @throws std::exception if something goes wrong |
|
13 |
+ */ |
|
14 |
+ void parseParams(std::string const ¶mStr); |
|
15 |
+ |
|
16 |
+protected: |
|
17 |
+ |
|
18 |
+}; |
|
19 |
+ |
|
20 |
+#endif // #ifndef PERMISSIONS_H |
... | ... |
@@ -0,0 +1,29 @@ |
1 |
+#include "StringUtils.h" |
|
2 |
+ |
|
3 |
+#include <stdexcept> |
|
4 |
+#include <sstream> |
|
5 |
+#include <string> |
|
6 |
+ |
|
7 |
+void StringUtils::getNextField(std::string const &str, |
|
8 |
+ std::string::size_type &pos, std::string &field, |
|
9 |
+ std::string const &name) { |
|
10 |
+ static const std::string whitespace(" \t"); |
|
11 |
+ |
|
12 |
+ std::string::size_type begin = str.find_first_not_of(whitespace, pos); |
|
13 |
+ if (begin == std::string::npos) { |
|
14 |
+ std::stringstream msg; |
|
15 |
+ msg << "<" << name <<"> field missing in \"" << str << "\""; |
|
16 |
+ throw std::runtime_error(msg.str()); |
|
17 |
+ } |
|
18 |
+ |
|
19 |
+ std::string::size_type end = str.find_first_of(whitespace, begin); |
|
20 |
+ if (end == std::string::npos) { |
|
21 |
+ end = str.length(); |
|
22 |
+ } |
|
23 |
+ field = str.substr(begin, end - begin); |
|
24 |
+ |
|
25 |
+ pos = str.find_first_not_of(whitespace, end); |
|
26 |
+ if (pos == std::string::npos) { |
|
27 |
+ pos = str.length(); |
|
28 |
+ } |
|
29 |
+} |
... | ... |
@@ -0,0 +1,20 @@ |
1 |
+#ifndef STRING_UTILS_H |
|
2 |
+#define STRING_UTILS_H |
|
3 |
+ |
|
4 |
+#include <string> |
|
5 |
+ |
|
6 |
+class StringUtils { |
|
7 |
+public: |
|
8 |
+ /** |
|
9 |
+ * @brief get next whitespace separated field in string |
|
10 |
+ * @param[in] str string on which to operate |
|
11 |
+ * @param[in, out] pos current position, updated to begin of next field |
|
12 |
+ * @param[out] field value of field extracted from string |
|
13 |
+ * @param[in] name filed name for exception |
|
14 |
+ * @throws std::exception if something goes wrong |
|
15 |
+ */ |
|
16 |
+ static void getNextField(std::string const &str, std::string::size_type &pos, |
|
17 |
+ std::string &field, std::string const &name); |
|
18 |
+}; |
|
19 |
+ |
|
20 |
+#endif // #ifndef STRING_UTILS_H |
... | ... |
@@ -0,0 +1,47 @@ |
1 |
+#include "Tree.h" |
|
2 |
+ |
|
3 |
+#include "Permissions.h" |
|
4 |
+#include "StringUtils.h" |
|
5 |
+ |
|
6 |
+#include <boost/filesystem.hpp> |
|
7 |
+#include <boost/optional.hpp> |
|
8 |
+#include <sstream> |
|
9 |
+#include <stdexcept> |
|
10 |
+#include <string> |
|
11 |
+#include <vector> |
|
12 |
+ |
|
13 |
+void Tree::parseParams(std::string const ¶mStr) { |
|
14 |
+ // format of paramStr is: <user> " " <group> " " <permissions> " " <root> |
|
15 |
+ // user, group, permissions may be - for no change |
|
16 |
+ std::string userStr, groupStr, permissionsStr, rootStr; |
|
17 |
+ |
|
18 |
+ std::string::size_type pos = 0; |
|
19 |
+ StringUtils::getNextField(paramStr, pos, userStr, "user"); |
|
20 |
+ StringUtils::getNextField(paramStr, pos, groupStr, "group"); |
|
21 |
+ StringUtils::getNextField(paramStr, pos, permissionsStr, "permissions"); |
|
22 |
+ if (pos >= paramStr.length()) { |
|
23 |
+ std::stringstream msg; |
|
24 |
+ msg << "<root> field missing in \"" << paramStr << "\""; |
|
25 |
+ throw std::runtime_error(msg.str()); |
|
26 |
+ } |
|
27 |
+ |
|
28 |
+ if (userStr == "-") { |
|
29 |
+ user = boost::none; |
|
30 |
+ } else { |
|
31 |
+ user = userStr; |
|
32 |
+ } |
|
33 |
+ if (groupStr == "-") { |
|
34 |
+ group = boost::none; |
|
35 |
+ } else { |
|
36 |
+ group = groupStr; |
|
37 |
+ } |
|
38 |
+ try { |
|
39 |
+ permissions.parseParams(permissionsStr); |
|
40 |
+ } catch (std::exception const & e) { |
|
41 |
+ std::stringstream msg; |
|
42 |
+ msg << "invalid <permissions> field in \"" << paramStr << "\": " |
|
43 |
+ << e.what(); |
|
44 |
+ throw std::runtime_error(msg.str()); |
|
45 |
+ } |
|
46 |
+ root = rootStr; |
|
47 |
+} |
... | ... |
@@ -0,0 +1,27 @@ |
1 |
+#ifndef TREE_H |
|
2 |
+#define TREE_H |
|
3 |
+ |
|
4 |
+#include "Permissions.h" |
|
5 |
+ |
|
6 |
+#include <boost/filesystem.hpp> |
|
7 |
+#include <boost/optional.hpp> |
|
8 |
+#include <string> |
|
9 |
+ |
|
10 |
+/// directory tree configuration |
|
11 |
+class Tree { |
|
12 |
+public: |
|
13 |
+ /** |
|
14 |
+ * @brief parse tree parameters |
|
15 |
+ * @param[in] parmStr parameter string |
|
16 |
+ * @throws std::exception if something goes wrong |
|
17 |
+ */ |
|
18 |
+ void parseParams(std::string const ¶mStr); |
|
19 |
+ |
|
20 |
+protected: |
|
21 |
+ boost::optional<std::string> user; |
|
22 |
+ boost::optional<std::string> group; |
|
23 |
+ Permissions permissions; |
|
24 |
+ boost::filesystem::path root; |
|
25 |
+}; |
|
26 |
+ |
|
27 |
+#endif // #ifndef TREE_H |
... | ... |
@@ -0,0 +1,24 @@ |
1 |
+#include "Config.h" |
|
2 |
+ |
|
3 |
+#include <cstdlib> |
|
4 |
+#include <iostream> |
|
5 |
+#include <stdexcept> |
|
6 |
+#include <string> |
|
7 |
+ |
|
8 |
+int main(int argc, char const **argv) { |
|
9 |
+ if (argc != 2) { |
|
10 |
+ std::cerr << "usage: " << argv[0] << " <config file>" << std::endl; |
|
11 |
+ return EXIT_FAILURE; |
|
12 |
+ } |
|
13 |
+ std::string configFileName(argv[1]); |
|
14 |
+ |
|
15 |
+ try { |
|
16 |
+ Config config; |
|
17 |
+ config.parseFile(configFileName); |
|
18 |
+ } catch (std::exception const &e) { |
|
19 |
+ std::cerr << "error: " << e.what() << std::endl; |
|
20 |
+ return EXIT_FAILURE; |
|
21 |
+ } |
|
22 |
+ |
|
23 |
+ return EXIT_SUCCESS; |
|
24 |
+} |
... | ... |
@@ -0,0 +1 @@ |
1 |
+add_subdirectory(config) |
... | ... |
@@ -0,0 +1,28 @@ |
1 |
+add_executable( |
|
2 |
+ testConfig |
|
3 |
+ testConfig.cpp |
|
4 |
+ ${CMAKE_SOURCE_DIR}/permissionerd/src/Config.cpp |
|
5 |
+ ${CMAKE_SOURCE_DIR}/permissionerd/src/Permissions.cpp |
|
6 |
+ ${CMAKE_SOURCE_DIR}/permissionerd/src/StringUtils.cpp |
|
7 |
+ ${CMAKE_SOURCE_DIR}/permissionerd/src/Tree.cpp |
|
8 |
+) |
|
9 |
+ |
|
10 |
+target_include_directories( |
|
11 |
+ testConfig |
|
12 |
+ PUBLIC |
|
13 |
+ ${CMAKE_SOURCE_DIR}/permissionerd/src |
|
14 |
+) |
|
15 |
+ |
|
16 |
+target_link_libraries( |
|
17 |
+ testConfig |
|
18 |
+ PUBLIC |
|
19 |
+ Boost::filesystem |
|
20 |
+) |
|
21 |
+ |
|
22 |
+add_test( |
|
23 |
+ NAME |
|
24 |
+ testConfig |
|
25 |
+ COMMAND |
|
26 |
+ ./testConfig |
|
27 |
+ ${CMAKE_CURRENT_SOURCE_DIR}/test.cfg |
|
28 |
+) |
... | ... |
@@ -0,0 +1 @@ |
1 |
+tree myuser mygroup go+rX,go-w /some/dir |