Example #1
0
static bool ChangePlaintextPasswordUsingLibPam(const char *puser, const char *password)
{
    int status;
    pam_handle_t *handle;
    struct pam_conv conv;
    conv.conv = PasswordSupplier;
    conv.appdata_ptr = (void*)password;

    status = pam_start("passwd", puser, &conv, &handle);
    if (status != PAM_SUCCESS)
    {
        Log(LOG_LEVEL_ERR, "Could not initialize pam session. (pam_start: '%s')", pam_strerror(NULL, status));
        return false;
    }
    Log(LOG_LEVEL_VERBOSE, "Changing password for user '%s'.", puser);
    status = pam_chauthtok(handle, PAM_SILENT);
    pam_end(handle, status);
    if (status == PAM_SUCCESS)
    {
        return true;
    }
    else
    {
        Log(LOG_LEVEL_ERR, "Could not change password for user '%s'. (pam_chauthtok: '%s')",
            puser, pam_strerror(handle, status));
        return false;
    }
}
Example #2
0
static enum pamtest_err run_test_case(pam_handle_t *ph,
				      struct pam_testcase *tc)
{
	switch (tc->pam_operation) {
	case PAMTEST_AUTHENTICATE:
		tc->op_rv = pam_authenticate(ph, tc->flags);
		return PAMTEST_ERR_OK;
	case PAMTEST_SETCRED:
		tc->op_rv = pam_setcred(ph, tc->flags);
		return PAMTEST_ERR_OK;
	case PAMTEST_ACCOUNT:
		tc->op_rv = pam_acct_mgmt(ph, tc->flags);
		return PAMTEST_ERR_OK;
	case PAMTEST_OPEN_SESSION:
		tc->op_rv = pam_open_session(ph, tc->flags);
		return PAMTEST_ERR_OK;
	case PAMTEST_CLOSE_SESSION:
		tc->op_rv = pam_close_session(ph, tc->flags);
		return PAMTEST_ERR_OK;
	case PAMTEST_CHAUTHTOK:
		tc->op_rv = pam_chauthtok(ph, tc->flags);
		return PAMTEST_ERR_OK;
	case PAMTEST_GETENVLIST:
		tc->case_out.envlist = pam_getenvlist(ph);
		return PAMTEST_ERR_OK;
	case PAMTEST_KEEPHANDLE:
		tc->case_out.ph = ph;
		return PAMTEST_ERR_KEEPHANDLE;
	default:
		return PAMTEST_ERR_OP;
	}

	return PAMTEST_ERR_OP;
}
Example #3
0
 bool PamHandle::chAuthTok(int flags) {
     m_result = pam_chauthtok(m_handle, flags | m_silent);
     if (m_result != PAM_SUCCESS) {
         qWarning() << "[PAM] chAuthTok:" << pam_strerror(m_handle, m_result);
     }
     return m_result == PAM_SUCCESS;
 }
Example #4
0
static void loginpam_acct(struct login_context *cxt)
{
	int rc;
	pam_handle_t *pamh = cxt->pamh;

	rc = pam_acct_mgmt(pamh, 0);

	if (rc == PAM_NEW_AUTHTOK_REQD)
		rc = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);

	if (is_pam_failure(rc))
		loginpam_err(pamh, rc);

	/*
	 * Grab the user information out of the password file for future use.
	 * First get the username that we are actually using, though.
	 */
	rc = loginpam_get_username(pamh, &cxt->username);
	if (is_pam_failure(rc))
		loginpam_err(pamh, rc);

	if (!cxt->username || !*cxt->username) {
		warnx(_("\nSession setup problem, abort."));
		syslog(LOG_ERR, _("NULL user name in %s:%d. Abort."),
		       __FUNCTION__, __LINE__);
		pam_end(pamh, PAM_SYSTEM_ERR);
		sleepexit(EXIT_FAILURE);
	}
}
void
do_pam_passwd(const char *user, int silent, int change_expired)
{
	pam_handle_t *pamh = NULL;
	int flags = 0, ret;

	if (silent)
		flags |= PAM_SILENT;
	if (change_expired)
		flags |= PAM_CHANGE_EXPIRED_AUTHTOK;

	ret = pam_start("passwd", user, &conv, &pamh);
	if (ret != PAM_SUCCESS) {
		fprintf(stderr, _("passwd: pam_start() failed, error %d\n"),
			ret);
		exit(10);  /* XXX */
	}

	ret = pam_chauthtok(pamh, flags);
	if (ret != PAM_SUCCESS) {
		fprintf(stderr, _("passwd: %s\n"), PAM_STRERROR(pamh, ret));
		pam_end(pamh, ret);
		exit(10);  /* XXX */
	}

	pam_end(pamh, PAM_SUCCESS);
}
int
sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
{
    const char *s;
    int *pam_status = (int *) auth->data;
    debug_decl(sudo_pam_verify, SUDO_DEBUG_AUTH)

    def_prompt = prompt;	/* for converse */

    /* PAM_SILENT prevents the authentication service from generating output. */
    *pam_status = pam_authenticate(pamh, PAM_SILENT);
    switch (*pam_status) {
	case PAM_SUCCESS:
	    *pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
	    switch (*pam_status) {
		case PAM_SUCCESS:
		    debug_return_int(AUTH_SUCCESS);
		case PAM_AUTH_ERR:
		    log_warning(NO_MAIL, N_("account validation failure, "
			"is your account locked?"));
		    debug_return_int(AUTH_FATAL);
		case PAM_NEW_AUTHTOK_REQD:
		    log_warning(NO_MAIL, N_("Account or password is "
			"expired, reset your password and try again"));
		    *pam_status = pam_chauthtok(pamh,
			PAM_CHANGE_EXPIRED_AUTHTOK);
		    if (*pam_status == PAM_SUCCESS)
			debug_return_int(AUTH_SUCCESS);
		    if ((s = pam_strerror(pamh, *pam_status)) != NULL) {
			log_warning(NO_MAIL,
			    N_("unable to change expired password: %s"), s);
		    }
		    debug_return_int(AUTH_FAILURE);
		case PAM_AUTHTOK_EXPIRED:
		    log_warning(NO_MAIL,
			N_("Password expired, contact your system administrator"));
		    debug_return_int(AUTH_FATAL);
		case PAM_ACCT_EXPIRED:
		    log_warning(NO_MAIL,
			N_("Account expired or PAM config lacks an \"account\" "
			"section for sudo, contact your system administrator"));
		    debug_return_int(AUTH_FATAL);
	    }
	    /* FALLTHROUGH */
	case PAM_AUTH_ERR:
	case PAM_AUTHINFO_UNAVAIL:
	    if (getpass_error) {
		/* error or ^C from tgetpass() */
		debug_return_int(AUTH_INTR);
	    }
	    /* FALLTHROUGH */
	case PAM_MAXTRIES:
	case PAM_PERM_DENIED:
	    debug_return_int(AUTH_FAILURE);
	default:
	    if ((s = pam_strerror(pamh, *pam_status)) != NULL)
		log_warning(NO_MAIL, N_("PAM authentication error: %s"), s);
	    debug_return_int(AUTH_FATAL);
    }
}
bool PAMAuthenticator::authenticate(void)
{
	pam_conv c;
	c.conv        = PAMAuthenticator::conv;
	c.appdata_ptr = this;

	int res = pam_start("repwatchproxy", 0, &c, &this->m_ph);
	if (res == PAM_SUCCESS) {
		res = pam_set_item(this->m_ph, PAM_RUSER, this->m_user.constData());
		if (res != PAM_SUCCESS) {
			goto getout;
		}

		res = pam_set_item(this->m_ph, PAM_RHOST, this->m_host.constData());
		if (res != PAM_SUCCESS) {
			goto getout;
		}

		res = pam_authenticate(this->m_ph, 0);
		if (res != PAM_SUCCESS) {
			goto getout;
		}

		res = pam_acct_mgmt(this->m_ph, 0);
		if (PAM_NEW_AUTHTOK_REQD == res) {
			res = pam_chauthtok(this->m_ph, PAM_CHANGE_EXPIRED_AUTHTOK);
		}

		if (res != PAM_SUCCESS) {
			goto getout;
		}

		res = pam_setcred(this->m_ph, PAM_ESTABLISH_CRED);
		if (res != PAM_SUCCESS) {
			goto getout;
		}

		res = pam_open_session(this->m_ph, 0);
		if (res != PAM_SUCCESS) {
			goto getout;
		}

		return true;

getout:
		qWarning("%s: %s", Q_FUNC_INFO, pam_strerror(this->m_ph, res));
		pam_end(this->m_ph, res);
	}
	else {
		qCritical("PAM initialization failed");
	}

	this->m_ph = 0;
	return false;
}
Example #8
0
File: pam.c Project: CVi/sudo
int
pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
{
    const char *s;
    int *pam_status = (int *) auth->data;

    def_prompt = prompt;	/* for converse */

    /* PAM_SILENT prevents the authentication service from generating output. */
    *pam_status = pam_authenticate(pamh, PAM_SILENT);
    switch (*pam_status) {
	case PAM_SUCCESS:
	    *pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
	    switch (*pam_status) {
		case PAM_SUCCESS:
		    return AUTH_SUCCESS;
		case PAM_AUTH_ERR:
		    log_error(NO_EXIT|NO_MAIL, _("account validation failure, "
			"is your account locked?"));
		    return AUTH_FATAL;
		case PAM_NEW_AUTHTOK_REQD:
		    log_error(NO_EXIT|NO_MAIL, _("Account or password is "
			"expired, reset your password and try again"));
		    *pam_status = pam_chauthtok(pamh,
			PAM_CHANGE_EXPIRED_AUTHTOK);
		    if (*pam_status == PAM_SUCCESS)
			return AUTH_SUCCESS;
		    if ((s = pam_strerror(pamh, *pam_status)))
			log_error(NO_EXIT|NO_MAIL, _("pam_chauthtok: %s"), s);
		    return AUTH_FAILURE;
		case PAM_AUTHTOK_EXPIRED:
		    log_error(NO_EXIT|NO_MAIL,
			_("Password expired, contact your system administrator"));
		    return AUTH_FATAL;
		case PAM_ACCT_EXPIRED:
		    log_error(NO_EXIT|NO_MAIL,
			_("Account expired or PAM config lacks an \"account\" "
			"section for sudo, contact your system administrator"));
		    return AUTH_FATAL;
	    }
	    /* FALLTHROUGH */
	case PAM_AUTH_ERR:
	    if (gotintr) {
		/* error or ^C from tgetpass() */
		return AUTH_INTR;
	    }
	case PAM_MAXTRIES:
	case PAM_PERM_DENIED:
	    return AUTH_FAILURE;
	default:
	    if ((s = pam_strerror(pamh, *pam_status)))
		log_error(NO_EXIT|NO_MAIL, _("pam_authenticate: %s"), s);
	    return AUTH_FATAL;
    }
}
Example #9
0
int main(int argc, char *argv[])
{
    pam_handle_t *pamh=NULL;
    int retval;
    const char *user="******";

    if(argc == 2) {
        user = argv[1];
    }

    if(argc > 2) {
        fprintf(stderr, "Usage: check_user [username]\n");
        exit(1);
    }

    retval = pam_start("sqlite3", user, &conv, &pamh);

    if(retval == PAM_SUCCESS)
        printf("PAM started.\n");

    if (retval == PAM_SUCCESS)
        retval = pam_authenticate(pamh, 0);    /* is user really user? */

    if(retval == PAM_SUCCESS)
        printf("Authentication succeeded, checking access.\n");
    else 
        printf("Authentication failed: %s\n", pam_strerror(pamh, retval));

    if (retval == PAM_SUCCESS)
        retval = pam_acct_mgmt(pamh, 0);       /* permitted access? */

    if(retval == PAM_SUCCESS)
        printf("Access permitted.\n");
    else 
        printf("Access denied: %s\n", pam_strerror(pamh, retval));

    /* lets try print password */
    printf("Changing authentication token...\n");
    retval = pam_chauthtok(pamh, 0); 
    if(retval != PAM_SUCCESS) {
        printf("Failed: %s\n", pam_strerror(pamh, retval));
    } else {
        printf("Token changed.\n");
    }

    /* This is where we have been authorized or not. */
    if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
        pamh = NULL;
        fprintf(stderr, "check_user: failed to release authenticator\n");
        exit(1);
    }

    return ( retval == PAM_SUCCESS ? 0:1 );       /* indicate success */
}
Example #10
0
static int
sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags)
{
	int result;

	if (sshpam_authctxt == NULL)
		fatal("PAM: sshpam_authctxt not initialized");
	if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1)
		fatal("%s: setreuid failed: %s", __func__, strerror(errno));
	result = pam_chauthtok(pamh, flags);
	if (setreuid(0, -1) == -1)
		fatal("%s: setreuid failed: %s", __func__, strerror(errno));
	return result;
}
Example #11
0
static void
pm_do_auth(adt_session_data_t *ah)
{
	pam_handle_t	*pm_pamh;
	int		err;
	int		pam_flag = 0;
	int		chpasswd_tries;
	struct pam_conv pam_conv = {pam_tty_conv, NULL};

	if (user[0] == '\0')
		return;

	if ((err = pam_start("sys-suspend", user, &pam_conv,
	    &pm_pamh)) != PAM_SUCCESS)
		return;

	pam_flag = PAM_DISALLOW_NULL_AUTHTOK;

	do {
		err = pam_authenticate(pm_pamh, pam_flag);

		if (err == PAM_SUCCESS) {
			err = pam_acct_mgmt(pm_pamh, pam_flag);

			if (err == PAM_NEW_AUTHTOK_REQD) {
				chpasswd_tries = 0;

				do {
					err = pam_chauthtok(pm_pamh,
					    PAM_CHANGE_EXPIRED_AUTHTOK);
					chpasswd_tries++;

				} while ((err == PAM_AUTHTOK_ERR ||
				    err == PAM_TRY_AGAIN) &&
				    chpasswd_tries < DEF_ATTEMPTS);
				pm_audit_event(ah, ADT_passwd, err);
			}
			err = pam_setcred(pm_pamh, PAM_REFRESH_CRED);
		}
		if (err != PAM_SUCCESS) {
			(void) fprintf(stdout, "%s\n",
			    pam_strerror(pm_pamh, err));
			pm_audit_event(ah, ADT_screenunlock, err);
		}
	} while (err != PAM_SUCCESS);
	pm_audit_event(ah, ADT_passwd, 0);

	(void) pam_end(pm_pamh, err);
}
Example #12
0
int main(int argc, char **argv) {
	pam_handle_t *pamh=NULL;
	static struct pam_conv pamc = {
			misc_conv,
			NULL
	};

	if( PAM_SUCCESS != pam_start("test", "testa", &pamc, &pamh) )
	{
		fprintf(stderr, "ERR: pam_start failed!\n");
		return 1;
	}

	/*
	if( PAM_SUCCESS != pam_set_item(pamh, PAM_USER, "tester") )
	{
		fprintf(stderr, "ERR: pam_set_item user failed!\n");
		return 1;
	}

	if( PAM_SUCCESS != pam_chauthtok(pamh, 0) )
	{
		fprintf(stderr, "ERR: pam_chauthtok failed!\n");
		return 1;
	}

	if( PAM_SUCCESS != pam_set_item(pamh, PAM_AUTHTOK, "mypassword") )
	{
		fprintf(stderr, "ERR: pam_set_item password failed!\n");
		return 1;
	}
	*/

	if( PAM_SUCCESS != pam_chauthtok(pamh, 0) )
	{
		fprintf(stderr, "ERR: pam_chauthtok failed!\n");
		return 1;
	}

	if( PAM_SUCCESS != pam_end(pamh, PAM_SUCCESS) )
	{
		fprintf(stderr, "ERR: pam_end failed!\n");
		return 1;
	}

	return 0;

}
Example #13
0
/*
 * XXX this should be done in the authentication phase, but ssh1 doesn't
 * support that
 */
