icinga2/base/utility.cpp

248 lines
6.4 KiB
C++
Raw Normal View History

/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) *
* *
* This program 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 2 *
* of the License, or (at your option) any later version. *
* *
* This program 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 this program; if not, write to the Free Software Foundation *
2012-05-11 13:33:57 +02:00
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
2012-04-22 16:45:31 +02:00
#include "i2-base.h"
#include <mmatch.h>
2012-04-22 16:45:31 +02:00
using namespace icinga;
2012-04-24 14:02:15 +02:00
bool I2_EXPORT Utility::m_SSLInitialized = false;
2012-07-11 20:55:46 +02:00
/**
* Returns a human-readable type name of a type_info object.
*
* @param ti A type_info object.
* @returns The type name of the object.
*/
string Utility::GetTypeName(const type_info& ti)
{
string klass = ti.name();
#ifdef HAVE_GCC_ABI_DEMANGLE
int status;
char *realname = abi::__cxa_demangle(klass.c_str(), 0, 0, &status);
if (realname != NULL) {
klass = string(realname);
free(realname);
}
#endif /* HAVE_GCC_ABI_DEMANGLE */
return klass;
}
2012-04-22 16:45:31 +02:00
/**
* Detaches from the controlling terminal.
*/
void Utility::Daemonize(void) {
#ifndef _WIN32
pid_t pid;
int fd;
pid = fork();
2012-04-23 08:42:24 +02:00
if (pid < 0)
2012-05-26 21:30:04 +02:00
throw PosixException("fork() failed", errno);
2012-04-22 16:45:31 +02:00
if (pid)
exit(0);
fd = open("/dev/null", O_RDWR);
2012-04-23 08:42:24 +02:00
if (fd < 0)
2012-05-26 21:30:04 +02:00
throw PosixException("open() failed", errno);
2012-04-23 08:42:24 +02:00
if (fd != STDIN_FILENO)
dup2(fd, STDIN_FILENO);
2012-04-23 08:42:24 +02:00
if (fd != STDOUT_FILENO)
dup2(fd, STDOUT_FILENO);
2012-04-23 08:42:24 +02:00
if (fd != STDERR_FILENO)
dup2(fd, STDERR_FILENO);
2012-04-23 08:42:24 +02:00
if (fd > STDERR_FILENO)
2012-04-23 08:42:24 +02:00
close(fd);
if (setsid() < 0)
2012-05-26 21:30:04 +02:00
throw PosixException("setsid() failed", errno);
2012-04-22 16:45:31 +02:00
#endif
}
2012-04-24 14:02:15 +02:00
/**
* Initializes the OpenSSL library.
*/
2012-04-24 14:02:15 +02:00
void Utility::InitializeOpenSSL(void)
{
if (m_SSLInitialized)
return;
SSL_library_init();
SSL_load_error_strings();
2012-04-24 14:02:15 +02:00
m_SSLInitialized = true;
2012-04-24 14:02:15 +02:00
}
/**
* Initializes an SSL context using the specified certificates.
*
* @param pubkey The public key.
* @param privkey The matching private key.
* @param cakey CA certificate chain file.
* @returns An SSL context.
*/
2012-04-24 14:02:15 +02:00
shared_ptr<SSL_CTX> Utility::MakeSSLContext(string pubkey, string privkey, string cakey)
{
InitializeOpenSSL();
2012-06-17 16:37:36 +02:00
shared_ptr<SSL_CTX> sslContext = shared_ptr<SSL_CTX>(SSL_CTX_new(TLSv1_method()), SSL_CTX_free);
2012-04-24 14:02:15 +02:00
SSL_CTX_set_mode(sslContext.get(), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
if (!SSL_CTX_use_certificate_chain_file(sslContext.get(), pubkey.c_str()))
2012-05-26 21:30:04 +02:00
throw OpenSSLException("Could not load public X509 key file", ERR_get_error());
2012-04-24 14:02:15 +02:00
if (!SSL_CTX_use_PrivateKey_file(sslContext.get(), privkey.c_str(), SSL_FILETYPE_PEM))
2012-05-26 21:30:04 +02:00
throw OpenSSLException("Could not load private X509 key file", ERR_get_error());
2012-04-24 14:02:15 +02:00
if (!SSL_CTX_load_verify_locations(sslContext.get(), cakey.c_str(), NULL))
2012-05-26 21:30:04 +02:00
throw OpenSSLException("Could not load public CA key file", ERR_get_error());
2012-04-24 14:02:15 +02:00
2012-06-21 12:51:50 +02:00
STACK_OF(X509_NAME) *cert_names;
cert_names = SSL_load_client_CA_file(cakey.c_str());
if (cert_names == NULL)
throw OpenSSLException("SSL_load_client_CA_file() failed", ERR_get_error());
SSL_CTX_set_client_CA_list(sslContext.get(), cert_names);
2012-04-24 14:02:15 +02:00
return sslContext;
}
/**
* Retrieves the common name for an X509 certificate.
*
* @param certificate The X509 certificate.
* @returns The common name.
*/
string Utility::GetCertificateCN(const shared_ptr<X509>& certificate)
{
char buffer[256];
int rc = X509_NAME_get_text_by_NID(X509_get_subject_name(certificate.get()), NID_commonName, buffer, sizeof(buffer));
if (rc == -1)
2012-05-26 21:30:04 +02:00
throw OpenSSLException("X509 certificate has no CN attribute", ERR_get_error());
return buffer;
}
/**
* Retrieves an X509 certificate from the specified file.
*
* @param pemfile The filename.
* @returns An X509 certificate.
*/
shared_ptr<X509> Utility::GetX509Certificate(string pemfile)
{
X509 *cert;
BIO *fpcert = BIO_new(BIO_s_file());
if (fpcert == NULL)
throw OpenSSLException("BIO_new failed", ERR_get_error());
if (BIO_read_filename(fpcert, pemfile.c_str()) < 0)
throw OpenSSLException("BIO_read_filename failed", ERR_get_error());
cert = PEM_read_bio_X509_AUX(fpcert, NULL, NULL, NULL);
if (cert == NULL)
throw OpenSSLException("PEM_read_bio_X509_AUX failed", ERR_get_error());
BIO_free(fpcert);
return shared_ptr<X509>(cert, X509_free);
}
/**
* Performs wildcard pattern matching.
*
* @param pattern The wildcard pattern.
* @param text The string that should be checked.
* @returns true if the wildcard pattern matches, false otherwise.
*/
bool Utility::Match(string pattern, string text)
{
2012-05-09 12:24:47 +02:00
return (match(pattern.c_str(), text.c_str()) == 0);
}
/**
* Returns the directory component of a path. See dirname(3) for details.
*
* @param path The full path.
* @returns The directory.
*/
string Utility::DirName(const string& path)
{
char *dir = strdup(path.c_str());
string result;
if (dir == NULL)
2012-07-08 21:24:20 +02:00
throw std::bad_alloc();
#ifndef _WIN32
result = dirname(dir);
#else /* _WIN32 */
if (!PathRemoveFileSpec(dir)) {
free(dir);
throw Win32Exception("PathRemoveFileSpec() failed", GetLastError());
}
result = dir;
#endif /* _WIN32 */
free(dir);
return result;
}
/**
* Returns the file component of a path. See basename(3) for details.
*
* @param path The full path.
* @returns The filename.
*/
string Utility::BaseName(const string& path)
{
char *dir = strdup(path.c_str());
string result;
if (dir == NULL)
2012-07-08 21:24:20 +02:00
throw std::bad_alloc();
#ifndef _WIN32
result = basename(dir);
#else /* _WIN32 */
result = PathFindFileName(dir);
#endif /* _WIN32 */
free(dir);
return result;
}