aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/auth.c5
-rw-r--r--src/auth.h6
-rw-r--r--src/client.c64
-rw-r--r--src/client_reqs.c6
-rw-r--r--src/globals.h7
-rw-r--r--src/obj.c6
-rw-r--r--src/obj.h2
-rw-r--r--src/server.c50
-rw-r--r--src/server_reqs.c62
-rw-r--r--src/server_reqs.h5
-rw-r--r--src/userdb.c2
-rw-r--r--src/util.c87
-rw-r--r--src/util.h3
-rw-r--r--src/world.c30
14 files changed, 210 insertions, 125 deletions
diff --git a/src/auth.c b/src/auth.c
index 069e9fe..c7b53d3 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -193,11 +193,12 @@ struct userdata_t *auth_check(const char *name2, const char *pass2)
{
debugf("auth module: user %s found\n", name2);
- /* hashes are in HEX to avoid the Trucha bug */
+ /* hashes are in lowercase hex to avoid the Trucha bug
+ * but still allow comparison with strcmp() */
char *new_hash_hex = hash_pass_hex(pass, salt);
bool success = true;
- /* constant-time comparison to a timing attack */
+ /* constant-time comparison to hopefully prevent a timing attack */
for(int i = 0; i < AUTH_HASHLEN; ++i)
{
if(new_hash_hex[i] != hash[i])
diff --git a/src/auth.h b/src/auth.h
index ba24595..c5c9dc1 100644
--- a/src/auth.h
+++ b/src/auth.h
@@ -26,12 +26,6 @@
//#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);
diff --git a/src/client.c b/src/client.c
index 3117b63..d66836e 100644
--- a/src/client.c
+++ b/src/client.c
@@ -46,9 +46,9 @@ void out_raw(const void *buf, size_t len)
error("out() called from master");
if(!len)
return;
-
+
try_again:
-
+
while(output_locked);
/* something weird happened and the value changed between the loop and here */
@@ -103,8 +103,8 @@ void __attribute__((format(printf,1,2))) out(const char *fmt, ...)
if(is_newline)
++ptr; /* skip the newline */
- /* skip following spaces */
- while(*ptr == ' ')
+ /* skip following spaces */
+ while(*ptr == ' ')
++ptr;
last_space = 0;
pos = 0;
@@ -208,7 +208,10 @@ int user_cb(char **save)
{
char *what = strtok_r(NULL, WSPACE, save);
if(!what)
+ {
+ out("Usage: USER <ADD|DEL|MODIFY|LIST> <ARGS>\n");
return CMD_OK;
+ }
all_upper(what);
@@ -308,7 +311,7 @@ int client_cb(char **save)
char *pid_s = strtok_r(NULL, WSPACE, save);
if(pid_s)
{
- all_upper(pid_s);
+ all_upper(pid_s);
if(!strcmp(pid_s, "ALL"))
{
const char *msg = "Kicking everyone...\n";
@@ -338,7 +341,7 @@ int client_cb(char **save)
debugf("Success.\n");
}
else
- out("Usage: CLIENT KICK <PID>\n");
+ out("Usage: CLIENT KICK <PID|ALL>\n");
}
return CMD_OK;
}
@@ -427,9 +430,53 @@ int drop_cb(char **save)
{
char *what = strtok_r(NULL, "", save);
if(what)
- client_drop(what);
+ client_drop(what);
else
- out("You must supply an object.\n");
+ out("You must supply an object.\n");
+ return CMD_OK;
+}
+
+int chpass_cb(char **save)
+{
+ out("Enter current password: ");
+ char *current = client_read_password();
+
+ struct userdata_t *current_data = auth_check(current_user, current);
+
+ memset(current, 0, strlen(current));
+ free(current);
+
+ if(!current_data)
+ {
+ out("Password mismatch.\n");
+ return CMD_OK;
+ }
+
+ out("Enter new password: ");
+ char *pass1 = client_read_password();
+
+ out("Retype new password: ");
+
+ char *pass2 = client_read_password();
+
+ if(strcmp(pass1, pass2))
+ {
+ memset(pass1, 0, strlen(pass1));
+ memset(pass2, 0, strlen(pass2));
+ free(pass1);
+ free(pass2);
+
+ out("Passwords do not match.\n");
+ return CMD_OK;
+ }
+
+ memset(pass2, 0, strlen(pass2));
+ free(pass2);
+
+ auth_user_add(current_user, pass1, current_data->priv);
+
+ memset(pass1, 0, strlen(pass1));
+
return CMD_OK;
}
@@ -451,6 +498,7 @@ static const struct client_cmd {
{ "WAIT", wait_cb, true },
{ "GO", go_cb, false },
{ "DROP", drop_cb, false },
+ { "CHPASS", chpass_cb, false },
};
static void *cmd_map = NULL;
diff --git a/src/client_reqs.c b/src/client_reqs.c
index 36f341c..21174c4 100644
--- a/src/client_reqs.c
+++ b/src/client_reqs.c
@@ -267,11 +267,11 @@ void client_take(char *obj)
{
if(obj)
{
- all_lower(obj);
- send_master(REQ_TAKE, obj, strlen(obj) + 1);
+ all_lower(obj);
+ send_master(REQ_TAKE, obj, strlen(obj) + 1);
}
else
- out("You must supply an object.\n");
+ out("You must supply an object.\n");
}
void client_inventory(void)
diff --git a/src/globals.h b/src/globals.h
index 0177b8a..5a164ba 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -21,17 +21,18 @@
#define _GNU_SOURCE
-#include <libev/ev.h>
+#include <ev.h>
+
#include <openssl/sha.h>
#include <openssl/opensslv.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>
#include <assert.h>
-//#include <bsd/string.h> // for strlcat
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <limits.h>
#include <netdb.h>
#include <netinet/in.h>
@@ -66,7 +67,7 @@
#define WORLD_MAGIC 0x31415926
#define USERDB_MAGIC 0x27182818
#define MAX_FAILURES 3
-#define NETCOSM_VERSION "0.5.0"
+#define NETCOSM_VERSION "0.5.1"
/* username length */
#define MAX_NAME_LEN 32
diff --git a/src/obj.c b/src/obj.c
index deeb30d..296fbb5 100644
--- a/src/obj.c
+++ b/src/obj.c
@@ -144,7 +144,7 @@ struct object_t *obj_copy(struct object_t *obj)
struct object_t *obj_dup(struct object_t *obj)
{
- debugf("Adding an object reference to #%lu.\n", obj->id);
+ debugf("Adding an object reference to #%" PRI_OBJID ".\n", obj->id);
++obj->refcount;
return obj;
}
@@ -154,11 +154,11 @@ void obj_free(void *ptr)
struct object_t *obj = ptr;
--obj->refcount;
- debugf("Freeing an object reference for #%lu (%s, %d).\n", obj->id, obj->name, obj->refcount);
+ debugf("Freeing an object reference for #%" PRI_OBJID" (%s, %d).\n", obj->id, obj->name, obj->refcount);
if(!obj->refcount)
{
- debugf("Freeing object #%lu\n", obj->id);
+ debugf("Freeing object #%"PRI_OBJID"\n", obj->id);
if(obj->class->hook_destroy)
obj->class->hook_destroy(obj);
diff --git a/src/obj.h b/src/obj.h
index 37dbfd9..3858d78 100644
--- a/src/obj.h
+++ b/src/obj.h
@@ -54,6 +54,8 @@ struct obj_class_t {
typedef uint64_t obj_id;
+#define PRI_OBJID PRId64
+
struct obj_alias_t {
char *alias;
struct obj_alias_t *next;
diff --git a/src/server.c b/src/server.c
index 6e8dba2..6d90c61 100644
--- a/src/server.c
+++ b/src/server.c
@@ -255,10 +255,34 @@ static void new_connection_cb(EV_P_ ev_io *w, int revents)
int readpipe[2]; /* child->parent */
int outpipe [2]; /* parent->child */
- if(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, readpipe) < 0)
- error("error creating pipe, need linux kernel >= 3.4");
- if(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, outpipe) < 0)
- error("error creating pipe, need linux kernel >= 3.4");
+ /* try several methods to create a packet pipe between the child and master: */
+
+ /* first try creating a pipe in "packet mode": see pipe(2) */
+ if(pipe2(readpipe, O_DIRECT) < 0)
+ {
+ /* then try a SOCK_SEQPACKET socket pair: see unix(7) */
+ if(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, readpipe) < 0)
+ {
+ /* if that failed, try a SOCK_DGRAM socket as a last resort */
+ if(socketpair(AF_UNIX, SOCK_DGRAM, 0, readpipe) < 0)
+ error("couldn't create child-master communication pipe");
+ else
+ debugf("WARNING: Using a SOCK_DGRAM socket pair for IPC, performance may be degraded.\n");
+ }
+ else
+ debugf("Using a SOCK_SEQPACKET socket pair for IPC.\n");
+ }
+ else
+ debugf("Using a packet-mode pipe for IPC.\n");
+
+ if(pipe2(outpipe, O_DIRECT) < 0)
+ {
+ if(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, outpipe) < 0)
+ {
+ if(socketpair(AF_UNIX, SOCK_DGRAM, 0, outpipe) < 0)
+ error("error creating pipe, need linux kernel >= 3.4");
+ }
+ }
pid_t pid = fork();
if(pid < 0)
@@ -329,6 +353,7 @@ static void init_signals(void)
{
struct sigaction sa;
+ /* SIGINT and SIGTERM cause graceful shutdown */
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGINT);
sa.sa_handler = sigint_handler;
@@ -338,6 +363,7 @@ static void init_signals(void)
if(sigaction(SIGTERM, &sa, NULL) < 0)
error("sigaction");
+ /* ignore SIGPIPE */
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
@@ -345,7 +371,7 @@ static void init_signals(void)
error("sigaction");
/* libev's default SIGCHLD handler exhibits some really strange
- * behavior, which we don't like, so we use our own ;) */
+ * behavior, which we don't like, so we use our own */
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGCHLD);
sa.sa_handler = sigchld_handler;
@@ -367,7 +393,7 @@ static void parse_args(int argc, char *argv[])
switch(c)
{
case 'h': /* help */
- debugf("FIXME: usage message");
+ debugf("Usage: %s [-d PREFIX] [-a <username> <password>]\n", argv[0]);
exit(0);
case 'a': /* automatic first-run config */
autoconfig = true;
@@ -393,7 +419,7 @@ static SIMP_EQUAL(pid_t, pid_equal);
static void check_libs(void)
{
- debugf("*** Starting NetCosm %s (libev %d.%d, %s) ***\n",
+ debugf("*** NetCosm %s (libev %d.%d, %s) ***\n",
NETCOSM_VERSION, EV_VERSION_MAJOR, EV_VERSION_MINOR, OPENSSL_VERSION_TEXT);
assert(ev_version_major() == EV_VERSION_MAJOR &&
ev_version_minor() >= EV_VERSION_MINOR);
@@ -405,11 +431,9 @@ int server_main(int argc, char *argv[])
parse_args(argc, argv);
- server_socket = server_bind();
-
userdb_init(USERFILE);
-
- /* also perform first-time setup */
+
+ /* also performs first-time setup: */
check_userfile();
load_worldfile();
@@ -427,10 +451,12 @@ int server_main(int argc, char *argv[])
debugf("Listening on port %d\n", port);
+ server_socket = server_bind();
+
struct ev_loop *loop = ev_default_loop(0);
/* we initialize signals after creating the default event loop
- * because libev grabs SIGCHLD */
+ * because libev grabs SIGCHLD in the process */
init_signals();
ev_io server_watcher;
diff --git a/src/server_reqs.c b/src/server_reqs.c
index 676403d..21787f4 100644
--- a/src/server_reqs.c
+++ b/src/server_reqs.c
@@ -150,7 +150,7 @@ static void req_send_desc(unsigned char *data, size_t datalen, struct child_data
send_packet(sender, REQ_BCASTMSG, (void*)room->data.desc, strlen(room->data.desc));
send_packet(sender, REQ_PRINTNEWLINE, NULL, 0);
-
+
/* list objects */
char buf[MSG_MAX];
buf[0] = 0;
@@ -189,7 +189,7 @@ static void req_send_desc(unsigned char *data, size_t datalen, struct child_data
{
strlcat(buf, "There are ", sizeof(buf));
char n[32];
- snprintf(n, sizeof(n), "%lu ", n_objs);
+ snprintf(n, sizeof(n), "%zu ", n_objs);
strlcat(buf, n, sizeof(buf));
strlcat(buf, name, sizeof(buf));
strlcat(buf, "s here.\n", sizeof(buf));
@@ -238,25 +238,25 @@ static void req_move_room(unsigned char *data, size_t datalen, struct child_data
/* TODO: bounds checking on `dir' */
room_id new = current->adjacent[dir];
-
+
if(new == ROOM_NONE)
{
- send_msg(sender, "You cannot go that way.\n");
+ send_msg(sender, "You cannot go that way.\n");
}
else
{
- struct room_t *new_room = room_get(new);
-
- if((!new_room->data.hook_enter ||
- (new_room->data.hook_enter && new_room->data.hook_enter(new, sender))) &&
- (!current->data.hook_leave ||
- (current->data.hook_leave && current->data.hook_leave(sender->room, sender))))
- {
- room_user_del(sender->room, sender);
-
- child_set_room(sender, new);
- status = 1;
- }
+ struct room_t *new_room = room_get(new);
+
+ if((!new_room->data.hook_enter ||
+ (new_room->data.hook_enter && new_room->data.hook_enter(new, sender))) &&
+ (!current->data.hook_leave ||
+ (current->data.hook_leave && current->data.hook_leave(sender->room, sender))))
+ {
+ room_user_del(sender->room, sender);
+
+ child_set_room(sender, new);
+ status = 1;
+ }
}
send_packet(sender, REQ_MOVE, &status, sizeof(status));
@@ -419,34 +419,8 @@ static void req_inventory(unsigned char *data, size_t datalen, struct child_data
struct object_t *obj = iter->val;
if(!strcmp(name, obj->name))
{
- if(n_objs == 1)
- {
- if(obj->default_article)
- {
- char *article = (is_vowel(name[0])?"An":"A");
- strlcat(buf, article, sizeof(buf));
- strlcat(buf, " ", sizeof(buf));
- strlcat(buf, name, sizeof(buf));
- }
- else
- {
- char tmp[2];
- tmp[0] = toupper(name[0]);
- tmp[1] = '\0';
- strlcat(buf, tmp, sizeof(buf));
- strlcat(buf, name + 1, sizeof(buf));
- }
- strlcat(buf, "\n", sizeof(buf));
- }
- else
- {
- char n[32];
- snprintf(n, sizeof(n), "%lu", n_objs);
- strlcat(buf, n, sizeof(buf));
- strlcat(buf, " ", sizeof(buf));
- strlcat(buf, name, sizeof(buf));
- strlcat(buf, "s\n", sizeof(buf));
- }
+ format_noun(buf, sizeof(buf), name, n_objs, obj->default_article, true);
+ strlcat(buf, "\n", sizeof(buf));
send_packet(sender, REQ_BCASTMSG, buf, strlen(buf));
}
diff --git a/src/server_reqs.h b/src/server_reqs.h
index 68ba74a..10c1755 100644
--- a/src/server_reqs.h
+++ b/src/server_reqs.h
@@ -23,7 +23,7 @@
#include "server.h"
/* child<->master commands */
-/* children might not implement all of these */
+/* not all of these are implemented by both parties */
/* meanings might be different for the server and child, see comments */
#define REQ_NOP 0 /* server, child: do nothing (used for acknowledgement) */
#define REQ_BCASTMSG 1 /* server: broadcast text; child: print following text */
@@ -32,7 +32,7 @@
#define REQ_CHANGEUSER 4 /* server: change child login name */
#define REQ_HANG 5 /* <UNIMP> server: loop forever */
#define REQ_KICK 6 /* server: kick PID with message; child: print message, quit */
-#define REQ_WAIT 7 /* server: sleep 10s */
+#define REQ_WAIT 7 /* <DEBUG> server: sleep 10s */
#define REQ_GETROOMDESC 8 /* server: send child room description */
#define REQ_SETROOM 9 /* server: set child room */
#define REQ_MOVE 10 /* server: move child based on direction; child: success or failure */
@@ -50,6 +50,7 @@
#define REQ_DROP 22 /* server: drop user object if allowed */
#define REQ_LISTUSERS 23 /* server: list users in USERFILE */
#define REQ_EXECVERB 24 /* server: execute a verb with its arguments */
+#define REQ_RAWMODE 25 /* child: toggle the child's processing of commands and instead sending input directly to master */
/* child states, sent as an int to the master */
#define STATE_INIT 0 /* initial state */
diff --git a/src/userdb.c b/src/userdb.c
index 54dd19e..0a13319 100644
--- a/src/userdb.c
+++ b/src/userdb.c
@@ -232,7 +232,7 @@ void userdb_dump(void)
while(iter)
{
struct object_t *obj = iter->val;
- debugf(" - Obj #%lu class %s: name %s\n", obj->id, obj->class->class_name, obj->name);
+ debugf(" - Obj #%"PRI_OBJID" class %s: name %s\n", obj->id, obj->class->class_name, obj->name);
iter = iter->next;
}
}
diff --git a/src/util.c b/src/util.c
index 9776c31..9c4b447 100644
--- a/src/util.c
+++ b/src/util.c
@@ -188,9 +188,9 @@ bool is_vowel(char c)
}
}
-/* $NetBSD: strlcat.c,v 1.4 2005/05/16 06:55:48 lukem Exp $ */
-/* from NetBSD: strlcat.c,v 1.16 2003/10/27 00:12:42 lukem Exp */
-/* from OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp */
+/* $NetBSD: strlcat.c,v 1.4 2005/05/16 06:55:48 lukem Exp $ */
+/* from NetBSD: strlcat.c,v 1.16 2003/10/27 00:12:42 lukem Exp */
+/* from OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -218,27 +218,62 @@ bool is_vowel(char c)
size_t
strlcat(char *dst, const char *src, size_t siz)
{
- char *d = dst;
- const char *s = src;
- size_t n = siz;
- size_t dlen;
-
- /* Find the end of dst and adjust bytes left but don't go past end */
- while (n-- != 0 && *d != '\0')
- d++;
- dlen = d - dst;
- n = siz - dlen;
-
- if (n == 0)
- return(dlen + strlen(s));
- while (*s != '\0') {
- if (n != 1) {
- *d++ = *s;
- n--;
- }
- s++;
- }
- *d = '\0';
-
- return(dlen + (s - src)); /* count does not include NUL */
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+char *format_noun(char *buf, size_t len, const char *name, size_t count, bool default_article, bool capitalize)
+{
+ assert(len > 1);
+ buf[0] = '\0';
+ if(count == 1)
+ {
+ if(default_article)
+ {
+ char *article = capitalize?(is_vowel(name[0])? "An" : "A"):(is_vowel(name[0])? "an" : "a");
+ strlcat(buf, article, len);
+ strlcat(buf, " ", len);
+ strlcat(buf, name, len);
+ }
+ else
+ {
+ char tmp[2];
+ tmp[0] = toupper(name[0]);
+ tmp[1] = '\0';
+ strlcat(buf, tmp, len);
+ strlcat(buf, name + 1, len);
+ }
+ }
+ else
+ {
+ char n[32];
+ snprintf(n, sizeof(n), "%zu", count);
+ strlcat(buf, n, len);
+ strlcat(buf, " ", len);
+ strlcat(buf, name, len);
+ strlcat(buf, "s", len);
+ }
+
+ return buf;
}
diff --git a/src/util.h b/src/util.h
index 407836a..8007ec8 100644
--- a/src/util.h
+++ b/src/util.h
@@ -51,3 +51,6 @@ size_t read_size(int fd);
bool is_vowel(char c);
size_t strlcat(char *dst, const char *src, size_t siz);
+
+/* formats a noun's name */
+char *format_noun(char *buf, size_t len, const char *name, size_t count, bool default_article, bool capitalize);
diff --git a/src/world.c b/src/world.c
index a06b08e..8c25d7d 100644
--- a/src/world.c
+++ b/src/world.c
@@ -134,13 +134,13 @@ void world_save(const char *fname)
void *ptr = world_map, *save;
for(unsigned int i = 0; i < world_sz; ++i)
{
- void *key;
- struct room_t *room = hash_iterate(ptr, &save, &key);
- if(!room)
- break;
- ptr = NULL;
- write_string(fd, key);
- write_roomid(fd, &room->id);
+ void *key;
+ struct room_t *room = hash_iterate(ptr, &save, &key);
+ if(!room)
+ break;
+ ptr = NULL;
+ write_string(fd, key);
+ write_roomid(fd, &room->id);
}
close(fd);
@@ -250,13 +250,13 @@ bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz
/* read in the room name -> room map */
world_map = hash_init(world_sz * 2, hash_djb, compare_strings);
-
+
for(unsigned int i = 0; i < world_sz; ++i)
{
- const char *key = read_string(fd);
- room_id id = read_roomid(fd);
- debugf("'%s' -> %d\n", key, id);
- hash_insert(world_map, key, world + id);
+ const char *key = read_string(fd);
+ room_id id = read_roomid(fd);
+ debugf("'%s' -> %d\n", key, id);
+ hash_insert(world_map, key, world + id);
}
close(fd);
@@ -269,7 +269,7 @@ static SIMP_EQUAL(enum direction_t, dir_equal);
/* loads room data (supplied by the world module) into our internal format */
void world_init(const struct roomdata_t *data, size_t sz, const char *name)
{
- debugf("Loading world with %lu rooms.\n", sz);
+ debugf("Loading world with %zu rooms.\n", sz);
world = calloc(sz, sizeof(struct room_t));
world_sz = 0;
world_name = strdup(name);
@@ -400,7 +400,7 @@ room_id room_get_id(const char *uniq_id)
{
struct room_t *room = hash_lookup(world_map, uniq_id);
if(!room)
- return ROOM_NONE;
+ return ROOM_NONE;
else
- return room->id;
+ return room->id;
}