Commit Diff


commit - 330fe27c7fd1e395ae626f5b6e64cf527f0ae951
commit + 0e324bf209a78fff0daca2edc14ddbf913717ea2
blob - 4011e0f3cb3a14e6359f82f82497db29b47dcd89
blob + b2437ee8b32e25362ea972f30849f0fc1fde5923
--- ctl.c
+++ ctl.c
@@ -21,8 +21,10 @@
 #include <unistd.h>
 #include <errno.h>
 #include <libgen.h>
+#include <limits.h>
 #include <histedit.h>
 #include <sys/signal.h>
+#include <sys/sysctl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
@@ -819,6 +821,87 @@ call_editor(char *name, char **args, char *z)
 	edit_file(tmpfile, daemons->mode, daemons->propername, args);
 }
 
+const char *motd_example = "\n\n"
+    "Welcome to OpenBSD: The proactively secure Unix-like operating system.\n"
+    "\n"
+    "Please use the sendbug(1) utility to report bugs in the system.\n"
+    "Before reporting a bug, please try to reproduce it with the latest\n"
+    "version of the code.  With bug reports, please try to ensure that\n"
+    "enough information to reproduce the problem is enclosed, and if a\n"
+    "known fix for it exists, include that as well.\n\n";
+
+static size_t
+make_example_motd(char *path, size_t size)
+{
+	char buf[1024];
+	int mib[] = { CTL_KERN, KERN_VERSION, INT_MAX };
+	int fd;
+	ssize_t w;
+	size_t len = 0;
+	char *eol;
+
+	if (strlcpy(path, "/tmp/nsh-motd-XXXXXXXXXX", size) >= size)
+		return 0;
+
+	fd = mkstemp(path);
+	if (fd == -1)
+		return 0;
+
+	if (sysctl_str(mib, buf, sizeof(buf), 1))
+		goto done;
+
+	eol = strchr(buf, '\n');
+	if (eol)
+		*eol = '\0';
+
+	len = strlen(buf);
+
+	w = write(fd, buf, len);
+	if (w != len) {
+		len = 0;
+		goto done;
+	}
+
+	len = strlen(motd_example);
+	w = write(fd, motd_example, len);
+	if (w != len)
+		len = 0;
+done:
+	close(fd);
+	if (len == 0)
+		unlink(path);
+	return len;
+}
+
+static size_t
+make_example_path(char *path, size_t size, const char *directory,
+    const char *name)
+{
+	size_t len;
+	int ret;
+
+	ret = snprintf(path, size, "%s/%s", directory, name);
+	if (ret < 0 || (size_t)ret >= size)
+		return 0;
+
+	/* Snip off rdomain trailer at end of filename. */
+	len = strlen(path);
+	while (len > 0) {
+		if (path[len - 1] >= '0' && path[len - 1] <= '9') {
+			path[len - 1] = '\0';
+			len--;
+		} else {
+			if (path[len - 1] == '.') {
+				path[len - 1] = '\0';
+				len--;
+			}
+			break;
+		}
+	}
+
+	return len;
+}
+
 static void
 provide_example_config(char *filename)
 {
@@ -826,7 +909,7 @@ provide_example_config(char *filename)
 	char path[PATH_MAX];
 	char tmpprompt[sizeof(prompt)];
 	FILE *f = NULL, *example = NULL;
-	int ret, num;
+	int num, unlink_example = 0;
 	struct stat sb;
 	size_t len, remain;
 
@@ -846,31 +929,45 @@ provide_example_config(char *filename)
 	if (name == NULL)
 		goto done;
 	
-	ret = snprintf(path, sizeof(path), "/etc/examples/%s", name);
-	if (ret < 0 || (size_t)ret >= sizeof(path))
-		goto done;
-
-	/* Snip off rdomain trailer at end of filename. */
-	len = strlen(path);
-	while (len > 0) {
-		if (path[len - 1] >= '0' && path[len - 1] <= '9') {
-			path[len - 1] = '\0';
-			len--;
-		} else {
-			if (path[len - 1] == '.') {
-				path[len - 1] = '\0';
-				len--;
-			}
-			break;
-		}
+	/*
+	 * Most examples are in /etc/examples. However, some daemons
+	 * which are enabled by default have default configs elsewhere.
+	 * In some cases nsh uses different names for configuration files.
+	 */
+	if (strncmp(name, "motd", 4) == 0) {
+		len = make_example_motd(path, sizeof(path));
+		if (len > 0)
+			unlink_example = 1;
+	} else if (strncmp(name, "sshd.conf", 9) == 0) {
+		len = make_example_path(path, sizeof(path),
+		    "/etc/ssh", "sshd_config");
+	} else if (strncmp(name, "smtpd.conf", 10) == 0) {
+		len = make_example_path(path, sizeof(path),
+		    "/etc/mail", name);
+	} else {
+		len = make_example_path(path, sizeof(path),
+		    "/etc/examples", name);
 	}
 	if (len == 0)
 		goto done;
 
 	example = fopen(path, "r");
-	if (example == NULL)
-		goto done;
+	if (example == NULL) {
+		if (errno != ENOENT)
+			goto done;
 
+		/* XXX npppd.conf should probably be in /etc/examples/ */
+		if (strncmp(name, "npppd.conf", 10) != 0)
+			goto done;
+		len = make_example_path(path, sizeof(path),
+		    "/etc/npppd", name);
+		if (len == 0)
+			goto done;
+		example = fopen(path, "r");
+		if (example == NULL)
+			goto done;
+	}
+
 	if (fstat(fileno(example), &sb) == -1)
 		goto done;
 
@@ -885,10 +982,8 @@ provide_example_config(char *filename)
 		const char *buf;
 
 		if ((buf = el_gets(elp, &num)) == NULL) {
-			if (num == -1) {
-				ret = -1;
+			if (num == -1)
 				goto done;
-			}
 			/* EOF, e.g. ^X or ^D via exit_i() in complete.c */
 			goto done;
 		}
@@ -938,6 +1033,8 @@ done:
 		restoreprompt();
 	if (example)
 		fclose(example);
+	if (unlink_example)
+		unlink(path);
 }
 
 int
blob - 2e4977cfe088faa4a96086ab42f1262d2a78f9c1
blob + 1d8310a256e3112a05a6b6ea4c8ab55e5bdb6c6e
--- externs.h
+++ externs.h
@@ -306,6 +306,7 @@ int Ambiguous(void *);
 
 /* sysctl.c */
 int sysctl_int(int[], int, int);
+int sysctl_str(int[], char *, size_t, int);
 int ipsysctl(int, char *, char *, int);
 void conf_sysctls(FILE *);
 
blob - b987820def6eb3b7bc042da908ed72a34ef6a2fb
blob + 6716dbe41a1d02630972e4686cf7b7884311d8d2
--- sysctl.c
+++ sysctl.c
@@ -102,6 +102,49 @@ sysctl_int(int mib[], int val, int read)
 	return(old);
 }
 