void
do_pam_chauthtok(void)
{
	if (use_privsep)
		fatal("Password expired (unable to change with privsep)");
	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
	    (const void *)&tty_conv);
	if (sshpam_err != PAM_SUCCESS)
		fatal("PAM: failed to set PAM_CONV: %s",
		    pam_strerror(sshpam_handle, sshpam_err));
	debug("PAM: changing password");
	sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
	if (sshpam_err != PAM_SUCCESS)
		fatal("PAM: pam_chauthtok(): %s",
		    pam_strerror(sshpam_handle, sshpam_err));
}
Example #14
0
int main(int argc, char *argv[])
{
	pam_handle_t *pamh = NULL;
	int retval;
	struct pam_conv conv = { gradm_pam_conv, NULL };
	struct gr_arg_wrapper wrapper;
	struct gr_arg arg;
	int fd;

	if (argc != 2)
		exit(EXIT_FAILURE);

	wrapper.version = GRADM_VERSION;
	wrapper.size = sizeof(struct gr_arg);
	wrapper.arg = &arg;
	arg.mode = GRADM_STATUS;

	if ((fd = open(GRDEV_PATH, O_WRONLY)) < 0) {
		fprintf(stderr, "Could not open %s.\n", GRDEV_PATH);
		failure("open");
	}

	retval = write(fd, &wrapper, sizeof(struct gr_arg_wrapper));
	close(fd);

	if (retval != 1)
		exit(EXIT_FAILURE);

	retval = pam_start(PAM_SERVICENAME, argv[1], &conv, &pamh);

	if (retval == PAM_SUCCESS)
		retval = pam_authenticate(pamh, 0);

	if (retval == PAM_SUCCESS)
		retval = pam_acct_mgmt(pamh, 0);

	if (retval == PAM_AUTHTOK_EXPIRED)
		retval = pam_chauthtok(pamh, 0);

	if (pamh)
		pam_end(pamh, retval);

	if (retval != PAM_SUCCESS)
		exit(EXIT_FAILURE);

	return EXIT_SUCCESS;
}
Example #15
0
File: auth.c Project: legionus/kbd
static int
do_account_password_management(pam_handle_t *pamh)
{
	int rc;

	/* Whether the authenticated user is allowed to log in? */
	rc = pam_acct_mgmt(pamh, 0);

	/* Do we need to prompt the user for a new password? */
	if (rc == PAM_NEW_AUTHTOK_REQD)
		rc = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);

	/* Extend the lifetime of the existing credentials. */
	if (rc == PAM_SUCCESS)
		rc = pam_setcred(pamh, PAM_REFRESH_CRED);

	return rc;
}
Example #16
0
File: pam.c Project: fqtools/ocserv
static void co_auth_user(void* data)
{
struct pam_ctx_st * pctx = data;
int pret;

	pctx->state = PAM_S_INIT;

	pret = pam_authenticate(pctx->ph, 0);
	if (pret != PAM_SUCCESS) {
		syslog(LOG_INFO, "PAM authenticate error: %s", pam_strerror(pctx->ph, pret));
		pctx->cr_ret = pret;
		goto wait;
	}
	
	pret = pam_acct_mgmt(pctx->ph, 0);
	if (pret == PAM_NEW_AUTHTOK_REQD) {
		/* change password */
		syslog(LOG_INFO, "Password for user '%s' is expired. Attempting to update...", pctx->username);

		pctx->changing = 1;
		pret = pam_chauthtok(pctx->ph, PAM_CHANGE_EXPIRED_AUTHTOK);
	}
	
	if (pret != PAM_SUCCESS) {
		syslog(LOG_INFO, "PAM acct-mgmt error: %s", pam_strerror(pctx->ph, pret));
		pctx->cr_ret = pret;
		goto wait;
	}
	
	pctx->state = PAM_S_COMPLETE;
	pctx->cr_ret = PAM_SUCCESS;

wait:
	while(1) {
		co_resume();
	}
}
Example #17
0
/*
 * Attempt to authenticate the user using PAM.  Returns 0 if the user is
 * authenticated, or 1 if not authenticated.  If some sort of PAM system
 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
 * function returns -1.  This can be used as an indication that we should
 * fall back to a different authentication mechanism.
 */
