33 hFile(INVALID_HANDLE_VALUE)
43 return hFile != INVALID_HANDLE_VALUE;
53 hFile = CreateFile(TEXT(filename.c_str()), GENERIC_READ, 0,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr);
54 if (hFile == INVALID_HANDLE_VALUE)
56 fd =
xopen(filename.c_str(), O_RDWR);
62 if (!LockFile(hFile, 0, 0, 1, 0))
64 if (lockf(fd, F_LOCK, 0) != 0)
66 if (flock(fd, LOCK_EX) != 0)
74 if (hFile != INVALID_HANDLE_VALUE) {
75 UnlockFile(hFile, 0, 0, 1, 0);
77 hFile = INVALID_HANDLE_VALUE;
82 lockf(fd, F_ULOCK, 0);
119 row = (
char **)OPENSSL_malloc(
sizeof(
char *) * (
width + 1));
120 for (
size_t i = 0; i <
width + 1; ++i)
135 if ((
max = (
void *)row[width]) !=
nullptr) {
140 for (
size_t i = 0; i < width + 1; ++i) {
141 if (((row[i] < (
char *)row) || (row[i] >
max)) && (row[i] !=
nullptr))
142 OPENSSL_free(row[i]);
145 for (
size_t i = 0; i < width + 1; ++i) {
147 OPENSSL_free(row[i]);
162 OPENSSL_free(row[cell]);
165 row[cell] =
static_cast<char *
>(OPENSSL_malloc(
sizeof(
char) * (strlen(value) + 1)));
166 memcpy(row[cell], value,
sizeof(
char) * (strlen(value) + 1));
181#if SQUID_SSLTXTDB_PSTRINGDATA
182 for (
int i = 0; i < sk_OPENSSL_PSTRING_num(
db->data); ++i) {
183#if SQUID_STACKOF_PSTRINGDATA_HACK
184 const char ** current_row = ((
const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING,
db->data), i));
186 const char ** current_row = ((
const char **)sk_OPENSSL_PSTRING_value(
db->data, i));
189 for (
int i = 0; i < sk_num(
db->data); ++i) {
190 const char ** current_row = ((
const char **)sk_value(
db->data, i));
192 if (current_row == row) {
199#define countof(arr) (sizeof(arr)/sizeof(*arr))
202#if SQUID_SSLTXTDB_PSTRINGDATA
203 rrow = (
char **)sk_OPENSSL_PSTRING_delete(
db->data, idx);
205 rrow = (
char **)sk_delete(
db->data, idx);
214 for (
unsigned int i = 0; i <
countof(db_indexes); ++i) {
215 void *data =
nullptr;
216#if SQUID_SSLTXTDB_PSTRINGDATA
217 if (LHASH_OF(OPENSSL_STRING) *fieldIndex =
db->index[db_indexes[i]])
218 data = lh_OPENSSL_STRING_delete(fieldIndex, rrow);
220 if (LHASH *fieldIndex =
db->index[db_indexes[i]])
239 return strcmp(aa, bb);
269 return pure_find(key, expectedOrig, cert, pkey);
278 if (!deleteByKey(key))
290 if (!
db || !cert || !pkey)
297 ASN1_INTEGER * ai = X509_get_serialNumber(cert.
get());
298 std::string serial_string;
302 serial_string = std::string(hex_bn.get());
304 row.
setValue(cnlSerial, serial_string.c_str());
305 char ** rrow = TXT_DB_get_by_index(
db.get(), cnlSerial, row.
getRow());
308 if (rrow !=
nullptr) {
317 size_t dbSize =
size();
318 if ((dbSize == 0 && hasRows()) ||
319 (dbSize > 0 && !hasRows()) ||
320 (dbSize > 10 * max_db_size)) {
322 dbSize = rebuildSize();
324 while (dbSize > max_db_size && deleteInvalidCertificate()) {
329 while (dbSize > max_db_size) {
330 if (!deleteOldestCertificate()) {
339 row.
setValue(cnlExp_date, std::string(
reinterpret_cast<char *
>(tm->data), tm->length).c_str());
341 row.
setValue(cnlName, subject.get());
342 row.
setValue(cnlKey, useKey.c_str());
344 if (!TXT_DB_insert(
db.get(), row.
getRow())) {
353 std::string filename(cert_full +
"/" + serial_string +
".pem");
354 if (!WriteEntry(filename.c_str(), cert, pkey, orig)) {
356 sq_TXT_DB_delete(
db.get(), (
const char **)rrow);
370 std::string db_full(
db_path +
"/" + db_file);
371 std::string cert_full(
db_path +
"/" + cert_dir);
372 std::string size_full(
db_path +
"/" + size_file);
374 if (mkdir(
db_path.c_str(), 0750))
377 if (mkdir(cert_full.c_str(), 0750))
380 std::ofstream
size(size_full.c_str());
385 std::ofstream
db(db_full.c_str());
402#if SQUID_SSLTXTDB_PSTRINGDATA
403 for (
int i = 0; i < sk_OPENSSL_PSTRING_num(
db.get()->data); ++i) {
404#if SQUID_STACKOF_PSTRINGDATA_HACK
405 const char ** current_row = ((
const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING,
db.get()->data), i));
407 const char ** current_row = ((
const char **)sk_OPENSSL_PSTRING_value(
db.get()->data, i));
410 for (
int i = 0; i < sk_num(
db.get()->data); ++i) {
411 const char ** current_row = ((
const char **)sk_value(
db.get()->data, i));
413 const std::string filename(cert_full +
"/" + current_row[cnlSerial] +
".pem");
414 const size_t fSize = getFileSize(filename);
430 char **rrow = TXT_DB_get_by_index(
db.get(), cnlKey, row.
getRow());
439 std::string filename(cert_full +
"/" + rrow[cnlSerial] +
".pem");
440 if (!ReadEntry(filename.c_str(), cert, pkey, storedOrig))
443 if (!storedOrig && !expectedOrig)
455 size_t dbSize = readSize();
456 dbSize += getFileSize(filename);
462 size_t dbSize = readSize();
463 const size_t fileSize = getFileSize(filename);
464 dbSize = dbSize > fileSize ? dbSize - fileSize : 0;
469 std::ifstream ifstr(size_full.c_str());
471 if (!ifstr || !(ifstr >> db_size))
472 return rebuildSize();
477 std::ofstream ofstr(size_full.c_str());
484 std::ifstream file(filename.c_str(), std::ios::binary);
487 file.seekg(0, std::ios_base::end);
488 const std::streampos file_size = file.tellg();
491 return ((
static_cast<size_t>(file_size) + fs_block_size - 1) / fs_block_size) * fs_block_size;
497 if (!in || BIO_read_filename(in.get(), db_full.c_str()) <= 0)
500 bool corrupt =
false;
506 if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlSerial,
nullptr, LHASH_HASH_FN(index_serial_hash), LHASH_COMP_FN(index_serial_cmp)))
509 if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlKey,
nullptr, LHASH_HASH_FN(index_name_hash), LHASH_COMP_FN(index_name_cmp)))
515 db.reset(temp_db.release());
524 if (!out || !BIO_write_filename(out.get(),
const_cast<char *
>(db_full.c_str())))
527 if (TXT_DB_write(out.get(),
db.get()) < 0)
533 const std::string filename(cert_full +
"/" + row[cnlSerial] +
".pem");
534 sq_TXT_DB_delete_row(
db.get(), rowIndex);
537 int ret = remove(filename.c_str());
538 if (ret < 0 && errno != ENOENT)
546 bool removed_one =
false;
547#if SQUID_SSLTXTDB_PSTRINGDATA
548 for (
int i = 0; i < sk_OPENSSL_PSTRING_num(
db.get()->data); ++i) {
549#if SQUID_STACKOF_PSTRINGDATA_HACK
550 const char ** current_row = ((
const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING,
db.get()->data), i));
552 const char ** current_row = ((
const char **)sk_OPENSSL_PSTRING_value(
db.get()->data, i));
555 for (
int i = 0; i < sk_num(
db.get()->data); ++i) {
556 const char ** current_row = ((
const char **)sk_value(
db.get()->data, i));
560 deleteRow(current_row, i);
576#if SQUID_SSLTXTDB_PSTRINGDATA
577#if SQUID_STACKOF_PSTRINGDATA_HACK
578 const char **row = ((
const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING,
db.get()->data), 0));
580 const char **row = (
const char **)sk_OPENSSL_PSTRING_value(
db.get()->data, 0);
583 const char **row = (
const char **)sk_value(
db.get()->data, 0);
596#if SQUID_SSLTXTDB_PSTRINGDATA
597 for (
int i = 0; i < sk_OPENSSL_PSTRING_num(
db.get()->data); ++i) {
598#if SQUID_STACKOF_PSTRINGDATA_HACK
599 const char ** current_row = ((
const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING,
db.get()->data), i));
601 const char ** current_row = ((
const char **)sk_OPENSSL_PSTRING_value(
db.get()->data, i));
604 for (
int i = 0; i < sk_num(
db.get()->data); ++i) {
605 const char ** current_row = ((
const char **)sk_value(
db.get()->data, i));
607 if (key == current_row[cnlKey]) {
608 deleteRow(current_row, i);
620#if SQUID_SSLTXTDB_PSTRINGDATA
621 if (sk_OPENSSL_PSTRING_num(
db.get()->data) == 0)
623 if (sk_num(
db.get()->data) == 0)
#define Here()
source code location of the caller
T * get() const
Returns raw and possibly nullptr pointer.
a source code location that is cheap to create, copy, and store
A wrapper for OpenSSL database row of TXT_DB database.
void setValue(size_t number, char const *value)
Set cell's value in row.
size_t width
Number of cells in the row.
void reset()
Abandon row and don't free memory.
bool deleteByKey(std::string const &key)
Delete using key.
const size_t fs_block_size
File system block size.
static bool WriteEntry(const std::string &filename, const Security::CertPointer &cert, const Security::PrivateKeyPointer &pkey, const Security::CertPointer &orig)
stores the db entry into a file
static int index_serial_cmp(const char **a, const char **b)
Callback compare function for serials. Used to create TXT_DB index of serials.
static void Create(std::string const &db_path)
Create and initialize a database under the db_path.
void deleteRow(const char **row, int rowIndex)
Delete a row from TXT_DB.
const std::string size_full
Full path of the file to store the db size.
TXT_DB_Pointer db
Database with certificates info.
bool pure_find(std::string const &key, const Security::CertPointer &expectedOrig, Security::CertPointer &cert, Security::PrivateKeyPointer &pkey)
Only find certificate in current db and return it.
void writeSize(size_t db_size)
Write size to file size_file.
static unsigned long index_serial_hash(const char **a)
Callback hash function for serials. Used to create TXT_DB index of serials.
bool purgeCert(std::string const &key)
Delete a certificate from database.
static const std::string cert_dir
Base name of the directory to store the certs.
const std::string cert_full
Full path of the directory to store the certs.
void subSize(std::string const &filename)
Decrease db size by the given file size and update size_file.
bool deleteOldestCertificate()
Delete oldest certificate.
static unsigned long index_name_hash(const char **a)
Callback hash function for names. Used to create TXT_DB index of names..
void addSize(std::string const &filename)
Increase db size by the given file size and update size_file.
static bool ReadEntry(std::string filename, Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, Security::CertPointer &orig)
loads a db entry from the file
size_t readSize()
Read size from file size_file.
bool hasRows() const
Whether the TXT_DB has stored items.
static int index_name_cmp(const char **a, const char **b)
Callback compare function for names. Used to create TXT_DB index of names..
const size_t max_db_size
Max size of db.
void save()
Save db to disk.
static void Check(std::string const &db_path, size_t max_db_size, size_t fs_block_size)
Check the database stored under the db_path.
Columns
Names of db columns.
CertificateDb(std::string const &db_path, size_t aMax_db_size, size_t aFs_block_size)
bool addCertAndPrivateKey(std::string const &useKey, const Security::CertPointer &cert, const Security::PrivateKeyPointer &pkey, const Security::CertPointer &orig)
Save certificate to disk.
static const std::string size_file
bool find(std::string const &key, const Security::CertPointer &expectedOrig, Security::CertPointer &cert, Security::PrivateKeyPointer &pkey)
finds matching generated certificate and its private key
const std::string db_full
Full path of the database index file.
static const char **static const char **static const std::string db_file
Base name of the database index file.
const std::string db_path
The database directory.
bool deleteInvalidCertificate()
Delete invalid certificate.
static void sq_TXT_DB_delete(TXT_DB *db, const char **row)
Removes the first matching row from TXT_DB. Ignores failures.
Lock dbLock
protects the database file
static void sq_TXT_DB_delete_row(TXT_DB *db, int idx)
Remove the row on position idx from TXT_DB. Ignores failures.
size_t getFileSize(std::string const &filename)
get file size on disk.
void load()
Load db from disk.
maintains an exclusive blocking file-based lock
Lock(std::string const &filename)
creates an unlocked lock
~Lock()
releases the lock if it is locked
bool locked() const
whether our lock is locked
void lock()
locks the lock, may block
void unlock()
unlocks locked lock or throws
an exception-safe way to obtain and release a lock
~Locker()
unlocks the lock if it was locked by us
Locker(Lock &, const SourceLocation &)
locks the lock if the lock was unlocked
Lock & lock
the lock we are operating on
bool weLocked
whether we locked the lock
an std::runtime_error with thrower location info
A const & max(A const &lhs, A const &rhs)
bool CertificatesCmp(const Security::CertPointer &cert1, const Security::CertPointer &cert2)
bool ReadPrivateKey(BIO_Pointer &bio, Security::PrivateKeyPointer &pkey, pem_password_cb *passwd_callback)
bool OpenCertsFileForWriting(BIO_Pointer &bio, const char *filename)
bool WritePrivateKey(BIO_Pointer &bio, const Security::PrivateKeyPointer &pkey)
bool sslDateIsInTheFuture(char const *date)
bool OpenCertsFileForReading(BIO_Pointer &bio, const char *filename)
bool WriteX509Certificate(BIO_Pointer &bio, const Security::CertPointer &cert)
std::unique_ptr< BIO, HardFun< void, BIO *, &BIO_vfree > > BIO_Pointer
std::unique_ptr< BIGNUM, HardFun< void, BIGNUM *, &BN_free > > BIGNUM_Pointer
std::unique_ptr< TXT_DB, HardFun< void, TXT_DB *, &TXT_DB_free > > TXT_DB_Pointer
Security::CertPointer ReadOptionalCertificate(const BIO_Pointer &)
UniqueCString OneLineSummary(X509_NAME &)
a RAII wrapper for the memory-allocating flavor of X509_NAME_oneline()
Security::CertPointer ReadCertificate(const BIO_Pointer &)
std::unique_ptr< char, HardFun< void, char *, &OPENSSL_free_for_c_strings > > UniqueCString
#define OPENSSL_LH_strhash
#define OPENSSL_LH_delete
#define X509_getm_notAfter
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
int xclose(int fd)
POSIX close(2) equivalent.
int xopen(const char *filename, int oflag, int pmode=0)
POSIX open(2) equivalent.