Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pure-ftpd and Postgreql Auth with password salt

I've recently begun the task of setting up an PureFTP server. At work we use Postgresql 8.4. The schema essentially boils down to,

username        text
password        character(40)
password_salt   text

The password is stored as hash of sha1( password + salt ). Using Postgresql's pgcrypto I can supply a username, and password and find out if the user has auth:

SELECT
 encode( digest( $password ||password_salt, 'sha1' ), 'hex' ) = password
   AS password_correct
 , username
 , password
 , password_salt
FROM contact.person;

Now the issue that I'm having is that such a function would require me getting the password into the query. This doesn't seem possible with Pureftp's current implementation of auth-postgresql. It only supports providing:

\L is replaced by the login of a user trying to authenticate.
\I is replaced by the IP address the client connected to.
\P is replaced by the port number the client connected to.
\R is replaced by the remote IP address the client connected from.
\D is replaced by the remote IPv4 address, as a long decimal number.

Is there another way I can do this? I either need to get the password into the query, or get the salt and password out and find another way to write the code in Pureftp.

Obviously, I have another option of writing a custom authentication module, but I would think this basic salting would be supported by the pg module.

References

  • Pure FTPd's Postgresql-auth docs
  • Postgresql 8.4's pgcrypto
like image 707
NO WAR WITH RUSSIA Avatar asked Nov 05 '22 17:11

NO WAR WITH RUSSIA


1 Answers

I had the very same problem. However, writing my own custom authentication module would've been an overkill since the available pgsql auth does nearly everything I want.. Here's what changes I made for it to suit my needs:

In log_pgsql_p.h add static char *salting; and static char *sqlreq_getsalt; and extend the static ConfigKeywords pgsql_config_keywords[] with { "PGSQLSalting", &salting }, and { "PGSQLGetSalt", &sqlreq_getsalt },.

In log_pgsql.h I added #define SALT_SQL_APPEND "append", #define SALT_SQL_PREPEND "prepend" and #define SALT_SQL_NONE "none".

In log_pgsql.c I then made the following changes in the pw_psql_check function:

I declared const char *salt = NULL; and char * salted_password = NULL; at the top. Directly before spwd gets assigned the result of the query to sqlreq_getpw I added

if (strcasecmp(salting, SALT_SQL_NONE) != 0) {
    salt = pw_pgsql_getquery(id_sql_server, sqlreq_getsalt,
                             escaped_account, escaped_ip,
                             escaped_port, escaped_peer_ip,
                             escaped_decimal_ip);
}

Then, before the encryption takes place:

if (salt != NULL) {
    int salted_pw_size = strlen(salt) + strlen(password) + 1;
    salted_password = (char *) malloc(salted_pw_size);
    if (strcasecmp(salting, SALT_SQL_APPEND) == 0) {
        strcpy(salted_password, password);
        strcat(salted_password, salt);            
    } else if (strcasecmp(salting, SALT_SQL_PREPEND) == 0) {
        strcpy(salted_password, salt);
        strcat(salted_password, password);
    }
} else {
    salted_password = (char *) malloc(strlen(password));
    strcpy(salted_password, password);
}

And then I replaced the password argument in subsequent calls to the crypt-methods (crypt, crypto_hash_md5, crypto_hash_sha1) and the strcasecmp for 'cleartext' with (const char*)salted_password.

Now all that's left to do is tidying up the memory we allocated. Especially the plaintext-password with appended/prepended salt shouldn't remain in memory - call it paranoia if you want. So after the bye: label add

free((void *) salt;
if(strcasecmp(salting, SALT_SQL_NONE) != 0) {
    volatile char *salted_password_ = (volatile char *) salted_password;
    while(*salted_password_ != 0) {
        *salted_password_++ = 0;
    }
    free((void *) salted_password);
}

With these changes you now have two additional parameters in your config file available:

  • PGSQLSalting: Accepts 'append' (appends the salt to the pw), 'prepend' and 'none' (without the apostrophe)
  • PGSQLGetSalt: Here you specify the field in your db to fetch the salt from, much like with the crypted password you need to retrieve via PGSQLGetPw.

Edit: Oh, and don't forget to free the allocated memory at the end of the function!

I also can provide a diff file that works for the release 1.0.36.. here you go! Beware though, i added the if around the freeing of salted_password later (because i only later realized how this might lead to an error if salted_password points to password), so this is not in the diff and I'm too lazy to change the diff file :/

like image 94
kaikuchn Avatar answered Nov 09 '22 16:11

kaikuchn