Merge pull request #3267 from Carbenium/crypto-hashing
Crypto: Implement a generic hashing API
This commit is contained in:
commit
4f2945bd57
|
@ -371,7 +371,6 @@ if (${ZM_CRYPTO_BACKEND} STREQUAL "gnutls")
|
|||
set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}")
|
||||
endif()
|
||||
mark_as_advanced(FORCE GNUTLS_LIBRARIES GNUTLS_INCLUDE_DIR)
|
||||
check_include_file("gnutls/gnutls.h" HAVE_GNUTLS_GNUTLS_H)
|
||||
set(optlibsfound "${optlibsfound} GnuTLS")
|
||||
else()
|
||||
set(optlibsnotfound "${optlibsnotfound} GnuTLS")
|
||||
|
@ -381,11 +380,9 @@ elseif (${ZM_CRYPTO_BACKEND} STREQUAL "openssl")
|
|||
find_package(OpenSSL REQUIRED)
|
||||
if(OPENSSL_FOUND)
|
||||
set(HAVE_LIBOPENSSL 1)
|
||||
set(HAVE_LIBCRYPTO 1)
|
||||
list(APPEND ZM_BIN_LIBS "${OPENSSL_LIBRARIES}")
|
||||
include_directories("${OPENSSL_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
|
||||
check_include_file("openssl/md5.h" HAVE_OPENSSL_MD5_H)
|
||||
set(optlibsfound "${optlibsfound} OpenSSL")
|
||||
else()
|
||||
set(optlibsnotfound "${optlibsnotfound} OpenSSL")
|
||||
|
@ -679,41 +676,6 @@ if(ZM_ONVIF)
|
|||
set(ZM_HAS_ONVIF 1)
|
||||
endif()
|
||||
|
||||
# Check for authentication functions
|
||||
if(HAVE_OPENSSL_MD5_H)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
|
||||
check_prototype_definition(
|
||||
MD5
|
||||
"unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)" "NULL" "openssl/md5.h"
|
||||
HAVE_MD5_OPENSSL)
|
||||
endif()
|
||||
|
||||
if(HAVE_GNUTLS_GNUTLS_H)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${GNUTLS_LIBRARIES}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}")
|
||||
check_prototype_definition(
|
||||
gnutls_fingerprint
|
||||
"int gnutls_fingerprint (gnutls_digest_algorithm_t algo, const gnutls_datum_t * data, void *result, size_t * result_size)" "0" "stdlib.h;gnutls/gnutls.h"
|
||||
HAVE_DECL_GNUTLS_FINGERPRINT)
|
||||
endif()
|
||||
|
||||
if(NOT HAVE_DECL_GNUTLS_FINGERPRINT AND HAVE_MD5_OPENSSL)
|
||||
set(HAVE_DECL_MD5 1)
|
||||
endif()
|
||||
|
||||
if((NOT HAVE_MD5_OPENSSL) AND (NOT HAVE_DECL_GNUTLS_FINGERPRINT))
|
||||
message(AUTHOR_WARNING
|
||||
"ZoneMinder requires a working MD5 function for hashed authentication but
|
||||
none were found - hashed authentication will not be available")
|
||||
endif()
|
||||
|
||||
# Dirty fix for zm_user only using openssl's md5 if gnutls is not available.
|
||||
# This needs to be fixed in zm_user.[h,cpp] but such fix will also require changes to configure.ac
|
||||
if(HAVE_LIBCRYPTO AND HAVE_OPENSSL_MD5_H AND HAVE_MD5_OPENSSL)
|
||||
set(HAVE_GNUTLS_OPENSSL_H 0)
|
||||
endif()
|
||||
|
||||
# Check for Perl
|
||||
find_package(Perl)
|
||||
if(NOT PERL_FOUND)
|
||||
|
|
|
@ -15,7 +15,6 @@ DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
|||
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
|
||||
CFLAGS = -Wall
|
||||
CXXFLAGS = -DHAVE_LIBCRYPTO
|
||||
|
||||
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
|
||||
DEBOPT = --enable-debug
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "zm_crypt.h"
|
||||
|
||||
#include "zm_logger.h"
|
||||
#include "zm_utils.h"
|
||||
#include "BCrypt.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
@ -11,13 +12,6 @@
|
|||
#include <jwt-cpp/jwt.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_LIBCRYPTO
|
||||
#include <openssl/sha.h>
|
||||
#elif HAVE_GNUTLS_GNUTLS_H
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/crypto.h>
|
||||
#endif
|
||||
|
||||
// returns username if valid, "" if not
|
||||
#if HAVE_LIBJWT
|
||||
std::pair <std::string, unsigned int> verifyToken(std::string jwt_token_str, std::string key) {
|
||||
|
@ -135,6 +129,8 @@ std::pair <std::string, unsigned int> verifyToken(std::string jwt_token_str, std
|
|||
#endif // HAVE_LIBJWT
|
||||
|
||||
bool verifyPassword(const char *username, const char *input_password, const char *db_password_hash) {
|
||||
using namespace zm::crypto;
|
||||
|
||||
bool password_correct = false;
|
||||
if ( strlen(db_password_hash) < 4 ) {
|
||||
// actually, shoud be more, but this is min. for next code
|
||||
|
@ -143,47 +139,13 @@ bool verifyPassword(const char *username, const char *input_password, const char
|
|||
}
|
||||
if ( db_password_hash[0] == '*' ) {
|
||||
// MYSQL PASSWORD
|
||||
Debug(1, "%s is using an MD5 encoded password", username);
|
||||
Debug(1, "%s is using an SHA1 encoded password", username);
|
||||
|
||||
#ifndef SHA_DIGEST_LENGTH
|
||||
#define SHA_DIGEST_LENGTH 20
|
||||
#endif
|
||||
SHA1::Digest digest = SHA1::GetDigestOf(SHA1::GetDigestOf(input_password));
|
||||
std::string hex_digest = '*' + StringToUpper(ByteArrayToHexString(digest));
|
||||
|
||||
#if HAVE_LIBCRYPTO
|
||||
unsigned char digest_interim[SHA_DIGEST_LENGTH];
|
||||
unsigned char digest_final[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx1, ctx2;
|
||||
|
||||
//get first iteration
|
||||
SHA1_Init(&ctx1);
|
||||
SHA1_Update(&ctx1, input_password, strlen(input_password));
|
||||
SHA1_Final(digest_interim, &ctx1);
|
||||
|
||||
//2nd iteration
|
||||
SHA1_Init(&ctx2);
|
||||
SHA1_Update(&ctx2, digest_interim,SHA_DIGEST_LENGTH);
|
||||
SHA1_Final(digest_final, &ctx2);
|
||||
#elif HAVE_GNUTLS_GNUTLS_H
|
||||
unsigned char digest_interim[SHA_DIGEST_LENGTH];
|
||||
unsigned char digest_final[SHA_DIGEST_LENGTH];
|
||||
//get first iteration
|
||||
gnutls_hash_fast(GNUTLS_DIG_SHA1, input_password, strlen(input_password), digest_interim);
|
||||
//2nd iteration
|
||||
gnutls_hash_fast(GNUTLS_DIG_SHA1, digest_interim, SHA_DIGEST_LENGTH, digest_final);
|
||||
#else
|
||||
Error("Authentication Error. ZoneMinder not built with GnuTLS or Openssl");
|
||||
return false;
|
||||
#endif
|
||||
|
||||
char final_hash[SHA_DIGEST_LENGTH * 2 +2];
|
||||
final_hash[0] = '*';
|
||||
//convert to hex
|
||||
for ( int i = 0; i < SHA_DIGEST_LENGTH; i++ )
|
||||
sprintf(&final_hash[i*2]+1, "%02X", (unsigned int)digest_final[i]);
|
||||
final_hash[SHA_DIGEST_LENGTH *2 + 1] = 0;
|
||||
|
||||
Debug(1, "Computed password_hash:%s, stored password_hash:%s", final_hash, db_password_hash);
|
||||
password_correct = (strcmp(db_password_hash, final_hash)==0);
|
||||
Debug(1, "Computed password_hash: %s, stored password_hash: %s", hex_digest.c_str(), db_password_hash);
|
||||
password_correct = (strcmp(db_password_hash, hex_digest.c_str()) == 0);
|
||||
} else if (
|
||||
(db_password_hash[0] == '$')
|
||||
&&
|
||||
|
|
|
@ -20,10 +20,36 @@
|
|||
#ifndef ZM_CRYPT_H
|
||||
#define ZM_CRYPT_H
|
||||
|
||||
#include "zm_config.h"
|
||||
#include "zm_crypto_gnutls.h"
|
||||
#include "zm_crypto_openssl.h"
|
||||
#include "zm_define.h"
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
bool verifyPassword( const char *username, const char *input_password, const char *db_password_hash);
|
||||
bool verifyPassword(const char *username, const char *input_password, const char *db_password_hash);
|
||||
|
||||
std::pair<std::string, unsigned int> verifyToken(std::string token, std::string key);
|
||||
|
||||
namespace zm {
|
||||
namespace crypto {
|
||||
namespace impl {
|
||||
|
||||
#if defined(HAVE_LIBGNUTLS)
|
||||
template<HashAlgorithms Algorithm>
|
||||
using Hash = gnutls::GenericHashImpl<Algorithm>;
|
||||
#elif defined(HAVE_LIBOPENSSL)
|
||||
template<HashAlgorithms Algorithm>
|
||||
using Hash = openssl::GenericHashImpl<Algorithm>;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace zm {
|
||||
namespace crypto {
|
||||
using MD5 = impl::Hash<impl::HashAlgorithms::kMD5>;
|
||||
using SHA1 = impl::Hash<impl::HashAlgorithms::kSHA1>;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair <std::string, unsigned int> verifyToken(std::string token, std::string key);
|
||||
#endif // ZM_CRYPT_H
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* This file is part of the ZoneMinder Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZONEMINDER_SRC_ZM_CRYPTO_GENERICS_H_
|
||||
#define ZONEMINDER_SRC_ZM_CRYPTO_GENERICS_H_
|
||||
|
||||
#include "zm_define.h"
|
||||
#include "zm_utils.h"
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
namespace zm {
|
||||
namespace crypto {
|
||||
namespace impl {
|
||||
|
||||
enum class HashAlgorithms {
|
||||
kMD5,
|
||||
kSHA1
|
||||
};
|
||||
|
||||
template<HashAlgorithms Algorithm>
|
||||
struct HashAlgorithm;
|
||||
|
||||
template<>
|
||||
struct HashAlgorithm<HashAlgorithms::kMD5> {
|
||||
static constexpr size_t digest_length = 16;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct HashAlgorithm<HashAlgorithms::kSHA1> {
|
||||
static constexpr size_t digest_length = 20;
|
||||
};
|
||||
|
||||
template<typename Impl, HashAlgorithms Algorithm>
|
||||
class GenericHash {
|
||||
public:
|
||||
static constexpr size_t DIGEST_LENGTH = HashAlgorithm<Algorithm>::digest_length;
|
||||
using Digest = std::array<uint8, DIGEST_LENGTH>;
|
||||
|
||||
static Digest GetDigestOf(uint8 const *data, size_t len) {
|
||||
Impl hash;
|
||||
hash.UpdateData(data, len);
|
||||
hash.Finalize();
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
template<typename... Ts>
|
||||
static Digest GetDigestOf(Ts &&... pack) {
|
||||
Impl hash;
|
||||
UpdateData(hash, std::forward<Ts>(pack)...);
|
||||
hash.Finalize();
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
void UpdateData(const uint8 *data, size_t length) {
|
||||
static_cast<Impl &>(*this).DoUpdateData(data, length);
|
||||
}
|
||||
void UpdateData(const std::string &str) {
|
||||
UpdateData(reinterpret_cast<const uint8 *>(str.c_str()), str.size());
|
||||
}
|
||||
void UpdateData(const char *str) {
|
||||
UpdateData(reinterpret_cast<const uint8 *>(str), strlen(str));
|
||||
}
|
||||
template<typename Container>
|
||||
void UpdateData(Container const &c) {
|
||||
UpdateData(ZM::data(c), ZM::size(c));
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
static_cast<Impl &>(*this).DoFinalize();
|
||||
}
|
||||
|
||||
const Digest &GetDigest() const { return digest_; }
|
||||
|
||||
protected:
|
||||
Digest digest_ = {};
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static void UpdateData(Impl &hash, T const &data) {
|
||||
hash.UpdateData(data);
|
||||
}
|
||||
|
||||
template<typename T, typename... TRest>
|
||||
static void UpdateData(Impl &hash, T const &data, TRest &&... rest) {
|
||||
hash.UpdateData(data);
|
||||
UpdateData(hash, std::forward<TRest>(rest)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //ZONEMINDER_SRC_ZM_CRYPTO_GENERICS_H_
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* This file is part of the ZoneMinder Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZONEMINDER_SRC_ZM_CRYPTO_GNUTLS_H_
|
||||
#define ZONEMINDER_SRC_ZM_CRYPTO_GNUTLS_H_
|
||||
|
||||
#ifdef HAVE_LIBGNUTLS
|
||||
|
||||
#include "zm_crypto_generics.h"
|
||||
#include "zm_utils.h"
|
||||
#include <gnutls/crypto.h>
|
||||
|
||||
namespace zm {
|
||||
namespace crypto {
|
||||
namespace impl {
|
||||
namespace gnutls {
|
||||
|
||||
template<HashAlgorithms Algorithm>
|
||||
struct HashAlgorithmMapper;
|
||||
|
||||
template<>
|
||||
struct HashAlgorithmMapper<HashAlgorithms::kMD5> {
|
||||
static constexpr gnutls_digest_algorithm_t algorithm = GNUTLS_DIG_MD5;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct HashAlgorithmMapper<HashAlgorithms::kSHA1> {
|
||||
static constexpr gnutls_digest_algorithm_t algorithm = GNUTLS_DIG_SHA1;
|
||||
};
|
||||
|
||||
template<HashAlgorithms Algorithm>
|
||||
class GenericHashImpl : public GenericHash<GenericHashImpl<Algorithm>, Algorithm> {
|
||||
public:
|
||||
GenericHashImpl() {
|
||||
int32 ret = gnutls_hash_init(&handle_, HashAlgorithmMapper<Algorithm>::algorithm);
|
||||
ASSERT(ret == 0);
|
||||
};
|
||||
|
||||
void DoUpdateData(const uint8 *data, size_t length) {
|
||||
int32 res = gnutls_hash(handle_, data, length);
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
void DoFinalize() {
|
||||
gnutls_hash_deinit(handle_, digest_.data());
|
||||
}
|
||||
|
||||
private:
|
||||
gnutls_hash_hd_t handle_ = {};
|
||||
|
||||
using Base = GenericHash<GenericHashImpl<Algorithm>, Algorithm>;
|
||||
using Base::digest_;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_LIBGNUTLS
|
||||
|
||||
#endif // ZONEMINDER_SRC_ZM_CRYPTO_GNUTLS_H_
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* This file is part of the ZoneMinder Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZONEMINDER_SRC_ZM_CRYPTO_OPENSSL_H_
|
||||
#define ZONEMINDER_SRC_ZM_CRYPTO_OPENSSL_H_
|
||||
|
||||
#ifdef HAVE_LIBOPENSSL
|
||||
|
||||
#include "zm_crypto_generics.h"
|
||||
#include "zm_utils.h"
|
||||
#include <openssl/evp.h>
|
||||
|
||||
namespace zm {
|
||||
namespace crypto {
|
||||
namespace impl {
|
||||
namespace openssl {
|
||||
|
||||
typedef EVP_MD const *(*HashCreator)();
|
||||
|
||||
template<HashAlgorithms Algorithm>
|
||||
struct HashAlgorithmMapper;
|
||||
|
||||
template<>
|
||||
struct HashAlgorithmMapper<HashAlgorithms::kMD5> {
|
||||
// TODO: Remove conditional once Jessie and CentOS 7 are deprecated
|
||||
// This is needed since GCC 4.8 is faulty (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60199)
|
||||
#if defined(__GNUC__) && __GNUC__ < 5
|
||||
static HashCreator hash_creator() {
|
||||
static constexpr HashCreator creator = EVP_md5;
|
||||
return creator;
|
||||
}
|
||||
#else
|
||||
static constexpr HashCreator hash_creator = EVP_md5;
|
||||
#endif
|
||||
};
|
||||
|
||||
template<>
|
||||
struct HashAlgorithmMapper<HashAlgorithms::kSHA1> {
|
||||
// TODO: Remove conditional once Jessie and CentOS 7 are deprecated
|
||||
// This is needed since GCC 4.8 is faulty (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60199)
|
||||
#if defined(__GNUC__) && __GNUC__ < 5
|
||||
static HashCreator hash_creator() {
|
||||
static constexpr HashCreator creator = EVP_sha1;
|
||||
return creator;
|
||||
}
|
||||
#else
|
||||
static constexpr HashCreator hash_creator = EVP_sha1;
|
||||
#endif
|
||||
};
|
||||
|
||||
template<HashAlgorithms Algorithm>
|
||||
class GenericHashImpl : public GenericHash<GenericHashImpl<Algorithm>, Algorithm> {
|
||||
public:
|
||||
GenericHashImpl() {
|
||||
// TODO: Use EVP_MD_CTX_new once we drop support for Jessie and CentOS 7 (OpenSSL > 1.1.0)
|
||||
ctx_ = EVP_MD_CTX_create();
|
||||
#if defined(__GNUC__) && __GNUC__ < 5
|
||||
EVP_DigestInit_ex(ctx_, HashAlgorithmMapper<Algorithm>::hash_creator()(), nullptr);
|
||||
#else
|
||||
EVP_DigestInit_ex(ctx_, HashAlgorithmMapper<Algorithm>::hash_creator(), nullptr);
|
||||
#endif
|
||||
};
|
||||
|
||||
~GenericHashImpl() {
|
||||
// TODO: Use EVP_MD_CTX_free once we drop support for Jessie and CentOS 7 (OpenSSL > 1.1.0)
|
||||
EVP_MD_CTX_destroy(ctx_);
|
||||
}
|
||||
|
||||
void DoUpdateData(const uint8 *data, size_t length) {
|
||||
int32 res = EVP_DigestUpdate(ctx_, data, length);
|
||||
ASSERT(res == 1);
|
||||
}
|
||||
|
||||
void DoFinalize() {
|
||||
uint32 length = 0;
|
||||
int32 res = EVP_DigestFinal_ex(ctx_, digest_.data(), &length);
|
||||
ASSERT(res == 1);
|
||||
ASSERT(length == HashAlgorithm<Algorithm>::digest_length);
|
||||
}
|
||||
|
||||
private:
|
||||
EVP_MD_CTX *ctx_;
|
||||
|
||||
using Base = GenericHash<GenericHashImpl<Algorithm>, Algorithm>;
|
||||
using Base::digest_;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_LIBOPENSSL
|
||||
|
||||
#endif // ZONEMINDER_SRC_ZM_CRYPTO_OPENSSL_H_
|
|
@ -285,7 +285,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
|
||||
// Set transport method as specified by method field, rtpUni is default
|
||||
std::string protocol = mPath.substr(0, 4);
|
||||
StringToUpper(protocol);
|
||||
protocol = StringToUpper(protocol);
|
||||
if ( protocol == "RTSP" ) {
|
||||
const std::string method = Method();
|
||||
if ( method == "rtpMulti" ) {
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include "zm_define.h"
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include "span.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
|
||||
#include "zm_rtsp_auth.h"
|
||||
|
||||
#include "zm_crypt.h"
|
||||
#include "zm_logger.h"
|
||||
#include "zm_utils.h"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
|
@ -119,74 +119,36 @@ std::string Authenticator::getAuthHeader(const std::string &method, const std::s
|
|||
}
|
||||
|
||||
std::string Authenticator::computeDigestResponse(const std::string &method, const std::string &uri) {
|
||||
#if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
// The "response" field is computed as:
|
||||
// md5(md5(<username>:<realm>:<password>):<nonce>:md5(<cmd>:<url>))
|
||||
constexpr size_t md5len = 16;
|
||||
uint8 md5buf[md5len];
|
||||
char md5HexBuf[md5len * 2 + 1];
|
||||
|
||||
// Step 1: md5(<username>:<realm>:<password>)
|
||||
std::string ha1Data = username() + ":" + realm() + ":" + password();
|
||||
Debug( 2, "HA1 pre-md5: %s", ha1Data.c_str() );
|
||||
#if HAVE_DECL_MD5
|
||||
MD5((unsigned char*)ha1Data.c_str(), ha1Data.length(), md5buf);
|
||||
#elif HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
gnutls_datum_t md5dataha1 = {(unsigned char *) ha1Data.c_str(), (unsigned int) ha1Data.length()};
|
||||
size_t md5_len_tmp = md5len;
|
||||
gnutls_fingerprint(GNUTLS_DIG_MD5, &md5dataha1, md5buf, &md5_len_tmp);
|
||||
assert(md5_len_tmp == md5len);
|
||||
#endif
|
||||
for ( unsigned int j = 0; j < md5len; j++ ) {
|
||||
sprintf(&md5HexBuf[2*j], "%02x", md5buf[j] );
|
||||
}
|
||||
md5HexBuf[md5len*2]='\0';
|
||||
std::string ha1Hash = md5HexBuf;
|
||||
Debug(2, "HA1 pre-md5: %s", ha1Data.c_str());
|
||||
|
||||
zm::crypto::MD5::Digest md5_digest = zm::crypto::MD5::GetDigestOf(ha1Data);
|
||||
std::string ha1Hash = ByteArrayToHexString(md5_digest);
|
||||
|
||||
// Step 2: md5(<cmd>:<url>)
|
||||
std::string ha2Data = method + ":" + uri;
|
||||
Debug( 2, "HA2 pre-md5: %s", ha2Data.c_str() );
|
||||
#if HAVE_DECL_MD5
|
||||
MD5((unsigned char*)ha2Data.c_str(), ha2Data.length(), md5buf );
|
||||
#elif HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
gnutls_datum_t md5dataha2 = {(unsigned char *) ha2Data.c_str(), (unsigned int) ha2Data.length()};
|
||||
md5_len_tmp = md5len;
|
||||
gnutls_fingerprint(GNUTLS_DIG_MD5, &md5dataha2, md5buf, &md5_len_tmp);
|
||||
assert(md5_len_tmp == md5len);
|
||||
#endif
|
||||
for ( unsigned int j = 0; j < md5len; j++ ) {
|
||||
sprintf( &md5HexBuf[2*j], "%02x", md5buf[j] );
|
||||
}
|
||||
md5HexBuf[md5len*2]='\0';
|
||||
std::string ha2Hash = md5HexBuf;
|
||||
Debug(2, "HA2 pre-md5: %s", ha2Data.c_str());
|
||||
|
||||
md5_digest = zm::crypto::MD5::GetDigestOf(ha2Data);
|
||||
std::string ha2Hash = ByteArrayToHexString(md5_digest);
|
||||
|
||||
// Step 3: md5(ha1:<nonce>:ha2)
|
||||
std::string digestData = ha1Hash + ":" + nonce();
|
||||
if ( ! fQop.empty() ) {
|
||||
digestData += ":" + stringtf("%08x", nc) + ":"+fCnonce + ":" + fQop;
|
||||
nc ++;
|
||||
if (!fQop.empty()) {
|
||||
digestData += ":" + stringtf("%08x", nc) + ":" + fCnonce + ":" + fQop;
|
||||
nc++;
|
||||
// if qop was specified, then we have to include t and a cnonce and an nccount
|
||||
}
|
||||
digestData += ":" + ha2Hash;
|
||||
Debug( 2, "pre-md5: %s", digestData.c_str() );
|
||||
#if HAVE_DECL_MD5
|
||||
MD5((unsigned char*)digestData.c_str(), digestData.length(), md5buf);
|
||||
#elif HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
gnutls_datum_t md5datadigest = {(unsigned char *) digestData.c_str(), (unsigned int) digestData.length()};
|
||||
md5_len_tmp = md5len;
|
||||
gnutls_fingerprint(GNUTLS_DIG_MD5, &md5datadigest, md5buf, &md5_len_tmp);
|
||||
assert(md5_len_tmp == md5len);
|
||||
#endif
|
||||
for ( unsigned int j = 0; j < md5len; j++ ) {
|
||||
sprintf( &md5HexBuf[2*j], "%02x", md5buf[j] );
|
||||
}
|
||||
md5HexBuf[md5len*2]='\0';
|
||||
Debug(2, "pre-md5: %s", digestData.c_str());
|
||||
|
||||
return md5HexBuf;
|
||||
#else // HAVE_DECL_MD5
|
||||
Error("You need to build with gnutls or openssl installed to use digest authentication");
|
||||
return 0;
|
||||
#endif // HAVE_DECL_MD5
|
||||
md5_digest = zm::crypto::MD5::GetDigestOf(digestData);
|
||||
|
||||
return ByteArrayToHexString(md5_digest);
|
||||
}
|
||||
|
||||
void Authenticator::checkAuthResponse(const std::string &response) {
|
||||
|
|
|
@ -22,14 +22,6 @@
|
|||
#include "zm_config.h"
|
||||
#include <string>
|
||||
|
||||
#if HAVE_GNUTLS_GNUTLS_H
|
||||
#include <gnutls/gnutls.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_LIBCRYPTO
|
||||
#include <openssl/md5.h>
|
||||
#endif // HAVE_LIBCRYPTO
|
||||
|
||||
namespace zm {
|
||||
|
||||
enum AuthMethod { AUTH_UNDEFINED = 0, AUTH_BASIC = 1, AUTH_DIGEST = 2 };
|
||||
|
|
|
@ -22,17 +22,8 @@
|
|||
#include "zm_crypt.h"
|
||||
#include "zm_logger.h"
|
||||
#include "zm_utils.h"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#if HAVE_GNUTLS_GNUTLS_H
|
||||
#include <gnutls/gnutls.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_LIBCRYPTO
|
||||
#include <openssl/md5.h>
|
||||
#endif // HAVE_LIBCRYPTO
|
||||
|
||||
User::User() {
|
||||
id = 0;
|
||||
username[0] = password[0] = 0;
|
||||
|
@ -189,11 +180,10 @@ User *zmLoadTokenUser(const std::string &jwt_token_str, bool use_remote_addr) {
|
|||
|
||||
// Function to validate an authentication string
|
||||
User *zmLoadAuthUser(const char *auth, bool use_remote_addr) {
|
||||
#if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
const char *remote_addr = "";
|
||||
if ( use_remote_addr ) {
|
||||
if (use_remote_addr) {
|
||||
remote_addr = getenv("REMOTE_ADDR");
|
||||
if ( !remote_addr ) {
|
||||
if (!remote_addr) {
|
||||
Warning("Can't determine remote address, using null");
|
||||
remote_addr = "";
|
||||
}
|
||||
|
@ -209,7 +199,7 @@ User *zmLoadAuthUser(const char *auth, bool use_remote_addr) {
|
|||
return nullptr;
|
||||
|
||||
int n_users = mysql_num_rows(result);
|
||||
if ( n_users < 1 ) {
|
||||
if (n_users < 1) {
|
||||
mysql_free_result(result);
|
||||
Warning("Unable to authenticate user");
|
||||
return nullptr;
|
||||
|
@ -218,28 +208,23 @@ User *zmLoadAuthUser(const char *auth, bool use_remote_addr) {
|
|||
// getting the time is expensive, so only do it once.
|
||||
time_t now = time(nullptr);
|
||||
unsigned int hours = config.auth_hash_ttl;
|
||||
if ( !hours ) {
|
||||
if (!hours) {
|
||||
Warning("No value set for ZM_AUTH_HASH_TTL. Defaulting to 2.");
|
||||
hours = 2;
|
||||
} else {
|
||||
Debug(1, "AUTH_HASH_TTL is %d, time is %" PRIi64, hours, static_cast<int64>(now));
|
||||
}
|
||||
char auth_key[512] = "";
|
||||
char auth_md5[32+1] = "";
|
||||
constexpr size_t md5len = 16;
|
||||
uint8 md5sum[md5len];
|
||||
|
||||
const char * hex = "0123456789abcdef";
|
||||
while ( MYSQL_ROW dbrow = mysql_fetch_row(result) ) {
|
||||
while (MYSQL_ROW dbrow = mysql_fetch_row(result)) {
|
||||
const char *username = dbrow[1];
|
||||
const char *password = dbrow[2];
|
||||
|
||||
time_t our_now = now;
|
||||
tm now_tm = {};
|
||||
for ( unsigned int i = 0; i < hours; i++, our_now -= 3600 ) {
|
||||
for (unsigned int i = 0; i < hours; i++, our_now -= 3600) {
|
||||
localtime_r(&our_now, &now_tm);
|
||||
|
||||
snprintf(auth_key, sizeof(auth_key)-1, "%s%s%s%s%d%d%d%d",
|
||||
std::string auth_key = stringtf("%s%s%s%s%d%d%d%d",
|
||||
config.auth_hash_secret,
|
||||
username,
|
||||
password,
|
||||
|
@ -249,27 +234,12 @@ User *zmLoadAuthUser(const char *auth, bool use_remote_addr) {
|
|||
now_tm.tm_mon,
|
||||
now_tm.tm_year);
|
||||
|
||||
#if HAVE_DECL_MD5
|
||||
MD5((unsigned char *)auth_key, strlen(auth_key), md5sum);
|
||||
#elif HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
gnutls_datum_t md5data = {(unsigned char *) auth_key, (unsigned int) strlen(auth_key)};
|
||||
size_t md5_len_tmp = md5len;
|
||||
gnutls_fingerprint(GNUTLS_DIG_MD5, &md5data, md5sum, &md5_len_tmp);
|
||||
assert(md5_len_tmp == md5len);
|
||||
#endif
|
||||
unsigned char *md5sum_ptr = md5sum;
|
||||
char *auth_md5_ptr = auth_md5;
|
||||
zm::crypto::MD5::Digest md5_digest = zm::crypto::MD5::GetDigestOf(auth_key);
|
||||
std::string auth_md5 = ByteArrayToHexString(md5_digest);
|
||||
|
||||
for ( unsigned int j = 0; j < md5len; j++ ) {
|
||||
*auth_md5_ptr++ = hex[(*md5sum_ptr>>4)&0xf];
|
||||
*auth_md5_ptr++ = hex[(*md5sum_ptr++)&0xf];
|
||||
}
|
||||
*auth_md5_ptr = 0;
|
||||
Debug(1, "Checking auth_key '%s' -> auth_md5 '%s' == '%s'", auth_key.c_str(), auth_md5.c_str(), auth);
|
||||
|
||||
Debug(1, "Checking auth_key '%s' -> auth_md5 '%s' == '%s'",
|
||||
auth_key, auth_md5, auth);
|
||||
|
||||
if ( !strcmp(auth, auth_md5) ) {
|
||||
if (!strcmp(auth, auth_md5.c_str())) {
|
||||
// We have a match
|
||||
User *user = new User(dbrow);
|
||||
Debug(1, "Authenticated user '%s'", user->getUsername());
|
||||
|
@ -281,9 +251,7 @@ User *zmLoadAuthUser(const char *auth, bool use_remote_addr) {
|
|||
} // end foreach hour
|
||||
} // end foreach user
|
||||
mysql_free_result(result);
|
||||
#else // HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
Error("You need to build with gnutls or openssl to use hash based auth");
|
||||
#endif // HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
|
||||
Debug(1, "No user found for auth_key %s", auth);
|
||||
return nullptr;
|
||||
} // end User *zmLoadAuthUser( const char *auth, bool use_remote_addr )
|
||||
|
|
|
@ -116,6 +116,23 @@ std::string Join(const StringVector &values, const std::string &delim) {
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
std::string ByteArrayToHexString(nonstd::span<const uint8> bytes) {
|
||||
static constexpr char lowercase_table[] = "0123456789abcdef";
|
||||
std::string buf;
|
||||
buf.resize(2 * bytes.size());
|
||||
|
||||
const uint8 *srcPtr = bytes.data();
|
||||
char *dstPtr = &buf[0];
|
||||
|
||||
for (size_t i = 0; i < bytes.size(); ++i) {
|
||||
uint8 c = *srcPtr++;
|
||||
*dstPtr++ = lowercase_table[c >> 4];
|
||||
*dstPtr++ = lowercase_table[c & 0x0f];
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string Base64Encode(const std::string &str) {
|
||||
static char base64_table[64] = {'\0'};
|
||||
|
||||
|
|
|
@ -20,23 +20,36 @@
|
|||
#ifndef ZM_UTILS_H
|
||||
#define ZM_UTILS_H
|
||||
|
||||
#include "zm_define.h"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "span.hpp"
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sys/time.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ASSERT(x) do { (void) sizeof(x); } while (0)
|
||||
#else
|
||||
#include <cassert>
|
||||
#define ASSERT(x) assert(x)
|
||||
#endif
|
||||
|
||||
typedef std::vector<std::string> StringVector;
|
||||
|
||||
std::string Trim(const std::string &str, const std::string &char_set);
|
||||
inline std::string TrimSpaces(const std::string &str) { return Trim(str, " \t"); }
|
||||
std::string ReplaceAll(std::string str, const std::string& old_value, const std::string& new_value);
|
||||
inline void StringToUpper(std::string &str) { std::transform(str.begin(), str.end(), str.begin(), ::toupper); }
|
||||
std::string ReplaceAll(std::string str, const std::string &old_value, const std::string &new_value);
|
||||
inline std::string StringToUpper(std::string str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
|
||||
return str;
|
||||
}
|
||||
|
||||
StringVector Split(const std::string &str, char delim);
|
||||
StringVector Split(const std::string &str, const std::string &delim, size_t limit = 0);
|
||||
|
@ -59,6 +72,8 @@ std::string stringtf(const std::string &format, Args... args) {
|
|||
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
||||
}
|
||||
|
||||
std::string ByteArrayToHexString(nonstd::span<const uint8> bytes);
|
||||
|
||||
std::string Base64Encode(const std::string &str);
|
||||
|
||||
void TimespecDiff(timespec *start, timespec *end, timespec *diff);
|
||||
|
@ -72,32 +87,53 @@ void *sse2_aligned_memcpy(void *dest, const void *src, size_t bytes);
|
|||
void touch(const char *pathname);
|
||||
|
||||
namespace ZM {
|
||||
//! std::make_unique implementation (TODO: remove this once C++14 is supported)
|
||||
// C++14 std::make_unique (TODO: remove this once C++14 is supported)
|
||||
template<typename T, typename ...Args>
|
||||
inline auto make_unique(Args &&...args) ->
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type {
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline auto make_unique(std::size_t size) ->
|
||||
typename std::enable_if<std::is_array<T>::value && std::extent<T>::value == 0, std::unique_ptr<T>>::type {
|
||||
return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline auto make_unique(Args &&...) ->
|
||||
typename std::enable_if<std::extent<T>::value != 0, void>::type = delete;
|
||||
|
||||
// C++17 std::clamp (TODO: remove this once C++17 is supported)
|
||||
template<class T, class Compare>
|
||||
constexpr const T &clamp(const T &v, const T &lo, const T &hi, Compare comp) {
|
||||
return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr const T &clamp(const T &v, const T &lo, const T &hi) {
|
||||
return ZM::clamp(v, lo, hi, std::less<T>{});
|
||||
}
|
||||
|
||||
// C++17 std::data (TODO: remove this once C++17 is supported)
|
||||
template<typename C>
|
||||
constexpr auto data(C &c) -> decltype(c.data()) { return c.data(); }
|
||||
|
||||
template<typename C>
|
||||
constexpr auto data(C const &c) -> decltype(c.data()) { return c.data(); }
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
constexpr T *data(T(&a)[N]) noexcept { return a; }
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
constexpr T const *data(const T(&a)[N]) noexcept { return a; }
|
||||
|
||||
template<typename T>
|
||||
constexpr T const *data(std::initializer_list<T> l) noexcept { return l.begin(); }
|
||||
|
||||
// C++17 std::size (TODO: remove this once C++17 is supported)
|
||||
template<typename C>
|
||||
constexpr auto size(const C &c) -> decltype(c.size()) { return c.size(); }
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
constexpr std::size_t size(const T(&)[N]) noexcept { return N; }
|
||||
}
|
||||
|
||||
typedef std::chrono::microseconds Microseconds;
|
||||
|
@ -146,4 +182,5 @@ class QueryString {
|
|||
|
||||
std::map<std::string, std::unique_ptr<QueryParameter>> parameters_;
|
||||
};
|
||||
|
||||
#endif // ZM_UTILS_H
|
||||
|
|
|
@ -76,3 +76,62 @@ TEST_CASE("JWT validation") {
|
|||
REQUIRE(result.second == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("zm::crypto::MD5") {
|
||||
using namespace zm::crypto;
|
||||
MD5 md5;
|
||||
|
||||
REQUIRE(md5.GetDigest() == MD5::Digest());
|
||||
|
||||
SECTION("hash from const char*") {
|
||||
md5.UpdateData("abcdefghijklmnopqrstuvwxyz");
|
||||
md5.Finalize();
|
||||
|
||||
REQUIRE(md5.GetDigest() == MD5::Digest{0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c, 0xca,
|
||||
0x67, 0xe1, 0x3b});
|
||||
}
|
||||
|
||||
SECTION("hash from std::string") {
|
||||
md5.UpdateData(std::string("abcdefghijklmnopqrstuvwxyz"));
|
||||
md5.Finalize();
|
||||
|
||||
REQUIRE(md5.GetDigest() == MD5::Digest{0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c, 0xca,
|
||||
0x67, 0xe1, 0x3b});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("zm::crypto::MD5::GetDigestOf") {
|
||||
using namespace zm::crypto;
|
||||
std::array<uint8, 3> data = {'a', 'b', 'c'};
|
||||
|
||||
SECTION("data and len") {
|
||||
MD5::Digest digest = MD5::GetDigestOf(reinterpret_cast<const uint8 *>(data.data()), data.size());
|
||||
|
||||
REQUIRE(digest == MD5::Digest{0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1,
|
||||
0x7f, 0x72});
|
||||
}
|
||||
|
||||
SECTION("container") {
|
||||
MD5::Digest digest = MD5::GetDigestOf(data);
|
||||
|
||||
REQUIRE(digest == MD5::Digest{0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1,
|
||||
0x7f, 0x72});
|
||||
}
|
||||
|
||||
SECTION("multiple containers") {
|
||||
MD5::Digest digest = MD5::GetDigestOf(data, data);
|
||||
|
||||
REQUIRE(digest == MD5::Digest{0x44, 0x0a, 0xc8, 0x58, 0x92, 0xca, 0x43, 0xad, 0x26, 0xd4, 0x4c, 0x7a, 0xd9, 0xd4,
|
||||
0x7d, 0x3e});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("zm::crypto::SHA1::GetDigestOf") {
|
||||
using namespace zm::crypto;
|
||||
std::array<uint8, 3> data = {'a', 'b', 'c'};
|
||||
|
||||
SHA1::Digest digest = SHA1::GetDigestOf(data);
|
||||
|
||||
REQUIRE(digest == SHA1::Digest{0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50,
|
||||
0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d});
|
||||
}
|
||||
|
|
|
@ -140,6 +140,18 @@ TEST_CASE("Join") {
|
|||
REQUIRE(Join({"a", "b"}, "") == "ab");
|
||||
}
|
||||
|
||||
TEST_CASE("ByteArrayToHexString") {
|
||||
std::vector<uint8> bytes;
|
||||
|
||||
REQUIRE(ByteArrayToHexString(bytes) == "");
|
||||
|
||||
bytes = {0x00};
|
||||
REQUIRE(ByteArrayToHexString(bytes) == "00");
|
||||
|
||||
bytes = {0x00, 0x01, 0x02, 0xff};
|
||||
REQUIRE(ByteArrayToHexString(bytes) == "000102ff");
|
||||
}
|
||||
|
||||
TEST_CASE("Base64Encode") {
|
||||
REQUIRE(Base64Encode("") == "");
|
||||
REQUIRE(Base64Encode("f") == "Zg==");
|
||||
|
|
|
@ -29,14 +29,11 @@
|
|||
#cmakedefine HAVE_LIBJPEG 1
|
||||
#cmakedefine HAVE_JPEGLIB_H 1
|
||||
#cmakedefine HAVE_LIBOPENSSL 1
|
||||
#cmakedefine HAVE_OPENSSL_MD5_H 1
|
||||
#cmakedefine HAVE_LIBCRYPTO 1
|
||||
#cmakedefine HAVE_LIBPTHREAD 1
|
||||
#cmakedefine HAVE_PTHREAD_H
|
||||
#cmakedefine HAVE_LIBPCRE 1
|
||||
#cmakedefine HAVE_PCRE_H 1
|
||||
#cmakedefine HAVE_LIBGNUTLS 1
|
||||
#cmakedefine HAVE_GNUTLS_GNUTLS_H 1
|
||||
#cmakedefine HAVE_LIBMYSQLCLIENT 1
|
||||
#cmakedefine HAVE_MYSQL_H 1
|
||||
#cmakedefine HAVE_LIBAVFORMAT 1
|
||||
|
@ -68,12 +65,6 @@
|
|||
#cmakedefine HAVE_LIBJWT 1
|
||||
#cmakedefine HAVE_RTSP_SERVER 1
|
||||
|
||||
/* Authenication checks */
|
||||
#cmakedefine HAVE_MD5_OPENSSL 1
|
||||
#cmakedefine HAVE_MD5_GNUTLS 1
|
||||
#cmakedefine HAVE_DECL_MD5 1
|
||||
#cmakedefine HAVE_DECL_GNUTLS_FINGERPRINT 1
|
||||
|
||||
/* Few ZM options that are needed by the source code */
|
||||
#cmakedefine ZM_MEM_MAPPED 1
|
||||
|
||||
|
|
Loading…
Reference in New Issue