aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/auth.c170
-rw-r--r--src/client.c115
-rw-r--r--src/netcosm.h10
-rw-r--r--src/server.c2
4 files changed, 230 insertions, 67 deletions
diff --git a/src/auth.c b/src/auth.c
index f47aee8..4bcb6b5 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -8,11 +8,15 @@
/*
* format:
- * [login]:[hash]\n
+ * { [username]:[salt]:[hash]:[authlevel]\n } [N]
*/
+static bool valid_login_name(const char *name);
+
static void add_user_append(int fd, const char *name, const char *pass, int authlevel)
{
+ if(errno < 0)
+ perror("unknown");
size_t pass_len = strlen(pass);
/* salt */
@@ -27,9 +31,7 @@ static void add_user_append(int fd, const char *name, const char *pass, int auth
memcpy(salted + SALT_LEN, pass, pass_len);
salted[pass_len + SALT_LEN] = '\0';
- printf("hashing %s\n", salted);
-
- int hash_len = gcry_md_get_algo_dlen(ALGO);
+ unsigned int hash_len = gcry_md_get_algo_dlen(ALGO);
unsigned char *hash = malloc(hash_len);
gcry_md_hash_buffer(ALGO, hash, salted, pass_len + SALT_LEN);
free(salted);
@@ -37,83 +39,131 @@ static void add_user_append(int fd, const char *name, const char *pass, int auth
/* convert to hex */
char *hex = malloc(hash_len * 2 + 1);
char *ptr = hex;
- for(int i = 0; i < hash_len; ++i, ptr += 2)
+ for(unsigned int i = 0; i < hash_len; ++i, ptr += 2)
snprintf(ptr, 3, "%02x", hash[i]);
free(hash);
/* write */
-
flock(fd, LOCK_EX);
-
- dprintf(fd, "%s:%s:%s:%d\n", name, salt, hex, authlevel);
-
- free(hex);
-
+ if(dprintf(fd, "%s:%s:%s:%d\n", name, salt, hex, authlevel) < 0)
+ perror("dprintf");
+ printf("writing %s:%s:%s:%d\n", name, salt, hex, authlevel);
flock(fd, LOCK_UN);
+
close(fd);
+ free(hex);
+ perror("add_user_append");
}
-void add_user(const char *name2, const char *pass2, int level)
+/* writes the contents of USERFILE to a temp file, and return its path, which is statically allocated */
+static char *remove_user_internal(const char *user, int *found)
{
- char *name = strdup(name2);
- strtok(name, "\r\n");
- char *pass = strdup(pass2);
- strtok(pass, "\r\n");
-
- /* remove any instances of the user in the file, write to temp file */
+ FILE *in_fd = fopen(USERFILE, "a+");
+ static char tmp[] = "userlist_tmp.XXXXXX";
+ int out_fd = mkstemp(tmp);
+ if(found)
+ *found = 0;
- FILE *in_fd = fopen(USERFILE, "w+");
- flock(fileno(in_fd), LOCK_SH);
- char *tmp = tmpnam(NULL);
- int out_fd = open(tmp, O_CREAT | O_WRONLY, 0600);
while(1)
{
char *line = NULL;
- size_t len = 0;
- if(getline(&line, &len, in_fd) < 0)
+ char *junk;
+ 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)
+ {
+ free(line);
break;
- if(strcmp(strtok(line, ":\r\n"), name) != 0)
- write(out_fd, line, len);
- }
- flock(fileno(in_fd), LOCK_UN);
- fclose(in_fd);
+ }
- /* add user to end of temp file */
+ char *old = strdup(line);
+
+ char *user_on_line = strtok_r(line, ":\r\n", &junk);
+
+ if(strcmp(user_on_line, user) != 0)
+ {
+ write(out_fd, old, len);
+ }
+ else
+ if(found)
+ (*found)++;
+ free(line);
+ free(old);
+ }
- add_user_append(out_fd, name, pass, level);
close(out_fd);
+ fclose(in_fd);
- /* rename temp file -> user list */
- int fd = open(tmp, O_RDONLY);
- int userfile = open(USERFILE, O_WRONLY | O_TRUNC | O_CREAT, 0600);
+ return tmp;
+}
- ssize_t nread;
- char buf[1024];
- while (nread = read(fd, buf, sizeof buf), nread > 0)
+bool auth_remove(const char *user2)
+{
+ char *user = strdup(user2);
+ strtok(user, "\r\n");
+ if(valid_login_name(user))
+ {
+ int found = 0;
+ char *tmp = remove_user_internal(user, &found);
+ free(user);
+ if(found)
+ {
+ rename(tmp, USERFILE);
+ return true;
+ }
+ else
+ {
+ remove(tmp);
+ return false;
+ }
+ }
+ else
{
- printf("writing %d bytes\n", nread);
- char *out_ptr = buf;
- ssize_t nwritten;
+ free(user);
+ return false;
+ }
+}
- do {
- nwritten = write(userfile, out_ptr, nread);
+bool add_change_user(const char *user2, const char *pass2, int level)
+{
+ char *user = strdup(user2);
+ strtok(user, "\r\n");
+ char *pass = strdup(pass2);
+ strtok(pass, "\r\n");
- if (nwritten >= 0)
- {
- nread -= nwritten;
- out_ptr += nwritten;
- }
- else
- break;
- } while (nread > 0);
+ printf("Add user '%s'\n", user);
+
+ if(!valid_login_name(user))
+ {
+ free(user);
+ free(pass);
+ return false;
}
- close(userfile);
- remove(tmp);
+ /* remove any instances of the user in the file, write to temp file */
+ char *tmp = remove_user_internal(user, NULL);
+
+ printf("point 0\n");
+
+ /* add user to end of temp file */
+ int out_fd = open(tmp, O_WRONLY | O_APPEND);
+ add_user_append(out_fd, user, pass, level);
+ printf("point 1\n");
+ close(out_fd);
+ printf("point 2\n");
+
+ /* rename temp file -> user list */
+ rename(tmp, USERFILE);
+
+ return true;
}
-bool valid_login_name(const char *name)
+static bool valid_login_name(const char *name)
{
while(*name)
{
@@ -154,7 +204,9 @@ void first_run_setup(void)
len = 0;
getline(&admin_pass, &len, stdin);
strtok(admin_pass, "\r\n");
- add_user(admin_name, admin_pass, 0);
+
+ if(!add_change_user(admin_name, admin_pass, PRIV_ADMIN))
+ error("Unknown error");
/* zero the memory */
memset(admin_name, 0, strlen(admin_name));
@@ -165,6 +217,8 @@ void first_run_setup(void)
struct authinfo_t auth_check(const char *name2, const char *pass2)
{
+ sleep(1);
+
/* get our own copy to remove newlines */
char *name = strdup(name2);
char *pass = strdup(pass2);
@@ -179,7 +233,7 @@ struct authinfo_t auth_check(const char *name2, const char *pass2)
struct authinfo_t ret;
ret.success = false;
- ret.authlevel = -1;
+ ret.authlevel = PRIV_NONE;
while(1)
{
@@ -202,7 +256,7 @@ struct authinfo_t auth_check(const char *name2, const char *pass2)
free(line);
- int hash_len = gcry_md_get_algo_dlen(ALGO);
+ unsigned int hash_len = gcry_md_get_algo_dlen(ALGO);
if(strlen(hash) != hash_len * 2)
error("hash corrupt %d %d", strlen(hash), hash_len * 2);
@@ -224,7 +278,7 @@ struct authinfo_t auth_check(const char *name2, const char *pass2)
char *hex = malloc(hash_len * 2 + 1);
char *ptr = hex;
- for(int i = 0; i < hash_len; ++i, ptr += 2)
+ for(unsigned int i = 0; i < hash_len; ++i, ptr += 2)
snprintf(ptr, 3, "%02x", newhash[i]);
free(newhash);
@@ -249,7 +303,7 @@ good:
printf("Successful authentication.\n");
return ret;
bad:
+ sleep(2);
printf("Failed authentication.\n");
- sleep(1);
return ret;
}
diff --git a/src/client.c b/src/client.c
index b49498f..d836467 100644
--- a/src/client.c
+++ b/src/client.c
@@ -17,7 +17,9 @@ void __attribute__((format(printf,1,2))) out(const char *fmt, ...)
char *client_read(void)
{
- char *buf = malloc(BUFSZ);
+ char *buf;
+tryagain:
+ buf = malloc(BUFSZ);
memset(buf, 0, BUFSZ);
if(read(client_fd, buf, BUFSZ - 1) < 0)
error("lost connection");
@@ -27,9 +29,27 @@ char *client_read(void)
if(!memcmp(buf, ctrlc, sizeof(ctrlc)))
exit(0);
+ printf("Read '%s'\n", buf);
+ if(buf[0] & 0x80)
+ {
+ free(buf);
+ goto tryagain;
+ }
+
return buf;
}
+void all_upper(char *s)
+{
+ while(*s)
+ {
+ *s = toupper(*s);
+ s++;
+ }
+}
+
+#define WSPACE " \t\r\n"
+
void client_main(int fd, struct sockaddr_in *addr, int total)
{
client_fd = fd;
@@ -50,17 +70,19 @@ void client_main(int fd, struct sockaddr_in *addr, int total)
int authlevel;
+ char *current_user;
+
/* auth loop */
while(1)
{
out("login: ");
- char *user = client_read();
+ current_user = client_read();
out("Password: ");
char *pass = client_read();
- printf("pass is %s\n", pass);
- struct authinfo_t auth = auth_check(user, pass);
- free(user);
+ struct authinfo_t auth = auth_check(current_user, pass);
+ memset(pass, 0, strlen(pass));
free(pass);
+
authlevel = auth.authlevel;
if(auth.success)
{
@@ -69,26 +91,101 @@ void client_main(int fd, struct sockaddr_in *addr, int total)
}
else
{
+ free(current_user);
out("Access Denied.\n\n");
if(++failures >= MAX_FAILURES)
return;
}
}
+ /* something has gone wrong, but we are here for some reason */
+ if(authlevel == PRIV_NONE)
+ return;
+
+ bool admin = (authlevel == PRIV_ADMIN);
+
/* authenticated */
while(1)
{
out(">> ");
char *cmd = client_read();
- char *tok = strtok(cmd, " \t\r\n");
+ char *save = NULL;
+
+ char *tok = strtok_r(cmd, WSPACE, &save);
+
+ all_upper(tok);
- if(!strcmp(tok, "USER"))
+ if(admin)
{
- void change_user(const char *name2, const char *pass2, int level);
- add_user("admin", "test", 0);
+ if(!strcmp(tok, "USER"))
+ {
+ char *what = strtok_r(NULL, WSPACE, &save);
+ all_upper(what);
+
+ if(!strcmp(what, "DEL"))
+ {
+ char *user = strtok_r(NULL, WSPACE, &save);
+ if(user)
+ {
+ if(strcmp(user, current_user) && auth_remove(user))
+ out("Success.\n");
+ else
+ out("Failure.\n");
+ }
+ else
+ {
+ out("Usage: USER DEL <USERNAME>\n");
+ }
+ }
+ else if(!strcmp(what, "ADD") || !strcmp(what, "PASS"))
+ {
+ char *user = strtok_r(NULL, WSPACE, &save);
+ if(user)
+ {
+ if(!strcmp(user, current_user))
+ {
+ out("Do not modify your own password using USER. User CHPASS instead.\n");
+ goto next_cmd;
+ }
+
+ out("Editing user '%s'\n", user);
+
+ out("New Password (_DO_NOT_USE_A_VALUABLE_PASSWORD_): ");
+
+ /* BAD BAD BAD BAD BAD BAD BAD CLEARTEXT PASSWORDS!!! */
+ char *pass = client_read();
+
+ out("Admin privileges [y/N]? ");
+ char *allow_admin = client_read();
+ int priv = PRIV_USER;
+ if(toupper(allow_admin[0]) == 'Y')
+ priv = PRIV_ADMIN;
+
+ if(add_change_user(user, pass, priv))
+ out("Success.\n");
+ else
+ out("Failure.\n");
+ memset(pass, 0, strlen(pass));
+ free(pass);
+ }
+ else
+ out("Usage: USER ADD|CHANGE <USERNAME>\n");
+ }
+ }
}
+ if(!strcmp(tok, "QUIT"))
+ {
+ free(cmd);
+ goto done;
+ }
+
+ next_cmd:
+
free(cmd);
}
+
+done:
+ free(current_user);
}
diff --git a/src/netcosm.h b/src/netcosm.h
index d7251ad..4f04e5b 100644
--- a/src/netcosm.h
+++ b/src/netcosm.h
@@ -1,4 +1,5 @@
#include <arpa/inet.h>
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <gcrypt.h>
@@ -14,12 +15,17 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <time.h>
#include <unistd.h>
#define USERFILE "users.dat"
#define MAX_FAILURES 3
#define NETCOSM_VERSION "v0.1"
+#define PRIV_NONE -1
+#define PRIV_USER 0
+#define PRIV_ADMIN 1337
+
struct authinfo_t {
bool success;
const char *user;
@@ -30,3 +36,7 @@ void client_main(int fd, struct sockaddr_in *addr, int);
void __attribute__((noreturn)) error(const char *fmt, ...);
void first_run_setup(void);
struct authinfo_t auth_check(const char*, const char*);
+
+/* add or change a user */
+bool add_change_user(const char *user2, const char *pass2, int level);
+bool auth_remove(const char*);
diff --git a/src/server.c b/src/server.c
index e717cfe..39719eb 100644
--- a/src/server.c
+++ b/src/server.c
@@ -37,6 +37,7 @@ int num_clients = 0;
void sigchld_handler(int s)
{
+ (void) s;
printf("Client disconnect.\n");
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
@@ -67,6 +68,7 @@ void serv_cleanup(void)
void sigint_handler(int sig)
{
+ (void) sig;
serv_cleanup();
}