Make sure we're using the right user/group for CLI commands
authorGunnar Beutner <gunnar.beutner@netways.de>
Mon, 13 Oct 2014 11:43:05 +0000 (13:43 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Mon, 13 Oct 2014 11:44:45 +0000 (13:44 +0200)
refs #7246

16 files changed:
config.h.cmake
debian/icinga2-common.icinga2.init
etc/CMakeLists.txt
etc/icinga2/init.conf.cmake [new file with mode: 0644]
etc/initsystem/icinga2.init.d.cmake
icinga-app/icinga.cpp
lib/base/application.cpp
lib/base/application.hpp
lib/base/tlsutility.cpp
lib/base/tlsutility.hpp
lib/cli/CMakeLists.txt
lib/cli/daemoncommand.cpp
lib/cli/pkinewcacommand.cpp [moved from lib/cli/pkiinitcacommand.cpp with 61% similarity]
lib/cli/pkinewcacommand.hpp [moved from lib/cli/pkiinitcacommand.hpp with 90% similarity]
lib/cli/pkinewcertcommand.cpp [moved from lib/cli/pkinewcsrcommand.cpp with 75% similarity]
lib/cli/pkinewcertcommand.hpp [moved from lib/cli/pkinewcsrcommand.hpp with 90% similarity]

index b537096f82e8722c36472f7540ae51dc8ae6c45c..24c38ef27258c9d12469b3c7b0642bfb3b0a269b 100644 (file)
@@ -18,5 +18,7 @@
 #define ICINGA_LOCALSTATEDIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}"
 #define ICINGA_PKGDATADIR "${CMAKE_INSTALL_FULL_DATADIR}/icinga2"
 #define ICINGA_INCLUDECONFDIR "${CMAKE_INSTALL_FULL_DATADIR}/icinga2/include"
+#define ICINGA_USER "${ICINGA2_USER}"
+#define ICINGA_GROUP "${ICINGA2_GROUP}"
 
 #endif /* CONFIG_H */
index cfdd04a36131f968c4ba4673595b7d75f8dd0e15..e04ff45974aee2f426e1911a7406af0a67ba0b0f 100644 (file)
@@ -17,7 +17,6 @@ PATH=/sbin:/usr/sbin:/bin:/usr/bin
 DESC="icinga2 monitoring daemon"
 NAME=icinga2
 DAEMON=/usr/sbin/icinga2
-DAEMON_CONFIG="/etc/icinga2/icinga2.conf"
 DAEMON_USER=nagios
 DAEMON_GROUP=nagios
 DAEMON_CMDGROUP=www-data
@@ -53,7 +52,7 @@ check_run () {
 }
 
 check_config () {
-  $DAEMON daemon --validate -u "$DAEMON_USER" -g "$DAEMON_GROUP" -c "$DAEMON_CONFIG"
+  $DAEMON daemon --validate
 }
 
 #
@@ -69,7 +68,7 @@ do_start()
   start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
     || return 1
   start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
-    daemon -c "$DAEMON_CONFIG" -u "$DAEMON_USER" -g "$DAEMON_GROUP" -d $DAEMON_ARGS \
+    daemon -d $DAEMON_ARGS \
     || return 2
   # Add code here, if necessary, that waits for the process to be ready
   # to handle requests from services started subsequently which depend
@@ -84,7 +83,7 @@ do_foreground()
   start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test \
     || return 1
   start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON -- \
-    daemon -c "$DAEMON_CONFIG" -u "$DAEMON_USER" -g "$DAEMON_GROUP" $DAEMON_ARGS \
+    daemon $DAEMON_ARGS \
     || return 2
 }
 
index 0145a39c5097981e798f72de85d4c54692c5f098..75bc37bccdfc4c28a2b6cb164fa3b22a38d5bae8 100644 (file)
 include(InstallConfig)
 
 configure_file(icinga/icinga-classic-apache.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/icinga/icinga-classic-apache.conf @ONLY)
+configure_file(icinga2/init.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/icinga2/init.conf @ONLY)
 configure_file(icinga2/constants.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/icinga2/constants.conf @ONLY)
 configure_file(logrotate.d/icinga2.cmake ${CMAKE_CURRENT_BINARY_DIR}/logrotate.d/icinga2 @ONLY)
 
