changeset 1004:13ac68b51d3d

Add su.
author M. Farkas-Dyck <strake888@gmail.com>
date Tue, 13 Aug 2013 04:17:34 -0500
parents 67eedf74a707
children 03f72b57a092
files toys/pending/su.c
diffstat 1 files changed, 98 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/pending/su.c	Tue Aug 13 04:17:34 2013 -0500
@@ -0,0 +1,98 @@
+/* su.c - switch user
+ *
+ * Copyright 2013 CE Strake <strake888@gmail.com>
+ *
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/su.html
+
+USE_SU(NEWTOY(su, "lmpc:s:", TOYFLAG_BIN))
+
+config SU
+  bool "su"
+  default n
+  help
+    usage: su [-lmp] [-c cmd] [-s shell] [user [argu...]]
+
+    Switch to given user, or root if not given, and call a shell with the given arguments.
+
+    options:
+      -s  shell to call
+      -c  command to pass to shell with -c
+
+    flags:
+      -l      login shell
+      -(m|p)  preserve environment
+*/
+
+#define FOR_su
+#include "toys.h"
+
+GLOBALS(
+  char *sArgu;
+  char *cArgu;
+)
+
+extern char **environ;
+
+static void deny () {
+  printf ("Denied\n");
+  xexit ();
+}
+
+void su_main () {
+  char *name, *passhash, **argu, **argv;
+  struct passwd *up;
+  struct spwd *shp;
+  long ii;
+
+  if (toys.optc && strcmp ("-", toys.optargs[0]) == 0) {
+    toys.optflags |= FLAG_l;
+    toys.optc--; toys.optargs++;
+  }
+
+  if (toys.optc) {
+    name = toys.optargs[0];
+    toys.optc--; toys.optargs++;
+  }
+  else name = "root";
+  shp = getspnam (name);
+  if (!shp) perror_exit ("failed to find password");
+
+  switch (shp -> sp_pwdp[0]) {
+  case '!': deny ();
+  case '$': break;
+  default : error_exit ("bad password format");
+  }
+
+  if (read_password (toybuf, sizeof (toybuf), "Password: ") != 0) perror_exit ("failed to read password");
+
+  passhash = crypt (toybuf, shp -> sp_pwdp);
+  if (!passhash) perror_exit ("failed to compute password hash");
+  for (ii = 0; toybuf[ii]; ii++) toybuf[ii] = 0;
+
+  if (strcmp (passhash, shp -> sp_pwdp) != 0) deny ();
+
+  up = getpwnam (name);
+  if (!up) perror_exit ("failed to getpwnam");
+
+  if (setuid (up -> pw_uid) < 0) perror_exit ("failed to setuid");
+  if (chdir  (up -> pw_dir) < 0) perror_exit ("failed to chdir");
+
+  argu = xmalloc (sizeof (char *)*(toys.optc + 4));
+  argv = argu;
+  argv[0] = toys.optflags & FLAG_s ? TT.sArgu : up -> pw_shell;
+  if (toys.optflags & FLAG_c) {
+    argv[1] = toys.optflags & FLAG_l ? "-lc" : "-c";
+    argv[2] = TT.cArgu;
+    argv += 2;
+  }
+  else if (toys.optflags & FLAG_l) (argv++)[1] = "-l";
+  for (ii = 0; ii < toys.optc; ii++) argv[ii + 1] = toys.optargs[ii];
+  if (execve (argu[0], argu,
+              toys.optflags & FLAG_l ? (char *[]){
+                xmsprintf ( "HOME=%s", up -> pw_dir),
+                xmsprintf ("SHELL=%s", up -> pw_shell),
+                xmsprintf ( "USER=%s", up -> pw_name),
+                xmsprintf ( "TERM=%s", getenv ("TERM")),
+                0
+              } : environ) < 0) perror_exit ("failed to exec %s", argu[0]);
+}