/* This file is part of TALER Copyright (C) 2014, 2015, 2016, 2020 Taler Systems SA TALER 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, or (at your option) any later version. TALER 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 TALER; see the file COPYING. If not, see */ /** * @file exchangedb/exchangedb_signkeys.c * @brief I/O operations for the Exchange's private online signing keys * @author Florian Dold * @author Benedikt Mueller * @author Sree Harsha Totakura * @author Christian Grothoff */ #include "platform.h" #include "taler_exchangedb_lib.h" /** * Closure for the #signkeys_iterate_dir_iter(). */ struct SignkeysIterateContext { /** * Function to call on each signing key. */ TALER_EXCHANGEDB_SigningKeyIterator it; /** * Closure for @e it. */ void *it_cls; }; /** * Function called on each file in the directory with our signing * keys. Parses the file and calls the iterator from @a cls. * * @param cls the `struct SignkeysIterateContext *` * @param filename name of the file to parse * @return #GNUNET_OK to continue, * #GNUNET_NO to stop iteration without error, * #GNUNET_SYSERR to stop iteration with error */ static int signkeys_iterate_dir_iter (void *cls, const char *filename) { struct SignkeysIterateContext *skc = cls; ssize_t nread; struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP issue; nread = GNUNET_DISK_fn_read (filename, &issue, sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP)); if (nread != sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid signkey file `%s': wrong size (%d, expected %u)\n", filename, (int) nread, (unsigned int) sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP)); return GNUNET_OK; } if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (issue.issue.expire)).rel_value_us) { if (0 != unlink (filename)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", filename); return GNUNET_OK; /* yes, we had an error, but continue to iterate anyway */ } /* Expired file deleted, continue to iterate -without- calling iterator as this key is expired */ return GNUNET_OK; } return skc->it (skc->it_cls, filename, &issue); } /** * Call @a it for each signing key found in the @a exchange_base_dir. * * @param exchange_base_dir base directory for the exchange, * the signing keys must be in the #TALER_EXCHANGEDB_DIR_SIGNING_KEYS * subdirectory * @param it function to call on each signing key * @param it_cls closure for @a it * @return number of files found (may not match * number of keys given to @a it as malformed * files are simply skipped), -1 on error */ int TALER_EXCHANGEDB_signing_keys_iterate (const char *exchange_base_dir, TALER_EXCHANGEDB_SigningKeyIterator it, void *it_cls) { struct SignkeysIterateContext skc = { .it = it, .it_cls = it_cls }; char *signkey_dir; int ret; GNUNET_asprintf (&signkey_dir, "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_SIGNING_KEYS, exchange_base_dir); ret = GNUNET_DISK_directory_scan (signkey_dir, &signkeys_iterate_dir_iter, &skc); GNUNET_free (signkey_dir); return ret; } /** * Exports a signing key to the given file. * * @param exchange_base_dir base directory for the keys * @param start start time of the validity for the key * @param ski the signing key * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. */ int TALER_EXCHANGEDB_signing_key_write ( const char *exchange_base_dir, struct GNUNET_TIME_Absolute start, const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski) { char *skf; ssize_t nwrite; GNUNET_asprintf (&skf, "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_SIGNING_KEYS DIR_SEPARATOR_STR "%llu", exchange_base_dir, (unsigned long long) start.abs_value_us); if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (skf)) { int eno; eno = errno; GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir (for file)", skf); errno = eno; return GNUNET_SYSERR; } nwrite = GNUNET_DISK_fn_write (skf, ski, sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP), GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ); if (sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP) != (size_t) nwrite) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", skf); GNUNET_free (skf); return GNUNET_SYSERR; } GNUNET_free (skf); return GNUNET_OK; } /* end of exchangedb_signkeys.c */