コード例 #1
0
ファイル: login.c プロジェクト: abrodkin/util-linux
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);
	}
}
コード例 #2
0
static void
init_groups (const struct passwd* pw, gid_t* groups, int num_groups) {
    int retval;

    errno = 0;

    if (num_groups) {
        retval = setgroups (num_groups, groups);
    } else {
        retval = initgroups (pw->pw_name, pw->pw_gid);
    }

    if (retval == -1) {
        cleanup_pam (PAM_ABORT);
        err (EXIT_FAILURE, _("cannot set groups"));
    }
    endgrent ();

    retval = pam_setcred (pamh, PAM_ESTABLISH_CRED);
    if (is_pam_failure(retval)) {
        errx (EXIT_FAILURE, "%s", pam_strerror (pamh, retval));
    } else {
        _pam_cred_established = 1;
    }
}
コード例 #3
0
ファイル: login.c プロジェクト: bdwalton/util-linux
static pam_handle_t *init_loginpam(struct login_context *cxt)
{
	pam_handle_t *pamh = NULL;
	int rc;

	/*
	 * username is initialized to NULL and if specified on the command line
	 * it is set.  Therefore, we are safe not setting it to anything
	 */
	rc = pam_start(cxt->remote ? "remote" : "login",
		       cxt->username, &cxt->conv, &pamh);
	if (rc != PAM_SUCCESS) {
		warnx(_("PAM failure, aborting: %s"), pam_strerror(pamh, rc));
		syslog(LOG_ERR, _("Couldn't initialize PAM: %s"),
		       pam_strerror(pamh, rc));
		sleepexit(EXIT_FAILURE);
	}

	/* hostname & tty are either set to NULL or their correct values,
	 * depending on how much we know
	 */
	rc = pam_set_item(pamh, PAM_RHOST, cxt->hostname);
	if (is_pam_failure(rc))
		loginpam_err(pamh, rc);

	rc = pam_set_item(pamh, PAM_TTY, cxt->tty_name);
	if (is_pam_failure(rc))
		loginpam_err(pamh, rc);

	/*
	 * [email protected]: Provide a user prompt to PAM so that
	 * the "login: "******"Password: " string (yet).
	 */
	rc = pam_set_item(pamh, PAM_USER_PROMPT, loginpam_get_prompt(cxt));
	if (is_pam_failure(rc))
		loginpam_err(pamh, rc);

	/* we need't the original username. We have to follow PAM. */
	free(cxt->username);
	cxt->username = NULL;
	cxt->pamh = pamh;

	return pamh;
}
コード例 #4
0
ファイル: login.c プロジェクト: abrodkin/util-linux
/*
 * Note that the position of the pam_setcred() call is discussable:
 *
 *  - the PAM docs recommend pam_setcred() before pam_open_session()
 *  - but the original RFC http://www.opengroup.org/rfc/mirror-rfc/rfc86.0.txt
 *    uses pam_setcred() after pam_open_session()
 *
 * The old login versions (before year 2011) followed the RFC. This is probably
 * not optimal, because there could be a dependence between some session modules
 * and the user's credentials.
 *
 * The best is probably to follow openssh and call pam_setcred() before and
 * after pam_open_session().                -- [email protected] (18-Nov-2011)
 *
 */
