On Monday 28 May 2007 18:28, Anselmo Lacerda S. de Melo wrote:
> Hi folks!
> 
> As I need PAM suport on busybox, I made a patch for busybox-1.4.2. It
> was based on  patch for busybox-1.2.1 that I found searching in the
> archives of this list.
> 
> All comments appreciated.

Patch against current svn is preferred.

+static struct pam_conv conv = {
+        misc_conv,
+        NULL
+};
+#endif

This struct can/should be const.


+#if ENABLE_PAM
+               pamret = PAM_SUCCESS;
+#endif
...
+#if ENABLE_PAM
+        pamret = pam_start( "login", username, &conv, &pamh );

What's the point of the first assignment?


+        else {
+            // continuing with pam authentication
+            // set TTY (so things like securetty work)
+            if((pamret = pam_set_item(pamh, PAM_TTY, short_tty)) != 
PAM_SUCCESS) {
+                bb_error_msg("Failed to pam_set_item TTY: %s", 
pam_strerror(pamh, pamret));
+                goto auth_failed;
+            }

Please use tabs for indent; please do not place assignments in if()s.


+        // Everything from here to auth_ok: is skipped when running
+        // PAM.  This is all PAM's responsibility anyway.
+#else
+               PWLOOKUP;
+#endif /* ENABLE_PAM */

If you will properly enclose non-PAM code in bigger #else block,
you will make life easier for people to read and for gcc to optimize
(it will notice that static check_securetty() is not needed).


+                        strcpy(username, pamuser);

Unsafe versus buffer overflow!


+ifeq ($(CONFIG_PAM),y)
+    LDFLAGS += -lpam -lpam_misc
+endif

Does not compile for me, need LDLIBS instead.


See attached updated patch against current svn.

It still has some grey areas:

+               if (pamret != PAM_SUCCESS) {
+                       bb_error_msg("pam_set_item(TTY) failed: %s", 
pam_strerror(pamh, pamret));
+                       goto auth_failed;

ok here.

+               }
+               pamret = pam_authenticate(pamh, 0);
+               if (pamret == PAM_SUCCESS) {
+                       // Then check that the account is healthy.
+                       pamret = pam_acct_mgmt(pamh, 0);
+                       if (pamret != PAM_SUCCESS) // No, it isn't
+                               bb_error_msg("user not allowed access: %s", 
pam_strerror(pamh, pamret));

shouldn't you goto auth_failed here?

+                       else {
+                               // read user back
+                               char *pamuser;
+                               /* gcc: "dereferencing type-punned pointer 
breaks aliasing rules..."
+                                * thus we use double cast */
+                               if (pam_get_item(pamh, PAM_USER, (const void 
**) (void*) &pamuser) != PAM_SUCCESS)
+                                       bb_error_msg("pam_get_item(USER) 
failed: %s", pam_strerror(pamh, pamret));

and here?

+                               else
+                                       safe_strncpy(username, pamuser, 
sizeof(username));
+                       }
+               }


+               if (pam_end(pamh, pamret) != PAM_SUCCESS)
+                       bb_error_msg("pam_end failed");

You do it only on success.
Do you need this on pam failure too? (If not, say so in comment).
Conversely, is it needed at all?
--
vda

diff -d -urpN busybox.2/loginutils/Config.in busybox.3/loginutils/Config.in
--- busybox.2/loginutils/Config.in	2007-05-23 02:36:36.000000000 +0200
+++ busybox.3/loginutils/Config.in	2007-05-29 03:59:05.000000000 +0200
@@ -128,6 +128,16 @@ config LOGIN
 	  Note that Busybox binary must be setuid root for this applet to
 	  work properly.
 
+config PAM
+	bool "Support for PAM (Pluggable Authentication Modules)"
+	default n
+	depends on LOGIN
+	help
+	Include support for PAM in /bin/login.  This will effectively disable
+	Busybox's built-in login, so pam_unix.so should be available if you wish
+	to use /etc/passwd for login.
+
+
 config LOGIN_SCRIPTS
 	bool "Support for login scripts"
 	depends on LOGIN
diff -d -urpN busybox.2/loginutils/login.c busybox.3/loginutils/login.c
--- busybox.2/loginutils/login.c	2007-05-26 20:45:07.000000000 +0200
+++ busybox.3/loginutils/login.c	2007-05-29 04:50:08.000000000 +0200
@@ -12,7 +12,16 @@
 #include <selinux/selinux.h>  /* for is_selinux_enabled()  */
 #include <selinux/get_context_list.h> /* for get_default_context() */
 #include <selinux/flask.h> /* for security class definitions  */
-#include <errno.h>
+#endif
+
+#if ENABLE_PAM
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+
+static const struct pam_conv conv = {
+        misc_conv,
+        NULL
+};
 #endif
 
 enum {
@@ -122,7 +131,7 @@ static void die_if_nologin_and_non_root(
 	puts("\r\n[Disconnect bypassed -- root login allowed.]\r");
 }
 
-#if ENABLE_FEATURE_SECURETTY
+#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM
 static int check_securetty(void)
 {
 	FILE *fp;
@@ -210,7 +219,7 @@ int login_main(int argc, char **argv)
 		LOGIN_OPT_h = (1<<1),
 		LOGIN_OPT_p = (1<<2),
 	};
-	char fromhost[512];
+	char *fromhost;
 	char username[USERNAME_SIZE];
 	const char *tmp;
 	int amroot;
@@ -222,6 +231,8 @@ int login_main(int argc, char **argv)
 	char full_tty[TTYNAME_SIZE];
 	USE_SELINUX(security_context_t user_sid = NULL;)
 	USE_FEATURE_UTMP(struct utmp utent;)
+	USE_PAM(pam_handle_t *pamh;)
+	USE_PAM(int pamret;)
 
 	short_tty = full_tty;
 	username[0] = '\0';
@@ -261,13 +272,12 @@ int login_main(int argc, char **argv)
 		USE_FEATURE_UTMP(
 			safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));
 		)
-		snprintf(fromhost, sizeof(fromhost)-1, " on '%.100s' from "
-					"'%.200s'", short_tty, opt_host);
+		fromhost = xasprintf(" on '%s' from '%s'", short_tty, opt_host);
 	} else
