simple-discuss/src/redis_auth.c
thematdev 140738e4e8
Added redis auth module
In order to use hiredis it is needed to move from ANSI C to C99 or
gnu89.

For now redis auth code is untested it's just first compiling prototype
2023-07-04 18:39:14 +03:00

132 lines
3.1 KiB
C

#include "auth.h"
#include "config.h"
#include <hiredis/hiredis.h>
#include <uuid/uuid.h>
#include <string.h>
#include <errno.h>
#include <tomcrypt.h>
#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);
}