+install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/icinga2/init.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2)
 install_if_not_exists(icinga2/icinga2.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2)
 install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/icinga2/constants.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2)
 install_if_not_exists(icinga2/zones.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2)
diff --git a/etc/icinga2/init.conf.cmake b/etc/icinga2/init.conf.cmake
new file mode 100644 (file)
index 0000000..50e7cae
--- /dev/null
@@ -0,0 +1,2 @@
+const RunAsUser = "@ICINGA2_USER@"
+const RunAsGroup = "@ICINGA2_GROUP@"
index 08b434c5690d340f89eaef2b24dec5fa8872fe9c..f13496fc016138a9100b37d3f39b4723d21bdd0f 100644 (file)
@@ -48,7 +48,7 @@ start() {
        printf "Starting Icinga 2: "
        @CMAKE_INSTALL_FULL_SBINDIR@/icinga2-prepare-dirs $SYSCONFIGFILE
 
-       if ! $DAEMON daemon -c $ICINGA2_CONFIG_FILE -d -e $ICINGA2_ERROR_LOG -u $ICINGA2_USER -g $ICINGA2_GROUP > $ICINGA2_STARTUP_LOG 2>&1; then
+       if ! $DAEMON daemon -c $ICINGA2_CONFIG_FILE -d -e $ICINGA2_ERROR_LOG > $ICINGA2_STARTUP_LOG 2>&1; then
                echo "Error starting Icinga. Check '$ICINGA2_STARTUP_LOG' for details."
                exit 1
        else
@@ -111,7 +111,7 @@ reload() {
 checkconfig() {
        printf "Checking configuration: "
 
-       if ! $DAEMON daemon -c $ICINGA2_CONFIG_FILE -C -u $ICINGA2_USER -g $ICINGA2_GROUP > $ICINGA2_STARTUP_LOG 2>&1; then
+       if ! $DAEMON daemon -c $ICINGA2_CONFIG_FILE -C > $ICINGA2_STARTUP_LOG 2>&1; then
                 if [ "x$1" = "x" ]; then
                        cat $ICINGA2_STARTUP_LOG
                        echo "Icinga 2 detected configuration errors. Check '$ICINGA2_STARTUP_LOG' for details."
index 74b9650182f157ea9270b41ae26027e9ad93a07a..fe94f47fbcd5e34b1a9ed501ae22cbc90b265705 100644 (file)
 #include <boost/tuple/tuple.hpp>
 #include <boost/foreach.hpp>
 
+#ifndef _WIN32
+#      include <sys/types.h>
+#      include <pwd.h>
+#      include <grp.h>
+#endif /* _WIN32 */
+
 using namespace icinga;
 namespace po = boost::program_options;
 
@@ -110,6 +116,8 @@ int Main(void)
 
        Application::DeclareZonesDir(Application::GetSysconfDir() + "/icinga2/zones.d");
        Application::DeclareApplicationType("icinga/IcingaApplication");
+       Application::DeclareRunAsUser(ICINGA_USER);
+       Application::DeclareRunAsGroup(ICINGA_GROUP);
 
        LogSeverity logLevel = Logger::GetConsoleLogSeverity();
        Logger::SetConsoleLogSeverity(LogWarning);
@@ -124,8 +132,12 @@ int Main(void)
                ("define,D", po::value<std::vector<std::string> >(), "define a constant")
                ("library,l", po::value<std::vector<std::string> >(), "load a library")
                ("include,I", po::value<std::vector<std::string> >(), "add include search directory")
-               ("log-level,x", po::value<std::string>(), "specify the log level for the console log");
-
+               ("log-level,x", po::value<std::string>(), "specify the log level for the console log")
+#ifndef _WIN32
+               ("user,u", po::value<std::string>(), "user to run Icinga as")
+               ("group,g", po::value<std::string>(), "group to run Icinga as")
+#endif /* _WIN32 */
+       ;
 
        po::options_description hiddenDesc("Hidden options");
 
@@ -145,6 +157,13 @@ int Main(void)
                return EXIT_FAILURE;
        }
 
+       String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf";
+
+       if (Utility::PathExists(initconfig)) {
+               ConfigCompilerContext::GetInstance()->Reset();
+               ConfigCompiler::CompileFile(initconfig);
+       }
+       
        if (vm.count("define")) {
                BOOST_FOREACH(const String& define, vm["define"].as<std::vector<std::string> >()) {
                        String key, value;
@@ -159,7 +178,86 @@ int Main(void)
                        ScriptVariable::Set(key, value);
                }
        }
+
+       if (vm.count("group"))
+               ScriptVariable::Set("RunAsGroup", String(vm["group"].as<std::string>()));
+
+       if (vm.count("user"))
+               ScriptVariable::Set("RunAsUser", String(vm["user"].as<std::string>()));
+
+#ifndef _WIN32
+       String group = Application::GetRunAsGroup();
+
+       errno = 0;
+       struct group *gr = getgrnam(group.CStr());
+
+       if (!gr) {
+               if (errno == 0) {
+                       std::ostringstream msgbuf;
+                       msgbuf << "Invalid group specified: " + group;
+                       Log(LogCritical, "cli",  msgbuf.str());
+                       return EXIT_FAILURE;
+               } else {
+                       std::ostringstream msgbuf;
+                       msgbuf << "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
+                       Log(LogCritical, "cli",  msgbuf.str());
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (getgid() != gr->gr_gid) {
+               if (!vm.count("reload-internal") && setgroups(0, NULL) < 0) {
+                       std::ostringstream msgbuf;
+                       msgbuf << "setgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
+                       Log(LogCritical, "cli",  msgbuf.str());
+                       return EXIT_FAILURE;
+               }
+       
+               if (setgid(gr->gr_gid) < 0) {
+                       std::ostringstream msgbuf;
+                       msgbuf << "setgid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
+                       Log(LogCritical, "cli",  msgbuf.str());
+                       return EXIT_FAILURE;
+               }
+       }
+
+       String user = Application::GetRunAsUser();
+
+       errno = 0;
+       struct passwd *pw = getpwnam(user.CStr());
+
+       if (!pw) {
+               if (errno == 0) {
+                       std::ostringstream msgbuf;
+                       msgbuf << "Invalid user specified: " + user;
+                       Log(LogCritical, "cli",  msgbuf.str());
+                       return EXIT_FAILURE;
+               } else {
+                       std::ostringstream msgbuf;
+                       msgbuf << "getpwnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
+                       Log(LogCritical, "cli",  msgbuf.str());
+                       return EXIT_FAILURE;
+               }
+       }
+
+       // also activate the additional groups the configured user is member of
+       if (getuid() != pw->pw_uid) {
+               if (!vm.count("reload-internal") && initgroups(user.CStr(), pw->pw_gid) < 0) {
+                       std::ostringstream msgbuf;
+                       msgbuf << "initgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
+                       Log(LogCritical, "cli",  msgbuf.str());
+                       return EXIT_FAILURE;
+               }
        
+               if (setuid(pw->pw_uid) < 0) {
+                       std::ostringstream msgbuf;
+                       msgbuf << "setuid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
+                       Log(LogCritical, "cli",  msgbuf.str());
+                       return EXIT_FAILURE;
+               }
+       }
+#endif /* _WIN32 */
+
        Application::DeclareStatePath(Application::GetLocalStateDir() + "/lib/icinga2/icinga2.state");
        Application::DeclareObjectsPath(Application::GetLocalStateDir() + "/cache/icinga2/icinga2.debug");
        Application::DeclarePidPath(Application::GetRunDir() + "/icinga2/icinga2.pid");
index 062db1aae98b1fb30a16c695f41c9ecf2d544c09..053844dc06391e490377b9750d2aaba99e6fe898 100644 (file)
@@ -1051,6 +1051,45 @@ void Application::DeclareApplicationType(const String& type)
        ScriptVariable::Set("ApplicationType", type, false);
 }
 
+/**
+ * Retrieves the name of the user.
+ *
+ * @returns The name.
+ */
+String Application::GetRunAsUser(void)
+{
+       return ScriptVariable::Get("RunAsUser");
+}
+
+/**
+ * Sets the name of the user.
+ *
+ * @param path The new user name.
+ */
+void Application::DeclareRunAsUser(const String& user)
+{
+       ScriptVariable::Set("RunAsUser", user, false);
+}
+/**
+ * Retrieves the name of the group.
+ *
+ * @returns The name.
+ */
+String Application::GetRunAsGroup(void)
+{
+       return ScriptVariable::Get("RunAsGroup");
+}
+
+/**
+ * Sets the name of the group.
+ *
+ * @param path The new group name.
+ */
+void Application::DeclareRunAsGroup(const String& group)
+{
+       ScriptVariable::Set("RunAsGroup", group, false);
+}
+
 void Application::MakeVariablesConstant(void)
 {
        ScriptVariable::GetByName("PrefixDir")->SetConstant(true);
@@ -1062,6 +1101,8 @@ void Application::MakeVariablesConstant(void)
        ScriptVariable::GetByName("ObjectsPath")->SetConstant(true);
        ScriptVariable::GetByName("PidPath")->SetConstant(true);
        ScriptVariable::GetByName("ApplicationType")->SetConstant(true);
+       ScriptVariable::GetByName("RunAsUser")->SetConstant(true);
+       ScriptVariable::GetByName("RunAsGroup")->SetConstant(true);
 }
 
 /**
index b1d043b6b9911d79f22153e8497800496bf6d5b8..4b66f257c0b2cafa34d63dbc26c66d69309044b9 100644 (file)
@@ -113,6 +113,12 @@ public:
        static String GetApplicationType(void);
        static void DeclareApplicationType(const String& type);
 
+       static String GetRunAsUser(void);
+       static void DeclareRunAsUser(const String& user);
+
+       static String GetRunAsGroup(void);
+       static void DeclareRunAsGroup(const String& group);
+
        static void MakeVariablesConstant(void);
 
        static ThreadPool& GetTP(void);
index 5e285b66cbd25e9c4678dddd9d42faf623152c36..44aba63857fd2ddd99efc4b3f1694c58d424d569 100644 (file)
@@ -270,8 +270,6 @@ int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile,
 
        EVP_PKEY *key = EVP_PKEY_new();
        EVP_PKEY_assign_RSA(key, rsa);
-       X509_REQ_set_version(req, 0);
-       X509_REQ_set_pubkey(req, key);
        
        if (!certfile.IsEmpty()) {
                X509 *cert = X509_new();
@@ -295,22 +293,27 @@ int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile,
                X509_free(cert);
        }
 
-       X509_NAME *name = X509_REQ_get_subject_name(req);
-       X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)cn.CStr(), -1, -1, 0);
-
-       X509_REQ_sign(req, key, EVP_sha1());
+       if (!csrfile.IsEmpty()) {
+               X509_REQ_set_version(req, 0);
+               X509_REQ_set_pubkey(req, key);
+       
+               X509_NAME *name = X509_REQ_get_subject_name(req);
+               X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)cn.CStr(), -1, -1, 0);
+       
+               X509_REQ_sign(req, key, EVP_sha1());
+       
+               Log(LogInformation, "base", "Writing certificate signing request to '" + certfile + "'.");
+       
+               bio = BIO_new(BIO_s_file());
+               BIO_write_filename(bio, const_cast<char *>(csrfile.CStr()));
+               PEM_write_bio_X509_REQ(bio, req);
+               BIO_free(bio);
+       
+               X509_REQ_free(req);
+       }
 
        EVP_PKEY_free(key);
 
-       Log(LogInformation, "base", "Writing certificate signing request to '" + certfile + "'.");
-
-       bio = BIO_new(BIO_s_file());
-       BIO_write_filename(bio, const_cast<char *>(csrfile.CStr()));
-       PEM_write_bio_X509_REQ(bio, req);
-       BIO_free(bio);
-
-       X509_REQ_free(req);
-
        return 1;
 }
 
index f3575bb440f7bc6ac0e9f091741345a46308d669..662a604ad78b5231633794366aa1e7a8a8b11343 100644 (file)
@@ -37,7 +37,7 @@ shared_ptr<SSL_CTX> I2_BASE_API MakeSSLContext(const String& pubkey, const Strin
 void I2_BASE_API AddCRLToSSLContext(const shared_ptr<SSL_CTX>& context, const String& crlPath);
 String I2_BASE_API GetCertificateCN(const shared_ptr<X509>& certificate);
 shared_ptr<X509> I2_BASE_API GetX509Certificate(const String& pemfile);
-int I2_BASE_API MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile, const String& certfile = String());
+int I2_BASE_API MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile = String(), const String& certfile = String());
 String I2_BASE_API SHA256(const String& s);
 
 class I2_BASE_API openssl_error : virtual public std::exception, virtual public boost::exception { };
index 8c54e665fadc9a03ada368713aa34804b1d240c9..d51b0a35290175310c9e453734da8d78eed13100 100644 (file)
@@ -16,7 +16,7 @@
 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
 set(cli_SOURCES
-  pkiinitcacommand.cpp pkinewcsrcommand.cpp daemoncommand.cpp
+  pkinewcacommand.cpp pkinewcertcommand.cpp daemoncommand.cpp
 )
 
 if(ICINGA2_UNITY_BUILD)
index da6000197456c25cb295387700e50fdd6289e060..00200253eda8278ff9c56a0eb40379358268f912 100644 (file)
 #include <boost/foreach.hpp>
 #include <iostream>
 
-#ifndef _WIN32
-#      include <sys/types.h>
-#      include <pwd.h>
-#      include <grp.h>
-#endif /* _WIN32 */
-
 using namespace icinga;
 namespace po = boost::program_options;
 
@@ -291,8 +285,6 @@ void DaemonCommand::InitParameters(boost::program_options::options_description&
                ("errorlog,e", po::value<std::string>(), "log fatal errors to the specified log file (only works in combination with --daemonize)")
 #ifndef _WIN32
                ("daemonize,d", "detach from the controlling terminal")
-               ("user,u", po::value<std::string>(), "user to run Icinga as")
-               ("group,g", po::value<std::string>(), "group to run Icinga as")
 #endif /* _WIN32 */
        ;
 
@@ -309,79 +301,6 @@ void DaemonCommand::InitParameters(boost::program_options::options_description&
  */
 int DaemonCommand::Run(const po::variables_map& vm) const
 {
-#ifndef _WIN32
-       if (vm.count("group")) {
-               String group = vm["group"].as<std::string>();
-
-               errno = 0;
-               struct group *gr = getgrnam(group.CStr());
-
-               if (!gr) {
-                       if (errno == 0) {
-                               std::ostringstream msgbuf;
-                               msgbuf << "Invalid group specified: " + group;
-                               Log(LogCritical, "cli",  msgbuf.str());
-                               return EXIT_FAILURE;
-                       } else {
-                               std::ostringstream msgbuf;
-                               msgbuf << "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
-                               Log(LogCritical, "cli",  msgbuf.str());
-                               return EXIT_FAILURE;
-                       }
-               }
-
-               if (!vm.count("reload-internal") && setgroups(0, NULL) < 0) {
-                       std::ostringstream msgbuf;
-                       msgbuf << "setgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
-                       Log(LogCritical, "cli",  msgbuf.str());
-                       return EXIT_FAILURE;
-               }
-
-               if (setgid(gr->gr_gid) < 0) {
-                       std::ostringstream msgbuf;
-                       msgbuf << "setgid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
-                       Log(LogCritical, "cli",  msgbuf.str());
-                       return EXIT_FAILURE;
-               }
-       }
-
-       if (vm.count("user")) {
-               String user = vm["user"].as<std::string>();
-
-               errno = 0;
-               struct passwd *pw = getpwnam(user.CStr());
-
-               if (!pw) {
-                       if (errno == 0) {
-                               std::ostringstream msgbuf;
-                               msgbuf << "Invalid user specified: " + user;
-                               Log(LogCritical, "cli",  msgbuf.str());
-                               return EXIT_FAILURE;
-                       } else {
-                               std::ostringstream msgbuf;
-                               msgbuf << "getpwnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
-                               Log(LogCritical, "cli",  msgbuf.str());
-                               return EXIT_FAILURE;
-                       }
-               }
-
-               // also activate the additional groups the configured user is member of
-               if (!vm.count("reload-internal") && initgroups(user.CStr(), pw->pw_gid) < 0) {
-                       std::ostringstream msgbuf;
-                       msgbuf << "initgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
-                       Log(LogCritical, "cli",  msgbuf.str());
-                       return EXIT_FAILURE;
-               }
-
-               if (setuid(pw->pw_uid) < 0) {
-                       std::ostringstream msgbuf;
-                       msgbuf << "setuid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
-                       Log(LogCritical, "cli",  msgbuf.str());
-                       return EXIT_FAILURE;
-               }
-       }
-#endif /* _WIN32 */
-
        ScriptVariable::Set("UseVfork", true, false, true);
 
        Application::MakeVariablesConstant();
similarity index 61%
rename from lib/cli/pkiinitcacommand.cpp
rename to lib/cli/pkinewcacommand.cpp
index b4117b7af9738fc79a173b16411f1566752a07ba..419115b00498d06a34ed71bf8c440d49def4c5e9 100644 (file)
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
  ******************************************************************************/
 
-#include "cli/pkiinitcacommand.hpp"
+#include "cli/pkinewcacommand.hpp"
 #include "base/logger_fwd.hpp"
 #include "base/clicommand.hpp"
+#include "base/application.hpp"
+#include "base/tlsutility.hpp"
+#include <fstream>
 
 using namespace icinga;
 
-REGISTER_CLICOMMAND("pki/init-ca", PKIInitCACommand);
+REGISTER_CLICOMMAND("pki/new-ca", PKINewCACommand);
 
-String PKIInitCACommand::GetDescription(void) const
+String PKINewCACommand::GetDescription(void) const
 {
        return "Sets up a new Certificate Authority.";
 }
 
-String PKIInitCACommand::GetShortDescription(void) const
+String PKINewCACommand::GetShortDescription(void) const
 {
        return "sets up a new CA";
 }
 
-void PKIInitCACommand::InitParameters(boost::program_options::options_description& visibleDesc,
+void PKINewCACommand::InitParameters(boost::program_options::options_description& visibleDesc,
     boost::program_options::options_description& hiddenDesc) const
 {
        /* Command doesn't support any parameters. */
 }
 
 /**
- * The entry point for the "ca init" CLI command.
+ * The entry point for the "pki new-ca" CLI command.
  *
  * @returns An exit status.
  */
-int PKIInitCACommand::Run(const boost::program_options::variables_map& vm) const
+int PKINewCACommand::Run(const boost::program_options::variables_map& vm) const
 {
-       Log(LogNotice, "cli", "Test!");
-       Log(LogInformation, "cli", "Hello World!");
+       String cadir = Application::GetLocalStateDir() + "/lib/icinga2/ca";
+
+       if (Utility::PathExists(cadir)) {
+               Log(LogCritical, "base", "CA directory '" + cadir + "' already exists.");
+               return 1;
+       }
+       
+       if (!Utility::MkDirP(cadir, 0700)) {
+               Log(LogCritical, "base", "Could not create CA directory '" + cadir + "'.");
+               return 1;
+       }
+       
+       MakeX509CSR("Icinga CA", cadir + "/ca.key", String(), cadir + "/ca.crt");
+       
+       String serialpath = cadir + "/serial.txt";
+
+       Log(LogInformation, "cli", "Initializing serial file in '" + serialpath + "'.");
+               
+       std::ofstream fp;
+       fp.open(serialpath.CStr());
+       fp << "01";
+       fp.close();
 
        return 0;
 }
similarity index 90%
rename from lib/cli/pkiinitcacommand.hpp
rename to lib/cli/pkinewcacommand.hpp
index 66181ed481a0f1e0d7e0723757017f8a791581df..150852579976a61aed339bf472f35d62bbb50771 100644 (file)
@@ -17,8 +17,8 @@
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
  ******************************************************************************/
 
-#ifndef PKIINITCACOMMAND_H
-#define PKIINITCACOMMAND_H
+#ifndef PKINEWCACOMMAND_H
+#define PKINEWCACOMMAND_H
 
 #include "base/qstring.hpp"
 #include "base/clicommand.hpp"
@@ -27,14 +27,14 @@ namespace icinga
 {
 
 /**
- * The "pki init-ca" command.
+ * The "pki new-ca" command.
  *
  * @ingroup cli
  */
-class PKIInitCACommand : public CLICommand
+class PKINewCACommand : public CLICommand
 {
 public:
-       DECLARE_PTR_TYPEDEFS(PKIInitCACommand);
+       DECLARE_PTR_TYPEDEFS(PKINewCACommand);
     
        virtual String GetDescription(void) const;
        virtual String GetShortDescription(void) const;
@@ -46,4 +46,4 @@ public:
 
 }
 
-#endif /* PKIINITCACOMMAND_H */
+#endif /* PKINEWCACOMMAND_H */
similarity index 75%
rename from lib/cli/pkinewcsrcommand.cpp
rename to lib/cli/pkinewcertcommand.cpp
index 1710d73f07eb56fd6727657fcc97454c890fa17f..10c29ff1da2d237fdb53f78969b9f01b4b584928 100644 (file)
@@ -17,7 +17,7 @@
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
  ******************************************************************************/
 
-#include "cli/pkinewcsrcommand.hpp"
+#include "cli/pkinewcertcommand.hpp"
 #include "base/logger_fwd.hpp"
 #include "base/clicommand.hpp"
 #include "base/tlsutility.hpp"
 using namespace icinga;
 namespace po = boost::program_options;
 
-REGISTER_CLICOMMAND("pki/new-csr", PKINewCSRCommand);
+REGISTER_CLICOMMAND("pki/new-cert", PKINewCertCommand);
 
-String PKINewCSRCommand::GetDescription(void) const
+String PKINewCertCommand::GetDescription(void) const
 {
-       return "Creates a new Certificate Signing Request and optionally a self-signed X509 certificate.";
+       return "Creates a new Certificate Signing Request, a self-signed X509 certificate or both.";
 }
 
-String PKINewCSRCommand::GetShortDescription(void) const
+String PKINewCertCommand::GetShortDescription(void) const
 {
        return "creates a new CSR";
 }
 
-void PKINewCSRCommand::InitParameters(boost::program_options::options_description& visibleDesc,
+void PKINewCertCommand::InitParameters(boost::program_options::options_description& visibleDesc,
     boost::program_options::options_description& hiddenDesc) const
 {
        visibleDesc.add_options()
                ("cn", po::value<std::string>(), "Common Name")
                ("keyfile", po::value<std::string>(), "Key file path")
-               ("csrfile", po::value<std::string>(), "CSR file path")
+               ("csrfile", po::value<std::string>(), "CSR file path (optional)")
                ("certfile", po::value<std::string>(), "Certificate file path (optional)");
 }
 
 /**
- * The entry point for the "ca init" CLI command.
+ * The entry point for the "pki new-cert" CLI command.
  *
  * @returns An exit status.
  */
-int PKINewCSRCommand::Run(const boost::program_options::variables_map& vm) const
+int PKINewCertCommand::Run(const boost::program_options::variables_map& vm) const
 {
        if (!vm.count("cn")) {
                Log(LogCritical, "cli", "Common name (--cn) must be specified.");
@@ -64,17 +64,15 @@ int PKINewCSRCommand::Run(const boost::program_options::variables_map& vm) const
                return 1;
        }
 
-       if (!vm.count("csrfile")) {
-               Log(LogCritical, "cli", "CSR file path (--csrfile) must be specified.");
-               return 1;
-       }
-
-       String certfile;
+       String csrfile, certfile;
        
+       if (vm.count("csrfile"))
+               csrfile = vm["csrfile"].as<std::string>();
+
        if (vm.count("certfile"))
                certfile = vm["certfile"].as<std::string>();
        
-       MakeX509CSR(vm["cn"].as<std::string>(), vm["keyfile"].as<std::string>(), vm["csrfile"].as<std::string>(), certfile);
+       MakeX509CSR(vm["cn"].as<std::string>(), vm["keyfile"].as<std::string>(), csrfile, certfile);
 
        return 0;
 }
similarity index 90%
rename from lib/cli/pkinewcsrcommand.hpp
rename to lib/cli/pkinewcertcommand.hpp
index d0c31f42e7d4fc6b96b23781741861a6132c9865..0a463e7bc830c3a5d07e9147e6ff093697624060 100644 (file)
@@ -17,8 +17,8 @@
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
  ******************************************************************************/
 
-#ifndef PKINEWCSRCOMMAND_H
-#define PKINEWCSRCOMMAND_H
+#ifndef PKINEWCERTCOMMAND_H
+#define PKINEWCERTCOMMAND_H
 
 #include "base/qstring.hpp"
 #include "base/clicommand.hpp"
@@ -27,14 +27,14 @@ namespace icinga
 {
 
 /**
- * The "pki new-csr" command.
+ * The "pki new-cert" command.
  *
  * @ingroup cli
  */
-class PKINewCSRCommand : public CLICommand
+class PKINewCertCommand : public CLICommand
 {
 public:
-       DECLARE_PTR_TYPEDEFS(PKINewCSRCommand);
+       DECLARE_PTR_TYPEDEFS(PKINewCertCommand);
     
        virtual String GetDescription(void) const;
        virtual String GetShortDescription(void) const;
@@ -46,4 +46,4 @@ public:
 
 }
 
-#endif /* PKINEWCSRCOMMAND_H */
+#endif /* PKINEWCERTCOMMAND_H */