#include "auth.h" #include "config.h" #include #include #include #include #include #define UUID_SIZE 36 #define SHA512_DIGEST_SIZE 64 #define FAIL_AUTH() do { \ strcpy(session_id, ""); \ retval = 0; \ goto defer; \ } while (0) int user_by_session_id(const char *session_id, char *username) { redisContext *ctx; redisReply *reply; uuid_t uu_tmp; struct timeval timeout = RA_CONNECTION_TIMEOUT; int retval = 0; ctx = NULL; reply = NULL; if (uuid_parse(session_id, uu_tmp) < 0) { retval = -EINVAL; goto defer; } ctx = redisConnectUnixWithTimeout(RA_HOSTNAME, timeout); if (!ctx || ctx->err) { retval = -EIO; goto defer; } reply = redisCommand(ctx, "GET session:%s", session_id); if (reply->type != REDIS_REPLY_STRING) { strcpy(username, ""); } else { strcpy(username, reply->str); } defer: redisFree(ctx); freeReplyObject(reply); return retval; } int authenticate(const char *username, const char *password, char *session_id) { redisContext *ctx; redisReply *salt_reply, *hash_reply, *sid_reply; char *sid; unsigned char db_hash[SHA512_DIGEST_SIZE], got_hash[SHA512_DIGEST_SIZE]; uuid_t uu_tmp; hash_state md; struct timeval timeout = RA_CONNECTION_TIMEOUT; int retval = 0; ctx = NULL; salt_reply = hash_reply = sid_reply = NULL; if (strlen(username) > RA_USER_MAX_LENGTH || strlen(password) > RA_PASSWORD_MAX_LENGTH) { retval = -EINVAL; goto defer; } ctx = redisConnectUnixWithTimeout(RA_HOSTNAME, timeout); if (!ctx || ctx->err) { retval = -EIO; goto defer; } salt_reply = redisCommand(ctx, "GET salt:%s", username); if (salt_reply->type != REDIS_REPLY_STRING) { FAIL_AUTH(); } hash_reply = redisCommand(ctx, "GET hash:%s", username); if (hash_reply->type != REDIS_REPLY_STRING || hash_reply->len != SHA512_DIGEST_SIZE) { FAIL_AUTH(); } memcpy(db_hash, hash_reply->str, SHA512_DIGEST_SIZE); sha512_init(&md); sha512_process(&md, RA_MAGIC, strlen(RA_MAGIC)); sha512_process(&md, password, strlen(password)); sha512_process(&md, salt_reply->str, strlen(salt_reply->str)); sha512_done(&md, got_hash); if (memcmp(db_hash, got_hash, SHA512_DIGEST_SIZE)) { FAIL_AUTH(); } else { redisCommand(ctx, "GET session:%s", username); if (sid_reply->type != REDIS_REPLY_STRING) { /* assuming there is no session for this user */ freeReplyObject(sid_reply); uuid_generate(uu_tmp); uuid_unparse(uu_tmp, session_id); sid_reply = redisCommand(ctx, "SET session:%s %s", username, session_id); freeReplyObject(sid_reply); sid_reply = redisCommand(ctx, "EXPIRY session:%s %d", username, RA_SESSION_EXPIRY); } else { strcpy(session_id, sid_reply->str); } retval = 1; } defer: redisFree(ctx); freeReplyObject(salt_reply); freeReplyObject(hash_reply); freeReplyObject(sid_reply); }