openssh 3.6.1_p2 problem with pam (fwd)

Frank Cusack fcusack at fcusack.com
Mon May 12 14:20:31 EST 2003


OK, here is my take on how PAM flow should go, in pseudocode, with #ifdef
commentary on where openssh-3.6.1p2 strays.  I've just submitted a patch

http://bugzilla.mindrot.org/show_bug.cgi?id=559
http://bugzilla.mindrot.org/attachment.cgi?id=289&action=view

which adresses some of the problems below.  The description below isn't as
readable as I had hoped, but at least it does show PAM behavior as a
single flow of control; whereas in openssh you'll have to look into a
number of files.

#ifdef OPENSSH
pw = getpwbynam(user);
pamh = pam_start(service, pw ? user : "NOUSER", ...);
#else
pamh = pam_start(service, user, ...);
#endif

if (options.permit_empty_password)
    pam_auth_flags = 0;
else
    pam_auth_flags = PAM_DISALLOW_NULL_AUTHTOK;

if (protocol == 1) {
    if (password_auth_enabled()) {
	/* kludge */
	set_conv(non_interactive_conv_func);

#ifdef OPENSSH
	{
#else
	if (options.permit_empty_password) {
#endif
	    /*
	     * Need to do this because of a password_auth deficiency:  the
	     * client prompts for the password before the server asks for it.
	     * This breaks "don't prompt on null password" expected behavior.
	     *
	     * Results in a spurious pam log for accounts with password. :-(
	     * And is just plain broken, for the general case--consider
	     * a PAM module that only allows x attempts in y secs.
	     */
	    set_password("");
#ifdef OPENSSH
	    /*
	     * NB: pam_auth_flags might be PAM_DISALLOW_NULL_AUTHTOK,
	     * in which case this call to pam_authenticate() is pointless.
	     * See above, where we test options.permit_empty_password first.
	     */
#endif
	    pam_authenticate(pamh, pam_auth_flags);
	    if (authenticated)
		goto pam_account;
	}
	set_password(get_password());
	pam_authenticate(pamh, pam_auth_flags);
    }
}

if ("none" authentication) {
    /* protocol 2 does this first */
#ifdef OPENSSH
    {
#else
    if (password_auth_enabled() && options.permit_empty_password) {
	/* kbdint handles this itself */
#endif
	set_conv(non_interactive_conv_func);
	set_password("");
#ifdef OPENSSH
	/* see comment about pam_auth_flags, above */
#endif
	pam_authenticate(pamh, pam_auth_flags);
	if (authenticated)
	    goto pam_account;
    }
}


if (is_password_auth || is_kbd_int_auth) {
    if (is_password_auth)
	set_conv(non_interactive_conv_func);
    else
	set_conv(interactive_conv_function);
#ifdef OPENSSH
    /* NB: Ignores setting of options.permit_empty_password */
    if (protocol == 2)
	pam_auth_flags = 0;
#endif
    pam_authenticate(pamh, pam_auth_flags);
    if (!authenticated)
	return failure;
}

pam_account:
r = pam_acct_mgmt(pamh, pam_auth_flags);
if (r == PAM_SUCCESS)
    return success;

#ifndef OPENSSH
if (r != PAM_NEW_AUTHTOK_REQD)
#endif
    /* NB: OPENSSH notes below don't matter since we fail here */
    return failure;

/* new password required */
if (is_password_auth) {
    /* password_auth deficiency, argh */
    flag_password_change_needed();
    return success;
}

if (is_kbd_int_auth) {
#ifdef OPENSSH
    /* password_auth deficiency, not a kbd_int deficiency, argh! */
    flag_password_change_needed();
    return success;
#else
    /* PAM_CHANGE_EXPIRED_AUTHTOK is iffy */
    return ((pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK) == 0)
	    ? success
	    : failure);
#endif
}

/* non password, non kbd-int, but password expired ... a tough call */
return success;

In addition to the parts noted above, additional bugs:

- #if 0'd out code for pam_chauthtok && privsep, even though it works
  correctly for non-privsep, AFAIK (auth-pam.c:251; auth-pam.c:347)
- extraneous failure message for 'none' auth (noise)
- PAM_TEXT_INFO and PAM_ERROR_MSG messages are aggregrated rather than passed
  to the client in order; if the conversation is *only* PAM_TEXT_INFO and
  PAM_ERROR_MSG messages the client doesn't see them at all, for kbdint
- do_pam_conversation_kbd_int() leaks char *text
- protocol 2 assumes client will do 'none' authentication
- kbdint authentication cannot be abandoned
- user:style is not supported by the ietf-drafts

/fc




More information about the openssh-unix-dev mailing list