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); } }
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; }