]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug 4042: ext_kerberos_ldap_group: add -P principal option (#195) M-staged-PR195
authorhuaraz <huaraz@moeller.plus.com>
Sun, 6 May 2018 16:06:42 +0000 (16:06 +0000)
committerSquid Anubis <squid-anubis@squid-cache.org>
Wed, 9 May 2018 16:38:34 +0000 (16:38 +0000)
Added a -P principal option to ext_kerberos_ldap_group to
select a principal from the keytab overwriting the automated
method which may make it more responsive.

src/acl/external/kerberos_ldap_group/ext_kerberos_ldap_group_acl.8
src/acl/external/kerberos_ldap_group/kerberos_ldap_group.cc
src/acl/external/kerberos_ldap_group/support.h
src/acl/external/kerberos_ldap_group/support_krb5.cc
src/acl/external/kerberos_ldap_group/support_ldap.cc

index 4c74092f6c564d70d4dc628c845c5170e00ff279..4ee82d893e3812a135505202e4d0b75d983363cc 100644 (file)
@@ -7,7 +7,7 @@ Version 1.3.0sq
 .
 .SH SYNOPSIS
 .if !'po4a'hide' .B ext_kerberos_ldap_group_acl
-.if !'po4a'hide' .B [\-h] [\-d] [\-i] [\-s] [\-a] [\-D Realm ] [\-N Netbios\-Realm\-List] [\-m Max\-Depth] [\-u Ldap\-User] [\-p Ldap\-Password] [\-b Ldap\-Bind\-Path] [\-l Ldap\-URL] [\-S ldap server list] \-g Group\-Realm\-List \-t  Hex\-Group\-Realm\-List \-T Hex\-Group\-Hex\-Realm\-List 
+.if !'po4a'hide' .B [\-h] [\-d] [\-i] [\-s] [\-a] [\-D Realm ] [\-N Netbios\-Realm\-List] [\-P service principal name] [\-m Max\-Depth] [\-u Ldap\-User] [\-p Ldap\-Password] [\-b Ldap\-Bind\-Path] [\-l Ldap\-URL] [\-S ldap server list] \-g Group\-Realm\-List \-t Hex\-Group\-Realm\-List \-T Hex\-Group\-Hex\-Realm\-List
 .
 .SH DESCRIPTION
 .B ext_kerberos_ldap_group_acl
@@ -89,6 +89,8 @@ information (e.g. for users using basic authentication).
 A list of Netbios name mappings to Kerberos domain names of the form 
 Netbios\-Name@Kerberos\-Realm[:Netbios\-Name@Kerberos\-Realm] (e.g. for users 
 using NTLM authentication).
+.if !'po4a'hide' .B \-P service principal name
+The principal name in the keytab to use. Avoids automated selection of name.
 .if !'po4a'hide' .TP 12
 .if !'po4a'hide' .B \-m Max\-Depth
 Maximal depth of recursive group search.
@@ -100,7 +102,8 @@ Username for LDAP server.
 Password for LDAP server.
 .IP
 As the password needs to be printed in plain text in your Squid configuration
-it is strongly recommended to use an account with minimal associated privileges.  
+it is strongly recommended to use an account with minimal associated privileges.
+
 This to limit the damage in case someone could get hold of a copy of your Squid 
 configuration file or extracts the password used from a process listing.
 .
@@ -119,7 +122,7 @@ lserver|lserver@|lserver@Realm[:lserver@|lserver@Realm]
 A list of group name per Kerberos domain of the form 
 Group|Group@|Group@Realm[:Group@|Group@Realm]
 .if !'po4a'hide' .TP 12
-.if !'po4a'hide' .B \-t  Hex\-Group\-Realm\-List
+.if !'po4a'hide' .B \-t Hex\-Group\-Realm\-List
 A list of group name per Kerberos domain of the 
 form Group|Group@|Group@Realm[:Group@|Group@Realm] where group is in 
 UTF\-8 hex format
@@ -138,9 +141,9 @@ helper in
 .if !'po4a'hide' .P
 .if !'po4a'hide' .ft CR
 .if !'po4a'hide' .nf
-.if !'po4a'hide' external_acl_type kerberos_ldap_group1  ttl=3600  negative_ttl=3600 %LOGIN /path/to/ext_kerberos_ldap_group_acl \-g GROUP1
+.if !'po4a'hide' external_acl_type kerberos_ldap_group1 ttl=3600 negative_ttl=3600 %LOGIN /path/to/ext_kerberos_ldap_group_acl \-g GROUP1
 .if !'po4a'hide' .br
-.if !'po4a'hide' external_acl_type kerberos_ldap_group2  ttl=3600  negative_ttl=3600 %LOGIN /path/to/ext_kerberos_ldap_group_acl \-g GROUP2
+.if !'po4a'hide' external_acl_type kerberos_ldap_group2 ttl=3600 negative_ttl=3600 %LOGIN /path/to/ext_kerberos_ldap_group_acl \-g GROUP2
 .if !'po4a'hide' .br
 .if !'po4a'hide' acl group1 external kerberos_ldap_group1
 .if !'po4a'hide' .br
@@ -198,7 +201,7 @@ The Groups to check against are determined as follows:
 3) For NDOMAIN\\user
    a) Use realm given by \-N NDOMAIN@REALM and then use values given by \-g option which contain a @REALM e.g. \-g GROUP1@REALM:GROUP2@REALM
 
