commit-inetutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Inetutils branch, master, updated. inetutils-1_9_1-97-gbc4a16


From: Mats Erik Andersson
Subject: [SCM] GNU Inetutils branch, master, updated. inetutils-1_9_1-97-gbc4a16b
Date: Mon, 21 May 2012 16:08:04 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Inetutils ".

The branch, master has been updated
       via  bc4a16bcd250c497340ac7d22c3d8bd4c2a0531e (commit)
      from  481c0ccc01b8d6d6328dbc85835b689ecc3531fe (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://git.savannah.gnu.org/cgit/inetutils.git/commit/?id=bc4a16bcd250c497340ac7d22c3d8bd4c2a0531e


commit bc4a16bcd250c497340ac7d22c3d8bd4c2a0531e
Author: Mats Erik Andersson <address@hidden>
Date:   Mon May 21 12:31:53 2012 +0200

    rexecd: Implement PAM support.

diff --git a/ChangeLog b/ChangeLog
index 368af76..057b10c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2012-05-21  Mats Erik Andersson  <address@hidden>
+
+       rexecd: Adapt to PAM authentication.
+
+       * src/Makefile.am (rexecd_LDADD): Use $(LIBPAM).
+       * src/rexecd.c [HAVE_SECURITY_PAM_APPL_H]: Include
+       <security/pam_appl.h>.
+       (pam_rc, password_pam, pam_flags, pam_handle, pam_conv)
+       [WITH_PAM]: New variables.
+       (rexec_conv) [WITH_PAM]: New function.
+       (remotehost): New variable, used in environment.
+       (envinit) [!WITH_PAM]: Add `remotehost' to list.
+       (doit) [WITH_PAM]: New variable TOKEN.  Add alternate
+       authentication checks.  Set `pam_rc = PAM_ABORT' where
+       errors are caught.
+       <parent fork>: Set `pam_handle' to NULL, since the child
+       process closes all authentication.
+       (die) [WITH_PAM]: Call pam_end() if PAM is still active.
+       * doc/inetutils.texi (rexecd invocation): Update.
+
 2012-05-20  Mats Erik Andersson  <address@hidden>
 
        rexecd: Use getpwnam_r() if available, thus
diff --git a/doc/inetutils.texi b/doc/inetutils.texi
index de7d8f7..2d81a83 100644
--- a/doc/inetutils.texi
+++ b/doc/inetutils.texi
@@ -3399,7 +3399,7 @@ useful in an ``open'' environment.
 @chapter @command{rexecd}: server for @code{rexec}
 @cindex rexecd
 
address@hidden is the server for the @code{Rexec} routine.  The
address@hidden is the server for the @code{rexec} routine.  The
 server provides remote execution facilities with authentication based
 on user names and passwords.  It passes error messages and notices
 to the @code{syslog} facility @samp{LOG_DAEMON}.
@@ -3465,6 +3465,9 @@ increased verbosity.  The @code{syslog} facility in use is
 
 @end table
 
+Should @command{rexecd} have been built with PAM support,
+it reads any setting specified for a service named @samp{rexec}.
+
 @section Diagnostics
 
 Except for the last one listed below, all diagnostic messages are
diff --git a/src/Makefile.am b/src/Makefile.am
index a98272b..75d5e6c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -74,7 +74,7 @@ EXTRA_PROGRAMS += inetd
 
 inetdaemon_PROGRAMS += $(rexecd_BUILD)
 rexecd_SOURCES = rexecd.c
-rexecd_LDADD = $(LDADD) $(LIBCRYPT)
+rexecd_LDADD = $(LDADD) $(LIBCRYPT) $(LIBPAM)
 EXTRA_PROGRAMS += rexecd
 
 inetdaemon_PROGRAMS += $(rlogind_BUILD)
diff --git a/src/rexecd.c b/src/rexecd.c
index d4d0220..0236a5d 100644
--- a/src/rexecd.c
+++ b/src/rexecd.c
@@ -47,8 +47,17 @@
  * SUCH DAMAGE.
  */
 
-/* TODO: Implement PAM support as `rexec' service.
- *       Pending with Mats Erik Andersson.
+/* Implementation of PAM support for a service `rexec'
+ * was done by Mats Erik Andersson.
+ *
+ * Simple PAM configuration:
+ *
+ *   rexec auth     requisite  pam_nologin.so
+ *   rexec auth     required   pam_unix.so
+ *   rexec account  required   pam_unix.so
+ *   rexec account  required   pam_time.so
+ *   rexec session  required   pam_unix.so
+ *   rexec password required   pam_deny.so
  */
 
 #include <config.h>
@@ -83,6 +92,9 @@
 # include <shadow.h>
 #endif
 #include <syslog.h>
+#ifdef HAVE_SECURITY_PAM_APPL_H
+# include <security/pam_appl.h>
+#endif
 #ifdef HAVE_GETPWNAM_R
 # include <xalloc.h>
 #endif
@@ -95,6 +107,17 @@
 void die (int code, const char *fmt, ...);
 int doit (int f, struct sockaddr *fromp, socklen_t fromlen);
 
+#ifdef WITH_PAM
+static int pam_rc = PAM_AUTH_ERR;      /* doit() and die() */
+static char *password_pam = NULL;      /* doit() and rexec_conv() */
+static int pam_flags = PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK;
+
+static pam_handle_t *pam_handle = NULL;                /* doit() and die() */
+static int rexec_conv (int, const struct pam_message **,
+                      struct pam_response **, void *);
+static struct pam_conv pam_conv = { rexec_conv, NULL };
+#endif /* WITH_PAM */
+
 static int logging = 0;
 
 static struct argp_option options[] = {
@@ -173,7 +196,11 @@ char logname[32 + sizeof ("LOGNAME=")] = "LOGNAME=";       
/* Identical to USER.  */
 char homedir[256 + sizeof ("HOME=")] = "HOME=";
 char shell[256 + sizeof ("SHELL=")] = "SHELL=";
 char path[sizeof (PATH_DEFPATH) + sizeof ("PATH=")] = "PATH=";
-char *envinit[] = { homedir, shell, path, username, logname, NULL };
+char remotehost[128 + sizeof ("RHOST=")] = "RHOST=";
+#ifndef WITH_PAM
+char *envinit[] = { homedir, shell, path, username,
+                   logname, remotehost, NULL };
+#endif
 extern char **environ;
 
 char *getstr (const char *);
@@ -195,6 +222,9 @@ doit (int f, struct sockaddr *fromp, socklen_t fromlen)
 {
   char *cmdbuf, *cp, *namep;
   char *user, *pass, *pw_password;
+#ifdef WITH_PAM
+  const void *token;
+#endif
 #ifdef HAVE_GETPWNAM_R
   char *pwbuf;
   int pwbuflen;
@@ -322,6 +352,7 @@ doit (int f, struct sockaddr *fromp, socklen_t fromlen)
 
   endpwent ();
 
+#if !WITH_PAM
   /* Last need of elevated privilege.  */
   pw_password = get_user_password (pwd);
   if (*pw_password != '\0')
@@ -334,6 +365,61 @@ doit (int f, struct sockaddr *fromp, socklen_t fromlen)
          die (EXIT_FAILURE, "Password incorrect.");
        }
     }
+#else /* WITH_PAM */
+  /* Failure at this stage should not disclose server side causes,
+   * but only fail almost silently.  Use "Try again" for now.
+   */
+  password_pam = pass;         /* Needed by pam_conv().  */
+
+  pam_rc = pam_start ("rexec", user, &pam_conv, &pam_handle);
+  if (pam_rc != PAM_SUCCESS)
+    die (EXIT_FAILURE, "Try again.");
+
+  pam_rc = pam_set_item (pam_handle, PAM_RHOST, rhost);
+  if (pam_rc != PAM_SUCCESS)
+    die (EXIT_FAILURE, "Try again.");
+
+  pam_rc = pam_authenticate (pam_handle, pam_flags);
+  if (pam_rc != PAM_SUCCESS)
+    {
+      switch (pam_rc)
+       {
+       case PAM_ABORT:
+         /* This is potentially severe.  No communication!  */
+         pam_end (pam_handle, pam_rc);
+         exit (EXIT_FAILURE);
+         break;
+       case PAM_AUTHINFO_UNAVAIL:
+       case PAM_CRED_INSUFFICIENT:
+       case PAM_USER_UNKNOWN:
+         die (EXIT_FAILURE, "Login incorrect.");
+         break;
+       case PAM_AUTH_ERR:
+       case PAM_MAXTRIES:
+       default:
+         die (EXIT_FAILURE, "Password incorrect.");
+         break;
+       }
+    }
+
+  pam_rc = pam_acct_mgmt (pam_handle, pam_flags);
+  if (pam_rc != PAM_SUCCESS)
+    {
+      switch (pam_rc)
+       {
+       case PAM_NEW_AUTHTOK_REQD:
+       case PAM_PERM_DENIED:
+         die (EXIT_FAILURE, "Password incorrect.");
+         break;
+       case PAM_ACCT_EXPIRED:
+       case PAM_AUTH_ERR:
+       case PAM_USER_UNKNOWN:
+       default:
+         die (EXIT_FAILURE, "Login incorrect.");
+         break;
+       }
+    }
+#endif /* WITH_PAM */
 
   /* Step down from superuser personality.
    *
@@ -343,6 +429,9 @@ doit (int f, struct sockaddr *fromp, socklen_t fromlen)
    */
   if (setgid ((gid_t) pwd->pw_gid) < 0)
     {
+#ifdef WITH_PAM
+      pam_rc = PAM_ABORT;
+#endif
       syslog (LOG_DEBUG, "setgid(gid = %d): %m", pwd->pw_gid);
       die (EXIT_FAILURE, "Failed group protections.");
     }
@@ -350,14 +439,30 @@ doit (int f, struct sockaddr *fromp, socklen_t fromlen)
 #ifdef HAVE_INITGROUPS
   if (initgroups (pwd->pw_name, pwd->pw_gid) < 0)
     {
+# ifdef WITH_PAM
+      pam_rc = PAM_ABORT;
+# endif
       syslog (LOG_DEBUG, "initgroups(%s, %s): %m",
              pwd->pw_name, pwd->pw_gid);
       die (EXIT_FAILURE, "Failed group protections.");
     }
 #endif
 
+#ifdef WITH_PAM
+  pam_rc = pam_setcred(pam_handle, PAM_ESTABLISH_CRED);
+  if (pam_rc != PAM_SUCCESS)
+    {
+      syslog (LOG_ERR, "pam_setcred: %s",
+             pam_strerror (pam_handle, pam_rc));
+      pam_rc = PAM_SUCCESS;    /* Only report the above anomaly.  */
+    }
+#endif /* WITH_PAM */
+
   if (setuid ((uid_t) pwd->pw_uid) < 0)
     {
+#ifdef WITH_PAM
+      pam_rc = PAM_ABORT;
+#endif
       syslog (LOG_DEBUG, "setuid(uid = %d): %m", pwd->pw_uid);
       die (EXIT_FAILURE, "Failed user identity.");
     }
@@ -370,11 +475,22 @@ doit (int f, struct sockaddr *fromp, socklen_t fromlen)
        {
          if (logging)
            syslog (LOG_ERR, "forking for \"%s\": %m", user);
+#ifdef WITH_PAM
+         pam_rc = PAM_ABORT;
+#endif
          die (EXIT_FAILURE, "Try again.");
        }
 
       if (pid)
        {
+#ifdef WITH_PAM
+         /* This process steps down from PAM now,
+          * the child continues communication.  */
+         pam_handle = NULL;
+# ifdef PAM_DATA_SILENT
+         pam_rc |= PAM_DATA_SILENT;
+# endif
+#endif /* WITH_PAM */
          close (STDIN_FILENO);
          close (STDOUT_FILENO);
          close (STDERR_FILENO);
@@ -432,15 +548,58 @@ doit (int f, struct sockaddr *fromp, socklen_t fromlen)
     {
       if (logging)
        syslog (LOG_NOTICE, "\"%s\" uses invalid \"%s\"", user, pwd->pw_dir);
+#ifdef WITH_PAM
+      pam_rc = PAM_ABORT;
+#endif
       die (EXIT_FAILURE, "No remote directory.");
     }
 
+#ifdef WITH_PAM
+  /* Refresh knowledge of user, which might have been
+   * remapped by the PAM stack during conversation.
+   */
+  pam_rc = pam_get_item (pam_handle, PAM_USER, &token);
+  if (pam_rc != PAM_SUCCESS)
+    die (EXIT_FAILURE, "Try again.");
+
+# ifdef HAVE_GETPWNAM_R
+  ret = getpwnam_r (user, &pwstor, pwbuf, pwbuflen, &pwd);
+  if (ret || pwd == NULL)
+# else /* !HAVE_GETPWNAM_R */
+  pwd = getpwnam (user);
+  if (pwd == NULL)
+# endif /* HAVE_GETPWNAM_R */
+    {
+      syslog (LOG_ERR, "no user named \"%s\"", user);
+      die (EXIT_FAILURE, "Login incorrect.");
+    }
+#endif /* WITH_PAM */
+
   strcat (path, PATH_DEFPATH);
-  environ = envinit;
   strncat (homedir, pwd->pw_dir, sizeof (homedir) - sizeof ("HOME=") - 1);
   strncat (shell, pwd->pw_shell, sizeof (shell) - sizeof ("SHELL=") - 1);
   strncat (username, pwd->pw_name, sizeof (username) - sizeof ("USER=") - 1);
   strncat (logname, pwd->pw_name, sizeof (logname) - sizeof ("LOGNAME=") - 1);
+  strncat (remotehost, rhost, sizeof (remotehost) - sizeof ("RHOST=") - 1);
+
+#ifdef WITH_PAM
+  if (pam_getenv (pam_handle, "PATH") == NULL)
+    (void) pam_putenv (pam_handle, path);
+  if (pam_getenv (pam_handle, "HOME") == NULL)
+    (void) pam_putenv (pam_handle, homedir);
+  if (pam_getenv (pam_handle, "SHELL") == NULL)
+    (void) pam_putenv (pam_handle, shell);
+  if (pam_getenv (pam_handle, "USER") == NULL)
+    (void) pam_putenv (pam_handle, username);
+  if (pam_getenv (pam_handle, "LOGNAME") == NULL)
+    (void) pam_putenv (pam_handle, logname);
+  if (pam_getenv (pam_handle, "RHOST") == NULL)
+    (void) pam_putenv (pam_handle, remotehost);
+
+  environ = pam_getenvlist (pam_handle);
+#else /* !WITH_PAM */
+  environ = envinit;
+#endif /* !WITH_PAM */
 
   if (*pwd->pw_shell == '\0')
     pwd->pw_shell = PATH_BSHELL;
@@ -482,6 +641,10 @@ die (int code, const char *fmt, ...)
     n = sizeof buf - 1;
   buf[n++] = '\n';
   write (STDERR_FILENO, buf, n);
+#ifdef WITH_PAM
+  if (pam_handle != NULL)
+    pam_end (pam_handle, pam_rc);
+#endif
   exit (code);
 }
 
@@ -522,3 +685,46 @@ getstr (const char *err)
 
   return buf;
 }
