about summary refs log tree commit diff
path: root/extra/edit
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--extra/edit/edit.c60
1 files changed, 36 insertions, 24 deletions
diff --git a/extra/edit/edit.c b/extra/edit/edit.c
index 1f0d8bb..ffbf7a9 100644
--- a/extra/edit/edit.c
+++ b/extra/edit/edit.c
@@ -240,10 +240,13 @@ static const char *Boolean[] = {
 	"no-names", "no-sts", "palaver", "sasl-external", "verbose",
 };
 
+// FIXME: size needs to be validated for power of two
 static const char *Integer[] = {
 	"local-port", "port", "queue-interval", "size",
 };
 
+// FIXME: local-pass needs to be validated for hash
+// FIXME: sasl-plain needs to be validated for colon
 static const char *String[] = {
 	"away", "bind", "blind-req", "client-cert", "client-priv", "host", "join",
 	"local-ca", "local-cert", "local-host", "local-pass", "local-path",
@@ -251,52 +254,57 @@ static const char *String[] = {
 	"trust", "user",
 };
 
-static const char *Unsafe[] = {
-	"bind", "blind-req", "client-cert", "client-priv", "host", "local-ca",
-	"local-cert", "local-host", "local-path", "local-port", "local-priv",
-	"pass", "port", "sasl-external", "sasl-plain", "save", "trust", "verbose",
+// TODO: nick, user aren't safe until pounce can fall back in case
+// they're invalid
+static const char *Safe[] = {
+	"away", "join", "local-pass", "mode", "nick", "no-names", "no-sts",
+	"palaver", "quit", "real", "user",
 };
 
 static bool allowUnsafe;
+static bool safe(const char *name) {
+	if (allowUnsafe) return true;
+	for (size_t i = 0; i < ARRAY_LEN(Safe); ++i) {
+		if (!strcmp(Safe[i], name)) return true;
+	}
+	return false;
+}
 
-static const char *validate(const char *name, const char *value) {
-	if (!allowUnsafe) {
-		for (size_t i = 0; i < ARRAY_LEN(Unsafe); ++i) {
-			if (!strcmp(Unsafe[i], name)) return "is unsafe";
-		}
+static bool exists(const char *name) {
+	for (size_t i = 0; i < ARRAY_LEN(Boolean); ++i) {
+		if (!strcmp(Boolean[i], name)) return true;
 	}
+	for (size_t i = 0; i < ARRAY_LEN(Integer); ++i) {
+		if (!strcmp(Integer[i], name)) return true;
+	}
+	for (size_t i = 0; i < ARRAY_LEN(String); ++i) {
+		if (!strcmp(String[i], name)) return true;
+	}
+	return false;
+}
+
+static const char *validate(const char *name, const char *value) {
 	for (size_t i = 0; i < ARRAY_LEN(Boolean); ++i) {
 		if (strcmp(Boolean[i], name)) continue;
+		if (!safe(name)) return "cannot be set";
 		return (value ? "does not take a value" : NULL);
 	}
 	for (size_t i = 0; i < ARRAY_LEN(Integer); ++i) {
 		if (strcmp(Integer[i], name)) continue;
+		if (!safe(name)) return "cannot be set";
 		if (!value) return "requires a value";
 		char *end;
 		strtoul(value, &end, 10);
-		if (!*value || *end) return "must be an integer";
-		return NULL;
+		return (!*value || *end ? "must be an integer" : NULL);
 	}
 	for (size_t i = 0; i < ARRAY_LEN(String); ++i) {
 		if (strcmp(String[i], name)) continue;
+		if (!safe(name)) return "cannot be set";
 		return (value ? NULL : "requires a value");
 	}
 	return "is not an option";
 }
 
-static bool exists(const char *name) {
-	for (size_t i = 0; i < ARRAY_LEN(Boolean); ++i) {
-		if (!strcmp(Boolean[i], name)) return true;
-	}
-	for (size_t i = 0; i < ARRAY_LEN(Integer); ++i) {
-		if (!strcmp(Integer[i], name)) return true;
-	}
-	for (size_t i = 0; i < ARRAY_LEN(String); ++i) {
-		if (!strcmp(String[i], name)) return true;
-	}
-	return false;
-}
-
 static void handlePrivmsg(struct Message *msg) {
 	require(msg, true, 2);
 	if (strcmp(msg->nick, msg->params[0])) return;
@@ -359,6 +367,10 @@ static void handlePrivmsg(struct Message *msg) {
 			format("NOTICE %s :\2%s\2 is not an option\r\n", msg->nick, name);
 			return;
 		}
+		if (!safe(name)) {
+			format("NOTICE %s :\2%s\2 cannot be unset\r\n", msg->nick, name);
+			return;
+		}
 
 		configUnset(&own, name);
 		configWrite(&own, config);