PolicyKit: Branch 'master'

David Zeuthen david at kemper.freedesktop.org
Fri Jul 2 13:34:55 PDT 2010


 src/polkitagent/Makefile.am                |    9 
 src/polkitagent/polkitagenthelper-pam.c    |  264 ++++++++++++++++++++++
 src/polkitagent/polkitagenthelper-shadow.c |  198 ++++++++++++++++
 src/polkitagent/polkitagenthelper.c        |  339 -----------------------------
 src/polkitagent/polkitagenthelperprivate.c |  106 +++++++++
 src/polkitagent/polkitagenthelperprivate.h |   45 +++
 src/programs/pkexec.c                      |    8 
 7 files changed, 629 insertions(+), 340 deletions(-)

New commits:
commit a2edcef54d2ab1a92f729e34dfa0c183b2533c61
Author: Andrew Psaltis <ampsaltis at gmail.com>
Date:   Mon Jun 28 22:04:00 2010 -0400

    Add shadow support
    
    Added support for the shadow authentication framework instead of PAM.
    Enable it by passing --with-authfw=shadow to configure.
    
    This is done by splitting the polkitagenthelper source into separate
    parts, one that does auth with PAM, and another that does auth with
    shadow, sharing functions where appropriate.
    
    Also, all PAM-dependendent code in all other files has been #ifdef'd.
    The only affected file is src/programs/pkexec.c
    
    Signed-off-by: David Zeuthen <davidz at redhat.com>

diff --git a/src/polkitagent/Makefile.am b/src/polkitagent/Makefile.am
index 3f38329..820be4d 100644
--- a/src/polkitagent/Makefile.am
+++ b/src/polkitagent/Makefile.am
@@ -68,9 +68,16 @@ libpolkit_agent_1_la_LDFLAGS = -export-symbols-regex '(^polkit_.*)'
 libexec_PROGRAMS = polkit-agent-helper-1
 
 polkit_agent_helper_1_SOURCES = 					\
-	polkitagenthelper.c						\
+	polkitagenthelperprivate.c polkitagenthelperprivate.h		\
 	$(NULL)
 
+if POLKIT_AUTHFW_PAM
+polkit_agent_helper_1_SOURCES += polkitagenthelper-pam.c
+endif
+if POLKIT_AUTHFW_SHADOW
+polkit_agent_helper_1_SOURCES += polkitagenthelper-shadow.c
+endif
+
 polkit_agent_helper_1_CFLAGS  = 					\
         -D_POLKIT_COMPILATION                                  		\
 	$(GLIB_CFLAGS)							\
