From 2819d11ceeb1ac739ed5f17ccb0abab63f494299 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sat, 2 Jan 2016 18:40:29 -0500 Subject: preliminary refactor of user data management --- src/auth.c | 41 +++++++++------------- src/auth.h | 40 +++++++++++++++++++++ src/client.c | 18 +++++++++- src/hash.h | 2 +- src/netcosm.h | 75 +++++++++++++++++++-------------------- src/server.c | 17 ++++----- src/telnet.h | 5 +++ src/test.c | 18 +++++----- src/userdb.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/userdb.h | 43 +++++++++++++++++++++++ 10 files changed, 289 insertions(+), 81 deletions(-) create mode 100644 src/auth.h create mode 100644 src/userdb.c create mode 100644 src/userdb.h (limited to 'src') diff --git a/src/auth.c b/src/auth.c index 5027e5f..c0a6a46 100644 --- a/src/auth.c +++ b/src/auth.c @@ -18,11 +18,6 @@ #include "netcosm.h" -#define SALT_LEN 12 -#define ALGO GCRY_MD_SHA512 -//#define HASH_ITERS 500000 -#define HASH_ITERS 1 - static bool valid_login_name(const char *name); /* returns a pointer to a malloc-allocated buffer containing the salted hex hash of pass */ @@ -65,7 +60,7 @@ static char *hash_pass_hex(const char *pass, const char *salt) return hex; } -static void add_user_append(int fd, const char *name, const char *pass, int authlevel) +static void add_user_internal(const char *name, const char *pass, int authlevel) { char salt[SALT_LEN + 1]; for(int i = 0; i < SALT_LEN; ++i) @@ -74,16 +69,22 @@ static void add_user_append(int fd, const char *name, const char *pass, int auth } salt[SALT_LEN] = '\0'; - char *hex = hash_pass_hex(pass, salt); + char *hexhash = hash_pass_hex(pass, salt); + + /* doesn't need to be malloc'd */ + struct userdata_t userdata; + + userdata.username = (char*)name; + + memcpy(userdata.passhash, hexhash, sizeof(userdata.passhash)); + + free(hexhash); - /* write */ - flock(fd, LOCK_EX); - if(dprintf(fd, "%s:%s:%s:%d\n", name, salt, hex, authlevel) < 0) - perror("dprintf"); - flock(fd, LOCK_UN); + userdata.priv = authlevel; - close(fd); - free(hex); + memcpy(userdata.salt, salt, sizeof(salt)); + + userdb_add(&userdata); } /* writes the contents of USERFILE to a temp file, and return its path, which is statically allocated */ @@ -108,7 +109,6 @@ static int remove_user_internal(const char *user, int *found, char **filename) size_t buflen = 0; ssize_t len = getline(&line, &buflen, in_fd); - /* getline's return value is the actual length of the line read */ /* it's second argument in fact stores the length of the /buffer/, not the line */ if(len < 0) @@ -181,20 +181,13 @@ bool auth_user_add(const char *user2, const char *pass2, int level) return false; } - /* remove any instances of the user in the file, write to temp file */ - char *tmp; - int out_fd = remove_user_internal(user, NULL, &tmp); - /* add user to end of temp file */ - add_user_append(out_fd, user, pass, level); - close(out_fd); + add_user_internal(user, pass, level); + free(user); memset(pass, 0, strlen(pass)); free(pass); - /* rename temp file -> user list */ - rename(tmp, USERFILE); - return true; } diff --git a/src/auth.h b/src/auth.h new file mode 100644 index 0000000..cd2fc1a --- /dev/null +++ b/src/auth.h @@ -0,0 +1,40 @@ +/* + * NetCosm - a MUD server + * Copyright (C) 2015 Franklin Wei + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define SALT_LEN 12 +#define ALGO GCRY_MD_SHA512 +#define AUTH_HASHLEN 64 +//#define HASH_ITERS 500000 +#define HASH_ITERS 1 + +struct authinfo_t { + bool success; + const char *user; + int authlevel; +}; + +/* makes admin account */ +void first_run_setup(void); + +struct authinfo_t auth_check(const char *user, const char *pass); + +bool auth_user_add(const char *user, const char *pass, int authlevel); +bool auth_user_del(const char *user); + +/* lists users through out() */ +void auth_user_list(void); diff --git a/src/client.c b/src/client.c index 2784987..8591858 100644 --- a/src/client.c +++ b/src/client.c @@ -172,7 +172,9 @@ void sig_rt_0_handler(int s, siginfo_t *info, void *v) } unsigned char cmd; + /* drop this command */ read(from_parent, &cmd, 1); + switch(cmd) { case REQ_BCASTMSG: @@ -211,6 +213,18 @@ void sig_rt_0_handler(int s, siginfo_t *info, void *v) sigqueue(getppid(), SIGRTMIN+1, junk); } +static void sigpipe_handler(int s) +{ + (void) s; + union sigval junk; + /* + * necessary in case we get SIGPIPE in our SIGRTMIN+1 handler, + * the master expects a response from us + */ + sigqueue(getppid(), SIGRTMIN+1, junk); + _exit(0); +} + static void client_change_state(int state) { send_master(REQ_CHANGESTATE, &state, sizeof(state)); @@ -289,7 +303,9 @@ void client_main(int fd, struct sockaddr_in *addr, int total, int to, int from) output_locked = 0; struct sigaction sa; - sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + sa.sa_handler = sigpipe_handler; + sa.sa_flags = SA_RESTART; if(sigaction(SIGPIPE, &sa, NULL) < 0) error("sigaction"); diff --git a/src/hash.h b/src/hash.h index 28a5352..5eb8135 100644 --- a/src/hash.h +++ b/src/hash.h @@ -39,7 +39,7 @@ void hash_setfreekey_cb(void*, void (*cb)(void *key)); void hash_free(void*); /* - * insert a pair, returns null if not already found, otherwise returns + * insert a pair, returns NULL if not already found, otherwise returns * the existing data pointer */ void *hash_insert(void*, const void *key, const void *data); diff --git a/src/netcosm.h b/src/netcosm.h index 3e056d2..c6acf44 100644 --- a/src/netcosm.h +++ b/src/netcosm.h @@ -18,6 +18,9 @@ #ifndef _NC_H_ #define _NC_H_ + +#define _GNU_SOURCE /* for pipe2() */ + #include #include #include @@ -44,6 +47,7 @@ #include "auth.h" #include "hash.h" #include "telnet.h" +#include "userdb.h" #define USERFILE "users.dat" #define WORLDFILE "world.dat" @@ -96,8 +100,6 @@ #define MSG_MAX 512 -#define ROOM_NONE -1 - #define ARRAYLEN(x) (sizeof(x)/sizeof(x[0])) #define MAX(a,b) ((a>b)?(a):(b)) #define MIN(a,b) ((ausername, + data->salt, + data->passhash, + &data->priv) != 6) + break; + + hash_insert(map, data->username, data); + ++entries; + } + + fclose(f); + } + + free(format); +} + +void userdb_write(const char *file) +{ + int fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0600); + void *save, *ptr = map; + while(1) + { + struct userdata_t *user = hash_iterate(ptr, &save, NULL); + ptr = NULL; + if(!user) + break; + dprintf(fd, "%s:%*s:%*s:%d\n", user->username, + SALT_LEN, user->salt, + AUTH_HASHLEN*2, user->passhash, + user->priv); + } + close(fd); +} + +struct userdata_t *userdb_lookup(const char *key) +{ + return hash_lookup(map, key); +} + +void userdb_remove(const char *key) +{ + if(hash_remove(map, key)) + --entries; +} + +struct userdata_t *userdb_add(struct userdata_t *data) +{ + struct userdata_t *new = calloc(1, sizeof(*new)); /* only in C! */ + memcpy(new, data, sizeof(*new)); + new->username = strdup(data->username); + struct userdata_t *ret; + if((ret = hash_insert(map, new->username, new))) /* failure */ + { + hash_remove(map, new->username); + ret = hash_insert(map, new->username, new); + } + + userdb_write(db_file); + if(!ret) + --entries; + + return ret; +} + +void userdb_shutdown(void) +{ + hash_free(map); + if(db_file) + free(db_file); +} + +size_t userdb_size(void) +{ + return entries; +} diff --git a/src/userdb.h b/src/userdb.h new file mode 100644 index 0000000..89e2566 --- /dev/null +++ b/src/userdb.h @@ -0,0 +1,43 @@ +#include "netcosm.h" + +/* + * on-disk database for storing user data + * + * child processes MUST go through the master to use this + */ + +struct userdata_t { + char *username; + + char salt[SALT_LEN + 1]; + + /* in hex + NULL terminator */ + char passhash[AUTH_HASHLEN * 2 + 1]; + + int priv; +}; + +/* call before using anything else */ +void userdb_init(const char *dbfile); + +/* looks up a username in the DB, returns NULL upon failure */ +struct userdata_t *userdb_lookup(const char *username); + +void userdb_remove(const char *username); + +/* is it empty? */ +size_t userdb_size(void); + +/* + * adds an entry to the DB + * if it already exists, OVERWRITE + * returns a pointer to the added entry, NULL on failure + * + * a DUPLICATE of the entry will be inserted + */ +struct userdata_t *userdb_add(struct userdata_t*); + +void userdb_shutdown(void); + +/* save the DB to disk */ +void userdb_write(const char*); -- cgit v1.1