krb5_error_code samba_make_krb5_pac(krb5_context context, DATA_BLOB *pac_blob, krb5_pac *pac) { krb5_data pac_data; krb5_error_code ret; /* The user account may be set not to want the PAC */ if (!pac_blob) { return 0; } ret = krb5_data_copy(&pac_data, pac_blob->data, pac_blob->length); if (ret != 0) { return ret; } ret = krb5_pac_init(context, pac); if (ret != 0) { krb5_data_free(&pac_data); return ret; } ret = krb5_pac_add_buffer(context, *pac, PAC_TYPE_LOGON_INFO, &pac_data); krb5_data_free(&pac_data); if (ret != 0) { return ret; } return ret; }
static krb5_error_code pac_generate(void *ctx, krb5_context context, struct hdb_entry_ex *client, krb5_pac *pac) { krb5_error_code ret; krb5_data data; krb5_warnx(context, "pac generate"); data.data = "\x00\x01"; data.length = 2; ret = krb5_pac_init(context, pac); if (ret) return ret; ret = krb5_pac_add_buffer(context, *pac, 1, &data); if (ret) return ret; return 0; }
/* * Parse the supplied data into the PAC allocated by this function */ krb5_error_code KRB5_CALLCONV krb5_pac_parse(krb5_context context, const void *ptr, size_t len, krb5_pac *ppac) { krb5_error_code ret; size_t i; const unsigned char *p = (const unsigned char *)ptr; krb5_pac pac; size_t header_len; krb5_ui_4 cbuffers, version; *ppac = NULL; if (len < PACTYPE_LENGTH) return ERANGE; cbuffers = load_32_le(p); p += 4; version = load_32_le(p); p += 4; if (version != 0) return EINVAL; header_len = PACTYPE_LENGTH + (cbuffers * PAC_INFO_BUFFER_LENGTH); if (len < header_len) return ERANGE; ret = krb5_pac_init(context, &pac); if (ret != 0) return ret; pac->pac = (PACTYPE *)realloc(pac->pac, sizeof(PACTYPE) + ((cbuffers - 1) * sizeof(PAC_INFO_BUFFER))); if (pac->pac == NULL) { krb5_pac_free(context, pac); return ENOMEM; } pac->pac->cBuffers = cbuffers; pac->pac->Version = version; for (i = 0; i < pac->pac->cBuffers; i++) { PAC_INFO_BUFFER *buffer = &pac->pac->Buffers[i]; buffer->ulType = load_32_le(p); p += 4; buffer->cbBufferSize = load_32_le(p); p += 4; buffer->Offset = load_64_le(p); p += 8; if (buffer->Offset % PAC_ALIGNMENT) { krb5_pac_free(context, pac); return EINVAL; } if (buffer->Offset < header_len || buffer->Offset + buffer->cbBufferSize > len) { krb5_pac_free(context, pac); return ERANGE; } } pac->data.data = realloc(pac->data.data, len); if (pac->data.data == NULL) { krb5_pac_free(context, pac); return ENOMEM; } memcpy(pac->data.data, ptr, len); pac->data.length = len; *ppac = pac; return 0; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_pac pac; krb5_data data; krb5_principal p, p2; ret = krb5_init_context(&context); if (ret) errx(1, "krb5_init_contex"); krb5_enctype_enable(context, ETYPE_DES_CBC_MD5); ret = krb5_parse_name_flags(context, user, KRB5_PRINCIPAL_PARSE_NO_REALM, &p); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_pac_parse(context, saved_pac, sizeof(saved_pac), &pac); if (ret) krb5_err(context, 1, ret, "krb5_pac_parse"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify"); ret = _krb5_pac_sign(context, pac, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) krb5_err(context, 1, ret, "_krb5_pac_sign"); krb5_pac_free(context, pac); ret = krb5_pac_parse(context, data.data, data.length, &pac); krb5_data_free(&data); if (ret) krb5_err(context, 1, ret, "krb5_pac_parse 2"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify 2"); /* make a copy and try to reproduce it */ { uint32_t *list; size_t len, i; krb5_pac pac2; ret = krb5_pac_init(context, &pac2); if (ret) krb5_err(context, 1, ret, "krb5_pac_init"); /* our two user buffer plus the three "system" buffers */ ret = krb5_pac_get_types(context, pac, &len, &list); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_types"); for (i = 0; i < len; i++) { /* skip server_cksum, privsvr_cksum, and logon_name */ if (list[i] == 6 || list[i] == 7 || list[i] == 10) continue; ret = krb5_pac_get_buffer(context, pac, list[i], &data); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_buffer"); if (list[i] == 1) { if (type_1_length != data.length) krb5_errx(context, 1, "type 1 have wrong length: %lu", (unsigned long)data.length); } else krb5_errx(context, 1, "unknown type %lu", (unsigned long)list[i]); ret = krb5_pac_add_buffer(context, pac2, list[i], &data); if (ret) krb5_err(context, 1, ret, "krb5_pac_add_buffer"); krb5_data_free(&data); } free(list); ret = _krb5_pac_sign(context, pac2, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) krb5_err(context, 1, ret, "_krb5_pac_sign 4"); krb5_pac_free(context, pac2); ret = krb5_pac_parse(context, data.data, data.length, &pac2); krb5_data_free(&data); if (ret) krb5_err(context, 1, ret, "krb5_pac_parse 4"); ret = krb5_pac_verify(context, pac2, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify 4"); krb5_pac_free(context, pac2); } krb5_pac_free(context, pac); /* * check pac from Christian */ ret = krb5_parse_name_flags(context, user2, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_pac_parse(context, saved_pac2, sizeof(saved_pac2) -1, &pac); if (ret) krb5_err(context, 1, ret, "krb5_pac_parse"); ret = krb5_pac_verify(context, pac, authtime2, p2, &member_keyblock2, NULL); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify c1"); krb5_pac_free(context, pac); krb5_free_principal(context, p2); /* * Test empty free */ ret = krb5_pac_init(context, &pac); if (ret) krb5_err(context, 1, ret, "krb5_pac_init"); krb5_pac_free(context, pac); /* * Test add remove buffer */ ret = krb5_pac_init(context, &pac); if (ret) krb5_err(context, 1, ret, "krb5_pac_init"); { const krb5_data cdata = { 2, "\x00\x01" } ; ret = krb5_pac_add_buffer(context, pac, 1, &cdata); if (ret) krb5_err(context, 1, ret, "krb5_pac_add_buffer"); } { ret = krb5_pac_get_buffer(context, pac, 1, &data); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0) krb5_errx(context, 1, "krb5_pac_get_buffer data not the same"); krb5_data_free(&data); } { const krb5_data cdata = { 2, "\x02\x00" } ; ret = krb5_pac_add_buffer(context, pac, 2, &cdata); if (ret) krb5_err(context, 1, ret, "krb5_pac_add_buffer"); } { ret = krb5_pac_get_buffer(context, pac, 1, &data); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0) krb5_errx(context, 1, "krb5_pac_get_buffer data not the same"); krb5_data_free(&data); /* */ ret = krb5_pac_get_buffer(context, pac, 2, &data); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x02\x00", 2) != 0) krb5_errx(context, 1, "krb5_pac_get_buffer data not the same"); krb5_data_free(&data); } ret = _krb5_pac_sign(context, pac, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) krb5_err(context, 1, ret, "_krb5_pac_sign"); krb5_pac_free(context, pac); ret = krb5_pac_parse(context, data.data, data.length, &pac); krb5_data_free(&data); if (ret) krb5_err(context, 1, ret, "krb5_pac_parse 3"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify 3"); { uint32_t *list; size_t len; /* our two user buffer plus the three "system" buffers */ ret = krb5_pac_get_types(context, pac, &len, &list); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_types"); if (len != 5) krb5_errx(context, 1, "list wrong length"); free(list); } krb5_pac_free(context, pac); krb5_free_principal(context, p); krb5_free_context(context); return 0; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_pac pac; krb5_data data; krb5_principal p; ret = krb5_init_context(&context); if (ret) err(NULL, 0, "krb5_init_contex"); krb5_set_default_realm(context, "WIN2K3.THINKER.LOCAL"); ret = krb5_parse_name(context, user, &p); if (ret) err(context, ret, "krb5_parse_name"); ret = krb5_pac_parse(context, saved_pac, sizeof(saved_pac), &pac); if (ret) err(context, ret, "krb5_pac_parse"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) err(context, ret, "krb5_pac_verify"); ret = krb5int_pac_sign(context, pac, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) err(context, ret, "krb5int_pac_sign"); krb5_pac_free(context, pac); ret = krb5_pac_parse(context, data.data, data.length, &pac); krb5_free_data_contents(context, &data); if (ret) err(context, ret, "krb5_pac_parse 2"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) err(context, ret, "krb5_pac_verify 2"); /* make a copy and try to reproduce it */ { uint32_t *list; size_t len, i; krb5_pac pac2; ret = krb5_pac_init(context, &pac2); if (ret) err(context, ret, "krb5_pac_init"); /* our two user buffer plus the three "system" buffers */ ret = krb5_pac_get_types(context, pac, &len, &list); if (ret) err(context, ret, "krb5_pac_get_types"); for (i = 0; i < len; i++) { /* skip server_cksum, privsvr_cksum, and logon_name */ if (list[i] == 6 || list[i] == 7 || list[i] == 10) continue; ret = krb5_pac_get_buffer(context, pac, list[i], &data); if (ret) err(context, ret, "krb5_pac_get_buffer"); if (list[i] == 1) { if (type_1_length != data.length) err(context, 0, "type 1 have wrong length: %lu", (unsigned long)data.length); } else err(context, 0, "unknown type %lu", (unsigned long)list[i]); ret = krb5_pac_add_buffer(context, pac2, list[i], &data); if (ret) err(context, ret, "krb5_pac_add_buffer"); krb5_free_data_contents(context, &data); } free(list); ret = krb5int_pac_sign(context, pac2, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) err(context, ret, "krb5int_pac_sign 4"); krb5_pac_free(context, pac2); ret = krb5_pac_parse(context, data.data, data.length, &pac2); if (ret) err(context, ret, "krb5_pac_parse 4"); ret = krb5_pac_verify(context, pac2, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) err(context, ret, "krb5_pac_verify 4"); krb5_free_data_contents(context, &data); krb5_pac_free(context, pac2); } krb5_pac_free(context, pac); /* * Test empty free */ ret = krb5_pac_init(context, &pac); if (ret) err(context, ret, "krb5_pac_init"); krb5_pac_free(context, pac); /* * Test add remove buffer */ ret = krb5_pac_init(context, &pac); if (ret) err(context, ret, "krb5_pac_init"); { const krb5_data cdata = { 0, 2, "\x00\x01" } ; ret = krb5_pac_add_buffer(context, pac, 1, &cdata); if (ret) err(context, ret, "krb5_pac_add_buffer"); } { ret = krb5_pac_get_buffer(context, pac, 1, &data); if (ret) err(context, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0) err(context, 0, "krb5_pac_get_buffer data not the same"); krb5_free_data_contents(context, &data); } { const krb5_data cdata = { 0, 2, "\x02\x00" } ; ret = krb5_pac_add_buffer(context, pac, 2, &cdata); if (ret) err(context, ret, "krb5_pac_add_buffer"); } { ret = krb5_pac_get_buffer(context, pac, 1, &data); if (ret) err(context, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0) err(context, 0, "krb5_pac_get_buffer data not the same"); krb5_free_data_contents(context, &data); /* */ ret = krb5_pac_get_buffer(context, pac, 2, &data); if (ret) err(context, ret, "krb5_pac_get_buffer"); if (data.length != 2 || memcmp(data.data, "\x02\x00", 2) != 0) err(context, 0, "krb5_pac_get_buffer data not the same"); krb5_free_data_contents(context, &data); } ret = krb5int_pac_sign(context, pac, authtime, p, &member_keyblock, &kdc_keyblock, &data); if (ret) err(context, ret, "krb5int_pac_sign"); krb5_pac_free(context, pac); ret = krb5_pac_parse(context, data.data, data.length, &pac); krb5_free_data_contents(context, &data); if (ret) err(context, ret, "krb5_pac_parse 3"); ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, &kdc_keyblock); if (ret) err(context, ret, "krb5_pac_verify 3"); { uint32_t *list; size_t len; /* our two user buffer plus the three "system" buffers */ ret = krb5_pac_get_types(context, pac, &len, &list); if (ret) err(context, ret, "krb5_pac_get_types"); if (len != 5) err(context, 0, "list wrong length"); free(list); } krb5_pac_free(context, pac); krb5_free_principal(context, p); krb5_free_context(context); return 0; }