-To support Non\-ASCII character use \-t GROUP  or \-t GROUP@REALM instead of \-g where GROUP is the hex UTF\-8 representation e.g.
+To support Non\-ASCII character use \-t GROUP or \-t GROUP@REALM instead of \-g where GROUP is the hex UTF\-8 representation e.g.
 
    \-t 6d61726b7573 instead of \-g markus
 
@@ -210,8 +213,8 @@ For a translation of hex UTF\-8 see for example http://www.utf8\-chartable.de/un
 
 The ldap server list can be:
 server \- In this case server can be used for all Kerberos domains
-server@  \- In this case server can be used for all Kerberos domains
-server@domain  \- In this case server can be used for Kerberos domain domain
+server@ \- In this case server can be used for all Kerberos domains
+server@domain \- In this case server can be used for Kerberos domain domain
 server1a@domain1:server1b@domain1:server2@domain2:server3@:server4 \- A list is build with a colon as separator
 
 .
index fc548da35dc6d42ba0855307a3f66bdaa7b0e54d..a12d7c02507dd3b92af52c0f8dfa3a280d187153 100644 (file)
@@ -83,6 +83,7 @@ init_args(struct main_args *margs)
     margs->groups = NULL;
     margs->ndoms = NULL;
     margs->lservs = NULL;
+    margs->principal = NULL;
 }
 
 void clean_gd(struct gdstruct *gdsp);
@@ -178,6 +179,7 @@ clean_args(struct main_args *margs)
         clean_ls(margs->lservs);
         margs->lservs = NULL;
     }
+    safe_free(margs->principal);
 }
 
 void strup(char *s);
@@ -202,7 +204,7 @@ main(int argc, char *const argv[])
 
     init_args(&margs);
 
