aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2015-12-03 17:57:36 -0500
committerFranklin Wei <git@fwei.tk>2015-12-03 17:57:36 -0500
commit1c795424fde9839ab6ebfd49ce7a84ac946be3c0 (patch)
tree2a33473d1ada10efe52b770ce9ec8ab2d452ec20 /src
downloadnetcosm-1c795424fde9839ab6ebfd49ce7a84ac946be3c0.zip
netcosm-1c795424fde9839ab6ebfd49ce7a84ac946be3c0.tar.gz
netcosm-1c795424fde9839ab6ebfd49ce7a84ac946be3c0.tar.bz2
netcosm-1c795424fde9839ab6ebfd49ce7a84ac946be3c0.tar.xz
initial commit
Diffstat (limited to 'src')
-rw-r--r--src/auth.c68
-rw-r--r--src/client.c47
-rw-r--r--src/netcosm.h23
-rw-r--r--src/server.c142
4 files changed, 280 insertions, 0 deletions
diff --git a/src/auth.c b/src/auth.c
new file mode 100644
index 0000000..55fe083
--- /dev/null
+++ b/src/auth.c
@@ -0,0 +1,68 @@
+#include "netcosm.h"
+
+/* add a user to the on-disk database */
+
+/*
+ * format:
+ * [login]:[hash]\n
+*/
+
+void add_user(const char *name, const char *pass)
+{
+ int fd = open(USERFILE, O_WRONLY | O_CREAT | O_APPEND, 0600);
+
+ int hash_len = gcry_md_get_algo_dlen(GCRY_MD_SHA512);
+ unsigned char *hash = malloc(hash_len);
+ gcry_md_hash_buffer(GCRY_MD_SHA512, hash, pass, strlen(pass));
+ char *hex = malloc(hash_len * 2 + 1);
+ char *ptr = hex;
+ for(int i = 0; i < hash_len; ++i, ++ptr)
+ snprintf(ptr, 3, "%02x", hash[i]);
+
+ flock(fd, LOCK_EX);
+
+ dprintf(fd, "%s:%s\n", name, hex);
+
+ flock(fd, LOCK_UN);
+}
+
+bool valid_login_name(const char *name)
+{
+ while(*name)
+ {
+ char c = *name++;
+ switch(c)
+ {
+ case ':':
+ return false;
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+void first_run_setup(void)
+{
+ printf("Welcome to NetCosm!\n");
+ printf("Please set up the administrator account now.\n");
+
+ char *admin_name;
+ size_t len = 0;
+ do {
+ admin_name = NULL;
+ printf("Admin account name: ");
+ fflush(stdout);
+ getline(&admin_name, &len, stdin);
+ } while(!valid_login_name(admin_name));
+
+ printf("Admin password (DO NOT USE A VALUABLE PASSWORD): ");
+ fflush(stdout);
+ char *admin_pass = NULL;
+ len = 0;
+ getline(&admin_pass, &len, stdin);
+
+ /* hash and store */
+
+ add_user(admin_name, admin_pass);
+}
diff --git a/src/client.c b/src/client.c
new file mode 100644
index 0000000..e907172
--- /dev/null
+++ b/src/client.c
@@ -0,0 +1,47 @@
+#include "netcosm.h"
+
+int client_fd;
+
+void __attribute__((format(printf,1,2))) out(const char *fmt, ...)
+{
+ char buf[128];
+ memset(buf, 0, sizeof(buf));
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ write(client_fd, buf, sizeof(buf));
+}
+
+char *client_read(void)
+{
+ static char buf[128];
+ if(read(client_fd, buf, sizeof(buf) - 1) < 0)
+ {
+ error("lost connection");
+ exit(EXIT_FAILURE);
+ }
+ buf[sizeof(buf) - 1] = '\0';
+ const unsigned char ctrlc[] = { 0xff, 0xf4, 0xff, 0xfd, 0x06 };
+
+ if(!memcmp(buf, ctrlc, sizeof(ctrlc)))
+ exit(0);
+
+ return buf;
+}
+
+void client_main(int fd, struct sockaddr_in *addr, int total)
+{
+ client_fd = fd;
+
+ bool admin = false;
+
+ char *ip = inet_ntoa(addr->sin_addr);
+ printf("New client %s\n", ip);
+ printf("Total clients: %d\n", total);
+ out("Hello %s.\n", ip);
+ out("Please authenticate to continue.\n");
+ out("login: ");
+ char *input = client_read();
+
+}
diff --git a/src/netcosm.h b/src/netcosm.h
new file mode 100644
index 0000000..e8a1384
--- /dev/null
+++ b/src/netcosm.h
@@ -0,0 +1,23 @@
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <gcrypt.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define USERFILE "users.dat"
+
+void client_main(int fd, struct sockaddr_in *addr, int);
+void __attribute__((noreturn)) error(const char *fmt, ...);
+void first_run_setup(void);
diff --git a/src/server.c b/src/server.c
new file mode 100644
index 0000000..e727d19
--- /dev/null
+++ b/src/server.c
@@ -0,0 +1,142 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "netcosm.h"
+
+#define PORT 1234
+#define BACKLOG 16
+
+void __attribute__((noreturn)) error(const char *fmt, ...)
+{
+ char buf[128];
+ memset(buf, 0, sizeof(buf));
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ perror(buf);
+ exit(EXIT_FAILURE);
+}
+
+void sigchld_handler(int s)
+{
+ // waitpid() might overwrite errno, so we save and restore it:
+ int saved_errno = errno;
+
+ while(waitpid(-1, NULL, WNOHANG) > 0);
+
+ errno = saved_errno;
+}
+
+int port;
+
+void handle_client(int fd, struct sockaddr_in *addr, int num_clients)
+{
+ client_main(fd, addr, num_clients);
+}
+
+int server_socket;
+
+void serv_cleanup(void)
+{
+ printf("Shutdown server.\n");
+ if(shutdown(server_socket, SHUT_RDWR) > 0)
+ error("shutdown");
+ close(server_socket);
+}
+
+void sigint_handler(int sig)
+{
+ serv_cleanup();
+}
+
+int main(int argc, char *argv[])
+{
+ port = PORT;
+ int sock = socket(AF_INET, SOCK_STREAM, 0);
+
+ if(sock<0)
+ error("socket");
+
+ int tmp = 1;
+
+ if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof tmp) < 0)
+ error("setsockopt");
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if(bind(sock, (struct sockaddr*) &addr, sizeof addr) < 0)
+ error("bind");
+
+ if(listen(sock, BACKLOG) < 0)
+ error("listen");
+
+ server_socket = sock;
+
+ struct sigaction sa;
+
+ sa.sa_handler = sigchld_handler; // reap all dead processes
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ if (sigaction(SIGCHLD, &sa, NULL) == -1) {
+ perror("sigaction");
+ exit(1);
+ }
+
+ signal(SIGINT, sigint_handler);
+
+ int num_clients = 0;
+
+ if(access(USERFILE, F_OK) < 0)
+ first_run_setup();
+
+ printf("Listening on port %d\n", port);
+
+ while(1)
+ {
+ struct sockaddr_in client;
+ socklen_t client_len;
+ int new_sock = accept(sock, (struct sockaddr*) &client, &client_len);
+ if(new_sock < 0)
+ error("accept");
+
+ pid_t pid = fork();
+ if(pid < 0)
+ error("fork");
+ if(!pid)
+ {
+ close(sock);
+
+ server_socket = new_sock;
+
+ ++num_clients;
+
+ handle_client(new_sock, &client, num_clients);
+
+ --num_clients;
+
+ exit(0);
+ }
+ else
+ close(new_sock);
+ }
+}