login: make it saner and smaller by ~0.5k.
This commit was genuinely broken at the time (not related to our build system): scripts/config/mkconfigs.c (2005-08-01 - 2006-10-05 arasi) uretilen bbconfigopts.h icine .config satirlarini kacissiz, ham newline'larla gömüyordu - gecerli C degildi, busybox'un kendi bb_mkdep araci bile parse edemiyordu (7d219aab7 ile duzeltildi, mkconfigs shell scripte cevrildi)
No binary (build failed)
—
(log yok)
| @@ -29,59 +29,59 @@ | |
| #ifdef CONFIG_FEATURE_UTMP | |
| // import from utmp.c | |
| - | static void checkutmp(int picky); |
| - | static void setutmp(const char *name, const char *line); |
| - | /* Stuff global to this file */ |
| static struct utmp utent; | |
| + | static void read_or_build_utent(int picky); |
| + | static void write_utent(const char *username); |
| #endif | |
| enum { | |
| TIMEOUT = 60, | |
| EMPTY_USERNAME_COUNT = 10, | |
| USERNAME_SIZE = 32, | |
| + | TTYNAME_SIZE = 32, |
| }; | |
| - | static int check_nologin(int amroot); |
| + | static void die_if_nologin_and_non_root(int amroot); |
| #if defined CONFIG_FEATURE_SECURETTY | |
| - | static int check_tty(const char *tty); |
| + | static int check_securetty(void); |
| #else | |
| - | static inline int check_tty(const char *tty) { return 1; } |
| + | static inline int check_securetty(void) { return 1; } |
| #endif | |
| - | static int is_my_tty(const char *tty); |
| - | static int login_prompt(char *buf_name); |
| + | static int is_my_tty(void); |
| + | static void get_username_or_die(char *buf, int size_buf); |
| static void motd(void); | |
| static void alarm_handler(int sig ATTRIBUTE_UNUSED) | |
| { | |
| - | fprintf(stderr, "\r\nLogin timed out after %s seconds\r\n", TIMEOUT); |
| + | fprintf(stderr, "\r\nLogin timed out after %d seconds\r\n", TIMEOUT); |
| exit(EXIT_SUCCESS); | |
| } | |
| + | static char full_tty[TTYNAME_SIZE]; |
| + | static char* short_tty = full_tty; |
| + | |
| + | |
| int login_main(int argc, char **argv) | |
| { | |
| - | char tty[BUFSIZ]; |
| - | char full_tty[200]; |
| char fromhost[512]; | |
| char username[USERNAME_SIZE]; | |
| const char *tmp; | |
| int amroot; | |
| int flag; | |
| - | int failed; |
| int count = 0; | |
| - | struct passwd *pw, pw_copy; |
| + | struct passwd *pw; |
| #ifdef CONFIG_WHEEL_GROUP | |
| struct group *grp; | |
| #endif | |
| int opt_preserve = 0; | |
| int opt_fflag = 0; | |
| char *opt_host = 0; | |
| - | int alarmstarted = 0; |
| #ifdef CONFIG_SELINUX | |
| security_context_t user_sid = NULL; | |
| #endif | |
| @@ -90,7 +90,6 @@ int login_main(int argc, char **argv) | |
| amroot = (getuid() == 0); | |
| signal(SIGALRM, alarm_handler); | |
| alarm(TIMEOUT); | |
| - | alarmstarted = 1; |
| while ((flag = getopt(argc, argv, "f:h:p")) != EOF) { | |
| switch (flag) { | |
| @@ -105,10 +104,10 @@ int login_main(int argc, char **argv) | |
| if (optarg != argv[optind-1]) | |
| bb_show_usage(); | |
| - | if (!amroot) /* Auth bypass only if real UID is zero */ |
| - | bb_error_msg_and_die("-f permission denied"); |
| + | if (!amroot) /* Auth bypass only if real UID is zero */ |
| + | bb_error_msg_and_die("-f is for root only"); |
| - | safe_strncpy(username, optarg, USERNAME_SIZE); |
| + | safe_strncpy(username, optarg, sizeof(username)); |
| opt_fflag = 1; | |
| break; | |
| case 'h': | |
| @@ -118,113 +117,83 @@ int login_main(int argc, char **argv) | |
| bb_show_usage(); | |
| } | |
| } | |
| - | |
| if (optind < argc) /* user from command line (getty) */ | |
| - | safe_strncpy(username, argv[optind], USERNAME_SIZE); |
| + | safe_strncpy(username, argv[optind], sizeof(username)); |
| + | /* Let's find out and memorize our tty */ |
| if (!isatty(0) || !isatty(1) || !isatty(2)) | |
| return EXIT_FAILURE; /* Must be a terminal */ | |
| - | |
| - | #ifdef CONFIG_FEATURE_UTMP |
| - | checkutmp(!amroot); |
| - | #endif |
| - | |
| + | safe_strncpy(full_tty, "UNKNOWN", sizeof(full_tty)); |
| tmp = ttyname(0); | |
| - | if (tmp && (strncmp(tmp, "/dev/", 5) == 0)) |
| - | safe_strncpy(tty, tmp + 5, sizeof(tty)); |
| - | else if (tmp && *tmp == '/') |
| - | safe_strncpy(tty, tmp, sizeof(tty)); |
| - | else |
| - | safe_strncpy(tty, "UNKNOWN", sizeof(tty)); |
| + | if (tmp) { |
| + | safe_strncpy(full_tty, tmp, sizeof(full_tty)); |
| + | if (strncmp(full_tty, "/dev/", 5) == 0) |
| + | short_tty = full_tty + 5; |
| + | } |
| - | #ifdef CONFIG_FEATURE_UTMP |
| - | if (amroot) |
| - | memset(utent.ut_host, 0, sizeof(utent.ut_host)); |
| - | #endif |
| + | if (ENABLE_FEATURE_UTMP) { |
| + | read_or_build_utent(!amroot); |
| + | if (amroot) |
| + | memset(utent.ut_host, 0, sizeof(utent.ut_host)); |
| + | } |
| if (opt_host) { | |
| - | #ifdef CONFIG_FEATURE_UTMP |
| - | safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host)); |
| - | #endif |
| + | if (ENABLE_FEATURE_UTMP) |
| + | safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host)); |
| snprintf(fromhost, sizeof(fromhost)-1, " on `%.100s' from " | |
| - | "`%.200s'", tty, opt_host); |
| + | "`%.200s'", short_tty, opt_host); |
| } | |
| else | |
| - | snprintf(fromhost, sizeof(fromhost)-1, " on `%.100s'", tty); |
| + | snprintf(fromhost, sizeof(fromhost)-1, " on `%.100s'", short_tty); |
| bb_setpgrp; | |
| openlog(bb_applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); | |
| while (1) { | |
| - | failed = 0; |
| - | |
| if (!username[0]) | |
| - | if (!login_prompt(username)) |
| - | return EXIT_FAILURE; |
| - | |
| - | if (!alarmstarted && (TIMEOUT > 0)) { |
| - | alarm(TIMEOUT); |
| - | alarmstarted = 1; |
| - | } |
| + | get_username_or_die(username, sizeof(username)); |
| pw = getpwnam(username); | |
| if (!pw) { | |
| - | pw_copy.pw_name = "UNKNOWN"; |
| - | pw_copy.pw_passwd = "!"; |
| - | opt_fflag = 0; |
| - | failed = 1; |
| - | } else |
| - | pw_copy = *pw; |
| - | |
| - | pw = &pw_copy; |
| + | safe_strncpy(username, "UNKNOWN", sizeof(username)); |
| + | goto auth_failed; |
| + | } |
| - | if ((pw->pw_passwd[0] == '!') || (pw->pw_passwd[0] == '*')) |
| - | failed = 1; |
| + | if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*') |
| + | goto auth_failed; |
| - | if (opt_fflag) { |
| - | opt_fflag = 0; |
| - | goto auth_ok; |
| - | } |
| + | if (opt_fflag) |
| + | break; /* -f USER: success without asking passwd */ |
| - | if (!failed && (pw->pw_uid == 0) && (!check_tty(tty))) |
| - | failed = 1; |
| + | if (pw->pw_uid == 0 && !check_securetty()) |
| + | goto auth_failed; |
| /* Don't check the password if password entry is empty (!) */ | |
| if (!pw->pw_passwd[0]) | |
| - | goto auth_ok; |
| + | break; |
| /* authorization takes place here */ | |
| if (correct_password(pw)) | |
| - | goto auth_ok; |
| - | |
| - | failed = 1; |
| - | |
| - | auth_ok: |
| - | if (!failed) |
| - | break; |
| + | break; |
| + | auth_failed: |
| + | opt_fflag = 0; |
| bb_do_delay(FAIL_DELAY); | |
| puts("Login incorrect"); | |
| - | username[0] = 0; |
| if (++count == 3) { | |
| - | syslog(LOG_WARNING, "invalid password for `%s'%s", pw->pw_name, fromhost); |
| + | syslog(LOG_WARNING, "invalid password for `%s'%s", |
| + | username, fromhost); |
| return EXIT_FAILURE; | |
| } | |
| + | username[0] = '\0'; |
| } | |
| alarm(0); | |
| - | if (check_nologin(pw->pw_uid == 0)) |
| - | return EXIT_FAILURE; |
| - | |
| - | #ifdef CONFIG_FEATURE_UTMP |
| - | setutmp(username, tty); |
| - | #endif |
| + | die_if_nologin_and_non_root(pw->pw_uid == 0); |
| - | if (*tty != '/') |
| - | snprintf(full_tty, sizeof(full_tty)-1, "/dev/%s", tty); |
| - | else |
| - | safe_strncpy(full_tty, tty, sizeof(full_tty)-1); |
| + | if (ENABLE_FEATURE_UTMP) |
| + | write_utent(username); |
| #ifdef CONFIG_SELINUX | |
| if (is_selinux_enabled()) { | |
| @@ -249,7 +218,7 @@ auth_ok: | |
| } | |
| } | |
| #endif | |
| - | if (!is_my_tty(full_tty)) |
| + | if (!is_my_tty()) |
| syslog(LOG_ERR, "unable to determine TTY name, got %s", full_tty); | |
| /* Try these, but don't complain if they fail | |
| @@ -300,96 +269,91 @@ auth_ok: | |
| } | |
| - | static int login_prompt(char *buf_name) |
| + | static void get_username_or_die(char *buf, int size_buf) |
| { | |
| - | char buf[1024]; |
| - | char *sp, *ep; |
| - | int i; |
| - | |
| - | for (i=0; i<EMPTY_USERNAME_COUNT; i++) { |
| - | print_login_prompt(); |
| - | |
| - | if (!fgets(buf, sizeof(buf)-1, stdin)) |
| - | return 0; |
| - | |
| - | if (!strchr(buf, '\n')) |
| - | return 0; |
| - | |
| - | for (sp = buf; isspace(*sp); sp++) { } |
| - | for (ep = sp; isgraph(*ep); ep++) { } |
| - | |
| - | *ep = '\0'; |
| - | safe_strncpy(buf_name, sp, USERNAME_SIZE); |
| - | if (buf_name[0]) |
| - | return 1; |
| - | } |
| - | return 0; |
| + | int c, cntdown; |
| + | cntdown = EMPTY_USERNAME_COUNT; |
| + | prompt: |
| + | /* skip whitespace */ |
| + | print_login_prompt(); |
| + | do { |
| + | c = getchar(); |
| + | if (c == EOF) exit(1); |
| + | if (c == '\n') { |
| + | if (!--cntdown) exit(1); |
| + | goto prompt; |
| + | } |
| + | } while (isspace(c)); |
| + | |
| + | *buf++ = c; |
| + | if (!fgets(buf, size_buf-2, stdin)) |
| + | exit(1); |
| + | if (!strchr(buf, '\n')) |
| + | exit(1); |
| + | while (isgraph(*buf)) buf++; |
| + | *buf = '\0'; |
| } | |
| - | static int check_nologin(int amroot) |
| + | static void die_if_nologin_and_non_root(int amroot) |
| { | |
| - | if (access(bb_path_nologin_file, F_OK) == 0) { |
| - | FILE *fp; |
| - | int c; |
| - | |
| - | fp = fopen(bb_path_nologin_file, "r"); |
| - | if (fp) { |
| - | while ((c = getc(fp)) != EOF) |
| - | putchar((c=='\n') ? '\r' : c); |
| + | FILE *fp; |
| + | int c; |
| - | fflush(stdout); |
| - | fclose(fp); |
| - | } else { |
| - | puts("\r\nSystem closed for routine maintenance.\r"); |
| - | } |
| - | if (!amroot) |
| - | return 1; |
| + | if (access(bb_path_nologin_file, F_OK)) |
| + | return; |
| - | puts("\r\n[Disconnect bypassed -- root login allowed.]\r"); |
| - | } |
| - | return 0; |
| + | fp = fopen(bb_path_nologin_file, "r"); |
| + | if (fp) { |
| + | while ((c = getc(fp)) != EOF) |
| + | putchar((c=='\n') ? '\r' : c); |
| + | fflush(stdout); |
| + | fclose(fp); |
| + | } else |
| + | puts("\r\nSystem closed for routine maintenance\r"); |
| + | if (!amroot) |
| + | exit(1); |
| + | puts("\r\n[Disconnect bypassed -- root login allowed.]\r"); |
| } | |
| #ifdef CONFIG_FEATURE_SECURETTY | |
| - | static int check_tty(const char *tty) |
| + | static int check_securetty(void) |
| { | |
| FILE *fp; | |
| int i; | |
| char buf[BUFSIZ]; | |
| fp = fopen(bb_path_securetty_file, "r"); | |
| - | if (fp) { |
| - | while (fgets(buf, sizeof(buf)-1, fp)) { |
| - | for(i = strlen(buf)-1; i>=0; --i) { |
| - | if (!isspace(buf[i])) |
| - | break; |
| - | } |
| - | buf[++i] = '\0'; |
| - | if ((buf[0]=='\0') || (buf[0]=='#')) |
| - | continue; |
| - | |
| - | if (strcmp(buf, tty)== 0) { |
| - | fclose(fp); |
| - | return 1; |
| - | } |
| + | if (!fp) { |
| + | /* A missing securetty file is not an error. */ |
| + | return 1; |
| + | } |
| + | while (fgets(buf, sizeof(buf)-1, fp)) { |
| + | for(i = strlen(buf)-1; i>=0; --i) { |
| + | if (!isspace(buf[i])) |
| + | break; |
| + | } |
| + | buf[++i] = '\0'; |
| + | if ((buf[0]=='\0') || (buf[0]=='#')) |
| + | continue; |
| + | if (strcmp(buf, short_tty) == 0) { |
| + | fclose(fp); |
| + | return 1; |
| } | |
| - | fclose(fp); |
| - | return 0; |
| } | |
| - | /* A missing securetty file is not an error. */ |
| - | return 1; |
| + | fclose(fp); |
| + | return 0; |
| } | |
| #endif | |
| /* returns 1 if true */ | |
| - | static int is_my_tty(const char *tty) |
| + | static int is_my_tty(void) |
| { | |
| struct stat by_name, by_fd; | |
| - | if (stat(tty, &by_name) || fstat(0, &by_fd)) |
| + | if (stat(full_tty, &by_name) || fstat(0, &by_fd)) |
| return 0; | |
| if (by_name.st_rdev != by_fd.st_rdev) | |
| @@ -414,15 +378,10 @@ static void motd(void) | |
| #ifdef CONFIG_FEATURE_UTMP | |
| - | // vv Taken from tinylogin utmp.c vv |
| - | |
| - | #define NO_UTENT \ |
| - | "No utmp entry. You must exec \"login\" from the lowest level \"sh\"" |
| - | #define NO_TTY \ |
| - | "Unable to determine your tty name." |
| + | /* vv Taken from tinylogin utmp.c vv */ |
| /* | |
| - | * checkutmp - see if utmp file is correct for this process |
| + | * read_or_build_utent - see if utmp file is correct for this process |
| * | |
| * System V is very picky about the contents of the utmp file | |
| * and requires that a slot for the current process exist. | |
| @@ -435,9 +394,8 @@ static void motd(void) | |
| * command line flags. | |
| */ | |
| - | static void checkutmp(int picky) |
| + | static void read_or_build_utent(int picky) |
| { | |
| - | char *line; |
| struct utmp *ut; | |
| pid_t pid = getpid(); | |
| @@ -446,53 +404,41 @@ static void checkutmp(int picky) | |
| /* First, try to find a valid utmp entry for this process. */ | |
| while ((ut = getutent())) | |
| if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] && | |
| - | (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS)) |
| + | (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS)) |
| break; | |
| /* If there is one, just use it, otherwise create a new one. */ | |
| if (ut) { | |
| utent = *ut; | |
| } else { | |
| - | time_t t_tmp; |
| - | |
| - | if (picky) { |
| - | puts(NO_UTENT); |
| - | exit(1); |
| - | } |
| - | line = ttyname(0); |
| - | if (!line) { |
| - | puts(NO_TTY); |
| - | exit(1); |
| - | } |
| - | if (strncmp(line, "/dev/", 5) == 0) |
| - | line += 5; |
| + | if (picky) |
| + | bb_error_msg_and_die("no utmp entry found"); |
| + | |
| memset(&utent, 0, sizeof(utent)); | |
| utent.ut_type = LOGIN_PROCESS; | |
| utent.ut_pid = pid; | |
| - | strncpy(utent.ut_line, line, sizeof(utent.ut_line)); |
| - | /* XXX - assumes /dev/tty?? */ |
| - | strncpy(utent.ut_id, utent.ut_line + 3, sizeof(utent.ut_id)); |
| + | strncpy(utent.ut_line, short_tty, sizeof(utent.ut_line)); |
| + | /* This one is only 4 chars wide. Try to fit something |
| + | * remotely meaningful by skipping "tty"... */ |
| + | strncpy(utent.ut_id, short_tty + 3, sizeof(utent.ut_id)); |
| strncpy(utent.ut_user, "LOGIN", sizeof(utent.ut_user)); | |
| - | t_tmp = (time_t)utent.ut_time; |
| - | time(&t_tmp); |
| + | utent.ut_time = time(NULL); |
| } | |
| } | |
| /* | |
| - | * setutmp - put a USER_PROCESS entry in the utmp file |
| + | * write_utent - put a USER_PROCESS entry in the utmp file |
| * | |
| - | * setutmp changes the type of the current utmp entry to |
| + | * write_utent changes the type of the current utmp entry to |
| * USER_PROCESS. the wtmp file will be updated as well. | |
| */ | |
| - | static void setutmp(const char *name, const char *line ATTRIBUTE_UNUSED) |
| + | static void write_utent(const char *username) |
| { | |
| - | time_t t_tmp = (time_t)utent.ut_time; |
| - | |
| utent.ut_type = USER_PROCESS; | |
| - | strncpy(utent.ut_user, name, sizeof(utent.ut_user)); |
| - | time(&t_tmp); |
| - | /* other fields already filled in by checkutmp above */ |
| + | strncpy(utent.ut_user, username, sizeof(utent.ut_user)); |
| + | utent.ut_time = time(NULL); |
| + | /* other fields already filled in by read_or_build_utent above */ |
| setutent(); | |
| pututline(&utent); | |
| endutent(); | |