begin of permissioner config parsing
Stefan Schuermans

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,9 @@
1
+#include "Permissions.h"
2
+
3
+#include <string>
4
+
5
+void Permissions::parseParams(std::string const &paramStr) {
6
+  for (char c : paramStr) {
7
+    (void)c;
8
+  }
9
+}
... ...
@@ -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 &paramStr);
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 &paramStr) {
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 &paramStr);
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
... ...
@@ -0,0 +1,10 @@
1
+#include "Config.h"
2
+
3
+#include <cstdlib>
4
+
5
+int main(int argc, char const **argv) {
6
+  (void)argc;
7
+  Config config;
8
+  config.parseFile(argv[1]);
9
+  return EXIT_SUCCESS;
10
+}
0 11