static void loginpam_session(struct login_context *cxt)
{
	int rc;
	pam_handle_t *pamh = cxt->pamh;

	rc = pam_setcred(pamh, PAM_ESTABLISH_CRED);
	if (is_pam_failure(rc))
		loginpam_err(pamh, rc);

	rc = pam_open_session(pamh, 0);
	if (is_pam_failure(rc)) {
		pam_setcred(cxt->pamh, PAM_DELETE_CRED);
		loginpam_err(pamh, rc);
	}

	rc = pam_setcred(pamh, PAM_REINITIALIZE_CRED);
	if (is_pam_failure(rc)) {
		pam_close_session(pamh, 0);
		loginpam_err(pamh, rc);
	}
}
コード例 #5
0
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"));
    }
}
コード例 #6
0
static void
create_watching_parent (void) {
    pid_t child;
    sigset_t ourset;
    struct sigaction oldact[3];
    int status = 0;
    int retval;

    retval = pam_open_session (pamh, 0);
    if (is_pam_failure(retval)) {
        cleanup_pam (retval);
        errx (EXIT_FAILURE, _("cannot open session: %s"),
              pam_strerror (pamh, retval));
    } else {
        _pam_session_opened = 1;
    }

    memset(oldact, 0, sizeof(oldact));

    child = fork ();
    if (child == (pid_t) - 1) {
        cleanup_pam (PAM_ABORT);
        err (EXIT_FAILURE, _("cannot create child process"));
    }

    /* the child proceeds to run the shell */
    if (child == 0) {
        return;
    }

    /* In the parent watch the child.  */

    /* su without pam support does not have a helper that keeps
       sitting on any directory so let's go to /.  */
    if (chdir ("/") != 0) {
        warn (_("cannot change directory to %s"), "/");
    }

    sigfillset (&ourset);
    if (sigprocmask (SIG_BLOCK, &ourset, NULL)) {
        warn (_("cannot block signals"));
        caught_signal = true;
    }
    if (!caught_signal) {
        struct sigaction action;
        action.sa_handler = su_catch_sig;
        sigemptyset (&action.sa_mask);
        action.sa_flags = 0;
        sigemptyset (&ourset);
        if (!same_session) {
            if (sigaddset(&ourset, SIGINT) || sigaddset(&ourset, SIGQUIT)) {
                warn (_("cannot set signal handler"));
                caught_signal = true;
            }
        }
        if (!caught_signal && (sigaddset(&ourset, SIGTERM)
                               || sigaddset(&ourset, SIGALRM)
                               || sigaction(SIGTERM, &action, &oldact[0])
                               || sigprocmask(SIG_UNBLOCK, &ourset, NULL))) {
            warn (_("cannot set signal handler"));
            caught_signal = true;
        }
        if (!caught_signal && !same_session && (sigaction(SIGINT, &action, &oldact[1])
                                                || sigaction(SIGQUIT, &action, &oldact[2]))) {
            warn (_("cannot set signal handler"));
            caught_signal = true;
        }
    }
    if (!caught_signal) {
        pid_t pid;
        for (;;) {
            pid = waitpid (child, &status, WUNTRACED);

            if (pid != (pid_t) - 1 && WIFSTOPPED (status)) {
                kill (getpid (), SIGSTOP);
                /* once we get here, we must have resumed */
                kill (pid, SIGCONT);
            } else {
                break;
            }
        }
        if (pid != (pid_t) - 1) {
            if (WIFSIGNALED (status)) {
                fprintf (stderr, "%s%s\n", strsignal (WTERMSIG (status)),
                         WCOREDUMP (status) ? _(" (core dumped)") : "");
                status = WTERMSIG (status) + 128;
            } else {
                status = WEXITSTATUS (status);
            }
        } else if (caught_signal) {
            status = caught_signal + 128;
        } else {
            status = 1;
        }
    } else {
        status = 1;
    }

    if (caught_signal) {
        fprintf (stderr, _("\nSession terminated, killing shell..."));
        kill (child, SIGTERM);
    }

    cleanup_pam (PAM_SUCCESS);

    if (caught_signal) {
        sleep (2);
        kill (child, SIGKILL);
        fprintf (stderr, _(" ...killed.\n"));

        /* Let's terminate itself with the received signal.
         *
         * It seems that shells use WIFSIGNALED() rather than our exit status
         * value to detect situations when is necessary to cleanup (reset)
         * terminal settings (kzak -- Jun 2013).
         */
        switch (caught_signal) {
        case SIGTERM:
            sigaction(SIGTERM, &oldact[0], NULL);
            break;
        case SIGINT:
            sigaction(SIGINT, &oldact[1], NULL);
            break;
        case SIGQUIT:
            sigaction(SIGQUIT, &oldact[2], NULL);
            break;
        default:
            /* just in case that signal stuff initialization failed and
             * caught_signal = true */
            caught_signal = SIGKILL;
            break;
        }
        kill(getpid(), caught_signal);
    }
    exit (status);
}
コード例 #7
0
ファイル: login.c プロジェクト: abrodkin/util-linux
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);
	}
}