Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
1c1a982829 | |||
c920d34e23 |
2
Makefile
2
Makefile
@ -6,7 +6,7 @@ LIBS ?= $(wildcard $(LIBS_DIR)/*)
|
||||
CGI_EXECS ?= view_comments.cgi new_client.cgi
|
||||
EXEC_TARGETS := $(patsubst %.cgi,$(BD)/%.cgi,$(CGI_EXECS))
|
||||
|
||||
LDFLAGS ?= -L$(BD)/ -lcgic -lqments -lhiredis -ltomcrypt -luuid
|
||||
LDFLAGS ?= -L$(BD)/ -lconfig -lcgic -lqments -lhiredis -ltomcrypt -luuid
|
||||
|
||||
SRC_FILES := $(shell find $(SD) -name *.c)
|
||||
EXEC_OBJS := $(patsubst %.cgi,$(BD)/%.o,$(CGI_EXECS))
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit a3490b7612f194f029b6e7a7fc602ad962bc33e2
|
||||
Subproject commit 40e57a1a9c222ea9757c52ba9f92f0d2d5cb2630
|
22
redis_create_user.sh
Executable file
22
redis_create_user.sh
Executable file
@ -0,0 +1,22 @@
|
||||
die() {
|
||||
echo "$@" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
magic='$z$'
|
||||
redis_socket=$1
|
||||
read -p "Username: " username
|
||||
read -s -p "Password: " password
|
||||
echo
|
||||
read -s -p "Confirm your password: " password_conf
|
||||
echo
|
||||
if [[ $password != $password_conf ]]; then
|
||||
die "Passwords don't match"
|
||||
fi
|
||||
|
||||
salt=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13)
|
||||
|
||||
encoded_hash=$({ echo -n $magic; echo -n $password; echo -n $salt; } | sha512sum - \
|
||||
| xxd -r -p | od -tx1 - | sed -e 's/^[0-9]* //' -e '$d' -e 's/^/ /' -e 's/ /\\x/g' | tr -d '\n')
|
||||
redis-cli -s $redis_socket set salt:$username $salt || die "Failed to send redis command"
|
||||
echo \'\"$encoded_hash\"\' | xargs -n 1 redis-cli --quoted-input -s $redis_socket set hash:$username || die "Failed to send redis command"
|
@ -1,6 +1,9 @@
|
||||
#ifndef AUTH_H
|
||||
#define AUTH_H
|
||||
|
||||
/* return 0 on success; negative number on error */
|
||||
int load_auth_config();
|
||||
|
||||
/* return 0 on success, negative number on error
|
||||
* if session_id is not associated with any user, empty
|
||||
* string is put in username */
|
||||
|
36
src/config.c
Normal file
36
src/config.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
config_t config;
|
||||
|
||||
int
|
||||
try_preload_config(const char *filename)
|
||||
{
|
||||
if (access(filename, F_OK) != 0) {
|
||||
return CFG_PLD_NOT_FOUND;
|
||||
}
|
||||
if (config_read_file(&config, filename) == CONFIG_FALSE) {
|
||||
return CFG_PLD_INVALID;
|
||||
}
|
||||
return CFG_PLD_OK;
|
||||
}
|
||||
|
||||
int
|
||||
preload_config(const char *filename)
|
||||
{
|
||||
char **filename_ptr = config_preload_paths;
|
||||
int err;
|
||||
if (filename) {
|
||||
err = try_preload_config(filename);
|
||||
if (err != CFG_PLD_NOT_FOUND) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
while (filename_ptr && (err = try_preload_config(*filename_ptr++))) {
|
||||
if (err != CFG_PLD_NOT_FOUND) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
56
src/config.h
56
src/config.h
@ -1,20 +1,48 @@
|
||||
#define RA_USER_MAX_LENGTH 64
|
||||
#define RA_PASSWORD_MAX_LENGTH 256
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#define RA_SESSION_EXPIRE 86400
|
||||
#include "drivers/unix_fs/unix_fs_driver.h"
|
||||
#include "driver.h"
|
||||
|
||||
#define RA_CONNECTION_TIMEOUT {1, 500000}
|
||||
#define RA_HOSTNAME "ra-socket"
|
||||
#include <sys/time.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
#define RA_MAGIC "$z$"
|
||||
enum ConfigPreloadError {
|
||||
CFG_PLD_INVALID = -2,
|
||||
CFG_PLD_NOT_FOUND,
|
||||
CFG_PLD_OK
|
||||
};
|
||||
|
||||
#define COMMENTS_PER_PAGE 20
|
||||
#define MAX_NAME_SIZE 1024
|
||||
#define MAX_COMMENT_SIZE 4096
|
||||
static char *config_preload_paths[] = {"discuss.conf", "/etc/discuss.conf", NULL};
|
||||
extern config_t config;
|
||||
|
||||
#define QMENTS_PATH "qments-storage"
|
||||
#define DRIVER_DATA { QMENTS_PATH }
|
||||
#define DRIVER unix_fs_driver
|
||||
/* first tries to load config `filename`, then tries preload_paths in order
|
||||
* on first invalid config returns CFG_PLD_INVALID,
|
||||
* if all paths do not exist returns CFG_PLD_NOT_FOUND
|
||||
* if filename is NULL, checks only preload_paths
|
||||
*/
|
||||
int preload_config(const char *filename);
|
||||
|
||||
#define SESSION_COOKIE_NAME "thecookie"
|
||||
#define HOSTNAME "localhost"
|
||||
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
|
||||
#define CONF_ROOT_LOOKUP(type, name) config_lookup_##type(&config, #name, &name)
|
||||
|
||||
/* defaults */
|
||||
static int comments_per_page = 20;
|
||||
|
||||
static int max_name_size = 1024;
|
||||
static int max_comment_size = 4096;
|
||||
|
||||
static int user_max_length = 64;
|
||||
static int password_max_length = 256;
|
||||
|
||||
static int session_expire = 86400;
|
||||
|
||||
static char *qments_path = "qments-storage";
|
||||
static UnixFsDriverData driver_data;
|
||||
static Driver driver = unix_fs_driver;
|
||||
|
||||
static char *session_cookie_name = "thecookie";
|
||||
static char *hostname = "localhost";
|
||||
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define UUID_SIZE 37
|
||||
|
||||
@ -11,12 +13,12 @@
|
||||
char *
|
||||
validate_credentials()
|
||||
{
|
||||
char username[RA_USER_MAX_LENGTH + 1], password[RA_PASSWORD_MAX_LENGTH + 1];
|
||||
char username[user_max_length + 1], password[password_max_length + 1];
|
||||
char session_id[UUID_SIZE];
|
||||
cgiFormResultType err;
|
||||
int auth;
|
||||
|
||||
err = cgiFormString("username", username, RA_USER_MAX_LENGTH + 1);
|
||||
err = cgiFormString("username", username, user_max_length + 1);
|
||||
if (err == cgiFormTruncated) {
|
||||
return "Username too long\n";
|
||||
}
|
||||
@ -24,7 +26,7 @@ validate_credentials()
|
||||
return "Username not provided\n";
|
||||
}
|
||||
|
||||
err = cgiFormString("password", password, RA_PASSWORD_MAX_LENGTH + 1);
|
||||
err = cgiFormString("password", password, password_max_length + 1);
|
||||
if (err == cgiFormTruncated) {
|
||||
return "Password too long\n";
|
||||
}
|
||||
@ -46,7 +48,7 @@ validate_credentials()
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
cgiHeaderCookieSet(SESSION_COOKIE_NAME, session_id, RA_SESSION_EXPIRE, "/", HOSTNAME, 0);
|
||||
cgiHeaderCookieSet(session_cookie_name, session_id, session_expire, "/", hostname, 0);
|
||||
return "You've successfully logged in!\n";
|
||||
} else {
|
||||
return "Failed to log in, check credentials\n";
|
||||
@ -68,7 +70,24 @@ print_login_form()
|
||||
int
|
||||
cgiMain()
|
||||
{
|
||||
int cfg_pld_err;
|
||||
char *message;
|
||||
|
||||
config_init(&config);
|
||||
cfg_pld_err = preload_config((cgiArgc > 1 ? cgiArgv[1] : NULL));
|
||||
|
||||
if (cfg_pld_err == CFG_PLD_INVALID) {
|
||||
syslog(LOG_ERR, "Got invalid config\n");
|
||||
syslog(LOG_ERR, "%s\n", config_error_text(&config));
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (cfg_pld_err == CFG_PLD_NOT_FOUND) {
|
||||
syslog(LOG_WARNING, "Config not found, loading defaults\n");
|
||||
} else {
|
||||
load_auth_config();
|
||||
}
|
||||
|
||||
CONF_ROOT_LOOKUP(int, session_expire);
|
||||
|
||||
if (cgiFormSubmitClicked("login") == cgiFormSuccess &&
|
||||
!strcmp(cgiRequestMethod, "POST")) {
|
||||
message = validate_credentials();
|
||||
@ -76,7 +95,6 @@ cgiMain()
|
||||
message = "";
|
||||
}
|
||||
|
||||
|
||||
cgiHeaderContentType("text/html; charset=utf-8");
|
||||
|
||||
fprintf(cgiOut, "<html>\n");
|
||||
|
@ -16,13 +16,33 @@
|
||||
goto defer; \
|
||||
} while (0)
|
||||
|
||||
/* redis auth defaults */
|
||||
static struct timeval ra_connection_timeout = {1, 500000}; /* 1.5 secs */
|
||||
|
||||
static char *ra_hostname = "ra-socket";
|
||||
static char *ra_magic = "$z$";
|
||||
|
||||
|
||||
int
|
||||
load_auth_config()
|
||||
{
|
||||
CONF_ROOT_LOOKUP(string, ra_hostname);
|
||||
CONF_ROOT_LOOKUP(string, ra_magic);
|
||||
|
||||
CONF_ROOT_LOOKUP(int, user_max_length);
|
||||
CONF_ROOT_LOOKUP(int, password_max_length);
|
||||
|
||||
CONF_ROOT_LOOKUP(int, session_expire);
|
||||
|
||||
return 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;
|
||||
@ -33,7 +53,7 @@ user_by_session_id(const char *session_id, char *username)
|
||||
goto defer;
|
||||
}
|
||||
|
||||
ctx = redisConnectUnixWithTimeout(RA_HOSTNAME, timeout);
|
||||
ctx = redisConnectUnixWithTimeout(ra_hostname, ra_connection_timeout);
|
||||
|
||||
if (!ctx || ctx->err) {
|
||||
retval = -EIO;
|
||||
@ -44,6 +64,10 @@ user_by_session_id(const char *session_id, char *username)
|
||||
if (reply->type != REDIS_REPLY_STRING) {
|
||||
strcpy(username, "");
|
||||
} else {
|
||||
if (reply->len > user_max_length + 1) {
|
||||
retval = -EINVAL;
|
||||
goto defer;
|
||||
}
|
||||
strcpy(username, reply->str);
|
||||
}
|
||||
|
||||
@ -62,18 +86,17 @@ authenticate(const char *username, const char *password, char *session_id)
|
||||
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) {
|
||||
if (strlen(username) > user_max_length || strlen(password) > password_max_length) {
|
||||
retval = -EINVAL;
|
||||
goto defer;
|
||||
}
|
||||
|
||||
ctx = redisConnectUnixWithTimeout(RA_HOSTNAME, timeout);
|
||||
ctx = redisConnectUnixWithTimeout(ra_hostname, ra_connection_timeout);
|
||||
|
||||
if (!ctx || ctx->err) {
|
||||
retval = -EIO;
|
||||
@ -96,7 +119,7 @@ authenticate(const char *username, const char *password, char *session_id)
|
||||
|
||||
sha512_init(&md);
|
||||
|
||||
sha512_process(&md, RA_MAGIC, strlen(RA_MAGIC));
|
||||
sha512_process(&md, ra_magic, strlen(ra_magic));
|
||||
sha512_process(&md, password, strlen(password));
|
||||
sha512_process(&md, salt_reply->str, strlen(salt_reply->str));
|
||||
|
||||
@ -120,9 +143,9 @@ authenticate(const char *username, const char *password, char *session_id)
|
||||
} else {
|
||||
strcpy(session_id, sid_reply->str);
|
||||
}
|
||||
sid_reply = redisCommand(ctx, "EXPIRE session:%s %d", username, RA_SESSION_EXPIRE);
|
||||
sid_reply = redisCommand(ctx, "EXPIRE session:%s %d", username, session_expire);
|
||||
freeReplyObject(sid_reply);
|
||||
sid_reply = redisCommand(ctx, "EXPIRE username:%s %d", session_id, RA_SESSION_EXPIRE);
|
||||
sid_reply = redisCommand(ctx, "EXPIRE username:%s %d", session_id, session_expire);
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define VALID_FOR_USERNAME(c) (isalpha(c) || c == '_')
|
||||
#define VALID_FOR_USERNAME(c) (isalpha(c) || isdigit(c) || c == '_')
|
||||
|
||||
int
|
||||
contain_special(const char *s)
|
||||
|
@ -1,25 +1,26 @@
|
||||
#include "config.h"
|
||||
#include "string_buffer.h"
|
||||
#include "utils.h"
|
||||
#include "comment.h"
|
||||
#include "cgic.h"
|
||||
#include "driver.h"
|
||||
#include "drivers/unix_fs/unix_fs_driver.h"
|
||||
#include "config.h"
|
||||
#include "auth.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#define UUID_SIZE 37
|
||||
|
||||
char authorized_user_sid[RA_USER_MAX_LENGTH + 1], session_id[UUID_SIZE];
|
||||
char session_id[UUID_SIZE], *authorized_user_sid;
|
||||
|
||||
int
|
||||
page_by_id(int id)
|
||||
{
|
||||
return id / COMMENTS_PER_PAGE + 1;
|
||||
return id / comments_per_page + 1;
|
||||
}
|
||||
|
||||
void
|
||||
@ -50,8 +51,8 @@ render_comment(const Comment *comment)
|
||||
void
|
||||
allocate_header(CommentHeader *header)
|
||||
{
|
||||
header->user_sid = malloc(MAX_NAME_SIZE);
|
||||
header->user_displayname = malloc(MAX_NAME_SIZE);
|
||||
header->user_sid = malloc(max_name_size);
|
||||
header->user_displayname = malloc(max_name_size);
|
||||
}
|
||||
|
||||
void
|
||||
@ -120,8 +121,6 @@ print_page()
|
||||
int page, max_id;
|
||||
int id_begin, id_end, i;
|
||||
Comment comment;
|
||||
UnixFsDriverData driver_data = DRIVER_DATA;
|
||||
Driver driver = DRIVER;
|
||||
|
||||
cgiFormInteger("page", &page, 0);
|
||||
if ((max_id = unix_fs_driver_get_max_id(&driver_data)) < 0) {
|
||||
@ -131,18 +130,18 @@ print_page()
|
||||
|
||||
if (page <= 0) {
|
||||
id_end = max_id;
|
||||
id_begin = (max_id > COMMENTS_PER_PAGE ? max_id - COMMENTS_PER_PAGE : 1);
|
||||
id_begin = (max_id > comments_per_page ? max_id - comments_per_page : 1);
|
||||
} else {
|
||||
/* max_id > COMMENTS_PER_PAGE * (page - 1) + 1
|
||||
* max_id - 1 > COMMENTS_PER_PAGE * (page - 1)
|
||||
/* max_id > comments_per_page * (page - 1) + 1
|
||||
* max_id - 1 > comments_per_page * (page - 1)
|
||||
* perform this check without overflow
|
||||
*/
|
||||
if ((max_id + COMMENTS_PER_PAGE - 1) / COMMENTS_PER_PAGE <= (page - 1)) {
|
||||
if ((max_id + comments_per_page - 1) / comments_per_page <= (page - 1)) {
|
||||
fprintf(cgiOut, "There is no such page\n");
|
||||
return;
|
||||
}
|
||||
id_begin = COMMENTS_PER_PAGE * (page - 1) + 1;
|
||||
id_end = id_begin + COMMENTS_PER_PAGE;
|
||||
id_begin = comments_per_page * (page - 1) + 1;
|
||||
id_end = id_begin + comments_per_page;
|
||||
if (id_end > max_id) {
|
||||
id_end = max_id;
|
||||
}
|
||||
@ -162,16 +161,14 @@ print_page()
|
||||
int
|
||||
handle_submitted_comment()
|
||||
{
|
||||
char displayname[MAX_NAME_SIZE], text[MAX_COMMENT_SIZE], *sanitized_text;
|
||||
char displayname[max_name_size], text[max_comment_size], *sanitized_text;
|
||||
int rid, retval;
|
||||
cgiFormResultType err;
|
||||
CommentHeader header;
|
||||
Driver driver = DRIVER;
|
||||
UnixFsDriverData driver_data = DRIVER_DATA;
|
||||
|
||||
err = cgiFormString("text", text, MAX_COMMENT_SIZE);
|
||||
err = cgiFormString("text", text, max_comment_size);
|
||||
if (err == cgiFormTruncated) {
|
||||
fprintf(cgiOut, "Comment too long (max %d bytes)\n", MAX_COMMENT_SIZE);
|
||||
fprintf(cgiOut, "Comment too long (max %d bytes)\n", max_comment_size);
|
||||
goto defer;
|
||||
}
|
||||
if (err == cgiFormNotFound) {
|
||||
@ -179,9 +176,9 @@ handle_submitted_comment()
|
||||
goto defer;
|
||||
}
|
||||
|
||||
err = cgiFormString("displayname", displayname, MAX_NAME_SIZE);
|
||||
err = cgiFormString("displayname", displayname, max_name_size);
|
||||
if (err == cgiFormTruncated) {
|
||||
fprintf(cgiOut, "Name too long (max %d bytes)\n", MAX_NAME_SIZE);
|
||||
fprintf(cgiOut, "Name too long (max %d bytes)\n", max_name_size);
|
||||
goto defer;
|
||||
}
|
||||
if (err == cgiFormNotFound) {
|
||||
@ -224,7 +221,35 @@ defer:
|
||||
int
|
||||
cgiMain()
|
||||
{
|
||||
if (cgiCookieString(SESSION_COOKIE_NAME, session_id, UUID_SIZE) == cgiFormSuccess) {
|
||||
int cfg_pld_err;
|
||||
config_init(&config);
|
||||
cfg_pld_err = preload_config((cgiArgc > 1 ? cgiArgv[1] : NULL));
|
||||
|
||||
if (cfg_pld_err == CFG_PLD_INVALID) {
|
||||
syslog(LOG_ERR, "Got invalid config\n");
|
||||
syslog(LOG_ERR, "%s\n", config_error_text(&config));
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (cfg_pld_err == CFG_PLD_NOT_FOUND) {
|
||||
syslog(LOG_WARNING, "Config not found, loading defaults\n");
|
||||
} else {
|
||||
load_auth_config();
|
||||
}
|
||||
|
||||
CONF_ROOT_LOOKUP(int, comments_per_page);
|
||||
CONF_ROOT_LOOKUP(int, max_name_size);
|
||||
CONF_ROOT_LOOKUP(int, max_comment_size);
|
||||
|
||||
CONF_ROOT_LOOKUP(int, user_max_length);
|
||||
CONF_ROOT_LOOKUP(int, password_max_length);
|
||||
|
||||
CONF_ROOT_LOOKUP(string, qments_path);
|
||||
CONF_ROOT_LOOKUP(string, session_cookie_name);
|
||||
CONF_ROOT_LOOKUP(string, hostname);
|
||||
|
||||
driver_data.path = qments_path;
|
||||
|
||||
authorized_user_sid = malloc(user_max_length + 1);
|
||||
if (cgiCookieString(session_cookie_name, session_id, UUID_SIZE) == cgiFormSuccess) {
|
||||
user_by_session_id(session_id, authorized_user_sid);
|
||||
} else {
|
||||
authorized_user_sid[0] = '\0';
|
||||
@ -253,6 +278,9 @@ cgiMain()
|
||||
fprintf(cgiOut, "</body>\n");
|
||||
|
||||
fprintf(cgiOut, "</html>\n");
|
||||
|
||||
free(authorized_user_sid);
|
||||
config_destroy(&config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user