Package: libpam-ldap
Tags: patch upstream

        Hi!

We (Helsinki University of Technology) have been using a patch for libpam-ldap for a couple of years (4+) now, and I'd really like to get it in the official package. Here's a description by the author (ie. not me):

- Two new configuration options:
  - pam_require_fqdn, allow matching host to either fully qualified
    domain name or short hostname.
  - pam_require_host_group, match against freely specified hostgroup
    to gain access. Looked up from host attribute.
  - Can work either way at the same time

- Introduces directly LDAP speaking variants of two internal
  functions, _has_deny_value / _has_value. authorizedService
  and host attributes are compared on the server side, thus
  allowing to set somewhat more strict ACL's to those attributes
  if wanted, and possibly saving some network bandwidth..
- Disable some old code replaced by use of _ldap_cmp_has_deny_value
  and _ldap_cmp_has_value.

It was sent upstream but got no feedback (link to the patch is broken now):

http://bugzilla.padl.com/show_bug.cgi?id=172



t
diff -ruN libpam-ldap-178.orig/ldap.conf libpam-ldap-178/ldap.conf
--- libpam-ldap-178.orig/ldap.conf	2005-03-24 02:00:04.000000000 +0200
+++ libpam-ldap-178/ldap.conf	2005-04-25 10:22:22.000000000 +0300
@@ -84,6 +84,14 @@
 # then the user will not be allowed to login.
 #pam_check_host_attr yes
 
+# Require the 'host' attribute value to be FQDN address
+#pam_require_fqdn yes
+
+# Alternatively, instead of automatically determined
+# hostname, you can specify a group that the user must
+# have to gain access.
+#pam_require_host_group @admin
+
 # Check the 'authorizedService' attribute for access
 # control
 # Default is no; if set to yes, and the user has no
diff -ruN libpam-ldap-178.orig/pam_ldap.c libpam-ldap-178/pam_ldap.c
--- libpam-ldap-178.orig/pam_ldap.c	2005-04-25 10:19:29.000000000 +0300
+++ libpam-ldap-178/pam_ldap.c	2005-04-25 10:21:07.000000000 +0300
@@ -486,6 +486,11 @@
       free (c->tmpluser);
     }
 
