diff options
Diffstat (limited to 'src/gs-auth-pam.c.orig')
-rw-r--r-- | src/gs-auth-pam.c.orig | 843 |
1 files changed, 0 insertions, 843 deletions
diff --git a/src/gs-auth-pam.c.orig b/src/gs-auth-pam.c.orig deleted file mode 100644 index 88852d9..0000000 --- a/src/gs-auth-pam.c.orig +++ /dev/null @@ -1,843 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * Copyright (C) 2006 William Jon McCann <[email protected]> - * Copyright (C) 2006 Ray Strode <[email protected]> - * Copyright (C) 2003 Bill Nottingham <[email protected]> - * Copyright (c) 1993-2003 Jamie Zawinski <[email protected]> - * - * 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 "config.h" - -#include <stdlib.h> -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <pwd.h> -#include <grp.h> -#include <security/pam_appl.h> -#include <signal.h> -#include <errno.h> - -#include <glib.h> -#include <glib/gstdio.h> -#include <glib/gi18n.h> -#include <gtk/gtk.h> - -#include "gs-auth.h" - -#include "subprocs.h" - -/* Some time between Red Hat 4.2 and 7.0, the words were transposed - in the various PAM_x_CRED macro names. Yay! -*/ -#ifndef PAM_REFRESH_CRED -# define PAM_REFRESH_CRED PAM_CRED_REFRESH -#endif - -#ifdef HAVE_PAM_FAIL_DELAY -/* We handle delays ourself.*/ -/* Don't set this to 0 (Linux bug workaround.) */ -# define PAM_NO_DELAY(pamh) pam_fail_delay ((pamh), 1) -#else /* !HAVE_PAM_FAIL_DELAY */ -# define PAM_NO_DELAY(pamh) /* */ -#endif /* !HAVE_PAM_FAIL_DELAY */ - - -/* On SunOS 5.6, and on Linux with PAM 0.64, pam_strerror() takes two args. - On some other Linux systems with some other version of PAM (e.g., - whichever Debian release comes with a 2.2.5 kernel) it takes one arg. - I can't tell which is more "recent" or "correct" behavior, so configure - figures out which is in use for us. Shoot me! -*/ -#ifdef PAM_STRERROR_TWO_ARGS -# define PAM_STRERROR(pamh, status) pam_strerror((pamh), (status)) -#else /* !PAM_STRERROR_TWO_ARGS */ -# define PAM_STRERROR(pamh, status) pam_strerror((status)) -#endif /* !PAM_STRERROR_TWO_ARGS */ - -static gboolean verbose_enabled = FALSE; -static pam_handle_t *pam_handle = NULL; -static gboolean did_we_ask_for_password = FALSE; - -struct pam_closure -{ - const char *username; - GSAuthMessageFunc cb_func; - gpointer cb_data; - int signal_fd; - int result; -}; - -typedef struct -{ - struct pam_closure *closure; - GSAuthMessageStyle style; - const char *msg; - char **resp; - gboolean should_interrupt_stack; -} GsAuthMessageHandlerData; - -static GCond *message_handled_condition; -static GMutex *message_handler_mutex; - -GQuark -gs_auth_error_quark (void) -{ - static GQuark quark = 0; - if (! quark) - { - quark = g_quark_from_static_string ("gs_auth_error"); - } - - return quark; -} - -void -gs_auth_set_verbose (gboolean enabled) -{ - verbose_enabled = enabled; -} - -gboolean -gs_auth_get_verbose (void) -{ - return verbose_enabled; -} - -static GSAuthMessageStyle -pam_style_to_gs_style (int pam_style) -{ - GSAuthMessageStyle style; - - switch (pam_style) - { - case PAM_PROMPT_ECHO_ON: - style = GS_AUTH_MESSAGE_PROMPT_ECHO_ON; - break; - case PAM_PROMPT_ECHO_OFF: - style = GS_AUTH_MESSAGE_PROMPT_ECHO_OFF; - break; - case PAM_ERROR_MSG: - style = GS_AUTH_MESSAGE_ERROR_MSG; - break; - case PAM_TEXT_INFO: - style = GS_AUTH_MESSAGE_TEXT_INFO; - break; - default: - g_assert_not_reached (); - break; - } - - return style; -} - -static gboolean -auth_message_handler (GSAuthMessageStyle style, - const char *msg, - char **response, - gpointer data) -{ - gboolean ret; - - ret = TRUE; - *response = NULL; - - switch (style) - { - case GS_AUTH_MESSAGE_PROMPT_ECHO_ON: - break; - case GS_AUTH_MESSAGE_PROMPT_ECHO_OFF: - if (msg != NULL && g_str_has_prefix (msg, _("Password:"))) - { - did_we_ask_for_password = TRUE; - } - break; - case GS_AUTH_MESSAGE_ERROR_MSG: - break; - case GS_AUTH_MESSAGE_TEXT_INFO: - break; - default: - g_assert_not_reached (); - } - - return ret; -} - -static gboolean -gs_auth_queued_message_handler (GsAuthMessageHandlerData *data) -{ - gboolean res; - - if (gs_auth_get_verbose ()) - { - g_message ("Waiting for lock"); - } - - g_mutex_lock (message_handler_mutex); - - if (gs_auth_get_verbose ()) - { - g_message ("Waiting for response"); - } - - res = data->closure->cb_func (data->style, - data->msg, - data->resp, - data->closure->cb_data); - - data->should_interrupt_stack = res == FALSE; - - g_cond_signal (message_handled_condition); - g_mutex_unlock (message_handler_mutex); - - if (gs_auth_get_verbose ()) - { - g_message ("Got response"); - } - - return FALSE; -} - -static gboolean -gs_auth_run_message_handler (struct pam_closure *c, - GSAuthMessageStyle style, - const char *msg, - char **resp) -{ - GsAuthMessageHandlerData data; - - data.closure = c; - data.style = style; - data.msg = msg; - data.resp = resp; - data.should_interrupt_stack = TRUE; - - g_mutex_lock (message_handler_mutex); - - /* Queue the callback in the gui (the main) thread - */ - g_idle_add ((GSourceFunc) gs_auth_queued_message_handler, &data); - - if (gs_auth_get_verbose ()) - { - g_message ("Waiting for respose to message style %d: '%s'", style, msg); - } - - /* Wait for the response - */ - g_cond_wait (message_handled_condition, - message_handler_mutex); - g_mutex_unlock (message_handler_mutex); - - if (gs_auth_get_verbose ()) - { - g_message ("Got respose to message style %d: interrupt:%d", style, data.should_interrupt_stack); - } - - return data.should_interrupt_stack == FALSE; -} - -static int -pam_conversation (int nmsgs, - const struct pam_message **msg, - struct pam_response **resp, - void *closure) -{ - int replies = 0; - struct pam_response *reply = NULL; - struct pam_closure *c = (struct pam_closure *) closure; - gboolean res; - int ret; - - reply = (struct pam_response *) calloc (nmsgs, sizeof (*reply)); - - if (reply == NULL) - { - return PAM_CONV_ERR; - } - - res = TRUE; - ret = PAM_SUCCESS; - - for (replies = 0; replies < nmsgs && ret == PAM_SUCCESS; replies++) - { - GSAuthMessageStyle style; - char *utf8_msg; - - style = pam_style_to_gs_style (msg [replies]->msg_style); - - utf8_msg = g_locale_to_utf8 (msg [replies]->msg, - -1, - NULL, - NULL, - NULL); - - /* if we couldn't convert text from locale then - * assume utf-8 and hope for the best */ - if (utf8_msg == NULL) - { - char *p; - char *q; - - utf8_msg = g_strdup (msg [replies]->msg); - - p = utf8_msg; - while (*p != '\0' && !g_utf8_validate ((const char *)p, -1, (const char **)&q)) - { - *q = '?'; - p = q + 1; - } - } - - /* handle message locally first */ - auth_message_handler (style, - utf8_msg, - &reply [replies].resp, - NULL); - - if (c->cb_func != NULL) - { - if (gs_auth_get_verbose ()) - { - g_message ("Handling message style %d: '%s'", style, utf8_msg); - } - - /* blocks until the gui responds - */ - res = gs_auth_run_message_handler (c, - style, - utf8_msg, - &reply [replies].resp); - - if (gs_auth_get_verbose ()) - { - g_message ("Msg handler returned %d", res); - } - - /* If the handler returns FALSE - interrupt the PAM stack */ - if (res) - { - reply [replies].resp_retcode = PAM_SUCCESS; - } - else - { - int i; - for (i = 0; i <= replies; i++) - { - free (reply [i].resp); - } - free (reply); - reply = NULL; - ret = PAM_CONV_ERR; - } - } - - g_free (utf8_msg); - } - - *resp = reply; - - return ret; -} - -static gboolean -close_pam_handle (int status) -{ - - if (pam_handle != NULL) - { - int status2; - - status2 = pam_end (pam_handle, status); - pam_handle = NULL; - - if (gs_auth_get_verbose ()) - { - g_message (" pam_end (...) ==> %d (%s)", - status2, - (status2 == PAM_SUCCESS ? "Success" : "Failure")); - } - } - - if (message_handled_condition != NULL) - { - g_cond_free (message_handled_condition); - message_handled_condition = NULL; - } - - if (message_handler_mutex != NULL) - { - g_mutex_free (message_handler_mutex); - message_handler_mutex = NULL; - } - - return TRUE; -} - -static gboolean -create_pam_handle (const char *username, - const char *display, - struct pam_conv *conv, - int *status_code) -{ - int status; - const char *service = PAM_SERVICE_NAME; - char *disp; - gboolean ret; - - if (pam_handle != NULL) - { - g_warning ("create_pam_handle: Stale pam handle around, cleaning up"); - close_pam_handle (PAM_SUCCESS); - } - - /* init things */ - pam_handle = NULL; - status = -1; - disp = NULL; - ret = TRUE; - - /* Initialize a PAM session for the user */ - if ((status = pam_start (service, username, conv, &pam_handle)) != PAM_SUCCESS) - { - pam_handle = NULL; - g_warning (_("Unable to establish service %s: %s\n"), - service, - PAM_STRERROR (NULL, status)); - - if (status_code != NULL) - { - *status_code = status; - } - - ret = FALSE; - goto out; - } - - if (gs_auth_get_verbose ()) - { - g_message ("pam_start (\"%s\", \"%s\", ...) ==> %d (%s)", - service, - username, - status, - PAM_STRERROR (pam_handle, status)); - } - - disp = g_strdup (display); - if (disp == NULL) - { - disp = g_strdup (":0.0"); - } - - if ((status = pam_set_item (pam_handle, PAM_TTY, disp)) != PAM_SUCCESS) - { - g_warning (_("Can't set PAM_TTY=%s"), display); - - if (status_code != NULL) - { - *status_code = status; - } - - ret = FALSE; - goto out; - } - - ret = TRUE; - message_handled_condition = g_cond_new (); - message_handler_mutex = g_mutex_new (); - -out: - if (status_code != NULL) - { - *status_code = status; - } - - g_free (disp); - - return ret; -} - -static void -set_pam_error (GError **error, - int status) -{ - if (status == PAM_AUTH_ERR || status == PAM_USER_UNKNOWN) - { - char *msg; - - if (did_we_ask_for_password) - { - msg = g_strdup (_("Incorrect password.")); - } - else - { - msg = g_strdup (_("Authentication failed.")); - } - - g_set_error (error, - GS_AUTH_ERROR, - GS_AUTH_ERROR_AUTH_ERROR, - "%s", - msg); - g_free (msg); - } - else if (status == PAM_PERM_DENIED) - { - g_set_error (error, - GS_AUTH_ERROR, - GS_AUTH_ERROR_AUTH_DENIED, - "%s", - _("Not permitted to gain access at this time.")); - } - else if (status == PAM_ACCT_EXPIRED) - { - g_set_error (error, - GS_AUTH_ERROR, - GS_AUTH_ERROR_AUTH_DENIED, - "%s", - _("No longer permitted to access the system.")); - } - -} - -static int -gs_auth_thread_func (int auth_operation_fd) -{ - static const int flags = 0; - int status; - int status2; - struct timespec timeout; - sigset_t set; - const void *p; - - timeout.tv_sec = 0; - timeout.tv_nsec = 1; - - set = block_sigchld (); - - status = pam_authenticate (pam_handle, flags); - - sigtimedwait (&set, NULL, &timeout); - unblock_sigchld (); - - if (gs_auth_get_verbose ()) - { - g_message (" pam_authenticate (...) ==> %d (%s)", - status, - PAM_STRERROR (pam_handle, status)); - } - - if (status != PAM_SUCCESS) - { - goto done; - } - - if ((status = pam_get_item (pam_handle, PAM_USER, &p)) != PAM_SUCCESS) - { - /* is not really an auth problem, but it will - pretty much look as such, it shouldn't really - happen */ - goto done; - } - - /* We don't actually care if the account modules fail or succeed, - * but we need to run them anyway because certain pam modules - * depend on side effects of the account modules getting run. - */ - status2 = pam_acct_mgmt (pam_handle, 0); - - if (gs_auth_get_verbose ()) - { - g_message ("pam_acct_mgmt (...) ==> %d (%s)\n", - status2, - PAM_STRERROR (pam_handle, status2)); - } - - /* FIXME: should we handle these? */ - switch (status2) - { - case PAM_SUCCESS: - break; - case PAM_NEW_AUTHTOK_REQD: - break; - case PAM_AUTHINFO_UNAVAIL: - break; - case PAM_ACCT_EXPIRED: - break; - case PAM_PERM_DENIED: - break; - default : - break; - } - - /* Each time we successfully authenticate, refresh credentials, - for Kerberos/AFS/DCE/etc. If this fails, just ignore that - failure and blunder along; it shouldn't matter. - - Note: this used to be PAM_REFRESH_CRED instead of - PAM_REINITIALIZE_CRED, but Jason Heiss <[email protected]> - says that the Linux PAM library ignores that one, and only refreshes - credentials when using PAM_REINITIALIZE_CRED. - */ - status2 = pam_setcred (pam_handle, PAM_REINITIALIZE_CRED); - if (gs_auth_get_verbose ()) - { - g_message (" pam_setcred (...) ==> %d (%s)", - status2, - PAM_STRERROR (pam_handle, status2)); - } - -done: - /* we're done, close the fd and wake up the main - * loop - */ - close (auth_operation_fd); - - return status; -} - -static gboolean -gs_auth_loop_quit (GIOChannel *source, - GIOCondition condition, - gboolean *thread_done) -{ - *thread_done = TRUE; - gtk_main_quit (); - return FALSE; -} - -static gboolean -gs_auth_pam_verify_user (pam_handle_t *handle, - int *status) -{ - GThread *auth_thread; - GIOChannel *channel; - guint watch_id; - int auth_operation_fds[2]; - int auth_status; - gboolean thread_done; - - channel = NULL; - watch_id = 0; - auth_status = PAM_AUTH_ERR; - - /* This pipe gives us a set of fds we can hook into - * the event loop to be notified when our helper thread - * is ready to be reaped. - */ - if (pipe (auth_operation_fds) < 0) - { - goto out; - } - - if (fcntl (auth_operation_fds[0], F_SETFD, FD_CLOEXEC) < 0) - { - close (auth_operation_fds[0]); - close (auth_operation_fds[1]); - goto out; - } - - if (fcntl (auth_operation_fds[1], F_SETFD, FD_CLOEXEC) < 0) - { - close (auth_operation_fds[0]); - close (auth_operation_fds[1]); - goto out; - } - - channel = g_io_channel_unix_new (auth_operation_fds[0]); - - /* we use a recursive main loop to process ui events - * while we wait on a thread to handle the blocking parts - * of pam authentication. - */ - thread_done = FALSE; - watch_id = g_io_add_watch (channel, G_IO_ERR | G_IO_HUP, - (GIOFunc) gs_auth_loop_quit, &thread_done); - - auth_thread = g_thread_create ((GThreadFunc) gs_auth_thread_func, - GINT_TO_POINTER (auth_operation_fds[1]), - TRUE, NULL); - - if (auth_thread == NULL) - { - goto out; - } - - gtk_main (); - - /* if the event loop was quit before the thread is done then we can't - * reap the thread without blocking on it finishing. The - * thread may not ever finish though if the pam module is blocking. - * - * The only time the event loop is going to stop when the thread isn't - * done, however, is if the dialog quits early (from, e.g., "cancel"), - * so we can just exit. An alternative option would be to switch to - * using pthreads directly and calling pthread_cancel. - */ - if (!thread_done) - { - raise (SIGTERM); - } - - auth_status = GPOINTER_TO_INT (g_thread_join (auth_thread)); - -out: - if (watch_id != 0) - { - g_source_remove (watch_id); - } - - if (channel != NULL) - { - g_io_channel_unref (channel); - } - - if (status) - { - *status = auth_status; - } - - return auth_status == PAM_SUCCESS; -} - -gboolean -gs_auth_verify_user (const char *username, - const char *display, - GSAuthMessageFunc func, - gpointer data, - GError **error) -{ - int status = -1; - struct pam_conv conv; - struct pam_closure c; - struct passwd *pwent; - - pwent = getpwnam (username); - if (pwent == NULL) - { - return FALSE; - } - - c.username = username; - c.cb_func = func; - c.cb_data = data; - - conv.conv = &pam_conversation; - conv.appdata_ptr = (void *) &c; - - /* Initialize PAM. */ - create_pam_handle (username, display, &conv, &status); - if (status != PAM_SUCCESS) - { - goto done; - } - - pam_set_item (pam_handle, PAM_USER_PROMPT, _("Username:")); - - PAM_NO_DELAY(pam_handle); - - did_we_ask_for_password = FALSE; - if (! gs_auth_pam_verify_user (pam_handle, &status)) - { - goto done; - } - -done: - if (status != PAM_SUCCESS) - { - set_pam_error (error, status); - } - - close_pam_handle (status); - - return (status == PAM_SUCCESS ? TRUE : FALSE); -} - -gboolean -gs_auth_init (void) -{ - return TRUE; -} - -gboolean -gs_auth_priv_init (void) -{ - /* We have nothing to do at init-time. - However, we might as well do some error checking. - If "/etc/pam.d" exists and is a directory, but "/etc/pam.d/xlock" - does not exist, warn that PAM probably isn't going to work. - - This is a priv-init instead of a non-priv init in case the directory - is unreadable or something (don't know if that actually happens.) - */ - const char dir [] = "/etc/pam.d"; - const char file [] = "/etc/pam.d/" PAM_SERVICE_NAME; - const char file2 [] = "/etc/pam.conf"; - struct stat st; - - if (g_stat (dir, &st) == 0 && st.st_mode & S_IFDIR) - { - if (g_stat (file, &st) != 0) - { - g_warning ("%s does not exist.\n" - "Authentication via PAM is unlikely to work.", - file); - } - } - else if (g_stat (file2, &st) == 0) - { - FILE *f = g_fopen (file2, "r"); - if (f) - { - gboolean ok = FALSE; - char buf[255]; - while (fgets (buf, sizeof(buf), f)) - { - if (strstr (buf, PAM_SERVICE_NAME)) - { - ok = TRUE; - break; - } - } - - fclose (f); - if (!ok) - { - g_warning ("%s does not list the `%s' service.\n" - "Authentication via PAM is unlikely to work.", - file2, PAM_SERVICE_NAME); - } - } - /* else warn about file2 existing but being unreadable? */ - } - else - { - g_warning ("Neither %s nor %s exist.\n" - "Authentication via PAM is unlikely to work.", - file2, file); - } - - /* Return true anyway, just in case. */ - return TRUE; -} |