int _hx509_Name_to_string(const Name *n, char **str) { size_t total_len = 0; size_t i, j, m; int ret; *str = strdup(""); if (*str == NULL) return ENOMEM; for (m = n->u.rdnSequence.len; m > 0; m--) { size_t len; i = m - 1; for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; char *oidname; char *ss; oidname = oidtostring(&n->u.rdnSequence.val[i].val[j].type); switch(ds->element) { case choice_DirectoryString_ia5String: ss = ds->u.ia5String.data; len = ds->u.ia5String.length; break; case choice_DirectoryString_printableString: ss = ds->u.printableString.data; len = ds->u.printableString.length; break; case choice_DirectoryString_utf8String: ss = ds->u.utf8String; len = strlen(ss); break; case choice_DirectoryString_bmpString: { const uint16_t *bmp = ds->u.bmpString.data; size_t bmplen = ds->u.bmpString.length; size_t k; ret = wind_ucs2utf8_length(bmp, bmplen, &k); if (ret) { free(oidname); free(*str); *str = NULL; return ret; } ss = malloc(k + 1); if (ss == NULL) _hx509_abort("allocation failure"); /* XXX */ ret = wind_ucs2utf8(bmp, bmplen, ss, NULL); if (ret) { free(oidname); free(ss); free(*str); *str = NULL; return ret; } ss[k] = '\0'; len = k; break; } case choice_DirectoryString_teletexString: ss = ds->u.teletexString; len = strlen(ss); break; case choice_DirectoryString_universalString: { const uint32_t *uni = ds->u.universalString.data; size_t unilen = ds->u.universalString.length; size_t k; ret = wind_ucs4utf8_length(uni, unilen, &k); if (ret) { free(oidname); free(*str); *str = NULL; return ret; } ss = malloc(k + 1); if (ss == NULL) _hx509_abort("allocation failure"); /* XXX */ ret = wind_ucs4utf8(uni, unilen, ss, NULL); if (ret) { free(ss); free(oidname); free(*str); *str = NULL; return ret; } ss[k] = '\0'; len = k; break; } default: _hx509_abort("unknown directory type: %d", ds->element); exit(1); } append_string(str, &total_len, oidname, strlen(oidname), 0); free(oidname); append_string(str, &total_len, "=", 1, 0); append_string(str, &total_len, ss, len, 1); if (ds->element == choice_DirectoryString_bmpString || ds->element == choice_DirectoryString_universalString) { free(ss); } if (j + 1 < n->u.rdnSequence.val[i].len) append_string(str, &total_len, "+", 1, 0); } if (i > 0) append_string(str, &total_len, ",", 1, 0); } return 0; }
static krb5_error_code verify_logonname(krb5_context context, const struct PAC_INFO_BUFFER *logon_name, const krb5_data *data, time_t authtime, krb5_const_principal principal) { krb5_error_code ret; krb5_principal p2; uint32_t time1, time2; krb5_storage *sp; uint16_t len; char *s; sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo, logon_name->buffersize); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_ret_uint32(sp, &time1), out); CHECK(ret, krb5_ret_uint32(sp, &time2), out); { uint64_t t1, t2; t1 = unix2nttime(authtime); t2 = ((uint64_t)time2 << 32) | time1; if (t1 != t2) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch"); return EINVAL; } } CHECK(ret, krb5_ret_uint16(sp, &len), out); if (len == 0) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC logon name length missing"); return EINVAL; } s = malloc(len); if (s == NULL) { krb5_storage_free(sp); return krb5_enomem(context); } ret = krb5_storage_read(sp, s, len); if (ret != len) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name"); return EINVAL; } krb5_storage_free(sp); { size_t ucs2len = len / 2; uint16_t *ucs2; size_t u8len; unsigned int flags = WIND_RW_LE; ucs2 = malloc(sizeof(ucs2[0]) * ucs2len); if (ucs2 == NULL) return krb5_enomem(context); ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len); free(s); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to convert string to UCS-2"); return ret; } ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string"); return ret; } u8len += 1; /* Add space for NUL */ s = malloc(u8len); if (s == NULL) { free(ucs2); return krb5_enomem(context); } ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len); free(ucs2); if (ret) { free(s); 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) return ret; if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) { ret = EINVAL; krb5_set_error_message(context, ret, "PAC logon name mismatch"); } krb5_free_principal(context, p2); return ret; out: return ret; }
static krb5_error_code verify_logonname(krb5_context context, const struct PAC_INFO_BUFFER *logon_name, const krb5_data *data, time_t authtime, krb5_const_principal principal) { krb5_error_code ret; uint32_t time1, time2; krb5_storage *sp; uint16_t len; 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); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_ret_uint32(sp, &time1), out); CHECK(ret, krb5_ret_uint32(sp, &time2), out); { uint64_t t1, t2; t1 = unix2nttime(authtime); t2 = ((uint64_t)time2 << 32) | time1; /* * 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; } } CHECK(ret, krb5_ret_uint16(sp, &len), out); if (len == 0) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC logon name length missing"); return EINVAL; } s = malloc(len); if (s == NULL) { krb5_storage_free(sp); return krb5_enomem(context); } ret = krb5_storage_read(sp, s, len); if (ret != len) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name"); return EINVAL; } krb5_storage_free(sp); { size_t ucs2len = len / 2; uint16_t *ucs2; size_t u8len; unsigned int flags = WIND_RW_LE; ucs2 = malloc(sizeof(ucs2[0]) * ucs2len); if (ucs2 == NULL) return krb5_enomem(context); ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len); free(s); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to convert string to UCS-2"); return ret; } ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string"); return ret; } u8len += 1; /* Add space for NUL */ logon_string = malloc(u8len); if (logon_string == NULL) { free(ucs2); return krb5_enomem(context); } ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len); free(ucs2); if (ret) { free(logon_string); krb5_set_error_message(context, ret, "Failed to convert to UTF-8"); return 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; } ret = strcmp(logon_string, principal_string); if (ret != 0) { ret = EINVAL; krb5_set_error_message(context, ret, "PAC logon name [%s] mismatch principal name [%s]", logon_string, principal_string); } free(logon_string); free(principal_string); return ret; out: return ret; }