gboolean mdm_verify_setup_user (MdmDisplay *d, const gchar *login, char **new_login) { struct passwd *pwent; *new_login = NULL; pwent = getpwnam (login); if (pwent == NULL) { mdm_debug ("Cannot get passwd structure for user"); return FALSE; } if ( ! mdm_setup_gids (login, pwent->pw_gid)) { mdm_debug ("Cannot set user group"); mdm_errorgui_error_box (d, GTK_MESSAGE_ERROR, _("\nCannot set your user group; " "you will not be able to log in. " "Please contact your system administrator.")); return FALSE; } return TRUE; }
void mdm_save_customlist_data (const gchar *file, const gchar *key, const gchar *id) { GKeyFile *cfg; mdm_debug ("Saving custom configuration data to file=%s, key=%s", file, key); cfg = mdm_common_config_load (file, NULL); if (cfg == NULL) { gint fd = -1; mdm_debug ("creating file: %s", file); VE_IGNORE_EINTR (fd = g_open (file, O_CREAT | O_TRUNC | O_RDWR, 0644)); if (fd < 0) return; write (fd, "\n", 2); close (fd); cfg = mdm_common_config_load (file, NULL); if (cfg == NULL) { return; } } g_key_file_set_string (cfg, "GreeterInfo", key, ve_sure_string (id)); mdm_common_config_save (cfg, file, NULL); g_key_file_free (cfg); }
/* * Get the VT number associated with the display via the XFree86_VT * Atom. */ long mdm_get_current_vtnum (Display *display) { Atom prop; Atom actualtype; int actualformat; unsigned long nitems; unsigned long bytes_after; unsigned char *buf; unsigned long num; if (display == NULL) return -1; prop = XInternAtom (display, "XFree86_VT", True); if (prop == None) { mdm_debug ("no XFree86_VT atom\n"); return -1; } if (XGetWindowProperty (display, DefaultRootWindow (display), prop, 0, 1, False, AnyPropertyType, &actualtype, &actualformat, &nitems, &bytes_after, &buf)) { mdm_debug ("no XFree86_VT property\n"); return -1; } if (nitems != 1) { mdm_debug ("%lu items in XFree86_VT property!\n", nitems); XFree (buf); return -1; } switch (actualtype) { case XA_CARDINAL: case XA_INTEGER: case XA_WINDOW: switch (actualformat) { case 8: num = (*(uint8_t *)(void *)buf); break; case 16: num = (*(uint16_t *)(void *)buf); break; case 32: num = (*(uint32_t *)(void *)buf); break; default: mdm_debug ("format %d in XFree86_VT property!\n", actualformat); XFree (buf); return -1; } break; default: mdm_debug ("type %lx in XFree86_VT property!\n", actualtype); XFree (buf); return -1; } XFree (buf); return num; }
void mdm_verify_cleanup (MdmDisplay *d) { gid_t groups[1] = { 0 }; cur_mdm_disp = d; if (pamh != NULL) { gint pamerr; pam_handle_t *tmp_pamh; gboolean old_opened_session; gboolean old_did_setcred; mdm_debug ("Running mdm_verify_cleanup and pamh != NULL"); mdm_sigterm_block_push (); mdm_sigchld_block_push (); tmp_pamh = pamh; pamh = NULL; old_opened_session = opened_session; opened_session = FALSE; old_did_setcred = did_setcred; did_setcred = FALSE; mdm_sigchld_block_pop (); mdm_sigterm_block_pop (); pamerr = PAM_SUCCESS; /* Close the users session */ if (old_opened_session) { mdm_debug ("Running pam_close_session"); pamerr = pam_close_session (tmp_pamh, 0); } /* Throw away the credentials */ if (old_did_setcred) { mdm_debug ("Running pam_setcred with PAM_DELETE_CRED"); pamerr = pam_setcred (tmp_pamh, PAM_DELETE_CRED); } pam_end (tmp_pamh, pamerr); /* Workaround to avoid mdm messages being logged as PAM_pwdb */ mdm_log_shutdown (); mdm_log_init (); } /* Clear the group setup */ setgid (0); /* this will get rid of any suplementary groups etc... */ setgroups (1, groups); cur_mdm_disp = NULL; /* reset limits */ mdm_reset_limits (); }
/* 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); }
void mdm_verify_set_user_settings (const char *user) { char * session; char * language; gboolean savesess = FALSE; if (mdm_verify_check_selectable_user(user)) { mdm_debug("mdm_verify_set_user_settings: Checking settings for '%s'", user); char * home_dir = g_strdup_printf("/home/%s", user); if ( !(g_file_test(home_dir, G_FILE_TEST_EXISTS))) { mdm_debug("mdm_verify_set_user_settings: user '%s' doesn't exist.", user); return; } mdm_daemon_config_get_user_session_lang (&session, &language, home_dir, &savesess); if (!ve_string_empty(session)) { mdm_debug("mdm_verify_set_user_settings: Found session '%s'.", session); mdm_slave_greeter_ctl_no_ret (MDM_SETSESS, session); } else { mdm_debug("mdm_verify_set_user_settings: No session found, setting to default '%s'.", "default"); mdm_slave_greeter_ctl_no_ret (MDM_SETSESS, "default"); // Do not translate "default" here, it's a value } if (!ve_string_empty(language)) { mdm_debug("mdm_verify_set_user_settings: Found language '%s'.", language); mdm_slave_greeter_ctl_no_ret (MDM_SETLANG, language); } else { const char * mdmlang = g_getenv ("LANG"); if (mdmlang) { mdm_debug("mdm_verify_set_user_settings: No language found, setting to default '%s'.", mdmlang); mdm_slave_greeter_ctl_no_ret (MDM_SETLANG, mdmlang); } } } }
/** * mdm_display_unmanage: * @d: Pointer to a MdmDisplay struct * * Stop services for a display */ void mdm_display_unmanage (MdmDisplay *d) { if (!d) return; mdm_debug ("mdm_display_unmanage: Stopping %s (slave pid: %d)", d->name, (int)d->slavepid); /* whack connections about this display */ if (unixconn != NULL) mdm_kill_subconnections_with_display (unixconn, d); /* Kill slave, this may in fact hang for a bit at least until the * slave dies, which should be ASAP though */ whack_old_slave (d, TRUE /* kill_connection */); d->dispstat = DISPLAY_DEAD; if (d->type != TYPE_STATIC) mdm_display_dispose (d); mdm_debug ("mdm_display_unmanage: Display stopped"); }
gboolean mdm_verify_check_selectable_user (const char * user) { // Return if the username is null or empty if (user == NULL || strcmp (user, "") == 0) { mdm_debug("mdm_verify_check_selectable_user: invalid username."); return FALSE; } // Return if the username is "oem" if (strcmp (user, "oem") == 0) { mdm_debug("mdm_verify_check_selectable_user: username is 'oem'."); return FALSE; } char * home_dir = g_strdup_printf("/home/%s", user); char * accounts_service = g_strdup_printf("/var/lib/AccountsService/users/%s", user); // Return if the user doesn't exist (check /home and AccountsService) if ( !(g_file_test(home_dir, G_FILE_TEST_EXISTS) || g_file_test(accounts_service, G_FILE_TEST_EXISTS)) ) { mdm_debug("mdm_verify_check_selectable_user: user '%s' doesn't exist.", user); return FALSE; } // Return if the user belongs to the nopasswdlogin group char result[255]; char * command = g_strdup_printf("id '%s' 2>/dev/null | grep nopasswdlogin | wc -l", user); FILE *fp = popen(command, "r"); fscanf(fp, "%s", result); pclose(fp); if (strcmp(result, "0") != 0) { mdm_debug("mdm_verify_check_selectable_user: user '%s' is part of the nopasswdlogin group.", user); return FALSE; } return TRUE; }
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); } }
/* 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; }
gchar * mdm_verify_user (MdmDisplay *d, const char *username, gboolean allow_retry) { gchar *login, *passwd, *ppasswd; struct passwd *pwent; struct spwd *sp; #if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS) \ || defined (HAVE_LOGINRESTRICTIONS) gchar *message = NULL; #endif #if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS) gchar *info_msg = NULL, *response = NULL; gint reEnter, ret; #endif if (d->attached && d->timed_login_ok) mdm_slave_greeter_ctl_no_ret (MDM_STARTTIMER, ""); if (username == NULL) { authenticate_again: /* Ask for the user's login */ mdm_verify_select_user (NULL); mdm_slave_greeter_ctl_no_ret (MDM_MSG, _("Please enter your username")); login = mdm_slave_greeter_ctl (MDM_PROMPT, _("Username:"******""); g_free (login); return NULL; } } mdm_slave_greeter_ctl_no_ret (MDM_MSG, ""); 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_ERRBOX, info); g_free (info); } } else { login = g_strdup (username); } mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login); pwent = getpwnam (login); setspent (); /* Lookup shadow password */ sp = getspnam (login); /* Use shadow password when available */ if (sp != NULL) { ppasswd = g_strdup (sp->sp_pwdp); } else { /* In case shadow password cannot be retrieved (when using NIS authentication for example), use standard passwd */ if (pwent != NULL && pwent->pw_passwd != NULL) ppasswd = g_strdup (pwent->pw_passwd); else /* If no password can be retrieved, set it to NULL */ ppasswd = NULL; } endspent (); /* Request the user's password */ if (pwent != NULL && ve_string_empty (ppasswd)) { /* eeek a passwordless account */ passwd = g_strdup (""); } else { passwd = mdm_slave_greeter_ctl (MDM_NOECHO, _("Password:"******""); if (mdm_slave_greeter_check_interruption ()) { if (d->attached) mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, ""); g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } } if (d->attached) mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, ""); if (pwent == NULL) { mdm_sleep_no_signal (mdm_daemon_config_get_value_int (MDM_KEY_RETRY_DELAY)); mdm_debug ("Couldn't authenticate user"); print_cant_auth_errbox (); g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } /* Check whether password is valid */ if (ppasswd == NULL || (ppasswd[0] != '\0' && strcmp (crypt (passwd, ppasswd), ppasswd) != 0)) { mdm_sleep_no_signal (mdm_daemon_config_get_value_int (MDM_KEY_RETRY_DELAY)); mdm_debug ("Couldn't authenticate user"); print_cant_auth_errbox (); g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } if (( ! mdm_daemon_config_get_value_bool (MDM_KEY_ALLOW_ROOT) || ( ! mdm_daemon_config_get_value_bool (MDM_KEY_ALLOW_REMOTE_ROOT) && ! d->attached)) && pwent->pw_uid == 0) { mdm_debug ("Root login disallowed on display '%s'", d->name); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("The system administrator " "is not allowed to login " "from this screen")); /*mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG, _("Root login disallowed"));*/ g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } #ifdef HAVE_LOGINRESTRICTIONS /* Check with the 'loginrestrictions' function if the user has been disallowed */ if (loginrestrictions (login, 0, NULL, &message) != 0) { mdm_debug ("User not allowed to log in"); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe system administrator " "has disabled your " "account.")); g_free (login); g_free (passwd); g_free (ppasswd); if (message != NULL) free (message); return NULL; } if (message != NULL) free (message); message = NULL; #else /* ! HAVE_LOGINRESTRICTIONS */ /* check for the standard method of disallowing users */ if (pwent->pw_shell != NULL && (strcmp (pwent->pw_shell, NOLOGIN) == 0 || strcmp (pwent->pw_shell, "/bin/true") == 0 || strcmp (pwent->pw_shell, "/bin/false") == 0)) { mdm_debug ("User not allowed to log in"); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe system administrator " "has disabled your " "account.")); /*mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG, _("Login disabled"));*/ g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } #endif /* HAVE_LOGINRESTRICTIONS */ g_free (passwd); g_free (ppasswd); if ( ! mdm_slave_check_user_wants_to_log_in (login)) { g_free (login); login = NULL; goto authenticate_again; } if ( ! mdm_setup_gids (login, pwent->pw_gid)) { mdm_debug ("Cannot set user group"); 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.")); g_free (login); return NULL; } #if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS) switch (passwdexpired (login, &info_msg)) { case 1 : mdm_debug ("User password has expired"); mdm_errorgui_error_box (d, GTK_MESSAGE_ERROR, _("You are required to change your password.\n" "Please choose a new one.")); g_free (info_msg); do { ret = chpass (login, response, &reEnter, &message); g_free (response); if (ret != 1) { if (ret != 0) { mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nCannot change your password; " "you will not be able to log in. " "Please try again later or contact " "your system administrator.")); } else if ((reEnter != 0) && (message)) { response = mdm_slave_greeter_ctl (MDM_NOECHO, message); if (response == NULL) response = g_strdup (""); } } g_free (message); message = NULL; } while ( ((reEnter != 0) && (ret == 0)) || (ret ==1) ); g_free (response); g_free (message); if ((ret != 0) || (reEnter != 0)) { return NULL; } #if defined (CAN_CLEAR_ADMCHG) /* The password is changed by root, clear the ADM_CHG flag in the passwd file */ ret = setpwdb (S_READ | S_WRITE); if (!ret) { upwd = getuserpw (login); if (upwd == NULL) { ret = -1; } else { upwd->upw_flags &= ~PW_ADMCHG; ret = putuserpw (upwd); if (!ret) { ret = endpwdb (); } } } if (ret) { mdm_errorgui_error_box (d, GTK_MESSAGE_WARNING, _("Your password has been changed but " "you may have to change it again. " "Please try again later or contact " "your system administrator.")); } #else /* !CAN_CLEAR_ADMCHG */ mdm_errorgui_error_box (d, GTK_MESSAGE_WARNING, _("Your password has been changed but you " "may have to change it again. Please try again " "later or contact your system administrator.")); #endif /* CAN_CLEAR_ADMCHG */ break; case 2 : mdm_debug ("User password has expired"); mdm_errorgui_error_box (d, GTK_MESSAGE_ERROR, _("Your password has expired.\n" "Only a system administrator can now change it")); g_free (info_msg); return NULL; break; case -1 : mdm_debug ("Internal error on passwdexpired"); mdm_errorgui_error_box (d, GTK_MESSAGE_ERROR, _("An internal error occurred. You will not be able to log in.\n" "Please try again later or contact your system administrator.")); g_free (info_msg); return NULL; break; default : g_free (info_msg); break; } #endif /* HAVE_PASSWDEXPIRED && HAVE_CHPASS */ return login; }
void mdm_display_dispose (MdmDisplay *d) { if (d == NULL) return; /* paranoia */ if (unixconn != NULL) mdm_kill_subconnections_with_display (unixconn, d); if (d->socket_conn != NULL) { MdmConnection *conn = d->socket_conn; d->socket_conn = NULL; mdm_connection_set_close_notify (conn, NULL, NULL); } if (d->slave_notify_fd >= 0) { VE_IGNORE_EINTR (close (d->slave_notify_fd)); d->slave_notify_fd = -1; } if (d->master_notify_fd >= 0) { VE_IGNORE_EINTR (close (d->master_notify_fd)); d->master_notify_fd = -1; } mdm_daemon_config_display_list_remove (d); d->dispstat = DISPLAY_DEAD; d->type = -1; count_session_limits (); if (d->name) { mdm_debug ("mdm_display_dispose: Disposing %s", d->name); g_free (d->name); d->name = NULL; } g_free (d->chosen_hostname); d->chosen_hostname = NULL; g_free (d->hostname); d->hostname = NULL; g_free (d->windowpath); d->windowpath = NULL; g_free (d->addrs); d->addrs = NULL; d->addr_count = 0; g_free (d->authfile); d->authfile = NULL; g_free (d->authfile_mdm); d->authfile_mdm = NULL; if (d->auths) { mdm_auth_free_auth_list (d->auths); d->auths = NULL; } if (d->local_auths) { mdm_auth_free_auth_list (d->local_auths); d->local_auths = NULL; } g_free (d->userauth); d->userauth = NULL; g_free (d->windowpath); d->windowpath = NULL; g_free (d->command); d->command = NULL; g_free (d->device_name); d->device_name = NULL; g_free (d->cookie); d->cookie = NULL; g_free (d->bcookie); d->bcookie = NULL; d->indirect_id = 0; g_free (d->login); d->login = NULL; g_free (d->preset_user); d->preset_user = NULL; g_free (d->xsession_errors_filename); d->xsession_errors_filename = NULL; if (d->session_output_fd >= 0) { VE_IGNORE_EINTR (close (d->session_output_fd)); d->session_output_fd = -1; } if (d->xsession_errors_fd >= 0) { VE_IGNORE_EINTR (close (d->xsession_errors_fd)); d->xsession_errors_fd = -1; } g_free (d->chooser_last_line); d->chooser_last_line = NULL; if (d->chooser_output_fd >= 0) { VE_IGNORE_EINTR (close (d->chooser_output_fd)); d->chooser_output_fd = -1; } g_free (d->theme_name); d->theme_name = NULL; g_free (d->xserver_session_args); d->xserver_session_args = NULL; g_free (d); }
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 void whack_old_slave (MdmDisplay *d, gboolean kill_connection) { time_t t = time (NULL); gboolean waitsleep = TRUE; if (kill_connection) { /* This should never happen, but just in case */ if (d->socket_conn != NULL) { MdmConnection *conn = d->socket_conn; d->socket_conn = NULL; mdm_connection_set_close_notify (conn, NULL, NULL); } } if (d->master_notify_fd >= 0) { VE_IGNORE_EINTR (close (d->master_notify_fd)); d->master_notify_fd = -1; } /* if we have DISPLAY_DEAD set, then this has already been killed */ if (d->dispstat == DISPLAY_DEAD) waitsleep = FALSE; /* Kill slave */ if (d->slavepid > 1 && (d->dispstat == DISPLAY_DEAD || kill (d->slavepid, SIGTERM) == 0)) { int exitstatus; int ret; wait_again: if (waitsleep) { /* wait for some signal, yes this is a race */ mdm_debug ("mdm whack_old_slave: sleeping for 10 seconds"); sleep (10); } waitsleep = TRUE; errno = 0; ret = waitpid (d->slavepid, &exitstatus, WNOHANG); if (ret <= 0) { /* rekill the slave to tell it to hurry up and die if we're getting killed ourselves */ if ((mdm_daemon_config_signal_terminthup_was_notified ()) || (t + 10 <= time (NULL))) { mdm_debug ("whack_old_slave: GOT ANOTHER SIGTERM (or it was 10 secs already), killing slave again with SIGKILL"); t = time (NULL); kill (d->slavepid, SIGKILL); goto wait_again; } else if (ret < 0 && errno == EINTR) { goto wait_again; } } if (WIFSIGNALED (exitstatus)) { mdm_debug ("whack_old_slave: Slave crashed (signal %d), killing its children", (int)WTERMSIG (exitstatus)); if (d->sesspid > 1) kill (-(d->sesspid), SIGTERM); d->sesspid = 0; if (d->greetpid > 1) kill (-(d->greetpid), SIGTERM); d->greetpid = 0; if (d->chooserpid > 1) kill (-(d->chooserpid), SIGTERM); d->chooserpid = 0; if (d->servpid > 1) kill (d->servpid, SIGTERM); d->servpid = 0; } } d->slavepid = 0; }
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; }