static void
authenticate (const struct passwd* pw) {
    const struct passwd* lpw = NULL;
    const char* cp, *srvname = NULL;
    int retval;

    switch (su_mode) {
    case SU_MODE:
        srvname = simulate_login ? PAM_SRVNAME_SU_L : PAM_SRVNAME_SU;
        break;
    case RUNUSER_MODE:
        srvname = simulate_login ? PAM_SRVNAME_RUNUSER_L : PAM_SRVNAME_RUNUSER;
        break;
    default:
        abort();
        break;
    }

    retval = pam_start (srvname, pw->pw_name, &conv, &pamh);
    if (is_pam_failure(retval)) {
        goto done;
    }

    if (isatty (0) && (cp = ttyname (0)) != NULL) {
        const char* tty;

        if (strncmp (cp, "/dev/", 5) == 0) {
            tty = cp + 5;
        } else {
            tty = cp;
        }
        retval = pam_set_item (pamh, PAM_TTY, tty);
        if (is_pam_failure(retval)) {
            goto done;
        }
    }

    lpw = current_getpwuid ();
    if (lpw && lpw->pw_name) {
        retval = pam_set_item (pamh, PAM_RUSER, (const void*) lpw->pw_name);
        if (is_pam_failure(retval)) {
            goto done;
        }
    }

    if (su_mode == RUNUSER_MODE) {
        /*
         * This is the only difference between runuser(1) and su(1). The command
         * runuser(1) does not required authentication, because user is root.
         */
        if (restricted) {
            errx(EXIT_FAILURE, _("may not be used by non-root users"));
        }
        return;
    }

    retval = pam_authenticate (pamh, 0);
    if (is_pam_failure(retval)) {
        goto done;
    }

    retval = pam_acct_mgmt (pamh, 0);
    if (retval == PAM_NEW_AUTHTOK_REQD) {
        /* Password has expired.  Offer option to change it.  */
        retval = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
    }

done:

    log_syslog(pw, !is_pam_failure(retval));

    if (is_pam_failure(retval)) {
        const char* msg;

        log_btmp(pw);

        msg  = pam_strerror(pamh, retval);
        pam_end(pamh, retval);
        sleep (getlogindefs_num ("FAIL_DELAY", 1));
        errx (EXIT_FAILURE, "%s", msg ? msg : _("incorrect password"));
    }
}
Example #2
0
static void loginpam_auth(struct login_context *cxt)
{
	int rc, show_unknown;
	unsigned int retries, failcount = 0;
	const char *hostname = cxt->hostname ? cxt->hostname :
			       cxt->tty_name ? cxt->tty_name : "<unknown>";
	pam_handle_t *pamh = cxt->pamh;

	/* if we didn't get a user on the command line, set it to NULL */
	loginpam_get_username(pamh, &cxt->username);

	show_unknown = getlogindefs_bool("LOG_UNKFAIL_ENAB", 0);
	retries = getlogindefs_num("LOGIN_RETRIES", LOGIN_MAX_TRIES);

	/*
	 * There may be better ways to deal with some of these conditions, but
	 * at least this way I don't think we'll be giving away information...
	 *
	 * Perhaps someday we can trust that all PAM modules will pay attention
	 * to failure count and get rid of LOGIN_MAX_TRIES?
	 */
	rc = pam_authenticate(pamh, 0);

	while ((++failcount < retries) &&
	       ((rc == PAM_AUTH_ERR) ||
		(rc == PAM_USER_UNKNOWN) ||
		(rc == PAM_CRED_INSUFFICIENT) ||
		(rc == PAM_AUTHINFO_UNAVAIL))) {

		if (rc == PAM_USER_UNKNOWN && !show_unknown)
			/*
			 * Logging unknown usernames may be a security issue if
			 * a user enters her password instead of her login name.
			 */
			cxt->username = NULL;
		else
			loginpam_get_username(pamh, &cxt->username);

		syslog(LOG_NOTICE,
		       _("FAILED LOGIN %u FROM %s FOR %s, %s"),
		       failcount, hostname,
		       cxt->username ? cxt->username : "******",
		       pam_strerror(pamh, rc));

		log_btmp(cxt);
		log_audit(cxt, 0);

		fprintf(stderr, _("Login incorrect\n\n"));

		pam_set_item(pamh, PAM_USER, NULL);
		rc = pam_authenticate(pamh, 0);
	}

	if (is_pam_failure(rc)) {

		if (rc == PAM_USER_UNKNOWN && !show_unknown)
			cxt->username = NULL;
		else
			loginpam_get_username(pamh, &cxt->username);

		if (rc == PAM_MAXTRIES)
			syslog(LOG_NOTICE,
			       _("TOO MANY LOGIN TRIES (%u) FROM %s FOR %s, %s"),
			       failcount, hostname,
			       cxt->username ? cxt->username : "******",
			       pam_strerror(pamh, rc));
		else
			syslog(LOG_NOTICE,
			       _("FAILED LOGIN SESSION FROM %s FOR %s, %s"),
			       hostname,
			       cxt->username ? cxt->username : "******",
			       pam_strerror(pamh, rc));

		log_btmp(cxt);
		log_audit(cxt, 0);

		fprintf(stderr, _("\nLogin incorrect\n"));
		pam_end(pamh, rc);
		sleepexit(EXIT_SUCCESS);
	}
}