/* 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; }
/* 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); }
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; }
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; }
/* 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; }
void mdm_xdmcp_migrate (MdmDisplay *from, MdmDisplay *to) { mdm_error (_("%s: No XDMCP support"), "mdm_xdmcp_migrate"); }
void mdm_xdmcp_close (void) { mdm_error (_("%s: No XDMCP support"), "mdm_xdmcp_close"); }
void mdm_xdmcp_run (void) { mdm_error (_("%s: No XDMCP support"), "mdm_xdmcp_run"); }
/* 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; }
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; }
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; }