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
This commit is contained in:
parent
10cbea0dac
commit
140738e4e8
5
Makefile
5
Makefile
@ -5,7 +5,7 @@ SD ?= src
|
||||
LIBS_DIR ?= libs
|
||||
LIBS ?= $(wildcard $(LIBS_DIR)/*)
|
||||
|
||||
LDFLAGS ?= -L$(BD)/ -lcgic -lqments
|
||||
LDFLAGS ?= -L$(BD)/ -lcgic -lqments -lhiredis -ltomcrypt -luuid
|
||||
|
||||
SRC_FILES := $(shell find $(SD) -name *.c)
|
||||
OBJ_FILES := $(patsubst $(SD)/%.c,$(BD)/%.o,$(SRC_FILES))
|
||||
@ -13,10 +13,11 @@ OBJ_FILES := $(patsubst $(SD)/%.c,$(BD)/%.o,$(SRC_FILES))
|
||||
INCLUDE_DIRS = -Ilibs/qments/include -Ilibs/cgic
|
||||
LIB_TARGETS = $(patsubst $(LIBS_DIR)/%,$(BD)/lib%.a,$(LIBS))
|
||||
|
||||
CFLAGS ?= -O2 -ansi -pedantic
|
||||
CFLAGS ?= -O2 -std=c99 -pedantic
|
||||
|
||||
$(BD)/libcgic.a:
|
||||
$(MAKE) -C $(LIBS_DIR)/cgic
|
||||
mkdir -p $(@D)
|
||||
cp $(LIBS_DIR)/cgic/libcgic.a $(BD)
|
||||
|
||||
$(BD)/libqments.a:
|
||||
|
12
src/auth.h
Normal file
12
src/auth.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef AUTH_H
|
||||
#define AUTH_H
|
||||
|
||||
/* return 0 on success, negative number on error
|
||||
* if session_id is not associated with any user, empty
|
||||
* string is put in username */
|
||||
int user_by_session_id(const char *session_id, char *username);
|
||||
|
||||
/* return 0 on failure, 1 on success, negative number on error */
|
||||
int authenticate(const char *username, const char *password, char *sid);
|
||||
|
||||
#endif /* AUTH_H */
|
18
src/config.h
Normal file
18
src/config.h
Normal file
@ -0,0 +1,18 @@
|
||||
#define RA_USER_MAX_LENGTH 64
|
||||
#define RA_PASSWORD_MAX_LENGTH 256
|
||||
|
||||
#define RA_SESSION_EXPIRY 86400
|
||||
|
||||
#define RA_CONNECTION_TIMEOUT {1, 500000}
|
||||
#define RA_HOSTNAME "ra-socket"
|
||||
|
||||
#define RA_MAGIC "$z$"
|
||||
|
||||
#define COMMENTS_PER_PAGE 20
|
||||
#define MAX_NAME_SIZE 1024
|
||||
#define MAX_COMMENT_SIZE 4096
|
||||
|
||||
#define QMENTS_PATH "qments-storage"
|
||||
#define DRIVER_DATA { QMENTS_PATH }
|
||||
#define DRIVER unix_fs_driver
|
||||
|
19
src/main.c
19
src/main.c
@ -4,19 +4,12 @@
|
||||
#include "cgic.h"
|
||||
#include "driver.h"
|
||||
#include "drivers/unix_fs/unix_fs_driver.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define COMMENTS_PER_PAGE 20
|
||||
#define MAX_NAME 1024
|
||||
#define MAX_COMMENT_SIZE 4096
|
||||
|
||||
#define QMENTS_PATH "qments-storage"
|
||||
#define DRIVER_DATA { QMENTS_PATH }
|
||||
#define DRIVER unix_fs_driver
|
||||
|
||||
int
|
||||
page_by_id(int id)
|
||||
{
|
||||
@ -51,8 +44,8 @@ render_comment(const Comment *comment)
|
||||
void
|
||||
allocate_header(CommentHeader *header)
|
||||
{
|
||||
header->user_sid = malloc(MAX_NAME);
|
||||
header->user_displayname = malloc(MAX_NAME);
|
||||
header->user_sid = malloc(MAX_NAME_SIZE);
|
||||
header->user_displayname = malloc(MAX_NAME_SIZE);
|
||||
}
|
||||
|
||||
void
|
||||
@ -163,7 +156,7 @@ print_page()
|
||||
int
|
||||
handle_submitted_comment()
|
||||
{
|
||||
char displayname[MAX_NAME], text[MAX_COMMENT_SIZE], *sanitized_text;
|
||||
char displayname[MAX_NAME_SIZE], text[MAX_COMMENT_SIZE], *sanitized_text;
|
||||
int rid, retval;
|
||||
cgiFormResultType err;
|
||||
CommentHeader header;
|
||||
@ -180,9 +173,9 @@ handle_submitted_comment()
|
||||
goto defer;
|
||||
}
|
||||
|
||||
err = cgiFormString("displayname", displayname, MAX_NAME);
|
||||
err = cgiFormString("displayname", displayname, MAX_NAME_SIZE);
|
||||
if (err == cgiFormTruncated) {
|
||||
fprintf(cgiOut, "Name too long (max %d bytes)\n", MAX_NAME);
|
||||
fprintf(cgiOut, "Name too long (max %d bytes)\n", MAX_NAME_SIZE);
|
||||
goto defer;
|
||||
}
|
||||
if (err == cgiFormNotFound) {
|
||||
|
131
src/redis_auth.c
Normal file
131
src/redis_auth.c
Normal file
@ -0,0 +1,131 @@
|
||||
#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);
|
||||
}
|
@ -50,5 +50,5 @@ sb_init_empty(StringBuffer *buffer)
|
||||
void
|
||||
sb_free(StringBuffer *buffer)
|
||||
{
|
||||
free(buffer->buf);
|
||||
if (buffer) free(buffer->buf);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user