Optimized querying by using single query and using asynch functions libpam-csc-1.2
authorDavid Bartley <dtbartle@csclub.uwaterloo.ca>
Wed, 8 Aug 2007 22:59:10 +0000 (18:59 -0400)
committerDavid Bartley <dtbartle@csclub.uwaterloo.ca>
Wed, 8 Aug 2007 22:59:10 +0000 (18:59 -0400)
Added preliminary code for detecting CS accounts
Refactored variable names to use underscores instead of camel-case
Prefixed helper functions with pam_csc_
Added -g to compiler flags

Makefile
debian/changelog
debian/control
debian/docs
debian/rules
pam_csc.c

index f08c234..2db17f8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,11 @@
 CC=gcc
 CC=gcc
-CFLAGS=-O2 -fPIC -Wall
-LDFLAGS=-shared -lpam -lldap
-LD=ld
+CFLAGS=-g -O2 -fPIC -Wall
+LDFLAGS=-g -shared -lpam -lldap
 
 all: pam_csc.so
 
 pam_csc.so: pam_csc.o
 
 all: pam_csc.so
 
 pam_csc.so: pam_csc.o
-       $(LD) -o $@ $(LDFLAGS) $<
+       $(CC) -o $@ $(LDFLAGS) $<
 
 clean:
        rm -f pam_csc.so pam_csc.o
 
 clean:
        rm -f pam_csc.so pam_csc.o
index 82eff95..1e08b6a 100644 (file)
@@ -1,3 +1,13 @@
+libpam-csc (1.2) stable testing; urgency=low
+
+  * Optimized querying by using single query and using asynch functions
+  * Added preliminary code for detecting CS accounts
+  * Refactored variable names to use underscores instead of camel-case
+  * Prefixed helper functions with pam_csc_
+  * Added -g to compiler flags
+
+ -- David Bartley <dtbartle@csclub.uwaterloo.ca>  Fri, 27 Jul 2007 13:17:35 -0400
+
 libpam-csc (1.1) unstable; urgency=low
 
   * Removed hardcoding of URI.
 libpam-csc (1.1) unstable; urgency=low
 
   * Removed hardcoding of URI.
index 8ea3148..bd5c0c5 100644 (file)
@@ -2,11 +2,11 @@ Source: libpam-csc
 Section: net
 Priority: optional
 Maintainer: David Bartley <dtbartle@csclub.uwaterloo.ca>
 Section: net
 Priority: optional
 Maintainer: David Bartley <dtbartle@csclub.uwaterloo.ca>
-Build-Depends: debhelper (>= 4.0.0), libldap-dev, libpam0g-dev
+Build-Depends: debhelper (>= 4.0.0), libldap2-dev, libpam0g-dev, libsasl2-dev
 Standards-Version: 3.7.2
 
 Package: libpam-csc
 Architecture: any
 Depends: ${shlibs:Depends}, ${misc:Depends}
 Standards-Version: 3.7.2
 
 Package: libpam-csc
 Architecture: any
 Depends: ${shlibs:Depends}, ${misc:Depends}
-Description: Custom CSC PAM module to handle account expiration.
- Custom CSC PAM module to handle account expiration.
+Description: CSC PAM module to handle account expiration.
+ CSC PAM module to handle account expiration.
index 1333ed7..e69de29 100644 (file)
@@ -1 +0,0 @@
-TODO
index 0d37306..40542fc 100755 (executable)
@@ -33,9 +33,7 @@ build: build-stamp
 build-stamp: configure-stamp 
        dh_testdir
 
 build-stamp: configure-stamp 
        dh_testdir
 
-       # Add here commands to compile the package.
        $(MAKE)
        $(MAKE)
-       #docbook-to-man debian/libpam-csc.sgml > libpam-csc.1
 
        touch $@
 
 
        touch $@
 
@@ -44,8 +42,7 @@ clean:
        dh_testroot
        rm -f build-stamp configure-stamp
 
        dh_testroot
        rm -f build-stamp configure-stamp
 
-       # Add here commands to clean up after the build process.
-       -$(MAKE) clean
+       $(MAKE) clean
 
        dh_clean 
 
 
        dh_clean 
 
@@ -56,9 +53,6 @@ install: build-stamp
        dh_installdirs
        install -m 644 pam_csc.so $(CURDIR)/debian/libpam-csc/lib/security
 
        dh_installdirs
        install -m 644 pam_csc.so $(CURDIR)/debian/libpam-csc/lib/security
 
