From 0202865a1d8d5ffb8f312bf700d74fb4f43f14f5 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 27 Mar 2021 07:20:38 -0500 Subject: More cleanup of chsh.c --- toys/pending/chsh.c | 97 +++++++++++++++++------------------------------------ 1 file changed, 30 insertions(+), 67 deletions(-) diff --git a/toys/pending/chsh.c b/toys/pending/chsh.c index 194946de..c34660f7 100644 --- a/toys/pending/chsh.c +++ b/toys/pending/chsh.c @@ -28,93 +28,56 @@ GLOBALS( void chsh_main() { - int i; FILE *file; - size_t size, buf_size; - char *user, *line, *shell, *password, *encrypted; + char *user, *line, *shell, *encrypted; struct passwd *passwd_info; struct spwd *shadow_info; - - // Use max login name size for buffer size - if (-1 == (buf_size = sysconf(_SC_LOGIN_NAME_MAX))) buf_size = 256; - - if (!(user = malloc(buf_size * sizeof(user)))) perror_exit("Failed to allocate memory"); - if (!(shell = malloc(buf_size * sizeof(shell)))) perror_exit("Failed to allocate memory"); - if (!(line = malloc(buf_size * sizeof(line)))) perror_exit("Failed to allocate memory"); - if (MAP_FAILED == (password = mmap(NULL, buf_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED | MAP_NORESERVE, -1, 0))) perror_exit("Failed to get memory map"); + int i; // Get uid user information, may be discarded later - if (!(passwd_info = getpwuid(getuid()))) perror_exit("Failed to get passwd record"); if ((user = *toys.optargs)) { - errno = 0; - if (!(passwd_info = getpwnam(user)) && !errno) error_exit("Failed to get user info"); - - // Are we either root or changing our own shell? - if (getuid() && strcmp(passwd_info->pw_name, user)) error_exit("Permission denied\n"); - } else user = passwd_info->pw_name; + passwd_info = xgetpwnam(user); + if (geteuid() && strcmp(passwd_info->pw_name, user)) + error_exit("Permission denied\n"); + } else { + passwd_info = xgetpwuid(getuid()); + user = passwd_info->pw_name; + } // Get a password, encrypt it, wipe it, and check it - if (!(shadow_info = getspnam(passwd_info->pw_name))) perror_exit("Failed to get shadow record"); - if (!read_password(password, buf_size, "Password: ")) error_exit("Failed to read password\n"); - if (!(encrypted = crypt(password, shadow_info->sp_pwdp))) perror_exit("Failed to encrypt password"); - memset(password, 0, buf_size); - if (!munmap(password, buf_size)) perror_exit("Failed to unmap memory"); - if (strcmp(encrypted, shadow_info->sp_pwdp)) perror_exit("Incorrect password"); + if (mlock(toybuf, sizeof(toybuf))) perror_exit("mlock"); + if (!(shadow_info = getspnam(passwd_info->pw_name))) perror_exit("getspnam"); + if (!read_password(toybuf, sizeof(toybuf), "Password: ")) xexit(); + if (!(encrypted = crypt(toybuf, shadow_info->sp_pwdp))) perror_exit("crypt"); + memset(toybuf, 0, sizeof(toybuf)); + munlock(toybuf, sizeof(toybuf)); // prevents memset from "optimizing" away. + if (strcmp(encrypted, shadow_info->sp_pwdp)) perror_exit("Bad password"); // Get new shell (either -s or interactive) - if (!(file = fopen("/etc/shells", "r"))) perror_exit("Failed to open /etc/shells"); + file = xfopen("/etc/shells", "r"); if (toys.optflags) shell = TT.s; else { - xprintf("Changing the login shell for %s\nEnter the new value, or press ENTER for default\n Login shell [%s]: ", user, passwd_info->pw_shell); - - errno = 0; size = 0; - while (EOF != (i = fgetc(stdin))) { - if (errno) perror_exit("Failed to read character from stdin"); - - if ('\n' != i) *(shell + size++) = i; - else { - *(shell + size) = '\0'; break; - } - } + xprintf("Changing the login shell for %s\n" + "Enter the new value, or press ENTER for default\n" + " Login shell [%s]: ", user, passwd_info->pw_shell); + if (!(shell = xgetline(stdin))) xexit(); } - // Is shell in /etc/shells? - if (strlen(shell)) { - line = NULL; size = 0; i = 0; errno = 0; - - while (EOF != getline(&line, &size, file)) { - if (errno) perror_exit("Failed to read from /etc/shells"); - - size = strlen(line) - 1; - if ('\n' == *(line + size)) *(line + size) = '\0'; - - if (!strcmp(shell, line)) { - i = 1; break; - } - } - - if (!i) error_exit("Shell not found in '/etc/shells'"); - } else { - - // Get default shell, ignoring comments and blank lines - do { - shell = NULL; - if (-1 == getline(&shell, &size, file)) perror_exit("Failed to read from /etc/shells"); - } while (*shell != '/'); - - size = strlen(shell) - 1; - if ('\n' == *(shell + size)) *(shell + size) = '\0'; - } + // Verify supplied shell in /etc/shells, or get default shell + if (strlen(shell)) + while ((line = xgetline(file)) && strcmp(shell, line)) free(line); + else do line = xgetline(file); while (line && *line != '/'); + if (!line) error_exit("Shell not found in '/etc/shells'"); // Update shell and write passwd entry to tempfile - strncpy(passwd_info->pw_shell, shell, buf_size); - if (!(file = tmpfile())) perror_exit("Failed to create tempfile"); - if (!putpwent(passwd_info, file)) perror_exit("Failed to write to passwd entry"); + passwd_info->pw_shell = line; + if (!(file = tmpfile())) perror_exit("tmpfile"); + if (!putpwent(passwd_info, file)) perror_exit("putpwent"); // Move passwd entry from file to string if (-1 == (i = ftell(file))) perror_exit("Failed to get tempfile offset"); - if (buf_size < i && !realloc(line, i)) perror_exit("Failed to reallocate memory"); + if (sizeof(toybuf) < i && !realloc(line, i)) perror_exit("Failed to reallocate memory"); rewind(file); if (fread(line, 1, i, file) < i) perror_exit("Failed to read from tempfile"); -- cgit v1.2.3