+/*
+ * sysctl_str: get or set a string value
+ *
+ * val - value to read or set in sysctl
+ * read - are we just reading the value (1), or setting it? (0)
+ */
+
+int
+sysctl_str(int mib[], char *val, size_t val_size, int read)
+{
+	void *old = NULL, *new = NULL;
+	size_t oldlen = 0, newlen = 0;
+	int i;
+
+	if (read) {
+		old = val;
+		oldlen = val_size;
+	} else {
+		new = val;
+		newlen = val_size;
+	}
+
+	for (i = 0; i < 6; i++)
+		if (mib[i] == MIB_STOP)
+			break;
+
+	if (sysctl(mib, i, old, &oldlen, new, newlen) == -1) {
+		if (!read) {
+			printf("%% sysctl_str: sysctl: %s\n", strerror(errno));
+		} else if (errno != ENOPROTOOPT) {
+			printf("%% sysctl_str: sysctl: %s\n", strerror(errno));
+			for (i = 0; i < 6; i++) {
+		                if (mib[i] == MIB_STOP)
+					break;
+				printf("%% mib[%i] == %d\n", i, mib[i]);
+			}
+		}
+		return -1;
+	}
+
+	return 0;
+}
+
 struct sysctltab sysctls[] = {
 	{ "ip",		PF_INET,	iptab,		ipsysctls },
 	{ "ip6",	PF_INET6,	ip6tab,		ip6sysctls },