From: WanBingjiang Date: Thu, 8 May 2025 02:14:35 +0000 (+0800) Subject: login: using an avaiable shell while logging in. X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=fce1b6502982f076537153edf35a77cfc5a3d1c6;p=thirdparty%2Futil-linux.git login: using an avaiable shell while logging in. --- diff --git a/login-utils/login.c b/login-utils/login.c index 321f9d6ce..f54c97df1 100644 --- a/login-utils/login.c +++ b/login-utils/login.c @@ -1416,10 +1416,76 @@ static void initialize(int argc, char **argv, struct login_context *cxt) ul_close_all_fds(STDERR_FILENO + 1, ~0U); } +static bool build_shell_argv(char *shell, char **child_argv) +{ + bool script; + int child_argc = 0; + + /* if the shell field has a space: treat it like a shell script */ + script = strchr(shell, ' ') != NULL; + + if (script) { + char *buff; + + xasprintf(&buff, "exec %s", shell); + child_argv[child_argc++] = "/bin/sh"; + child_argv[child_argc++] = "-sh"; + child_argv[child_argc++] = "-c"; + child_argv[child_argc++] = buff; + } else { + char *buff, *p; + + xasprintf(&buff, "-%.*s", PATH_MAX, + ((p = strrchr(shell, '/')) ? + p + 1 : shell)); + child_argv[child_argc++] = shell; + child_argv[child_argc++] = buff; + } + + child_argv[child_argc++] = NULL; + + return script; +} + +static void login_shell_fallback(char **child_argv) +{ +#if defined (HAVE_LIBECONF) && defined (USE_VENDORDIR) + size_t size = 0; + econf_err error; + char **keys = NULL; + econf_file *key_file = open_etc_shells(); + + if (!key_file) + return; + + error = econf_getKeys(key_file, NULL, &size, &keys); + if (error) { + econf_free(key_file); + errx(EXIT_FAILURE, + _("Cannot evaluate entries in shells files: %s"), + econf_errString(error)); + } + + for (size_t i = 0; i < size; i++) { + build_shell_argv(keys[i], child_argv); + execvp(child_argv[0], child_argv + 1); + } + econf_free(keys); + econf_free(key_file); +#else + char *s; + setusershell(); + while ((s = getusershell())) { + build_shell_argv(s, child_argv); + execvp(child_argv[0], child_argv + 1); + } + endusershell(); +#endif +} + int main(int argc, char **argv) { char *child_argv[10]; - int child_argc = 0; struct passwd *pwd; struct login_context cxt = { .tty_mode = TTY_MODE, /* tty chmod() */ @@ -1555,38 +1621,21 @@ int main(int argc, char **argv) printf(_("Logging in with home = \"/\".\n")); } - /* if the shell field has a space: treat it like a shell script */ - script = strchr(pwd->pw_shell, ' ') != NULL; - - if (script) { - char *buff; - - xasprintf(&buff, "exec %s", pwd->pw_shell); - child_argv[child_argc++] = "/bin/sh"; - child_argv[child_argc++] = "-sh"; - child_argv[child_argc++] = "-c"; - child_argv[child_argc++] = buff; - } else { - char *buff, *p; - - xasprintf(&buff, "-%.*s", PATH_MAX, - ((p = strrchr(pwd->pw_shell, '/')) ? - p + 1 : pwd->pw_shell)); - child_argv[child_argc++] = pwd->pw_shell; - child_argv[child_argc++] = buff; - } - - child_argv[child_argc++] = NULL; - /* http://www.linux-pam.org/Linux-PAM-html/adg-interface-by-app-expected.html#adg-pam_end */ (void) pam_end(cxt.pamh, PAM_SUCCESS|PAM_DATA_SILENT); + script = build_shell_argv(pwd->pw_shell, child_argv); execvp(child_argv[0], child_argv + 1); - if (script) - warn(_("couldn't exec shell script")); - else - warn(_("no shell")); + if (getlogindefs_bool("LOGIN_SHELL_FALLBACK", 0)) { + login_shell_fallback(child_argv); + warn(_("no available shell")); + } else { + if (script) + warn(_("couldn't exec shell script")); + else + warn(_("no shell")); + } exit(EXIT_SUCCESS); }