Index: krb5/src/include/krb5.hin diff -u krb5/src/include/krb5.hin:1.1.1.6 krb5/src/include/krb5.hin:1.9 --- krb5/src/include/krb5.hin:1.1.1.6 Tue Nov 8 16:10:48 2005 +++ krb5/src/include/krb5.hin Tue Nov 8 17:32:53 2005 @@ -683,7 +683,11 @@ /* #define KDC_OPT_RESERVED 0x00080000 */ /* #define KDC_OPT_RESERVED 0x00040000 */ #define KDC_OPT_REQUEST_ANONYMOUS 0x00020000 +#if defined(UMICH) /* MICROSOFT CANONICALIZATION PATCH */ +#define KDC_OPT_NAME_CANONICALIZE 0x00010000 +#else /* #define KDC_OPT_RESERVED 0x00010000 */ +#endif /* #define KDC_OPT_RESERVED 0x00008000 */ /* #define KDC_OPT_RESERVED 0x00004000 */ /* #define KDC_OPT_RESERVED 0x00002000 */ @@ -2238,6 +2242,12 @@ (krb5_context, const char *, char ** ); +#if defined(UMICH) +krb5_error_code KRB5_CALLCONV krb5_get_host_referral_realm + (krb5_context, + const char *, + char *** ); +#endif #endif krb5_boolean KRB5_CALLCONV krb5_kuserok (krb5_context, Index: krb5/src/kdc/do_tgs_req.c diff -u krb5/src/kdc/do_tgs_req.c:1.1.1.5 krb5/src/kdc/do_tgs_req.c:1.11 --- krb5/src/kdc/do_tgs_req.c:1.1.1.5 Tue Nov 8 15:54:45 2005 +++ krb5/src/kdc/do_tgs_req.c Tue Nov 8 17:32:59 2005 @@ -167,7 +167,12 @@ * might be a request for a TGT for some other realm; we * should do our best to find such a TGS in this db */ +#if defined(UMICH) /* MICROSOFT CANONICALIZATION PATCH */ + if (firstpass) { + if (krb5_is_tgs_principal(request->server) == TRUE) { +#else if (firstpass && krb5_is_tgs_principal(request->server) == TRUE) { +#endif if (krb5_princ_size(kdc_context, request->server) == 2) { krb5_data *server_1 = krb5_princ_component(kdc_context, request->server, 1); @@ -182,6 +187,164 @@ goto tgt_again; } } +#if defined(UMICH) /* MICROSOFT CANONICALIZATION PATCH */ + } + else if (isflagset(request->kdc_options, KDC_OPT_NAME_CANONICALIZE)) { + /* + * (This is the firstpass, it is *not* a tgs_principal, + * and NAME_CANONICALIZE was requested by the client.) + */ + + krb5_principal reftgt; + char *req_realm; + char **referral_list; + krb5_data *req_host; + char *req_hostname, *hostname; + int realm_len; + + /* + * Make sure that requested principal has exactly two components + * i.e. "HOST/foxtrot.itcs.umich.edu" or "HOST/FOXTROT" + */ + + if (krb5_princ_size(kdc_context, request->server) == 2) { + req_host = krb5_princ_component(kdc_context, request->server, 1); + req_hostname = req_host->data; + + hostname = (char *) malloc(req_host->length + 1); + if (hostname == NULL) { + errcode = ENOMEM; + status = "REFERRAL_GET_HOSTNAME"; + goto cleanup; + } + strncpy(hostname, req_hostname, req_host->length); + hostname[req_host->length] = '\0'; + + /* + * See if there is a configured referral realm via the + * host_referral mapping in the configuration file. + * In reality, the following routine returns either an empty list, + * or a list of one element, there can never be more than one + * referral realm for a given host name. + */ + + errcode = krb5_get_host_referral_realm(kdc_context, hostname, &referral_list); + free(hostname); + + /* + * Now, if the request was successful, but did not return a referral, + * we'll back up to use the "default" referral_realm as was used in + * the original Microsoft patch (which can only issue referrals + * to one place). + */ + + if ( errcode == 0 ) { + + /* Dig out the realm name that the request came to */ + + realm_len = (krb5_princ_realm(kdc_context, request->server))->length; + req_realm = (char *) malloc(realm_len + 1); + if (req_realm == NULL) { + errcode = ENOMEM; + status = "REFERRAL_GET_REALM"; + goto cleanup; + } + memset(req_realm, 0, realm_len + 1); + strncpy(req_realm, krb5_princ_name(kdc_context, + krb5_princ_realm(kdc_context, request->server)), realm_len); + + /* + * If nothing was found from the krb5_get_host_referral() + * lookup, we'll try to get the default referral realm + * for this realm from the configuration file. If that + * fails, then we can't be of any help for this request. + */ + + if ( referral_list[0] == NULL ) { + /* + * Note: Solaris complains with "non-constant initializer" with: + * const char *ref_names[4] = {"realms", req_realm, "referral_realm", 0}; + * so it was changed to the following two lines... + */ + const char *ref_names[4] = {"realms", 0, "referral_realm", 0}; + ref_names[1] = req_realm; + + /* + * Fix memory leak (8 bytes) by freeing referral_list that was + * returned from call to krb5_get_host_referral_realm() above + * before reusing the variable in the call to profile_get_values. + */ + krb5_free_krbhst(kdc_context, referral_list); + + errcode = profile_get_values(kdc_context->profile, ref_names, &referral_list); + if (errcode != 0) { + free(req_realm); + status = "REFERRAL_NO_DEFAULT_TARGET"; + goto cleanup; + } + } + + /* + * At this point, we have a proposed referral realm (in referral_list[0]) + * from either the krb5_get_host_referral() lookup, or from the + * "referral_realm" lookup. Now see if we have a cross-realm ticket + * for the proposed referral realm. + */ + + errcode = krb5_build_principal(kdc_context, &reftgt, + realm_len, + req_realm, + KRB5_TGS_NAME, + referral_list[0], + 0); + krb5_free_krbhst(kdc_context, referral_list); + free(req_realm); + + if (errcode == 0) { + krb5_db_free_principal(kdc_context, &server, nprincs); + errcode = krb5_db_get_principal(kdc_context, + reftgt, &server, + &nprincs, &more); + if (errcode == 0 && nprincs == 1) { + char *s0name; + krb5_unparse_name(kdc_context, request->server, &s0name); + + /* + * Fix memory leak by freeing previous sname that may + * have been allocated above before reusing the pointer. + */ + if (sname) { + free(sname); + sname = 0; + } + krb5_unparse_name(kdc_context, reftgt, &sname); + + limit_string(sname); + limit_string(s0name); + krb5_klog_syslog(LOG_INFO, + "TGS_REQ: issuing referral TGT %s for %s", + sname ? sname : "", + s0name ? s0name : ""); + if (s0name) free(s0name); + krb5_free_principal(kdc_context, request->server); + request->server = reftgt; + firstpass = 0; + goto tgt_again; + } + else { + char *refname; + krb5_unparse_name(kdc_context, reftgt, &refname); + limit_string(refname); + krb5_klog_syslog(LOG_INFO, "TGS_REQ: WARNING: Principal %s not " + "in database while attempting referral", + refname ? refname : ""); + if (refname) free(refname); + } + } + } + } + } +#endif /* UMICH (MICROSOFT CANONICALIZATION PATCH) */ } krb5_db_free_principal(kdc_context, &server, nprincs); status = "UNKNOWN_SERVER"; Index: krb5/src/kdc/kdc_util.c diff -u krb5/src/kdc/kdc_util.c:1.1.1.5 krb5/src/kdc/kdc_util.c:1.9 --- krb5/src/kdc/kdc_util.c:1.1.1.5 Thu Apr 15 10:07:28 2004 +++ krb5/src/kdc/kdc_util.c Thu Apr 15 12:30:46 2004 @@ -1094,12 +1094,21 @@ * Returns a Kerberos protocol error number, which is _not_ the same * as a com_err error number! */ +#if defined(UMICH) /* MICROSOFT CANONICALIZATION PATCH */ +#define TGS_OPTIONS_HANDLED (KDC_OPT_FORWARDABLE | KDC_OPT_FORWARDED | \ + KDC_OPT_PROXIABLE | KDC_OPT_PROXY | \ + KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED | \ + KDC_OPT_RENEWABLE | KDC_OPT_RENEWABLE_OK | \ + KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_RENEW | \ + KDC_OPT_VALIDATE | KDC_OPT_NAME_CANONICALIZE) +#else #define TGS_OPTIONS_HANDLED (KDC_OPT_FORWARDABLE | KDC_OPT_FORWARDED | \ KDC_OPT_PROXIABLE | KDC_OPT_PROXY | \ KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED | \ KDC_OPT_RENEWABLE | KDC_OPT_RENEWABLE_OK | \ KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_RENEW | \ KDC_OPT_VALIDATE) +#endif #define NO_TGT_OPTION (KDC_OPT_FORWARDED | KDC_OPT_PROXY | KDC_OPT_RENEW | \ KDC_OPT_VALIDATE) Index: krb5/src/lib/krb5/os/hst_realm.c diff -u krb5/src/lib/krb5/os/hst_realm.c:1.1.1.4 krb5/src/lib/krb5/os/hst_realm.c:1.7 --- krb5/src/lib/krb5/os/hst_realm.c:1.1.1.4 Tue Nov 8 16:01:35 2005 +++ krb5/src/lib/krb5/os/hst_realm.c Tue Nov 8 20:58:49 2005 @@ -342,6 +342,108 @@ return 0; } +#if defined(UMICH) + +/* + * This is a copy of the krb5_get_host_realm routine. Instead of + * trying to find the realm of a host, we are looking for the + * referral realm for a request. This is needed in order to + * determine the correct Windows2000 KDC to refer a client + * to. The W2K client depends on the server to determine where + * it should go next, if the server itself cannot fulfill the request. + * KWC 02/28/2001 + */ + +krb5_error_code KRB5_CALLCONV +krb5_get_host_referral_realm(krb5_context context, const char *host, char ***realmsp) +{ + char **retrealms; + char *realm, *cp, *temp_realm; + krb5_error_code retval; + int l; + char local_host[MAXDNAME+1]; + struct hostent *h; + + + /* + * We MUST have a non-null host name, there is no default. + * If there is no matching name in the config file, we + * return a null list. + */ + if (host) + strncpy(local_host, host, sizeof(local_host)); + else { + return EINVAL; + } + local_host[sizeof(local_host) - 1] = '\0'; + + l = strlen(local_host); + if (l <= 0) + return EINVAL; + + /* Make sure the name is all lower-case */ + for (cp = local_host; *cp; cp++) { + if (isupper(*cp)) + *cp = tolower(*cp); + } + /* strip off trailing dot */ + if (local_host[l-1] == '.') + local_host[l-1] = 0; + + /* + Search for the best match for the host or domain. + Example: Given a host a.b.c.d, try to match on: + 1) A.B.C.D + 2) .B.C.D + 3) B.C.D + 4) .C.D + 5) C.D + 6) .D + 7) D + */ + + cp = local_host; + realm = (char *)NULL; + temp_realm = 0; + while (cp) { + retval = profile_get_string(context->profile, "domain_referral", cp, + 0, (char *)NULL, &temp_realm); + if (retval) + return retval; + if (temp_realm != (char *)NULL) + break; /* Match found */ + + /* Setup for another test */ + if (*cp == '.') { + cp++; + } else { + cp = strchr(cp, '.'); + } + } + if (temp_realm) { + realm = malloc(strlen(temp_realm) + 1); + if (!realm) { + profile_release_string(temp_realm); + return ENOMEM; + } + strcpy(realm, temp_realm); + profile_release_string(temp_realm); + } + + if (!(retrealms = (char **)calloc(2, sizeof(*retrealms)))) { + if (realm != (char *)NULL) + free(realm); + return ENOMEM; + } + + retrealms[0] = realm; + retrealms[1] = 0; + + *realmsp = retrealms; + return 0; +} +#endif /* UMICH */ + #if defined(_WIN32) && !defined(__CYGWIN32__) # ifndef EAFNOSUPPORT # define EAFNOSUPPORT WSAEAFNOSUPPORT Index: krb5/src/lib/krb5/libkrb5.exports --- krb5/src/lib/krb5/libkrb5.exports.orig 2005-01-05 15:54:51.000000000 -0500 +++ krb5/src/lib/krb5/libkrb5.exports 2005-11-16 15:31:59.000000000 -0500 @@ -426,6 +426,7 @@ krb5_get_default_in_tkt_ktypes krb5_get_default_realm krb5_get_host_realm +krb5_get_host_referral_realm krb5_get_in_tkt krb5_get_in_tkt_with_keytab krb5_get_in_tkt_with_password Index: krb5/src/include/krb5/stock/osconf.h *** krb5/src/include/krb5/stock/osconf.h.0 Thu Jun 5 18:26:46 2003 --- krb5/src/include/krb5/stock/osconf.h Thu Sep 2 09:08:03 2004 *************** *** 27,32 **** --- 27,35 ---- * Site- and OS- dependant configuration. */ + /* Enable UMich referral patch: (MF 27Sep2001) */ + #define UMICH + #ifndef KRB5_OSCONF__ #define KRB5_OSCONF__