+
+#ifdef WITH_PAM
+/* Call back function for passing user's password
+ * to any PAM module requesting this information.
+ */
+static int
+rexec_conv (int num, const struct pam_message **pam_msg,
+           struct pam_response **pam_resp, void *data)
+{
+  struct pam_response *resp;
+
+  /* Reject composite call-backs.  */
+  if (num <= 0 || num > 1)
+    return PAM_CONV_ERR;
+
+  /* We only accept password reporting.  */
+  if (pam_msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)
+    return PAM_CONV_ERR;
+
+  /* Allocate a single response structure,
+   * as we are ignoring composite calls.
+   *
+   * This is an external call-back, so we check
+   * for successful allocation ourselves.
+   */
+  resp = malloc (sizeof (*resp));
+  if (resp == NULL)
+    return PAM_BUF_ERR;
+
+  /* Prepare response to a single PAM_PROMPT_ECHO_OFF.  */
+  resp->resp_retcode = 0;
+  resp->resp = strdup (password_pam);
+  if (resp->resp == NULL)
+    {
+      free (resp);
+      return PAM_BUF_ERR;
+    }
+
+  *pam_resp = resp;
+
+  return PAM_SUCCESS;
+}
+#endif /* WITH_PAM */

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog          |   20 +++++
 doc/inetutils.texi |    5 +-
 src/Makefile.am    |    2 +-
 src/rexecd.c       |  214 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 235 insertions(+), 6 deletions(-)


hooks/post-receive
-- 
GNU Inetutils 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]