static int
auth_pam(void)
{
	const char *tmpl_user;
	const void *item;
	int rval;

	pam_err = pam_authenticate(pamh, pam_silent);
	switch (pam_err) {

	case PAM_SUCCESS:
		/*
		 * With PAM we support the concept of a "template"
		 * user.  The user enters a login name which is
		 * authenticated by PAM, usually via a remote service
		 * such as RADIUS or TACACS+.  If authentication
		 * succeeds, a different but related "template" name
		 * is used for setting the credentials, shell, and
		 * home directory.  The name the user enters need only
		 * exist on the remote authentication server, but the
		 * template name must be present in the local password
		 * database.
		 *
		 * This is supported by two various mechanisms in the
		 * individual modules.  However, from the application's
		 * point of view, the template user is always passed
		 * back as a changed value of the PAM_USER item.
		 */
		pam_err = pam_get_item(pamh, PAM_USER, &item);
		if (pam_err == PAM_SUCCESS) {
			tmpl_user = (const char *)item;
			if (strcmp(username, tmpl_user) != 0)
				pwd = getpwnam(tmpl_user);
		} else {
			pam_syslog("pam_get_item(PAM_USER)");
		}
		rval = 0;
		break;

	case PAM_AUTH_ERR:
	case PAM_USER_UNKNOWN:
	case PAM_MAXTRIES:
		rval = 1;
		break;

	default:
		pam_syslog("pam_authenticate()");
		rval = -1;
		break;
	}

	if (rval == 0) {
		pam_err = pam_acct_mgmt(pamh, pam_silent);
		switch (pam_err) {
		case PAM_SUCCESS:
			break;
		case PAM_NEW_AUTHTOK_REQD:
			pam_err = pam_chauthtok(pamh,
			    pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK);
			if (pam_err != PAM_SUCCESS) {
				pam_syslog("pam_chauthtok()");
				rval = 1;
			}
			break;
		default:
			pam_syslog("pam_acct_mgmt()");
			rval = 1;
			break;
		}
	}

	if (rval != 0) {
		pam_end(pamh, pam_err);
		pamh = NULL;
	}
	return (rval);
}
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 #19
0
int main(int argc, char **argv) {
	struct sockaddr_storage peer_sa;
	struct sockaddr *peer = (struct sockaddr *)&peer_sa;
	int peerlen = sizeof(peer_sa);
	
	char user[1024];
	char luser[1024];
	char term[1024];
		
	int port;
	
	struct passwd *pw;
	
	int err;
	
	char opt;

	char host[NI_MAXHOST];
	
	char buf[4096];
	int len;
	
	struct pollfd pfd[3];
	
	struct winsize winsize;
	uint16_t winbuf[4];
	int i;
	
	int master, slave;
	char *tty;

	pam_handle_t *handle;		
	struct pam_conv conv = {conv_h, NULL};
	const void *item;
	char *pamuser;
	
	int pid;
	
	argv0 = argv[0];
	
	/* Process options */
			
	while((opt = getopt(argc, argv, "+")) != -1) {
		switch(opt) {
			default:
				syslog(LOG_ERR, "Unknown option!");
				usage();
				return 1;
		}
	}
	
	if(optind != argc) {
		syslog(LOG_ERR, "Too many arguments!");
		usage();
		return 1;
	}
	
	/* Check source of connection */
	
	if(getpeername(0, peer, &peerlen)) {
		syslog(LOG_ERR, "Can't get address of peer: %m");
		return 1;
	}
	
	/* Unmap V4MAPPED addresses */
	
	if(peer->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)peer)->sin6_addr)) {
		((struct sockaddr_in *)peer)->sin_addr.s_addr = ((struct sockaddr_in6 *)peer)->sin6_addr.s6_addr32[3];
		peer->sa_family = AF_INET;
	}

	/* Lookup hostname */
	
	if((err = getnameinfo(peer, peerlen, host, sizeof(host), NULL, 0, 0))) {
		syslog(LOG_ERR, "Error resolving address: %s", gai_strerror(err));
		return 1;
	}
	
	/* Check if connection comes from a privileged port */
	
	switch(peer->sa_family) {
		case AF_INET:
			port = ntohs(((struct sockaddr_in *)peer)->sin_port);
			break;
		case AF_INET6:
			port = ntohs(((struct sockaddr_in6 *)peer)->sin6_port);
			break;
		default:
			port = -1;
			break;
	}

	if(port != -1 && (port < 512 || port >= 1024)) {
		syslog(LOG_ERR, "Connection from %s on illegal port %d.", host, port);
		return 1;
	}
	
	/* Wait for NULL byte */
	
	if(read(0, buf, 1) != 1 || *buf) {
		syslog(LOG_ERR, "Didn't receive NULL byte from %s: %m\n", host);
		return 1;
	}

	/* Read usernames and terminal info */
	
	if(readtonull(0, user, sizeof(user)) <= 0 || readtonull(0, luser, sizeof(luser)) <= 0) {
		syslog(LOG_ERR, "Error while receiving usernames from %s: %m", host);
		return 1;
	}
	
	if(readtonull(0, term, sizeof(term)) <= 0) {
		syslog(LOG_ERR, "Error while receiving terminal from %s: %m", host);
		return 1;
	}
	
	syslog(LOG_NOTICE, "Connection from %s@%s for %s", user, host, luser);
	
	/* We need to have a pty before we can use PAM */
	
	if(openpty(&master, &slave, 0, 0, &winsize) != 0) {
		syslog(LOG_ERR, "Could not open pty: %m");
		return 1;
	}
	
	tty = ttyname(slave);

	/* Start PAM */
	
	if((err = pam_start("rlogin", luser, &conv, &handle)) != PAM_SUCCESS) {
		safewrite(1, "Authentication failure\n", 23);
		syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err));
		return 1;
	}
		
	pam_set_item(handle, PAM_USER, luser);
	pam_set_item(handle, PAM_RUSER, user);
	pam_set_item(handle, PAM_RHOST, host);
	pam_set_item(handle, PAM_TTY, tty);

	/* Write NULL byte to client so we can give a login prompt if necessary */
	
	if(safewrite(1, "", 1) == -1) {
		syslog(LOG_ERR, "Unable to write NULL byte: %m");
		return 1;
	}
	
	/* Try to authenticate */
	
	err = pam_authenticate(handle, 0);
	
	/* PAM might ask for a new password */
	
	if(err == PAM_NEW_AUTHTOK_REQD) {
		err = pam_chauthtok(handle, PAM_CHANGE_EXPIRED_AUTHTOK);
		if(err == PAM_SUCCESS)
			err = pam_authenticate(handle, 0);
	}
	
	if(err != PAM_SUCCESS) {
		safewrite(1, "Authentication failure\n", 23);
		syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err));
		return 1;
	}

	/* Check account */
	
	err = pam_acct_mgmt(handle, 0);
	
	if(err != PAM_SUCCESS) {
		safewrite(1, "Authentication failure\n", 23);
		syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err));
		return 1;
	}

	/* PAM can map the user to a different user */
	
	err = pam_get_item(handle, PAM_USER, &item);
	
	if(err != PAM_SUCCESS) {
		syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err));
		return 1;
	}
	
	pamuser = strdup((char *)item);
	
	if(!pamuser || !*pamuser) {
		syslog(LOG_ERR, "PAM didn't return a username?!");
		return 1;
	}

	pw = getpwnam(pamuser);

	if (!pw) {
		syslog(LOG_ERR, "PAM_USER does not exist?!");
		return 1;
	}
	
	if (setgid(pw->pw_gid)) {
		syslog(LOG_ERR, "setgid() failed: %m");
		return 1;
	}
	
	if (initgroups(pamuser, pw->pw_gid)) {
		syslog(LOG_ERR, "initgroups() failed: %m");
		return 1;
	}
	
	err = pam_setcred(handle, PAM_ESTABLISH_CRED);
	
	if(err != PAM_SUCCESS) {
		syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err));
		return 1;
	}
	
	/* Authentication succeeded */
	
	pam_end(handle, PAM_SUCCESS);
	
	/* spawn login shell */
	
	if((pid = fork()) < 0) {
		syslog(LOG_ERR, "fork() failed: %m");
		return 1;
	}
	
	if(send(1, "\x80", 1, MSG_OOB) <= 0) {
		syslog(LOG_ERR, "Unable to write OOB \x80: %m");
		return 1;
	}
	
	if(pid) {
		/* Parent process, still the rlogin server */
		
		close(slave);

		/* Process input/output */

		pfd[0].fd = 0;
		pfd[0].events = POLLIN | POLLERR | POLLHUP;
		pfd[1].fd = master;
		pfd[1].events = POLLIN | POLLERR | POLLHUP;
		
		for(;;) {
			errno = 0;

			if(poll(pfd, 2, -1) == -1) {
				if(errno == EINTR)
					continue;
				break;
			}

			if(pfd[0].revents) {
				len = read(0, buf, sizeof(buf));
				if(len <= 0)
					break;

				/* Scan for control messages. Yes this is evil and should be done differently. */
				
				for(i = 0; i < len - 11;) {
					if(buf[i++] == (char)0xFF)
					if(buf[i++] == (char)0xFF)
					if(buf[i++] == 's')
					if(buf[i++] == 's') {
						memcpy(winbuf, buf + i, 8);
						winsize.ws_row = ntohs(winbuf[0]);
						winsize.ws_col = ntohs(winbuf[1]);
						winsize.ws_xpixel = ntohs(winbuf[2]);
						winsize.ws_ypixel = ntohs(winbuf[3]);
						if(ioctl(master, TIOCSWINSZ, &winsize) == -1)
							break;
						memcpy(buf + i - 4, buf + i + 8, len - i - 8);
						i -= 4;
						len -= 12;
					}
				}
				
				if(safewrite(master, buf, len) == -1)
					break;
				pfd[0].revents = 0;
			}

			if(pfd[1].revents) {
				len = read(master, buf, sizeof(buf));
				if(len <= 0) {
					errno = 0;
					break;
				}
				if(safewrite(1, buf, len) == -1)
					break;
				pfd[1].revents = 0;
			}
		}

		/* The end */
		
		if(errno) {
			syslog(LOG_NOTICE, "Closing connection with %s@%s: %m", user, host);
			return 1;
		} else {
			syslog(LOG_NOTICE, "Closing connection with %s@%s", user, host);
			return 0;
		}
		
		close(master);
	} else {
		/* Child process, will become the shell */
		
		char *speed;
		struct termios tios;
		char *envp[2];

		/* Prepare tty for login */

		close(master);
		if(login_tty(slave)) {
			syslog(LOG_ERR, "login_tty() failed: %m");
			return 1;
		}

		/* Fix terminal type and speed */
		
		tcgetattr(0, &tios);

		if((speed = strchr(term, '/'))) {
			*speed++ = '\0';
			cfsetispeed(&tios, atoi(speed));
			cfsetospeed(&tios, atoi(speed));
		}
		
		tcsetattr(0, TCSADRAIN, &tios);

		/* Create environment */

		asprintf(&envp[0], "TERM=%s", term);
		envp[1] = NULL;

		/* Spawn login process */
		
		execle("/bin/login", "login", "-p", "-h", host, "-f", pamuser, NULL, envp);

		syslog(LOG_ERR, "Failed to spawn login process: %m");
		return 1;
	}
}
Example #20
0
int main (int argc, char **argv)
{
#ifdef USE_PAM
    pam_handle_t *pamh = NULL;
    struct passwd *pampw;
    int retval;
#endif

    /*
     * Get my name so that I can use it to report errors.
     */

    Prog = Basename (argv[0]);

    setlocale (LC_ALL, "");
    bindtextdomain (PACKAGE, LOCALEDIR);
    textdomain (PACKAGE);

#ifdef USE_PAM
    retval = PAM_SUCCESS;

    pampw = getpwuid (getuid ());
    if (pampw == NULL) {
        retval = PAM_USER_UNKNOWN;
    }

    if (retval == PAM_SUCCESS) {
        retval =
            pam_start ("shadow", pampw->pw_name, &conv, &pamh);
    }

    if (retval == PAM_SUCCESS) {
        retval = pam_authenticate (pamh, 0);
        if (retval != PAM_SUCCESS) {
            pam_end (pamh, retval);
        }
    }

    if (retval == PAM_SUCCESS) {
        retval = pam_acct_mgmt (pamh, 0);
        if (retval != PAM_SUCCESS) {
            pam_end (pamh, retval);
        }
    }

    if (retval != PAM_SUCCESS) {
        fprintf (stderr, _("%s: PAM authentication failed\n"),
                 Prog);
        exit (1);
    }
#endif				/* USE_PAM */

    OPENLOG (Prog);

#ifdef SHADOWGRP
    is_shadow_grp = sgr_file_present ();
#endif

    /*
     * The open routines for the DBM files don't use read-write as the
     * mode, so we have to clue them in.
     */

#ifdef	NDBM
    gr_dbm_mode = O_RDWR;
#ifdef	SHADOWGRP
    sg_dbm_mode = O_RDWR;
#endif				/* SHADOWGRP */
#endif				/* NDBM */
    process_flags (argc, argv);

    /*
     * Start with a quick check to see if the group exists.
     */

    if (getgrnam (group_name)) {
        if (fflg) {
            exit (E_SUCCESS);
        }
        fprintf (stderr, _("%s: group %s exists\n"), Prog,
                 group_name);
        exit (E_NAME_IN_USE);
    }

    /*
     * Do the hard stuff - open the files, create the group entries,
     * then close and update the files.
     */

    open_files ();

    if (!gflg || !oflg)
        find_new_gid ();

    grp_update ();

    close_files ();

#ifdef USE_PAM
    if (retval == PAM_SUCCESS) {
        retval = pam_chauthtok (pamh, 0);
        if (retval != PAM_SUCCESS) {
            pam_end (pamh, retval);
        }
    }

    if (retval != PAM_SUCCESS) {
        fprintf (stderr, _("%s: PAM chauthtok failed\n"), Prog);
        exit (1);
    }

    if (retval == PAM_SUCCESS)
        pam_end (pamh, PAM_SUCCESS);
#endif				/* USE_PAM */
    exit (E_SUCCESS);
    /*NOTREACHED*/
}
Example #21
0
int main(int argc, char **argv) {
  hardened_shadow_openlog("su");

  if (!hardened_shadow_get_current_username(&current_username))
    errx(EXIT_FAILURE, "Cannot determine your user name.");

  parse_args(argc, argv);

  uid_t my_uid = getuid();
  bool is_root = (my_uid == 0);

  if (!is_root && (!isatty(STDIN_FILENO) || !ttyname(STDIN_FILENO)))
    errx(EXIT_FAILURE, "must be run from a terminal");

  const struct pam_conv pam_conversation = {
    misc_conv,
    NULL
  };
  pam_handle_t *pam_handle = NULL;
  int pam_rv = pam_start("su", target_username, &pam_conversation, &pam_handle);
  if (pam_rv != PAM_SUCCESS) {
    hardened_shadow_syslog(LOG_ERR, "pam_start: error %d", pam_rv);
    su_fatal();
  }

  pam_rv = pam_set_item(pam_handle, PAM_TTY, ttyname(STDIN_FILENO));
  if (pam_rv != PAM_SUCCESS) {
    hardened_shadow_syslog(LOG_ERR, "pam_set_item: %s",
                           pam_strerror(pam_handle, pam_rv));
    goto pam_cleanup;
  }

  pam_rv = pam_set_item(pam_handle, PAM_RUSER, current_username);
  if (pam_rv != PAM_SUCCESS) {
    hardened_shadow_syslog(LOG_ERR, "pam_set_item: %s",
                           pam_strerror(pam_handle, pam_rv));
    goto pam_cleanup;
  }

  pam_rv = pam_fail_delay(pam_handle, 1000000);
  if (pam_rv != PAM_SUCCESS) {
    hardened_shadow_syslog(LOG_ERR, "pam_fail_delay: %s",
                           pam_strerror(pam_handle, pam_rv));
    goto pam_cleanup;
  }

  pam_rv = pam_authenticate(pam_handle, 0);
  if (pam_rv != PAM_SUCCESS) {
    hardened_shadow_syslog(LOG_ERR, "pam_authenticate: %s",
                           pam_strerror(pam_handle, pam_rv));
    goto pam_cleanup;
  }

  pam_rv = pam_acct_mgmt(pam_handle, 0);
  if (pam_rv != PAM_SUCCESS) {
    if (is_root) {
      warnx("%s (ignored)", pam_strerror(pam_handle, pam_rv));
    } else if (pam_rv == PAM_NEW_AUTHTOK_REQD) {
      pam_rv = pam_chauthtok(pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
      if (pam_rv != PAM_SUCCESS) {
	hardened_shadow_syslog(LOG_ERR, "pam_chauthtok: %s",
                               pam_strerror(pam_handle, pam_rv));
        goto pam_cleanup;
      }
    } else {
      hardened_shadow_syslog(LOG_ERR, "pam_acct_mgmt: %s",
                             pam_strerror(pam_handle, pam_rv));
      goto pam_cleanup;
    }
  }

  if (setgid(target_gid) != 0) {
    hardened_shadow_syslog(LOG_ERR, "bad group ID `%d' for user `%s': %s",
                           target_gid, target_username, strerror(errno));
    pam_rv = PAM_ABORT;
    goto pam_cleanup;
  }
  if (initgroups(target_username, target_gid) != 0) {
    hardened_shadow_syslog(LOG_ERR, "initgroups failed for user `%s': %s",
                           target_username, strerror(errno));
    pam_rv = PAM_ABORT;
    goto pam_cleanup;
  }

  pam_rv = pam_setcred(pam_handle, PAM_ESTABLISH_CRED);
  if (pam_rv != PAM_SUCCESS) {
    hardened_shadow_syslog(LOG_ERR, "pam_setcred: %s",
                           pam_strerror(pam_handle, pam_rv));
    goto pam_cleanup;
  }

  pam_rv = pam_open_session(pam_handle, 0);
  if (pam_rv != PAM_SUCCESS) {
    hardened_shadow_syslog(LOG_ERR, "pam_open_session: %s",
                           pam_strerror(pam_handle, pam_rv));
    goto pam_cred_cleanup;
  }

  char **pam_env = pam_getenvlist(pam_handle);
  if (!pam_env)
    errx(EXIT_FAILURE, "pam_getenvlist returned NULL");

  struct environment_options environment_options = {
    .pam_environment = pam_env,
    .preserve_environment = preserve_environment,
    .login_shell = login_shell,
    .target_username = target_username,
    .target_homedir = target_homedir,
    .target_shell = shell,
  };
  if (!hardened_shadow_prepare_environment(&environment_options)) {
    pam_rv = PAM_ABORT;
    goto pam_session_cleanup;
  }

  if (setuid(target_uid) != 0) {
    hardened_shadow_syslog(LOG_ERR, "bad user ID `%d' for user `%s': %s",
                           target_uid, target_username, strerror(errno));
    goto pam_session_cleanup;
  }

  int shell_argc = command ? 4 : 2;
  char **shell_argv = calloc(shell_argc, sizeof(*shell_argv));
  if (!shell_argv) {
    hardened_shadow_syslog(LOG_ERR, "memory allocation failure");
    goto pam_session_cleanup;
  }
  /* When argv[0] starts with a dash ("-"), bash will recognize
   * it as a login shell. This is what shadow-utils does. */
  shell_argv[0] = login_shell ? "-su" : shell;
  if (command) {
    shell_argv[1] = "-c";
    shell_argv[2] = command;
  }
  shell_argv[shell_argc - 1] = NULL;
  int status;
  if (!run_shell(shell, shell_argv, &status)) {
    pam_rv = PAM_ABORT;
    goto pam_session_cleanup;
  }
  free(shell_argv);

  pam_rv = pam_setcred(pam_handle, PAM_DELETE_CRED);
  if (pam_rv != PAM_SUCCESS) {
    hardened_shadow_syslog(LOG_ERR, "pam_setcred: %s",
                           pam_strerror(pam_handle, pam_rv));
    pam_close_session(pam_handle, 0);
    pam_end(pam_handle, pam_rv);
    errx(EXIT_FAILURE, "pam_setcred");
  }

  pam_rv = pam_close_session(pam_handle, 0);
  if (pam_rv != PAM_SUCCESS) {
    hardened_shadow_syslog(LOG_ERR, "pam_close_session: %s",
                           pam_strerror(pam_handle, pam_rv));
    pam_end(pam_handle, pam_rv);
    errx(EXIT_FAILURE, "pam_close_session");
  }

  pam_end(pam_handle, pam_rv);

  free(shell);
  free(current_username);
  free(target_username);
  free(target_homedir);

  hardened_shadow_closelog();

  if (WIFEXITED(status))
    return WEXITSTATUS(status);

  return WTERMSIG(status) + 128;
pam_session_cleanup:
  pam_close_session(pam_handle, 0);
pam_cred_cleanup:
  pam_setcred(pam_handle, PAM_DELETE_CRED);
pam_cleanup:
  pam_end(pam_handle, pam_rv);
  su_fatal();
}
Example #22
0
gchar *
mdm_verify_user (MdmDisplay *d,
		 const char *username,
		 gboolean allow_retry)
{
	gint pamerr = 0;
	struct passwd *pwent = NULL;
	char *login, *passreq;
	char *pam_stack = NULL;
	MDM_PAM_QUAL void *p;
	int null_tok = 0;
	gboolean credentials_set = FALSE;
	gboolean error_msg_given = FALSE;
	gboolean started_timer   = FALSE;

    verify_user_again:

	pamerr = 0;
	login = NULL;
	error_msg_given = FALSE;
	credentials_set = FALSE;
	started_timer = FALSE;
	null_tok = 0;

	/* Don't start a timed login if we've already entered a username */
	if (username != NULL) {
		login = g_strdup (username);
		mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login);
	} else {
		/* start the timer for timed logins */
		if ( ! ve_string_empty (mdm_daemon_config_get_value_string (MDM_KEY_TIMED_LOGIN)) &&
		    d->timed_login_ok && (d->attached)) {
			mdm_slave_greeter_ctl_no_ret (MDM_STARTTIMER, "");
			started_timer = TRUE;
		}
	}

	cur_mdm_disp = d;

 authenticate_again:

	if (prev_user && !login) {
		login = g_strdup (prev_user);
	} else if (login && !prev_user) {
		prev_user = g_strdup (login);
		auth_retries = 0;
	} else if (login && prev_user && strcmp (login, prev_user)) {
		g_free (prev_user);
		prev_user = g_strdup (login);
		auth_retries = 0;
	}

	/*
	 * Initialize a PAM session for the user...
	 * Get value per-display so different displays can use different
	 * PAM Stacks, in case one display should use a different
	 * authentication mechanism than another display.
	 */
	pam_stack = mdm_daemon_config_get_value_string_per_display (MDM_KEY_PAM_STACK,
		(char *)d->name);

	if ( ! create_pamh (d, pam_stack, login, &pamc, d->name, &pamerr)) {
		if (started_timer)
			mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, "");
		g_free (pam_stack);
		goto pamerr;
	}

	g_free (pam_stack);

	/*
	 * have to unset login otherwise there is no chance to ever enter
	 * a different user
	 */
	g_free (login);
	login = NULL;

	pam_set_item (pamh, PAM_USER_PROMPT, _("Username:"******"PASSREQ=");

	if (mdm_daemon_config_get_value_bool (MDM_KEY_PASSWORD_REQUIRED) ||
            ((passreq != NULL) && g_ascii_strcasecmp (passreq, "YES") == 0))
		null_tok |= PAM_DISALLOW_NULL_AUTHTOK;

	mdm_verify_select_user (NULL);

	/* Start authentication session */
	did_we_ask_for_password = FALSE;
	if ((pamerr = pam_authenticate (pamh, null_tok)) != PAM_SUCCESS) {
		if ( ! ve_string_empty (selected_user)) {
			pam_handle_t *tmp_pamh;

			/* Face browser was used to select a user,
			   just completely rewhack everything since it
			   seems various PAM implementations are
			   having goats with just setting PAM_USER
			   and trying to pam_authenticate again */

			g_free (login);
			login = selected_user;
			selected_user = NULL;

			mdm_sigterm_block_push ();
			mdm_sigchld_block_push ();
			tmp_pamh = pamh;
			pamh     = NULL;
			mdm_sigchld_block_pop ();
			mdm_sigterm_block_pop ();

			/* FIXME: what about errors */
			/* really this has been a sucess, not a failure */
			pam_end (tmp_pamh, pamerr);

			g_free (prev_user);
			prev_user    = NULL;
			auth_retries = 0;

			mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login);

			goto authenticate_again;
		}

		if (started_timer)
			mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, "");

		if (mdm_slave_action_pending ()) {
			/* FIXME: see note above about PAM_FAIL_DELAY */
			/* #ifndef PAM_FAIL_DELAY */
			mdm_sleep_no_signal (mdm_daemon_config_get_value_int (MDM_KEY_RETRY_DELAY));
			/* wait up to 100ms randomly */
			usleep (g_random_int_range (0, 100000));
			/* #endif */ /* PAM_FAIL_DELAY */
			mdm_error ("Couldn't authenticate user");

			if (prev_user) {

				unsigned max_auth_retries = 3;
				char *val = mdm_read_default ("LOGIN_RETRIES=");

				if (val) {
					max_auth_retries = atoi (val);
					g_free (val);
				}

				if (allow_retry == FALSE || pamerr == PAM_MAXTRIES ||
				    ++auth_retries >= max_auth_retries) {

					g_free (prev_user);
					prev_user    = NULL;
					auth_retries = 0;
				}
			}
		} else {
			/* cancel, configurator etc pressed */
			g_free (prev_user);
			prev_user    = NULL;
			auth_retries = 0;
		}

		goto pamerr;
	}

	/* stop the timer for timed logins */
	if (started_timer)
		mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, "");

	g_free (login);
	login = NULL;
	g_free (prev_user);
	prev_user = NULL;

	if ((pamerr = pam_get_item (pamh, PAM_USER, &p)) != PAM_SUCCESS) {
		login = NULL;
		/* is not really an auth problem, but it will
		   pretty much look as such, it shouldn't really
		   happen */
		if (mdm_slave_action_pending ())
			mdm_error ("Couldn't authenticate user");
		goto pamerr;
	}

	login = g_strdup ((const char *)p);
	/* kind of anal, the greeter likely already knows, but it could have
	   been changed */
	mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login);

	if ( ! mdm_slave_check_user_wants_to_log_in (login)) {
		/* cleanup stuff */
		mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, "");
		g_free (login);
		login = NULL;
		mdm_slave_greeter_ctl_no_ret (MDM_RESETOK, "");

		mdm_verify_cleanup (d);

		goto verify_user_again;
	}

	/* Check if user is root and is allowed to log in */

	pwent = getpwnam (login);
	if (( ! mdm_daemon_config_get_value_bool (MDM_KEY_ALLOW_ROOT) ||
            ( ! d->attached )) &&
            (pwent != NULL && pwent->pw_uid == 0)) {
		mdm_error ("Root login disallowed on display '%s'", d->name);
		mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX,
					      _("\nThe system administrator "
						"is not allowed to login "
						"from this screen"));
		/*mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG,
		  _("Root login disallowed"));*/
		error_msg_given = TRUE;

		goto pamerr;
	}

	if (mdm_daemon_config_get_value_bool (MDM_KEY_DISPLAY_LAST_LOGIN)) {
		char *info = mdm_get_last_info (login);
		mdm_slave_greeter_ctl_no_ret (MDM_MSG, info);
		g_free (info);
	}

	/* Check if the user's account is healthy. */
	pamerr = pam_acct_mgmt (pamh, null_tok);
	switch (pamerr) {
	case PAM_SUCCESS :
		break;
	case PAM_NEW_AUTHTOK_REQD :
		if ((pamerr = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK)) != PAM_SUCCESS) {
			mdm_error ("Authentication token change failed for user %s", login);
			mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX,
						      _("\nThe change of the authentication token failed. "
							"Please try again later or contact the system administrator."));
			error_msg_given = TRUE;
			goto pamerr;
		}
		break;
	case PAM_ACCT_EXPIRED :
		mdm_error ("User %s no longer permitted to access the system", login);
		mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX,
					      _("\nThe system administrator has disabled your account."));
		error_msg_given = TRUE;
		goto pamerr;
	case PAM_PERM_DENIED :
		mdm_error ("User %s not permitted to gain access at this time", login);
		mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX,
					      _("\nThe system administrator has disabled access to the system temporarily."));
		error_msg_given = TRUE;
		goto pamerr;
	default :
		if (mdm_slave_action_pending ())
			mdm_error ("Couldn't set acct. mgmt for %s", login);
		goto pamerr;
	}

	pwent = getpwnam (login);
	if (/* paranoia */ pwent == NULL ||
	    ! mdm_setup_gids (login, pwent->pw_gid)) {
		mdm_error ("Cannot set user group for %s", login);
		mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX,
					      _("\nCannot set your user group; "
						"you will not be able to log in. "
						"Please contact your system administrator."));
		goto pamerr;
	}

	did_setcred = TRUE;

	/* Set credentials */
	pamerr = pam_setcred (pamh, PAM_ESTABLISH_CRED);
	if (pamerr != PAM_SUCCESS) {
		did_setcred = FALSE;
		if (mdm_slave_action_pending ())
			mdm_error ("Couldn't set credentials for %s", login);
		goto pamerr;
	}

	credentials_set = TRUE;
	opened_session  = TRUE;

	/* Register the session */
	pamerr = pam_open_session (pamh, 0);
	if (pamerr != PAM_SUCCESS) {
		opened_session = FALSE;
		/* we handle this above */
		did_setcred = FALSE;
		if (mdm_slave_action_pending ())
			mdm_error ("Couldn't open session for %s", login);
		goto pamerr;
	}

	/* Workaround to avoid mdm messages being logged as PAM_pwdb */
	mdm_log_shutdown ();
	mdm_log_init ();

	cur_mdm_disp = NULL;

	/*
	 * Login succeeded.
	 * This function is a no-op if libaudit is not present.
	 */
	log_to_audit_system(login, d->hostname, d->name, AU_SUCCESS);

	return login;

 pamerr:
	/*
	 * Take care of situation where we get here before setting pwent.
	 * Since login can be passed in as NULL, get the actual value if
	 * possible.
	 */
	if ((pam_get_item (pamh, PAM_USER, &p)) == PAM_SUCCESS) {
		g_free (login);
		login = g_strdup ((const char *)p);
	}
	if (pwent == NULL && login != NULL) {
		pwent = getpwnam (login);
	}

	/*
	 * Log the failed login attempt.
	 * This function is a no-op if libaudit is not present.
	 */
	log_to_audit_system(login, d->hostname, d->name, AU_FAILED);

	/* The verbose authentication is turned on, output the error
	 * message from the PAM subsystem */
	if ( ! error_msg_given &&
	     mdm_slave_action_pending ()) {
		mdm_slave_write_utmp_wtmp_record (d,
					MDM_SESSION_RECORD_TYPE_FAILED_ATTEMPT,
					login, getpid ());

		/*
		 * I'm not sure yet if I should display this message for any
		 * other issues - heeten
		 * Adding AUTHINFO_UNAVAIL to the list - its what an unknown
		 * user is.
		 */
		if (pamerr == PAM_AUTH_ERR ||
		    pamerr == PAM_USER_UNKNOWN ||
		    pamerr == PAM_AUTHINFO_UNAVAIL) {
			gboolean is_capslock = FALSE;
			const char *basemsg;
			char *msg;
			char *ret;

			ret = mdm_slave_greeter_ctl (MDM_QUERY_CAPSLOCK, "");
			if ( ! ve_string_empty (ret))
				is_capslock = TRUE;
			g_free (ret);

			/* Only give this message if we actually asked for
			   password, otherwise it would be silly to say that
			   the password may have been wrong */
			if (did_we_ask_for_password) {
				basemsg = _("\nIncorrect username or password.  "
					    "Letters must be typed in the correct "
					    "case.");
			} else {
				basemsg = _("\nAuthentication failed.  "
					    "Letters must be typed in the correct "
					    "case.");
			}
			if (is_capslock) {
				msg = g_strconcat (basemsg, "  ",
						   _("Caps Lock is on."),
						   NULL);
			} else {
				msg = g_strdup (basemsg);
			}
			mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, msg);
			g_free (msg);
		} else {
			mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG, _("Authentication failed"));
		}
	}

	did_setcred = FALSE;
	opened_session = FALSE;

	if (pamh != NULL) {
		pam_handle_t *tmp_pamh;
		mdm_sigterm_block_push ();
		mdm_sigchld_block_push ();
		tmp_pamh = pamh;
		pamh = NULL;
		mdm_sigchld_block_pop ();
		mdm_sigterm_block_pop ();

		/* Throw away the credentials */
		if (credentials_set)
			pam_setcred (tmp_pamh, PAM_DELETE_CRED);
		pam_end (tmp_pamh, pamerr);
	}
	pamh = NULL;

	/* Workaround to avoid mdm messages being logged as PAM_pwdb */
	mdm_log_shutdown ();
	mdm_log_init ();

	g_free (login);

	cur_mdm_disp = NULL;

	return NULL;
}
Example #23
0
int
main(int argc, char *argv[])
{
	char hostname[MAXHOSTNAMELEN];
	const char *user, *tty;
	const void *item;
	char **args, **pam_envlist, **pam_env;
	struct passwd *pwd;
	int o, pam_err, status;
	pid_t pid;

	while ((o = getopt(argc, argv, "")) != -1)
		switch (o) {
		default:
			usage();
		}

	argc -= optind;
	argv += optind;

	if (argc > 0) {
		user = *argv;
		--argc;
		++argv;
	} else {
		user = "******";
	}

	/* initialize PAM */
	pamc.conv = &openpam_ttyconv;
	pam_start("su", user, &pamc, &pamh);

	/* set some items */
	gethostname(hostname, sizeof(hostname));
	if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
		goto pamerr;
	user = getlogin();
	if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
		goto pamerr;
	tty = ttyname(STDERR_FILENO);
	if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
		goto pamerr;

	/* authenticate the applicant */
	if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
		goto pamerr;
	if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
		pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
	if (pam_err != PAM_SUCCESS)
		goto pamerr;

	/* establish the requested credentials */
	if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
		goto pamerr;

	/* authentication succeeded; open a session */
	if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
		goto pamerr;

	/* get mapped user name; PAM may have changed it */
	pam_err = pam_get_item(pamh, PAM_USER, &item);
	if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user = item)) == NULL)
		goto pamerr;

	/* export PAM environment */
	if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
		for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
			putenv(*pam_env);
			free(*pam_env);
		}
		free(pam_envlist);
	}

	/* build argument list */
	if ((args = calloc(argc + 2, sizeof *args)) == NULL) {
		warn("calloc()");
		goto err;
	}
	*args = pwd->pw_shell;
	memcpy(args + 1, argv, argc * sizeof *args);

	/* fork and exec */
	switch ((pid = fork())) {
	case -1:
		warn("fork()");
		goto err;
	case 0:
		/* child: give up privs and start a shell */

		/* set uid and groups */
		if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
			warn("initgroups()");
			_exit(1);
		}
		if (setgid(pwd->pw_gid) == -1) {
			warn("setgid()");
			_exit(1);
		}
		if (setuid(pwd->pw_uid) == -1) {
			warn("setuid()");
			_exit(1);
		}
		execve(*args, args, environ);
		warn("execve()");
		_exit(1);
	default:
		/* parent: wait for child to exit */
		waitpid(pid, &status, 0);

		/* close the session and release PAM resources */
		pam_err = pam_close_session(pamh, 0);
		pam_end(pamh, pam_err);

		exit(WEXITSTATUS(status));
	}

