]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
ext_kerberos_ldap_group_acl: -n option to disable automated SASL/GSSAPI
authorMarkus Moeller <huaraz@moeller.plus.com>
Wed, 29 Oct 2014 04:47:53 +0000 (21:47 -0700)
committerAmos Jeffries <squid3@treenet.co.nz>
Wed, 29 Oct 2014 04:47:53 +0000 (21:47 -0700)
The -n option disables the automated Kerberos authentication
(SASL/GSSAPI) to AD and requires username/password (SASL/SIMPLE)
instead.

Also, improvements in caching Kerberos credentials for setup with low
Squid cache TTL.

helpers/external_acl/kerberos_ldap_group/kerberos_ldap_group.cc
helpers/external_acl/kerberos_ldap_group/support.h
helpers/external_acl/kerberos_ldap_group/support_krb5.cc
helpers/external_acl/kerberos_ldap_group/support_ldap.cc

index f186cb06fc412fd1c5accc6f8d1e8e0925d474e6..37b7841b766d32743b1d597c435b59ed007a3d95 100644 (file)
 #include "support.h"
 #include <cctype>
 
+#if HAVE_KRB5
+struct kstruct kparam;
+#endif
+
 void
 init_args(struct main_args *margs)
 {
@@ -61,6 +65,7 @@ init_args(struct main_args *margs)
     margs->rc_allow = 0;
     margs->AD = 0;
     margs->mdepth = 5;
+    margs->nokerberos = 0;
     margs->ddomain = NULL;
     margs->groups = NULL;
     margs->ndoms = NULL;
@@ -173,13 +178,18 @@ main(int argc, char *const argv[])
     char *nuser, *nuser8 = NULL, *netbios;
     int opt;
     struct main_args margs;
+#if HAVE_KRB5
+    krb5_error_code code = 0;
+
+    kparam.context = NULL;
+#endif
 
     setbuf(stdout, NULL);
     setbuf(stdin, NULL);
 
     init_args(&margs);
 
-    while (-1 != (opt = getopt(argc, argv, "diasg:D:N:S:u:U:t:T:p:l:b:m:h"))) {
+    while (-1 != (opt = getopt(argc, argv, "diasng:D:N:S:u:U:t:T:p:l:b:m:h"))) {
         switch (opt) {
         case 'd':
             debug_enabled = 1;
@@ -193,6 +203,9 @@ main(int argc, char *const argv[])
         case 's':
             margs.ssl = (char *) "yes";
             break;
+        case 'n':
+            margs.nokerberos = 1;
+            break;
         case 'g':
             margs.glist = xstrdup(optarg);
             break;
@@ -236,6 +249,7 @@ main(int argc, char *const argv[])
             fprintf(stderr, "squid_kerb_ldap [-d] [-i] -g group list [-D domain] [-N netbios domain map] [-s] [-u ldap user] [-p ldap user password] [-l ldap url] [-b ldap bind path] [-a] [-m max depth] [-h]\n");
             fprintf(stderr, "-d full debug\n");
             fprintf(stderr, "-i informational messages\n");
+            fprintf(stderr, "-n do not use Kerberos to authenticate to AD. Requires -u , -p and -l option\n");
             fprintf(stderr, "-g group list\n");
             fprintf(stderr, "-t group list (only group name hex UTF-8 format)\n");
             fprintf(stderr, "-T group list (all in hex UTF-8 format - except seperator @)\n");
@@ -280,7 +294,7 @@ main(int argc, char *const argv[])
     if (create_gd(&margs)) {
         if ( margs.glist != NULL ) {
             debug((char *) "%s| %s: FATAL: Error in group list: %s\n", LogTime(), PROGRAM, margs.glist ? margs.glist : "NULL");
-            SEND_ERR("");
+            SEND_BH("");
             clean_args(&margs);
             exit(1);
         } else {
@@ -290,16 +304,36 @@ main(int argc, char *const argv[])
     }
     if (create_nd(&margs)) {
         debug((char *) "%s| %s: FATAL: Error in netbios list: %s\n", LogTime(), PROGRAM, margs.nlist ? margs.nlist : "NULL");
-        SEND_ERR("");
+        SEND_BH("");
         clean_args(&margs);
         exit(1);
     }
     if (create_ls(&margs)) {
         debug((char *) "%s| %s: Error in ldap server list: %s\n", LogTime(), PROGRAM, margs.llist ? margs.llist : "NULL");
-        SEND_ERR("");
+        SEND_BH("");
         clean_args(&margs);
         exit(1);
     }
+
+#if HAVE_KRB5
+    /*
+     * Initialise Kerberos
+     */
+
+    code = krb5_init_context(&kparam.context);
+    for (int i=0; i<MAX_DOMAINS; i++) {
+        kparam.mem_ccache[i]=NULL;
+        kparam.cc[i]=NULL;
+        kparam.ncache=0;
+    }
+    if (code) {
+        error((char *) "%s| %s: ERROR: Error while initialising Kerberos library : %s\n", LogTime(), PROGRAM, error_message(code));
+        SEND_BH("");
+        clean_args(&margs);
+        exit(1);
+    }
+#endif
+
     while (1) {
         char *c;
         if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
@@ -307,19 +341,25 @@ main(int argc, char *const argv[])
                 debug((char *) "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n", LogTime(), PROGRAM, ferror(stdin),
                       strerror(ferror(stdin)));
 
-                SEND_ERR("");
+                SEND_BH(strerror(ferror(stdin)));
                 clean_args(&margs);
+#if HAVE_KRB5
+                krb5_cleanup();
+#endif
                 exit(1);       /* BIIG buffer */
             }
-            SEND_ERR("");
+            SEND_BH("fgets NULL");
             clean_args(&margs);
+#if HAVE_KRB5
+            krb5_cleanup();
+#endif
             exit(0);
         }
         c = (char *) memchr(buf, '\n', sizeof(buf) - 1);
         if (c) {
             *c = '\0';
         } else {
-            SEND_ERR("Invalid input. CR missing");
+            SEND_BH("Invalid input. CR missing");
             debug((char *) "%s| %s: ERR\n", LogTime(), PROGRAM);
             continue;
         }
@@ -327,7 +367,7 @@ main(int argc, char *const argv[])
         user = strtok(buf, " \n");
         if (!user) {
             debug((char *) "%s| %s: INFO: No Username given\n", LogTime(), PROGRAM);
-            SEND_ERR("Invalid request. No Username");
+            SEND_BH("Invalid request. No Username");
             continue;
         }
         rfc1738_unescape(user);
@@ -381,6 +421,10 @@ main(int argc, char *const argv[])
         safe_free(dp);
         if (!strcmp(user, "QQ") && domain && !strcmp(domain, "QQ")) {
             clean_args(&margs);
+#if HAVE_KRB5
+            krb5_cleanup();
+#endif
+
             exit(-1);
         }
         if (gopt) {
@@ -393,12 +437,12 @@ main(int argc, char *const argv[])
                 }
                 margs.glist = xstrdup(group);
                 if (create_gd(&margs)) {
-                    SEND_ERR("Error in group list");
+                    SEND_BH("Error in group list");
                     debug((char *) "%s| %s: FATAL: Error in group list: %s\n", LogTime(), PROGRAM, margs.glist ? margs.glist : "NULL");
                     continue;
                 }
             } else {
-                SEND_ERR("No group list received on stdin");
+                SEND_BH("No group list received on stdin");
                 debug((char *) "%s| %s: FATAL: No group list received on stdin\n", LogTime(), PROGRAM);
                 continue;
             }
index fca5a0fbfe52f9eb435dbae1bf46c0edf53fb9b3..e762e1df4d354905705ebb3658db6bf8694cf370 100644 (file)
@@ -30,7 +30,7 @@
  * -----------------------------------------------------------------------------
  */
 
-#define KERBEROS_LDAP_GROUP_VERSION "1.3.1sq"
+#define KERBEROS_LDAP_GROUP_VERSION "1.4.0sq"
 
 #include <cstring>
 
@@ -60,16 +60,16 @@ extern "C" {
 #endif /* HAVE_COM_ERR_H */
 
 #define LDAP_DEPRECATED 1
-#ifdef HAVE_LDAP_REBIND_FUNCTION
+#if HAVE_LDAP_REBIND_FUNCTION
 #define LDAP_REFERRALS
 #endif
-#ifdef HAVE_LBER_H
+#if HAVE_LBER_H
 #include <lber.h>
 #endif
-#ifdef HAVE_LDAP_H
+#if HAVE_LDAP_H
 #include <ldap.h>
 #endif
-#ifdef HAVE_MOZLDAP_LDAP_H
+#if HAVE_MOZLDAP_LDAP_H
 #include <mozldap/ldap.h>
 #endif
 
@@ -103,6 +103,7 @@ struct main_args {
     int rc_allow;
     int AD;
     int mdepth;
+    int nokerberos;
     char *ddomain;
     struct gdstruct *groups;
     struct ndstruct *ndoms;
@@ -161,11 +162,6 @@ int create_gd(struct main_args *margs);
 int create_nd(struct main_args *margs);
 int create_ls(struct main_args *margs);
 
-#ifdef HAVE_KRB5
-int krb5_create_cache(char *domain);
-void krb5_cleanup(void);
-#endif
-
 size_t get_ldap_hostname_list(struct main_args *margs, struct hstruct **hlist, size_t nhosts, char *domain);
 size_t get_hostname_list(struct hstruct **hlist, size_t nhosts, char *name);
 size_t free_hostname_list(struct hstruct **hlist, size_t nhosts);
@@ -174,4 +170,17 @@ size_t free_hostname_list(struct hstruct **hlist, size_t nhosts);
 int tool_sasl_bind(LDAP * ld, char *binddn, char *ssl);
 #endif
 
+#if HAVE_KRB5
+#define MAX_DOMAINS 16
+#define MAX_SKEW 300
+struct kstruct {
+    krb5_context context;
+    krb5_ccache cc[MAX_DOMAINS];
+    char* mem_ccache[MAX_DOMAINS];
+    int ncache;
+};
+int krb5_create_cache(char *domain);
+void krb5_cleanup(void);
+#endif
+
 #define PROGRAM "kerberos_ldap_group"
index be9ab3df1eda3817f3e628051ec154e0a502a9ac..eb0bac05b52bfee30e7a32205f32c60d77bb47a7 100644 (file)
 
 #include "support.h"
 
-struct kstruct {
-    krb5_context context;
-    krb5_ccache cc;
-};
-
-static struct kstruct kparam;
+#if HAVE_KRB5
+extern struct kstruct kparam;
+#endif
 
 #define KT_PATH_MAX 256
 
 void
 krb5_cleanup()
 {
-    if (kparam.context) {
-        if (kparam.cc)
-            krb5_cc_destroy(kparam.context, kparam.cc);
-        krb5_free_context(kparam.context);
-    }
+    if (kparam.context)
+        for (int i=0; i<MAX_DOMAINS; i++) {
+            if (kparam.cc[i])
+                krb5_cc_destroy(kparam.context, kparam.cc[i]);
+            safe_free(kparam.mem_ccache[i]);
+        }
+    krb5_free_context(kparam.context);
 }
 /*
  * create Kerberos memory cache
@@ -62,9 +61,10 @@ int
 krb5_create_cache(char *domain)
 {
 
-    krb5_keytab keytab = 0;
+    krb5_keytab keytab = NULL;
     krb5_keytab_entry entry;
     krb5_kt_cursor cursor;
+    krb5_cc_cursor ccursor;
     krb5_creds *creds = NULL;
     krb5_principal *principal_list = NULL;
     krb5_principal principal = NULL;
@@ -74,272 +74,397 @@ krb5_create_cache(char *domain)
     size_t j,nprinc = 0;
     int retval = 0;
     krb5_error_code code = 0;
-
-    kparam.context = NULL;
+    int ccindex=-1;
 
     if (!domain || !strcmp(domain, ""))
         return (1);
 
-    /*
-     * Initialise Kerberos
-     */
-
-    code = krb5_init_context(&kparam.context);
-    if (code) {
-        error((char *) "%s| %s: ERROR: Error while initialising Kerberos library : %s\n", LogTime(), PROGRAM, error_message(code));
-        retval = 1;
-        goto cleanup;
-    }
     /*
      * prepare memory credential cache
      */
 #if  !HAVE_KRB5_MEMORY_CACHE || HAVE_SUN_LDAP_SDK
-    mem_cache = (char *) xmalloc(strlen("FILE:/tmp/squid_ldap_") + 16);
-    snprintf(mem_cache, strlen("FILE:/tmp/squid_ldap_") + 16, "FILE:/tmp/squid_ldap_%d", (int) getpid());
+    mem_cache = (char *) xmalloc(strlen("FILE:/tmp/squid_ldap_") + strlen(domain) + 1 + 16);
+    snprintf(mem_cache, strlen("FILE:/tmp/squid_ldap_") + strlen(domain) + 1 + 16, "FILE:/tmp/squid_ldap_%s_%d", domain, (int) getpid());
 #else
-    mem_cache = (char *) xmalloc(strlen("MEMORY:squid_ldap_") + 16);
-    snprintf(mem_cache, strlen("MEMORY:squid_ldap_") + 16, "MEMORY:squid_ldap_%d", (int) getpid());
+    mem_cache = (char *) xmalloc(strlen("MEMORY:squid_ldap_") + strlen(domain) + 1 + 16);
+    snprintf(mem_cache, strlen("MEMORY:squid_ldap_") + strlen(domain) + 1 + 16, "MEMORY:squid_ldap_%s_%d", domain, (int) getpid());
 #endif
 
     setenv("KRB5CCNAME", mem_cache, 1);
     debug((char *) "%s| %s: DEBUG: Set credential cache to %s\n", LogTime(), PROGRAM, mem_cache);
-    code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc);
-    if (code) {
-        error((char *) "%s| %s: ERROR: Error while resolving memory ccache : %s\n", LogTime(), PROGRAM, error_message(code));
-        retval = 1;
-        goto cleanup;
+    for (int i=0; i<MAX_DOMAINS; i++) {
+        if (kparam.mem_ccache[i] && !strcmp(mem_cache,kparam.mem_ccache[i])) {
+            ccindex=i;
+            break;
+        }
+    }
+    if ( ccindex == -1 ) {
+        kparam.mem_ccache[kparam.ncache]=strdup(mem_cache);
+        ccindex=kparam.ncache;
+        kparam.ncache++;
+        if ( kparam.ncache == MAX_DOMAINS ) {
+            error((char *) "%s| %s: ERROR: Too many domains to support: # domains %d\n", LogTime(), PROGRAM, kparam.ncache);
+            retval = 1;
+            goto cleanup;
+        }
+        code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc[ccindex]);
+        if (code) {
+            error((char *) "%s| %s: ERROR: Error while resolving memory ccache : %s\n", LogTime(), PROGRAM, error_message(code));
+            retval = 1;
+            goto cleanup;
+        }
     }
     /*
-     * getting default keytab name
+     * getting default principal from cache
      */
 
-    debug((char *) "%s| %s: DEBUG: Get default keytab file name\n", LogTime(), PROGRAM);
-    krb5_kt_default_name(kparam.context, buf, KT_PATH_MAX);
-    p = strchr(buf, ':');      /* Find the end if "FILE:" */
-    if (p)
-        ++p;                   /* step past : */
-    keytab_name = xstrdup(p ? p : buf);
-    debug((char *) "%s| %s: DEBUG: Got default keytab file name %s\n", LogTime(), PROGRAM, keytab_name);
-
-    code = krb5_kt_resolve(kparam.context, keytab_name, &keytab);
+    code = krb5_cc_get_principal(kparam.context, kparam.cc[ccindex], &principal);
     if (code) {
-        error((char *) "%s| %s: ERROR: Error while resolving keytab %s : %s\n", LogTime(), PROGRAM, keytab_name, error_message(code));
-        retval = 1;
-        goto cleanup;
+        if (principal)
+            krb5_free_principal(kparam.context, principal);
+        principal = NULL;
+        debug((char *) "%s| %s: DEBUG: No default principal found in ccache : %s\n", LogTime(), PROGRAM, error_message(code));
+
+    } else {
+        /*
+         * Look for krbtgt and check if it is expired (or soon to be expired)
+         */
+        code = krb5_cc_start_seq_get(kparam.context, kparam.cc[ccindex], &ccursor);
+        if (code) {
+            error((char *) "%s| %s: ERROR: Error while starting ccache scan : %s\n", LogTime(), PROGRAM, error_message(code));
+            code = krb5_cc_close (kparam.context, kparam.cc[ccindex]);
+            if (code) {
+                error((char *) "%s| %s: ERROR: while closing ccache : %s\n", LogTime(), PROGRAM, error_message(code));
+            }
+            if (kparam.cc[ccindex]) {
+                code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
+                if (code) {
+                    error((char *) "%s| %s: ERROR: while destroying ccache : %s\n", LogTime(), PROGRAM, error_message(code));
+                }
+            }
+        } else {
+            krb5_error_code code2 = 0;
+            creds = (krb5_creds *) xcalloc(1,sizeof(*creds));
+            while ((krb5_cc_next_cred(kparam.context, kparam.cc[ccindex], &ccursor, creds)) == 0) {
+                code2 = krb5_unparse_name(kparam.context, creds->server, &principal_name);
+                if (code2) {
+                    error((char *) "%s| %s: ERROR: Error while unparsing principal : %s\n", LogTime(), PROGRAM, error_message(code2));
+                    code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
+                    if (code) {
+                        error((char *) "%s| %s: ERROR: while destroying ccache : %s\n", LogTime(), PROGRAM, error_message(code));
+                    }
+                    if (creds)
+                        krb5_free_creds(kparam.context, creds);
+                    safe_free(creds);
+                    safe_free(principal_name);
+                    debug((char *) "%s| %s: DEBUG: Reset credential cache to %s\n", LogTime(), PROGRAM, mem_cache);
+                    code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc[ccindex]);
+                    if (code) {
+                        error((char *) "%s| %s: ERROR: Error while resolving memory ccache : %s\n", LogTime(), PROGRAM, error_message(code));
+                        retval = 1;
+                        goto cleanup;
+                    }
+                    code =1;
+                    break;
+                }
+                if (!strncmp(KRB5_TGS_NAME,principal_name,KRB5_TGS_NAME_SIZE)) {
+                    time_t now;
+                    static krb5_deltat skew=MAX_SKEW;
+
+                    debug((char *) "%s| %s: DEBUG: Found %s in cache : %s\n", LogTime(), PROGRAM,KRB5_TGS_NAME,principal_name);
+                    /*
+                     * Check time
+                     */
+                    time(&now);
+                    debug((char *) "%s| %s: DEBUG: credential time diff %d\n", LogTime(), PROGRAM, (int)(creds->times.endtime - now));
+                    if (creds->times.endtime - now < 2*skew) {
+                        debug((char *) "%s| %s: DEBUG: credential will soon expire %d\n", LogTime(), PROGRAM, (int)(creds->times.endtime - now));
+                        if (principal)
+                            krb5_free_principal(kparam.context, principal);
+                        principal = NULL;
+                        code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
+                        if (code) {
+                            error((char *) "%s| %s: ERROR: while destroying ccache : %s\n", LogTime(), PROGRAM, error_message(code));
+                        }
+                        if (creds)
+                            krb5_free_creds(kparam.context, creds);
+                        creds = NULL;
+                        safe_free(principal_name);
+                        debug((char *) "%s| %s: DEBUG: Reset credential cache to %s\n", LogTime(), PROGRAM, mem_cache);
+                        code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc[ccindex]);
+                        if (code) {
+                            error((char *) "%s| %s: ERROR: Error while resolving memory ccache : %s\n", LogTime(), PROGRAM, error_message(code));
+                            retval = 1;
+                            goto cleanup;
+                        }
+                        code = 1;
+                    } else {
+                        safe_free(principal_name);
+                    }
+                    break;
+                }
+                if (creds)
+                    krb5_free_creds(kparam.context, creds);
+                creds = (krb5_creds *) xcalloc(1,sizeof(*creds));
+                safe_free(principal_name);
+            }
+            if (creds)
+                krb5_free_creds(kparam.context, creds);
+            creds = NULL;
+            code2 = krb5_cc_end_seq_get(kparam.context, kparam.cc[ccindex], &ccursor);
+            if (code2) {
+                error((char *) "%s| %s: ERROR: Error while ending ccache scan : %s\n", LogTime(), PROGRAM, error_message(code));
+                retval = 1;
+                goto cleanup;
+            }
+        }
     }
-    code = krb5_kt_start_seq_get(kparam.context, keytab, &cursor);
     if (code) {
-        error((char *) "%s| %s: ERROR: Error while starting keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
-        retval = 1;
-        goto cleanup;
-    }
-    debug((char *) "%s| %s: DEBUG: Get principal name from keytab %s\n", LogTime(), PROGRAM, keytab_name);
+        /*
+         * getting default keytab name
+         */
 
-    nprinc = 0;
-    while ((code = krb5_kt_next_entry(kparam.context, keytab, &entry, &cursor)) == 0) {
-        int found = 0;
+        debug((char *) "%s| %s: DEBUG: Get default keytab file name\n", LogTime(), PROGRAM);
+        krb5_kt_default_name(kparam.context, buf, KT_PATH_MAX);
+        p = strchr(buf, ':');  /* Find the end if "FILE:" */
+        if (p)
+            ++p;                       /* step past : */
+        keytab_name = xstrdup(p ? p : buf);
+        debug((char *) "%s| %s: DEBUG: Got default keytab file name %s\n", LogTime(), PROGRAM, keytab_name);
 
-        principal_list = (krb5_principal *) xrealloc(principal_list, sizeof(krb5_principal) * (nprinc + 1));
-        krb5_copy_principal(kparam.context, entry.principal, &principal_list[nprinc++]);
+        code = krb5_kt_resolve(kparam.context, keytab_name, &keytab);
+        if (code) {
+            error((char *) "%s| %s: ERROR: Error while resolving keytab %s : %s\n", LogTime(), PROGRAM, keytab_name, error_message(code));
+            retval = 1;
+            goto cleanup;
+        }
+        code = krb5_kt_start_seq_get(kparam.context, keytab, &cursor);
+        if (code) {
+            error((char *) "%s| %s: ERROR: Error while starting keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
+            retval = 1;
+            goto cleanup;
+        }
+        debug((char *) "%s| %s: DEBUG: Get principal name from keytab %s\n", LogTime(), PROGRAM, keytab_name);
+
+        nprinc = 0;
+        while ((code = krb5_kt_next_entry(kparam.context, keytab, &entry, &cursor)) == 0) {
+            int found = 0;
+
+            principal_list = (krb5_principal *) xrealloc(principal_list, sizeof(krb5_principal) * (nprinc + 1));
+            krb5_copy_principal(kparam.context, entry.principal, &principal_list[nprinc++]);
 #if USE_HEIMDAL_KRB5
-        debug((char *) "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, entry.principal->realm);
+            debug((char *) "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, entry.principal->realm);
 #else
-        debug((char *) "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, krb5_princ_realm(kparam.context, entry.principal)->data);
+            debug((char *) "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, krb5_princ_realm(kparam.context, entry.principal)->data);
 #endif
 #if USE_HEIMDAL_KRB5
-        if (!strcasecmp(domain, entry.principal->realm))
+            if (!strcasecmp(domain, entry.principal->realm))
 #else
-        if (!strcasecmp(domain, krb5_princ_realm(kparam.context, entry.principal)->data))
+            if (!strcasecmp(domain, krb5_princ_realm(kparam.context, entry.principal)->data))
 #endif
-        {
-            code = krb5_unparse_name(kparam.context, entry.principal, &principal_name);
-            if (code) {
-                error((char *) "%s| %s: ERROR: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
-            } else {
-                debug((char *) "%s| %s: DEBUG: Found principal name: %s\n", LogTime(), PROGRAM, principal_name);
-                found = 1;
+            {
+                code = krb5_unparse_name(kparam.context, entry.principal, &principal_name);
+                if (code) {
+                    error((char *) "%s| %s: ERROR: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
+                } else {
+                    debug((char *) "%s| %s: DEBUG: Found principal name: %s\n", LogTime(), PROGRAM, principal_name);
+                    found = 1;
+                }
             }
-        }
 #if USE_HEIMDAL_KRB5 || ( HAVE_KRB5_KT_FREE_ENTRY && HAVE_DECL_KRB5_KT_FREE_ENTRY )
-        code = krb5_kt_free_entry(kparam.context, &entry);
+            code = krb5_kt_free_entry(kparam.context, &entry);
 #else
-        code = krb5_free_keytab_entry_contents(kparam.context, &entry);
+            code = krb5_free_keytab_entry_contents(kparam.context, &entry);
 #endif
-        if (code) {
-            error((char *) "%s| %s: ERROR: Error while freeing keytab entry : %s\n", LogTime(), PROGRAM, error_message(code));
-            retval = 1;
-            break;
-        }
-        if (found) {
-            debug((char *) "%s| %s: DEBUG: Got principal name %s\n", LogTime(), PROGRAM, principal_name);
-            /*
-             * build principal
-             */
-            code = krb5_parse_name(kparam.context, principal_name, &principal);
             if (code) {
-                error((char *) "%s| %s: ERROR: Error while parsing name %s : %s\n", LogTime(), PROGRAM, principal_name, error_message(code));
-                safe_free(principal_name);
-                if (principal)
-                    krb5_free_principal(kparam.context, principal);
-                found = 0;
-                continue;
+                error((char *) "%s| %s: ERROR: Error while freeing keytab entry : %s\n", LogTime(), PROGRAM, error_message(code));
+                retval = 1;
+                break;
             }
-            creds = (krb5_creds *) xcalloc(1,sizeof(*creds));
+            if (found) {
+                debug((char *) "%s| %s: DEBUG: Got principal name %s\n", LogTime(), PROGRAM, principal_name);
+                /*
+                 * build principal
+                 */
+                code = krb5_parse_name(kparam.context, principal_name, &principal);
+                if (code) {
+                    error((char *) "%s| %s: ERROR: Error while parsing name %s : %s\n", LogTime(), PROGRAM, principal_name, error_message(code));
+                    safe_free(principal_name);
+                    if (principal)
+                        krb5_free_principal(kparam.context, principal);
+                    found = 0;
+                    continue;
+                }
+                creds = (krb5_creds *) xcalloc(1,sizeof(*creds));
 
-            /*
-             * get credentials
-             */
+                /*
+                 * get credentials
+                 */
 #if HAVE_GET_INIT_CREDS_KEYTAB
-            code = krb5_get_init_creds_keytab(kparam.context, creds, principal, keytab, 0, NULL, NULL);
+                code = krb5_get_init_creds_keytab(kparam.context, creds, principal, keytab, 0, NULL, NULL);
 #else
-            service = (char *) xmalloc(strlen("krbtgt") + 2 * strlen(domain) + 3);
-            snprintf(service, strlen("krbtgt") + 2 * strlen(domain) + 3, "krbtgt/%s@%s", domain, domain);
-            creds->client = principal;
-            code = krb5_parse_name(kparam.context, service, &creds->server);
-            xfree(service);
-            code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0);
+                service = (char *) xmalloc(strlen("krbtgt") + 2 * strlen(domain) + 3);
+                snprintf(service, strlen("krbtgt") + 2 * strlen(domain) + 3, "krbtgt/%s@%s", domain, domain);
+                creds->client = principal;
+                code = krb5_parse_name(kparam.context, service, &creds->server);
+                xfree(service);
+                code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0);
 #endif
 
-            if (code) {
-                error((char *) "%s| %s: ERROR: Error while initialising credentials from keytab : %s\n", LogTime(), PROGRAM, error_message(code));
-                safe_free(principal_name);
-                if (principal)
-                    krb5_free_principal(kparam.context, principal);
-                if (creds)
-                    krb5_free_creds(kparam.context, creds);
-                creds = NULL;
-                found = 0;
-                continue;
-            }
-            code = krb5_cc_initialize(kparam.context, kparam.cc, principal);
-            if (code) {
-                error((char *) "%s| %s: ERROR: Error while initializing memory caches : %s\n", LogTime(), PROGRAM, error_message(code));
-                safe_free(principal_name);
-                if (principal)
-                    krb5_free_principal(kparam.context, principal);
-                if (creds)
-                    krb5_free_creds(kparam.context, creds);
-                creds = NULL;
-                found = 0;
-                continue;
-            }
-            code = krb5_cc_store_cred(kparam.context, kparam.cc, creds);
-            if (code) {
-                error((char *) "%s| %s: ERROR: Error while storing credentials : %s\n", LogTime(), PROGRAM, error_message(code));
-                if (principal)
-                    krb5_free_principal(kparam.context, principal);
-                safe_free(principal_name);
-                if (creds)
-                    krb5_free_creds(kparam.context, creds);
-                creds = NULL;
-                found = 0;
-                continue;
+                if (code) {
+                    error((char *) "%s| %s: ERROR: Error while initialising credentials from keytab : %s\n", LogTime(), PROGRAM, error_message(code));
+                    safe_free(principal_name);
+                    if (principal)
+                        krb5_free_principal(kparam.context, principal);
+                    if (creds)
+                        krb5_free_creds(kparam.context, creds);
+                    creds = NULL;
+                    found = 0;
+                    continue;
+                }
+                code = krb5_cc_initialize(kparam.context, kparam.cc[ccindex], principal);
+                if (code) {
+                    error((char *) "%s| %s: ERROR: Error while initializing memory caches : %s\n", LogTime(), PROGRAM, error_message(code));
+                    safe_free(principal_name);
+                    if (principal)
+                        krb5_free_principal(kparam.context, principal);
+                    if (creds)
+                        krb5_free_creds(kparam.context, creds);
+                    creds = NULL;
+                    found = 0;
+                    continue;
+                }
+                code = krb5_cc_store_cred(kparam.context, kparam.cc[ccindex], creds);
+                if (code) {
+                    error((char *) "%s| %s: ERROR: Error while storing credentials : %s\n", LogTime(), PROGRAM, error_message(code));
+                    if (principal)
+                        krb5_free_principal(kparam.context, principal);
+                    safe_free(principal_name);
+                    if (creds)
+                        krb5_free_creds(kparam.context, creds);
+                    creds = NULL;
+                    found = 0;
+                    continue;
+                }
+                debug((char *) "%s| %s: DEBUG: Stored credentials\n", LogTime(), PROGRAM);
+                break;
             }
-            debug((char *) "%s| %s: DEBUG: Stored credentials\n", LogTime(), PROGRAM);
-            break;
         }
-    }
 
-    if (code && code != KRB5_KT_END) {
-        error((char *) "%s| %s: ERROR: Error while scanning keytab : %s\n", LogTime(), PROGRAM, error_message(code));
-        retval = 1;
-        goto cleanup;
-    }
-    code = krb5_kt_end_seq_get(kparam.context, keytab, &cursor);
-    if (code) {
-        error((char *) "%s| %s: ERROR: Error while ending keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
-        retval = 1;
-        goto cleanup;
-    }
+        if (code && code != KRB5_KT_END) {
+            error((char *) "%s| %s: ERROR: Error while scanning keytab : %s\n", LogTime(), PROGRAM, error_message(code));
+            retval = 1;
+            goto cleanup;
+        }
+        code = krb5_kt_end_seq_get(kparam.context, keytab, &cursor);
+        if (code) {
+            error((char *) "%s| %s: ERROR: Error while ending keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
+            retval = 1;
+            goto cleanup;
+        }
 
-    /*
-     * if no principal name found in keytab for domain use the prinipal name which can get a TGT
-     */
-    if (!principal_name) {
-        size_t i;
-        debug((char *) "%s| %s: DEBUG: Did not find a principal in keytab for domain %s.\n", LogTime(), PROGRAM, domain);
-        debug((char *) "%s| %s: DEBUG: Try to get principal of trusted domain.\n", LogTime(), PROGRAM);
+        /*
+         * if no principal name found in keytab for domain use the prinipal name which can get a TGT
+         */
+        if (!principal_name) {
+            size_t i;
+            debug((char *) "%s| %s: DEBUG: Did not find a principal in keytab for domain %s.\n", LogTime(), PROGRAM, domain);
+            debug((char *) "%s| %s: DEBUG: Try to get principal of trusted domain.\n", LogTime(), PROGRAM);
 
-        for (i = 0; i < nprinc; ++i) {
-            krb5_creds *tgt_creds = NULL;
-            creds = (krb5_creds *) xmalloc(sizeof(*creds));
-            memset(creds, 0, sizeof(*creds));
-            /*
-             * get credentials
-             */
-            code = krb5_unparse_name(kparam.context, principal_list[i], &principal_name);
-            if (code) {
-                debug((char *) "%s| %s: DEBUG: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
-                goto loop_end;
-            }
-            debug((char *) "%s| %s: DEBUG: Keytab entry has principal: %s\n", LogTime(), PROGRAM, principal_name);
+            for (i = 0; i < nprinc; ++i) {
+                krb5_creds *tgt_creds = NULL;
+                creds = (krb5_creds *) xmalloc(sizeof(*creds));
+                memset(creds, 0, sizeof(*creds));
+                /*
+                 * get credentials
+                 */
+                code = krb5_unparse_name(kparam.context, principal_list[i], &principal_name);
+                if (code) {
+                    debug((char *) "%s| %s: DEBUG: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
+                    goto loop_end;
+                }
+                debug((char *) "%s| %s: DEBUG: Keytab entry has principal: %s\n", LogTime(), PROGRAM, principal_name);
 
 #if HAVE_GET_INIT_CREDS_KEYTAB
-            code = krb5_get_init_creds_keytab(kparam.context, creds, principal_list[i], keytab, 0, NULL, NULL);
+                code = krb5_get_init_creds_keytab(kparam.context, creds, principal_list[i], keytab, 0, NULL, NULL);
 #else
-            service = (char *) xmalloc(strlen("krbtgt") + 2 * strlen(domain) + 3);
-            snprintf(service, strlen("krbtgt") + 2 * strlen(domain) + 3, "krbtgt/%s@%s", domain, domain);
-            creds->client = principal_list[i];
-            code = krb5_parse_name(kparam.context, service, &creds->server);
-            xfree(service);
-            code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0);
+                service = (char *) xmalloc(strlen("krbtgt") + 2 * strlen(domain) + 3);
+                snprintf(service, strlen("krbtgt") + 2 * strlen(domain) + 3, "krbtgt/%s@%s", domain, domain);
+                creds->client = principal_list[i];
+                code = krb5_parse_name(kparam.context, service, &creds->server);
+                xfree(service);
+                code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0);
 #endif
-            if (code) {
-                debug((char *) "%s| %s: DEBUG: Error while initialising credentials from keytab : %s\n", LogTime(), PROGRAM, error_message(code));
-                goto loop_end;
-            }
-            code = krb5_cc_initialize(kparam.context, kparam.cc, principal_list[i]);
-            if (code) {
-                error((char *) "%s| %s: ERROR: Error while initializing memory caches : %s\n", LogTime(), PROGRAM, error_message(code));
-                goto loop_end;
-            }
-            code = krb5_cc_store_cred(kparam.context, kparam.cc, creds);
-            if (code) {
-                debug((char *) "%s| %s: DEBUG: Error while storing credentials : %s\n", LogTime(), PROGRAM, error_message(code));
-                goto loop_end;
-            }
-            if (creds->server)
-                krb5_free_principal(kparam.context, creds->server);
+                if (code) {
+                    debug((char *) "%s| %s: DEBUG: Error while initialising credentials from keytab : %s\n", LogTime(), PROGRAM, error_message(code));
+                    goto loop_end;
+                }
+                code = krb5_cc_initialize(kparam.context, kparam.cc[ccindex], principal_list[i]);
+                if (code) {
+                    error((char *) "%s| %s: ERROR: Error while initializing memory caches : %s\n", LogTime(), PROGRAM, error_message(code));
+                    goto loop_end;
+                }
+                code = krb5_cc_store_cred(kparam.context, kparam.cc[ccindex], creds);
+                if (code) {
+                    debug((char *) "%s| %s: DEBUG: Error while storing credentials : %s\n", LogTime(), PROGRAM, error_message(code));
+                    goto loop_end;
+                }
+                if (creds->server)
+                    krb5_free_principal(kparam.context, creds->server);
 #if USE_HEIMDAL_KRB5
-            service = (char *) xmalloc(strlen("krbtgt") + strlen(domain) + strlen(principal_list[i]->realm) + 3);
-            snprintf(service, strlen("krbtgt") + strlen(domain) + strlen(principal_list[i]->realm) + 3, "krbtgt/%s@%s", domain, principal_list[i]->realm);
+                service = (char *) xmalloc(strlen("krbtgt") + strlen(domain) + strlen(principal_list[i]->realm) + 3);
+                snprintf(service, strlen("krbtgt") + strlen(domain) + strlen(principal_list[i]->realm) + 3, "krbtgt/%s@%s", domain, principal_list[i]->realm);
 #else
-            service = (char *) xmalloc(strlen("krbtgt") + strlen(domain) + strlen(krb5_princ_realm(kparam.context, principal_list[i])->data) + 3);
-            snprintf(service, strlen("krbtgt") + strlen(domain) + strlen(krb5_princ_realm(kparam.context, principal_list[i])->data) + 3, "krbtgt/%s@%s", domain, krb5_princ_realm(kparam.context, principal_list[i])->data);
+                service = (char *) xmalloc(strlen("krbtgt") + strlen(domain) + strlen(krb5_princ_realm(kparam.context, principal_list[i])->data) + 3);
+                snprintf(service, strlen("krbtgt") + strlen(domain) + strlen(krb5_princ_realm(kparam.context, principal_list[i])->data) + 3, "krbtgt/%s@%s", domain, krb5_princ_realm(kparam.context, principal_list[i])->data);
 #endif
-            code = krb5_parse_name(kparam.context, service, &creds->server);
-            xfree(service);
-            if (code) {
-                error((char *) "%s| %s: ERROR: Error while initialising TGT credentials : %s\n", LogTime(), PROGRAM, error_message(code));
-                goto loop_end;
-            }
-            code = krb5_get_credentials(kparam.context, 0, kparam.cc, creds, &tgt_creds);
-            if (code) {
-                debug((char *) "%s| %s: DEBUG: Error while getting tgt : %s\n", LogTime(), PROGRAM, error_message(code));
-                goto loop_end;
-            } else {
-                debug((char *) "%s| %s: DEBUG: Found trusted principal name: %s\n", LogTime(), PROGRAM, principal_name);
+                code = krb5_parse_name(kparam.context, service, &creds->server);
+                xfree(service);
+                if (code) {
+                    error((char *) "%s| %s: ERROR: Error while initialising TGT credentials : %s\n", LogTime(), PROGRAM, error_message(code));
+                    goto loop_end;
+                }
+                code = krb5_get_credentials(kparam.context, 0, kparam.cc[ccindex], creds, &tgt_creds);
+                if (code) {
+                    debug((char *) "%s| %s: DEBUG: Error while getting tgt : %s\n", LogTime(), PROGRAM, error_message(code));
+                    goto loop_end;
+                } else {
+                    debug((char *) "%s| %s: DEBUG: Found trusted principal name: %s\n", LogTime(), PROGRAM, principal_name);
+                    if (tgt_creds)
+                        krb5_free_creds(kparam.context, tgt_creds);
+                    tgt_creds = NULL;
+                    break;
+                }
+
+loop_end:
+                safe_free(principal_name);
                 if (tgt_creds)
                     krb5_free_creds(kparam.context, tgt_creds);
                 tgt_creds = NULL;
-                break;
+                if (creds)
+                    krb5_free_creds(kparam.context, creds);
+                creds = NULL;
+
             }
 
-loop_end:
-            safe_free(principal_name);
-            if (tgt_creds)
-                krb5_free_creds(kparam.context, tgt_creds);
-            tgt_creds = NULL;
             if (creds)
                 krb5_free_creds(kparam.context, creds);
             creds = NULL;
-
         }
-
-        if (creds)
-            krb5_free_creds(kparam.context, creds);
-        creds = NULL;
+    } else {
+        debug((char *) "%s| %s: DEBUG: Got principal from ccache\n", LogTime(), PROGRAM);
+        /*
+         * get credentials
+         */
+        code = krb5_unparse_name(kparam.context, principal, &principal_name);
+        if (code) {
+            debug((char *) "%s| %s: DEBUG: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
+            retval = 1;
+            goto cleanup;
+        }
+        debug((char *) "%s| %s: DEBUG: ccache has principal: %s\n", LogTime(), PROGRAM, principal_name);
     }
+
     if (!principal_name) {
         debug((char *) "%s| %s: DEBUG: Got no principal name\n", LogTime(), PROGRAM);
         retval = 1;
@@ -359,7 +484,6 @@ cleanup:
     xfree(principal_list);
     if (creds)
         krb5_free_creds(kparam.context, creds);
-
     return (retval);
 }
 #endif
index 1f3d50f8eb85d8ad6923b3886e9ffcda415cc42a..7c37ba89b08f3fa125260f41d09cb8e8d5421e89 100644 (file)
@@ -47,7 +47,7 @@
 #include "squid.h"
 #include "util.h"
 
-#ifdef HAVE_LDAP
+#if HAVE_LDAP
 
 #include "support.h"
 #include <cerrno>
@@ -888,9 +888,14 @@ get_memberof(struct main_args *margs, char *user, char *domain, char *group)
         debug((char *) "%s| %s: DEBUG: Setup Kerberos credential cache\n", LogTime(), PROGRAM);
 
 #if HAVE_KRB5
-        kc = krb5_create_cache(domain);
-        if (kc) {
-            error((char *) "%s| %s: ERROR: Error during setup of Kerberos credential cache\n", LogTime(), PROGRAM);
+        if (margs->nokerberos) {
+            kc = 1;
+            debug((char *) "%s| %s: DEBUG: Kerberos is disabled. Use username/password with ldap url instead\n", LogTime(), PROGRAM);
+        } else {
+            kc = krb5_create_cache(domain);
+            if (kc) {
+                error((char *) "%s| %s: ERROR: Error during setup of Kerberos credential cache\n", LogTime(), PROGRAM);
+            }
         }
 #else
         kc = 1;
@@ -1375,10 +1380,6 @@ get_memberof(struct main_args *margs, char *user, char *domain, char *group)
     }
     debug((char *) "%s| %s: DEBUG: Unbind ldap server\n", LogTime(), PROGRAM);
 cleanup:
-#if HAVE_KRB5
-    if (domain)
-        krb5_cleanup();
-#endif
     if (lcreds) {
         xfree(lcreds->dn);
         xfree(lcreds->pw);