-    while (-1 != (opt = getopt(argc, argv, "diasng:D:N:S:u:U:t:T:p:l:b:m:h"))) {
+    while (-1 != (opt = getopt(argc, argv, "diasng:D:N:P:S:u:U:t:T:p:l:b:m:h"))) {
         switch (opt) {
         case 'd':
             debug_enabled = 1;
@@ -228,6 +230,9 @@ main(int argc, char *const argv[])
         case 'N':
             margs.nlist = xstrdup(optarg);
             break;
+        case 'P':
+            margs.principal = xstrdup(optarg);
+            break;
         case 'u':
             margs.luser = xstrdup(optarg);
             break;
@@ -259,7 +264,7 @@ main(int argc, char *const argv[])
             break;
         case 'h':
             fprintf(stderr, "Usage: \n");
-            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, "squid_kerb_ldap [-d] [-i] -g group list [-D domain] [-N netbios domain map] [-P service principal name] [-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");
@@ -268,6 +273,7 @@ main(int argc, char *const argv[])
             fprintf(stderr, "-T group list (all in hex UTF-8 format - except separator @)\n");
             fprintf(stderr, "-D default domain\n");
             fprintf(stderr, "-N netbios to dns domain map\n");
+            fprintf(stderr, "-P service principal name to be used from keytab\n");
             fprintf(stderr, "-S ldap server to dns domain map\n");
             fprintf(stderr, "-u ldap user\n");
             fprintf(stderr, "-p ldap user password\n");
index 14e9decacb09efeabc4d1f0e4bba55e9ffaf0fdf..c279e7d9dcc162e37b00ac66b34226621de0148e 100644 (file)
@@ -110,6 +110,7 @@ struct main_args {
     struct gdstruct *groups;
     struct ndstruct *ndoms;
     struct lsstruct *lservs;
+    char *principal;
 };
 
 SQUIDCEXTERN int log_enabled;
@@ -181,7 +182,7 @@ struct kstruct {
     char* mem_ccache[MAX_DOMAINS];
     int ncache;
 };
-int krb5_create_cache(char *domain);
+int krb5_create_cache(char *domain, char* princ);
 void krb5_cleanup(void);
 #endif
 
index e87bab8a1f0e39c373fb3b820ee10e8dff2af024..77df81b09fb0179b42ac7ef1128462d0a6d3f708 100644 (file)
@@ -70,6 +70,21 @@ k5_error2(const char* msg, char* msg2, krb5_error_code code)
 #endif
 }
 
+static void
+k5_debug(const char* msg, krb5_error_code code)
+{
+    const char *errmsg;
+    errmsg = krb5_get_error_message(kparam.context, code);
+    debug((char *) "%s| %s: DEBUG: %s : %s\n", LogTime(), PROGRAM, msg, errmsg);
+#if HAVE_KRB5_FREE_ERROR_MESSAGE
+    krb5_free_error_message(kparam.context, errmsg);
+#elif HAVE_KRB5_FREE_ERROR_STRING
+    krb5_free_error_string(kparam.context, (char *)errmsg);
+#else
+    xfree(errmsg);
+#endif
+}
+
 static void
 k5_error(const char* msg, krb5_error_code code)
 {
@@ -80,7 +95,7 @@ k5_error(const char* msg, krb5_error_code code)
  * create Kerberos memory cache
  */
 int
-krb5_create_cache(char *domain)
+krb5_create_cache(char *domain, char *service_principal_name)
 {
 
     krb5_keytab keytab = NULL;
@@ -131,7 +146,7 @@ krb5_create_cache(char *domain)
         }
         code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc[ccindex]);
         if (code) {
-            k5_error("Error while resolving memory ccache",code);
+            k5_error("Error while resolving memory ccache", code);
             retval = 1;
             goto cleanup;
         }
@@ -145,22 +160,22 @@ krb5_create_cache(char *domain)
         if (principal)
             krb5_free_principal(kparam.context, principal);
         principal = NULL;
-        k5_error("No default principal found in ccache",code);
+        k5_debug("No default principal found in ccache", 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) {
-            k5_error("Error while starting ccache scan",code);
+            k5_error("Error while starting ccache scan", code);
             code = krb5_cc_close (kparam.context, kparam.cc[ccindex]);
             if (code) {
-                k5_error("Error while closing ccache",code);
+                k5_error("Error while closing ccache", code);
             }
             if (kparam.cc[ccindex]) {
                 code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
                 if (code) {
-                    k5_error("Error while destroying ccache",code);
+                    k5_error("Error while destroying ccache", code);
                 }
             }
         } else {
@@ -169,10 +184,10 @@ krb5_create_cache(char *domain)
             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) {
-                    k5_error("Error while unparsing principal",code2);
+                    k5_error("Error while unparsing principal", code2);
                     code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
                     if (code) {
-                        k5_error("Error while destroying ccache",code);
+                        k5_error("Error while destroying ccache", code);
                     }
                     assert(creds != NULL);
                     krb5_free_creds(kparam.context, creds);
@@ -181,7 +196,7 @@ krb5_create_cache(char *domain)
                     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) {
-                        k5_error("Error  while resolving memory ccache",code);
+                        k5_error("Error while resolving memory ccache", code);
                         retval = 1;
                         goto cleanup;
                     }
@@ -205,7 +220,7 @@ krb5_create_cache(char *domain)
                         principal = NULL;
                         code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
                         if (code) {
-                            k5_error("Error  while destroying ccache",code);
+                            k5_error("Error  while destroying ccache", code);
                         }
                         assert(creds != NULL);
                         krb5_free_creds(kparam.context, creds);
@@ -214,7 +229,7 @@ krb5_create_cache(char *domain)
                         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) {
-                            k5_error("Error  while resolving ccache",code);
+                            k5_error("Error  while resolving ccache", code);
                             retval = 1;
                             goto cleanup;
                         }
