commit - 25e1b3c7a65c61732e655a97f1596a52f28a3424
commit + 2cbf96e394f7a7decbae2f8a6829b8cddd03536b
blob - bf26e0f35483d84fb4e011938121109ca0717c72
blob + cb93dae29f883f57ee923b60a332edcaf8749fa6
--- Makefile
+++ Makefile
DEBUG?=-O0 -g
.endif
+NSH_REXEC_PATH?=/usr/local/bin/nsh
+
.if make(install)
DESTDIR?=/usr/local
BINDIR?=/bin
#CFLAGS=-O -DDHCPLEASES=\"/flash/dhcpd.leases\" -Wmissing-prototypes -Wformat -Wall -Wpointer-arith -Wbad-function-cast #-W
CFLAGS?=-O
CFLAGS+=-Wmissing-prototypes -Wformat -Wall -Wbad-function-cast -I/usr/local/include #-W -Wpointer-arith
-CPPFLAGS+=-DNSH_VERSION=${NSH_VERSION}
+CPPFLAGS+=-DNSH_VERSION=${NSH_VERSION} -DNSH_REXEC_PATH=${NSH_REXEC_PATH}
SRCS=arp.c compile.c main.c genget.c commands.c stats.c kroute.c
SRCS+=ctl.c show.c if.c version.c route.c conf.c complete.c ieee80211.c
blob - 28c7350a7c3e5500d0fad8a789c320416b51c08e
blob + eebb73667f75dda726d8e045bee3e25554254690
--- commands.c
+++ commands.c
pid_t child;
-static int quit(void);
static int disable(void);
static int doverbose(int, char**);
static int doediting(int, char**);
int
quit(void)
{
- printf("%% Session terminated.\n");
- exit(0);
+ if (privexec) {
+ exit(NSH_REXEC_EXIT_CODE_QUIT);
+ } else {
+ printf("%% Session terminated.\n");
+ exit(0);
+ }
return 0;
}
int
disable(void)
{
+ if (privexec) {
+ exit(0);
+ return 0;
+ }
priv = 0;
config_mode = 0;
return 0;
blob - f87dcc248a9328234f8eb72469036d383f529e0f
blob + 0be9d4e399ef96e55a54cac6c8dd39ed4b847d08
--- externs.h
+++ externs.h
#error "NSH_VERSION is undefined"
#endif
-#define NSH_STRINGIFY_VERSION(x) #x
-#define NSH_STRINGVAL_VERSION(x) NSH_STRINGIFY_VERSION(x)
+#define NSH_STRINGIFY(x) #x
+#define NSH_STRINGVAL(x) NSH_STRINGIFY(x)
-#define NSH_VERSION_STR NSH_STRINGVAL_VERSION(NSH_VERSION)
+#define NSH_VERSION_STR NSH_STRINGVAL(NSH_VERSION)
+#define NSH_REXEC_PATH_STR NSH_STRINGVAL(NSH_REXEC_PATH)
+#define NSH_REXEC_EXIT_CODE_QUIT 42
+
#define NO_ARG(x) (strcasecmp(x, "no") == 0) /* absolute "no" */
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) /* sys/param.h */
extern int config_mode; /* are we in comfig mode? */
extern int bridge; /* are we in bridge mode (or interface mode?) */
extern int priv; /* privileged mode or not? */
+extern int privexec; /* process was started in privileged mode? */
extern pid_t pid; /* process id of nsh */
extern int cli_rtable; /* environment rtable */
#define DIFF "/usr/bin/diff"
#define REBOOT "/sbin/reboot"
#define HALT "/sbin/halt"
+#define SU "/usr/bin/su"
+#define DOAS "/usr/bin/doas"
#define SAVESCRIPT "/usr/local/bin/save.sh"
#ifndef DHCPLEASES
#define DHCPLEASES "/var/db/dhcpd.leases"
#endif
+int quit(void);
void command(void);
char **step_optreq(char **, char **, int, char **, int);
int argvtostring(int, char **, char *, int);
blob - 6b3aefcbe9ed0aca92fbaa37f049f21d07a5a939
blob + 9ba61d37637b0bb62d90fcd2821475b4bcd990ab
--- main.c
+++ main.c
char *vers = NSH_VERSION_STR;
int bridge = 0; /* bridge mode for interface() */
int verbose = 0; /* verbose mode */
-int priv = 0, cli_rtable = 0;
+int priv = 0, privexec = 0, cli_rtable = 0;
int editing = 1, config_mode = 0;;
pid_t pid;
setlocale(LC_CTYPE, "");
- if(getuid() != 0)
- printf("%% Functionality limited without root privilege.\n");
-
pid = getpid();
- while ((ch = getopt(argc, argv, "c:i:v")) != -1)
+ while ((ch = getopt(argc, argv, "c:ei:v")) != -1)
switch (ch) {
case 'c':
cflag = 1;
strlcpy(rc, optarg, PATH_MAX);
break;
+ case 'e':
+ if (getuid() != 0) {
+ fprintf(stderr, "%s: Use of -e option requires "
+ "root privileges.\n", getprogname());
+ exit(1);
+ }
+ privexec = 1;
+ break;
case 'i':
iflag = 1;
strlcpy(rc, optarg, PATH_MAX);
usage();
}
+
+ if (getuid() != 0) {
+ printf("%% Functionality is limited without root privileges.\n"
+ "%% The 'enable' command will switch to the root user.\n");
+ }
+
argc -= optind;
argv += optind;
if (cflag && iflag)
if (iflag)
rmtemp(SQ3DBFILE);
- printf("%% NSH v%s\n", vers);
+ if (!privexec)
+ printf("%% NSH v%s\n", vers);
/* create temporal tables (if they aren't already there) */
if (db_create_table_rtables() < 0)
exit(0);
}
+ if (privexec) {
+ /*
+ * We start out in privileged mode.
+ * We are already running as root as per -e option handling.
+ */
+ priv = 1;
+ }
top = setjmp(toplevel) == 0;
if (top) {
blob - 54ea3c3deb08da424263112ddae92e7895e9f1ee
blob + af71bd01fd67ae20381615194fddba516473b430
--- passwd.c
+++ passwd.c
/*
* enable privileged mode
*/
-int
-enable(int argc, char **argv)
+static int
+enable_passwd(int argc, char **argv)
{
char *p, *cpass;
char salt[_PASSWORD_LEN];
switch (argc) {
case 1:
- if (priv == 1)
- return 0;
-
/* try to read pass */
if (!(read_pass(pass, sizeof(pass)))) {
if (errno == ENOENT) {
/* no password file, so enable */
- priv = 1;
return 1;
} else {
/* cant read password file */
return 0;
}
}
- p = getpass("Password:");
+ p = getpass("Privileged Mode Secret:");
if (p == NULL || *p == '\0')
return 0;
if (strcmp(crypt(p, pass), pass) == 0) {
- priv = 1;
return 1;
} else {
- printf("%% Password incorrect\n");
+ printf("%% Secret incorrect\n");
return 0;
}
printf("%% enable\t\t\t\tEnable privileged mode\n");
printf("%% enable ?\t\t\t\tPrint help information\n");
secretusage();
- return 1;
+ return 0;
} else {
if (isprefix(argv[1], "secret")) {
secretusage();
- return 1;
+ return 0;
}
printf("%% Invalid argument: %s\n", argv[1]);
return 0;
}
if (strlen(argv[2]) < 8) {
- printf("%% Password too short; at least 8 characters required\n");
+ printf("%% Secret too short; at least 8 characters required\n");
return 0;
}
if (strlen(argv[2]) > _PASSWORD_LEN) {
- printf("%% Password too long; at most %d characters allowed\n",
+ printf("%% Secret too long; at most %d characters allowed\n",
_PASSWORD_LEN);
return 0;
}
printf("%% crypt failed\n");
return 0;
}
- return(write_pass(cpass));
+ write_pass(cpass);
+ return 0;
case 4:
if (!isprefix(argv[1], "secret")) {
/* set crypted pass */
strlcpy(pass, argv[3], sizeof(pass));
- return (write_pass(pass));
+ write_pass(pass);
+ return 0;
default:
printf("%% Too many arguments\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+int
+enable(int argc, char **argv)
+{
+ char *doas_argv[] = {
+ DOAS, NSH_REXEC_PATH_STR, "-e", NULL
+ };
+ char *su_argv[] = {
+ SU, "root", "-c", NSH_REXEC_PATH_STR " -e", NULL
+
+ };
+ int exit_code;
+
+ if (argc != 1)
+ return enable_passwd(argc, argv);
+
+ if (priv == 1 || !enable_passwd(argc, argv))
return 0;
+
+ if (getuid() == 0) {
+ priv = 1;
+ return 0;
}
+ /*
+ * Start an nsh child process in privileged mode.
+ * The 'priv' flag will remain at zero in our own process.
+ */
+ printf("%% Obtaining root privileges via %s\n", DOAS);
+ exit_code = cmdargs(doas_argv[0], doas_argv);
+ if (exit_code == 0)
+ return 0;
+ else if (exit_code == NSH_REXEC_EXIT_CODE_QUIT) {
+ /* The child exited due to a 'quit' command. */
+ quit();
+ }
+
+ /*
+ * XXX We cannot differentiate a doas exit code of 1 from an
+ * nsh exit code of 1. Under normal circumstances nsh will exit
+ * with code zero. Just assume that doas failed to run the
+ * command if we get here and retry with su.
+ */
+
+ printf("%% Obtaining root privileges via %s\n", SU);
+ exit_code = cmdargs(su_argv[0], su_argv);
+
+ if (exit_code == -1 || exit_code == 127) {
+ printf("%% Entering privileged mode failed: "
+ "Could not re-execute nsh\n");
+ } else if (exit_code == NSH_REXEC_EXIT_CODE_QUIT) {
+ /* The child exited due to a 'quit' command. */
+ quit();
+ } else if (exit_code) {
+ printf("%% Privileged mode child process exited "
+ "with error code %d\n", exit_code);
+ }
+
+ return 0;
}