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 */