diff --git a/src/polkitagent/polkitagenthelper-pam.c b/src/polkitagent/polkitagenthelper-pam.c
new file mode 100644
index 0000000..5e8b54c
--- /dev/null
+++ b/src/polkitagent/polkitagenthelper-pam.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2008, 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz at redhat.com>
+ */
+
+#include "config.h"
+#include "polkitagenthelperprivate.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include <security/pam_appl.h>
+
+#include <polkit/polkit.h>
+
+static int conversation_function (int n, const struct pam_message **msg, struct pam_response **resp, void *data);
+
+int
+main (int argc, char *argv[])
+{
+  int rc;
+  const char *user_to_auth;
+  const char *cookie;
+  struct pam_conv pam_conversation;
+  pam_handle_t *pam_h;
+  const void *authed_user;
+
+  rc = 0;
+  pam_h = NULL;
+
+  /* clear the entire environment to avoid attacks using with libraries honoring environment variables */
+  if (_polkit_clearenv () != 0)
+    goto error;
+
+  /* set a minimal environment */
+  setenv ("PATH", "/usr/sbin:/usr/bin:/sbin:/bin", 1);
+
+  /* check that we are setuid root */
+  if (geteuid () != 0)
+    {
+      fprintf (stderr, "polkit-agent-helper-1: needs to be setuid root\n");
+      goto error;
+    }
+
+  openlog ("polkit-agent-helper-1", LOG_CONS | LOG_PID, LOG_AUTHPRIV);
+
+  /* check for correct invocation */
+  if (argc != 3)
+    {
+      syslog (LOG_NOTICE, "inappropriate use of helper, wrong number of arguments [uid=%d]", getuid ());
+      fprintf (stderr, "polkit-agent-helper-1: wrong number of arguments. This incident has been logged.\n");
+      goto error;
+    }
+
+  user_to_auth = argv[1];
+  cookie = argv[2];
+
+  if (getuid () != 0)
+    {
+      /* check we're running with a non-tty stdin */
+      if (isatty (STDIN_FILENO) != 0)
+        {
+          syslog (LOG_NOTICE, "inappropriate use of helper, stdin is a tty [uid=%d]", getuid ());
+          fprintf (stderr, "polkit-agent-helper-1: inappropriate use of helper, stdin is a tty. This incident has been logged.\n");
+          goto error;
+        }
+    }
+
+#ifdef PAH_DEBUG
+  fprintf (stderr, "polkit-agent-helper-1: user to auth is '%s'.\n", user_to_auth);
+#endif /* PAH_DEBUG */
+
+  pam_conversation.conv        = conversation_function;
+  pam_conversation.appdata_ptr = NULL;
+
+  /* start the pam stack */
+  rc = pam_start ("polkit-1",
+                  user_to_auth,
+                  &pam_conversation,
+                  &pam_h);
+  if (rc != PAM_SUCCESS)
+    {
+      fprintf (stderr, "polkit-agent-helper-1: pam_start failed: %s\n", pam_strerror (pam_h, rc));
+      goto error;
+    }
+
+  /* set the requesting user */
+  rc = pam_set_item (pam_h, PAM_RUSER, user_to_auth);
+  if (rc != PAM_SUCCESS)
+    {
+      fprintf (stderr, "polkit-agent-helper-1: pam_set_item failed: %s\n", pam_strerror (pam_h, rc));
+      goto error;
+    }
+
+  /* is user really user? */
+  rc = pam_authenticate (pam_h, 0);
+  if (rc != PAM_SUCCESS)
+    {
+      fprintf (stderr, "polkit-agent-helper-1: pam_authenticated failed: %s\n", pam_strerror (pam_h, rc));
+      goto error;
+    }
+
+  /* permitted access? */
+  rc = pam_acct_mgmt (pam_h, 0);
+  if (rc != PAM_SUCCESS)
+    {
+      fprintf (stderr, "polkit-agent-helper-1: pam_acct_mgmt failed: %s\n", pam_strerror (pam_h, rc));
+      goto error;
+    }
+
+  /* did we auth the right user? */
+  rc = pam_get_item (pam_h, PAM_USER, &authed_user);
+  if (rc != PAM_SUCCESS)
+    {
+      fprintf (stderr, "polkit-agent-helper-1: pam_get_item failed: %s\n", pam_strerror (pam_h, rc));
+      goto error;
+    }
+
+  if (strcmp (authed_user, user_to_auth) != 0)
+    {
+      fprintf (stderr, "polkit-agent-helper-1: Tried to auth user '%s' but we got auth for user '%s' instead",
+               user_to_auth, (const char *) authed_user);
+      goto error;
+    }
+
+#ifdef PAH_DEBUG
+  fprintf (stderr, "polkit-agent-helper-1: successfully authenticated user '%s'.\n", user_to_auth);
+#endif /* PAH_DEBUG */
+
+  pam_end (pam_h, rc);
+  pam_h = NULL;
+
+#ifdef PAH_DEBUG
+  fprintf (stderr, "polkit-agent-helper-1: sending D-Bus message to PolicyKit daemon\n");
+#endif /* PAH_DEBUG */
+
+  /* now send a D-Bus message to the PolicyKit daemon that
+   * includes a) the cookie; and b) the user we authenticated
+   */
+  if (!send_dbus_message (cookie, user_to_auth))
+    {
+#ifdef PAH_DEBUG
+      fprintf (stderr, "polkit-agent-helper-1: error sending D-Bus message to PolicyKit daemon\n");
+#endif /* PAH_DEBUG */
+      goto error;
+    }
+
+#ifdef PAH_DEBUG
+  fprintf (stderr, "polkit-agent-helper-1: successfully sent D-Bus message to PolicyKit daemon\n");
+#endif /* PAH_DEBUG */
+
+  fprintf (stdout, "SUCCESS\n");
+  flush_and_wait();
+  return 0;
+
+error:
+  if (pam_h != NULL)
+    pam_end (pam_h, rc);
+
+  fprintf (stdout, "FAILURE\n");
+  flush_and_wait();
+  return 1;
+}
+
+static int
+conversation_function (int n, const struct pam_message **msg, struct pam_response **resp, void *data)
+{
+  struct pam_response *aresp;
+  char buf[PAM_MAX_RESP_SIZE];
+  int i;
+
+  data = data;
+  if (n <= 0 || n > PAM_MAX_NUM_MSG)
+    return PAM_CONV_ERR;
+
+  if ((aresp = calloc(n, sizeof *aresp)) == NULL)
+    return PAM_BUF_ERR;
+
+  for (i = 0; i < n; ++i)
+    {
+      aresp[i].resp_retcode = 0;
+      aresp[i].resp = NULL;
+      switch (msg[i]->msg_style)
+        {
+
+        case PAM_PROMPT_ECHO_OFF:
+          fprintf (stdout, "PAM_PROMPT_ECHO_OFF ");
+          goto conv1;
+
+        case PAM_PROMPT_ECHO_ON:
+          fprintf (stdout, "PAM_PROMPT_ECHO_ON ");
+        conv1:
+          fputs (msg[i]->msg, stdout);
+          if (strlen (msg[i]->msg) > 0 && msg[i]->msg[strlen (msg[i]->msg) - 1] != '\n')
+            fputc ('\n', stdout);
+          fflush (stdout);
+
+          if (fgets (buf, sizeof buf, stdin) == NULL)
+            goto error;
+
+          if (strlen (buf) > 0 &&
+              buf[strlen (buf) - 1] == '\n')
+            buf[strlen (buf) - 1] = '\0';
+
+          aresp[i].resp = strdup (buf);
+          if (aresp[i].resp == NULL)
+            goto error;
+          break;
+
+        case PAM_ERROR_MSG:
+          fprintf (stdout, "PAM_ERROR_MSG ");
+          goto conv2;
+
+        case PAM_TEXT_INFO:
+          fprintf (stdout, "PAM_TEXT_INFO ");
+        conv2:
+          fputs (msg[i]->msg, stdout);
+          if (strlen (msg[i]->msg) > 0 &&
+              msg[i]->msg[strlen (msg[i]->msg) - 1] != '\n')
+            fputc ('\n', stdout);
+          fflush (stdout);
+          break;
+
+        default:
+          goto error;
+        }
+    }
+
+  *resp = aresp;
+  return PAM_SUCCESS;
+
+error:
+
+  for (i = 0; i < n; ++i)
+    {
+      if (aresp[i].resp != NULL) {
+        memset (aresp[i].resp, 0, strlen(aresp[i].resp));
+        free (aresp[i].resp);
+      }
+    }
+  memset (aresp, 0, n * sizeof *aresp);
+  *resp = NULL;
+  return PAM_CONV_ERR;
+}
diff --git a/src/polkitagent/polkitagenthelper-shadow.c b/src/polkitagent/polkitagenthelper-shadow.c
new file mode 100644
index 0000000..a4f73ac
--- /dev/null
+++ b/src/polkitagent/polkitagenthelper-shadow.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2009-2010 Andrew Psaltis <ampsaltis at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Andrew Psaltis <ampsaltis at gmail.com>, based on
+ *            polkitagenthelper.c which was written by
+ *          David Zeuthen <davidz at redhat.com>
+ */
+
+#include "config.h"
+#include "polkitagenthelperprivate.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include <shadow.h>
+#include <grp.h>
+#include <pwd.h>
+#include <time.h>
+
+#include <polkit/polkit.h>
+
+static gboolean shadow_authenticate (struct spwd *shadow);
+
+int
+main (int argc, char *argv[])
+{
+  struct spwd *shadow;
+  const char *user_to_auth;
+  const char *cookie;
+  time_t now;
+
+  /* clear the entire environment to avoid attacks with
+     libraries honoring environment variables */
+  if (_polkit_clearenv () != 0)
+    goto error;
+
+  /* set a minimal environment */
+  setenv ("PATH", "/usr/sbin:/usr/bin:/sbin:/bin", 1);
+
+  /* check that we are setuid root */
+  if (geteuid () != 0)
+    {
+      fprintf (stderr, "polkit-agent-helper-1: needs to be setuid root\n");
+      goto error;
+    }
+
+  openlog ("polkit-agent-helper-1", LOG_CONS | LOG_PID, LOG_AUTHPRIV);
+
+  /* check for correct invocation */
+  if (argc != 3)
+    {
+      syslog (LOG_NOTICE, "inappropriate use of helper, wrong number of arguments [uid=%d]", getuid ());
+      fprintf (stderr, "polkit-agent-helper-1: wrong number of arguments. This incident has been logged.\n");
+      goto error;
+    }
+
+  if (getuid () != 0)
+    {
+    /* check we're running with a non-tty stdin */
+    if (isatty (STDIN_FILENO) != 0)
+      {
+        syslog (LOG_NOTICE, "inappropriate use of helper, stdin is a tty [uid=%d]", getuid ());
+        fprintf (stderr, "polkit-agent-helper-1: inappropriate use of helper, stdin is a tty. This incident has been logged.\n");
+        goto error;
+      }
+    }
+
+  user_to_auth = argv[1];
+  cookie = argv[2];
+
+#ifdef PAH_DEBUG
+  fprintf (stderr, "polkit-agent-helper-1: user to auth is '%s'.\n", user_to_auth);
+#endif /* PAH_DEBUG */
+
+
+  /* Ask shadow about the user requesting authentication */
+  shadow = getspnam (user_to_auth);
+
+  if (shadow == NULL)
+    {
+      syslog (LOG_NOTICE, "shadow file data information request for user '%s' [uid=%d] failed", user_to_auth, getuid ());
+      fprintf(stderr, "polkit-agent-helper-1: could not get shadow information for '%s'", user_to_auth);
+      goto error;
+    }
+
+  /* Check the user's identity */
+  if (shadow_authenticate (shadow) == FALSE)
+    {
+      syslog (LOG_NOTICE, "authentication failure [uid=%d] trying to authenticate '%s'", getuid (), user_to_auth);
+      fprintf (stderr, "polkit-agent-helper-1: authentication failure. This incident has been logged.\n");
+      goto error;
+    }
+
+  /* Check whether the user's password has expired */
+  now = time (NULL);
+  if (shadow->sp_max >= 0 && (shadow->sp_lstchg + shadow->sp_max) * 60 * 60 * 24 <= now)
+    {
+      syslog (LOG_NOTICE, "password expired for user '%s' [uid=%d] trying to authenticate", user_to_auth, getuid ());
+      fprintf (stderr, "polkit-agent-helper-1: authorization failure. This incident has been logged.\n");
+      goto error;
+    }
+
+  /* Check whether the user's password has aged (and account expired along
+   * with it)
+   */
+  if (shadow->sp_inact >= 0 && (shadow->sp_lstchg + shadow->sp_max + shadow->sp_inact) * 60 * 60 * 24 <= now)
+    {
+      syslog (LOG_NOTICE, "password aged for user '%s' [uid=%d] trying to authenticate", user_to_auth, getuid ());
+      fprintf (stderr, "polkit-agent-helper-1: authorization failure. This incident has been logged.\n");
+      goto error;
+    }
+
+  /* Check whether the user's account has expired */
+  if (shadow->sp_expire >= 0 && shadow->sp_expire * 60 * 60 * 24 <= now)
+    {
+      syslog (LOG_NOTICE, "account expired for user '%s' [uid=%d] trying to authenticate", user_to_auth, getuid ());
+      fprintf (stderr, "polkit-agent-helper-1: authorization failure. This incident has been logged.\n");
+      goto error;
+    }
+
+#ifdef PAH_DEBUG
+  fprintf (stderr, "polkit-agent-helper-1: sending D-Bus message to PolicyKit daemon\n");
+#endif /* PAH_DEBUG */
+
+  /* now send a D-Bus message to the PolicyKit daemon that
+   * includes a) the cookie; and b) the user we authenticated
+   */
+  if (!send_dbus_message (cookie, user_to_auth))
+    {
+#ifdef PAH_DEBUG
+      fprintf (stderr, "polkit-agent-helper-1: error sending D-Bus message to PolicyKit daemon\n");
+#endif /* PAH_DEBUG */
+      goto error;
+    }
+
+#ifdef PAH_DEBUG
+  fprintf (stderr, "polkit-agent-helper-1: successfully sent D-Bus message to PolicyKit daemon\n");
+#endif /* PAH_DEBUG */
+
+  fprintf (stdout, "SUCCESS\n");
+  flush_and_wait ();
+  return 0;
+
+error:
+  fprintf (stdout, "FAILURE\n");
+  flush_and_wait ();
+  return 1;
+}
+
+static gboolean
+shadow_authenticate (struct spwd *shadow)
+{
+  char passwd[512], *crypt_pass;
+
+  fprintf (stdout, "PAM_PROMPT_ECHO_OFF password:\n");
+  fflush (stdout);
+  usleep (10 * 1000); /* since fflush(3) seems buggy */
+
+  if (fgets (passwd, sizeof (passwd), stdin) == NULL)
+    goto error;
+
+  if (strlen (passwd) > 0 && passwd[strlen (passwd) - 1] == '\n')
+    passwd[strlen (passwd) - 1] = '\0';
+
+  /* Use the encrypted password as the salt, according to the crypt(3) man page,
+   * it will perform whatever encryption method is specified in /etc/shadow
+   */
+  crypt_pass = crypt (passwd, shadow->sp_pwdp);
+
+  if (crypt_pass == NULL)
+    goto error;
+
+  if (strcmp (shadow->sp_pwdp, crypt (passwd, shadow->sp_pwdp)) != 0)
+    goto error;
+  return 1;
+error:
+  return 0;
+}
diff --git a/src/polkitagent/polkitagenthelper.c b/src/polkitagent/polkitagenthelper.c
deleted file mode 100644
index cca86db..0000000
--- a/src/polkitagent/polkitagenthelper.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Copyright (C) 2008 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: David Zeuthen <davidz at redhat.com>
- */
-
-#include "config.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <syslog.h>
-#include <security/pam_appl.h>
-
-#include <polkit/polkit.h>
-
-#ifdef HAVE_SOLARIS
-#  define LOG_AUTHPRIV    (10<<3)
-#endif
-
-#ifndef HAVE_CLEARENV
-extern char **environ;
-
-static int
-clearenv (void)
-{
-	if (environ != NULL)
-		environ[0] = NULL;
-	return 0;
-}
-#endif
-
-/* Development aid: define PAH_DEBUG to get debugging output. Do _NOT_
- * enable this in production builds; it may leak passwords and other
- * sensitive information.
- */
-#undef PAH_DEBUG
-// #define PAH_DEBUG
-
-static gboolean send_dbus_message (const char *cookie, const char *user);
-
-static int conversation_function (int n, const struct pam_message **msg, struct pam_response **resp, void *data);
-
-int
-main (int argc, char *argv[])
-{
-  int rc;
-  const char *user_to_auth;
-  const char *cookie;
-  struct pam_conv pam_conversation;
-  pam_handle_t *pam_h;
-  const void *authed_user;
-
-  rc = 0;
-  pam_h = NULL;
-
-  /* clear the entire environment to avoid attacks using with libraries honoring environment variables */
-  if (clearenv () != 0)
-    goto error;
-
-  /* set a minimal environment */
-  setenv ("PATH", "/usr/sbin:/usr/bin:/sbin:/bin", 1);
-
-  /* check that we are setuid root */
-  if (geteuid () != 0)
-    {
-      fprintf (stderr, "polkit-agent-helper-1: needs to be setuid root\n");
-      goto error;
-    }
-
-  openlog ("polkit-agent-helper-1", LOG_CONS | LOG_PID, LOG_AUTHPRIV);
-
-  /* check for correct invocation */
-  if (argc != 3)
-    {
-      syslog (LOG_NOTICE, "inappropriate use of helper, wrong number of arguments [uid=%d]", getuid ());
-      fprintf (stderr, "polkit-agent-helper-1: wrong number of arguments. This incident has been logged.\n");
-      goto error;
-    }
-
-  user_to_auth = argv[1];
-  cookie = argv[2];
-
-  if (getuid () != 0)
-    {
-      /* check we're running with a non-tty stdin */
-      if (isatty (STDIN_FILENO) != 0)
-        {
-          syslog (LOG_NOTICE, "inappropriate use of helper, stdin is a tty [uid=%d]", getuid ());
-          fprintf (stderr, "polkit-agent-helper-1: inappropriate use of helper, stdin is a tty. This incident has been logged.\n");
-          goto error;
-        }
-    }
-
-#ifdef PAH_DEBUG
-  fprintf (stderr, "polkit-agent-helper-1: user to auth is '%s'.\n", user_to_auth);
-#endif /* PAH_DEBUG */
-
-  pam_conversation.conv        = conversation_function;
-  pam_conversation.appdata_ptr = NULL;
-
-  /* start the pam stack */
-  rc = pam_start ("polkit-1",
-                  user_to_auth,
-                  &pam_conversation,
-                  &pam_h);
-  if (rc != PAM_SUCCESS)
-    {
-      fprintf (stderr, "polkit-agent-helper-1: pam_start failed: %s\n", pam_strerror (pam_h, rc));
-      goto error;
-    }
-
-  /* set the requesting user */
-  rc = pam_set_item (pam_h, PAM_RUSER, user_to_auth);
-  if (rc != PAM_SUCCESS)
-    {
-      fprintf (stderr, "polkit-agent-helper-1: pam_set_item failed: %s\n", pam_strerror (pam_h, rc));
-      goto error;
-    }
-
-  /* is user really user? */
-  rc = pam_authenticate (pam_h, 0);
-  if (rc != PAM_SUCCESS)
-    {
-      fprintf (stderr, "polkit-agent-helper-1: pam_authenticated failed: %s\n", pam_strerror (pam_h, rc));
-      goto error;
-    }
-
-  /* permitted access? */
-  rc = pam_acct_mgmt (pam_h, 0);
-  if (rc != PAM_SUCCESS)
-    {
-      fprintf (stderr, "polkit-agent-helper-1: pam_acct_mgmt failed: %s\n", pam_strerror (pam_h, rc));
-      goto error;
-    }
-
-  /* did we auth the right user? */
-  rc = pam_get_item (pam_h, PAM_USER, &authed_user);
-  if (rc != PAM_SUCCESS)
-    {
-      fprintf (stderr, "polkit-agent-helper-1: pam_get_item failed: %s\n", pam_strerror (pam_h, rc));
-      goto error;
-    }
-
-  if (strcmp (authed_user, user_to_auth) != 0)
-    {
-      fprintf (stderr, "polkit-agent-helper-1: Tried to auth user '%s' but we got auth for user '%s' instead",
-               user_to_auth, (const char *) authed_user);
-      goto error;
-    }
-
-#ifdef PAH_DEBUG
-  fprintf (stderr, "polkit-agent-helper-1: successfully authenticated user '%s'.\n", user_to_auth);
-#endif /* PAH_DEBUG */
-
-  pam_end (pam_h, rc);
-  pam_h = NULL;
-
-#ifdef PAH_DEBUG
-  fprintf (stderr, "polkit-agent-helper-1: sending D-Bus message to PolicyKit daemon\n");
-#endif /* PAH_DEBUG */
-
-  /* now send a D-Bus message to the PolicyKit daemon that
-   * includes a) the cookie; and b) the user we authenticated
-   */
-  if (!send_dbus_message (cookie, user_to_auth))
-    {
-#ifdef PAH_DEBUG
-      fprintf (stderr, "polkit-agent-helper-1: error sending D-Bus message to PolicyKit daemon\n");
-#endif /* PAH_DEBUG */
-      goto error;
-    }
-
-#ifdef PAH_DEBUG
-  fprintf (stderr, "polkit-agent-helper-1: successfully sent D-Bus message to PolicyKit daemon\n");
-#endif /* PAH_DEBUG */
-
-  fprintf (stdout, "SUCCESS\n");
-  fflush (stdout);
-  fflush (stderr);
-  usleep (10 * 1000); /* since fflush(3) seems buggy */
-  return 0;
-
-error:
-  if (pam_h != NULL)
-    pam_end (pam_h, rc);
-
-  fprintf (stdout, "FAILURE\n");
-  fflush (stdout);
-  fflush (stderr);
-  usleep (10 * 1000); /* since fflush(3) seems buggy */
-  return 1;
-}
-
-static int
-conversation_function (int n, const struct pam_message **msg, struct pam_response **resp, void *data)
-{
-  struct pam_response *aresp;
-  char buf[PAM_MAX_RESP_SIZE];
-  int i;
-
-  data = data;
-  if (n <= 0 || n > PAM_MAX_NUM_MSG)
-    return PAM_CONV_ERR;
-
-  if ((aresp = calloc(n, sizeof *aresp)) == NULL)
-    return PAM_BUF_ERR;
-
-  for (i = 0; i < n; ++i)
-    {
-      aresp[i].resp_retcode = 0;
-      aresp[i].resp = NULL;
-      switch (msg[i]->msg_style)
-        {
-
-        case PAM_PROMPT_ECHO_OFF:
-          fprintf (stdout, "PAM_PROMPT_ECHO_OFF ");
-          goto conv1;
-
-        case PAM_PROMPT_ECHO_ON:
-          fprintf (stdout, "PAM_PROMPT_ECHO_ON ");
-        conv1:
-          fputs (msg[i]->msg, stdout);
-          if (strlen (msg[i]->msg) > 0 && msg[i]->msg[strlen (msg[i]->msg) - 1] != '\n')
-            fputc ('\n', stdout);
-          fflush (stdout);
-
-          if (fgets (buf, sizeof buf, stdin) == NULL)
-            goto error;
-
-          if (strlen (buf) > 0 &&
-              buf[strlen (buf) - 1] == '\n')
-            buf[strlen (buf) - 1] = '\0';
-
-          aresp[i].resp = strdup (buf);
-          if (aresp[i].resp == NULL)
-            goto error;
-          break;
-
-        case PAM_ERROR_MSG:
-          fprintf (stdout, "PAM_ERROR_MSG ");
-          goto conv2;
-
-        case PAM_TEXT_INFO:
-          fprintf (stdout, "PAM_TEXT_INFO ");
-        conv2:
-          fputs (msg[i]->msg, stdout);
-          if (strlen (msg[i]->msg) > 0 &&
-              msg[i]->msg[strlen (msg[i]->msg) - 1] != '\n')
-            fputc ('\n', stdout);
-          fflush (stdout);
-          break;
-
-        default:
-          goto error;
-        }
-    }
-
-  *resp = aresp;
-  return PAM_SUCCESS;
-
-error:
-
-  for (i = 0; i < n; ++i)
-    {
-      if (aresp[i].resp != NULL) {
-        memset (aresp[i].resp, 0, strlen(aresp[i].resp));
-        free (aresp[i].resp);
-      }
-    }
-  memset (aresp, 0, n * sizeof *aresp);
-  *resp = NULL;
-  return PAM_CONV_ERR;
-}
-
-static gboolean
-send_dbus_message (const char *cookie, const char *user)
-{
-  PolkitAuthority *authority;
-  PolkitIdentity *identity;
-  GError *error;
-  gboolean ret;
-
-  ret = FALSE;
-
-  error = NULL;
-
-  g_type_init ();
-
-  authority = polkit_authority_get ();
-
-  identity = polkit_unix_user_new_for_name (user, &error);
-  if (identity == NULL)
-    {
-      g_printerr ("Error constructing identity: %s\n", error->message);
-      g_error_free (error);
-      goto out;
-    }
-
-  if (!polkit_authority_authentication_agent_response_sync (authority,
-                                                            cookie,
-                                                            identity,
-                                                            NULL,
-                                                            &error))
-    {
-      g_printerr ("polkit-agent-helper-1: error response to PolicyKit daemon: %s\n", error->message);
-      g_error_free (error);
-      goto out;
-    }
-
-  ret = TRUE;
-
- out:
-
-  if (identity != NULL)
-    g_object_unref (identity);
-
-  if (authority != NULL)
-    g_object_unref (authority);
-
-  return ret;
-}
diff --git a/src/polkitagent/polkitagenthelperprivate.c b/src/polkitagent/polkitagenthelperprivate.c
new file mode 100644
index 0000000..be495e9
--- /dev/null
+++ b/src/polkitagent/polkitagenthelperprivate.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2009-2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors: David Zeuthen <davidz at redhat.com>,
+ *          Andrew Psaltis <ampsaltis at gmail.com>
+ */
+
+#include "config.h"
+#include "polkitagenthelperprivate.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifndef HAVE_CLEARENV
+extern char **environ;
+
+int
+_polkit_clearenv (void)
+{
+  if (environ != NULL)
+    environ[0] = NULL;
+  return 0;
+}
+#else
+int
+_polkit_clearenv (void)
+{
+  return clearenv ();
+}
+#endif
+
+
+gboolean
+send_dbus_message (const char *cookie, const char *user)
+{
+  PolkitAuthority *authority;
+  PolkitIdentity *identity;
+  GError *error;
+  gboolean ret;
+
+  ret = FALSE;
+
+  error = NULL;
+
+  g_type_init ();
+
+  authority = polkit_authority_get ();
+
+  identity = polkit_unix_user_new_for_name (user, &error);
+  if (identity == NULL)
+    {
+      g_printerr ("Error constructing identity: %s\n", error->message);
+      g_error_free (error);
+      goto out;
+    }
+
+  if (!polkit_authority_authentication_agent_response_sync (authority,
+                                                            cookie,
+                                                            identity,
+                                                            NULL,
+                                                            &error))
+    {
+      g_printerr ("polkit-agent-helper-1: error response to PolicyKit daemon: %s\n", error->message);
+      g_error_free (error);
+      goto out;
+    }
+
+  ret = TRUE;
+
+ out:
+
+  if (identity != NULL)
+    g_object_unref (identity);
+
+  if (authority != NULL)
+    g_object_unref (authority);
+
+  return ret;
+}
+
+/* fflush(3) stdin and stdout and wait a little bit.
+ * This replaces the three-line commands at the bottom of
+ * polkit-agent-helper-1's main() function.
+ */
+void
+flush_and_wait ()
+{
+  fflush (stdout);
+  fflush (stderr);
+  usleep (10 * 1000); /* since fflush(3) seems buggy */
+}
diff --git a/src/polkitagent/polkitagenthelperprivate.h b/src/polkitagent/polkitagenthelperprivate.h
new file mode 100644
index 0000000..7294d46
--- /dev/null
+++ b/src/polkitagent/polkitagenthelperprivate.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009-2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors: David Zeuthen <davidz at redhat.com>,
+ *          Andrew Psaltis <ampsalits at gmail.com>
+ */
+#ifndef __POLKIT_AGENT_HELPER_PRIVATE_H
+#define __POLKIT_AGENT_HELPER_PRIVATE_H
+
+#define _GNU_SOURCE
+#include <polkit/polkit.h>
+
+/* Development aid: define PAH_DEBUG to get debugging output. Do _NOT_
+ * enable this in production builds; it may leak passwords and other
+ * sensitive information.
+ */
+#undef PAH_DEBUG
+// #define PAH_DEBUG
+
+#ifdef HAVE_SOLARIS
+#  define LOG_AUTHPRIV    (10<<3)
+#endif
+
+int _polkit_clearenv (void);
+
+gboolean send_dbus_message (const char *cookie, const char *user);
+
+void flush_and_wait ();
+
+#endif /* __POLKIT_AGENT_HELPER_PRIVATE_H */
diff --git a/src/programs/pkexec.c b/src/programs/pkexec.c
index 17c191e..b0193f4 100644
--- a/src/programs/pkexec.c
+++ b/src/programs/pkexec.c
@@ -34,7 +34,11 @@
 #include <grp.h>
 #include <pwd.h>
 #include <errno.h>
+
+#ifdef POLKIT_AUTHFW_PAM
 #include <security/pam_appl.h>
+#endif /* POLKIT_AUTHFW_PAM */
+
 #include <syslog.h>
 #include <stdarg.h>
 
@@ -115,6 +119,7 @@ log_message (gint     level,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+#ifdef POLKIT_AUTHFW_PAM
 static int
 pam_conversation_function (int n,
                            const struct pam_message **msg,
@@ -167,6 +172,7 @@ out:
     pam_end (pam_h, rc);
   return ret;
 }
+#endif /* POLKIT_AUTHFW_PAM */
 
 /* ---------------------------------------------------------------------------------------------------- */
 
@@ -741,10 +747,12 @@ main (int argc, char *argv[])
    * TODO: The question here is whether we should clear the limits before applying them?
    * As evident above, neither su(1) (and, for that matter, nor sudo(8)) does this.
    */
+#ifdef POLKIT_AUTHFW_PAM
   if (!open_session (pw->pw_name))
     {
       goto out;
     }
+#endif /* POLKIT_AUTHFW_PAM */
 
   /* become the user */
   if (setgroups (0, NULL) != 0)


More information about the hal-commit mailing list