pamerr:
	fprintf(stderr, "Sorry\n");
err:
	pam_end(pamh, pam_err);
	exit(1);
}
Example #24
0
int
main(int argc, char **argv)
{
	char hostname[MAXHOSTNAMELEN];
	struct passwd *pwd = NULL;
	int o, pam_err;
	uid_t uid;

	while ((o = getopt(argc, argv, "d:h:loy")) != -1)
		switch (o) {
		case 'd':
			yp_domain = optarg;
			break;
		case 'h':
			yp_host = optarg;
			break;
		case 'l':
		case 'o':
		case 'y':
			/* compatibility */
			break;
		default:
			usage();
		}

	argc -= optind;
	argv += optind;

	uid = getuid();

	switch (argc) {
	case 0:
		if ((pwd = getpwuid(uid)) == NULL)
			errx(1, "who are you?");
		break;
	case 1:
		if ((pwd = getpwnam(*argv)) == NULL)
			errx(1, "%s: no such user", *argv);
		break;
	default:
		usage();
	}

	if (uid != 0 && uid != pwd->pw_uid)
		errx(1, "permission denied");

	/* check where the user's from */
	switch (pwd->pw_fields & _PWF_SOURCE) {
	case _PWF_FILES:
		fprintf(stderr, "Changing local password for %s\n",
		    pwd->pw_name);
		break;
	case _PWF_NIS:
		fprintf(stderr, "Changing NIS password for %s\n",
		    pwd->pw_name);
		break;
	default:
		fprintf(stderr, "Changing password for %s\n",
		    pwd->pw_name);
	}

#define pam_check(func) do { \
	if (pam_err != PAM_SUCCESS) { \
		if (pam_err == PAM_AUTH_ERR || pam_err == PAM_PERM_DENIED || \
		    pam_err == PAM_AUTHTOK_RECOVERY_ERR) \
			warnx("sorry"); \
		else \
			warnx("%s(): %s", func, pam_strerror(pamh, pam_err)); \
		goto end; \
	} \
} while (0)

	/* initialize PAM */
	pam_err = pam_start("passwd", pwd->pw_name, &pamc, &pamh);
	pam_check("pam_start");

	pam_err = pam_set_item(pamh, PAM_TTY, ttyname(STDERR_FILENO));
	pam_check("pam_set_item");
	gethostname(hostname, sizeof hostname);
	pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
	pam_check("pam_set_item");
	pam_err = pam_set_item(pamh, PAM_RUSER, getlogin());
	pam_check("pam_set_item");

	/* set YP domain and host */
	pam_err = pam_set_data(pamh, "yp_domain", yp_domain, NULL);
	pam_check("pam_set_data");
	pam_err = pam_set_data(pamh, "yp_server", yp_host, NULL);
	pam_check("pam_set_data");

	/* set new password */
	pam_err = pam_chauthtok(pamh, 0);
	pam_check("pam_chauthtok");

 end:
	pam_end(pamh, pam_err);
	exit(pam_err == PAM_SUCCESS ? 0 : 1);
}
Example #25
0
/*
 * Authentication thread.
 */
