diff options
Diffstat (limited to 'src/gs-auth-helper.c')
-rw-r--r-- | src/gs-auth-helper.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/gs-auth-helper.c b/src/gs-auth-helper.c new file mode 100644 index 0000000..ea9aefe --- /dev/null +++ b/src/gs-auth-helper.c @@ -0,0 +1,213 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * written by Olaf Kirch <[email protected]> + * xscreensaver, Copyright (c) 1993-2004 Jamie Zawinski <[email protected]> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +/* The idea here is to be able to run mate-screensaver-dialog without any setuid bits. + * Password verification happens through an external program that you feed + * your password to on stdin. The external command is invoked with a user + * name argument. + * + * The external helper does whatever authentication is necessary. Currently, + * SuSE uses "unix2_chkpwd", which is a variation of "unix_chkpwd" from the + * PAM distribution. + * + * Normally, the password helper should just authenticate the calling user + * (i.e. based on the caller's real uid). This is in order to prevent + * brute-forcing passwords in a shadow environment. A less restrictive + * approach would be to allow verifying other passwords as well, but always + * with a 2 second delay or so. (Not sure what SuSE's "unix2_chkpwd" + * currently does.) + * -- Olaf Kirch <[email protected]>, 16-Dec-2003 + */ + +#include "config.h" + +#include <stdlib.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <pwd.h> +#include <errno.h> +#include <sys/wait.h> + +#include <glib.h> +#include <glib/gstdio.h> + +#include "gs-auth.h" +#include "subprocs.h" + +static gboolean verbose_enabled = FALSE; + +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 gboolean +ext_run (const char *user, + const char *typed_passwd, + gboolean verbose) +{ + int pfd[2], status; + pid_t pid; + + if (pipe (pfd) < 0) + { + return 0; + } + + if (verbose) + { + g_message ("ext_run (%s, %s)", + PASSWD_HELPER_PROGRAM, user); + } + + block_sigchld (); + + if ((pid = fork ()) < 0) + { + close (pfd [0]); + close (pfd [1]); + return FALSE; + } + + if (pid == 0) + { + close (pfd [1]); + if (pfd [0] != 0) + { + dup2 (pfd [0], 0); + } + + /* Helper is invoked as helper service-name [user] */ + execlp (PASSWD_HELPER_PROGRAM, PASSWD_HELPER_PROGRAM, "mate-screensaver", user, NULL); + if (verbose) + { + g_message ("%s: %s", PASSWD_HELPER_PROGRAM, g_strerror (errno)); + } + + exit (1); + } + + close (pfd [0]); + + /* Write out password to helper process */ + if (!typed_passwd) + { + typed_passwd = ""; + } + write (pfd [1], typed_passwd, strlen (typed_passwd)); + close (pfd [1]); + + while (waitpid (pid, &status, 0) < 0) + { + if (errno == EINTR) + { + continue; + } + + if (verbose) + { + g_message ("ext_run: waitpid failed: %s\n", + g_strerror (errno)); + } + + unblock_sigchld (); + return FALSE; + } + + unblock_sigchld (); + + if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) + { + return FALSE; + } + + return TRUE; +} + +gboolean +gs_auth_verify_user (const char *username, + const char *display, + GSAuthMessageFunc func, + gpointer data, + GError **error) +{ + gboolean res = FALSE; + char *password; + + password = NULL; + + /* ask for the password for user */ + if (func != NULL) + { + func (GS_AUTH_MESSAGE_PROMPT_ECHO_OFF, + "Password: ", + &password, + data); + } + + if (password == NULL) + { + return FALSE; + } + + res = ext_run (username, password, gs_auth_get_verbose ()); + + return res; +} + +gboolean +gs_auth_init (void) +{ + return TRUE; +} + +gboolean +gs_auth_priv_init (void) +{ + /* Make sure the passwd helper exists */ + if (g_access (PASSWD_HELPER_PROGRAM, X_OK) < 0) + { + g_warning ("%s does not exist. " + "password authentication via " + "external helper will not work.", + PASSWD_HELPER_PROGRAM); + return FALSE; + } + + return TRUE; +} |