-       # Add here commands to install the package into debian/libpam-csc.
-#      $(MAKE) DESTDIR=$(CURDIR)/debian/libpam-csc install
-
 
 # Build architecture-independent files here.
 binary-indep: build install
 
 # Build architecture-independent files here.
 binary-indep: build install
index d0c026e..c7274dc 100644 (file)
--- a/pam_csc.c
+++ b/pam_csc.c
@@ -5,24 +5,54 @@
 #include <time.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <string.h>
 #include <security/pam_modules.h>
 #include <security/pam_appl.h>
 #include <ldap.h>
 #include <string.h>
 #include <security/pam_modules.h>
 #include <security/pam_appl.h>
 #include <ldap.h>
+#include <sasl/sasl.h>
 #include <syslog.h>
 #include <pwd.h>
 
 #include <syslog.h>
 #include <pwd.h>
 
-#define PAM_CSC_LDAP_USER_BASE_DN       "ou=People,dc=csclub,dc=uwaterloo,dc=ca"
-#define PAM_CSC_LDAP_GROUP_BASE_DN      "ou=Group,dc=csclub,dc=uwaterloo,dc=ca"
-#define PAM_CSC_LDAP_TIMEOUT            5
-#define PAM_CSC_ALLOWED_GROUPS          "cn=staff"
-#define PAM_CSC_MINIMUM_UID             1000
+/* TODO
+ *
+ * We need to create a cronjob (that runs on logon and every hour) to run
+ * 'kinit -p TODO@STUDENT.CS.UWATERLOO.CA -k -c /tmp/krb5cc_pam_csc'
+ *
+ * We also need to add a keytab entry for TODO@STUDENT.CS.UWATERLOO.CA
+ *
+ */
+
+#define PAM_CSC_CSC_BASE_DN         "ou=People,dc=csclub,dc=uwaterloo,dc=ca"
+#define PAM_CSC_CSCF_URI \
+    "ldaps://eponina.student.cs.uwaterloo.ca" \
+    "ldaps://canadenis.student.cs.uwaterloo.ca"
+#define PAM_CSC_CSCF_BASE_DN        "dc=student,dc=cs,dc=uwateloo,dc=ca"
+#define PAM_CSC_CSCF_BIND_DN \
+    "uid=TODO,dc=student,dc=cs,dc=uwaterloo,dc=ca"
+#define PAM_CSC_KRB5CCNAME          "/tmp/krb5cc_pam_csc"
+#define PAM_CSC_CSCF_SASL_USER \
+    "dn:uid=TODO,cn=STUDENT.CS.UWATERLOO.CA,cn=GSSAPI,cn=auth"
+#define PAM_CSC_CSCF_SASL_REALM     "STUDENT.CS.UWATERLOO.CA"
+#define PAM_CSC_LDAP_TIMEOUT        5
+#define PAM_CSC_MINIMUM_UID         1000
 #define PAM_CSC_EXPIRED_MSG \
     "*****************************************************************************\n" \
     "*                                                                           *\n" \
     "*    Your account has expired - please contact the Computer Science Club    *\n" \
     "*                                                                           *\n" \
     "*****************************************************************************\n"
 #define PAM_CSC_EXPIRED_MSG \
     "*****************************************************************************\n" \
     "*                                                                           *\n" \
     "*    Your account has expired - please contact the Computer Science Club    *\n" \
     "*                                                                           *\n" \
     "*****************************************************************************\n"
+#define PAM_CSC_CSCF_DISALLOWED_MSG \
+    "You are not registered as a CS student - login denied."
+
+#define PAM_CSC_SYSLOG_EXPIRED_WARNING \
+    "(pam_csc): %s was not registered for current term or previous term - denying login\n"
+#define PAM_CSC_SYSLOG_EXPIRED_ERROR \
+    "(pam_csc): %s was not registered for current term but was registered for previous term - permitting login\n"
+#define PAM_CSC_SYSLOG_CSCF_DISALLOWED \
+    "(pam_csc): %s is using a CSCF machine but is not enrolled in CS - denying login\n"
+#define PAM_CSC_SYSLOG_SASL_UNRECOGNIZED_CALLBACK \
+    "(pam_csc): %ld is not a recognized SASL callback option\n"
 
 /*
  * User terms are defined as (3 * year + term) where term is:
 
 /*
  * User terms are defined as (3 * year + term) where term is:
  * Term is a string in the form [f|w|s][year]
  */
 
  * Term is a string in the form [f|w|s][year]
  */
 