@@ -234,7 +249,7 @@ krb5_create_cache(char *domain)
             creds = NULL;
             code2 = krb5_cc_end_seq_get(kparam.context, kparam.cc[ccindex], &ccursor);
             if (code2) {
-                k5_error("Error  while ending ccache scan",code2);
+                k5_error("Error while ending ccache scan", code2);
                 retval = 1;
                 goto cleanup;
             }
@@ -255,13 +270,13 @@ krb5_create_cache(char *domain)
 
         code = krb5_kt_resolve(kparam.context, keytab_name, &keytab);
         if (code) {
-            k5_error2("Error while resolving keytab ",keytab_name,code);
+            k5_error2("Error while resolving keytab ", keytab_name,code);
             retval = 1;
             goto cleanup;
         }
         code = krb5_kt_start_seq_get(kparam.context, keytab, &cursor);
         if (code) {
-            k5_error("Error while starting keytab scan",code);
+            k5_error("Error while starting keytab scan", code);
             retval = 1;
             goto cleanup;
         }
@@ -286,10 +301,15 @@ krb5_create_cache(char *domain)
             {
                 code = krb5_unparse_name(kparam.context, entry.principal, &principal_name);
                 if (code) {
-                    k5_error("Error while unparsing principal name",code);
+                    k5_error("Error while unparsing principal name", code);
                 } else {
                     debug((char *) "%s| %s: DEBUG: Found principal name: %s\n", LogTime(), PROGRAM, principal_name);
                     found = 1;
+                    if (service_principal_name && strcasecmp(principal_name,service_principal_name) != 0 ) {
+                        debug((char *) "%s| %s: DEBUG: principal name does not match parameter: %s\n", LogTime(), PROGRAM, service_principal_name);
+                        safe_free(principal_name);
+                        found = 0;
+                    }
                 }
             }
 #if USE_HEIMDAL_KRB5 || ( HAVE_KRB5_KT_FREE_ENTRY && HAVE_DECL_KRB5_KT_FREE_ENTRY )
@@ -298,7 +318,7 @@ krb5_create_cache(char *domain)
             code = krb5_free_keytab_entry_contents(kparam.context, &entry);
 #endif
             if (code) {
-                k5_error("Error while freeing keytab entry",code);
+                k5_error("Error while freeing keytab entry", code);
                 retval = 1;
                 break;
             }
@@ -333,7 +353,7 @@ krb5_create_cache(char *domain)
 #endif
 
                 if (code) {
-                    k5_error("Error while initialising credentials from keytab",code);
+                    k5_error("Error while initialising credentials from keytab", code);
                     safe_free(principal_name);
                     if (principal)
                         krb5_free_principal(kparam.context, principal);
@@ -345,7 +365,7 @@ krb5_create_cache(char *domain)
                 }
                 code = krb5_cc_initialize(kparam.context, kparam.cc[ccindex], principal);
                 if (code) {
-                    k5_error("Error while initialising  memory caches",code);
+                    k5_error("Error while initialising cache", code);
                     safe_free(principal_name);
                     if (principal)
                         krb5_free_principal(kparam.context, principal);
@@ -357,7 +377,7 @@ krb5_create_cache(char *domain)
                 }
                 code = krb5_cc_store_cred(kparam.context, kparam.cc[ccindex], creds);
                 if (code) {
-                    k5_error("Error while storing credentials",code);
+                    k5_error("Error while storing credentials", code);
                     if (principal)
                         krb5_free_principal(kparam.context, principal);
                     safe_free(principal_name);
@@ -373,13 +393,13 @@ krb5_create_cache(char *domain)
         }
 
         if (code && code != KRB5_KT_END) {
-            k5_error("Error while scanning keytab",code);
+            k5_error("Error while scanning keytab", code);
             retval = 1;
             goto cleanup;
         }
         code = krb5_kt_end_seq_get(kparam.context, keytab, &cursor);
         if (code) {
-            k5_error("Error while ending keytab scan",code);
+            k5_error("Error while ending keytab scan", code);
             retval = 1;
             goto cleanup;
         }
