On Sunday 01 February 2009 20:47, walter harms wrote:
> Denys Vlasenko schrieb:
> > On Saturday 31 January 2009 18:37, walter harms wrote:
> >> Hi Denis,
> >> i have broken down my patch to login.c into several pieces (4).
> >> Shall i send the diff or the .c ?
> > 
> > Please send diffs
> 
> attached all patches should apply on top of each other. The patches are based
> on the login.c i send to the list end of last year.
> 
> v0-v1: basicly moves SELINUX and LOGIN_SCRIPTS out of the way

-#if ENABLE_SELINUX
-       if (is_selinux_enabled()) {
-               security_context_t old_tty_sid, new_tty_sid;
+       USE_SELINUX(initselinux(username, full_tty, &user_sid));

-               if (get_default_context(username, NULL, &user_sid)) {

but then

+static void initselinux(char *username, char *full_tty,
+                                               security_context_t * user_sid)
+{
+       security_context_t old_tty_sid, new_tty_sid;
+
+       if (get_default_context(username, NULL, user_sid)) {
+               bb_error_msg_and_die("cannot get SID for %s", username);
+       }

You lost "if (is_selinux_enabled()) ..." part


> v1-v2: rework the get ttynam() part, move from array to pointer

+       full_tty = ttyname(STDIN_FILENO);
+       if (!full_tty || strncmp(full_tty, "/dev/", 5)) {
+               full_tty = (char *) "UNKNOWN";
+               short_tty = full_tty;
+       } else {
+               short_tty = full_tty + 5;

If ttyname does not start with "/dev/", you set it to "UNKNOWN".
This is wrong.


> v2-v3: move pswd check for PAM and !PAM into check_pswd()
>       - fix getpwnam_r buffer size

+static
+struct passwd *bb_getpwnam_r(char *username)
+{
+       struct passwd *pwdstruct,*ptr;
+       struct passwd *pwd1;
+       size_t len = 1024;
+       long int initlen = sysconf(_SC_GETPW_R_SIZE_MAX);
+
+       if (initlen > 0)
+               len = (size_t) initlen;

what if sysconf() return a value which doesn't fit in size_t?

+
+       /*
+          pwdstruct is a list of pointers to

no, it isn't

+          data stored in pwdbuf

stored where?

+        */
+
+       pwdstruct= xmalloc(len+sizeof(*pwdstruct));
+       ptr=pwdstruct+len;

Bug. pwdstruct + n moves ptr n * sizeof(struct passwd) bytes!



+       /*
+         pwd1 will become NULL on not found
+          getpwnam_r will become 0 on eror

getpwnam does not "become", it "returns".



+/*
+  this is a special case
+*/
+       if (!pamuser || !pamuser[0])
+               goto auth_failed;

Does this comment actually explain something? If it says
'NULL or "" username is considered a failure', well,
that's obvious from the code.


        if (option_mask32 & LOGIN_OPT_f)
...
...
...
                opt &= ~LOGIN_OPT_f;

You forgot to copy updated flags to option_mask32.



I think check_pswd() can be better implemented as:

struct passwd *check_pswd(const char *username)

instead of

static int check_pswd(char *username, int userlen, struct passwd **pw2)



When these issues are addressed:

function                                             old     new   delta
login_main                                          1552    1584     +32

:(

I applied patches 1 and 2, thanks! Please look at attached patch.
It's a cleaned up version of patch 3. I hesitate to apply it
to svn, there might be more unexploded ordnance there.

If it would be at least not bigger with the patch according
to "make bloatcheck", then maybe...
--
vda
diff -d -urpN busybox.4/loginutils/login.c busybox.5/loginutils/login.c
--- busybox.4/loginutils/login.c	2009-02-02 00:13:37.000000000 +0100
+++ busybox.5/loginutils/login.c	2009-02-02 01:03:16.000000000 +0100
@@ -31,7 +31,12 @@ enum {
 	TIMEOUT = 60,
 	EMPTY_USERNAME_COUNT = 10,
 	USERNAME_SIZE = 32,
-	TTYNAME_SIZE = 32,
+};
+
+enum {
+	LOGIN_OPT_f = (1 << 0),
+	LOGIN_OPT_h = (1 << 1),
+	LOGIN_OPT_p = (1 << 2),
 };
 
 static char* short_tty;
@@ -267,14 +272,129 @@ static void alarm_handler(int sig UNUSED
 	_exit(EXIT_SUCCESS);
 }
 
+#if ENABLE_PAM
+static struct passwd *bb_getpwnam_r(const char *username)
+{
+	struct passwd *pw, *result;
+	int buflen;
+	long sclen;
+
+	buflen = 1024;
+	sclen = sysconf(_SC_GETPW_R_SIZE_MAX);
+	if ((unsigned long)sclen < 999999)
+		buflen = sclen;
+
+	pw = xmalloc(sizeof(*pw) + buflen);
+	result = NULL;
+	getpwnam_r(username, pw, (char*)(pw + 1), buflen, &result);
+	if (result != NULL)
+		return result;
+	free(pw);
+	return NULL;
+}
+
+static struct passwd *check_pswd(const char *username)
+{
+	int pamret;
+	pam_handle_t *pamh;
+	const char *pamuser;
+	const char *failed_msg;
+	struct passwd *pw = NULL;
+
+	pamret = pam_start("login", username, &conv, &pamh);
+	if (pamret != PAM_SUCCESS) {
+		failed_msg = "start";
+		goto pam_auth_failed;
+	}
+	/* set TTY (so things like securetty work) */
+	pamret = pam_set_item(pamh, PAM_TTY, short_tty);
+	if (pamret != PAM_SUCCESS) {
+		failed_msg = "set_item(TTY)";
+		goto pam_auth_failed;
+	}
+	pamret = pam_authenticate(pamh, 0);
+	if (pamret != PAM_SUCCESS) {
+		failed_msg = "authenticate";
+		goto pam_auth_failed;
+		/* TODO: or just "goto auth_failed"
+		 * since user seems to enter wrong password
+		 * (in this case pamret == 7)
+		 */
+	}
+	/* check that the account is healthy */
+	pamret = pam_acct_mgmt(pamh, 0);
+	if (pamret != PAM_SUCCESS) {
+		failed_msg = "acct_mgmt";
+		goto pam_auth_failed;
+	}
+	/* read user back */
+	pamuser = NULL;
+	/* gcc: "dereferencing type-punned pointer breaks aliasing rules..."
+	 * thus we cast to (void*) */
+	if (pam_get_item(pamh, PAM_USER, (void *) &pamuser) != PAM_SUCCESS) {
+		failed_msg = "get_item(USER)";
+		goto pam_auth_failed;
+	}
+	if (!pamuser || !pamuser[0])
+		goto auth_failed;
+
+	/* Don't use "pw = getpwnam(username);",
+	 * PAM is said to be capable of destroying static storage
+	 * used by getpwnam(). We are using safe(r) function */
+	pw = bb_getpwnam_r(username);
+	if (!pw)
+		goto auth_failed;
+
+	pamret = pam_open_session(pamh, 0);
+	if (pamret != PAM_SUCCESS) {
+		failed_msg = "open_session";
+		goto pam_auth_failed;
+	}
+	pamret = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+	if (pamret != PAM_SUCCESS) {
+		failed_msg = "setcred";
+		goto pam_auth_failed;
+	}
+	return pw; /* success, continue login process */
+
+ pam_auth_failed:
+	bb_error_msg("pam_%s call failed: %s (%d)", failed_msg,
+				 pam_strerror(pamh, pamret), pamret);
+ auth_failed:
+	free(pw);
+	return NULL;
+}
+#else /* !ENABLE_PAM */
+static struct passwd *check_pswd(const char *username)
+{
+	struct passwd *pw;
+
+	pw = getpwnam(username);	/* replace with _r  ?? */
+	if (!pw)
+		goto fake_it;
+
+	if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')
+		goto auth_failed;
+	if (option_mask32 & LOGIN_OPT_f)
+		return pw;	/* -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])
+		return pw; /* success */
+ fake_it:
+	/* Authorization takes place here */
+	if (correct_password(pw))
+		return pw;
+ auth_failed:
+//	free(pw);
+	return NULL;
+}
+#endif
+
 int login_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int login_main(int argc UNUSED_PARAM, char **argv)
 {
-	enum {
-		LOGIN_OPT_f = (1<<0),
-		LOGIN_OPT_h = (1<<1),
-		LOGIN_OPT_p = (1<<2),
-	};
 	char *fromhost;
 	char username[USERNAME_SIZE];
 	const char *tmp;
@@ -287,14 +407,6 @@ int login_main(int argc UNUSED_PARAM, ch
 	char *full_tty;
 	USE_SELINUX(security_context_t user_sid = NULL;)
 	USE_FEATURE_UTMP(struct utmp utent;)
-#if ENABLE_PAM
-	int pamret;
-	pam_handle_t *pamh;
-	const char *pamuser;
-	const char *failed_msg;
-	struct passwd pwdstruct;
-	char pwdbuf[256];
-#endif
 
 	username[0] = '\0';
 	signal(SIGALRM, alarm_handler);
@@ -351,96 +463,17 @@ int login_main(int argc UNUSED_PARAM, ch
 		if (!username[0])
 			get_username_or_die(username, sizeof(username));
 
-#if ENABLE_PAM
-		pamret = pam_start("login", username, &conv, &pamh);
-		if (pamret != PAM_SUCCESS) {
-			failed_msg = "start";
-			goto pam_auth_failed;
-		}
-		/* set TTY (so things like securetty work) */
-		pamret = pam_set_item(pamh, PAM_TTY, short_tty);
-		if (pamret != PAM_SUCCESS) {
-			failed_msg = "set_item(TTY)";
-			goto pam_auth_failed;
-		}
-		pamret = pam_authenticate(pamh, 0);
-		if (pamret != PAM_SUCCESS) {
-			failed_msg = "authenticate";
-			goto pam_auth_failed;
-			/* TODO: or just "goto auth_failed"
-			 * since user seems to enter wrong password
-			 * (in this case pamret == 7)
-			 */
-		}
-		/* check that the account is healthy */
-		pamret = pam_acct_mgmt(pamh, 0);
-		if (pamret != PAM_SUCCESS) {
-			failed_msg = "acct_mgmt";
-			goto pam_auth_failed;
-		}
-		/* read user back */
-		pamuser = NULL;
-		/* gcc: "dereferencing type-punned pointer breaks aliasing rules..."
-		 * thus we cast to (void*) */
-		if (pam_get_item(pamh, PAM_USER, (void*)&pamuser) != PAM_SUCCESS) {
-			failed_msg = "get_item(USER)";
-			goto pam_auth_failed;
-		}
-		if (!pamuser || !pamuser[0])
-			goto auth_failed;
-		safe_strncpy(username, pamuser, sizeof(username));
-		/* Don't use "pw = getpwnam(username);",
-		 * PAM is said to be capable of destroying static storage
-		 * used by getpwnam(). We are using safe(r) function */
-		pw = NULL;
-		getpwnam_r(username, &pwdstruct, pwdbuf, sizeof(pwdbuf), &pw);
-		if (!pw)
-			goto auth_failed;
-		pamret = pam_open_session(pamh, 0);
-		if (pamret != PAM_SUCCESS) {
-			failed_msg = "open_session";
-			goto pam_auth_failed;
-		}
-		pamret = pam_setcred(pamh, PAM_ESTABLISH_CRED);
-		if (pamret != PAM_SUCCESS) {
-			failed_msg = "setcred";
-			goto pam_auth_failed;
-		}
-		break; /* success, continue login process */
-
- pam_auth_failed:
-		bb_error_msg("pam_%s call failed: %s (%d)", failed_msg,
-					pam_strerror(pamh, pamret), pamret);
-		safe_strncpy(username, "UNKNOWN", sizeof(username));
-#else /* not PAM */
-		pw = getpwnam(username);
-		if (!pw) {
-			strcpy(username, "UNKNOWN");
-			goto fake_it;
-		}
-
-		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;
- fake_it:
-		/* authorization takes place here */
-		if (correct_password(pw))
+		pw = check_pswd(username);
+		if (pw)
 			break;
-#endif /* ENABLE_PAM */
- auth_failed:
+		safe_strncpy(username, "UNKNOWN", userlen);
+
 		opt &= ~LOGIN_OPT_f;
+		option_mask32 = opt;
 		bb_do_delay(FAIL_DELAY);
 		/* TODO: doesn't sound like correct English phrase to me */
 		puts("Login incorrect");
+//FIXME: PAM may have it own ideas how often we can try
 		if (++count == 3) {
 			syslog(LOG_WARNING, "invalid password for '%s'%s",
 						username, fromhost);
@@ -450,6 +483,8 @@ int login_main(int argc UNUSED_PARAM, ch
 	} /* while (1) */
 
 	alarm(0);
+	safe_strncpy(username, pw->pw_name, sizeof(username));
+
 	/* We can ignore /etc/nologin if we are logging in as root,
 	 * it doesn't matter whether we are run by root or not */
 	if (pw->pw_uid != 0)
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to