static void *
sshpam_thread(void *ctxtp)
{
	struct pam_ctxt *ctxt = ctxtp;
	Buffer buffer;
	struct pam_conv sshpam_conv;
	int flags = (options.permit_empty_passwd == 0 ?
	    PAM_DISALLOW_NULL_AUTHTOK : 0);
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
	extern char **environ;
	char **env_from_pam;
	u_int i;
	const char *pam_user;
	const char **ptr_pam_user = &pam_user;
	char *tz = getenv("TZ");

	sshpam_err = pam_get_item(sshpam_handle, PAM_USER,
	    (sshpam_const void **)ptr_pam_user);
	if (sshpam_err != PAM_SUCCESS)
		goto auth_fail;

	environ[0] = NULL;
	if (tz != NULL)
		if (setenv("TZ", tz, 1) == -1)
			error("PAM: could not set TZ environment: %s",
			    strerror(errno));

	if (sshpam_authctxt != NULL) {
		setproctitle("%s [pam]",
		    sshpam_authctxt->valid ? pam_user : "******");
	}
#endif

	sshpam_conv.conv = sshpam_thread_conv;
	sshpam_conv.appdata_ptr = ctxt;

	if (sshpam_authctxt == NULL)
		fatal("%s: PAM authctxt not initialized", __func__);

	buffer_init(&buffer);
	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
	    (const void *)&sshpam_conv);
	if (sshpam_err != PAM_SUCCESS)
		goto auth_fail;
	sshpam_err = pam_authenticate(sshpam_handle, flags);
	if (sshpam_err != PAM_SUCCESS)
		goto auth_fail;

	if (compat20) {
		if (!do_pam_account()) {
			sshpam_err = PAM_ACCT_EXPIRED;
			goto auth_fail;
		}
		if (sshpam_authctxt->force_pwchange) {
			sshpam_err = pam_chauthtok(sshpam_handle,
			    PAM_CHANGE_EXPIRED_AUTHTOK);
			if (sshpam_err != PAM_SUCCESS)
				goto auth_fail;
			sshpam_password_change_required(0);
		}
	}

	buffer_put_cstring(&buffer, "OK");

#ifndef UNSUPPORTED_POSIX_THREADS_HACK
	/* Export variables set by do_pam_account */
	buffer_put_int(&buffer, sshpam_account_status);
	buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);

	/* Export any environment strings set in child */
	for(i = 0; environ[i] != NULL; i++)
		; /* Count */
	buffer_put_int(&buffer, i);
	for(i = 0; environ[i] != NULL; i++)
		buffer_put_cstring(&buffer, environ[i]);

	/* Export any environment strings set by PAM in child */
	env_from_pam = pam_getenvlist(sshpam_handle);
	for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
		; /* Count */
	buffer_put_int(&buffer, i);
	for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
		buffer_put_cstring(&buffer, env_from_pam[i]);
