diff options
Diffstat (limited to 'lib/krb5/pac.c')
-rw-r--r-- | lib/krb5/pac.c | 104 |
1 files changed, 78 insertions, 26 deletions
diff --git a/lib/krb5/pac.c b/lib/krb5/pac.c index 91f68d5e00e7..c26201be9cd7 100644 --- a/lib/krb5/pac.c +++ b/lib/krb5/pac.c @@ -405,7 +405,7 @@ krb5_pac_get_types(krb5_context context, { size_t i; - *types = calloc(p->pac->numbuffers, sizeof(*types)); + *types = calloc(p->pac->numbuffers, sizeof(**types)); if (*types == NULL) { *len = 0; return krb5_enomem(context); @@ -549,6 +549,8 @@ create_checksum(krb5_context context, if (cksumtype == (uint32_t)CKSUMTYPE_HMAC_MD5) { ret = HMAC_MD5_any_checksum(context, key, data, datalen, KRB5_KU_OTHER_CKSUM, &cksum); + if (ret) + return ret; } else { ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) @@ -595,11 +597,12 @@ verify_logonname(krb5_context context, krb5_const_principal principal) { krb5_error_code ret; - krb5_principal p2; uint32_t time1, time2; krb5_storage *sp; uint16_t len; - char *s; + char *s = NULL; + char *principal_string = NULL; + char *logon_string = NULL; sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo, logon_name->buffersize); @@ -615,7 +618,13 @@ verify_logonname(krb5_context context, uint64_t t1, t2; t1 = unix2nttime(authtime); t2 = ((uint64_t)time2 << 32) | time1; - if (t1 != t2) { + /* + * When neither the ticket nor the PAC set an explicit authtime, + * both times are zero, but relative to different time scales. + * So we must compare "not set" values without converting to a + * common time reference. + */ + if (t1 != t2 && (t2 != 0 && authtime != 0)) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch"); return EINVAL; @@ -664,29 +673,36 @@ verify_logonname(krb5_context context, return ret; } u8len += 1; /* Add space for NUL */ - s = malloc(u8len); - if (s == NULL) { + logon_string = malloc(u8len); + if (logon_string == NULL) { free(ucs2); return krb5_enomem(context); } - ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len); + ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len); free(ucs2); if (ret) { - free(s); + free(logon_string); krb5_set_error_message(context, ret, "Failed to convert to UTF-8"); return ret; } } - ret = krb5_parse_name_flags(context, s, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2); - free(s); - if (ret) + ret = krb5_unparse_name_flags(context, principal, + KRB5_PRINCIPAL_UNPARSE_NO_REALM | + KRB5_PRINCIPAL_UNPARSE_DISPLAY, + &principal_string); + if (ret) { + free(logon_string); return ret; + } - if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) { + ret = strcmp(logon_string, principal_string); + if (ret != 0) { ret = EINVAL; - krb5_set_error_message(context, ret, "PAC logon name mismatch"); + krb5_set_error_message(context, ret, "PAC logon name [%s] mismatch principal name [%s]", + logon_string, principal_string); } - krb5_free_principal(context, p2); + free(logon_string); + free(principal_string); return ret; out: return ret; @@ -722,7 +738,9 @@ build_logon_name(krb5_context context, CHECK(ret, krb5_store_uint32(sp, t >> 32), out); ret = krb5_unparse_name_flags(context, principal, - KRB5_PRINCIPAL_UNPARSE_NO_REALM, &s); + KRB5_PRINCIPAL_UNPARSE_NO_REALM | + KRB5_PRINCIPAL_UNPARSE_DISPLAY, + &s); if (ret) goto out; @@ -733,8 +751,8 @@ build_logon_name(krb5_context context, ret = wind_utf8ucs2_length(s, &ucs2_len); if (ret) { + krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s); free(s); - krb5_set_error_message(context, ret, "Failed to count length of UTF-8 string"); return ret; } @@ -745,16 +763,17 @@ build_logon_name(krb5_context context, } ret = wind_utf8ucs2(s, ucs2, &ucs2_len); - free(s); if (ret) { free(ucs2); - krb5_set_error_message(context, ret, "Failed to convert string to UCS-2"); + krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s); + free(s); return ret; - } + } else + free(s); s2_len = (ucs2_len + 1) * 2; s2 = malloc(s2_len); - if (ucs2 == NULL) { + if (s2 == NULL) { free(ucs2); return krb5_enomem(context); } @@ -849,15 +868,14 @@ krb5_pac_verify(krb5_context context, { krb5_data *copy; + if (pac->server_checksum->buffersize < 4 || + pac->privsvr_checksum->buffersize < 4) + return EINVAL; + ret = krb5_copy_data(context, &pac->data, ©); if (ret) return ret; - if (pac->server_checksum->buffersize < 4) - return EINVAL; - if (pac->privsvr_checksum->buffersize < 4) - return EINVAL; - memset((char *)copy->data + pac->server_checksum->offset_lo + 4, 0, pac->server_checksum->buffersize - 4); @@ -948,7 +966,7 @@ pac_checksum(krb5_context context, return 0; } -krb5_error_code +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL _krb5_pac_sign(krb5_context context, krb5_pac p, time_t authtime, @@ -969,6 +987,40 @@ _krb5_pac_sign(krb5_context context, krb5_data_zero(&logon); + for (i = 0; i < p->pac->numbuffers; i++) { + if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) { + if (p->server_checksum == NULL) { + p->server_checksum = &p->pac->buffers[i]; + } + if (p->server_checksum != &p->pac->buffers[i]) { + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("PAC have two server checksums", "")); + goto out; + } + } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) { + if (p->privsvr_checksum == NULL) { + p->privsvr_checksum = &p->pac->buffers[i]; + } + if (p->privsvr_checksum != &p->pac->buffers[i]) { + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("PAC have two KDC checksums", "")); + goto out; + } + } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) { + if (p->logon_name == NULL) { + p->logon_name = &p->pac->buffers[i]; + } + if (p->logon_name != &p->pac->buffers[i]) { + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("PAC have two logon names", "")); + goto out; + } + } + } + if (p->logon_name == NULL) num++; if (p->server_checksum == NULL) |