aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2019-03-07 21:04:25 -0600
committerRob Landley <rob@landley.net>2019-03-07 21:04:25 -0600
commite191597e6bbf03e920e1b42f44ac65faaddedf51 (patch)
tree1df440763287236d530ad379165e0f4f67348c8c
parentf8ba1d6d8a9a6023bd28c19a43580d768f45c199 (diff)
downloadtoybox-e191597e6bbf03e920e1b42f44ac65faaddedf51.tar.gz
Add reset_env() and make su and login use it. Do long-delayed login cleanup.
-rw-r--r--lib/lib.c35
-rw-r--r--lib/lib.h1
-rw-r--r--toys/lsb/su.c65
-rw-r--r--toys/other/login.c61
4 files changed, 87 insertions, 75 deletions
diff --git a/lib/lib.c b/lib/lib.c
index 54bfc8c4..d1210f49 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -122,6 +122,7 @@ ssize_t readall(int fd, void *buf, size_t len)
ssize_t writeall(int fd, void *buf, size_t len)
{
size_t count = 0;
+
while (count<len) {
int i = write(fd, count+(char *)buf, len-count);
if (i<1) return i;
@@ -1427,3 +1428,37 @@ char *format_iso_time(char *buf, size_t len, struct timespec *ts)
return buf;
}
+
+// reset environment for a user, optionally clearing most of it
+void reset_env(struct passwd *p, int clear)
+{
+ int i;
+
+ if (clear) {
+ char *s, *stuff[] = {"TERM", "DISPLAY", "COLORTERM", "XAUTHORITY"};
+
+ for (i=0; i<ARRAY_LEN(stuff); i++)
+ stuff[i] = (s = getenv(stuff[i])) ? xmprintf("%s=%s", stuff[i], s) : 0;
+ clearenv();
+ for (i=0; i < ARRAY_LEN(stuff); i++) if (stuff[i]) putenv(stuff[i]);
+ if (chdir(p->pw_dir)) {
+ perror_msg("chdir %s", p->pw_dir);
+ xchdir("/");
+ }
+ } else {
+ char **ev1, **ev2;
+
+ // remove LD_*, IFS, ENV, and BASH_ENV from environment
+ for (ev1 = ev2 = environ;;) {
+ while (*ev2 && (strstart(ev2, "LD_") || strstart(ev2, "IFS=") ||
+ strstart(ev2, "ENV=") || strstart(ev2, "BASH_ENV="))) ev2++;
+ if (!(*ev1++ = *ev2++)) break;
+ }
+ }
+
+ setenv("PATH", _PATH_DEFPATH, 1);
+ setenv("HOME", p->pw_dir, 1);
+ setenv("SHELL", p->pw_shell, 1);
+ setenv("USER", p->pw_name, 1);
+ setenv("LOGNAME", p->pw_name, 1);
+}
diff --git a/lib/lib.h b/lib/lib.h
index bdabd4a2..87f4150e 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -259,6 +259,7 @@ void do_lines(int fd, char delim, void (*call)(char **pline, long len));
long environ_bytes();
long long millitime(void);
char *format_iso_time(char *buf, size_t len, struct timespec *ts);
+void reset_env(struct passwd *p, int clear);
#define HR_SPACE 1 // Space between number and units
#define HR_B 2 // Use "B" for single byte units
diff --git a/toys/lsb/su.c b/toys/lsb/su.c
index 0bffe782..c48a0c9f 100644
--- a/toys/lsb/su.c
+++ b/toys/lsb/su.c
@@ -4,22 +4,34 @@
*
* See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/su.html
* TODO: log su attempts
+ * TODO: suid support
+ * Supports undocumented compatibility options: -m synonym for -p, - for -l
-USE_SU(NEWTOY(su, "lmpc:s:", TOYFLAG_BIN|TOYFLAG_ROOTONLY))
+USE_SU(NEWTOY(su, "^lmpu:g:c:s:[!lmp]", TOYFLAG_BIN|TOYFLAG_ROOTONLY))
config SU
bool "su"
default y
depends on TOYBOX_SHADOW
help
- usage: su [-lmp] [-c CMD] [-s SHELL] [USER [ARGS...]]
+ usage: su [-lp] [-u UID] [-g GID,...] [-s SHELL] [-c CMD] [USER [COMMAND...]]
- Switch to user (or root) and run shell (with optional command line).
+ Switch user, prompting for password of new user when not run as root.
- -s Shell to use
- -c Command to pass to shell with -c
- -l Login shell
- -(m|p) Preserve environment
+ With one argument, switch to USER and run user's shell from /etc/passwd.
+ With no arguments, USER is root. If COMMAND line provided after USER,
+ exec() it as new USER (bypasing shell). If -u or -g specified, first
+ argument (if any) isn't USER (it's COMMAND).
+
+ first argument is USER name to switch to (which must exist).
+ Non-root users are prompted for new user's password.
+
+ -s Shell to use (default is user's shell from /etc/passwd)
+ -c Command line to pass to -s shell (ala sh -c "CMD")
+ -l Reset environment as if new login.
+ -u Switch to UID instead of USER
+ -g Switch to GID (only root allowed, can be comma separated list)
+ -p Preserve environment (except for $PATH and $IFS)
*/
#define FOR_su
@@ -53,6 +65,8 @@ void su_main()
if (*toys.optargs) name = *(toys.optargs++);
else name = "root";
+ loggit(name, 0);
+
if (!(shp = getspnam(name))) perror_exit("no '%s'", name);
if (getuid()) {
if (*shp->sp_pwdp != '$') goto deny;
@@ -61,32 +75,26 @@ void su_main()
memset(toybuf, 0, sizeof(toybuf));
if (!passhash || strcmp(passhash, shp->sp_pwdp)) goto deny;
}
+ closelog();
- up = xgetpwnam(name);
- xsetuser(up);
+ xsetuser(up = xgetpwnam(name));
+
+ if (FLAG(m)||FLAG(p)) {
+ unsetenv("IFS");
+ setenv("PATH", _PATH_DEFPATHS, 1);
+ } else reset_env(up, FLAG(l));
argv = argu = xmalloc(sizeof(char *)*(toys.optc + 4));
*(argv++) = TT.s ? TT.s : up->pw_shell;
+ loggit(name, *argu);
+
+ if (FLAG(m)||FLAG(p)) {
+ unsetenv("IFS");
+ setenv("PATH", _PATH_DEFPATHS, 1);
+ } else reset_env(up, FLAG(l));
- if (toys.optflags & FLAG_l) {
- int i;
- char *stuff[] = {snapshot_env("TERM"), snapshot_env("DISPLAY"),
- snapshot_env("COLORTERM"), snapshot_env("XAUTHORITY")};
-
- clearenv();
- for (i=0; i < ARRAY_LEN(stuff); i++) if (stuff[i]) putenv(stuff[i]);
- *(argv++) = "-l";
- xchdir(up->pw_dir);
- } else unsetenv("IFS");
- setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
- if (!(toys.optflags & (FLAG_m|FLAG_p))) {
- setenv("HOME", up->pw_dir, 1);
- setenv("SHELL", up->pw_shell, 1);
- setenv("USER", up->pw_name, 1);
- setenv("LOGNAME", up->pw_name, 1);
- } else unsetenv("IFS");
-
- if (toys.optflags & FLAG_c) {
+ if (FLAG(l)) *(argv++) = "-l";
+ if (FLAG(c)) {
*(argv++) = "-c";
*(argv++) = TT.c;
}
@@ -94,6 +102,7 @@ void su_main()
xexec(argu);
deny:
+ syslog(LOG_NOTICE, "No.", getusername(getuid()), name);
puts("No.");
toys.exitval = 1;
}
diff --git a/toys/other/login.c b/toys/other/login.c
index 76e1f345..9bd6cc95 100644
--- a/toys/other/login.c
+++ b/toys/other/login.c
@@ -4,9 +4,6 @@
*
* No support for PAM/securetty/selinux/login script/issue/utmp
* Relies on libcrypt for hash calculation.
- *
- * TODO: this command predates "pending" but needs cleanup. It #defines
- * random stuff, calls exit() form a signal handler... yeah.
USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
@@ -36,24 +33,17 @@ GLOBALS(
static void login_timeout_handler(int sig __attribute__((unused)))
{
printf("\nLogin timed out after %d seconds.\n", TT.login_timeout);
- exit(0);
+ xexit();
}
void login_main(void)
{
- char *forbid[] = {
- "BASH_ENV", "ENV", "HOME", "IFS", "LD_LIBRARY_PATH", "LD_PRELOAD",
- "LD_TRACE_LOADED_OBJECTS", "LD_BIND_NOW", "LD_AOUT_LIBRARY_PATH",
- "LD_AOUT_PRELOAD", "LD_NOWARN", "LD_KEEPDIR", "SHELL"
- };
- int hh = FLAG(h), count, tty;
- char uu[33], *username, *pass = 0, *ss;
+ int hh = FLAG(h), count, tty = tty_fd();
+ char *username, *pass = 0, *ss;
struct passwd *pwd = 0;
- for (tty=0; tty<3; tty++) if (isatty(tty)) break;
- if (tty == 3) error_exit("no tty");
-
- for (count = 0; count < ARRAY_LEN(forbid); count++) unsetenv(forbid[count]);
+ // we read user/password from stdin, but tty can be stderr?
+ if (tty == -1) error_exit("no tty");
openlog("login", LOG_PID | LOG_CONS, LOG_AUTH);
xsignal(SIGALRM, login_timeout_handler);
@@ -65,27 +55,23 @@ void login_main(void)
tcflush(0, TCIFLUSH);
if (!username) {
- int i;
-
- memset(username = uu, 0, sizeof(uu));
- gethostname(uu, sizeof(uu)-1);
- printf("%s%slogin: ", *uu ? uu : "", *uu ? " " : "");
+ if (gethostname(toybuf, sizeof(toybuf)-1)) *toybuf = 0;
+ printf("%s%slogin: ", *toybuf ? toybuf : "", *toybuf ? " " : "");
fflush(stdout);
- if(!fgets(uu, sizeof(uu)-1, stdin)) _exit(1);
+ if(!fgets(toybuf, sizeof(toybuf)-1, stdin)) xexit();
// Remove trailing \n and so on
- for (i = 0; i<sizeof(uu); i++) if (uu[i]<=' ' || uu[i]==':') uu[i]=0;
- if (!*uu) {
+ for (ss = toybuf; *ss; ss++) if (*ss<=' ' || *ss==':') break;
+ *ss = 0;
+ if (!*(username = toybuf)) {
username = 0;
continue;
}
}
// If user exists and isn't locked
- pwd = getpwnam(username);
- if (pwd && *pwd->pw_passwd != '!' && *pwd->pw_passwd != '*') {
-
+ if ((pwd = getpwnam(username))) {
// Pre-authenticated or passwordless
if (TT.f || !*pwd->pw_passwd) break;
@@ -117,9 +103,6 @@ void login_main(void)
}
alarm(0);
- // This had password data in it, and we reuse for motd below
- memset(toybuf, 0, sizeof(toybuf));
-
if (!pwd) error_exit("max retries (3)");
// Check twice because "this file exists" is a security test, and in
@@ -136,26 +119,10 @@ void login_main(void)
if (fchown(tty, pwd->pw_uid, pwd->pw_gid) || fchmod(tty, 0600))
printf("can't claim tty");
xsetuser(pwd);
-
- if (chdir(pwd->pw_dir)) printf("bad $HOME: %s\n", pwd->pw_dir);
-
- if (!FLAG(p)) {
- char *term = getenv("TERM");
-
- clearenv();
- if (term) setenv("TERM", term, 1);
- }
-
- setenv("USER", pwd->pw_name, 1);
- setenv("LOGNAME", pwd->pw_name, 1);
- setenv("HOME", pwd->pw_dir, 1);
- setenv("SHELL", pwd->pw_shell, 1);
+ reset_env(pwd, FLAG(p));
// Message of the day
- if ((ss = readfile("/etc/motd", 0, 0))) {
- puts(ss);
- free(ss);
- }
+ if ((ss = readfile("/etc/motd", 0, 0))) puts(ss);
syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name,
ttyname(tty), hh ? "from" : "", hh ? TT.h : "");