@@ -387,7 +407,7 @@ krb5_create_cache(char *domain)
         /*
          * if no principal name found in keytab for domain use the prinipal name which can get a TGT
          */
-        if (!principal_name) {
+        if (!principal_name && !service_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);
@@ -401,7 +421,7 @@ krb5_create_cache(char *domain)
                  */
                 code = krb5_unparse_name(kparam.context, principal_list[i], &principal_name);
                 if (code) {
-                    k5_error("Error while unparsing principal name",code);
+                    k5_error("Error while unparsing principal name", code);
                     goto loop_end;
                 }
                 debug((char *) "%s| %s: DEBUG: Keytab entry has principal: %s\n", LogTime(), PROGRAM, principal_name);
@@ -417,17 +437,17 @@ krb5_create_cache(char *domain)
                 code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0);
 #endif
                 if (code) {
-                    k5_error("Error while initialising credentials from keytab",code);
+                    k5_error("Error while initialising credentials from keytab", code);
                     goto loop_end;
                 }
                 code = krb5_cc_initialize(kparam.context, kparam.cc[ccindex], principal_list[i]);
                 if (code) {
-                    k5_error("Error while initialising memory caches",code);
+                    k5_error("Error while initialising memory caches", code);
                     goto loop_end;
                 }
                 code = krb5_cc_store_cred(kparam.context, kparam.cc[ccindex], creds);
                 if (code) {
-                    k5_error("Error while storing credentials",code);
+                    k5_error("Error while storing credentials", code);
                     goto loop_end;
                 }
                 if (creds->server)
@@ -442,12 +462,12 @@ krb5_create_cache(char *domain)
                 code = krb5_parse_name(kparam.context, service, &creds->server);
                 xfree(service);
                 if (code) {
-                    k5_error("Error while initialising TGT credentials",code);
+                    k5_error("Error while initialising TGT credentials", code);
                     goto loop_end;
                 }
                 code = krb5_get_credentials(kparam.context, 0, kparam.cc[ccindex], creds, &tgt_creds);
                 if (code) {
-                    k5_error("Error while getting tgt",code);
+                    k5_error("Error while getting tgt", code);
                     goto loop_end;
                 } else {
                     debug((char *) "%s| %s: DEBUG: Found trusted principal name: %s\n", LogTime(), PROGRAM, principal_name);
@@ -479,7 +499,7 @@ loop_end:
          */
         code = krb5_unparse_name(kparam.context, principal, &principal_name);
         if (code) {
-            k5_error("Error while unparsing principal name",code);
+            k5_error("Error while unparsing principal name", code);
             retval = 1;
             goto cleanup;
         }
index 057b19d78846752bd2936d4642657c50dfb78fcd..5a7439959963d9a15d11c4883094b8012d14ad4c 100644 (file)
@@ -1013,7 +1013,7 @@ get_memberof(struct main_args *margs, char *user, char *domain, char *group)
                   "%s| %s: DEBUG: Kerberos is disabled. Use username/password with ldap url instead\n",
                   LogTime(), PROGRAM);
         } else {
-            kc = krb5_create_cache(domain);
+            kc = krb5_create_cache(domain, margs->principal);
             if (kc) {
                 error((char *)
                       "%s| %s: ERROR: Error during setup of Kerberos credential cache\n",