#endif /* UNSUPPORTED_POSIX_THREADS_HACK */

	/* XXX - can't do much about an error here */
	ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
	buffer_free(&buffer);
	pthread_exit(NULL);

 auth_fail:
	buffer_put_cstring(&buffer,
	    pam_strerror(sshpam_handle, sshpam_err));
	/* XXX - can't do much about an error here */
	if (sshpam_err == PAM_ACCT_EXPIRED)
		ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, &buffer);
	else
		ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
	buffer_free(&buffer);
	pthread_exit(NULL);

	return (NULL); /* Avoid warning for non-pthread case */
}
Example #26
0
File: blank.c Project: aosm/pam
int main(int argc, char **argv)
{
     pam_handle_t *pamh=NULL;
     char *username=NULL;
     int retcode;

     /* did the user call with a username as an argument ? */

     if (argc > 2) {
	  fprintf(stderr,"usage: %s [username]\n",argv[0]);
     } else if (argc == 2) {
	  username = argv[1];
     } 

     /* initialize the Linux-PAM library */
     retcode = pam_start("blank", username, &conv, &pamh);
     bail_out(pamh,1,retcode,"pam_start");

     /* test the environment stuff */
     {
#define MAXENV 15
	 const char *greek[MAXENV] = {
	     "a=alpha", "b=beta", "c=gamma", "d=delta", "e=epsilon",
	     "f=phi", "g=psi", "h=eta", "i=iota", "j=mu", "k=nu",
	     "l=zeta", "h=", "d", "k=xi"
	 };
	 char **env;
	 int i;

	 for (i=0; i<MAXENV; ++i) {
	     retcode = pam_putenv(pamh,greek[i]);
	     bail_out(pamh,0,retcode,"pam_putenv");
	 }
	 env = pam_getenvlist(pamh);
	 if (env)
	     env = pam_misc_drop_env(env);
	 else
	     fprintf(stderr,"???\n");
	 fprintf(stderr,"a test: c=[%s], j=[%s]\n"
		 , pam_getenv(pamh, "c"), pam_getenv(pamh, "j"));
     }

     /* to avoid using goto we abuse a loop here */
     for (;;) {
	  /* authenticate the user --- `0' here, could have been PAM_SILENT
	   *	| PAM_DISALLOW_NULL_AUTHTOK */

	  retcode = pam_authenticate(pamh, 0);
	  bail_out(pamh,0,retcode,"pam_authenticate");

	  /* has the user proved themself valid? */
	  if (retcode != PAM_SUCCESS) {
	       fprintf(stderr,"%s: invalid request\n",argv[0]);
	       break;
	  }

	  /* the user is valid, but should they have access at this
	     time? */

	  retcode = pam_acct_mgmt(pamh, 0); /* `0' could be as above */
	  bail_out(pamh,0,retcode,"pam_acct_mgmt");

	  if (retcode == PAM_NEW_AUTHTOK_REQD) {
	       fprintf(stderr,"Application must request new password...\n");
	       retcode = pam_chauthtok(pamh,PAM_CHANGE_EXPIRED_AUTHTOK);
	       bail_out(pamh,0,retcode,"pam_chauthtok");
	  }

	  if (retcode != PAM_SUCCESS) {
	       fprintf(stderr,"%s: invalid request\n",argv[0]);
	       break;
	  }

	  /* `0' could be as above */
	  retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
	  bail_out(pamh,0,retcode,"pam_setcred1");

	  if (retcode != PAM_SUCCESS) {
	       fprintf(stderr,"%s: problem setting user credentials\n"
		       ,argv[0]);
	       break;
	  }

	  /* open a session for the user --- `0' could be PAM_SILENT */
	  retcode = pam_open_session(pamh,0);
	  bail_out(pamh,0,retcode,"pam_open_session");
	  if (retcode != PAM_SUCCESS) {
	       fprintf(stderr,"%s: problem opening a session\n",argv[0]);
	       break;
	  }

	  fprintf(stderr,"The user has been authenticated and `logged in'\n");

	  /* close a session for the user --- `0' could be PAM_SILENT
	   * it is possible that this pam_close_call is in another program..
	   */

	  retcode = pam_close_session(pamh,0);
	  bail_out(pamh,0,retcode,"pam_close_session");
	  if (retcode != PAM_SUCCESS) {
	       fprintf(stderr,"%s: problem closing a session\n",argv[0]);
	       break;
	  }
	  
	  retcode = pam_setcred(pamh, PAM_DELETE_CRED);
	  bail_out(pamh,0,retcode,"pam_setcred2");

	  break;                      /* don't go on for ever! */
     }

     /* close the Linux-PAM library */
     retcode = pam_end(pamh, PAM_SUCCESS);
     pamh = NULL;

     bail_out(pamh,1,retcode,"pam_end");

     exit(0);
}
Example #27
0
void
pwpam_process(const char *username, int argc, char **argv)
{
	int ch, pam_err;
	char hostname[MAXHOSTNAMELEN + 1];

	/* details about the invoking user for logging */
	const uid_t i_uid = getuid();
	const struct passwd *const i_pwd = getpwuid(i_uid);
	const char *const i_username = (i_pwd && i_pwd->pw_name)
		? i_pwd->pw_name : "(null)";

	while ((ch = getopt(argc, argv, "")) != -1) {
		switch (ch) {
		default:
			usage();
			/* NOTREACHED */
		}
	}

	argc -= optind;
	argv += optind;

	switch (argc) {
	case 0:
		/* username already provided */
		break;
	case 1:
		username = argv[0];
		break;
	default:
		usage();
		/* NOTREACHED */
	}

	(void)printf("Changing password for %s.\n", username);

	/* initialize PAM -- always use the program name "passwd" */
	pam_err = pam_start("passwd", username, &pamc, &pamh);
	if (pam_err != PAM_SUCCESS)
		errx(1, "unable to start PAM session: %s",
		    pam_strerror(NULL, pam_err));

	pam_err = pam_set_item(pamh, PAM_TTY, ttyname(STDERR_FILENO));
	pam_check("unable to set TTY");

	(void)gethostname(hostname, sizeof hostname);
	pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
	pam_check("unable to set RHOST");

	pam_err = pam_set_item(pamh, PAM_RUSER, getlogin());
	pam_check("unable to set RUSER");

	/* set new password */
	pam_err = pam_chauthtok(pamh, 0);
	if (pam_err != PAM_SUCCESS) {
		if (pam_err == PAM_PERM_DENIED) {
			syslog(LOG_AUTH | LOG_NOTICE,
			       "user %s (UID %lu) failed to change the "
			       "PAM authentication token of user %s: %s",
			       i_username, (unsigned long)i_uid, username,
			       pam_strerror(pamh, pam_err));
		}
		printf("Unable to change auth token: %s\n",
		    pam_strerror(pamh, pam_err));
	} else {
		syslog(LOG_AUTH | LOG_INFO,
		       "user %s (UID %lu) successfully changed the "
		       "PAM authentication token of user %s",
		       i_username, (unsigned long)i_uid, username);
	}

 end:
	pam_end(pamh, pam_err);
	if (pam_err == PAM_SUCCESS)
		return;
	exit(1);
}
Example #28
0
gboolean
mdm_verify_setup_user (MdmDisplay *d, const gchar *login, char **new_login)
{
	gint pamerr = 0;
	struct passwd *pwent = NULL;
	MDM_PAM_QUAL void *p;
	char *passreq;
	char *pam_stack = NULL;
	char *pam_service_name = NULL;
	int null_tok = 0;
	gboolean credentials_set;
	const char *after_login;

	credentials_set = FALSE;

	*new_login = NULL;

	if (login == NULL)
		return FALSE;

	cur_mdm_disp = d;

	g_free (extra_standalone_message);
	extra_standalone_message = g_strdup_printf ("%s (%s)",
						    _("Automatic login"),
						    login);

	/*
	 * Initialize a PAM session for the user...
	 * Get value per-display so different displays can use different
	 * PAM Stacks, in case one display should use a different
	 * authentication mechanism than another display.
	 */
	pam_stack = mdm_daemon_config_get_value_string_per_display (MDM_KEY_PAM_STACK,
		(char *)d->name);
	pam_service_name = g_strdup_printf ("%s-autologin", pam_stack);

	if ( ! create_pamh (d, pam_service_name, login, &standalone_pamc,
			    d->name, &pamerr)) {
		g_free (pam_stack);
		g_free (pam_service_name);
		goto setup_pamerr;
	}
	g_free (pam_stack);
	g_free (pam_service_name);

	passreq = mdm_read_default ("PASSREQ=");

	if (mdm_daemon_config_get_value_bool (MDM_KEY_PASSWORD_REQUIRED) ||
            ((passreq != NULL) && g_ascii_strcasecmp (passreq, "YES") == 0))
		null_tok |= PAM_DISALLOW_NULL_AUTHTOK;

	/* Start authentication session */
	did_we_ask_for_password = FALSE;
	if ((pamerr = pam_authenticate (pamh, null_tok)) != PAM_SUCCESS) {
		if (mdm_slave_action_pending ()) {
			mdm_error ("Couldn't authenticate user");
			mdm_errorgui_error_box (cur_mdm_disp,
						GTK_MESSAGE_ERROR,
						_("Authentication failed"));
		}
		goto setup_pamerr;
	}

	if ((pamerr = pam_get_item (pamh, PAM_USER, &p)) != PAM_SUCCESS) {
		/* is not really an auth problem, but it will
		   pretty much look as such, it shouldn't really
		   happen */
		mdm_error ("Couldn't authenticate user");
		mdm_errorgui_error_box (cur_mdm_disp,
					GTK_MESSAGE_ERROR,
					_("Authentication failed"));
		goto setup_pamerr;
	}
	after_login = p;

	if (after_login != NULL /* should never be */ &&
	    strcmp (after_login, login) != 0) {
		*new_login = g_strdup (after_login);
	}

	/* Check if the user's account is healthy. */
	pamerr = pam_acct_mgmt (pamh, null_tok);
	switch (pamerr) {
	case PAM_SUCCESS :
		break;
	case PAM_NEW_AUTHTOK_REQD :
		/* XXX: this is for automatic and timed logins,
		 * we shouldn't be asking for new pw since we never
		 * authenticated the user.  I suppose just ignoring
		 * this would be OK */
#if	0	/* don't change password */
		if ((pamerr = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK)) != PAM_SUCCESS) {
			mdm_error ("Authentication token change failed for user %s", login);
			mdm_errorgui_error_box (cur_mdm_disp,
						GTK_MESSAGE_ERROR,
						_("\nThe change of the authentication token failed. "
						  "Please try again later or contact the system administrator."));

			goto setup_pamerr;
		}

#endif	/* 0 */
		break;
	case PAM_ACCT_EXPIRED :
		mdm_error ("User %s no longer permitted to access the system", login);
		mdm_errorgui_error_box (cur_mdm_disp,
					GTK_MESSAGE_ERROR,
					_("The system administrator has disabled your account."));
		goto setup_pamerr;
	case PAM_PERM_DENIED :
		mdm_error ("User %s not permitted to gain access at this time", login);
		mdm_errorgui_error_box (cur_mdm_disp,
					GTK_MESSAGE_ERROR,
					_("The system administrator has disabled your access to the system temporarily."));
		goto setup_pamerr;
	default :
		if (mdm_slave_action_pending ())
			mdm_error ("Couldn't set acct. mgmt for %s", login);
		goto setup_pamerr;
	}

	pwent = getpwnam (login);
	if (/* paranoia */ pwent == NULL ||
	    ! mdm_setup_gids (login, pwent->pw_gid)) {
		mdm_error ("Cannot set user group for %s", login);
		mdm_errorgui_error_box (cur_mdm_disp,
					GTK_MESSAGE_ERROR,
					_("Cannot set your user group; "
					  "you will not be able to log in. "
					  "Please contact your system administrator."));

		goto setup_pamerr;
	}

	did_setcred = TRUE;

	/* Set credentials */
	pamerr = pam_setcred (pamh, PAM_ESTABLISH_CRED);
	if (pamerr != PAM_SUCCESS) {
		did_setcred = FALSE;
		if (mdm_slave_action_pending ())
			mdm_error ("Couldn't set credentials for %s", login);
		goto setup_pamerr;
	}

	credentials_set = TRUE;
	opened_session  = TRUE;

	/* Register the session */
	pamerr = pam_open_session (pamh, 0);
	if (pamerr != PAM_SUCCESS) {
		did_setcred = FALSE;
		opened_session = FALSE;
		/* Throw away the credentials */
		pam_setcred (pamh, PAM_DELETE_CRED);

		if (mdm_slave_action_pending ())
			mdm_error ("Couldn't open session for %s", login);
		goto setup_pamerr;
	}

	/* Workaround to avoid mdm messages being logged as PAM_pwdb */
	mdm_log_shutdown ();
	mdm_log_init ();

	cur_mdm_disp = NULL;

	g_free (extra_standalone_message);
	extra_standalone_message = NULL;

	/*
	 * Login succeeded.
	 * This function is a no-op if libaudit is not present
	 */
	log_to_audit_system(login, d->hostname, d->name, AU_SUCCESS);

	return TRUE;

 setup_pamerr:
	/*
	 * Take care of situation where we get here before setting pwent.
	 * Note login is never NULL when this function is called.
	 */
	if (pwent == NULL) {
		pwent = getpwnam (login);
	}

	/*
	 * Log the failed login attempt.
	 * This function is a no-op if libaudit is not present
	 */
	log_to_audit_system(login, d->hostname, d->name, AU_FAILED);

	did_setcred = FALSE;
	opened_session = FALSE;
	if (pamh != NULL) {
		pam_handle_t *tmp_pamh;

		mdm_sigterm_block_push ();
		mdm_sigchld_block_push ();
		tmp_pamh = pamh;
		pamh = NULL;
		mdm_sigchld_block_pop ();
		mdm_sigterm_block_pop ();

		/* Throw away the credentials */
		if (credentials_set)
			pam_setcred (tmp_pamh, PAM_DELETE_CRED);
		pam_end (tmp_pamh, pamerr);
	}
	pamh = NULL;

	/* Workaround to avoid mdm messages being logged as PAM_pwdb */
	mdm_log_shutdown ();
	mdm_log_init ();

	cur_mdm_disp = NULL;

	g_free (extra_standalone_message);
	extra_standalone_message = NULL;

	return FALSE;
}
Example #29
0
int
main (int argc, char *argv[])
{
        int             retcode;
        int             ret;
        pam_handle_t   *pamh;
        char           *username;
        char           *hostname;
        char           *tty_name;
        char           *ttyn;
        struct pam_conv conv = { misc_conv, NULL };
        int             failcount;

        ret = 1;
        username = NULL;
        hostname = NULL;
        tty_name = NULL;

        retcode = pam_start ("login", username, &conv, &pamh);
        if (retcode != PAM_SUCCESS) {
                fprintf (stderr, "login: PAM Failure, aborting: %s\n",
                         pam_strerror (pamh, retcode));
                exit (99);
        }

        ttyn = ttyname (0);

        if (strncmp (ttyn, _PATH_DEV, 5) == 0) {
                tty_name = ttyn + 5;
        } else {
                tty_name = ttyn;
        }

        retcode = pam_set_item (pamh, PAM_RHOST, hostname);
        PAM_FAIL_CHECK;
        retcode = pam_set_item (pamh, PAM_TTY, tty_name);
        PAM_FAIL_CHECK;
        pam_set_item (pamh, PAM_USER, NULL);

        retcode = pam_set_item (pamh, PAM_USER_PROMPT, "Username: "******"Login incorrect\n\n");
                pam_set_item (pamh, PAM_USER, NULL);
                retcode = pam_authenticate (pamh, 0);
        }

        if (retcode != PAM_SUCCESS) {
                fprintf (stderr, "\nLogin incorrect\n");
                pam_end (pamh, retcode);
                exit (0);
        }

        retcode = pam_acct_mgmt (pamh, 0);
        if (retcode == PAM_NEW_AUTHTOK_REQD) {
                retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
        }

        PAM_FAIL_CHECK;

        pam_putenv (pamh, "CKCON_TTY=/dev/tty55");
        pam_putenv (pamh, "CKCON_X11_DISPLAY=:50");

        retcode = pam_open_session (pamh, 0);
        PAM_FAIL_CHECK;

        retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
        PAM_FAIL_CHECK;

        pam_get_item (pamh, PAM_USER, (const void **) &username);

        printf ("Session opened for %s\n", username);

        printf ("sleeping for 20 seconds...");
        sleep (20);

        PAM_END;

        printf ("\nSession closed\n");

        return ret;
}
Example #30
0
/*
 * login - create a new login session for a user
 *
 *	login is typically called by getty as the second step of a
 *	new user session. getty is responsible for setting the line
 *	characteristics to a reasonable set of values and getting
 *	the name of the user to be logged in. login may also be
 *	called to create a new user session on a pty for a variety
 *	of reasons, such as X servers or network logins.
 *
 *	the flags which login supports are
 *	
 *	-p - preserve the environment
 *	-r - perform autologin protocol for rlogin
 *	-f - do not perform authentication, user is preauthenticated
 *	-h - the name of the remote host
 */
