Index: krb5/src/include/krb5.hin diff -u krb5/src/include/krb5.hin:1.1.1.4 krb5/src/include/krb5.hin:1.7 --- krb5/src/include/krb5.hin:1.1.1.4 Mon Aug 4 15:38:33 2003 +++ krb5/src/include/krb5.hin Mon Aug 4 15:55:50 2003 @@ -689,7 +689,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 */ @@ -2293,6 +2297,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.4 krb5/src/kdc/do_tgs_req.c:1.9 --- krb5/src/kdc/do_tgs_req.c:1.1.1.4 Mon Jul 21 16:28:37 2003 +++ krb5/src/kdc/do_tgs_req.c Tue Jul 22 10:32:14 2003 @@ -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.4 krb5/src/kdc/kdc_util.c:1.8 --- krb5/src/kdc/kdc_util.c:1.1.1.4 Mon Jul 21 16:28:38 2003 +++ krb5/src/kdc/kdc_util.c Fri Jan 23 14:06:54 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) @@ -1389,7 +1398,24 @@ * that's not the reality.... */ if (enctype == ENCTYPE_DES_CBC_MD5) +#if defined(UMICH) + /* + * UMICH MOD: + * Allow use of MD5 whether they have the bit set or not, + * since there is currently no administrative way to set + * the bit! KWC 11/02/98 + * Note: The routine fixup_database() in the dump/restore + * routines is supposed to set this bit, but we didn't use + * the MIT migration tools, but used the AFS->K5 migration + * tools... KWC 07/11/2000 + * This causes a problem with the Mac kadmin client? + * Don't allow MD5 just like MIT! + * KWC 01/23/2004 + */ + return 0; +#else return 0; +#endif /* * XXX we assume everything can understand DES_CBC_CRC Index: krb5/src/kdc/kerberos_v4.c diff -u krb5/src/kdc/kerberos_v4.c:1.1.1.3 krb5/src/kdc/kerberos_v4.c:1.9 --- krb5/src/kdc/kerberos_v4.c:1.1.1.3 Mon Jul 21 16:28:38 2003 +++ krb5/src/kdc/kerberos_v4.c Thu Dec 11 10:29:19 2003 @@ -361,6 +361,12 @@ out5->contents = NULL; return(retval); } +#if defined(UMICH) +/* + * klog(L_KRB_PERR, "*DEBUG* KDC V4: issrv %d enctype 0x%08x length %d", + * issrv, out5->enctype, out5->length); + */ +#endif if (K4KDC_ENCTYPE_OK(out5->enctype)) { if (out5->length == KRB5_MIT_DES_KEYSIZE) memcpy(out4, out5->contents, out5->length); @@ -439,13 +445,28 @@ * in v5, null instance means the null-component doesn't exist. */ +#if defined(UMICH) +/* klog(L_APPL_REQ, "CONV PRINC Request %s.%s@%s", + name, inst, local_realm, 0); */ +#endif if ((retval = krb5_425_conv_principal(kdc_context, name, inst, local_realm, &search))) return(0); +#if defined(UMICH) +/* klog(L_APPL_REQ, "CONV PRINC Request %s.%s@%s succeeded with realm.length %d, " + "realm.data '%s', data[0].length %d data[0].data '%s' data[1].length %d data[1].data '%s'", + name, inst, local_realm, search->realm.length, search->realm.data, + search->data[0].length, search->data[0].data, + search->data[1].length, search->data[1].data, 0); */ +#endif if ((retval = krb5_db_get_principal(kdc_context, search, &entries, &nprinc, &more5))) { krb5_free_principal(kdc_context, search); +#if defined(UMICH) +/* klog(L_APPL_REQ, "CONV PRINC Request %s.%s@%s krb5_db_get_principal failed", + name, inst, local_realm, 0); */ +#endif return(0); } principal->key_low = principal->key_high = 0; @@ -453,6 +474,12 @@ if (nprinc < 1) { *more = (int)more5 || (nprinc > maxn); +#if defined(UMICH) +/* + * klog(L_APPL_REQ, "CONV PRINC nprinc %d more5 %d maxn %d", + * nprinc, more5, maxn, 0); + */ +#endif return(nprinc); } @@ -460,6 +487,14 @@ if (krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES_CBC_CRC, +#if defined(UMICH) + KRB5_KDB_SALTTYPE_AFS3, /* Try AFS key first for K4 requests */ + kvno, + &pkey) && + krb5_dbe_find_enctype(kdc_context, + &entries, + ENCTYPE_DES_CBC_CRC, +#endif KRB5_KDB_SALTTYPE_V4, kvno, &pkey) && @@ -478,6 +513,12 @@ } else { if ( krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES_CBC_CRC, +#if defined(UMICH) + /* Try AFS key first for K4 requests */ + KRB5_KDB_SALTTYPE_AFS3, kvno, &pkey) && + krb5_dbe_find_enctype(kdc_context, &entries, + ENCTYPE_DES_CBC_CRC, +#endif KRB5_KDB_SALTTYPE_V4, kvno, &pkey) && krb5_dbe_find_enctype(kdc_context, &entries, ENCTYPE_DES_CBC_CRC, @@ -579,6 +620,12 @@ */ krb5_db_free_principal(kdc_context, &entries, nprinc); *more = (int) more5 || (nprinc > maxn); +#if defined(UMICH) +/* + * klog(L_APPL_REQ, "CONV PRINC RETURNING nprinc %d more5 %d maxn %d", + * nprinc, more5, maxn, 0); + */ +#endif return( nprinc); } @@ -737,12 +784,26 @@ krb5_free_keyblock_contents(kdc_context, &k5key); return; } +#if defined(UMICH) + /* + * UMICH MOD: kwc 11/19/98 + * If difference between workstation time and our time + * is too great, fail the request. The error number + * doesn't make a whole lot of sense, but it is what + * the clients are expecting... + */ + if ( abs(req_time_ws - kerb_time.tv_sec) > CLOCK_SKEW ) { + kerb_err_reply(client, pkt, KERB_ERR_SERVICE_EXP, "Clock skew too great"); + return; + } +#endif /* UMICH */ /* Bound requested lifetime with service and user */ v4req_end = krb_life_to_time(kerb_time.tv_sec, req_life); v4req_end = min(v4req_end, kerb_time.tv_sec + ck5life); v4req_end = min(v4req_end, kerb_time.tv_sec + sk5life); lifetime = krb_time_to_life(kerb_time.tv_sec, v4req_end); v4endtime = krb_life_to_time(kerb_time.tv_sec, lifetime); +#if !defined(UMICH) /* * Adjust issue time backwards if necessary, due to * roundup in krb_time_to_life(). XXX This frobs @@ -750,6 +811,7 @@ */ if (v4endtime > v4req_end) kerb_time.tv_sec -= v4endtime - v4req_end; +#endif #ifdef NOENCRYPTION memset(session_key, 0, sizeof(C_Block)); @@ -937,6 +999,7 @@ lifetime = krb_time_to_life(kerb_time.tv_sec, v4req_end); v4endtime = krb_life_to_time(kerb_time.tv_sec, lifetime); +#if !defined(UMICH) /* * Adjust issue time backwards if necessary, due to * roundup in krb_time_to_life(). XXX This frobs @@ -944,6 +1007,7 @@ */ if (v4endtime > v4req_end) kerb_time.tv_sec -= v4endtime - v4req_end; +#endif /* unseal server's key from master key */ memcpy(key, &s_name_data.key_low, 4); Index: krb5/src/kdc/replay.c diff -u krb5/src/kdc/replay.c:1.1.1.2 krb5/src/kdc/replay.c:1.3 --- krb5/src/kdc/replay.c:1.1.1.2 Mon Jul 21 16:28:39 2003 +++ krb5/src/kdc/replay.c Tue Jul 22 10:32:15 2003 @@ -103,6 +103,9 @@ if we just matched, we may get another retransmit... */ } if (STALE(eptr)) { + /* UMICH DEBUG */ + /* printf("** removing STALE replay cache entry 0x%08x **\n", eptr); */ + /* UMICH DEBUG */ /* flush it and collect stats */ max_hits_per_entry = max(max_hits_per_entry, eptr->num_hits); krb5_free_data(kdc_context, eptr->req_packet); Index: krb5/src/lib/krb5/os/hst_realm.c diff -u krb5/src/lib/krb5/os/hst_realm.c:1.1.1.3 krb5/src/lib/krb5/os/hst_realm.c:1.5 --- krb5/src/lib/krb5/os/hst_realm.c:1.1.1.3 Mon Jul 21 16:36:55 2003 +++ krb5/src/lib/krb5/os/hst_realm.c Tue Jul 22 15:55:18 2003 @@ -414,6 +414,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[MAX_DNS_NAMELEN+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