From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Mon, 22 Jun 2026 08:58:11 +0000 (-0700) Subject: agetty: handle systems without a shell or /bin/login X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=081b2af93b233cf0bd1b4f550f1bb46caa41c9df;p=thirdparty%2Futil-linux.git agetty: handle systems without a shell or /bin/login When the login program (default /bin/login, or the one set with --login-program) is missing or not executable, logging in is impossible. Previously agetty still displayed the issue file and prompted for a username, producing a confusing dead end. Before prompting, check whether the login program is executable with access(X_OK). If it is not, print a short banner ("This system does not permit logins." by default, configurable with --nologin-message) and wait for the user to press Enter, then re-check so an administrator who installs the login program at runtime can proceed without a reboot. The normal prompt flow is unaffected when the login program exists. Add --nologin-message to override the banner text and document the new behavior in agetty.8.adoc. Closes #4117 --- diff --git a/agetty-cmd/agetty.c b/agetty-cmd/agetty.c index 333dba2fa..65d1dde0c 100644 --- a/agetty-cmd/agetty.c +++ b/agetty-cmd/agetty.c @@ -46,7 +46,11 @@ static int inotify_fd = AGETTY_RELOAD_FDNONE; #define serial_tty_option(opt, flag) \ (((opt)->flags & (F_VCONSOLE|(flag))) == (flag)) +/* Default banner printed when the login program is not available. */ +#define DEFAULT_NOLOGIN_MESSAGE N_("This system does not permit logins.") + static int wait_for_term_input(struct agetty_issue *ie, int fd); +static void wait_for_login_program(struct agetty_options *op); static void do_prompt(struct agetty_issue *ie, struct agetty_options *op, struct termios *tp); static char *get_logname(struct agetty_issue *ie, struct agetty_options *op, struct termios *tp, struct chardata *cp); @@ -157,6 +161,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" --long-hostname show full qualified hostname\n"), out); fputs(_(" --erase-chars additional backspace chars\n"), out); fputs(_(" --kill-chars additional kill chars\n"), out); + fputs(_(" --nologin-message message shown when login program is missing\n"), out); fputs(_(" --chdir chdir before the login\n"), out); fputs(_(" --delay sleep seconds before prompt\n"), out); fputs(_(" --nice run login with this priority\n"), out); @@ -186,6 +191,7 @@ static void parse_args(int argc, char **argv, struct agetty_options *op) RELOAD_OPTION, LIST_SPEEDS_OPTION, ISSUE_SHOW_OPTION, + NOLOGIN_MESSAGE_OPTION, }; static const struct option longopts[] = { { "8bits", no_argument, NULL, '8' }, @@ -224,6 +230,7 @@ static void parse_args(int argc, char **argv, struct agetty_options *op) { "help", no_argument, NULL, HELP_OPTION }, { "erase-chars", required_argument, NULL, ERASE_CHARS_OPTION }, { "kill-chars", required_argument, NULL, KILL_CHARS_OPTION }, + { "nologin-message", required_argument, NULL, NOLOGIN_MESSAGE_OPTION }, { NULL, 0, NULL, 0 } }; @@ -339,6 +346,9 @@ static void parse_args(int argc, char **argv, struct agetty_options *op) case KILL_CHARS_OPTION: op->killchars = optarg; break; + case NOLOGIN_MESSAGE_OPTION: + op->nologin_message = optarg; + break; case RELOAD_OPTION: agetty_reload(); exit(EXIT_SUCCESS); @@ -541,6 +551,13 @@ int main(int argc, char **argv) INIT_CHARDATA(&chardata); + /* + * If the login program is missing or not executable there is no way to + * log in. Show a banner and wait until it becomes available instead of + * prompting for a username that can never be used. + */ + wait_for_login_program(&options); + if (options.autolog) { debug("doing auto login\n"); options.username = options.autolog; @@ -620,6 +637,32 @@ int main(int argc, char **argv) } +/* + * Block until the login program is executable. + * + * On systems without a shell or /bin/login there is no point in showing the + * issue file and prompting for a username, because the login program can never + * be executed. Instead of running into a confusing dead end, print a short + * banner and wait for the user to press Enter, then re-check whether the login + * program has become available (for example because an administrator installed + * it at runtime). As soon as the login program is executable we return and the + * normal prompt flow continues. + */ +static void wait_for_login_program(struct agetty_options *op) +{ + const char *message = op->nologin_message ? + op->nologin_message : _(DEFAULT_NOLOGIN_MESSAGE); + + while (access(op->login, X_OK) != 0) { + printf("%s\n", message); + fflush(stdout); + + /* Wait for Enter, then re-check the login program. */ + if (getc(stdin) == EOF) + return; + } +} + static void do_prompt(struct agetty_issue *ie, struct agetty_options *op, struct termios *tp) { #ifdef AGETTY_RELOAD diff --git a/agetty-cmd/agetty.h b/agetty-cmd/agetty.h index 00c824622..7465a173b 100644 --- a/agetty-cmd/agetty.h +++ b/agetty-cmd/agetty.h @@ -78,6 +78,7 @@ struct agetty_options { char *username; /* login name, given to /bin/login */ char *fakehost; /* fake hostname for ut_host */ char *osrelease; /* /etc/os-release data */ + char *nologin_message; /* message shown when login program is missing */ unsigned int delay; /* Sleep seconds before prompt */ int nice; /* Run login with this priority */ int numspeed; /* number of baud rates to try */ diff --git a/term-utils/agetty.8.adoc b/term-utils/agetty.8.adoc index fe7c3a57f..5f5482119 100644 --- a/term-utils/agetty.8.adoc +++ b/term-utils/agetty.8.adoc @@ -32,6 +32,8 @@ agetty - alternative Linux getty This program does not use the _/etc/gettydefs_ (System V) or _/etc/gettytab_ (SunOS 4) files. +If the login program (by default _/bin/login_, or the program given with *--login-program*) is missing or not executable, then logging in is impossible. In that case *agetty* does not display the issue file or prompt for a login name. Instead it prints a short message ("This system does not permit logins." by default, configurable with *--nologin-message*) and waits for the user to press Enter. On Enter it re-checks whether the login program has become available, for example because an administrator installed it at runtime, and either continues with the normal prompt or shows the message again. + == ARGUMENTS _port_:: @@ -168,6 +170,9 @@ This option specifies additional characters that should be interpreted as a back *--kill-chars* _string_:: This option specifies additional characters that should be interpreted as a kill ("ignore all previous characters") when the user types the login name. The default additional 'kill' has been '@', but since util-linux 2.23 no additional kill characters are enabled by default. +*--nologin-message* _string_:: +Use _string_ as the message that is shown when the login program is missing or not executable, instead of the default "This system does not permit logins." See the *DESCRIPTION* above for details about this behavior. + *--chdir* _directory_:: Change directory before the login.