LCOV - code coverage report
Current view: top level - snapwebsites - password.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 298 0.3 %
Date: 2019-12-15 17:13:15 Functions: 2 33 6.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Snap Websites Server -- handle creating / encrypting password
       2             : // Copyright (c) 2011-2019  Made to Order Software Corp.  All Rights Reserved
       3             : //
       4             : // This program is free software; you can redistribute it and/or modify
       5             : // it under the terms of the GNU General Public License as published by
       6             : // the Free Software Foundation; either version 2 of the License, or
       7             : // (at your option) any later version.
       8             : //
       9             : // This program is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             : // GNU General Public License for more details.
      13             : //
      14             : // You should have received a copy of the GNU General Public License
      15             : // along with this program; if not, write to the Free Software
      16             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      17             : 
      18             : 
      19             : // self
      20             : //
      21             : #include "snapwebsites/password.h"
      22             : 
      23             : 
      24             : // snapdev lib
      25             : //
      26             : #include <snapdev/hexadecimal_string.h>
      27             : #include <snapdev/not_used.h>
      28             : 
      29             : 
      30             : // boost lib
      31             : //
      32             : #include <boost/static_assert.hpp>
      33             : 
      34             : 
      35             : // OpenSSL lib
      36             : //
      37             : #include <openssl/err.h>
      38             : #include <openssl/evp.h>
      39             : #include <openssl/rand.h>
      40             : 
      41             : 
      42             : // C++ lib
      43             : //
      44             : #include <memory>
      45             : #include <iostream>
      46             : 
      47             : 
      48             : // C lib
      49             : //
      50             : #include <fcntl.h>
      51             : #include <termios.h>
      52             : 
      53             : 
      54             : // last include
      55             : //
      56             : #include <snapdev/poison.h>
      57             : 
      58             : 
      59             : 
      60             : namespace snap
      61             : {
      62             : 
      63             : 
      64             : 
      65             : namespace
      66             : {
      67             : 
      68             : /** \brief Size of the salt for a password.
      69             :  *
      70             :  * Whenever we encrypt a password, we use a corresponding salt.
      71             :  *
      72             :  * The salt is used to further encrypt the password so two users who
      73             :  * decided to use the exact same password will not be seen as having
      74             :  * the same password because of the salt since the salt renders any
      75             :  * password unique.
      76             :  *
      77             :  * \note
      78             :  * In the current implementation we do not in any way attempt to
      79             :  * make sure that each user gets a unique salt so it is always
      80             :  * possible for two users to end up with the exact same salt. However,
      81             :  * it is really very unlikely that those two users would also choose
      82             :  * the exact same password. Now, with a salt of 32 bytes, the real
      83             :  * likelihood for two people to end up with the same salt is really
      84             :  * very low (32 bytes is 256 bits, so one chance in 2 power 256, which
      85             :  * is a very small number, a little under 10 power -77.)
      86             :  *
      87             :  * \todo
      88             :  * We may want to offer the programmer a way to enter his own salt
      89             :  * size. Right now, this is fixed and cannot ever be changed since
      90             :  * the input of existing password will have a salt string of that
      91             :  * size exactly.
      92             :  */
      93             : int const SALT_SIZE = 32;
      94             : // to be worth something, the salt must be at least 6 bytes
      95             : BOOST_STATIC_ASSERT(SALT_SIZE >= 6);
      96             : // the salt size must be even
      97             : BOOST_STATIC_ASSERT((SALT_SIZE & 1) == 0);
      98             : 
      99             : 
     100             : /** \brief Delete an MD context.
     101             :  *
     102             :  * We allocate an EVP MD context in order to compute the hash according to
     103             :  * the digest specified by the programmer (or "sha512" by default.)
     104             :  *
     105             :  * The function using the \p mdctx may raise an exception on an error so
     106             :  * we save the context in a shared pointer which auto-deletes the context
     107             :  * once we are done with it by calling this very function.
     108             :  *
     109             :  * \note
     110             :  * The mdctx buffer is NOT allocated. It's created on the stack, but it
     111             :  * still needs cleanup and the digest may allocate buffers that need to
     112             :  * be released.
     113             :  *
     114             :  * \param[in] mdctx  The pointer to the MD context.
     115             :  */
     116           0 : void evp_md_ctx_deleter(EVP_MD_CTX * mdctx)
     117             : {
     118             :     // clean up the context
     119             :     // (note: the return value is not documented so we ignore it)
     120             : #if __cplusplus >= 201700
     121           0 :     EVP_MD_CTX_free(mdctx);
     122             : #else
     123             :     EVP_MD_CTX_cleanup(mdctx);
     124             :     delete mdctx;
     125             : #endif
     126           0 : }
     127             : 
     128             : 
     129           0 : EVP_MD_CTX * evp_md_ctx_allocate()
     130             : {
     131           0 :     EVP_MD_CTX * mdctx(nullptr);
     132             : #if __cplusplus >= 201700
     133           0 :     mdctx = EVP_MD_CTX_new();
     134             : #else
     135             :     mdctx = new EVP_MD_CTX;
     136             :     EVP_MD_CTX_init(mdctx);
     137             : #endif
     138           0 :     return mdctx;
     139             : }
     140             : 
     141             : 
     142             : /** \brief Close a file descriptor.
     143             :  *
     144             :  * This function will close the file descriptor pointer by fd.
     145             :  *
     146             :  * \param[in] fd  Pointer to the file descriptor to close.
     147             :  */
     148           0 : void close_file(int * fd)
     149             : {
     150           0 :     close(*fd);
     151           0 : }
     152             : 
     153             : 
     154             : }
     155             : 
     156             : 
     157             : /** \brief Initialize the password object.
     158             :  *
     159             :  * This function does nothing at this time. By default a password object
     160             :  * is empty.
     161             :  *
     162             :  * There are several ways the password object is used:
     163             :  *
     164             :  * \li To generate a new password automatically.
     165             :  *
     166             :  * \code
     167             :  *      password p;
     168             :  *      p.set_digest("sha512");   // always required in this case
     169             :  *      p.generate_password(10);  // necessary if you want to specify the size
     170             :  *      std::string hash(p.get_encrypted_password();
     171             :  *      std::string salt(p.get_salt());
     172             :  * \endcode
     173             :  *
     174             :  * The hash variable is the encypted password. Note that you will want to
     175             :  * also save the salt otherwise you won't be able to do anything with the
     176             :  * hash alone.
     177             :  *
     178             :  * \li To encrypt a password entered by a user.
     179             :  *
     180             :  * \code
     181             :  *      password p;
     182             :  *      p.set_digest("sha512");
     183             :  *      p.set_plain_password(user_entered_password);
     184             :  *      std::string hash(p.get_encrypted_password());
     185             :  *      std::string salt(p.get_salt());
     186             :  * \endcode
     187             :  *
     188             :  * \li To compare an already encrypted password against a password entered
     189             :  *     by a user.
     190             :  *
     191             :  * \code
     192             :  *      password p;
     193             :  *      p.set_digest(digest_of_existing_password);
     194             :  *      p.set_plain_password(user_entered_password, existing_password_salt);
     195             :  *      std::string hash(p.get_encrypted_password());
     196             :  *      if(hash == existing_password_hash) // ...got it right...
     197             :  * \endcode
     198             :  *
     199             :  * You may also defined two password objects and compare them against each
     200             :  * others to know whether the new login password is the same as the database
     201             :  * password:
     202             :  *
     203             :  * \code
     204             :  *      // or use two password objects:
     205             :  *      password p;
     206             :  *      p.set_digest(digest_of_existing_password);
     207             :  *      p.set_plain_password(user_entered_password, existing_password_salt);
     208             :  *      password op;  // old password
     209             :  *      op.set_encrypted_password();
     210             :  *      if(op == p) // ...got it right...
     211             :  * \endcode
     212             :  *
     213             :  * \warning
     214             :  * In the current implementation, the salt string must be exactly SALT_SIZE
     215             :  * in length. Although we use an std::string, the bytes can be any value
     216             :  * from '\0' to '\xFF'.
     217             :  */
     218           0 : password::password()
     219             : {
     220           0 : }
     221             : 
     222             : 
     223             : /** \brief Clean up a password object.
     224             :  *
     225             :  * This function cleans up the strings held by the password object.
     226             :  * That way they do not lay around in memory.
     227             :  */
     228           0 : password::~password()
     229             : {
     230           0 :     clear_string(f_plain_password);
     231           0 :     clear_string(f_encrypted_password);
     232           0 :     clear_string(f_salt);
     233           0 : }
     234             : 
     235             : 
     236             : /** \brief Define the OpenSSL function to use to encrypt the password.
     237             :  *
     238             :  * This function saves the digest to use to encrypt the password. Until
     239             :  * this is done, trying to retrieve an encrypted password from a plain
     240             :  * password will fail.
     241             :  *
     242             :  * For now, we use "sha512" as the default. We may also want to look
     243             :  * into using the bcrypt() function instead. However, Blowfish uses
     244             :  * only 64 bits and suffers from birthday attacks (guessing of words).
     245             :  *
     246             :  * \warning
     247             :  * This function has the side effect of clearing the cached encrypted
     248             :  * password.
     249             :  *
     250             :  * \todo
     251             :  * The test needs to verify that "sha512" exists so the default works.
     252             :  *
     253             :  * \exception password_exception_digest_not_available
     254             :  * If the digest is not defined in OpenSSL, then this exception is raised.
     255             :  *
     256             :  * \param[in] digest  The digest name.
     257             :  */
     258           0 : void password::set_digest(std::string const & digest)
     259             : {
     260             :     // Initialize so we gain access to all the necessary digests
     261             :     //
     262           0 :     OpenSSL_add_all_digests();
     263             : 
     264             :     // Make sure the digest actually exists
     265             :     //
     266           0 :     if(EVP_get_digestbyname(f_digest.c_str()) == nullptr)
     267             :     {
     268           0 :         throw password_exception_digest_not_available("the specified digest could not be found");
     269             :     }
     270             : 
     271           0 :     f_digest = digest;
     272             : 
     273           0 :     clear_string(f_encrypted_password);
     274           0 : }
     275             : 
     276             : 
     277             : /** \brief Retrieve the name of the current OpenSSL digest.
     278             :  *
     279             :  * This function returns the digest to use to encrypt the password.
     280             :  *
     281             :  * \return The name of the digest currently in use in this password.
     282             :  */
     283           0 : std::string const & password::get_digest() const
     284             : {
     285           0 :     return f_digest;
     286             : }
     287             : 
     288             : 
     289             : /** \brief Generate the password.
     290             :  *
     291             :  * In some cases an administrator may want to create an account for a user
     292             :  * which should then have a valid, albeit unknown, password.
     293             :  *
     294             :  * This function can be used to create that password.
     295             :  *
     296             :  * It is strongly advised to NOT send such passwords to the user via email
     297             :  * because they may contain "strange" characters and emails are notoriously
     298             :  * not safe.
     299             :  *
     300             :  * \note
     301             :  * The function verifies that the min_length parameter is at least 8. Note
     302             :  * that a safe password is more like 10 or more totally random characters.
     303             :  *
     304             :  * \note
     305             :  * The \p min_length parameter represent the minimum length, it is very
     306             :  * likely that the result will be longer.
     307             :  *
     308             :  * \warning
     309             :  * The function is not likely to generate a user friendly password. It is
     310             :  * expected to be used when a password is required but the user cannot
     311             :  * enter one and the user will have to run a Change Password procedure.
     312             :  *
     313             :  * \warning
     314             :  * Calling this functions also generates a new salt.
     315             :  *
     316             :  * \todo
     317             :  * Look into creating a genearte_human_password() with sets of characters
     318             :  * in each language instead of just basic ASCII and a length that makes
     319             :  * more sense (here the default is 64 because it is a "computer password").
     320             :  *
     321             :  * \todo
     322             :  * Also remove characters that can cause problems for users (i.e. spaces,
     323             :  * ampersand, look alike characters, etc.)
     324             :  *
     325             :  * \todo
     326             :  * Look in the RAND_seed() or maybe RAND_status() and RAND_load_file()
     327             :  * functions and whether the OpenSSL RAND_*() interface requires an
     328             :  * initialization because cURL does have such and it could be that we
     329             :  * need it too. In that case, I would suggest we create a separate
     330             :  * contrib library for random numbers. That library would be responsible
     331             :  * for generating the numbers automatically for us.
     332             :  *
     333             :  * \param[in] min_length  The minimum length of the password.
     334             :  */
     335           0 : void password::generate_password(int min_length)
     336             : {
     337             :     // restart from scratch
     338             :     //
     339           0 :     clear_string(f_plain_password);
     340           0 :     clear_string(f_encrypted_password);
     341           0 :     clear_string(f_salt);
     342             : 
     343           0 :     if(min_length < 8)
     344             :     {
     345           0 :         min_length = 8;
     346             :     }
     347             : 
     348             :     // a "large" set of random bytes
     349             :     //
     350           0 :     int const PASSWORD_SIZE(256);
     351             :     unsigned char buf[PASSWORD_SIZE];
     352           0 :     do
     353             :     {
     354             :         // get the random bytes
     355             :         //
     356           0 :         int const r(RAND_bytes(buf, sizeof(buf)));
     357           0 :         if(r != 1)
     358             :         {
     359             :             // something happened, RAND_bytes() failed!
     360             :             char err[256];
     361           0 :             ERR_error_string_n(ERR_peek_last_error(), err, sizeof(err));
     362             :             throw password_exception_function_failure(
     363           0 :                 QString("RAND_bytes() error, it could not properly fill the salt buffer (%1: %2)")
     364           0 :                         .arg(ERR_peek_last_error())
     365           0 :                         .arg(err));
     366             :         }
     367             : 
     368           0 :         for(int i(0); i < PASSWORD_SIZE; ++i)
     369             :         {
     370             :             // only but all ASCII characters are accepted for now
     371             :             //
     372           0 :             if(buf[i] >= ' ' && buf[i] < 0x7F)
     373             :             {
     374           0 :                 f_plain_password += static_cast<char>(buf[i]);
     375             :             }
     376             :             //else -- skip any other character
     377             :         }
     378             :     }
     379           0 :     while(f_plain_password.length() < static_cast<size_t>(min_length));
     380             :     // make sure it is long enough
     381           0 : }
     382             : 
     383             : 
     384             : /** \brief Define the password from a plain password.
     385             :  *
     386             :  * This function defines a password starting from a plain password.
     387             :  *
     388             :  * If this password comes from a log in screen, then you will need to
     389             :  * specify the existing salt. Otherwise, leave the salt string empty.
     390             :  * The password object will randomly generate a buffer of bytes
     391             :  * automatically for it.
     392             :  *
     393             :  * \note
     394             :  * Calling this function resets the encrypted password.
     395             :  *
     396             :  * \note
     397             :  * Although it is expected that the password is a valid C string,
     398             :  * this object does not check such. The password can include any
     399             :  * character, including '\0', and it can even be invalid UTF-8.
     400             :  * It is the caller's responsibility to verify the string if it
     401             :  * can be tainted in any special way.
     402             :  *
     403             :  * \param[in] plain_password  The plain password to encrypt.
     404             :  * \param[in] salt  The salt to use with the password encryption system.
     405             :  */
     406           0 : void password::set_plain_password(std::string const & plain_password, std::string const & salt)
     407             : {
     408             :     // the salt must be of the right length (or unspecified)
     409             :     //
     410           0 :     if(!salt.empty()
     411           0 :     && salt.length() != SALT_SIZE)
     412             :     {
     413           0 :         throw password_exception_invalid_parameter(QString("if defined, the salt must be exactly %1 bytes").arg(SALT_SIZE));
     414             :     }
     415             : 
     416             :     // that means the encrypted password is not going to be valid either
     417             :     //
     418           0 :     clear_string(f_plain_password);
     419           0 :     clear_string(f_encrypted_password);
     420           0 :     clear_string(f_salt);
     421             : 
     422           0 :     f_plain_password = plain_password;
     423           0 :     f_salt = salt;
     424           0 : }
     425             : 
     426             : 
     427             : /** \brief Ask the user to enter a password in his console.
     428             :  *
     429             :  * This function opens the process TTY ("/dev/tty") and reads a password.
     430             :  *
     431             :  * The function is responsible for cancel ECHO-ing in the console before
     432             :  * getting characters.
     433             :  *
     434             :  * This function accepts a \p salt parameter like the set_plain_password(),
     435             :  * it may be used to check the password of an existing user and not just to
     436             :  * create a new user entry so the salt is required.
     437             :  *
     438             :  * \note
     439             :  * The existing password information is cleared on entry. It is set to the
     440             :  * new password the user enters only if a valid password is entered. The
     441             :  * \p salt parameter is also used only if the new password is considered
     442             :  * valid.
     443             :  *
     444             :  * \todo
     445             :  * Add a minimum size for the password.
     446             :  *
     447             :  * \param[in] salt  The salt to encrypt the password.
     448             :  *
     449             :  * \return true if the password was properly entered, false otherwise.
     450             :  */
     451           0 : bool password::get_password_from_console(std::string const & salt)
     452             : {
     453             :     // read the new f_plain_password from the console
     454             :     //
     455           0 :     clear_string(f_plain_password);
     456           0 :     clear_string(f_encrypted_password);
     457           0 :     clear_string(f_salt);
     458             : 
     459             :     // the process must have a terminal
     460             :     //
     461           0 :     if(!isatty(STDIN_FILENO))
     462             :     {
     463           0 :         std::cerr << "snappassword:error: input terminal is not a TTY, cancel add with a --password option but no password." << std::endl;
     464           0 :         return 1;
     465             :     }
     466             : 
     467             :     // open process terminal
     468             :     //
     469           0 :     int tty(open("/dev/tty", O_RDONLY));
     470           0 :     if(tty == -1)
     471             :     {
     472           0 :         std::cerr << "snappassword:error: could not access process tty." << std::endl;
     473           0 :         return 1;
     474             :     }
     475           0 :     std::unique_ptr<int, decltype(&close_file)> raii_tty(&tty, close_file);
     476             : 
     477             :     // get current termios flags
     478             :     //
     479             :     struct safe_termios
     480             :     {
     481           0 :         safe_termios(int tty)
     482           0 :             : f_tty(tty)
     483             :         {
     484             :             // save the original termios flags
     485             :             //
     486           0 :             if(tcgetattr(f_tty, &f_original) != 0)
     487             :             {
     488           0 :                 return;
     489             :             }
     490             : 
     491             :             // setup termios to not echo input characters
     492             :             // and return characters one by one (avoid buffering)
     493             :             //
     494             :             // TODO: tcsetattr() returns 0 on success of any attribute changes
     495             :             //       meaning that we should call it once per change!
     496             :             //
     497           0 :             struct termios t(f_original);
     498           0 :             t.c_lflag &= ~(ICANON | ECHO);
     499           0 :             t.c_cc[VMIN] = 1;
     500           0 :             t.c_cc[VTIME] = 0;
     501           0 :             f_valid = tcsetattr(f_tty, TCSAFLUSH, &t) == 0;
     502             :         }
     503             : 
     504           0 :         ~safe_termios()
     505           0 :         {
     506             :             // restore the termios flags
     507             :             // ignore failures... it is likely to work since we did not
     508             :             // change the original data, but who knows.
     509             :             //
     510           0 :             NOTUSED(tcsetattr(f_tty, TCSAFLUSH, &f_original));
     511           0 :         }
     512             : 
     513           0 :         bool is_valid() const
     514             :         {
     515           0 :             return f_valid;
     516             :         }
     517             : 
     518             :     private:
     519             :         bool f_valid = false;
     520             :         int f_tty = -1;
     521             :         struct termios f_original = termios();
     522             :     };
     523             : 
     524           0 :     safe_termios st(tty);
     525           0 :     if(!st.is_valid())
     526             :     {
     527           0 :         std::cerr << "password:error: could not change terminal attributes to make it safe to read a password." << std::endl;
     528           0 :         return false;
     529             :     }
     530             : 
     531           0 :     std::string new_password;
     532             : 
     533           0 :     std::cout << "Password: " << std::flush;
     534             :     for(;;)
     535             :     {
     536             :         char c;
     537           0 :         if(read(tty, &c, 1) != 1)
     538             :         {
     539           0 :             std::cout << std::endl << std::flush;
     540           0 :             std::cerr << "snappassword:error: I/O error while reading from TTY." << std::endl;
     541           0 :             return false;
     542             :         }
     543           0 :         switch(c)
     544             :         {
     545           0 :         case '\b': // backspace
     546           0 :             if(!new_password.empty())
     547             :             {
     548             :                 // replace that last character with '.;, just in case
     549             :                 // then forget about it
     550             :                 //
     551           0 :                 new_password[new_password.length() - 1] = '.';
     552           0 :                 new_password.resize(new_password.length() - 1);
     553             :             }
     554           0 :             break;
     555             : 
     556           0 :         case '\n': // enter
     557           0 :             std::cout << std::endl << std::flush;
     558           0 :             if(new_password.empty())
     559             :             {
     560             :                 // we could allow empty passwords at some point?
     561             :                 //
     562           0 :                 std::cerr << "snappassword:error: password cannot be empty." << std::endl;
     563           0 :                 return false;
     564             :             }
     565           0 :             f_plain_password = new_password;
     566           0 :             f_salt = salt;
     567           0 :             clear_string(new_password);
     568           0 :             return true;
     569             : 
     570           0 :         default:
     571           0 :             if(c >= ' ')
     572             :             {
     573           0 :                 new_password += c;
     574             :             }
     575           0 :             break;
     576             : 
     577             :         }
     578           0 :     }
     579             : }
     580             : 
     581             : 
     582             : /** \brief Retrieve the plain password.
     583             :  *
     584             :  * This function returns a copy of the plain password.
     585             :  *
     586             :  * Note that the plain password is not available if the password object
     587             :  * was just set to an encrypted password (i.e. the "encryption" is a one
     588             :  * way hashing so we cannot get the password back out.) So you can get
     589             :  * the pain password only if the \p set_plain_password() was called earlier.
     590             :  *
     591             :  * \return The plain password.
     592             :  */
     593           0 : std::string const & password::get_plain_password() const
     594             : {
     595           0 :     return f_plain_password;
     596             : }
     597             : 
     598             : 
     599             : /** \brief Retrieve the salt of this password.
     600             :  *
     601             :  * When generating or encrypting a new password, the password object
     602             :  * also generates a new salt value. This salt has to be saved along
     603             :  * the encrypted password in order to be able to re-encrypt the same
     604             :  * password to the same value.
     605             :  *
     606             :  * \note
     607             :  * There is no set_salt() function. Instead, we expect you will call
     608             :  * the set_plain_password() including the salt parameter.
     609             :  *
     610             :  * \warning
     611             :  * The salt is not a printable string. It is a buffer of binary codes,
     612             :  * which may include '\0' bytes at any location. You must make sure to
     613             :  * use the length() function to know the exact size of the salt.
     614             :  *
     615             :  * \return The current salt key or an empty string if not defined.
     616             :  */
     617           0 : std::string const & password::get_salt() const
     618             : {
     619           0 :     return f_salt;
     620             : }
     621             : 
     622             : 
     623             : /** \brief Define the encrypted password.
     624             :  *
     625             :  * You may use this function to define the password object as an encrypted
     626             :  * password. This is used to one can compare two password for equality.
     627             :  *
     628             :  * This function let you set the salt. This is generally used when reading
     629             :  * the password from a file or a database. That way it can be read with
     630             :  * the get_salt() function and used with the plain password to encrypt it.
     631             :  *
     632             :  * \param[in] encrypted_password  The already encrypted password.
     633             :  * \param[in] salt  Set the password salt.
     634             :  */
     635           0 : void password::set_encrypted_password(std::string const & encrypted_password, std::string const & salt)
     636             : {
     637             :     // clear the previous data
     638             :     //
     639           0 :     clear_string(f_plain_password);
     640           0 :     clear_string(f_encrypted_password);
     641           0 :     clear_string(f_salt);
     642             : 
     643           0 :     f_encrypted_password = encrypted_password;
     644           0 :     f_salt = salt;
     645           0 : }
     646             : 
     647             : 
     648             : /** \brief Retrieve a copy of the encrypted password.
     649             :  *
     650             :  * In most cases this function is used to retrieve the resulting encrypted
     651             :  * password and then save it in a database.
     652             :  *
     653             :  * \note
     654             :  * The function caches the encrypted password so calling this function
     655             :  * multiple times is considered fast. However, if you change various
     656             :  * parameters, it is expected to recompute the new corresponding value.
     657             :  *
     658             :  * \return The encrypted password.
     659             :  */
     660           0 : std::string const & password::get_encrypted_password() const
     661             : {
     662           0 :     if(f_encrypted_password.empty())
     663             :     {
     664             :         // the encrypt password changes f_encrypted_password and
     665             :         // if required generates the password and salt strings
     666             :         //
     667           0 :         const_cast<password *>(this)->encrypt_password();
     668             :     }
     669             : 
     670           0 :     return f_encrypted_password;
     671             : }
     672             : 
     673             : 
     674             : /** \brief Check whether the encrypted passwords are equal.
     675             :  *
     676             :  * This function calls the get_encrypted_password() and compares
     677             :  * the results against each others. If the encrypted passwords
     678             :  * of both objects are the same, then it returns true.
     679             :  *
     680             :  * \param[in] rhs  The right hand side password to compare with this.
     681             :  *
     682             :  * \return true if the encrypted passwords are the same.
     683             :  */
     684           0 : bool password::operator == (password const & rhs) const
     685             : {
     686           0 :     return get_encrypted_password() == rhs.get_encrypted_password();
     687             : }
     688             : 
     689             : 
     690             : /** \brief Check whether this passwords is considered smaller.
     691             :  *
     692             :  * This function calls the get_encrypted_password() and compares
     693             :  * the results against each others. If this encrypted password
     694             :  * is considered smaller, then the function returns true.
     695             :  *
     696             :  * \param[in] rhs  The right hand side password to compare with this.
     697             :  *
     698             :  * \return true if this encrypted password is the smallest.
     699             :  */
     700           0 : bool password::operator < (password const & rhs) const
     701             : {
     702           0 :     return get_encrypted_password() < rhs.get_encrypted_password();
     703             : }
     704             : 
     705             : 
     706             : /** \brief Generate a new salt for a password.
     707             :  *
     708             :  * Every time you get to encrypt a new password, call this function to
     709             :  * get a new salt. This is important to avoid having the same hash for
     710             :  * the same password for multiple users.
     711             :  *
     712             :  * Imagine a user creating 3 accounts and each time using the exact same
     713             :  * password. Just using an md5sum it would encrypt that password to
     714             :  * exactly the same 16 bytes. In other words, if you crack one, you
     715             :  * crack all 3 (assuming you have access to the database you can
     716             :  * immediately see that all those accounts have the exact same password.)
     717             :  *
     718             :  * The salt prevents such problems. Plus we add 256 bits of completely
     719             :  * random entropy to the digest used to encrypt the passwords. This
     720             :  * in itself makes it for a much harder to decrypt hash.
     721             :  *
     722             :  * The salt is expected to be saved in the database along the password.
     723             :  */
     724           0 : void password::generate_password_salt()
     725             : {
     726           0 :     clear_string(f_salt);
     727             : 
     728             :     // we use 16 bytes before and 16 bytes after the password
     729             :     // so create a salt of SALT_SIZE bytes (256 bits at time of writing)
     730             :     //
     731             :     unsigned char buf[SALT_SIZE];
     732           0 :     int const r(RAND_bytes(buf, sizeof(buf)));
     733           0 :     if(r != 1)
     734             :     {
     735             :         // something happened, RAND_bytes() failed!
     736             :         //
     737             :         char err[256];
     738           0 :         ERR_error_string_n(ERR_peek_last_error(), err, sizeof(err));
     739             :         throw password_exception_function_failure(
     740           0 :             QString("RAND_bytes() error, it could not properly fill the salt buffer (%1: %2)")
     741           0 :                     .arg(ERR_peek_last_error())
     742           0 :                     .arg(err));
     743             :     }
     744             : 
     745           0 :     f_salt = std::string(reinterpret_cast<char *>(buf), sizeof(buf));
     746           0 : }
     747             : 
     748             : 
     749             : /** \brief Encrypt a password.
     750             :  *
     751             :  * This function generates a strong hash of a user password to prevent
     752             :  * easy brute force "decryption" of the password. (i.e. an MD5 can be
     753             :  * decrypted in 6 hours, and a SHA1 password, in about 1 day, with a
     754             :  * $100 GPU as of 2012.)
     755             :  *
     756             :  * Here we use 2 random salts (using RAND_bytes() which is expected to
     757             :  * be random enough for encryption like algorithms) and the specified
     758             :  * digest to encrypt (okay, hash--a one way "encryption") the password.
     759             :  *
     760             :  * Read more about hash functions on
     761             :  * http://ehash.iaik.tugraz.at/wiki/The_Hash_Function_Zoo
     762             :  *
     763             :  * \exception users_exception_size_mismatch
     764             :  * This exception is raised if the salt byte array is not exactly SALT_SIZE
     765             :  * bytes. For new passwords, you want to call the create_password_salt()
     766             :  * function to create the salt buffer.
     767             :  *
     768             :  * \exception users_exception_digest_not_available
     769             :  * This exception is raised if any of the OpenSSL digest functions fail.
     770             :  * This include an invalid digest name and adding/retrieving data to/from
     771             :  * the digest.
     772             :  *
     773             :  * \param[in] digest  The name of the digest to use (i.e. "sha512").
     774             :  * \param[in] password  The password to encrypt.
     775             :  * \param[in] salt  The salt information, necessary to encrypt passwords.
     776             :  */
     777           0 : void password::encrypt_password()
     778             : {
     779             :     // make sure we reset by default, if it fails, we get an empty string
     780             :     //
     781           0 :     clear_string(f_encrypted_password);
     782             : 
     783           0 :     if(f_plain_password.empty())
     784             :     {
     785           0 :         generate_password();
     786             :     }
     787             : 
     788           0 :     if(f_salt.empty())
     789             :     {
     790           0 :         generate_password_salt();
     791             :     }
     792             : 
     793             :     // Initialize so we gain access to all the necessary digests
     794           0 :     OpenSSL_add_all_digests();
     795             : 
     796             :     // retrieve the digest we want to use
     797             :     // (TODO: allows website owners to change this value)
     798           0 :     EVP_MD const * md(EVP_get_digestbyname(f_digest.c_str()));
     799           0 :     if(md == nullptr)
     800             :     {
     801           0 :         throw password_exception_digest_not_available("the specified digest could not be found");
     802             :     }
     803             : 
     804             :     // initialize the digest context
     805           0 :     std::unique_ptr<EVP_MD_CTX, decltype(&evp_md_ctx_deleter)> mdctx(evp_md_ctx_allocate(), evp_md_ctx_deleter);
     806           0 :     if(EVP_DigestInit_ex(mdctx.get(), md, nullptr) != 1)
     807             :     {
     808           0 :         throw password_exception_encryption_failed("EVP_DigestInit_ex() failed digest initialization");
     809             :     }
     810             : 
     811             :     // RAII cleanup
     812             :     //
     813             : 
     814             :     // add first salt
     815             :     //
     816           0 :     if(EVP_DigestUpdate(mdctx.get(), f_salt.c_str(), SALT_SIZE / 2) != 1)
     817             :     {
     818           0 :         throw password_exception_encryption_failed("EVP_DigestUpdate() failed digest update (salt1)");
     819             :     }
     820             : 
     821             :     // add password
     822             :     //
     823           0 :     if(EVP_DigestUpdate(mdctx.get(), f_plain_password.c_str(), f_plain_password.length()) != 1)
     824             :     {
     825           0 :         throw password_exception_encryption_failed("EVP_DigestUpdate() failed digest update (password)");
     826             :     }
     827             : 
     828             :     // add second salt
     829             :     //
     830           0 :     if(EVP_DigestUpdate(mdctx.get(), f_salt.c_str() + SALT_SIZE / 2, SALT_SIZE / 2) != 1)
     831             :     {
     832           0 :         throw password_exception_encryption_failed("EVP_DigestUpdate() failed digest update (salt2)");
     833             :     }
     834             : 
     835             :     // retrieve the result of the hash
     836             :     //
     837             :     unsigned char md_value[EVP_MAX_MD_SIZE];
     838           0 :     unsigned int md_len(EVP_MAX_MD_SIZE);
     839           0 :     if(EVP_DigestFinal_ex(mdctx.get(), md_value, &md_len) != 1)
     840             :     {
     841           0 :         throw password_exception_encryption_failed("EVP_DigestFinal_ex() digest finalization failed");
     842             :     }
     843           0 :     f_encrypted_password.append(reinterpret_cast<char *>(md_value), md_len);
     844           0 : }
     845             : 
     846             : 
     847             : /** \brief Clear a string so password do not stay in memory if possible.
     848             :  *
     849             :  * This function is used to clear the memory used by passwords. This
     850             :  * is a useful security trick, although really with encrypted passwords
     851             :  * in the Cassandra database, we will have passwords laying around anyway.
     852             :  *
     853             :  * \todo
     854             :  * See whether we could instead extend the std::string class? That way
     855             :  * we have that in the destructor and we can reuse it all over the place
     856             :  * where we load a password.
     857             :  *
     858             :  * \param[in,out] str  The string to clear.
     859             :  */
     860           0 : void password::clear_string(std::string & str)
     861             : {
     862             :     std::for_each(
     863             :               str.begin()
     864             :             , str.end()
     865           0 :             , [](auto & c)
     866             :             {
     867           0 :                 c = 0;
     868           0 :             });
     869           0 :     str.clear();
     870           0 : }
     871             : 
     872             : 
     873             : 
     874             : 
     875             : /** \brief Handle a password file.
     876             :  *
     877             :  * This constructor creates an object that knows how to handle a password
     878             :  * file.
     879             :  *
     880             :  * We only support our own format as follow:
     881             :  *
     882             :  * \li we support 4 fields (4 columns)
     883             :  * \li the fields are separated by colons
     884             :  * \li the first field is the user name
     885             :  * \li the second field is the digest used to hash the password
     886             :  * \li the third field is the password salt written in hexadecimal
     887             :  * \li the forth field is the password itself
     888             :  * \li lines are separated by '\\n'
     889             :  *
     890             :  * IMPORTANT NOTE: the password may include the ':' character.
     891             :  *
     892             :  * \warning
     893             :  * The password file will be loaded once and cached. If you are running
     894             :  * an application which sits around for a long time and other applications
     895             :  * may modify the password file, you want to use this class only
     896             :  * temporarilly (i.e. use it on your stack, make the necessary find/save
     897             :  * calls, then lose it.)
     898             :  *
     899             :  * \param[in] filename  The path and name of the password file.
     900             :  */
     901           0 : password_file::password_file(std::string const & filename)
     902           0 :     : f_passwords(filename)
     903             : {
     904           0 : }
     905             : 
     906             : 
     907             : /** \brief Clean up the file.
     908             :  *
     909             :  * This function makes sure to clean up the file.
     910             :  */
     911           0 : password_file::~password_file()
     912             : {
     913             :     // TODO: we need to be able to clear the file_content buffer
     914           0 : }
     915             : 
     916             : 
     917             : /** \brief Search for the specified user in this password file.
     918             :  *
     919             :  * This function scans the password file for the specified user
     920             :  * name (i.e. a line that starts with "name + ':'".)
     921             :  *
     922             :  * \exception password_exception_invalid_parameter
     923             :  * If the \p name parameter is an empty string, then this exception is raised.
     924             :  *
     925             :  * \param[in] name  The name of the user to search.
     926             :  * \param[out] password  The password if found.
     927             :  *
     928             :  * \return true if the password was found in the file.
     929             :  */
     930           0 : bool password_file::find(std::string const & name, password & p)
     931             : {
     932           0 :     if(name.empty())
     933             :     {
     934           0 :         throw password_exception_invalid_parameter("the password_file::find() function cannot be called with an empty string in 'name'");
     935             :     }
     936             : 
     937             :     // read the while file at once
     938             :     //
     939           0 :     if(!load_passwords())
     940             :     {
     941           0 :         return false;
     942             :     }
     943             : 
     944             :     // search the user
     945             :     //
     946           0 :     std::string const & passwords(f_passwords.get_content());
     947           0 :     std::string::size_type const user_pos(passwords.find(name + ":"));
     948             : 
     949             :     // did we find it?
     950             :     //
     951             :     // Note: if npos, obviously we did not find it at all
     952             :     //       if not npos, the character before must be a '\n', unless pos == 0
     953             :     //
     954           0 :     if(user_pos == std::string::npos
     955           0 :     || (user_pos != 0 && passwords[user_pos - 1] != '\n'))
     956             :     {
     957           0 :         return false;
     958             :     }
     959             : 
     960             :     // get the end of the line
     961             :     //
     962             :     // we use the end of line as the boundary of future searches
     963             :     //
     964           0 :     std::string::size_type const digest_position(user_pos + name.length() + 1);
     965           0 :     std::string::size_type const end_position(passwords.find("\n", digest_position));
     966           0 :     if(end_position == std::string::npos)
     967             :     {
     968           0 :         return false;
     969             :     }
     970             : 
     971             :     // search for the second ":"
     972             :     //
     973           0 :     std::string::size_type const salt_position(passwords.find(":", digest_position));
     974           0 :     if(salt_position == std::string::npos
     975           0 :     || digest_position == salt_position
     976           0 :     || salt_position >= end_position)
     977             :     {
     978             :         // either we did not find the next ":"
     979             :         // or the digest is an empty string, which is not considered valid
     980             :         //
     981           0 :         return false;
     982             :     }
     983             : 
     984             :     // search for the third ":"
     985             :     //
     986           0 :     std::string::size_type const password_position(passwords.find(":", salt_position + 1));
     987           0 :     if(password_position == std::string::npos
     988           0 :     || salt_position + 1 == password_position
     989           0 :     || password_position + 1 >= end_position)
     990             :     {
     991             :         // either we did not find the next ":"
     992             :         // or the salt is an empty string
     993             :         // or the password is empty
     994             :         //
     995           0 :         return false;
     996             :     }
     997             : 
     998           0 :     char const * ptr(passwords.c_str());
     999             : 
    1000             :     // setup the digest
    1001             :     //
    1002           0 :     std::string digest(ptr + digest_position, salt_position - digest_position);
    1003           0 :     p.set_digest(digest);
    1004           0 :     password::clear_string(digest);
    1005             : 
    1006             :     // setup the encrypted password and salt
    1007             :     //
    1008           0 :     std::string password_hex_salt(ptr + salt_position + 1, password_position - salt_position - 1);
    1009           0 :     std::string password_salt(hex_to_bin(password_hex_salt));
    1010           0 :     std::string encrypted_hex_password(ptr + password_position + 1, end_position - password_position - 1);
    1011           0 :     std::string encrypted_password(hex_to_bin(encrypted_hex_password));
    1012           0 :     p.set_encrypted_password(encrypted_password, password_salt);
    1013           0 :     password::clear_string(password_hex_salt);
    1014           0 :     password::clear_string(password_salt);
    1015           0 :     password::clear_string(encrypted_password);
    1016             : 
    1017             :     // done with success
    1018             :     //
    1019           0 :     return true;
    1020             : }
    1021             : 
    1022             : 
    1023             : /** \brief Save a password in this password_file.
    1024             :  *
    1025             :  * This function saves the specified password for the named user in
    1026             :  * this password_file. This function updates the content of the
    1027             :  * file so a future find() will find the new information as expected.
    1028             :  * However, if another application can make changes to the file, those
    1029             :  * will not be caught.
    1030             :  *
    1031             :  * If the named user already has a password defined in this file, then
    1032             :  * it gets replaced. Otherwise the new entry is added at the end.
    1033             :  *
    1034             :  * \warning
    1035             :  * This function has the side effect of calling rewind() so the next
    1036             :  * time you call the next() function, you will get the first user
    1037             :  * again.
    1038             :  *
    1039             :  * \param[in] name  The name of the user.
    1040             :  * \param[in] p  The password to save in this file.
    1041             :  */
    1042           0 : bool password_file::save(std::string const & name, password const & p)
    1043             : {
    1044           0 :     if(name.empty())
    1045             :     {
    1046           0 :         throw password_exception_invalid_parameter("the password_file::save() function cannot be called with an empty string in 'name'");
    1047             :     }
    1048             : 
    1049             :     // read the while file at once
    1050             :     //
    1051           0 :     if(!load_passwords())
    1052             :     {
    1053             :         // ... we are about to create the file if it does not exist yet ...
    1054             :     }
    1055             : 
    1056             :     std::string const new_line(
    1057             :               name
    1058           0 :             + ":"
    1059           0 :             + p.get_digest()
    1060           0 :             + ":"
    1061           0 :             + bin_to_hex(p.get_salt())
    1062           0 :             + ":"
    1063           0 :             + bin_to_hex(p.get_encrypted_password())
    1064           0 :             + "\n");
    1065             : 
    1066             :     // search the user
    1067             :     //
    1068           0 :     std::string const & passwords(f_passwords.get_content());
    1069           0 :     std::string::size_type const user_pos(passwords.find(name + ":"));
    1070             : 
    1071           0 :     std::string new_content;
    1072             : 
    1073             :     // did we find it?
    1074             :     //
    1075             :     // Note: if npos, obviously we did not find it at all
    1076             :     //       if not npos, the character before must be a '\n', unless pos == 0
    1077             :     //
    1078           0 :     if(user_pos == std::string::npos
    1079           0 :     || (user_pos != 0 && passwords[user_pos - 1] != '\n'))
    1080             :     {
    1081             :         // not found, append at the end
    1082             :         //
    1083           0 :         new_content = passwords + new_line;
    1084             :     }
    1085             :     else
    1086             :     {
    1087             :         // get the end of the line
    1088             :         //
    1089             :         // we will have 3 parts:
    1090             :         //
    1091             :         //    . what comes before 'user_pos'
    1092             :         //    . the line defining that user password
    1093             :         //    . what comas after the 'user_pos'
    1094             :         //
    1095           0 :         std::string::size_type const digest_position(user_pos + name.length() + 1);
    1096           0 :         std::string::size_type const end(passwords.find("\n", digest_position));
    1097           0 :         if(end == std::string::npos)
    1098             :         {
    1099           0 :             return false;
    1100             :         }
    1101             : 
    1102           0 :         char const * s(passwords.c_str());
    1103           0 :         std::string before(s, user_pos);
    1104           0 :         std::string after(s + end + 1, passwords.length() - end - 1);
    1105             :         // XXX: in regard to security, the + operator creates temporary buffers
    1106             :         //      (i.e. we would need to allocate our own buffer and copy there.)
    1107           0 :         new_content = before
    1108           0 :                     + new_line
    1109           0 :                     + after;
    1110           0 :         password::clear_string(before);
    1111           0 :         password::clear_string(after);
    1112             :     }
    1113             : 
    1114             :     // we are about to change the file so the f_next pointer is not unlikely
    1115             :     // to be invalidated, so we rewind it
    1116             :     //
    1117           0 :     rewind();
    1118             : 
    1119             :     // save the new content in the file_content object
    1120             :     //
    1121           0 :     f_passwords.set_content(new_content);
    1122             : 
    1123           0 :     password::clear_string(new_content);
    1124             : 
    1125             :     // write the new file to disk
    1126             :     //
    1127           0 :     f_passwords.write_all();
    1128             : 
    1129             :     // done with success
    1130             :     //
    1131           0 :     return true;
    1132             : }
    1133             : 
    1134             : 
    1135             : /** \brief Delete a user and his password from password_file.
    1136             :  *
    1137             :  * This function searches for the specified user, if found, then it gets
    1138             :  * removed from the password file. If that user is not defined in the
    1139             :  * password file, nothing happens.
    1140             :  *
    1141             :  * \warning
    1142             :  * This function has the side effect of calling rewind() so the next
    1143             :  * time you call the next() function, you will get the first user
    1144             :  * again.
    1145             :  *
    1146             :  * \param[in] name  The name of the user.
    1147             :  * \param[in] p  The password to save in this file.
    1148             :  */
    1149           0 : bool password_file::remove(std::string const & name)
    1150             : {
    1151           0 :     if(name.empty())
    1152             :     {
    1153           0 :         throw password_exception_invalid_parameter("the password_file::delete_user() function cannot be called with an empty string in 'name'");
    1154             :     }
    1155             : 
    1156             :     // read the while file at once
    1157             :     //
    1158           0 :     if(!load_passwords())
    1159             :     {
    1160           0 :         return false;
    1161             :     }
    1162             : 
    1163             :     // search the user
    1164             :     //
    1165           0 :     std::string const & passwords(f_passwords.get_content());
    1166           0 :     std::string::size_type const user_pos(passwords.find(name + ":"));
    1167             : 
    1168             :     // did we find it?
    1169             :     //
    1170             :     // Note: if npos, obviously we did not find it at all
    1171             :     //       if not npos, the character before must be a '\n', unless pos == 0
    1172             :     //
    1173           0 :     if(user_pos == std::string::npos
    1174           0 :     || (user_pos != 0 && passwords[user_pos - 1] != '\n'))
    1175             :     {
    1176             :         // not found, done
    1177             :         //
    1178           0 :         return true;
    1179             :     }
    1180             : 
    1181             :     // get the end of the line
    1182             :     //
    1183             :     // we will have 3 parts:
    1184             :     //
    1185             :     //    . what comes before 'user_pos'
    1186             :     //    . the line defining that user password
    1187             :     //    . what comas after the 'user_pos'
    1188             :     //
    1189           0 :     std::string::size_type const digest_position(user_pos + name.length() + 1);
    1190           0 :     std::string::size_type const end(passwords.find("\n", digest_position));
    1191           0 :     if(end == std::string::npos)
    1192             :     {
    1193           0 :         return false;
    1194             :     }
    1195             : 
    1196           0 :     char const * s(passwords.c_str());
    1197           0 :     std::string before(s, user_pos);
    1198           0 :     std::string after(s + end + 1, passwords.length() - end - 1);
    1199             :     // XXX: in regard to security, the + operator creates temporary buffers
    1200             :     //      (i.e. we would need to allocate our own buffer and copy there.)
    1201           0 :     std::string new_content(before + after);
    1202           0 :     password::clear_string(before);
    1203           0 :     password::clear_string(after);
    1204             : 
    1205             :     // we are about to change the file so the f_next pointer is not unlikely
    1206             :     // to be invalidated, so we rewind it
    1207             :     //
    1208           0 :     rewind();
    1209             : 
    1210             :     // save the new content in the file_content object
    1211             :     //
    1212           0 :     f_passwords.set_content(new_content);
    1213             : 
    1214           0 :     password::clear_string(new_content);
    1215             : 
    1216             :     // write the new file to disk
    1217             :     //
    1218           0 :     f_passwords.write_all();
    1219             : 
    1220             :     // done with success
    1221             :     //
    1222           0 :     return true;
    1223             : }
    1224             : 
    1225             : 
    1226             : /** \brief Read the next entry.
    1227             :  *
    1228             :  * This function can be used to read all the users one by one.
    1229             :  *
    1230             :  * The function returns the name of the user, which cannot be defined in
    1231             :  * the password object. Once the end of the file is reached, the function
    1232             :  * returns an empty string and does not modify \p p.
    1233             :  *
    1234             :  * \note
    1235             :  * The function may hit invalid input data, in which case it will return
    1236             :  * an empty string as if the end of the file was reached.
    1237             :  *
    1238             :  * \param[in,out] p  The password object where data gets saved.
    1239             :  *
    1240             :  * \return The username or an empty string once the end of the file is reached.
    1241             :  */
    1242           0 : std::string password_file::next(password & p)
    1243             : {
    1244           0 :     if(!load_passwords())
    1245             :     {
    1246           0 :         return std::string();
    1247             :     }
    1248             : 
    1249             :     // get the end of the line
    1250             :     //
    1251           0 :     std::string const & passwords(f_passwords.get_content());
    1252           0 :     std::string::size_type const next_user_pos(passwords.find("\n", f_next));
    1253           0 :     if(next_user_pos == std::string::npos)
    1254             :     {
    1255           0 :         return std::string();
    1256             :     }
    1257             : 
    1258             :     // retrieve the position of the end of the user name
    1259             :     //
    1260           0 :     std::string::size_type const end_name_pos(passwords.find(":", f_next, next_user_pos - f_next));
    1261           0 :     if(end_name_pos == std::string::npos)
    1262             :     {
    1263           0 :         return std::string();
    1264             :     }
    1265             : 
    1266           0 :     if(f_next == end_name_pos)
    1267             :     {
    1268           0 :         return std::string();
    1269             :     }
    1270             : 
    1271             :     // the find() function does all the parsing of the elements, use it
    1272             :     // instead of rewriting that code here (although we search for the
    1273             :     // user again... we could have a sub-function to avoid the double
    1274             :     // search!)
    1275             :     //
    1276           0 :     std::string const username(passwords.c_str(), end_name_pos - f_next);
    1277           0 :     find(username, p);
    1278             : 
    1279             :     // the next user will be found on the next line
    1280             :     //
    1281           0 :     f_next = next_user_pos + 1;
    1282             : 
    1283           0 :     return username;
    1284             : }
    1285             : 
    1286             : 
    1287             : /** \brief Reset the next pointer to the start of the file.
    1288             :  *
    1289             :  * This function allows you to restart the next() function to the beginning
    1290             :  * of the file.
    1291             :  */
    1292           0 : void password_file::rewind()
    1293             : {
    1294           0 :     f_next = 0;
    1295           0 : }
    1296             : 
    1297             : 
    1298             : /** \brief Load the password file once.
    1299             :  *
    1300             :  * This function loads the password file. It makes sure to not re-load
    1301             :  * it if it was already loaded.
    1302             :  */
    1303           0 : bool password_file::load_passwords()
    1304             : {
    1305           0 :     if(!f_file_loaded)
    1306             :     {
    1307           0 :         if(!f_passwords.read_all())
    1308             :         {
    1309           0 :             return false;
    1310             :         }
    1311           0 :         f_file_loaded = true;
    1312             :     }
    1313             : 
    1314           0 :     return true;
    1315             : }
    1316             : 
    1317             : 
    1318             : 
    1319           6 : } // namespace snap
    1320             : 
    1321             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13