summaryrefslogtreecommitdiff
path: root/src/gs-auth-pam.c.orig
diff options
context:
space:
mode:
Diffstat (limited to 'src/gs-auth-pam.c.orig')
-rw-r--r--src/gs-auth-pam.c.orig843
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;
-}