コード例 #1
0
ファイル: verify-pam.c プロジェクト: ActusOS/mdm
/* Creates a pam handle for the auto login */
static gboolean
create_pamh (MdmDisplay *d,
	     const char *service,
	     const char *login,
	     struct pam_conv *conv,
	     const char *display,
	     int *pamerr)
{

	if (display == NULL) {
		mdm_error ("Cannot setup pam handle with null display");
		return FALSE;
	}

	if (pamh != NULL) {
		mdm_error ("create_pamh: Stale pamh around, cleaning up");
		pam_end (pamh, PAM_SUCCESS);
	}
	/* init things */
	pamh = NULL;
	opened_session = FALSE;
	did_setcred = FALSE;

	/* Initialize a PAM session for the user */
	if ((*pamerr = pam_start (service, login, conv, &pamh)) != PAM_SUCCESS) {
		pamh = NULL; /* be anal */
		if (mdm_slave_action_pending ())
			mdm_error ("Unable to establish service %s: %s\n", service, pam_strerror (NULL, *pamerr));
		return FALSE;
	}

	/* Inform PAM of the user's tty */
		if ((*pamerr = pam_set_item (pamh, PAM_TTY, display)) != PAM_SUCCESS) {
			if (mdm_slave_action_pending ())
				mdm_error ("Can't set PAM_TTY=%s", display);
			return FALSE;
		}

	if ( ! d->attached) {
		/* Only set RHOST if host is remote */
		/* From the host of the display */
		if ((*pamerr = pam_set_item (pamh, PAM_RHOST,
					     d->hostname)) != PAM_SUCCESS) {
			if (mdm_slave_action_pending ())
				mdm_error ("Can't set PAM_RHOST=%s", d->hostname);
			return FALSE;
		}
	}

	// Preselect the previous user
	if (do_we_need_to_preset_the_username) {		
		do_we_need_to_preset_the_username = FALSE;
		mdm_preselect_user(pamerr);
	}

	return TRUE;
}
コード例 #2
0
ファイル: verify-pam.c プロジェクト: ActusOS/mdm
/* Preselects the last logged in user */
static void mdm_preselect_user (int *pamerr) {
	
	// Return if user preselection isn't enabled
	if (!mdm_daemon_config_get_value_bool (MDM_KEY_SELECT_LAST_LOGIN)) {
		return;
	}
	
	// Return if we're using automatic or timed login
	if (mdm_daemon_config_get_value_bool (MDM_KEY_AUTOMATIC_LOGIN_ENABLE) || mdm_daemon_config_get_value_bool (MDM_KEY_TIMED_LOGIN_ENABLE)) {
		mdm_debug("mdm_preselect_user: Automatic/Timed login detected, not presetting user.");
		return;
	}

        // Return if the user list is disabled (relevant to mdmlogin)
        if (!mdm_daemon_config_get_value_bool (MDM_KEY_BROWSER)) {
		mdm_debug("mdm_preselect_user: User list disabled, not presetting user.");
                return;
        }

	// Find the name of the last logged in user
	char last_username[255];
	FILE *fp = popen("last -w | grep tty | head -1 | awk {'print $1;'}", "r");
	fscanf(fp, "%s", last_username);
	pclose(fp);

	// If for any reason the user isn't selectable, don't preset.
	if (!mdm_verify_check_selectable_user(last_username)) {
		return;
	}	

	// Preset the user
	mdm_debug("mdm_verify_user: presetting user to '%s'", last_username);
	if ((*pamerr = pam_set_item (pamh, PAM_USER, last_username)) != PAM_SUCCESS) {		
		if (mdm_slave_action_pending ()) {
			mdm_error ("Can't set PAM_USER='******'", last_username);
		}
	}

	mdm_verify_set_user_settings (last_username);

}
コード例 #3
0
ファイル: xdmcp.c プロジェクト: AlbertJP/mdm
static void
reconnect_to_parent (MdmDisplay *to)
{
       GError *error;
       gchar *command_argv[10];
       const gchar *proxyreconnect = mdm_daemon_config_get_value_string (MDM_KEY_XDMCP_PROXY_RECONNECT);

       command_argv[0] = (char *)proxyreconnect;
       command_argv[1] = "--display";
       command_argv[2] = to->parent_disp;
       command_argv[3] = "--display-authfile";
       command_argv[4] = to->parent_auth_file;
       command_argv[5] = "--to";
       command_argv[6] = to->name;
       command_argv[7] = "--to-authfile";
       command_argv[8] = to->authfile;
       command_argv[9] = NULL;

       mdm_debug ("XDMCP: migrating display by running "
                  "'%s --display %s --display-authfile %s --to %s --to-authfile %s'",
                  proxyreconnect,
                  to->parent_disp, to->parent_auth_file,
                  to->name, to->authfile);

       error = NULL;
       if (!g_spawn_async (NULL, command_argv, NULL, 0, NULL, NULL, NULL, &error)) {
               mdm_error (_("%s: Failed to run "
                            "'%s --display %s --display-authfile %s --to %s --to-authfile %s': %s"),
                          "mdm_xdmcp_migrate",
                          proxyreconnect,
                          to->parent_disp, to->parent_auth_file,
                          to->name, to->authfile,
                          error->message);
               g_error_free (error);
       }
}
コード例 #4
0
ファイル: verify-pam.c プロジェクト: ActusOS/mdm
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;
}
コード例 #5
0
ファイル: verify-pam.c プロジェクト: ActusOS/mdm
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;
}
コード例 #6
0
ファイル: verify-pam.c プロジェクト: dotovr/mdm
/* Creates a pam handle for the auto login */
static gboolean
create_pamh (MdmDisplay *d,
	     const char *service,
	     const char *login,
	     struct pam_conv *conv,
	     const char *display,
	     int *pamerr)
{

	if (display == NULL) {
		mdm_error ("Cannot setup pam handle with null display");
		return FALSE;
	}

	if (pamh != NULL) {
		mdm_error ("create_pamh: Stale pamh around, cleaning up");
		pam_end (pamh, PAM_SUCCESS);
	}
	/* init things */
	pamh = NULL;
	opened_session = FALSE;
	did_setcred = FALSE;

	/* Initialize a PAM session for the user */
	if ((*pamerr = pam_start (service, login, conv, &pamh)) != PAM_SUCCESS) {
		pamh = NULL; /* be anal */
		if (mdm_slave_action_pending ())
			mdm_error ("Unable to establish service %s: %s\n", service, pam_strerror (NULL, *pamerr));
		return FALSE;
	}

	/* Inform PAM of the user's tty */
		if ((*pamerr = pam_set_item (pamh, PAM_TTY, display)) != PAM_SUCCESS) {
			if (mdm_slave_action_pending ())
				mdm_error ("Can't set PAM_TTY=%s", display);
			return FALSE;
		}

	if ( ! d->attached) {
		/* Only set RHOST if host is remote */
		/* From the host of the display */
		if ((*pamerr = pam_set_item (pamh, PAM_RHOST,
					     d->hostname)) != PAM_SUCCESS) {
			if (mdm_slave_action_pending ())
				mdm_error ("Can't set PAM_RHOST=%s", d->hostname);
			return FALSE;
		}
	}

	// Preselect the previous user
	if (do_we_need_to_preset_the_username) {		
		do_we_need_to_preset_the_username = FALSE;
		if (mdm_daemon_config_get_value_bool (MDM_KEY_SELECT_LAST_LOGIN)) {

			if (mdm_daemon_config_get_value_bool (MDM_KEY_AUTOMATIC_LOGIN_ENABLE) || mdm_daemon_config_get_value_bool (MDM_KEY_TIMED_LOGIN_ENABLE)) {
				mdm_debug("mdm_verify_user: Automatic/Timed login detected, not presetting user.");
			}
			else {
				char last_username[255];
				FILE *fp = popen("last -w | grep tty | head -1 | awk {'print $1;'}", "r");
				fscanf(fp, "%s", last_username);
				pclose(fp);
				if (last_username != NULL && strcmp (last_username, "") != 0) {
					// Verify that the username returned is actually legit
					char * home_dir = g_strdup_printf("/home/%s", last_username);
	  				char * accounts_service = g_strdup_printf("/var/lib/AccountsService/users/%s", last_username);
					if ((g_file_test(home_dir, G_FILE_TEST_EXISTS)) || (g_file_test(accounts_service, G_FILE_TEST_EXISTS))) {
						// Preset the user
	    				mdm_debug("mdm_verify_user: presetting user to '%s'", last_username);
						if ((*pamerr = pam_set_item (pamh, PAM_USER, last_username)) != PAM_SUCCESS) {
							if (mdm_slave_action_pending ()) {
								mdm_error ("Can't set PAM_USER='******'", last_username);
							}
						}
	  				}				
				}
			}
		}
	}

	return TRUE;
}
コード例 #7
0
ファイル: xdmcp.c プロジェクト: AlbertJP/mdm
void
mdm_xdmcp_migrate (MdmDisplay *from, MdmDisplay *to)
{
	mdm_error (_("%s: No XDMCP support"), "mdm_xdmcp_migrate");
}
コード例 #8
0
ファイル: xdmcp.c プロジェクト: AlbertJP/mdm
void
mdm_xdmcp_close (void)
{
	mdm_error (_("%s: No XDMCP support"), "mdm_xdmcp_close");
}
コード例 #9
0
ファイル: xdmcp.c プロジェクト: AlbertJP/mdm
void
mdm_xdmcp_run (void)
{
	mdm_error (_("%s: No XDMCP support"), "mdm_xdmcp_run");
}
コード例 #10
0
ファイル: xdmcp.c プロジェクト: AlbertJP/mdm
/* Here come some empty stubs for no XDMCP support */
int
mdm_xdmcp_init  (void)
{
	mdm_error (_("%s: No XDMCP support"), "mdm_xdmcp_init");
	return FALSE;
}
コード例 #11
0
ファイル: display.c プロジェクト: Jumziey/mdm
gboolean 
mdm_display_manage (MdmDisplay *d)
{
    pid_t pid;
    int fds[2];

    if (!d) 
	return FALSE;

    mdm_debug ("mdm_display_manage: Managing %s", d->name);

    if (pipe (fds) < 0) {
	    mdm_error ("mdm_display_manage: Cannot create pipe");
    }

    if ( ! mdm_display_check_loop (d))
	    return FALSE;

    if (d->slavepid != 0)
	    mdm_debug ("mdm_display_manage: Old slave pid is %d", (int)d->slavepid);

    /* If we have an old slave process hanging around, kill it */
    /* This shouldn't be a normal code path however, so it doesn't matter
     * that we are hanging */
    whack_old_slave (d, FALSE /* kill_connection */);

    /* Ensure that /tmp/.ICE-unix and /tmp/.X11-unix exist and have the
     * correct permissions */
    mdm_ensure_sanity ();

    d->managetime = time (NULL);

    mdm_debug ("Forking slave process");

    /* Fork slave process */
    pid = d->slavepid = fork ();

    switch (pid) {

    case 0:

	setpgid (0, 0);

	/* Make the slave it's own leader.  This 1) makes killing -pid of
	 * the daemon work more sanely because the daemon can whack the
	 * slave much better itself */
	setsid ();

	/* In the child setup empty mask and set all signals to
	 * default values, we'll make them more fun later */
	mdm_unset_signals ();

	d->slavepid = getpid ();
	
	mdm_connection_close (pipeconn);
	pipeconn = NULL;
	mdm_connection_close (unixconn);
	unixconn = NULL;

	mdm_log_shutdown ();

	/* Debian changes */
#if 0
	/* upstream version */
-	/* Close everything */
-	mdm_close_all_descriptors (0 /* from */, fds[0] /* except */, slave_fifo_pipe_fd /* except2 */);
#endif
	/* Close stdin/stdout/stderr.  Leave others, as pam modules may have them open */
	VE_IGNORE_EINTR (close (0));
	VE_IGNORE_EINTR (close (1));
	VE_IGNORE_EINTR (close (2));
	/* End of Debian changes */

	/* No error checking here - if it's messed the best response
         * is to ignore & try to continue */
	mdm_open_dev_null (O_RDONLY); /* open stdin - fd 0 */
	mdm_open_dev_null (O_RDWR); /* open stdout - fd 1 */
	mdm_open_dev_null (O_RDWR); /* open stderr - fd 2 */

	mdm_log_init ();

	d->slave_notify_fd = fds[0];

	fcntl (d->slave_notify_fd, F_SETFL, fcntl (d->slave_notify_fd, F_GETFL) | O_NONBLOCK);

	mdm_slave_start (d);
	/* should never retern */

	/* yaikes, how did we ever get here? */
	mdm_server_stop (d);
	_exit (DISPLAY_REMANAGE);

	break;

    case -1:
	d->slavepid = 0;
	mdm_error ("mdm_display_manage: Failed forking MDM slave process for %s", d->name);

	return FALSE;

    default:
	mdm_debug ("mdm_display_manage: Forked slave: %d", (int)pid);
	d->master_notify_fd = fds[1];
	VE_IGNORE_EINTR (close (fds[0]));
	break;
    }

    /* invalidate chosen hostname */
    g_free (d->chosen_hostname);
    d->chosen_hostname = NULL;

    /* use_chooser can only be temporary, if you want it permanent you set it
       up in the server definition with "chooser=true" and it will get set up
       during server command line resolution */
    d->use_chooser = FALSE;

    if (SERVER_IS_LOCAL (d)) {
	    d->dispstat = DISPLAY_ALIVE;
    }

    /* reset sleep to 1, to sleep just in case (avoids X server races) */
    d->sleep_before_run = 1;

    return TRUE;
}
コード例 #12
0
ファイル: display.c プロジェクト: Jumziey/mdm
static gboolean
mdm_display_check_loop (MdmDisplay *disp)
{
  time_t now;
  time_t since_last;
  time_t since_loop;
  
  now = time (NULL);

  mdm_debug ("loop check: last_start %ld, last_loop %ld, now: %ld, retry_count: %d", (long)disp->last_start_time, (long) disp->last_loop_start_time, (long) now, disp->retry_count);
  
  if (disp->last_loop_start_time > now || disp->last_loop_start_time == 0)
    {
      /* Reset everything if this is the first time in this
       * function, or if the system clock got reset backward.
       */
      disp->last_loop_start_time = now;
      disp->last_start_time = now;
      disp->retry_count = 1;

      mdm_debug ("Resetting counts for loop of death detection");
      
      return TRUE;
    }

  since_loop = now - disp->last_loop_start_time;
  since_last = now - disp->last_start_time;

  /* If it's been at least 1.5 minutes since the last startup loop
   * attempt, then we reset everything.  Or if the last startup was more then
   * 30 seconds ago, then it was likely a successful session.
   */

  if (since_loop >= 90 || since_last >= 30)
    {
      disp->last_loop_start_time = now;
      disp->last_start_time = now;
      disp->retry_count = 1;

      mdm_debug ("Resetting counts for loop of death detection, 90 seconds elapsed since loop started or session lasted more then 30 seconds.");
      
      return TRUE;
    }

  /* If we've tried too many times we bail out. i.e. this means we
   * tried too many times in the 90-second period.
   */
  if (disp->retry_count >= 6) {
	  /* This means we have no clue what's happening,
	   * it's not X server crashing as we would have
	   * cought that elsewhere.  Things are just
	   * not working out, so tell the user.
	   * However this may have been caused by a malicious local user
	   * zapping the display repeatedly, that shouldn't cause mdm
	   * to stop working completely so just wait for 2 minutes,
	   * that should give people ample time to stop mdm if needed,
	   * or just wait for the stupid malicious user to get bored
	   * and go away */
	  char *s = g_strdup_printf (C_(N_("The display server has been shut down "
					   "about 6 times in the last 90 seconds. "
					   "It is likely that something bad is "
					   "going on.  Waiting for 2 minutes "
					   "before trying again on display %s.")),
					disp->name);
	  /* only display a dialog box if this is a local display */
	  if (disp->type == TYPE_STATIC ||
	      disp->type == TYPE_FLEXI) {
		  mdm_text_message_dialog (s);
	  }
	  mdm_error ("%s", s);
	  g_free (s);

	  /* Wait 2 minutes */
	  disp->sleep_before_run = 120;
	  /* well, "last" start time will really be in the future */
	  disp->last_start_time = now + disp->sleep_before_run;

	  disp->retry_count = 1;
	  /* this will reset stuff in the next run (after this
	     "after-two-minutes" server starts) */
	  disp->last_loop_start_time = 0;
	  
	  return TRUE;
  }
  
  /* At least 8 seconds between start attempts, but only after
   * the second start attempt, so you can try to kill mdm from the console
   * in these gaps.
   */
  if (disp->retry_count > 2 && since_last < 8)
    {
      mdm_debug ("Will sleep %ld seconds before next X server restart attempt",
                 (long)(8 - since_last));
      now = time (NULL) + 8 - since_last;
      disp->sleep_before_run = 8 - since_last;
      /* well, "last" start time will really be in the future */
      disp->last_start_time = now + disp->sleep_before_run;
    }
  else
    {
      /* wait one second just for safety (avoids X server races) */
      disp->sleep_before_run = 1;
      disp->last_start_time = now;
    }

  disp->retry_count++;

  return TRUE;
}