tags 479406 pending thanks Hi,
On Sun, Jul 19, 2009 at 08:58:49PM +0100, stephane_chaze...@yahoo.fr wrote: > 2009-07-18 21:26:56 +0200, Nicolas François: > > Ping > > Sorry, forgot to reply to your earlier email. No problem (it took me a year for the previous answer ;) > > > Are there other su / login implementations which behave that way? > [...] > > AFAICS, the "login" from util-linux (derived from BSD) and the > one from NetBSD and OpenBSD at least do use the exec?p variants > (from a quick look at there source code). > > The OpenSolaris one seems to be checking for that case (pw_shell > being a shell script) explicitely and treats it specially: > > http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/login/login.c#2507 login is the easiest, su is more complex because the behavior of "su -c <command>" must be defined in this case. So I will just make it as "/bin/sh <shell> -c <command>" I will commit and test the attached patch, which should fix it for both login and su. Best Regards, -- Nekral
Index: libmisc/shell.c =================================================================== --- libmisc/shell.c (révision 3031) +++ libmisc/shell.c (copie de travail) @@ -79,6 +80,15 @@ execle (file, arg, (char *) 0, envp); err = errno; + if (access (file, R_OK|X_OK) == 0) { + /* + * Assume this is a shell script (with no shebang). + * Interpret it with /bin/sh + */ + execle ("/bin/sh", "sh", file, (char *)0, envp); + err = errno; + } + /* * Obviously something is really wrong - I can't figure out * how to execute this stupid shell, so I might as well give Index: src/su.c =================================================================== --- src/su.c (révision 3031) +++ src/su.c (copie de travail) @@ -174,7 +174,41 @@ exit (1); } +/* + * execve_shell - Execute a shell with execve, or interpret it with + * /bin/sh + */ +void execve_shell (const char *shellstr, char *args[], char *const envp[]) +{ + int err; + (void) execve (shellstr, (char **) args, envp); + err = errno; + if (access (shellstr, R_OK|X_OK) == 0) { + /* + * Assume this is a shell script (with no shebang). + * Interpret it with /bin/sh + */ + size_t n_args = 0; + char **targs; + while (NULL != args[n_args]) { + n_args++; + } + targs = (char **) xmalloc ((n_args + 2) * sizeof (args[0])); + targs[0] = "sh"; + targs[1] = xstrdup (shellstr); + targs[n_args+1] = NULL; + while (1 != n_args) { + targs[n_args] = args[n_args - 1]; + n_args--; + } + + (void) execve ("/bin/sh", targs, envp); + } else { + errno = err; + } +} + #ifdef USE_PAM /* Signal handler for parent process later */ static void catch_signals (unused int sig) @@ -206,8 +240,9 @@ if (doshell) { (void) shell (shellstr, (char *) args[0], envp); } else { - (void) execve (shellstr, (char **) args, envp); + execve_shell (shellstr, (char **) args, envp); } + exit (errno == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC); } else if ((pid_t)-1 == child) { (void) fprintf (stderr, "%s: Cannot fork user shell\n", Prog); @@ -949,7 +984,7 @@ */ argv[-1] = shellstr; #ifndef USE_PAM - (void) execve (shellstr, &argv[-1], environ); + execve_shell (shellstr, &argv[-1], environ); err = errno; (void) fputs (_("No shell\n"), stderr); SYSLOG ((LOG_WARN, "Cannot execute %s", shellstr));