+  if (c->requirehostgroup != NULL)
+    {
+      free (c->requirehostgroup);
+    }
+
   if (c->groupattr != NULL)
     {
       free (c->groupattr);
@@ -540,6 +545,7 @@
   _pam_overwrite ((*info)->userpw);
   _pam_drop ((*info)->userpw);
 
+#if 0
   if ((*info)->hosts_allow != NULL)
     {
       ldap_value_free ((*info)->hosts_allow);
@@ -549,6 +555,7 @@
     {
       ldap_value_free ((*info)->services_allow);
     }
+#endif
 
   if ((*info)->tmpluser != NULL)
     {
@@ -638,6 +645,8 @@
   result->groupdn = NULL;
   result->getpolicy = 0;
   result->checkhostattr = 0;
+  result->requirefqdn = 1;
+  result->requirehostgroup = NULL;
   result->checkserviceattr = 0;
 #ifdef LDAP_VERSION3
   result->version = LDAP_VERSION3;
@@ -1028,6 +1037,14 @@
 	{
 	  result->checkhostattr = !strcasecmp (v, "yes");
 	}
+      else if (!strcasecmp (k, "pam_require_fqdn"))
+	{
+	  result->requirefqdn = !strcasecmp (v, "yes");
+	}
+      else if (!strcasecmp (k, "pam_require_host_group"))
+	{
+	  CHECKPOINTER (result->requirehostgroup = strdup (v));
+	}
       else if (!strcasecmp (k, "pam_check_service_attr"))
 	{
 	  result->checkserviceattr = !strcasecmp (v, "yes");
@@ -2210,16 +2227,48 @@
 }
 
 static int
+_ldap_cmp_has_deny_value (pam_ldap_session_t * session, const char *attr, const char *tgt)
+{
+  int rc;
+  char buf[1024];
+
+  snprintf(buf, sizeof(buf), "!%s", tgt);
+  rc = ldap_compare_s (session->ld, session->info->userdn, attr, buf);
+#if 0
+  fprintf(stderr, "_ldap_cmp_has_deny_value: %s (rc %i)\n", buf, rc);
+#endif
+  if (rc == LDAP_COMPARE_TRUE)
+    return 1;
+  return 0;
+}
+
+static int
+_ldap_cmp_has_value (pam_ldap_session_t * session, const char *attr, const char *tgt)
+{
+  int rc;
+
+  rc = ldap_compare_s (session->ld, session->info->userdn, attr, tgt);
+#if 0
+  fprintf(stderr, "_ldap_cmp_has_value: %s (rc %i)\n", tgt, rc);
+#endif
+  if (rc == LDAP_COMPARE_TRUE)
+    return 1;
+  return 0;
+}
+
+static int
 _service_ok (pam_handle_t * pamh, pam_ldap_session_t * session)
 {
   int rc;
   char *service = NULL;
 
+#if 0
   /* simple host based access authorization */
   if (session->info->services_allow == NULL)
     {
       return PAM_PERM_DENIED;
     }
+#endif
 
   rc = pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &service);
   if (rc != PAM_SUCCESS)
@@ -2229,21 +2278,21 @@
 
   if (service != NULL)
     {
-      if (_has_deny_value (session->info->services_allow, service))
+      if (_ldap_cmp_has_deny_value (session, "authorizedService", service))
 	return PAM_PERM_DENIED;
-      else if (_has_value (session->info->services_allow, service))
+      else if (_ldap_cmp_has_value (session, "authorizedService", service))
 	return PAM_SUCCESS;
     }
 
   /* allow wild-card entries */
-  return (_has_value (session->info->services_allow, "*")) ? PAM_SUCCESS :
+  return (_ldap_cmp_has_value (session, "authorizedService", "*")) ? PAM_SUCCESS :
     PAM_PERM_DENIED;
 }
 
 static int
 _host_ok (pam_ldap_session_t * session)
 {
-  char hostname[MAXHOSTNAMELEN];
+  char hostname[MAXHOSTNAMELEN], *p;
   struct hostent *h;
 #ifdef HAVE_GETHOSTBYNAME_R
   struct hostent hbuf;
@@ -2256,11 +2305,13 @@
 #endif /* HAVE_GETHOSTBYNAME_R */
   char **q;
 
+#if 0
   /* simple host based access authorization */
   if (session->info->hosts_allow == NULL)
     {
       return PAM_PERM_DENIED;
     }
+#endif
 
 
   if (gethostname (hostname, sizeof hostname) < 0)
@@ -2297,24 +2348,46 @@
     }
 #endif
 
-  if (_has_deny_value (session->info->hosts_allow, h->h_name))
+  if (_ldap_cmp_has_deny_value(session, "host", h->h_name))
     return PAM_PERM_DENIED;
-  else if (_has_value (session->info->hosts_allow, h->h_name))
+  else if (_ldap_cmp_has_value(session, "host", h->h_name))
     return PAM_SUCCESS;
 
   if (h->h_aliases != NULL)
     {
       for (q = h->h_aliases; *q != NULL; q++)
 	{
-	  if (_has_value (session->info->hosts_allow, *q))
+	  if (_ldap_cmp_has_value(session, "host", *q))
 	    return PAM_SUCCESS;
-	  if (_has_deny_value (session->info->hosts_allow, *q))
+	  if (_ldap_cmp_has_deny_value(session, "host", *q))
 	    return PAM_PERM_DENIED;
 	}
     }
 
+  if (!session->conf->requirefqdn)
+    {
+      /* check for truncated hostname */
+      memset(hostname, MAXHOSTNAMELEN, 0);
+      strncpy(hostname, h->h_name, MAXHOSTNAMELEN);
+      if ((p = strchr(hostname, '.')))
+        *p = '\0';
+      if (_ldap_cmp_has_deny_value(session, "host", hostname))
+        return PAM_PERM_DENIED;
+      else if (_ldap_cmp_has_value(session, "host", hostname))
+        return PAM_SUCCESS;
+    }
+
+  if (session->conf->requirehostgroup != NULL)
+    {
+      /* check for group specified in the configuration file */
+      if (_ldap_cmp_has_deny_value(session, "host", session->conf->requirehostgroup))
+        return PAM_PERM_DENIED;
+      else if (_ldap_cmp_has_value(session, "host", session->conf->requirehostgroup))
+        return PAM_SUCCESS;
+    }
+
   /* allow wild-card entries */
-  if (_has_value (session->info->hosts_allow, "*"))
+  if (_ldap_cmp_has_value(session, "host", "*"))
     {
       return PAM_SUCCESS;
     }
@@ -2538,9 +2611,11 @@
    * it might be better to do a compare later, that way we can
    * avoid fetching any attributes at all
    */
+#if 0
   _get_string_values (session->ld, msg, "host", &session->info->hosts_allow);
   _get_string_values (session->ld, msg, "authorizedService",
 		      &session->info->services_allow);
+#endif
 
   /* get UID */
 #ifdef UID_NOBODY
diff -ruN libpam-ldap-178.orig/pam_ldap.h libpam-ldap-178/pam_ldap.h
--- libpam-ldap-178.orig/pam_ldap.h	2005-03-24 02:00:04.000000000 +0200
+++ libpam-ldap-178/pam_ldap.h	2005-04-25 10:20:04.000000000 +0300
@@ -89,6 +89,10 @@
     int getpolicy;
     /* host attribute checking, for access authorization */
     int checkhostattr;
+    /* require FQDN address for host attribute checking */
+    int requirefqdn;
+    /* required group for host attribute checking */
+    char *requirehostgroup;
     /* service attribute checking, for access authorization */
     int checkserviceattr;
     /* group name; optional, for access authorization */
@@ -233,9 +237,11 @@
     char *userdn;
     /* temporary cache of user's bind credentials for rebind function */
     char *userpw;
+#if 0
     /* host attribute from account objectclass */
     char **hosts_allow;
     char **services_allow;
+#endif
     /* seconds until password expires */
     long password_expiration_time;
     /* grace logins remaining */

Reply via email to