-		snprintf(fromhost, sizeof(fromhost)-1, " on '%.100s'", short_tty);
+		fromhost = xasprintf(" on '%s'", short_tty);
 
-	// Was breaking "login <username>" from shell command line:
-	// bb_setpgrp();
+	/* Was breaking "login <username>" from shell command line: */
+	/*bb_setpgrp();*/
 
 	openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
 
@@ -275,28 +285,68 @@ int login_main(int argc, char **argv)
 		if (!username[0])
 			get_username_or_die(username, sizeof(username));
 
+#if ENABLE_PAM
+		pamret = pam_start("login", username, &conv, &pamh);
+		if (pamret != PAM_SUCCESS) {
+			// pam failed, so abort the login
+			bb_error_msg("cannot init PAM: %s", pam_strerror(pamh, pamret));
+			goto auth_failed;
+		}
+		// continuing with pam authentication
+		// set TTY (so things like securetty work)
+		pamret = pam_set_item(pamh, PAM_TTY, short_tty);
+		if (pamret != PAM_SUCCESS) {
+			bb_error_msg("pam_set_item(TTY) failed: %s", pam_strerror(pamh, pamret));
+			goto auth_failed;
+		}
+		pamret = pam_authenticate(pamh, 0);
+		if (pamret == PAM_SUCCESS) {
+			// Then check that the account is healthy.
+			pamret = pam_acct_mgmt(pamh, 0);
+			if (pamret != PAM_SUCCESS) // No, it isn't
+				bb_error_msg("user not allowed access: %s", pam_strerror(pamh, pamret));
+			else {
+				// read user back
+				char *pamuser;
+				/* gcc: "dereferencing type-punned pointer breaks aliasing rules..."
+				 * thus we use double cast */
+				if (pam_get_item(pamh, PAM_USER, (const void **) (void*) &pamuser) != PAM_SUCCESS)
+					bb_error_msg("pam_get_item(USER) failed: %s", pam_strerror(pamh, pamret));
+				else
+					safe_strncpy(username, pamuser, sizeof(username));
+			}
+		}
+		// If we get here, the user was authenticated, and is
+		// granted access.
+		if (pam_end(pamh, pamret) != PAM_SUCCESS)
+			bb_error_msg("pam_end failed");
+
+		if (pamret != PAM_SUCCESS)
+			goto auth_failed;
+
+		pw = getpwnam(username);
+		if (pw)
+			break;
+		safe_strncpy(username, "UNKNOWN", sizeof(username));
+#else /* not PAM */
 		pw = getpwnam(username);
 		if (!pw) {
 			safe_strncpy(username, "UNKNOWN", sizeof(username));
 			goto auth_failed;
 		}
-
 		if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')
 			goto auth_failed;
-
 		if (opt & LOGIN_OPT_f)
 			break; /* -f USER: success without asking passwd */
-
 		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])
 			break;
-
 		/* authorization takes place here */
 		if (correct_password(pw))
 			break;
+#endif /* ENABLE_PAM */
 
  auth_failed:
 		opt &= ~LOGIN_OPT_f;
diff -d -urpN busybox.2/Makefile.flags busybox.3/Makefile.flags
--- busybox.2/Makefile.flags	2007-05-23 02:37:25.000000000 +0200
+++ busybox.3/Makefile.flags	2007-05-29 04:34:02.000000000 +0200
@@ -51,6 +51,10 @@ ifeq ($(CONFIG_DEBUG),y)
 CFLAGS += $(call cc-option,-g)
 endif
 
+ifeq ($(CONFIG_PAM),y)
+LDLIBS += -lpam -lpam_misc
+endif
+
 ifeq ($(CONFIG_STATIC),y)
 LDFLAGS += -static
 endif
_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox

Reply via email to