/* GDM - The Gnome Display Manager * Copyright (C) 1999, 2000 Martin K. Petersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #if defined(CAN_CLEAR_ADMCHG) && defined(HAVE_USERSEC_H) # include #endif /* CAN_CLEAR_ADMCHG && HAVE_USERSEC_H */ #ifdef HAVE_CRYPT # include #endif /* HAVE_CRYPT */ #include #include "gdm.h" #include "misc.h" #include "slave.h" #include "verify.h" #include "errorgui.h" /* Configuration option variables */ extern gboolean GdmAllowRoot; extern gboolean GdmAllowRemoteRoot; extern gint GdmRetryDelay; extern gboolean GdmDisplayLastLogin; static char *selected_user = NULL; void gdm_verify_select_user (const char *user) { g_free (selected_user); if (ve_string_empty (user)) selected_user = NULL; else selected_user = g_strdup (user); } static void print_cant_auth_errbox (void) { gboolean is_capslock = FALSE; const char *basemsg; char *msg; char *ret; ret = gdm_slave_greeter_ctl (GDM_QUERY_CAPSLOCK, ""); if ( ! ve_string_empty (ret)) is_capslock = TRUE; g_free (ret); basemsg = _("\nIncorrect username or password. " "Letters must be typed in the correct " "case."); if (is_capslock) { msg = g_strconcat (basemsg, " ", _("Please make sure the " "Caps Lock key is not " "enabled."), NULL); } else { msg = g_strdup (basemsg); } gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, msg); g_free (msg); } /** * gdm_verify_user: * @username: Name of user or NULL if we should ask * @display: Name of display to register with the authentication system * @local: boolean if local * * Provides a communication layer between the operating system's * authentication functions and the gdmgreeter. * * Returns the user's login on success and NULL on failure. */ gchar * gdm_verify_user (GdmDisplay *d, const char *username, const gchar *display, gboolean local) { 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 (local) gdm_slave_greeter_ctl_no_ret (GDM_STARTTIMER, ""); if (username == NULL) { authenticate_again: /* Ask for the user's login */ gdm_verify_select_user (NULL); gdm_slave_greeter_ctl_no_ret (GDM_MSG, _("Please enter your username")); login = gdm_slave_greeter_ctl (GDM_PROMPT, _("Username:")); if (login == NULL || gdm_slave_greeter_check_interruption ()) { if ( ! ve_string_empty (selected_user)) { /* user selected */ g_free (login); login = selected_user; selected_user = NULL; } else { /* some other interruption */ if (local) gdm_slave_greeter_ctl_no_ret (GDM_STOPTIMER, ""); g_free (login); return NULL; } } gdm_slave_greeter_ctl_no_ret (GDM_MSG, ""); if (GdmDisplayLastLogin) { char *info = gdm_get_last_info (login); gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, info); g_free (info); } } else { login = g_strdup (username); } gdm_slave_greeter_ctl_no_ret (GDM_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 = gdm_slave_greeter_ctl (GDM_NOECHO, _("Password:")); if (passwd == NULL) passwd = g_strdup (""); if (gdm_slave_greeter_check_interruption ()) { if (local) gdm_slave_greeter_ctl_no_ret (GDM_STOPTIMER, ""); g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } } if (local) gdm_slave_greeter_ctl_no_ret (GDM_STOPTIMER, ""); if (pwent == NULL) { gdm_sleep_no_signal (GdmRetryDelay); gdm_error (_("Couldn't authenticate user \"%s\""), login); 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)) { gdm_sleep_no_signal (GdmRetryDelay); gdm_error (_("Couldn't authenticate user \"%s\""), login); print_cant_auth_errbox (); g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } if ( ( ! GdmAllowRoot || ( ! GdmAllowRemoteRoot && ! local) ) && pwent->pw_uid == 0) { gdm_error (_("Root login disallowed on display '%s'"), display); gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, _("The system administrator " "is not allowed to login " "from this screen")); /*gdm_slave_greeter_ctl_no_ret (GDM_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) { gdm_error (_("User %s not allowed to log in"), login); gdm_slave_greeter_ctl_no_ret (GDM_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, "/sbin/nologin") == 0 || strcmp (pwent->pw_shell, "/bin/true") == 0 || strcmp (pwent->pw_shell, "/bin/false") == 0)) { gdm_error (_("User %s not allowed to log in"), login); gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, _("\nThe system administrator " "has disabled your " "account.")); /*gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, _("Login disabled"));*/ g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } #endif /* HAVE_LOGINRESTRICTIONS */ g_free (passwd); g_free (ppasswd); if ( ! gdm_slave_check_user_wants_to_log_in (login)) { g_free (login); login = NULL; goto authenticate_again; } if ( ! gdm_setup_gids (login, pwent->pw_gid)) { gdm_error (_("Cannot set user group for %s"), login); gdm_slave_greeter_ctl_no_ret (GDM_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 : gdm_error (_("Password of %s has expired"), login); gdm_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) { gdm_slave_greeter_ctl_no_ret (GDM_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 = gdm_slave_greeter_ctl (GDM_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) { gdm_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 */ gdm_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 : gdm_error (_("Password of %s has expired"), login); gdm_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 : gdm_error (_("Internal error on passwdexpired")); gdm_error_box (d, GTK_MESSAGE_ERROR, _("An internal error occured, 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; } /** * gdm_verify_setup_user: * @login: The name of the user * @display: The name of the display * * This is used for auto loging in. This just sets up the login * session for this user */ gboolean gdm_verify_setup_user (GdmDisplay *d, const gchar *login, const gchar *display, char **new_login) { struct passwd *pwent; *new_login = NULL; pwent = getpwnam (login); if (pwent == NULL) { gdm_error (_("Cannot get passwd structure for %s"), login); return FALSE; } if ( ! gdm_setup_gids (login, pwent->pw_gid)) { gdm_error (_("Cannot set user group for %s"), login); gdm_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; } /** * gdm_verify_cleanup: * * Unregister the user's session */ void gdm_verify_cleanup (GdmDisplay *d) { gid_t groups[1] = { 0 }; /* Clear the group setup */ setgid (0); /* this will get rid of any suplementary groups etc... */ setgroups (1, groups); } /** * gdm_verify_check: * * Check that the authentication system is correctly configured. * * Aborts daemon on error */ void gdm_verify_check (void) { } /* used in pam */ gboolean gdm_verify_setup_env (GdmDisplay *d) { return TRUE; } /* EOF */