diff -rubwBEN 3.4/configure.ac 3.4-mm/configure.ac --- 3.4/configure.ac 2013-08-24 19:10:13.310836377 +0100 +++ 3.4-mm/configure.ac 2013-08-24 17:52:47.001721169 +0100 @@ -1906,10 +1906,7 @@ AC_DEFINE(HAVE_KRB5_GET_ERROR_MESSAGE,1, [Define to 1 if you have krb5_get_error_message]),) AC_CHECK_DECLS(krb5_kt_free_entry,,,[#include ]) - AC_CHECK_TYPE(krb5_pac, - AC_DEFINE(HAVE_KRB5_PAC,1, - [Define to 1 if you have krb5_pac]),, - [#include ]) + AC_CHECK_DECLS(krb5_pac,,,[#include ]) AC_CHECK_LIB(krb5,krb5_kt_free_entry, AC_DEFINE(HAVE_KRB5_KT_FREE_ENTRY,1, [Define to 1 if you have krb5_kt_free_entry]),) diff -rubwBEN 3.4/helpers/external_acl/kerberos_ldap_group/kerberos_ldap_group.cc 3.4-mm/helpers/external_acl/kerberos_ldap_group/kerberos_ldap_group.cc --- 3.4/helpers/external_acl/kerberos_ldap_group/kerberos_ldap_group.cc 2013-08-12 00:01:44.458703000 +0100 +++ 3.4-mm/helpers/external_acl/kerberos_ldap_group/kerberos_ldap_group.cc 2013-08-25 01:11:05.941373265 +0100 @@ -413,8 +413,14 @@ log((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM, up, np); domain = get_netbios_name(&margs, netbios); user = nuser; + if (up) { xfree(up); + up=NULL; + } + if (np) { xfree(np); + np=NULL; + } } else if (domain) { strup(domain); *domain = '\0'; @@ -436,8 +442,14 @@ else log((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM, up, domain ? dp : "NULL"); + if (up) { xfree(up); + up=NULL; + } + if (dp) { xfree(dp); + dp=NULL; + } if (!strcmp(user, "QQ") && domain && !strcmp(domain, "QQ")) { clean_args(&margs); exit(-1); diff -rubwBEN 3.4/helpers/external_acl/kerberos_ldap_group/support_krb5.cc 3.4-mm/helpers/external_acl/kerberos_ldap_group/support_krb5.cc --- 3.4/helpers/external_acl/kerberos_ldap_group/support_krb5.cc 2013-08-12 00:01:44.458703000 +0100 +++ 3.4-mm/helpers/external_acl/kerberos_ldap_group/support_krb5.cc 2013-08-25 16:10:21.140711113 +0100 @@ -184,10 +184,10 @@ if (!principal_name) { 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); - creds = (krb5_creds *) xmalloc(sizeof(*creds)); - memset(creds, 0, sizeof(*creds)); for (i = 0; i < nprinc; ++i) { + creds = (krb5_creds *) xmalloc(sizeof(*creds)); + memset(creds, 0, sizeof(*creds)); /* * get credentials */ @@ -205,8 +205,10 @@ 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); - if (service) + if (service) { xfree(service); + service = NULL; + } code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0); #endif if (code) { @@ -233,8 +235,10 @@ 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); - if (service) + if (service) { xfree(service); + service=NULL; + } if (code) { error((char *) "%s| %s: ERROR: Error while initialising TGT credentials : %s\n", LogTime(), PROGRAM, error_message(code)); goto loop_end; @@ -253,8 +257,18 @@ if (principal_name) xfree(principal_name); principal_name = NULL; + if (tgt_creds) + krb5_free_creds(kparam.context, tgt_creds); + tgt_creds = NULL; + if (creds) + krb5_free_creds(kparam.context, creds); + creds = NULL; + } + if (principal_name) + xfree(principal_name); + principal_name = NULL; if (tgt_creds) krb5_free_creds(kparam.context, tgt_creds); tgt_creds = NULL; @@ -287,8 +301,10 @@ 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); - if (service) + if (service) { xfree(service); + service = NULL; + } code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0); #endif if (code) { @@ -318,10 +334,13 @@ krb5_kt_close(kparam.context, keytab); if (keytab_name) xfree(keytab_name); + keytab_name = NULL; if (principal_name) xfree(principal_name); + principal_name = NULL; if (mem_cache) xfree(mem_cache); + mem_cache = NULL; if (principal) krb5_free_principal(kparam.context, principal); for (i = 0; i < nprinc; ++i) { @@ -330,6 +349,7 @@ } if (principal_list) xfree(principal_list); + principal_list = NULL; if (creds) krb5_free_creds(kparam.context, creds); diff -rubwBEN 3.4/helpers/external_acl/kerberos_ldap_group/support_ldap.cc 3.4-mm/helpers/external_acl/kerberos_ldap_group/support_ldap.cc --- 3.4/helpers/external_acl/kerberos_ldap_group/support_ldap.cc 2013-08-12 00:01:44.458703000 +0100 +++ 3.4-mm/helpers/external_acl/kerberos_ldap_group/support_ldap.cc 2013-08-25 14:15:16.466539908 +0100 @@ -588,15 +588,15 @@ if ((values = ldap_get_values_len(ld, msg, attr)) != NULL) { for (il = 0; values[il] != NULL; ++il) { - attr_value = (char **) xrealloc(attr_value, (il + 1) * sizeof(char *)); + attr_value = (char **) xrealloc(attr_value, (max_attr + 1) * sizeof(char *)); if (!attr_value) break; - attr_value[il] = (char *) xmalloc(values[il]->bv_len + 1); - memcpy(attr_value[il], values[il]->bv_val, values[il]->bv_len); - attr_value[il][values[il]->bv_len] = 0; + attr_value[max_attr] = (char *) xmalloc(values[il]->bv_len + 1); + memcpy(attr_value[max_attr], values[il]->bv_val, values[il]->bv_len); + attr_value[max_attr][values[il]->bv_len] = 0; + max_attr++; } - max_attr = il; } ber_bvecfree(values); } @@ -940,7 +940,10 @@ } nhosts = free_hostname_list(&hlist, nhosts); + if (bindp) { xfree(bindp); + bindp = NULL; + } if (margs->lbind) { bindp = xstrdup(margs->lbind); } else { @@ -1180,10 +1183,13 @@ krb5_cleanup(); #endif if (lcreds) { + if (lcreds->dn) xfree(lcreds->dn); + if (lcreds->pw) xfree(lcreds->pw); xfree(lcreds); } + if (bindp) xfree(bindp); return (retval); } diff -rubwBEN 3.4/helpers/negotiate_auth/kerberos/Makefile.am 3.4-mm/helpers/negotiate_auth/kerberos/Makefile.am --- 3.4/helpers/negotiate_auth/kerberos/Makefile.am 2013-08-12 00:01:44.458703000 +0100 +++ 3.4-mm/helpers/negotiate_auth/kerberos/Makefile.am 2013-08-23 13:16:29.677167792 +0100 @@ -7,7 +7,7 @@ AM_CPPFLAGS = $(INCLUDES) -I$(srcdir) -negotiate_kerberos_auth_SOURCES = negotiate_kerberos_auth.cc +negotiate_kerberos_auth_SOURCES = negotiate_kerberos_auth.cc negotiate_kerberos_pac.cc negotiate_kerberos_auth_LDFLAGS = negotiate_kerberos_auth_LDADD = \ $(top_builddir)/lib/libmiscencoding.la \ diff -rubwBEN 3.4/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc 3.4-mm/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc --- 3.4/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc 2013-08-12 00:01:44.458703000 +0100 +++ 3.4-mm/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc 2013-08-24 22:20:20.064119213 +0100 @@ -36,79 +36,7 @@ #if HAVE_GSSAPI -#if HAVE_STRING_H -#include -#endif -#if HAVE_STDOI_H -#include -#endif -#if HAVE_NETDB_H -#include -#endif -#if HAVE_UNISTD_H -#include -#endif -#if HAVE_TIME_H -#include -#endif - -#include "util.h" -#include "base64.h" - -#if HAVE_GSSAPI_GSSAPI_H -#include -#elif HAVE_GSSAPI_H -#include -#endif - -#if !HAVE_HEIMDAL_KERBEROS -#if HAVE_GSSAPI_GSSAPI_KRB5_H -#include -#endif -#if HAVE_GSSAPI_GSSAPI_GENERIC_H -#include -#endif -#if HAVE_GSSAPI_GSSAPI_EXT_H -#include -#endif -#endif - -#ifndef gss_nt_service_name -#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE -#endif - -#define PROGRAM "negotiate_kerberos_auth" - -#ifndef MAX_AUTHTOKEN_LEN -#define MAX_AUTHTOKEN_LEN 65535 -#endif -#ifndef SQUID_KERB_AUTH_VERSION -#define SQUID_KERB_AUTH_VERSION "3.0.4sq" -#endif - -int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, - const char *function, int log); -char *gethost_name(void); -static const char *LogTime(void); - -static const unsigned char ntlmProtocol[] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0}; - -static const char * -LogTime() -{ - struct tm *tm; - struct timeval now; - static time_t last_t = 0; - static char buf[128]; - - gettimeofday(&now, NULL); - if (now.tv_sec != last_t) { - tm = localtime((time_t *) & now.tv_sec); - strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm); - last_t = now.tv_sec; - } - return buf; -} +#include "negotiate_kerberos.h" char * gethost_name(void) @@ -213,6 +141,19 @@ char buf[MAX_AUTHTOKEN_LEN]; char *c, *p; char *user = NULL; + char *rfc_user = NULL; +#if (defined(HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT) || defined(HAVE_GSS_MAP_NAME_TO_ANY)) && HAVE_KRB5_PAC + char ad_groups[MAX_PAC_GROUP_SIZE]; + char *ag=NULL; + krb5_context context = NULL; + krb5_error_code ret; + krb5_pac pac; +#if HAVE_HEIMDAL_KERBEROS + gss_buffer_desc data_set = GSS_C_EMPTY_BUFFER; +#else + gss_buffer_desc type_id = GSS_C_EMPTY_BUFFER; +#endif +#endif int length = 0; static int err = 0; int opt, log = 0, norealm = 0; @@ -284,6 +225,8 @@ snprintf((char *) service.value, strlen(service_name) + strlen(host_name) + 2, "%s@%s", service_name, host_name); service.length = strlen((char *) service.value); + xfree(host_name); + host_name = NULL; } while (1) { @@ -351,10 +294,6 @@ xfree(token); token = NULL; } - if (host_name) { - xfree(host_name); - host_name = NULL; - } fprintf(stdout, "BH quit command\n"); exit(0); } @@ -458,8 +397,44 @@ if (norealm && (p = strchr(user, '@')) != NULL) { *p = '\0'; } + +#if (defined(HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT) || defined(HAVE_GSS_MAP_NAME_TO_ANY)) && HAVE_KRB5_PAC + ret = krb5_init_context(&context); + if (!check_k5_err(context, "krb5_init_context", ret)) { +#define ADWIN2KPAC 128 +#if HAVE_HEIMDAL_KERBEROS + major_status = gsskrb5_extract_authz_data_from_sec_context(&minor_status, + gss_context, ADWIN2KPAC, &data_set); + if (!check_gss_err(major_status, minor_status, + "gsskrb5_extract_authz_data_from_sec_context()", log)) { + ret = krb5_pac_parse(context, data_set.value, data_set.length, &pac); + gss_release_buffer(&minor_status, &data_set); + if (!check_k5_err(context, "krb5_pac_parse", ret)) { + ag = get_ad_groups((char *)&ad_groups, context, pac); + krb5_pac_free(context, pac); + } + krb5_free_context(context); + } +#else + type_id.value = (void *)"mspac"; + type_id.length = strlen((char *)type_id.value); + + major_status = gss_map_name_to_any(&minor_status, client_name, 1, &type_id, (gss_any_t *)&pac); + if (!check_gss_err(major_status, minor_status, "gss_map_name_to_any()", log)) { + ag = get_ad_groups((char *)&ad_groups,context, pac); + } + (void)gss_release_any_name_mapping(&minor_status, client_name, &type_id, (gss_any_t *)&pac); + krb5_free_context(context); +#endif + } + if (ag) { + debug((char *) "%s| %s: DEBUG: Groups %s\n", LogTime(), PROGRAM, ag); + } +#endif fprintf(stdout, "AF %s %s\n", token, user); - debug((char *) "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, token, rfc1738_escape(user)); + rfc_user = rfc1738_escape(user); + debug((char *) "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, token, rfc_user); +/* xfree(rfc_user); */ if (log) fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(), PROGRAM, rfc1738_escape(user)); diff -rubwBEN 3.4/helpers/negotiate_auth/kerberos/negotiate_kerberos.h 3.4-mm/helpers/negotiate_auth/kerberos/negotiate_kerberos.h --- 3.4/helpers/negotiate_auth/kerberos/negotiate_kerberos.h 1970-01-01 01:00:00.000000000 +0100 +++ 3.4-mm/helpers/negotiate_auth/kerberos/negotiate_kerberos.h 2013-08-24 19:11:59.141839001 +0100 @@ -0,0 +1,154 @@ +/* + * ----------------------------------------------------------------------------- + * + * Author: Markus Moeller (markus_moeller at compuserve.com) + * + * Copyright (C) 2013 Markus Moeller. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * As a special exemption, M Moeller gives permission to link this program + * with MIT, Heimdal or other GSS/Kerberos libraries, and distribute + * the resulting executable, without including the source code for + * the Libraries in the source distribution. + * + * ----------------------------------------------------------------------------- + */ + +#if HAVE_STRING_H +#include +#endif +#if HAVE_STDIO_H +#include +#endif +#if HAVE_NETDB_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_TIME_H +#include +#endif + +#include "util.h" +#include "base64.h" + +#if HAVE_KRB5_H +#if HAVE_BROKEN_SOLARIS_KRB5_H +#warn "Warning! You have a broken Solaris system header" +#warn "http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6837512" +#if defined(__cplusplus) +#define KRB5INT_BEGIN_DECLS extern "C" { +#define KRB5INT_END_DECLS +KRB5INT_BEGIN_DECLS +#endif +#endif /* HAVE_BROKEN_SOLARIS_KRB5_H */ +#if HAVE_BROKEN_HEIMDAL_KRB5_H +extern "C" { +#include +} +#else +#include +#endif +#endif /* HAVE_KRB5_H */ + +#if HAVE_GSSAPI_GSSAPI_H +#include +#elif HAVE_GSSAPI_H +#include +#endif + +#if !HAVE_HEIMDAL_KERBEROS +#if HAVE_GSSAPI_GSSAPI_KRB5_H +#include +#endif +#if HAVE_GSSAPI_GSSAPI_GENERIC_H +#include +#endif +#if HAVE_GSSAPI_GSSAPI_EXT_H +#include +#endif +#else +#if HAVE_GSSAPI_GSSAPI_KRB5_H +#include +#endif +#endif + +#ifndef gss_nt_service_name +#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE +#endif + +#define PROGRAM "negotiate_kerberos_auth" + +#ifndef MAX_AUTHTOKEN_LEN +#define MAX_AUTHTOKEN_LEN 65535 +#endif +#ifndef SQUID_KERB_AUTH_VERSION +#define SQUID_KERB_AUTH_VERSION "3.0.4sq" +#endif + +typedef struct { + uint16_t length; + uint16_t maxlength; + uint32_t pointer; +} RPC_UNICODE_STRING; + +char *gethost_name(void); + +static const char *LogTime(void); + +static const unsigned char ntlmProtocol[] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0}; + +static const char * +LogTime() +{ + struct tm *tm; + struct timeval now; + static time_t last_t = 0; + static char buf[128]; + + gettimeofday(&now, NULL); + if (now.tv_sec != last_t) { + tm = localtime((time_t *) & now.tv_sec); + strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm); + last_t = now.tv_sec; + } + return buf; +} + +int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, + const char *function, int log); + +int check_k5_err(krb5_context context, const char *msg, krb5_error_code code); + +char *gethost_name(void); + +#if (defined(HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT) || defined(HAVE_GSS_MAP_NAME_TO_ANY)) && HAVE_KRB5_PAC +#define MAX_PAC_GROUP_SIZE 200*60 +void align(int n); +void getustr(RPC_UNICODE_STRING *string); +char **getgids(char **Rids, uint32_t GroupIds, uint32_t GroupCount); +char *getdomaingids(char *ad_groups, uint32_t DomainLogonId, char **Rids, uint32_t GroupCount); +char *getextrasids(char *ad_groups, uint32_t ExtraSids, uint32_t SidCount, uint32_t GroupCount); +uint64_t get6byt_be(void); +uint32_t get4byt(void); +uint16_t get2byt(void); +uint8_t get1byt(void); +char *xstrcpy( char *src, const char*dst); +char *xstrcat( char *src, const char*dst); +int checkustr(RPC_UNICODE_STRING *string); +char *get_ad_groups(char *ad_groups, krb5_context context, krb5_pac pac); +#endif diff -rubwBEN 3.4/helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc 3.4-mm/helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc --- 3.4/helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc 1970-01-01 01:00:00.000000000 +0100 +++ 3.4-mm/helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc 2013-08-24 22:39:51.018148248 +0100 @@ -0,0 +1,450 @@ +/* + * ----------------------------------------------------------------------------- + * + * Author: Markus Moeller (markus_moeller at compuserve.com) + * + * Copyright (C) 2007 Markus Moeller. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * As a special exemption, M Moeller gives permission to link this program + * with MIT, Heimdal or other GSS/Kerberos libraries, and distribute + * the resulting executable, without including the source code for + * the Libraries in the source distribution. + * + * ----------------------------------------------------------------------------- + */ + +#include "squid.h" +#include "rfc1738.h" +#include "compat/getaddrinfo.h" +#include "compat/getnameinfo.h" + +#if (defined(HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT) || defined(HAVE_GSS_MAP_NAME_TO_ANY)) && HAVE_KRB5_PAC + +#include "negotiate_kerberos.h" + +static int bpos; +static krb5_data *ad_data; +static unsigned char *p; + +int +check_k5_err(krb5_context context, const char *function, krb5_error_code code) +{ + const char *errmsg; + + if (code) { + errmsg = krb5_get_error_message(context, code); + debug((char *) "%s| %s: ERROR: %s failed: %s\n", LogTime(), PROGRAM, function, errmsg); + fprintf(stderr, "%s| %s: ERROR: %s: %s\n", LogTime(), PROGRAM, function, errmsg); + krb5_free_error_message(context, errmsg); + } + return code; +} + +void +align(int n){ + if ( bpos % n != 0 ) { + int al; + al = (bpos/n); + bpos = bpos+(bpos-n*al); + } +} + +void +getustr(RPC_UNICODE_STRING *string) { + + string->length = (p[bpos]<<0) | (p[bpos+1]<<8); + string->maxlength = (p[bpos+2]<<0) | (p[bpos+2+1]<<8); + string->pointer = (p[bpos+4]<<0) | (p[bpos+4+1]<<8) | (p[bpos+4+2]<<16) | (p[bpos+4+3]<<24); + bpos = bpos+8; + +} + +uint64_t +get6byt_be(void) { + uint64_t var; + + var = ((int64_t)p[bpos+5]<<0) | ((int64_t)p[bpos+4]<<8) | ((int64_t)p[bpos+3]<<16) | ((int64_t)p[bpos+2]<<24) | ((int64_t)p[bpos+1]<<32) | ((int64_t)p[bpos]<<40); + bpos = bpos+6; + + return var; +} + +uint32_t +get4byt(void) { + uint32_t var; + + var=(p[bpos]<<0) | (p[bpos+1]<<8) | (p[bpos+2]<<16) | (p[bpos+3]<<24); + bpos = bpos+4; + + return var; +} + +uint16_t +get2byt(void) { + uint16_t var; + + var=(p[bpos]<<0) | (p[bpos+1]<<8); + bpos = bpos+2; + + return var; +} + +uint8_t +get1byt(void) { + uint8_t var; + + var=(p[bpos]<<0); + bpos = bpos+1; + + return var; +} + +char * +xstrcpy( char *src, const char*dst) { + if (dst) { + if (strlen(dst)>MAX_PAC_GROUP_SIZE) + return NULL; + else + return strcpy(src,dst); + } else + return src; +} + +char * +xstrcat( char *src, const char*dst) { + if (dst) { + if (strlen(src)+strlen(dst)+1>MAX_PAC_GROUP_SIZE) + return NULL; + else + return strcat(src,dst); + } else + return src; +} + + +int +checkustr(RPC_UNICODE_STRING *string) { + uint32_t size,off,len; + + if (string->pointer != 0){ + align(4); + size = (p[bpos]<<0) | (p[bpos+1]<<8) | (p[bpos+2]<<16) | (p[bpos+3]<<24); + bpos = bpos+4; + off = (p[bpos]<<0) | (p[bpos+1]<<8) | (p[bpos+2]<<16) | (p[bpos+3]<<24); + bpos = bpos+4; + len = (p[bpos]<<0) | (p[bpos+1]<<8) | (p[bpos+2]<<16) | (p[bpos+3]<<24); + bpos = bpos+4; + if (len > size || off != 0 || + string->length > string->maxlength || len != string->length/2) { + debug((char *) "%s| %s: ERROR: RPC_UNICODE_STRING encoding error => size: %d len: %d/%d maxlength: %d offset: %d\n", + LogTime(), PROGRAM, size, len, string->length, string->maxlength, off); + return -1; + } + /* UNICODE string */ + bpos = bpos+string->length; + } + return 0; +} + +char ** +getgids(char **Rids, uint32_t GroupIds, uint32_t GroupCount) { + if (GroupIds!= 0){ + uint32_t ngroup; + uint32_t sauth; + int l; + + align(4); + ngroup = get4byt(); + if ( ngroup != GroupCount) { + debug((char *) "%s| %s: ERROR: Group encoding error => GroupCount: %d Array size: %d\n", + LogTime(), PROGRAM, GroupCount, ngroup); + return NULL; + } + debug((char *) "%s| %s: INFO: Found %d rids\n", LogTime(), PROGRAM, GroupCount); + + Rids=(char **)xcalloc(GroupCount*sizeof(char*),1); + for ( l=0; l<(int)GroupCount; l++) { + Rids[l]=(char *)xcalloc(4*sizeof(char),1); + memcpy((void *)Rids[l],(void *)&p[bpos],4); + sauth = get4byt(); + debug((char *) "%s| %s: Info: Got rid: %u\n", LogTime(), PROGRAM, sauth); + /* attribute */ + bpos = bpos+4; + } + } + return Rids; +} + +char * +getdomaingids(char *ad_groups, uint32_t DomainLogonId, char **Rids, uint32_t GroupCount) { + if (DomainLogonId!= 0) { + uint32_t nauth; + uint8_t rev; + uint64_t idauth; + uint32_t sauth; + char dli[256]; + char *ag; + int length; + int l; + + align(4); + + nauth = get4byt(); + + /* prepend rids with DomainID */ + length=1+1+6+nauth*4; + for (l=0; l<(int)GroupCount;l++){ + ag=(char *)xcalloc((length+4)*sizeof(char),1); + memcpy((void *)ag,(const void*)&p[bpos],1); + memcpy((void *)&ag[1],(const void*)&p[bpos+1],1); + ag[1] = ag[1]+1; + memcpy((void *)&ag[2],(const void*)&p[bpos+2],6+nauth*4); + memcpy((void *)&ag[length],(const void*)Rids[l],4); + if (l==0) { + if (!xstrcpy(ad_groups,"group=")) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + } else { + if (!xstrcat(ad_groups," group=")) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + } + if (!xstrcat(ad_groups,base64_encode_bin(ag, length+4))) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + xfree(ag); + xfree(Rids[l]); + } + xfree(Rids); + + /* mainly for debug only */ + rev = get1byt(); + bpos = bpos + 1; /*nsub*/ + idauth = get6byt_be(); + + snprintf(dli,sizeof(dli),"S-%d-%lu",rev,(long unsigned int)idauth); + for ( l=0;l<(int)nauth;l++ ) { + sauth = get4byt(); + snprintf((char *)&dli[strlen(dli)],sizeof(dli)-strlen(dli),"-%u",sauth); + } + debug((char *) "%s| %s: INFO: Got DomainLogonId %s\n", LogTime(), PROGRAM, dli); + } + return ad_groups; +} + +char * +getextrasids(char *ad_groups, uint32_t ExtraSids, uint32_t SidCount, uint32_t GroupCount) { + if (ExtraSids!= 0){ + uint32_t ngroup; + uint32_t *pa; + char *ag; + int length; + int l; + + align(4); + ngroup = get4byt(); + if ( ngroup != SidCount) { + debug((char *) "%s| %s: ERROR: Group encoding error => SidCount: %d Array size: %d\n", + LogTime(), PROGRAM, SidCount, ngroup); + return NULL; + } + debug((char *) "%s| %s: INFO: Found %d ExtraSIDs\n", LogTime(), PROGRAM, SidCount); + + pa=(uint32_t *)xmalloc(SidCount*sizeof(uint32_t)); + for ( l=0; l < (int)SidCount; l++ ){ + pa[l] = get4byt(); + bpos = bpos+4; /* attr */ + } + + for ( l=0; l<(int)SidCount; l++ ){ + char es[256]; + uint32_t nauth; + uint8_t rev; + uint64_t idauth; + uint32_t sauth; + int k; + + if (pa[l] != 0){ + nauth = get4byt(); + + length = 1+1+6+nauth*4; + ag = (char *)xcalloc((length)*sizeof(char),1); + memcpy((void *)ag,(const void*)&p[bpos],length); + if (!ad_groups) { + if (!xstrcpy(ad_groups,"group=")) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + } else { + if (!xstrcat(ad_groups," group=")) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + } + if (!xstrcat(ad_groups,base64_encode_bin(ag, length))) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + xfree(ag); + + rev = get1byt(); + bpos = bpos + 1; /* nsub */ + idauth = get6byt_be(); + + snprintf(es,sizeof(es),"S-%d-%lu",rev,(long unsigned int)idauth); + for ( k=0;k<(int)nauth;k++ ) { + sauth = get4byt(); + snprintf((char *)&es[strlen(es)],sizeof(es)-strlen(es),"-%u",sauth); + } + debug((char *) "%s| %s: INFO: Got ExtraSid %s\n", LogTime(), PROGRAM, es); + } + } + xfree(pa); + } + return ad_groups; +} + +char * +get_ad_groups(char *ad_groups, krb5_context context, krb5_pac pac){ + krb5_error_code ret; + RPC_UNICODE_STRING EffectiveName; + RPC_UNICODE_STRING FullName; + RPC_UNICODE_STRING LogonScript; + RPC_UNICODE_STRING ProfilePath; + RPC_UNICODE_STRING HomeDirectory; + RPC_UNICODE_STRING HomeDirectoryDrive; + RPC_UNICODE_STRING LogonServer; + RPC_UNICODE_STRING LogonDomainName; + uint32_t GroupCount=0; + uint32_t GroupIds=0; + uint32_t LogonDomainId=0; + uint32_t SidCount=0; + uint32_t ExtraSids=0; + /* + uint32_t ResourceGroupDomainSid=0; + uint32_t ResourceGroupCount=0; + uint32_t ResourceGroupIds=0; + */ + char **Rids=NULL; + int l=0; + + ad_data = (krb5_data *)xmalloc(sizeof(krb5_data)); + +#define KERB_LOGON_INFO 1 + ret = krb5_pac_get_buffer(context, pac, KERB_LOGON_INFO, ad_data); + if (check_k5_err(context, "krb5_pac_get_buffer", ret)) + goto k5clean; + + p = (unsigned char *)ad_data->data; + + debug((char *) "%s| %s: INFO: Got PAC data of lengh %d\n", + LogTime(), PROGRAM, (int)ad_data->length); + + /* Skip 16 bytes icommon RPC header + * Skip 4 bytes RPC unique pointer referent + * http://msdn.microsoft.com/en-gb/library/cc237933.aspx + */ + /* Some data are pointers to data which follows the main KRB5 LOGON structure => + * So need to read the data + * some logical consistency checks are done when analysineg the pointer data + */ + bpos = 20; + /* 8 bytes LogonTime + * 8 bytes LogoffTime + * 8 bytes KickOffTime + * 8 bytes PasswordLastSet + * 8 bytes PasswordCanChange + * 8 bytes PasswordMustChange + */ + bpos = bpos+48; + getustr(&EffectiveName); + getustr(&FullName); + getustr(&LogonScript); + getustr(&ProfilePath); + getustr(&HomeDirectory); + getustr(&HomeDirectoryDrive); + /* 2 bytes LogonCount + * 2 bytes BadPasswordCount + * 4 bytes UserID + * 4 bytes PrimaryGroupId + */ + bpos = bpos+12; + GroupCount = get4byt(); + GroupIds = get4byt(); + /* 4 bytes UserFlags + * 16 bytes UserSessionKey + */ + bpos = bpos+20; + getustr(&LogonServer); + getustr(&LogonDomainName); + LogonDomainId = get4byt(); + /* 8 bytes Reserved1 + * 4 bytes UserAccountControl + * 4 bytes SubAuthStatus + * 8 bytes LastSuccessfullLogon + * 8 bytes LastFailedLogon + * 4 bytes FailedLogonCount + * 4 bytes Reserved2 + */ + bpos = bpos+40; + SidCount = get4byt(); + ExtraSids = get4byt(); + /* 4 bytes ResourceGroupDomainSid + * 4 bytes ResourceGroupCount + * 4 bytes ResourceGroupIds + */ + bpos = bpos+12; + /* + * Read all data from structure => Now check pointers + */ + if (checkustr(&EffectiveName)<0) + goto k5clean; + if (checkustr(&FullName)<0) + goto k5clean; + if (checkustr(&LogonScript)<0) + goto k5clean; + if (checkustr(&ProfilePath)<0) + goto k5clean; + if (checkustr(&HomeDirectory)<0) + goto k5clean; + if (checkustr(&HomeDirectoryDrive)<0) + goto k5clean; + Rids = getgids(Rids,GroupIds,GroupCount); + if (checkustr(&LogonServer)<0) + goto k5clean; + if (checkustr(&LogonDomainName)<0) + goto k5clean; + ad_groups = getdomaingids(ad_groups,LogonDomainId,Rids,GroupCount); + if ((ad_groups = getextrasids(ad_groups,ExtraSids,SidCount,GroupCount))==NULL) + goto k5clean; + + debug((char *) "%s| %s: INFO: Read %d of %d bytes \n", LogTime(), PROGRAM, bpos, (int)ad_data->length); + krb5_free_data(context, ad_data); + return ad_groups; +k5clean: + for ( l=0; l<(int)GroupCount; l++) { + if (Rids[l]) + xfree(Rids[l]); + } + xfree(Rids); + krb5_free_data(context, ad_data); + return NULL; +} +#endif diff -rubwBEN 3.4/helpers/negotiate_auth/kerberos/test_negotiate_auth.sh 3.4-mm/helpers/negotiate_auth/kerberos/test_negotiate_auth.sh --- 3.4/helpers/negotiate_auth/kerberos/test_negotiate_auth.sh 1970-01-01 01:00:00.000000000 +0100 +++ 3.4-mm/helpers/negotiate_auth/kerberos/test_negotiate_auth.sh 2013-08-24 18:33:52.091782292 +0100 @@ -0,0 +1,7 @@ +#!/bin/bash +if [[ -z "$1" ]]; then + echo "Need squid hostname" + exit 0 +fi +dir=`dirname $0` +$dir/negotiate_kerberos_auth_test $1 | awk '{sub(/Token:/,"YR"); print $0}END{print "QQ"}' | $dir/negotiate_kerberos_auth -d diff -rubwBEN 3.4/negotiate_kerberos_auth.cc 3.4-mm/negotiate_kerberos_auth.cc --- 3.4/negotiate_kerberos_auth.cc 1970-01-01 01:00:00.000000000 +0100 +++ 3.4-mm/negotiate_kerberos_auth.cc 2013-08-24 14:45:18.571442258 +0100 @@ -0,0 +1,529 @@ +/* + * ----------------------------------------------------------------------------- + * + * Author: Markus Moeller (markus_moeller at compuserve.com) + * + * Copyright (C) 2007 Markus Moeller. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * As a special exemption, M Moeller gives permission to link this program + * with MIT, Heimdal or other GSS/Kerberos libraries, and distribute + * the resulting executable, without including the source code for + * the Libraries in the source distribution. + * + * ----------------------------------------------------------------------------- + */ +/* + * Hosted at http://sourceforge.net/projects/squidkerbauth + */ +#include "squid.h" +#include "rfc1738.h" +#include "compat/getaddrinfo.h" +#include "compat/getnameinfo.h" + +#if HAVE_GSSAPI + +#include "negotiate_kerberos.h" + +char * +gethost_name(void) +{ + /* + * char hostname[sysconf(_SC_HOST_NAME_MAX)]; + */ + char hostname[1024]; + struct addrinfo *hres = NULL, *hres_list; + int rc, count; + + rc = gethostname(hostname, sizeof(hostname)-1); + if (rc) { + fprintf(stderr, "%s| %s: ERROR: resolving hostname '%s' failed\n", + LogTime(), PROGRAM, hostname); + return NULL; + } + rc = getaddrinfo(hostname, NULL, NULL, &hres); + if (rc != 0) { + fprintf(stderr, + "%s| %s: ERROR: resolving hostname with getaddrinfo: %s failed\n", + LogTime(), PROGRAM, gai_strerror(rc)); + return NULL; + } + hres_list = hres; + count = 0; + while (hres_list) { + ++count; + hres_list = hres_list->ai_next; + } + rc = getnameinfo(hres->ai_addr, hres->ai_addrlen, hostname, + sizeof(hostname), NULL, 0, 0); + if (rc != 0) { + fprintf(stderr, + "%s| %s: ERROR: resolving ip address with getnameinfo: %s failed\n", + LogTime(), PROGRAM, gai_strerror(rc)); + freeaddrinfo(hres); + return NULL; + } + freeaddrinfo(hres); + hostname[sizeof(hostname)-1] = '\0'; + return (xstrdup(hostname)); +} + +int +check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, + const char *function, int log) +{ + if (GSS_ERROR(major_status)) { + OM_uint32 maj_stat, min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + char buf[1024]; + size_t len; + + len = 0; + msg_ctx = 0; + do { + /* convert major status code (GSS-API error) to text */ + maj_stat = gss_display_status(&min_stat, major_status, + GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); + if (maj_stat == GSS_S_COMPLETE && status_string.length > 0) { + if (sizeof(buf) > len + status_string.length + 1) { + snprintf(buf + len, (sizeof(buf) - len), "%s", (char *) status_string.value); + len += status_string.length; + } + } else + msg_ctx = 0; + gss_release_buffer(&min_stat, &status_string); + } while (msg_ctx); + if (sizeof(buf) > len + 2) { + snprintf(buf + len, (sizeof(buf) - len), "%s", ". "); + len += 2; + } + msg_ctx = 0; + do { + /* convert minor status code (underlying routine error) to text */ + maj_stat = gss_display_status(&min_stat, minor_status, + GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); + if (maj_stat == GSS_S_COMPLETE && status_string.length > 0) { + if (sizeof(buf) > len + status_string.length) { + snprintf(buf + len, (sizeof(buf) - len), "%s", (char *) status_string.value); + len += status_string.length; + } + } else + msg_ctx = 0; + gss_release_buffer(&min_stat, &status_string); + } while (msg_ctx); + debug((char *) "%s| %s: ERROR: %s failed: %s\n", LogTime(), PROGRAM, function, buf); + fprintf(stdout, "BH %s failed: %s\n", function, buf); + if (log) + fprintf(stderr, "%s| %s: INFO: User not authenticated\n", LogTime(), + PROGRAM); + return (1); + } + return (0); +} + +int +main(int argc, char *const argv[]) +{ + char buf[MAX_AUTHTOKEN_LEN]; + char *c, *p; + char *user = NULL; + char *rfc_user = NULL; +#if (defined(HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT) || defined(HAVE_GSS_MAP_NAME_TO_ANY)) && HAVE_DECL_KRB5_PAC + char ad_groups[MAX_PAC_GROUP_SIZE]; + char *ag=NULL; + krb5_context context = NULL; + krb5_error_code ret; + krb5_pac pac; +#if HAVE_HEIMDAL_KERBEROS + gss_buffer_desc data_set = GSS_C_EMPTY_BUFFER; +#else + gss_buffer_desc type_id = GSS_C_EMPTY_BUFFER; +#endif +#endif + int length = 0; + static int err = 0; + int opt, log = 0, norealm = 0; + OM_uint32 ret_flags = 0, spnego_flag = 0; + char *service_name = (char *) "HTTP", *host_name = NULL; + char *token = NULL; + char *service_principal = NULL; + OM_uint32 major_status, minor_status; + gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; + gss_name_t client_name = GSS_C_NO_NAME; + gss_name_t server_name = GSS_C_NO_NAME; + gss_cred_id_t server_creds = GSS_C_NO_CREDENTIAL; + gss_buffer_desc service = GSS_C_EMPTY_BUFFER; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + const unsigned char *kerberosToken = NULL; + const unsigned char *spnegoToken = NULL; + size_t spnegoTokenLength = 0; + + setbuf(stdout, NULL); + setbuf(stdin, NULL); + + while (-1 != (opt = getopt(argc, argv, "dirs:h"))) { + switch (opt) { + case 'd': + debug_enabled = 1; + break; + case 'i': + log = 1; + break; + case 'r': + norealm = 1; + break; + case 's': + service_principal = xstrdup(optarg); + break; + case 'h': + fprintf(stderr, "Usage: \n"); + fprintf(stderr, "squid_kerb_auth [-d] [-i] [-s SPN] [-h]\n"); + fprintf(stderr, "-d full debug\n"); + fprintf(stderr, "-i informational messages\n"); + fprintf(stderr, "-r remove realm from username\n"); + fprintf(stderr, "-s service principal name\n"); + fprintf(stderr, "-h help\n"); + fprintf(stderr, + "The SPN can be set to GSS_C_NO_NAME to allow any entry from keytab\n"); + fprintf(stderr, "default SPN is HTTP/fqdn@DEFAULT_REALM\n"); + exit(0); + default: + fprintf(stderr, "%s| %s: WARNING: unknown option: -%c.\n", LogTime(), + PROGRAM, opt); + } + } + + debug((char *) "%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM, SQUID_KERB_AUTH_VERSION); + if (service_principal && strcasecmp(service_principal, "GSS_C_NO_NAME")) { + service.value = service_principal; + service.length = strlen((char *) service.value); + } else { + host_name = gethost_name(); + if (!host_name) { + fprintf(stderr, + "%s| %s: FATAL: Local hostname could not be determined. Please specify the service principal\n", + LogTime(), PROGRAM); + fprintf(stdout, "BH hostname error\n"); + exit(-1); + } + service.value = xmalloc(strlen(service_name) + strlen(host_name) + 2); + snprintf((char *) service.value, strlen(service_name) + strlen(host_name) + 2, + "%s@%s", service_name, host_name); + service.length = strlen((char *) service.value); + xfree(host_name); + host_name = NULL; + } + + while (1) { + if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) { + if (ferror(stdin)) { + debug((char *) "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n", + LogTime(), PROGRAM, ferror(stdin), + strerror(ferror(stdin))); + + fprintf(stdout, "BH input error\n"); + exit(1); /* BIIG buffer */ + } + fprintf(stdout, "BH input error\n"); + exit(0); + } + c = (char *) memchr(buf, '\n', sizeof(buf) - 1); + if (c) { + *c = '\0'; + length = c - buf; + } else { + err = 1; + } + if (err) { + debug((char *) "%s| %s: ERROR: Oversized message\n", LogTime(), PROGRAM); + fprintf(stdout, "BH Oversized message\n"); + err = 0; + continue; + } + debug((char *) "%s| %s: DEBUG: Got '%s' from squid (length: %d).\n", LogTime(), PROGRAM, buf, length); + + if (buf[0] == '\0') { + debug((char *) "%s| %s: ERROR: Invalid request\n", LogTime(), PROGRAM); + fprintf(stdout, "BH Invalid request\n"); + continue; + } + if (strlen(buf) < 2) { + debug((char *) "%s| %s: ERROR: Invalid request [%s]\n", LogTime(), PROGRAM, buf); + fprintf(stdout, "BH Invalid request\n"); + continue; + } + if (!strncmp(buf, "QQ", 2)) { + gss_release_buffer(&minor_status, &input_token); + gss_release_buffer(&minor_status, &output_token); + gss_release_buffer(&minor_status, &service); + gss_release_cred(&minor_status, &server_creds); + if (server_name) + gss_release_name(&minor_status, &server_name); + if (client_name) + gss_release_name(&minor_status, &client_name); + if (gss_context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&minor_status, &gss_context, NULL); + if (kerberosToken) { + /* Allocated by parseNegTokenInit, but no matching free function exists.. */ + if (!spnego_flag) + xfree((char *) kerberosToken); + kerberosToken = NULL; + } + if (spnego_flag) { + /* Allocated by makeNegTokenTarg, but no matching free function exists.. */ + if (spnegoToken) + xfree((char *) spnegoToken); + spnegoToken = NULL; + } + if (token) { + xfree(token); + token = NULL; + } + fprintf(stdout, "BH quit command\n"); + exit(0); + } + if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) { + debug((char *) "%s| %s: ERROR: Invalid request [%s]\n", LogTime(), PROGRAM, buf); + fprintf(stdout, "BH Invalid request\n"); + continue; + } + if (!strncmp(buf, "YR", 2)) { + if (gss_context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&minor_status, &gss_context, NULL); + gss_context = GSS_C_NO_CONTEXT; + } + if (strlen(buf) <= 3) { + debug((char *) "%s| %s: ERROR: Invalid negotiate request [%s]\n", LogTime(), PROGRAM, buf); + fprintf(stdout, "BH Invalid negotiate request\n"); + continue; + } + input_token.length = base64_decode_len(buf+3); + debug((char *) "%s| %s: DEBUG: Decode '%s' (decoded length: %d).\n", + LogTime(), PROGRAM, buf + 3, (int) input_token.length); + input_token.value = xmalloc(input_token.length); + + input_token.length = base64_decode((char *) input_token.value, input_token.length, buf+3); + + if ((input_token.length >= sizeof ntlmProtocol + 1) && + (!memcmp(input_token.value, ntlmProtocol, sizeof ntlmProtocol))) { + debug((char *) "%s| %s: WARNING: received type %d NTLM token\n", + LogTime(), PROGRAM, + (int) *((unsigned char *) input_token.value + + sizeof ntlmProtocol)); + fprintf(stdout, "BH received type %d NTLM token\n", + (int) *((unsigned char *) input_token.value + + sizeof ntlmProtocol)); + goto cleanup; + } + if (service_principal) { + if (strcasecmp(service_principal, "GSS_C_NO_NAME")) { + major_status = gss_import_name(&minor_status, &service, + (gss_OID) GSS_C_NULL_OID, &server_name); + + } else { + server_name = GSS_C_NO_NAME; + major_status = GSS_S_COMPLETE; + } + } else { + major_status = gss_import_name(&minor_status, &service, + gss_nt_service_name, &server_name); + } + + if (check_gss_err(major_status, minor_status, "gss_import_name()", log)) + goto cleanup; + + major_status = + gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_ACCEPT, &server_creds, NULL, NULL); + if (check_gss_err(major_status, minor_status, "gss_acquire_cred()", log)) + goto cleanup; + + major_status = gss_accept_sec_context(&minor_status, + &gss_context, + server_creds, + &input_token, + GSS_C_NO_CHANNEL_BINDINGS, + &client_name, NULL, &output_token, &ret_flags, NULL, NULL); + + if (output_token.length) { + spnegoToken = (const unsigned char *) output_token.value; + spnegoTokenLength = output_token.length; + token = (char *) xmalloc(base64_encode_len(spnegoTokenLength)); + if (token == NULL) { + debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM); + fprintf(stdout, "BH Not enough memory\n"); + goto cleanup; + } + base64_encode_str(token, base64_encode_len(spnegoTokenLength), + (const char *) spnegoToken, spnegoTokenLength); + + if (check_gss_err(major_status, minor_status, "gss_accept_sec_context()", log)) + goto cleanup; + if (major_status & GSS_S_CONTINUE_NEEDED) { + debug((char *) "%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM); + fprintf(stdout, "TT %s\n", token); + goto cleanup; + } + gss_release_buffer(&minor_status, &output_token); + major_status = + gss_display_name(&minor_status, client_name, &output_token, + NULL); + + if (check_gss_err(major_status, minor_status, "gss_display_name()", log)) + goto cleanup; + user = (char *) xmalloc(output_token.length + 1); + if (user == NULL) { + debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM); + fprintf(stdout, "BH Not enough memory\n"); + goto cleanup; + } + memcpy(user, output_token.value, output_token.length); + user[output_token.length] = '\0'; + if (norealm && (p = strchr(user, '@')) != NULL) { + *p = '\0'; + } + +#if (defined(HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT) || defined(HAVE_GSS_MAP_NAME_TO_ANY)) && HAVE_DECL_KRB5_PAC + ret = krb5_init_context(&context); + if (!check_k5_err(context, "krb5_init_context", ret)) { +#define ADWIN2KPAC 128 +#if HAVE_HEIMDAL_KERBEROS + major_status = gsskrb5_extract_authz_data_from_sec_context(&minor_status, + gss_context, ADWIN2KPAC, &data_set); + if (!check_gss_err(major_status, minor_status, + "gsskrb5_extract_authz_data_from_sec_context()", log)) { + ret = krb5_pac_parse(context, data_set.value, data_set.length, &pac); + gss_release_buffer(&minor_status, &data_set); + if (!check_k5_err(context, "krb5_pac_parse", ret)) { + ag = get_ad_groups((char *)&ad_groups, context, pac); + krb5_pac_free(context, pac); + } + krb5_free_context(context); + } +#else + type_id.value = (void *)"mspac"; + type_id.length = strlen((char *)type_id.value); + + major_status = gss_map_name_to_any(&minor_status, client_name, 1, &type_id, (gss_any_t *)&pac); + if (!check_gss_err(major_status, minor_status, "gss_map_name_to_any()", log)) { + ag = get_ad_groups((char *)&ad_groups,context, pac); + } + (void)gss_release_any_name_mapping(&minor_status, client_name, &type_id, (gss_any_t *)&pac); + krb5_free_context(context); +#endif + } + if (ag) { + debug((char *) "%s| %s: DEBUG: Groups %s\n", LogTime(), PROGRAM, ag); + } +#endif + fprintf(stdout, "AF %s %s\n", token, user); + rfc_user = rfc1738_escape(user); + debug((char *) "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, token, rfc_user); + xfree(rfc_user); + if (log) + fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(), + PROGRAM, rfc1738_escape(user)); + goto cleanup; + } else { + if (check_gss_err(major_status, minor_status, "gss_accept_sec_context()", log)) + goto cleanup; + if (major_status & GSS_S_CONTINUE_NEEDED) { + debug((char *) "%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM); + fprintf(stdout, "NA %s\n", token); + goto cleanup; + } + gss_release_buffer(&minor_status, &output_token); + major_status = + gss_display_name(&minor_status, client_name, &output_token, + NULL); + + if (check_gss_err(major_status, minor_status, "gss_display_name()", log)) + goto cleanup; + /* + * Return dummy token AA. May need an extra return tag then AF + */ + user = (char *) xmalloc(output_token.length + 1); + if (user == NULL) { + debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM); + fprintf(stdout, "BH Not enough memory\n"); + goto cleanup; + } + memcpy(user, output_token.value, output_token.length); + user[output_token.length] = '\0'; + if (norealm && (p = strchr(user, '@')) != NULL) { + *p = '\0'; + } + fprintf(stdout, "AF %s %s\n", "AA==", user); + debug((char *) "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, "AA==", rfc1738_escape(user)); + if (log) + fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(), + PROGRAM, rfc1738_escape(user)); + + } +cleanup: + gss_release_buffer(&minor_status, &input_token); + gss_release_buffer(&minor_status, &output_token); + gss_release_cred(&minor_status, &server_creds); + if (server_name) + gss_release_name(&minor_status, &server_name); + if (client_name) + gss_release_name(&minor_status, &client_name); + if (kerberosToken) { + /* Allocated by parseNegTokenInit, but no matching free function exists.. */ + if (!spnego_flag) + xfree((char *) kerberosToken); + kerberosToken = NULL; + } + if (spnego_flag) { + /* Allocated by makeNegTokenTarg, but no matching free function exists.. */ + if (spnegoToken) + xfree((char *) spnegoToken); + spnegoToken = NULL; + } + if (token) { + xfree(token); + token = NULL; + } + if (user) { + xfree(user); + user = NULL; + } + continue; + } +} +#else +#include +#include +#ifndef MAX_AUTHTOKEN_LEN +#define MAX_AUTHTOKEN_LEN 65535 +#endif +int +main(int argc, char *const argv[]) +{ + setbuf(stdout, NULL); + setbuf(stdin, NULL); + char buf[MAX_AUTHTOKEN_LEN]; + while (1) { + if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) { + fprintf(stdout, "BH input error\n"); + exit(0); + } + fprintf(stdout, "BH Kerberos authentication not supported\n"); + } +} +#endif /* HAVE_GSSAPI */ diff -rubwBEN 3.4/negotiate_kerberos.h 3.4-mm/negotiate_kerberos.h --- 3.4/negotiate_kerberos.h 1970-01-01 01:00:00.000000000 +0100 +++ 3.4-mm/negotiate_kerberos.h 2013-08-24 14:45:04.670441914 +0100 @@ -0,0 +1,154 @@ +/* + * ----------------------------------------------------------------------------- + * + * Author: Markus Moeller (markus_moeller at compuserve.com) + * + * Copyright (C) 2013 Markus Moeller. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * As a special exemption, M Moeller gives permission to link this program + * with MIT, Heimdal or other GSS/Kerberos libraries, and distribute + * the resulting executable, without including the source code for + * the Libraries in the source distribution. + * + * ----------------------------------------------------------------------------- + */ + +#if HAVE_STRING_H +#include +#endif +#if HAVE_STDIO_H +#include +#endif +#if HAVE_NETDB_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_TIME_H +#include +#endif + +#include "util.h" +#include "base64.h" + +#if HAVE_KRB5_H +#if HAVE_BROKEN_SOLARIS_KRB5_H +#warn "Warning! You have a broken Solaris system header" +#warn "http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6837512" +#if defined(__cplusplus) +#define KRB5INT_BEGIN_DECLS extern "C" { +#define KRB5INT_END_DECLS +KRB5INT_BEGIN_DECLS +#endif +#endif /* HAVE_BROKEN_SOLARIS_KRB5_H */ +#if HAVE_BROKEN_HEIMDAL_KRB5_H +extern "C" { +#include +} +#else +#include +#endif +#endif /* HAVE_KRB5_H */ + +#if HAVE_GSSAPI_GSSAPI_H +#include +#elif HAVE_GSSAPI_H +#include +#endif + +#if !HAVE_HEIMDAL_KERBEROS +#if HAVE_GSSAPI_GSSAPI_KRB5_H +#include +#endif +#if HAVE_GSSAPI_GSSAPI_GENERIC_H +#include +#endif +#if HAVE_GSSAPI_GSSAPI_EXT_H +#include +#endif +#else +#if HAVE_GSSAPI_GSSAPI_KRB5_H +#include +#endif +#endif + +#ifndef gss_nt_service_name +#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE +#endif + +#define PROGRAM "negotiate_kerberos_auth" + +#ifndef MAX_AUTHTOKEN_LEN +#define MAX_AUTHTOKEN_LEN 65535 +#endif +#ifndef SQUID_KERB_AUTH_VERSION +#define SQUID_KERB_AUTH_VERSION "3.0.4sq" +#endif + +typedef struct { + uint16_t length; + uint16_t maxlength; + uint32_t pointer; +} RPC_UNICODE_STRING; + +char *gethost_name(void); + +static const char *LogTime(void); + +static const unsigned char ntlmProtocol[] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0}; + +static const char * +LogTime() +{ + struct tm *tm; + struct timeval now; + static time_t last_t = 0; + static char buf[128]; + + gettimeofday(&now, NULL); + if (now.tv_sec != last_t) { + tm = localtime((time_t *) & now.tv_sec); + strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm); + last_t = now.tv_sec; + } + return buf; +} + +int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, + const char *function, int log); + +int check_k5_err(krb5_context context, const char *msg, krb5_error_code code); + +char *gethost_name(void); + +#if (defined(HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT) || defined(HAVE_GSS_MAP_NAME_TO_ANY)) && HAVE_DECL_KRB5_PAC +#define MAX_PAC_GROUP_SIZE 200*60 +void align(int n); +void getustr(RPC_UNICODE_STRING *string); +char **getgids(char **Rids, uint32_t GroupIds, uint32_t GroupCount); +char *getdomaingids(char *ad_groups, uint32_t DomainLogonId, char **Rids, uint32_t GroupCount); +char *getextrasids(char *ad_groups, uint32_t ExtraSids, uint32_t SidCount, uint32_t GroupCount); +uint64_t get6byt_be(void); +uint32_t get4byt(void); +uint16_t get2byt(void); +uint8_t get1byt(void); +char *xstrcpy( char *src, const char*dst); +char *xstrcat( char *src, const char*dst); +int checkustr(RPC_UNICODE_STRING *string); +char *get_ad_groups(char *ad_groups, krb5_context context, krb5_pac pac); +#endif diff -rubwBEN 3.4/negotiate_kerberos_pac.cc 3.4-mm/negotiate_kerberos_pac.cc --- 3.4/negotiate_kerberos_pac.cc 1970-01-01 01:00:00.000000000 +0100 +++ 3.4-mm/negotiate_kerberos_pac.cc 2013-08-24 14:45:13.722442138 +0100 @@ -0,0 +1,450 @@ +/* + * ----------------------------------------------------------------------------- + * + * Author: Markus Moeller (markus_moeller at compuserve.com) + * + * Copyright (C) 2007 Markus Moeller. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * As a special exemption, M Moeller gives permission to link this program + * with MIT, Heimdal or other GSS/Kerberos libraries, and distribute + * the resulting executable, without including the source code for + * the Libraries in the source distribution. + * + * ----------------------------------------------------------------------------- + */ + +#include "squid.h" +#include "rfc1738.h" +#include "compat/getaddrinfo.h" +#include "compat/getnameinfo.h" + +#if (defined(HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT) || defined(HAVE_GSS_MAP_NAME_TO_ANY)) && HAVE_DECL_KRB5_PAC + +#include "negotiate_kerberos.h" + +static int bpos; +static krb5_data *ad_data; +static unsigned char *p; + +int +check_k5_err(krb5_context context, const char *function, krb5_error_code code) +{ + const char *errmsg; + + if (code) { + errmsg = krb5_get_error_message(context, code); + debug((char *) "%s| %s: ERROR: %s failed: %s\n", LogTime(), PROGRAM, function, errmsg); + fprintf(stderr, "%s| %s: ERROR: %s: %s\n", LogTime(), PROGRAM, function, errmsg); + krb5_free_error_message(context, errmsg); + } + return code; +} + +void +align(int n){ + if ( bpos % n != 0 ) { + int al; + al = (bpos/n); + bpos = bpos+(bpos-n*al); + } +} + +void +getustr(RPC_UNICODE_STRING *string) { + + string->length = (p[bpos]<<0) | (p[bpos+1]<<8); + string->maxlength = (p[bpos+2]<<0) | (p[bpos+2+1]<<8); + string->pointer = (p[bpos+4]<<0) | (p[bpos+4+1]<<8) | (p[bpos+4+2]<<16) | (p[bpos+4+3]<<24); + bpos = bpos+8; + +} + +uint64_t +get6byt_be(void) { + uint64_t var; + + var = ((int64_t)p[bpos+5]<<0) | ((int64_t)p[bpos+4]<<8) | ((int64_t)p[bpos+3]<<16) | ((int64_t)p[bpos+2]<<24) | ((int64_t)p[bpos+1]<<32) | ((int64_t)p[bpos]<<40); + bpos = bpos+6; + + return var; +} + +uint32_t +get4byt(void) { + uint32_t var; + + var=(p[bpos]<<0) | (p[bpos+1]<<8) | (p[bpos+2]<<16) | (p[bpos+3]<<24); + bpos = bpos+4; + + return var; +} + +uint16_t +get2byt(void) { + uint16_t var; + + var=(p[bpos]<<0) | (p[bpos+1]<<8); + bpos = bpos+2; + + return var; +} + +uint8_t +get1byt(void) { + uint8_t var; + + var=(p[bpos]<<0); + bpos = bpos+1; + + return var; +} + +char * +xstrcpy( char *src, const char*dst) { + if (dst) { + if (strlen(dst)>MAX_PAC_GROUP_SIZE) + return NULL; + else + return strcpy(src,dst); + } else + return src; +} + +char * +xstrcat( char *src, const char*dst) { + if (dst) { + if (strlen(src)+strlen(dst)+1>MAX_PAC_GROUP_SIZE) + return NULL; + else + return strcat(src,dst); + } else + return src; +} + + +int +checkustr(RPC_UNICODE_STRING *string) { + uint32_t size,off,len; + + if (string->pointer != 0){ + align(4); + size = (p[bpos]<<0) | (p[bpos+1]<<8) | (p[bpos+2]<<16) | (p[bpos+3]<<24); + bpos = bpos+4; + off = (p[bpos]<<0) | (p[bpos+1]<<8) | (p[bpos+2]<<16) | (p[bpos+3]<<24); + bpos = bpos+4; + len = (p[bpos]<<0) | (p[bpos+1]<<8) | (p[bpos+2]<<16) | (p[bpos+3]<<24); + bpos = bpos+4; + if (len > size || off != 0 || + string->length > string->maxlength || len != string->length/2) { + debug((char *) "%s| %s: ERROR: RPC_UNICODE_STRING encoding error => size: %d len: %d/%d maxlength: %d offset: %d\n", + LogTime(), PROGRAM, size, len, string->length, string->maxlength, off); + return -1; + } + /* UNICODE string */ + bpos = bpos+string->length; + } + return 0; +} + +char ** +getgids(char **Rids, uint32_t GroupIds, uint32_t GroupCount) { + if (GroupIds!= 0){ + uint32_t ngroup; + uint32_t sauth; + int l; + + align(4); + ngroup = get4byt(); + if ( ngroup != GroupCount) { + debug((char *) "%s| %s: ERROR: Group encoding error => GroupCount: %d Array size: %d\n", + LogTime(), PROGRAM, GroupCount, ngroup); + return NULL; + } + debug((char *) "%s| %s: INFO: Found %d rids\n", LogTime(), PROGRAM, GroupCount); + + Rids=(char **)xcalloc(GroupCount*sizeof(char*),1); + for ( l=0; l<(int)GroupCount; l++) { + Rids[l]=(char *)xcalloc(4*sizeof(char),1); + memcpy((void *)Rids[l],(void *)&p[bpos],4); + sauth = get4byt(); + debug((char *) "%s| %s: Info: Got rid: %u\n", LogTime(), PROGRAM, sauth); + /* attribute */ + bpos = bpos+4; + } + } + return Rids; +} + +char * +getdomaingids(char *ad_groups, uint32_t DomainLogonId, char **Rids, uint32_t GroupCount) { + if (DomainLogonId!= 0) { + uint32_t nauth; + uint8_t rev; + uint64_t idauth; + uint32_t sauth; + char dli[256]; + char *ag; + int length; + int l; + + align(4); + + nauth = get4byt(); + + /* prepend rids with DomainID */ + length=1+1+6+nauth*4; + for (l=0; l<(int)GroupCount;l++){ + ag=(char *)xcalloc((length+4)*sizeof(char),1); + memcpy((void *)ag,(const void*)&p[bpos],1); + memcpy((void *)&ag[1],(const void*)&p[bpos+1],1); + ag[1] = ag[1]+1; + memcpy((void *)&ag[2],(const void*)&p[bpos+2],6+nauth*4); + memcpy((void *)&ag[length],(const void*)Rids[l],4); + if (l==0) { + if (!xstrcpy(ad_groups,"group=")) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + } else { + if (!xstrcat(ad_groups," group=")) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + } + if (!xstrcat(ad_groups,base64_encode_bin(ag, length+4))) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + xfree(ag); + xfree(Rids[l]); + } + xfree(Rids); + + /* mainly for debug only */ + rev = get1byt(); + bpos = bpos + 1; /*nsub*/ + idauth = get6byt_be(); + + snprintf(dli,sizeof(dli),"S-%d-%lu",rev,(long unsigned int)idauth); + for ( l=0;l<(int)nauth;l++ ) { + sauth = get4byt(); + snprintf((char *)&dli[strlen(dli)],sizeof(dli)-strlen(dli),"-%u",sauth); + } + debug((char *) "%s| %s: INFO: Got DomainLogonId %s\n", LogTime(), PROGRAM, dli); + } + return ad_groups; +} + +char * +getextrasids(char *ad_groups, uint32_t ExtraSids, uint32_t SidCount, uint32_t GroupCount) { + if (ExtraSids!= 0){ + uint32_t ngroup; + uint32_t *pa; + char *ag; + int length; + int l; + + align(4); + ngroup = get4byt(); + if ( ngroup != SidCount) { + debug((char *) "%s| %s: ERROR: Group encoding error => SidCount: %d Array size: %d\n", + LogTime(), PROGRAM, SidCount, ngroup); + return NULL; + } + debug((char *) "%s| %s: INFO: Found %d ExtraSIDs\n", LogTime(), PROGRAM, SidCount); + + pa=(uint32_t *)xmalloc(SidCount*sizeof(uint32_t)); + for ( l=0; l < (int)SidCount; l++ ){ + pa[l] = get4byt(); + bpos = bpos+4; /* attr */ + } + + for ( l=0; l<(int)SidCount; l++ ){ + char es[256]; + uint32_t nauth; + uint8_t rev; + uint64_t idauth; + uint32_t sauth; + int k; + + if (pa[l] != 0){ + nauth = get4byt(); + + length = 1+1+6+nauth*4; + ag = (char *)xcalloc((length)*sizeof(char),1); + memcpy((void *)ag,(const void*)&p[bpos],length); + if (!ad_groups) { + if (!xstrcpy(ad_groups,"group=")) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + } else { + if (!xstrcat(ad_groups," group=")) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + } + if (!xstrcat(ad_groups,base64_encode_bin(ag, length+4))) { + debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n", + LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups); + } + xfree(ag); + + rev = get1byt(); + bpos = bpos + 1; /* nsub */ + idauth = get6byt_be(); + + snprintf(es,sizeof(es),"S-%d-%lu",rev,(long unsigned int)idauth); + for ( k=0;k<(int)nauth;k++ ) { + sauth = get4byt(); + snprintf((char *)&es[strlen(es)],sizeof(es)-strlen(es),"-%u",sauth); + } + debug((char *) "%s| %s: INFO: Got ExtraSid %s\n", LogTime(), PROGRAM, es); + } + } + xfree(pa); + } + return ad_groups; +} + +char * +get_ad_groups(char *ad_groups, krb5_context context, krb5_pac pac){ + krb5_error_code ret; + RPC_UNICODE_STRING EffectiveName; + RPC_UNICODE_STRING FullName; + RPC_UNICODE_STRING LogonScript; + RPC_UNICODE_STRING ProfilePath; + RPC_UNICODE_STRING HomeDirectory; + RPC_UNICODE_STRING HomeDirectoryDrive; + RPC_UNICODE_STRING LogonServer; + RPC_UNICODE_STRING LogonDomainName; + uint32_t GroupCount=0; + uint32_t GroupIds=0; + uint32_t LogonDomainId=0; + uint32_t SidCount=0; + uint32_t ExtraSids=0; + /* + uint32_t ResourceGroupDomainSid=0; + uint32_t ResourceGroupCount=0; + uint32_t ResourceGroupIds=0; + */ + char **Rids=NULL; + int l=0; + + ad_data = (krb5_data *)xmalloc(sizeof(krb5_data)); + +#define KERB_LOGON_INFO 1 + ret = krb5_pac_get_buffer(context, pac, KERB_LOGON_INFO, ad_data); + if (check_k5_err(context, "krb5_pac_get_buffer", ret)) + goto k5clean; + + p = (unsigned char *)ad_data->data; + + debug((char *) "%s| %s: INFO: Got PAC data of lengh %d\n", + LogTime(), PROGRAM, (int)ad_data->length); + + /* Skip 16 bytes icommon RPC header + * Skip 4 bytes RPC unique pointer referent + * http://msdn.microsoft.com/en-gb/library/cc237933.aspx + */ + /* Some data are pointers to data which follows the main KRB5 LOGON structure => + * So need to read the data + * some logical consistency checks are done when analysineg the pointer data + */ + bpos = 20; + /* 8 bytes LogonTime + * 8 bytes LogoffTime + * 8 bytes KickOffTime + * 8 bytes PasswordLastSet + * 8 bytes PasswordCanChange + * 8 bytes PasswordMustChange + */ + bpos = bpos+48; + getustr(&EffectiveName); + getustr(&FullName); + getustr(&LogonScript); + getustr(&ProfilePath); + getustr(&HomeDirectory); + getustr(&HomeDirectoryDrive); + /* 2 bytes LogonCount + * 2 bytes BadPasswordCount + * 4 bytes UserID + * 4 bytes PrimaryGroupId + */ + bpos = bpos+12; + GroupCount = get4byt(); + GroupIds = get4byt(); + /* 4 bytes UserFlags + * 16 bytes UserSessionKey + */ + bpos = bpos+20; + getustr(&LogonServer); + getustr(&LogonDomainName); + LogonDomainId = get4byt(); + /* 8 bytes Reserved1 + * 4 bytes UserAccountControl + * 4 bytes SubAuthStatus + * 8 bytes LastSuccessfullLogon + * 8 bytes LastFailedLogon + * 4 bytes FailedLogonCount + * 4 bytes Reserved2 + */ + bpos = bpos+40; + SidCount = get4byt(); + ExtraSids = get4byt(); + /* 4 bytes ResourceGroupDomainSid + * 4 bytes ResourceGroupCount + * 4 bytes ResourceGroupIds + */ + bpos = bpos+12; + /* + * Read all data from structure => Now check pointers + */ + if (checkustr(&EffectiveName)<0) + goto k5clean; + if (checkustr(&FullName)<0) + goto k5clean; + if (checkustr(&LogonScript)<0) + goto k5clean; + if (checkustr(&ProfilePath)<0) + goto k5clean; + if (checkustr(&HomeDirectory)<0) + goto k5clean; + if (checkustr(&HomeDirectoryDrive)<0) + goto k5clean; + Rids = getgids(Rids,GroupIds,GroupCount); + if (checkustr(&LogonServer)<0) + goto k5clean; + if (checkustr(&LogonDomainName)<0) + goto k5clean; + ad_groups = getdomaingids(ad_groups,LogonDomainId,Rids,GroupCount); + if ((ad_groups = getextrasids(ad_groups,ExtraSids,SidCount,GroupCount))==NULL) + goto k5clean; + + debug((char *) "%s| %s: INFO: Read %d of %d bytes \n", LogTime(), PROGRAM, bpos, (int)ad_data->length); + krb5_free_data(context, ad_data); + return ad_groups; +k5clean: + for ( l=0; l<(int)GroupCount; l++) { + if (Rids[l]) + xfree(Rids[l]); + } + xfree(Rids); + krb5_free_data(context, ad_data); + return NULL; +} +#endif diff -rubwBEN 3.4/src/peer_proxy_negotiate_auth.cc 3.4-mm/src/peer_proxy_negotiate_auth.cc --- 3.4/src/peer_proxy_negotiate_auth.cc 2013-08-12 00:01:44.458703000 +0100 +++ 3.4-mm/src/peer_proxy_negotiate_auth.cc 2013-08-24 17:18:50.208670666 +0100 @@ -210,21 +210,29 @@ static krb5_keytab_entry entry; static krb5_kt_cursor cursor; static krb5_creds *creds = NULL; -#if HAVE_HEIMDAL_KERBEROS +#if defined(HAVE_HEIMDAL_KERBEROS) && !defined(HAVE_KRB5_GET_RENEWED_CREDS) static krb5_creds creds2; #endif static krb5_principal principal = NULL; static krb5_deltat skew; +#if HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC + krb5_get_init_creds_opt *options; +#else krb5_get_init_creds_opt options; +#endif krb5_error_code code = 0; krb5_deltat rlife; #if HAVE_PROFILE_H && HAVE_KRB5_GET_PROFILE && HAVE_PROFILE_GET_INTEGER && HAVE_PROFILE_RELEASE profile_t profile; #endif -#if HAVE_HEIMDAL_KERBEROS +#if defined(HAVE_HEIMDAL_KERBEROS) && !defined(HAVE_KRB5_GET_RENEWED_CREDS) krb5_kdc_flags flags; - krb5_realm *client_realm; +#if HAVE_KRB5_PRINCIPAL_GET_REALM + const char *client_realm; +#else + krb5_realm client_realm; +#endif #endif char *mem_cache; @@ -236,7 +244,7 @@ (creds->times.endtime - time(0) > skew) && (creds->times.renew_till - time(0) > 2 * skew)) { if (creds->times.endtime - time(0) < 2 * skew) { -#if !HAVE_HEIMDAL_KERBEROS +#if HAVE_KRB5_GET_RENEWED_CREDS /* renew ticket */ code = krb5_get_renewed_creds(kparam.context, creds, principal, @@ -256,10 +264,15 @@ << error_message(code)); return (1); } +#if HAVE_KRB5_PRINCIPAL_GET_REALM + client_realm = krb5_principal_get_realm(kparam.context, principal); +#else client_realm = krb5_princ_realm(kparam.context, creds2.client); +#endif code = krb5_make_principal(kparam.context, &creds2.server, - *client_realm, KRB5_TGS_NAME, *client_realm, NULL); + (krb5_const_realm)&client_realm, KRB5_TGS_NAME, + (krb5_const_realm)&client_realm, NULL); if (code) { debugs(11, 5, HERE << "Error while getting krbtgt principal : " << @@ -400,7 +413,11 @@ creds = (krb5_creds *) xmalloc(sizeof(*creds)); memset(creds, 0, sizeof(*creds)); +#if HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC + krb5_get_init_creds_opt_alloc(kparam.context, &options); +#else krb5_get_init_creds_opt_init(&options); +#endif code = krb5_string_to_deltat((char *) MAX_RENEW_TIME, &rlife); if (code != 0 || rlife == 0) { debugs(11, 5, @@ -408,8 +425,18 @@ " : " << error_message(code)); return (1); } +#if HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC + krb5_get_init_creds_opt_set_renew_life(options, rlife); + code = + krb5_get_init_creds_keytab(kparam.context, creds, principal, + keytab, 0, NULL, options); +#if HAVE_KRB5_GET_INIT_CREDS_FREE_CONTEXT + krb5_get_init_creds_opt_free(kparam.context, options); +#else + krb5_get_init_creds_opt_free(options); +#endif +#else krb5_get_init_creds_opt_set_renew_life(&options, rlife); - code = krb5_get_init_creds_keytab(kparam.context, creds, principal, keytab, 0, NULL, &options); @@ -413,6 +440,7 @@ code = krb5_get_init_creds_keytab(kparam.context, creds, principal, keytab, 0, NULL, &options); +#endif if (code) { debugs(11, 5, HERE << diff -rubwBEN 3.4/test_negotiate_auth.sh 3.4-mm/test_negotiate_auth.sh --- 3.4/test_negotiate_auth.sh 1970-01-01 01:00:00.000000000 +0100 +++ 3.4-mm/test_negotiate_auth.sh 2013-08-24 14:45:29.159442521 +0100 @@ -0,0 +1,7 @@ +#!/bin/bash +if [[ -z "$1" ]]; then + echo "Need squid hostname" + exit 0 +fi +dir=`dirname $0` +$dir/negotiate_kerberos_auth_test $1 | awk '{sub(/Token:/,"YR"); print $0}END{print "QQ"}' | $dir/negotiate_kerberos_auth -d