I had a few (3 maybe?) system calls where I got the error checking backwards, 
so I fixed those. I also realized I forgot to format the code with the 80 
character thing, so I shortened a bunch of lines.

The command works fine except for when I request a shell of 15+ characters 
(such as /usr/bin/xonsh), in which case it segfaults. I'm still working on 
this, but I think the string is too long for the passwd struct (which wouldn't 
explain why `update_passwd("/etc/passwd", user, NULL)` is failing).

Sent with [ProtonMail](https://protonmail.com) Secure Email.
From 9e1aeb00748a4b99667b2aca8a0690ed343b94af Mon Sep 17 00:00:00 2001
From: Michael Christensen <[email protected]>
Date: Fri, 26 Mar 2021 16:50:01 -0600
Subject: [PATCH] Fix some system calls and clean up

---
 toys/lsb/chsh.c | 73 ++++++++++++++++++++++++++++++++-----------------
 1 file changed, 48 insertions(+), 25 deletions(-)

diff --git a/toys/lsb/chsh.c b/toys/lsb/chsh.c
index 1895755c..bea35e59 100644
--- a/toys/lsb/chsh.c
+++ b/toys/lsb/chsh.c
@@ -16,10 +16,9 @@ config CHSH
 
 	-s login_shell    Use specified shell rather than interactive prompt
 
-	The shell must be an absolute path to an executable file. An unpriviliged
-	user can only change his/her own shell to one listed in /etc/shells, and only if
-	he/she is not restricted (implementation-defined).
-*/
+    The shell must be an absolute path to an executable file. An unpriviliged
+    user can only change his/her own shell to one listed in /etc/shells, and
+    only if he/she is not restricted (implementation-defined).  */
 
 #define FOR_chsh
 #include "toys.h"
@@ -40,35 +39,52 @@ void chsh_main()
 	// 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");
+	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");
 
 	// Get uid user information, may be discarded later
-	if (!(passwd_info = getpwuid(getuid()))) perror_exit("Failed to get passwd record");
+	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");
+		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");
+		if (getuid() && strcmp(passwd_info->pw_name, user))
+            error_exit("Permission denied\n");
 	} else 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");
+	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 (munmap(password, buf_size)) perror_exit("Failed to unmap memory");
+	if (strcmp(encrypted, shadow_info->sp_pwdp))
+        perror_exit("Incorrect password");
 
 	// Get new shell (either -s or interactive)
-	if (!(file = fopen("/etc/shells", "r"))) perror_exit("Failed to open /etc/shells");
+	if (!(file = fopen("/etc/shells", "r")))
+        perror_exit("Failed to open /etc/shells");
 	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);
+		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);
 
 		errno = 0; size = 0;
 		while (EOF != (i = fgetc(stdin))) {
@@ -102,7 +118,8 @@ void chsh_main()
 		// 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");
+			if (-1 == getline(&shell, &size, file))
+                perror_exit("Failed to read from /etc/shells");
 		} while (*shell != '/');
 
 		size = strlen(shell) - 1;
@@ -112,15 +129,21 @@ void chsh_main()
 	// 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");
+	if (putpwent(passwd_info, file))
+        perror_exit("Failed to write to passwd entry");
 
 	// 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 (-1 == (i = ftell(file)))
+        perror_exit("Failed to get tempfile offset");
+	if (buf_size < 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");
+	if (fread(line, 1, i, file) < i)
+        perror_exit("Failed to read from tempfile");
 
 	// Update /etc/passwd using that string
-	if (-1 == update_password("/etc/passwd", user, NULL)) perror_exit("Failed to remove passwd entry");
-	if (-1 == update_password("/etc/passwd", user, line)) perror_exit("Failed to add passwd entry");
+	if (-1 == update_password("/etc/passwd", user, NULL))
+        perror_exit("Failed to remove passwd entry");
+	if (-1 == update_password("/etc/passwd", user, line))
+        perror_exit("Failed to add passwd entry");
 }
-- 
2.25.1

_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to