commit 784c6a5acffa7a0cba0b875b26e1c20db4a5613e
parent f7bfe68a9e4e934081523f97cc3efc767eeafeeb
Author: sin <sin@2f30.org>
Date: Fri, 18 Oct 2013 11:14:36 +0100
Implement -l support for su(1)
Diffstat:
M | su.c | | | 50 | +++++++++++++++++++++++++++++++++++++++++++++++--- |
1 file changed, 47 insertions(+), 3 deletions(-)
diff --git a/su.c b/su.c
@@ -12,6 +12,9 @@
extern char **environ;
+static char *msetenv(const char *, const char *);
+static void dologin(struct passwd *);
+
static void
usage(void)
{
@@ -93,8 +96,49 @@ main(int argc, char **argv)
if (setuid(pw->pw_uid) < 0)
eprintf("setuid:");
- newargv = (char *const[]){pw->pw_shell, NULL};
- setenv("HOME", pw->pw_dir, 1);
- execve(pw->pw_shell, newargv, environ);
+ if (lflag) {
+ dologin(pw);
+ } else {
+ newargv = (char *const[]){pw->pw_shell, NULL};
+ setenv("HOME", pw->pw_dir, 1);
+ execve(pw->pw_shell, newargv, environ);
+ }
return (errno == ENOENT) ? 127 : 126;
}
+
+static char *
+msetenv(const char *name, const char *value)
+{
+ char *buf;
+ size_t sz;
+
+ sz = strlen(name) + strlen(value) + 2;
+ buf = malloc(sz);
+ if (!buf)
+ eprintf("malloc:");
+ snprintf(buf, sz, "%s=%s", name, value);
+ return buf;
+}
+
+static void
+dologin(struct passwd *pw)
+{
+ char shbuf[strlen(pw->pw_shell) + 1];
+ char * const *newargv;
+ char * const *newenv;
+
+ strcpy(shbuf, pw->pw_shell);
+ newargv = (char *const[]){shbuf, NULL};
+ newenv = (char *const[]){
+ msetenv("HOME", pw->pw_dir),
+ msetenv("SHELL", pw->pw_shell),
+ msetenv("USER", pw->pw_name),
+ msetenv("LOGNAME", pw->pw_name),
+ msetenv("TERM", getenv("TERM")),
+ msetenv("PATH", getenv("PATH")),
+ NULL
+ };
+ if (chdir(pw->pw_dir) < 0)
+ eprintf("chdir %s:", pw->pw_dir);
+ execve(pw->pw_shell, newargv, newenv);
+}