int main (int argc, char **argv)
{
	const char *tmptty;
	char tty[BUFSIZ];

#ifdef RLOGIN
	char term[128] = "";
#endif				/* RLOGIN */
#if defined(HAVE_STRFTIME) && !defined(USE_PAM)
	char ptime[80];
#endif
	unsigned int delay;
	unsigned int retries;
	bool failed;
	bool subroot = false;
#ifndef USE_PAM
	bool is_console;
#endif
	int err;
	const char *cp;
	char *tmp;
	char fromhost[512];
	struct passwd *pwd = NULL;
	char **envp = environ;
	const char *failent_user;
	/*@null@*/struct utmp *utent;

#ifdef USE_PAM
	int retcode;
	pid_t child;
	char *pam_user = NULL;
#else
	struct spwd *spwd = NULL;
#endif
	/*
	 * Some quick initialization.
	 */

	sanitize_env ();

	(void) setlocale (LC_ALL, "");
	(void) bindtextdomain (PACKAGE, LOCALEDIR);
	(void) textdomain (PACKAGE);

	initenv ();

	amroot = (getuid () == 0);
	Prog = Basename (argv[0]);

	if (geteuid() != 0) {
		fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog);
		exit (1);
	}

	process_flags (argc, argv);

	if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
		exit (1);	/* must be a terminal */
	}

	utent = get_current_utmp ();
	/*
	 * Be picky if run by normal users (possible if installed setuid
	 * root), but not if run by root. This way it still allows logins
	 * even if your getty is broken, or if something corrupts utmp,
	 * but users must "exec login" which will use the existing utmp
	 * entry (will not overwrite remote hostname).  --marekm
	 */
	if (!amroot && (NULL == utent)) {
		(void) puts (_("No utmp entry.  You must exec \"login\" from the lowest level \"sh\""));
		exit (1);
	}
	/* NOTE: utent might be NULL afterwards */

	tmptty = ttyname (0);
	if (NULL == tmptty) {
		tmptty = "UNKNOWN";
	}
	STRFCPY (tty, tmptty);

#ifndef USE_PAM
	is_console = console (tty);
#endif

	if (rflg || hflg) {
		/*
		 * Add remote hostname to the environment. I think
		 * (not sure) I saw it once on Irix.  --marekm
		 */
		addenv ("REMOTEHOST", hostname);
	}
	if (fflg) {
		preauth_flag = true;
	}
	if (hflg) {
		reason = PW_RLOGIN;
	}
#ifdef RLOGIN
	if (rflg) {
		assert (NULL == username);
		username = xmalloc (USER_NAME_MAX_LENGTH + 1);
		username[USER_NAME_MAX_LENGTH] = '\0';
		if (do_rlogin (hostname, username, USER_NAME_MAX_LENGTH, term, sizeof term)) {
			preauth_flag = true;
		} else {
			free (username);
			username = NULL;
		}
	}
#endif				/* RLOGIN */

	OPENLOG ("login");

	setup_tty ();

#ifndef USE_PAM
	(void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));

	{
		/* 
		 * Use the ULIMIT in the login.defs file, and if
		 * there isn't one, use the default value. The
		 * user may have one for themselves, but otherwise,
		 * just take what you get.
		 */
		long limit = getdef_long ("ULIMIT", -1L);

		if (limit != -1) {
			set_filesize_limit (limit);
		}
	}

#endif
	/*
	 * The entire environment will be preserved if the -p flag
	 * is used.
	 */
	if (pflg) {
		while (NULL != *envp) {	/* add inherited environment, */
			addenv (*envp, NULL); /* some variables change later */
			envp++;
		}
	}

#ifdef RLOGIN
	if (term[0] != '\0') {
		addenv ("TERM", term);
	} else
#endif				/* RLOGIN */
	{
		/* preserve TERM from getty */
		if (!pflg) {
			tmp = getenv ("TERM");
			if (NULL != tmp) {
				addenv ("TERM", tmp);
			}
		}
	}

	init_env ();

	if (optind < argc) {	/* now set command line variables */
		set_env (argc - optind, &argv[optind]);
	}

	if (rflg || hflg) {
		cp = hostname;
#ifdef	HAVE_STRUCT_UTMP_UT_HOST
	} else if ((NULL != utent) && ('\0' != utent->ut_host[0])) {
		cp = utent->ut_host;
#endif				/* HAVE_STRUCT_UTMP_UT_HOST */
	} else {
		cp = "";
	}

	if ('\0' != *cp) {
		snprintf (fromhost, sizeof fromhost,
		          " on '%.100s' from '%.200s'", tty, cp);
	} else {
		snprintf (fromhost, sizeof fromhost,
		          " on '%.100s'", tty);
	}

      top:
	/* only allow ALARM sec. for login */
	(void) signal (SIGALRM, alarm_handler);
	timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM);
	if (timeout > 0) {
		(void) alarm (timeout);
	}

	environ = newenvp;	/* make new environment active */
	delay   = getdef_unum ("FAIL_DELAY", 1);
	retries = getdef_unum ("LOGIN_RETRIES", RETRIES);

#ifdef USE_PAM
	retcode = pam_start ("login", username, &conv, &pamh);
	if (retcode != PAM_SUCCESS) {
		fprintf (stderr,
		         _("login: PAM Failure, aborting: %s\n"),
		         pam_strerror (pamh, retcode));
		SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
		         pam_strerror (pamh, retcode)));
		exit (99);
	}

	/*
	 * hostname & tty are either set to NULL or their correct values,
	 * depending on how much we know. We also set PAM's fail delay to
	 * ours.
	 *
	 * PAM_RHOST and PAM_TTY are used for authentication, only use
	 * information coming from login or from the caller (e.g. no utmp)
	 */
	retcode = pam_set_item (pamh, PAM_RHOST, hostname);
	PAM_FAIL_CHECK;
	retcode = pam_set_item (pamh, PAM_TTY, tty);
	PAM_FAIL_CHECK;
#ifdef HAS_PAM_FAIL_DELAY
	retcode = pam_fail_delay (pamh, 1000000 * delay);
	PAM_FAIL_CHECK;
#endif
	/* if fflg, then the user has already been authenticated */
	if (!fflg) {
		unsigned int failcount = 0;
		char hostn[256];
		char loginprompt[256];	/* That's one hell of a prompt :) */

		/* Make the login prompt look like we want it */
		if (gethostname (hostn, sizeof (hostn)) == 0) {
			snprintf (loginprompt,
			          sizeof (loginprompt),
			          _("%s login: "******"login: "******"TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
				         failcount, fromhost, failent_user));
				fprintf(stderr,
				        _("Maximum number of tries exceeded (%u)\n"),
				        failcount);
				PAM_END;
				exit(0);
			} else if (retcode == PAM_ABORT) {
				/* Serious problems, quit now */
				(void) fputs (_("login: abort requested by PAM\n"), stderr);
				SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
				PAM_END;
				exit(99);
			} else if (retcode != PAM_SUCCESS) {
				SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%u)%s FOR '%s', %s",
				         failcount, fromhost, failent_user,
				         pam_strerror (pamh, retcode)));
				failed = true;
			}

			if (!failed) {
				break;
			}

#ifdef WITH_AUDIT
			audit_fd = audit_open ();
			audit_log_acct_message (audit_fd,
			                        AUDIT_USER_LOGIN,
			                        NULL,    /* Prog. name */
			                        "login",
			                        failent_user,
			                        AUDIT_NO_ID,
			                        hostname,
			                        NULL,    /* addr */
			                        tty,
			                        0);      /* result */
			close (audit_fd);
#endif				/* WITH_AUDIT */

			(void) puts ("");
			(void) puts (_("Login incorrect"));

			if (failcount >= retries) {
				SYSLOG ((LOG_NOTICE,
				         "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
				         failcount, fromhost, failent_user));
				fprintf(stderr,
				        _("Maximum number of tries exceeded (%u)\n"),
				        failcount);
				PAM_END;
				exit(0);
			}

			/*
			 * Let's give it another go around.
			 * Even if a username was given on the command
			 * line, prompt again for the username.
			 */
			retcode = pam_set_item (pamh, PAM_USER, NULL);
			PAM_FAIL_CHECK;
		}

		/* We don't get here unless they were authenticated above */
		(void) alarm (0);
	}

	/* Check the account validity */
	retcode = pam_acct_mgmt (pamh, 0);
	if (retcode == PAM_NEW_AUTHTOK_REQD) {
		retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
	}
	PAM_FAIL_CHECK;

	/* Open the PAM session */
	get_pam_user (&pam_user);
	retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0);
	PAM_FAIL_CHECK;

	/* Grab the user information out of the password file for future usage
	 * First get the username that we are actually using, though.
	 *
	 * From now on, we will discard changes of the user (PAM_USER) by
	 * PAM APIs.
	 */
	get_pam_user (&pam_user);
	if (NULL != username) {
		free (username);
	}
	username = pam_user;
	failent_user = get_failent_user (username);

	pwd = xgetpwnam (username);
	if (NULL == pwd) {
		SYSLOG ((LOG_ERR, "cannot find user %s", failent_user));
		exit (1);
	}

	/* This set up the process credential (group) and initialize the
	 * supplementary group access list.
	 * This has to be done before pam_setcred
	 */
	if (setup_groups (pwd) != 0) {
		exit (1);
	}

	retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
	PAM_FAIL_CHECK;
	/* NOTE: If pam_setcred changes PAM_USER, this will not be taken
	 * into account.
	 */

