core: add support for temporary privilege drop and elevation

Added "user" and "group" options to general section of configuration file.
NFD will attempt to set the effective group and user id to these values
after initializing all management modules.

Added privilege helper to drop and temporarily elevate privileges on demand.

Updated README.md with instructions to configure NFD to drop privileges.

Added handler for general confguration file section.

refs: #1370

Change-Id: Id27140ad2dc2ca14751058691511132a35649d58
diff --git a/tests/mgmt/general-config-section.cpp b/tests/mgmt/general-config-section.cpp
new file mode 100644
index 0000000..e3c8cc0
--- /dev/null
+++ b/tests/mgmt/general-config-section.cpp
@@ -0,0 +1,135 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014  Regents of the University of California,
+ *                     Arizona Board of Regents,
+ *                     Colorado State University,
+ *                     University Pierre & Marie Curie, Sorbonne University,
+ *                     Washington University in St. Louis,
+ *                     Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "mgmt/general-config-section.hpp"
+
+#include "tests/test-common.hpp"
+
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(GeneralSectionConfig)
+
+BOOST_AUTO_TEST_CASE(TestConfig)
+{
+  const std::string CONFIG =
+    "general\n"
+    "{\n"
+    "  user nobody\n"
+    "  group nogroup\n"
+    "}\n";
+
+  ConfigFile configFile;
+
+  general::setConfigFile(configFile);
+  BOOST_CHECK_NO_THROW(configFile.parse(CONFIG, true, "test-general-config-section"));
+
+}
+
+BOOST_AUTO_TEST_CASE(TestDefaultConfig)
+{
+  const std::string CONFIG =
+    "general\n"
+    "{\n"
+    "}\n";
+
+  ConfigFile configFile;
+
+  general::setConfigFile(configFile);
+  BOOST_CHECK_NO_THROW(configFile.parse(CONFIG, true, "test-general-config-section"));
+}
+
+BOOST_AUTO_TEST_CASE(TestNoUserConfig)
+{
+  const std::string CONFIG =
+    "general\n"
+    "{\n"
+    "  group nogroup\n"
+    "}\n";
+
+  ConfigFile configFile;
+
+  general::setConfigFile(configFile);
+  BOOST_CHECK_NO_THROW(configFile.parse(CONFIG, true, "test-general-config-section"));
+}
+
+BOOST_AUTO_TEST_CASE(TestNoGroupConfig)
+{
+  const std::string CONFIG =
+    "general\n"
+    "{\n"
+    "  user nobody\n"
+    "}\n";
+
+  ConfigFile configFile;
+
+  general::setConfigFile(configFile);
+  BOOST_CHECK_NO_THROW(configFile.parse(CONFIG, true, "test-general-config-section"));
+}
+
+static bool
+checkExceptionMessage(const ConfigFile::Error& error, const std::string& expected)
+{
+  return error.what() == expected;
+}
+
+BOOST_AUTO_TEST_CASE(TestInvalidUserConfig)
+{
+  const std::string CONFIG =
+    "general\n"
+    "{\n"
+    "  user\n"
+    "}\n";
+
+  ConfigFile configFile;
+  general::setConfigFile(configFile);
+
+  const std::string expected = "Invalid value for \"user\" in \"general\" section";
+  BOOST_REQUIRE_EXCEPTION(configFile.parse(CONFIG, true, "test-general-config-section"),
+                          ConfigFile::Error,
+                          bind(&checkExceptionMessage, _1, expected));
+}
+
+BOOST_AUTO_TEST_CASE(TestInvalidGroupConfig)
+{
+  const std::string CONFIG =
+    "general\n"
+    "{\n"
+    "  group\n"
+    "}\n";
+
+  ConfigFile configFile;
+  general::setConfigFile(configFile);
+
+  const std::string expected = "Invalid value for \"group\" in \"general\" section";
+  BOOST_REQUIRE_EXCEPTION(configFile.parse(CONFIG, true, "test-general-config-section"),
+                          ConfigFile::Error,
+                          bind(&checkExceptionMessage, _1, expected));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+
+} // namespace nfd