-enum check_user_type_t
-{
-    check_user_exists,
-    check_user_cur_term,
-    check_user_prev_term,
-    check_user_groups
-};
-
 #define HANDLE_WARN \
 { \
     syslog(LOG_AUTHPRIV | LOG_WARNING, "pam_csc generated a warning on line %d of %s\n", __LINE__, __FILE__); \
 #define HANDLE_WARN \
 { \
     syslog(LOG_AUTHPRIV | LOG_WARNING, "pam_csc generated a warning on line %d of %s\n", __LINE__, __FILE__); \
@@ -57,124 +79,78 @@ enum check_user_type_t
 #define WARN_LDAP(x) \
     if( (x) != LDAP_SUCCESS ) HANDLE_WARN
 
 #define WARN_LDAP(x) \
     if( (x) != LDAP_SUCCESS ) HANDLE_WARN
 
-char* escape_ldap_string(const char* src)
+struct pam_csc_sasl_interact_param
 {
 {
-    char *dst, *dstPtr;
-    int i;
-
-    if(!(dst = malloc(2 * strlen(src) + 1)))
-        return NULL;
-    dstPtr = dst;
+    const char* realm;
+    const char* user;
+};
+typedef struct pam_csc_sasl_interact_param pam_csc_sasl_interact_param_t;
 
 
-    for(i = 0; i < strlen(src); i++)
+int pam_csc_sasl_interact(LDAP* ld, unsigned flags, void* def, void* inter)
+{
+    pam_csc_sasl_interact_param_t* param = (pam_csc_sasl_interact_param_t*)def;
+    sasl_interact_t* interact = (sasl_interact_t*)interact;
+    while(interact->id != SASL_CB_LIST_END)
     {
     {
-        if(src[i] == '*' || src[i] == '(' || src[i] == ')' || src[i] == '\\')
+        switch(interact->id)
         {
         {
-            dstPtr[0] = '\\';
-            dstPtr++;
+        case SASL_CB_GETREALM:
+            interact->result = param->realm;
+            interact->len = strlen(param->realm);
+        case SASL_CB_USER:
+            interact->result = param->user;
+            interact->len = strlen(param->user);
+            break;
+        default:
+            syslog(LOG_AUTHPRIV | LOG_NOTICE,
+                PAM_CSC_SYSLOG_SASL_UNRECOGNIZED_CALLBACK, interact->id);
+            interact->result = "";
+            interact->len = 0;
         }
         }
-        dstPtr[0] = src[i];
-        dstPtr++;
     }
     }
-    dstPtr[0] = '\0';
 
 
-    return dst;
+    return LDAP_SUCCESS;
 }
 
 }
 
-int check_user(const char* username, enum check_user_type_t checkType)
+char* pam_csc_escape_ldap_string(const char* src)
 {
 {
-    int retval = PAM_SUCCESS;
-    time_t curTime;
-    struct tm* localTime;
-    int longTerm, year, term;
-    LDAP* ld = NULL;
-    static const char termChars[] = {'w', 's', 'f'};
-    char* usernameEscaped = NULL;
-    char* filter = NULL;
-    char* attr[] = {"objectClass", NULL};
-    struct timeval timeout = {PAM_CSC_LDAP_TIMEOUT, 0};
-    LDAPMessage* res = NULL;
-    char* baseDN = NULL;
-
-    /* fail-safe for root */
-    if(strcmp(username, "root") == 0)
-    {
-        return PAM_SUCCESS;
-    }
+    char *dst, *dst_ptr;
+    int i;
 
 
-    /* connect and bind */
-    WARN_LDAP( ldap_create(&ld) )
-    WARN_NEG1( ldap_simple_bind(ld, NULL, NULL) )
+    if(!(dst = malloc(2 * strlen(src) + 1)))
+        return NULL;
+    dst_ptr = dst;
 
 
-    WARN_ZERO( usernameEscaped = escape_ldap_string(username) );
-    switch(checkType)
+    for(i = 0; i < strlen(src); i++)
     {
     {
-    case check_user_exists:
-
-        /* format filter */
-        WARN_ZERO( filter = malloc(50 + strlen(usernameEscaped)) )
-        sprintf(filter, "(uid=%s)", usernameEscaped);
-        baseDN = PAM_CSC_LDAP_USER_BASE_DN;
-        break;
-
-    case check_user_prev_term:
-    case check_user_cur_term:
-
-        /* get term info and compute current and previous term */
-        WARN_NEG1( curTime = time(NULL) )
-        WARN_ZERO( localTime = localtime(&curTime) )
-        longTerm = 3 * (1900 + localTime->tm_year) + (localTime->tm_mon / 4);
-        if(checkType == check_user_prev_term)
-            longTerm--;
-        term = termChars[longTerm % 3];
-        year = longTerm / 3;
-
-        /* format filter */
-        WARN_ZERO( filter = malloc(100 + strlen(usernameEscaped)) )
-        sprintf(filter, "(&(uid=%s)(|(&(objectClass=member)(term=%c%d))(!(objectClass=member))))", 
-            usernameEscaped, term, year);
-        baseDN = PAM_CSC_LDAP_USER_BASE_DN;
-        break;
-
-    case check_user_groups:
-
-        /* format filter */
-        WARN_ZERO( filter = malloc(50 + strlen(PAM_CSC_ALLOWED_GROUPS) + strlen(usernameEscaped)) )
-        sprintf(filter, "(&(objectClass=posixGroup)(%s)(memberUid=%s))", PAM_CSC_ALLOWED_GROUPS, usernameEscaped);
-        baseDN = PAM_CSC_LDAP_GROUP_BASE_DN;
-        break;
+        if(src[i] == '*' || src[i] == '(' || src[i] == ')' || src[i] == '\\')
+        {
+            dst_ptr[0] = '\\';
+            dst_ptr++;
+        }
+        dst_ptr[0] = src[i];
+        dst_ptr++;
     }
     }
+    dst_ptr[0] = '\0';
 
 
-    /* search */
-    WARN_LDAP( ldap_search_st(ld, baseDN, LDAP_SCOPE_SUBTREE, filter, attr, 1, &timeout, &res) )
-    if((term = ldap_count_entries(ld, res)) == 0)
-        retval = PAM_AUTH_ERR;
-
-cleanup:
-
-    if(usernameEscaped) free(usernameEscaped);
-    if(res) ldap_msgfree(res);
-    if(filter) free(filter);
-    if(ld) ldap_unbind(ld);
-
-    return retval;
+    return dst;
 }
 
 }
 
-int print_pam_message(pam_handle_t* pamh, char* msg, int style)
+int pam_csc_print_message(pam_handle_t* pamh, char* msg, int style)
 {
     int retval = PAM_SUCCESS;
 {
     int retval = PAM_SUCCESS;
-    struct pam_conv* pamConv;
-    struct pam_message pamMessage;
-    struct pam_message* pamMessages[1];
-    struct pam_response* pamResponse;
+    struct pam_conv* conv;
+    struct pam_message message;
+    struct pam_message* messages[1];
+    struct pam_response* response;
 
     /* output message */
 
     /* output message */
-    WARN_PAM( pam_get_item(pamh, PAM_CONV, (const void**)&pamConv) )
-    pamMessages[0] = &pamMessage;
-    pamMessage.msg_style = style;
-    pamMessage.msg = msg;
-    WARN_PAM( pamConv->conv(1, (const struct pam_message**)pamMessages, 
-        &pamResponse, pamConv->appdata_ptr) )
+    WARN_PAM( pam_get_item(pamh, PAM_CONV, (void**)&conv) )
+    messages[0] = &message;
+    message.msg_style = style;
+    message.msg = msg;
+    WARN_PAM( conv->conv(1, (const struct pam_message**)messages, 
+        &response, conv->appdata_ptr) )
 
 cleanup:
 
 
 cleanup:
 
@@ -183,8 +159,27 @@ cleanup:
 
 PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char* argv[])
 {
 
 PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char* argv[])
 {
+    int retval = PAM_SUCCESS;
     const char* username;
     struct passwd* pwd;
     const char* username;
     struct passwd* pwd;
+    time_t cur_time;
+    struct tm* local_time;
+    int long_term;
+    static const char term_chars[] = {'w', 's', 'f'};
+    char cur_term[6], prev_term[6];
+    LDAP *ld_csc = NULL, *ld_cscf = NULL;
+    bool cscf;
+    char* username_escaped = NULL;
+    char *filter_csc = NULL, *filter_cscf = NULL;
+    char *attrs_csc[] = {"objectClass", "term", NULL}, 
+        *attrs_cscf[] = {"objectClass", NULL};
+    bool expired;
+    const char* pam_rhost;
+    int msg_csc, msg_cscf;
+    LDAPMessage *res_csc = NULL, *res_cscf = NULL;
+    struct timeval timeout = {PAM_CSC_LDAP_TIMEOUT, 0};
+    LDAPMessage* entry = NULL;
+    char **values = NULL, **values_iter = NULL;
 
     /* determine username */
     if((pam_get_user(pamh, &username, NULL) != PAM_SUCCESS) || !username)
 
     /* determine username */
     if((pam_get_user(pamh, &username, NULL) != PAM_SUCCESS) || !username)
@@ -199,39 +194,135 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const c
         return PAM_SUCCESS;
     }
 
         return PAM_SUCCESS;
     }
 
-    /* check if user exists in ldap */
-    if(check_user(username, check_user_exists) == PAM_AUTH_ERR)
+    /* escape username */
+    WARN_ZERO( username_escaped = pam_csc_escape_ldap_string(username) );
+
+    /* get term info and compute current and previous term */
+    WARN_NEG1( cur_time = time(NULL) )
+    WARN_ZERO( local_time = localtime(&cur_time) )
+    long_term = 3 * (1900 + local_time->tm_year) + (local_time->tm_mon / 4);
+    sprintf(cur_term, "%c%d", term_chars[long_term % 3], long_term / 3);
+    long_term--;
+    sprintf(prev_term, "%c%d", term_chars[long_term % 3], long_term / 3);
+
+    /* connect to CSC */
+    WARN_LDAP( ldap_create(&ld_csc) )
+    WARN_NEG1( ldap_simple_bind(ld_csc, NULL, NULL) )
+
+    /* check if we are logging in from a CSCF teaching thin client */
+    cscf = false;
+    if(pam_get_item(pamh, PAM_RHOST, (void**)&pam_rhost) && pam_rhost)
     {
     {
-        return PAM_SUCCESS;
+        /* TODO: check pam_rhost
+         * It appears that the thin clients all have hostnames of the form
+         * tc[0-9]+\.cs
+         */
     }
 
     }
 
-    /* check if user is registered for the current term */
-    if(check_user(username, check_user_cur_term) == PAM_SUCCESS)
+    if(cscf)
     {
     {
-        return PAM_SUCCESS;
+        /* set krb5 cache location */
+        setenv("KRB5CCNAME", PAM_CSC_KRB5CCNAME, 1);
+
+        /* connect to CSCF */
+        pam_csc_sasl_interact_param_t interact_param = {
+            PAM_CSC_CSCF_SASL_REALM,
+            PAM_CSC_CSCF_SASL_USER,
+        };
+        WARN_LDAP( ldap_initialize(&ld_cscf, PAM_CSC_CSCF_URI) )
+        WARN_NEG1( ldap_sasl_interactive_bind_s(ld_cscf, PAM_CSC_CSCF_BIND_DN,
+            "GSSAPI", NULL, NULL, LDAP_SASL_INTERACTIVE | LDAP_SASL_QUIET,
+            pam_csc_sasl_interact, &interact_param) )
     }
 
     }
 
-    /* check if user is registered for the previous term */
-    if(check_user(username, check_user_prev_term) == PAM_SUCCESS)
+    /* create CSC request string */
+    WARN_ZERO( filter_csc = malloc(100 + strlen(username_escaped)) )
+    sprintf(filter_csc, "(&(uid=%s)(|(&(objectClass=member)(|(term=%s)(term=%s)))(!(objectClass=member))))", username_escaped, cur_term, prev_term);
+
+    /* issue CSC request */
+    WARN_NEG1( msg_csc = ldap_search(ld_csc, PAM_CSC_CSC_BASE_DN, 
+        LDAP_SCOPE_SUBTREE, filter_csc, attrs_csc, 0) )
+
+    if(cscf)
     {
     {
-        /* show warning */
-        syslog(LOG_AUTHPRIV | LOG_NOTICE, "(pam_csc): %s was not registered for current term but was registered for previous term - permitting login\n", username);
-        print_pam_message(pamh, PAM_CSC_EXPIRED_MSG, PAM_TEXT_INFO);
-        return PAM_SUCCESS;
+        /* create CSCF request string */
+        WARN_ZERO( filter_cscf = malloc(100 + strlen(username_escaped)) )
+        sprintf(filter_csc, "TODO %s", username_escaped);
+
+        /* issue CSCF request */
+        WARN_NEG1( msg_cscf = ldap_search(ld_cscf, PAM_CSC_CSCF_BASE_DN, 
+            LDAP_SCOPE_SUBTREE, filter_cscf, attrs_cscf, 1) )
     }
 
     }
 
-    /* check if user is in allowed groups */
-    if(check_user(username, check_user_groups) == PAM_SUCCESS)
+    /* wait for CSC response */
+    WARN_NEG1( ldap_result(ld_csc, msg_csc, 1, &timeout, &res_csc) )
+
+    /* check if we received an entry from CSC */
+    if(ldap_count_entries(ld_csc, res_csc) == 0)
     {
     {
-        /* show warning */
-        print_pam_message(pamh, PAM_CSC_EXPIRED_MSG, PAM_TEXT_INFO);
-        syslog(LOG_AUTHPRIV | LOG_NOTICE, "(pam_csc): %s was not registered but was in allowed groups - permitting login\n", username);
-        return PAM_SUCCESS;
+        /* show notice and disallow login */
+        pam_csc_print_message(pamh, PAM_CSC_EXPIRED_MSG, PAM_ERROR_MSG);
+        syslog(LOG_AUTHPRIV | LOG_NOTICE, PAM_CSC_SYSLOG_EXPIRED_WARNING, 
+            username);
+        retval = PAM_AUTH_ERR;
+        goto cleanup;
     }
 
     }
 
-    /* account has expired - show prompt */
-    print_pam_message(pamh, PAM_CSC_EXPIRED_MSG, PAM_ERROR_MSG);
-    syslog(LOG_AUTHPRIV | LOG_NOTICE, "(pam_csc): %s was not registered and was not in allowed groups - denying login\n", username);
+    /* get CSC entry */
+    WARN_ZERO( entry = ldap_first_entry(ld_csc, res_csc) )
+    WARN_ZERO( values = ldap_get_values(ld_csc, entry, "term") )
 
 
-    return PAM_AUTH_ERR;
+    /* iterate through term attributes */
+    expired = true;
+    values_iter = values;
+    while(*values_iter)
+    {
+        if(strcmp(*values_iter, cur_term) == 0)
+        {
+            /* user is registered in current term */
+            expired = false;
+            break;
+        }
+        values_iter++;
+    }
+
+    /* check if account is expired */
+    if(expired)
+    {
+        /* show notice and continue */
+        pam_csc_print_message(pamh, PAM_CSC_EXPIRED_MSG, PAM_TEXT_INFO);
+        syslog(LOG_AUTHPRIV | LOG_NOTICE, PAM_CSC_SYSLOG_EXPIRED_ERROR, 
+            username);
+    }
+
+    if(cscf)
+    {
+        /* wait for CSCF response */
+        WARN_NEG1( ldap_result(ld_cscf, msg_cscf, 1, &timeout, &res_cscf) )
+
+        /* check if we got an entry back from CSCF */
+        if(ldap_count_entries(ld_cscf, res_cscf) == 0)
+        {
+            /* output CSCF disallowed message */
+            pam_csc_print_message(pamh, PAM_CSC_CSCF_DISALLOWED_MSG, 
+                PAM_ERROR_MSG);
+            syslog(LOG_AUTHPRIV | LOG_NOTICE, PAM_CSC_SYSLOG_CSCF_DISALLOWED, 
+                username);
+            retval = PAM_AUTH_ERR;
+            goto cleanup;
+        }
+    }
+
+cleanup:
+
+    if(values) ldap_value_free(values);
+    if(res_csc) ldap_msgfree(res_csc);
+    if(res_cscf) ldap_msgfree(res_cscf);
+    if(ld_csc) ldap_unbind(ld_csc);
+    if(ld_cscf) ldap_unbind(ld_cscf);
+    if(filter_csc) free(filter_csc);
+    if(filter_cscf) free(filter_cscf);
+    if(username_escaped) free(username_escaped);
+
+    return retval;
 }
 }