#else				/* ! USE_PAM */
	while (true) {	/* repeatedly get login/password pairs */
		/* user_passwd is always a pointer to this constant string
		 * or a passwd or shadow password that will be memzero by
		 * pw_free / spw_free.
		 * Do not free() user_passwd. */
		const char *user_passwd = "!";

		/* Do some cleanup to avoid keeping entries we do not need
		 * anymore. */
		if (NULL != pwd) {
			pw_free (pwd);
			pwd = NULL;
		}
		if (NULL != spwd) {
			spw_free (spwd);
			spwd = NULL;
		}

		failed = false;	/* haven't failed authentication yet */
		if (NULL == username) {	/* need to get a login id */
			if (subroot) {
				closelog ();
				exit (1);
			}
			preauth_flag = false;
			username = xmalloc (USER_NAME_MAX_LENGTH + 1);
			username[USER_NAME_MAX_LENGTH] = '\0';
			login_prompt (_("\n%s login: "******"!",
			 * the account is locked and the user cannot
			 * login, even if they have been
			 * "pre-authenticated."
			 */
			if (   ('!' == user_passwd[0])
			    || ('*' == user_passwd[0])) {
				failed = true;
			}
		}

		if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) {
			spwd = xgetspnam (username);
			if (NULL != spwd) {
				user_passwd = spwd->sp_pwdp;
			} else {
				/* The user exists in passwd, but not in
				 * shadow. SHADOW_PASSWD_STRING indicates
				 * that the password shall be in shadow.
				 */
				SYSLOG ((LOG_WARN,
				         "no shadow password for '%s'%s",
				         username, fromhost));
			}
		}

		/*
		 * The -r and -f flags provide a name which has already
		 * been authenticated by some server.
		 */
		if (preauth_flag) {
			goto auth_ok;
		}

		if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) {
			goto auth_ok;
		}

		SYSLOG ((LOG_WARN, "invalid password for '%s' %s",
		         failent_user, fromhost));
		failed = true;

	      auth_ok:
		/*
		 * This is the point where all authenticated users wind up.
		 * If you reach this far, your password has been
		 * authenticated and so on.
		 */
		if (   !failed
		    && (NULL != pwd)
		    && (0 == pwd->pw_uid)
		    && !is_console) {
			SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
			failed = true;
		}
		if (   !failed
		    && !login_access (username, ('\0' != *hostname) ? hostname : tty)) {
			SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s",
			         username, fromhost));
			failed = true;
		}
		if (   (NULL != pwd)
		    && getdef_bool ("FAILLOG_ENAB")
		    && !failcheck (pwd->pw_uid, &faillog, failed)) {
			SYSLOG ((LOG_CRIT,
			         "exceeded failure limit for '%s' %s",
			         username, fromhost));
			failed = true;
		}
		if (!failed) {
			break;
		}

		/* don't log non-existent users */
		if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) {
			failure (pwd->pw_uid, tty, &faillog);
		}
		if (getdef_str ("FTMP_FILE") != NULL) {
#ifdef USE_UTMPX
			struct utmpx *failent =
				prepare_utmpx (failent_user,
				               tty,
			/* FIXME: or fromhost? */hostname,
				               utent);
#else				/* !USE_UTMPX */
			struct utmp *failent =
				prepare_utmp (failent_user,
				              tty,
				              hostname,
				              utent);
#endif				/* !USE_UTMPX */
			failtmp (failent_user, failent);
			free (failent);
		}

		retries--;
		if (retries <= 0) {
			SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
			         fromhost));
		}

		/*
		 * If this was a passwordless account and we get here, login
		 * was denied (securetty, faillog, etc.). There was no
		 * password prompt, so do it now (will always fail - the bad
		 * guys won't see that the passwordless account exists at
		 * all).  --marekm
		 */
		if (user_passwd[0] == '\0') {
			pw_auth ("!", username, reason, (char *) 0);
		}

		/*
		 * Authentication of this user failed.
		 * The username must be confirmed in the next try.
		 */
		free (username);
		username = NULL;

		/*
		 * Wait a while (a la SVR4 /usr/bin/login) before attempting
		 * to login the user again. If the earlier alarm occurs
		 * before the sleep() below completes, login will exit.
		 */
		if (delay > 0) {
			(void) sleep (delay);
		}

		(void) puts (_("Login incorrect"));

		/* allow only one attempt with -r or -f */
		if (rflg || fflg || (retries <= 0)) {
			closelog ();
			exit (1);
		}
	}			/* while (true) */
#endif				/* ! USE_PAM */
	assert (NULL != username);
	assert (NULL != pwd);

	(void) alarm (0);		/* turn off alarm clock */

#ifndef USE_PAM			/* PAM does this */
	/*
	 * porttime checks moved here, after the user has been
	 * authenticated. now prints a message, as suggested
	 * by Ivan Nejgebauer <*****@*****.**>.  --marekm
	 */
	if (   getdef_bool ("PORTTIME_CHECKS_ENAB")
	    && !isttytime (username, tty, time ((time_t *) 0))) {
		SYSLOG ((LOG_WARN, "invalid login time for '%s'%s",
		         username, fromhost));
		closelog ();
		bad_time_notify ();
		exit (1);
	}

	check_nologin (pwd->pw_uid == 0);
#endif

	if (getenv ("IFS")) {	/* don't export user IFS ... */
		addenv ("IFS= \t\n", NULL);	/* ... instead, set a safe IFS */
	}

	if (pwd->pw_shell[0] == '*') {	/* subsystem root */
		pwd->pw_shell++;	/* skip the '*' */
		subsystem (pwd);	/* figure out what to execute */
		subroot = true;	/* say I was here again */
		endpwent ();	/* close all of the file which were */
		endgrent ();	/* open in the original rooted file */
		endspent ();	/* system. they will be re-opened */
#ifdef	SHADOWGRP
		endsgent ();	/* in the new rooted file system */
#endif
		goto top;	/* go do all this all over again */
	}

#ifdef WITH_AUDIT
	audit_fd = audit_open ();
	audit_log_acct_message (audit_fd,
	                        AUDIT_USER_LOGIN,
	                        NULL,    /* Prog. name */
	                        "login",
	                        username,
	                        AUDIT_NO_ID,
	                        hostname,
	                        NULL,    /* addr */
	                        tty,
	                        1);      /* result */
	close (audit_fd);
#endif				/* WITH_AUDIT */

#ifndef USE_PAM			/* pam_lastlog handles this */
	if (getdef_bool ("LASTLOG_ENAB")) {	/* give last login and log this one */
		dolastlog (&ll, pwd, tty, hostname);
	}
#endif

#ifndef USE_PAM			/* PAM handles this as well */
	/*
	 * Have to do this while we still have root privileges, otherwise we
	 * don't have access to /etc/shadow.
	 */
	if (NULL != spwd) {		/* check for age of password */
		if (expire (pwd, spwd)) {
			/* The user updated her password, get the new
			 * entries.
			 * Use the x variants because we need to keep the
			 * entry for a long time, and there might be other
			 * getxxyy in between.
			 */
			pw_free (pwd);
			pwd = xgetpwnam (username);
			if (NULL == pwd) {
				SYSLOG ((LOG_ERR,
				         "cannot find user %s after update of expired password",
				         username));
				exit (1);
			}
			spw_free (spwd);
			spwd = xgetspnam (username);
		}
	}
	setup_limits (pwd);	/* nice, ulimit etc. */
#endif				/* ! USE_PAM */
	chown_tty (pwd);

#ifdef USE_PAM
	/*
	 * We must fork before setuid() because we need to call
	 * pam_close_session() as root.
	 */
	(void) signal (SIGINT, SIG_IGN);
	child = fork ();
	if (child < 0) {
		/* error in fork() */
		fprintf (stderr, _("%s: failure forking: %s"),
		         Prog, strerror (errno));
		PAM_END;
		exit (0);
	} else if (child != 0) {
		/*
		 * parent - wait for child to finish, then cleanup
		 * session
		 */
		wait (NULL);
		PAM_END;
		exit (0);
	}
	/* child */
#endif

	/* If we were init, we need to start a new session */
	if (getppid() == 1) {
		setsid();
		if (ioctl(0, TIOCSCTTY, 1) != 0) {
			fprintf (stderr, _("TIOCSCTTY failed on %s"), tty);
		}
	}

	/*
	 * The utmp entry needs to be updated to indicate the new status
	 * of the session, the new PID and SID.
	 */
	update_utmp (username, tty, hostname, utent);

	/* The pwd and spwd entries for the user have been copied.
	 *
	 * Close all the files so that unauthorized access won't occur.
	 */
	endpwent ();		/* stop access to password file */
	endgrent ();		/* stop access to group file */
	endspent ();		/* stop access to shadow passwd file */
#ifdef	SHADOWGRP
	endsgent ();		/* stop access to shadow group file */
#endif

	/* Drop root privileges */
#ifndef USE_PAM
	if (setup_uid_gid (pwd, is_console))
#else
	/* The group privileges were already dropped.
	 * See setup_groups() above.
	 */
	if (change_uid (pwd))
#endif
	{
		exit (1);
	}

	setup_env (pwd);	/* set env vars, cd to the home dir */

#ifdef USE_PAM
	{
		const char *const *env;

		env = (const char *const *) pam_getenvlist (pamh);
		while ((NULL != env) && (NULL != *env)) {
			addenv (*env, NULL);
			env++;
		}
	}
#endif

	(void) setlocale (LC_ALL, "");
	(void) bindtextdomain (PACKAGE, LOCALEDIR);
	(void) textdomain (PACKAGE);

	if (!hushed (username)) {
		addenv ("HUSHLOGIN=FALSE", NULL);
		/*
		 * pam_unix, pam_mail and pam_lastlog should take care of
		 * this
		 */
#ifndef USE_PAM
		motd ();	/* print the message of the day */
		if (   getdef_bool ("FAILLOG_ENAB")
		    && (0 != faillog.fail_cnt)) {
			failprint (&faillog);
			/* Reset the lockout times if logged in */
			if (   (0 != faillog.fail_max)
			    && (faillog.fail_cnt >= faillog.fail_max)) {
				(void) puts (_("Warning: login re-enabled after temporary lockout."));
				SYSLOG ((LOG_WARN,
				         "login '%s' re-enabled after temporary lockout (%d failures)",
				         username, (int) faillog.fail_cnt));
			}
		}
		if (   getdef_bool ("LASTLOG_ENAB")
		    && (ll.ll_time != 0)) {
			time_t ll_time = ll.ll_time;

#ifdef HAVE_STRFTIME
			(void) strftime (ptime, sizeof (ptime),
			                 "%a %b %e %H:%M:%S %z %Y",
			                 localtime (&ll_time));
			printf (_("Last login: %s on %s"),
			        ptime, ll.ll_line);
#else
			printf (_("Last login: %.19s on %s"),
			        ctime (&ll_time), ll.ll_line);
#endif
#ifdef HAVE_LL_HOST		/* __linux__ || SUN4 */
			if ('\0' != ll.ll_host[0]) {
				printf (_(" from %.*s"),
				        (int) sizeof ll.ll_host, ll.ll_host);
			}
#endif
			printf (".\n");
		}
		agecheck (spwd);

		mailcheck ();	/* report on the status of mail */
#endif				/* !USE_PAM */
	} else {
		addenv ("HUSHLOGIN=TRUE", NULL);
	}

	ttytype (tty);

	(void) signal (SIGQUIT, SIG_DFL);	/* default quit signal */
	(void) signal (SIGTERM, SIG_DFL);	/* default terminate signal */
	(void) signal (SIGALRM, SIG_DFL);	/* default alarm signal */
	(void) signal (SIGHUP, SIG_DFL);	/* added this.  --marekm */
	(void) signal (SIGINT, SIG_DFL);	/* default interrupt signal */

	if (0 == pwd->pw_uid) {
		SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
	} else if (getdef_bool ("LOG_OK_LOGINS")) {
		SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost));
	}
	closelog ();
	tmp = getdef_str ("FAKE_SHELL");
	if (NULL != tmp) {
		err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */
	} else {
		/* exec the shell finally */
		err = shell (pwd->pw_shell, (char *) 0, newenvp);
	}

	return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
}