static krb5_error_code mspac_import_authdata(krb5_context kcontext, krb5_authdata_context context, void *plugin_context, void *request_context, krb5_authdata **authdata, krb5_boolean kdc_issued, krb5_const_principal kdc_issuer) { krb5_error_code code; struct mspac_context *pacctx = (struct mspac_context *)request_context; if (kdc_issued) return EINVAL; if (pacctx->pac != NULL) { krb5_pac_free(kcontext, pacctx->pac); pacctx->pac = NULL; } assert(authdata[0] != NULL); assert((authdata[0]->ad_type & AD_TYPE_FIELD_TYPE_MASK) == KRB5_AUTHDATA_WIN2K_PAC); code = krb5_pac_parse(kcontext, authdata[0]->contents, authdata[0]->length, &pacctx->pac); return code; }
static krb5_error_code mspac_export_internal(krb5_context kcontext, krb5_authdata_context context, void *plugin_context, void *request_context, krb5_boolean restrict_authenticated, void **ptr) { struct mspac_context *pacctx = (struct mspac_context *)request_context; krb5_error_code code; krb5_pac pac; *ptr = NULL; if (pacctx->pac == NULL) return ENOENT; if (restrict_authenticated && (pacctx->pac->verified) == FALSE) return ENOENT; code = krb5_pac_parse(kcontext, pacctx->pac->data.data, pacctx->pac->data.length, &pac); if (code == 0) { pac->verified = pacctx->pac->verified; *ptr = pac; } return code; }
static int mit_samba_update_pac_data(struct mit_samba_context *ctx, hdb_entry_ex *client, DATA_BLOB *pac_data, DATA_BLOB *logon_data) { TALLOC_CTX *tmp_ctx; DATA_BLOB *logon_blob; krb5_error_code code; NTSTATUS nt_status; krb5_pac pac = NULL; int ret; /* The user account may be set not to want the PAC */ if (client && !samba_princ_needs_pac(client)) { return EINVAL; } tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac_data context"); if (!tmp_ctx) { return ENOMEM; } logon_blob = talloc_zero(tmp_ctx, DATA_BLOB); if (!logon_blob) { ret = ENOMEM; goto done; } code = krb5_pac_parse(ctx->context, pac_data->data, pac_data->length, &pac); if (code) { ret = EINVAL; goto done; } nt_status = samba_kdc_update_pac_blob(tmp_ctx, ctx->context, &pac, logon_blob); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("Building PAC failed: %s\n", nt_errstr(nt_status))); ret = EINVAL; goto done; } logon_data->data = (uint8_t *)malloc(logon_blob->length); if (!logon_data->data) { ret = ENOMEM; goto done; } memcpy(logon_data->data, logon_blob->data, logon_blob->length); logon_data->length = logon_blob->length; ret = 0; done: if (pac) krb5_pac_free(ctx->context, pac); talloc_free(tmp_ctx); return ret; }
static krb5_error_code mspac_internalize(krb5_context kcontext, krb5_authdata_context context, void *plugin_context, void *request_context, krb5_octet **buffer, size_t *lenremain) { struct mspac_context *pacctx = (struct mspac_context *)request_context; krb5_error_code code; krb5_int32 ibuf; krb5_octet *bp; size_t remain; krb5_pac pac = NULL; bp = *buffer; remain = *lenremain; /* length */ code = krb5_ser_unpack_int32(&ibuf, &bp, &remain); if (code != 0) return code; if (ibuf != 0) { code = krb5_pac_parse(kcontext, bp, ibuf, &pac); if (code != 0) return code; bp += ibuf; remain -= ibuf; } /* verified */ code = krb5_ser_unpack_int32(&ibuf, &bp, &remain); if (code != 0) { krb5_pac_free(kcontext, pac); return code; } if (pac != NULL) { pac->verified = (ibuf != 0); } if (pacctx->pac != NULL) { krb5_pac_free(kcontext, pacctx->pac); } pacctx->pac = pac; *buffer = bp; *lenremain = remain; return 0; }
NTSTATUS kerberos_pac_blob_to_server_info(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, DATA_BLOB pac_blob, krb5_context context, struct auth_serversupplied_info **server_info) { krb5_error_code ret; krb5_pac pac; ret = krb5_pac_parse(context, pac_blob.data, pac_blob.length, &pac); if (ret) { return map_nt_error_from_unix(ret); } ret = kerberos_pac_to_server_info(mem_ctx, iconv_convenience, pac, context, server_info); krb5_pac_free(context, pac); if (ret) { return map_nt_error_from_unix(ret); } return NT_STATUS_OK; }
NTSTATUS kerberos_pac_blob_to_user_info_dc(TALLOC_CTX *mem_ctx, DATA_BLOB pac_blob, krb5_context context, struct auth_user_info_dc **user_info_dc, struct PAC_SIGNATURE_DATA *pac_srv_sig, struct PAC_SIGNATURE_DATA *pac_kdc_sig) { krb5_error_code ret; krb5_pac pac; ret = krb5_pac_parse(context, pac_blob.data, pac_blob.length, &pac); if (ret) { return map_nt_error_from_unix_common(ret); } ret = kerberos_pac_to_user_info_dc(mem_ctx, pac, context, user_info_dc, pac_srv_sig, pac_kdc_sig); krb5_pac_free(context, pac); if (ret) { return map_nt_error_from_unix_common(ret); } return NT_STATUS_OK; }
static krb5_error_code mspac_set_attribute(krb5_context kcontext, krb5_authdata_context context, void *plugin_context, void *request_context, krb5_boolean complete, const krb5_data *attribute, const krb5_data *value) { struct mspac_context *pacctx = (struct mspac_context *)request_context; krb5_error_code code; krb5_ui_4 type; if (pacctx->pac == NULL) return ENOENT; code = mspac_attr2type(attribute, &type); if (code != 0) return code; /* -1 is a magic type that refers to the entire PAC */ if (type == (krb5_ui_4)-1) { krb5_pac newpac; code = krb5_pac_parse(kcontext, value->data, value->length, &newpac); if (code != 0) return code; krb5_pac_free(kcontext, pacctx->pac); pacctx->pac = newpac; } else { code = krb5_pac_add_buffer(kcontext, pacctx->pac, type, value); } return code; }
static int mit_samba_update_pac_data(struct mit_samba_context *ctx, hdb_entry_ex *client, DATA_BLOB *pac_data, DATA_BLOB *logon_data) { TALLOC_CTX *tmp_ctx; DATA_BLOB *logon_blob; krb5_error_code code; NTSTATUS nt_status; krb5_pac pac = NULL; int ret; struct samba_kdc_entry *skdc_entry = NULL; if (client) { skdc_entry = talloc_get_type_abort(client->ctx, struct samba_kdc_entry); } /* The user account may be set not to want the PAC */ if (client && !samba_princ_needs_pac(skdc_entry)) { return EINVAL; } tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac_data context"); if (!tmp_ctx) { return ENOMEM; } logon_blob = talloc_zero(tmp_ctx, DATA_BLOB); if (!logon_blob) { ret = ENOMEM; goto done; } code = krb5_pac_parse(ctx->context, pac_data->data, pac_data->length, &pac); if (code) { ret = EINVAL; goto done; } /* TODO: An implementation-specific decision will need to be * made as to when to check the KDC pac signature, and how to * untrust untrusted RODCs */ nt_status = samba_kdc_update_pac_blob(tmp_ctx, ctx->context, pac, logon_blob, NULL, NULL); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("Building PAC failed: %s\n", nt_errstr(nt_status))); ret = EINVAL; goto done; } logon_data->data = (uint8_t *)malloc(logon_blob->length); if (!logon_data->data) { ret = ENOMEM; goto done; } memcpy(logon_data->data, logon_blob->data, logon_blob->length); logon_data->length = logon_blob->length; ret = 0; done: if (pac) krb5_pac_free(ctx->context, pac); talloc_free(tmp_ctx); return ret; }
static krb5_error_code check_PAC(krb5_context context, krb5_kdc_configuration *config, const krb5_principal client_principal, hdb_entry_ex *client, hdb_entry_ex *server, const EncryptionKey *server_key, const EncryptionKey *krbtgt_key, EncTicketPart *tkt, krb5_data *rspac, int *require_signedpath) { AuthorizationData *ad = tkt->authorization_data; unsigned i, j; krb5_error_code ret; if (ad == NULL || ad->len == 0) return 0; for (i = 0; i < ad->len; i++) { AuthorizationData child; if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT) continue; ret = decode_AuthorizationData(ad->val[i].ad_data.data, ad->val[i].ad_data.length, &child, NULL); if (ret) { krb5_set_error_string(context, "Failed to decode " "IF_RELEVANT with %d", ret); return ret; } for (j = 0; j < child.len; j++) { if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { krb5_pac pac; /* Found PAC */ ret = krb5_pac_parse(context, child.val[j].ad_data.data, child.val[j].ad_data.length, &pac); free_AuthorizationData(&child); if (ret) return ret; ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal, krbtgt_key, NULL); if (ret) { krb5_pac_free(context, pac); return ret; } ret = _kdc_pac_verify(context, client_principal, client, server, &pac); if (ret) { krb5_pac_free(context, pac); return ret; } *require_signedpath = 0; ret = _krb5_pac_sign(context, pac, tkt->authtime, client_principal, server_key, krbtgt_key, rspac); krb5_pac_free(context, pac); return ret; } } free_AuthorizationData(&child); } return 0; }
static void test_ap(krb5_context context, krb5_principal target, krb5_principal server, krb5_keytab keytab, krb5_ccache ccache, const krb5_flags client_flags) { krb5_error_code ret; krb5_auth_context client_ac = NULL, server_ac = NULL; krb5_data data; krb5_flags server_flags; krb5_ticket *ticket = NULL; int32_t server_seq, client_seq; ret = krb5_mk_req_exact(context, &client_ac, client_flags, target, NULL, ccache, &data); if (ret) krb5_err(context, 1, ret, "krb5_mk_req_exact"); ret = krb5_rd_req(context, &server_ac, &data, server, keytab, &server_flags, &ticket); if (ret) krb5_err(context, 1, ret, "krb5_rd_req"); if (server_flags & AP_OPTS_MUTUAL_REQUIRED) { krb5_ap_rep_enc_part *repl; krb5_data_free(&data); if ((client_flags & AP_OPTS_MUTUAL_REQUIRED) == 0) krb5_errx(context, 1, "client flag missing mutual req"); ret = krb5_mk_rep (context, server_ac, &data); if (ret) krb5_err(context, 1, ret, "krb5_mk_rep"); ret = krb5_rd_rep (context, client_ac, &data, &repl); if (ret) krb5_err(context, 1, ret, "krb5_rd_rep"); krb5_free_ap_rep_enc_part (context, repl); } else { if (client_flags & AP_OPTS_MUTUAL_REQUIRED) krb5_errx(context, 1, "server flag missing mutual req"); } krb5_auth_con_getremoteseqnumber(context, server_ac, &server_seq); krb5_auth_con_getremoteseqnumber(context, client_ac, &client_seq); if (server_seq != client_seq) krb5_errx(context, 1, "seq num differ"); krb5_auth_con_getlocalseqnumber(context, server_ac, &server_seq); krb5_auth_con_getlocalseqnumber(context, client_ac, &client_seq); if (server_seq != client_seq) krb5_errx(context, 1, "seq num differ"); krb5_data_free(&data); krb5_auth_con_free(context, client_ac); krb5_auth_con_free(context, server_ac); if (verify_pac) { krb5_pac pac; ret = krb5_ticket_get_authorization_data_type(context, ticket, KRB5_AUTHDATA_WIN2K_PAC, &data); if (ret) krb5_err(context, 1, ret, "get pac"); ret = krb5_pac_parse(context, data.data, data.length, &pac); if (ret) krb5_err(context, 1, ret, "pac parse"); krb5_pac_free(context, pac); } krb5_free_ticket(context, ticket); }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_rd_req_ctx(krb5_context context, krb5_auth_context *auth_context, const krb5_data *inbuf, krb5_const_principal server, krb5_rd_req_in_ctx inctx, krb5_rd_req_out_ctx *outctx) { krb5_error_code ret; krb5_ap_req ap_req; krb5_rd_req_out_ctx o = NULL; krb5_keytab id = NULL, keytab = NULL; krb5_principal service = NULL; *outctx = NULL; o = calloc(1, sizeof(*o)); if (o == NULL) { krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } if (*auth_context == NULL) { ret = krb5_auth_con_init(context, auth_context); if (ret) goto out; } ret = krb5_decode_ap_req(context, inbuf, &ap_req); if(ret) goto out; /* Save that principal that was in the request */ ret = _krb5_principalname2krb5_principal(context, &o->server, ap_req.ticket.sname, ap_req.ticket.realm); if (ret) goto out; if (ap_req.ap_options.use_session_key && (*auth_context)->keyblock == NULL) { ret = KRB5KRB_AP_ERR_NOKEY; krb5_set_error_message(context, ret, N_("krb5_rd_req: user to user auth " "without session key given", "")); goto out; } if (inctx && inctx->keytab) id = inctx->keytab; if((*auth_context)->keyblock){ ret = krb5_copy_keyblock(context, (*auth_context)->keyblock, &o->keyblock); if (ret) goto out; } else if(inctx && inctx->keyblock){ ret = krb5_copy_keyblock(context, inctx->keyblock, &o->keyblock); if (ret) goto out; } else { if(id == NULL) { krb5_kt_default(context, &keytab); id = keytab; } if (id == NULL) goto out; if (server == NULL) { ret = _krb5_principalname2krb5_principal(context, &service, ap_req.ticket.sname, ap_req.ticket.realm); if (ret) goto out; server = service; } ret = get_key_from_keytab(context, &ap_req, server, id, &o->keyblock); if (ret) { /* If caller specified a server, fail. */ if (service == NULL && (context->flags & KRB5_CTX_F_RD_REQ_IGNORE) == 0) goto out; /* Otherwise, fall back to iterating over the keytab. This * have serious performace issues for larger keytab. */ o->keyblock = NULL; } } if (o->keyblock) { /* * We got an exact keymatch, use that. */ ret = krb5_verify_ap_req2(context, auth_context, &ap_req, server, o->keyblock, 0, &o->ap_req_options, &o->ticket, KRB5_KU_AP_REQ_AUTH); if (ret) goto out; } else { /* * Interate over keytab to find a key that can decrypt the request. */ krb5_keytab_entry entry; krb5_kt_cursor cursor; int done = 0, kvno = 0; memset(&cursor, 0, sizeof(cursor)); if (ap_req.ticket.enc_part.kvno) kvno = *ap_req.ticket.enc_part.kvno; ret = krb5_kt_start_seq_get(context, id, &cursor); if (ret) goto out; done = 0; while (!done) { krb5_principal p; ret = krb5_kt_next_entry(context, id, &entry, &cursor); if (ret) { _krb5_kt_principal_not_found(context, ret, id, o->server, ap_req.ticket.enc_part.etype, kvno); krb5_kt_end_seq_get(context, id, &cursor); goto out; } if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype) { krb5_kt_free_entry (context, &entry); continue; } ret = krb5_verify_ap_req2(context, auth_context, &ap_req, server, &entry.keyblock, 0, &o->ap_req_options, &o->ticket, KRB5_KU_AP_REQ_AUTH); if (ret) { krb5_kt_free_entry(context, &entry); continue; } /* * Found a match, save the keyblock for PAC processing, * and update the service principal in the ticket to match * whatever is in the keytab. */ ret = krb5_copy_keyblock(context, &entry.keyblock, &o->keyblock); if (ret) { krb5_kt_free_entry(context, &entry); krb5_kt_end_seq_get(context, id, &cursor); goto out; } ret = krb5_copy_principal(context, entry.principal, &p); if (ret) { krb5_kt_free_entry(context, &entry); krb5_kt_end_seq_get(context, id, &cursor); goto out; } krb5_free_principal(context, o->ticket->server); o->ticket->server = p; krb5_kt_free_entry(context, &entry); done = 1; } krb5_kt_end_seq_get(context, id, &cursor); } /* If there is a PAC, verify its server signature */ if (inctx == NULL || inctx->check_pac) { krb5_pac pac; krb5_data data; ret = krb5_ticket_get_authorization_data_type(context, o->ticket, KRB5_AUTHDATA_WIN2K_PAC, &data); if (ret == 0) { ret = krb5_pac_parse(context, data.data, data.length, &pac); krb5_data_free(&data); if (ret) goto out; ret = krb5_pac_verify(context, pac, o->ticket->ticket.authtime, o->ticket->client, o->keyblock, NULL); krb5_pac_free(context, pac); if (ret == 0) o->flags |= KRB5_RD_REQ_OUT_PAC_VALID; ret = 0; } else ret = 0; } out: if (ret || outctx == NULL) { krb5_rd_req_out_ctx_free(context, o); } else *outctx = o; free_AP_REQ(&ap_req); if (service) krb5_free_principal(context, service); if (keytab) krb5_kt_close(context, keytab); return ret; }
krb5_error_code KRB5_LIB_FUNCTION krb5_rd_req_ctx(krb5_context context, krb5_auth_context *auth_context, const krb5_data *inbuf, krb5_const_principal server, krb5_rd_req_in_ctx inctx, krb5_rd_req_out_ctx *outctx) { krb5_error_code ret; krb5_ap_req ap_req; krb5_principal service = NULL; krb5_rd_req_out_ctx o = NULL; ret = _krb5_rd_req_out_ctx_alloc(context, &o); if (ret) goto out; if (*auth_context == NULL) { ret = krb5_auth_con_init(context, auth_context); if (ret) goto out; } ret = krb5_decode_ap_req(context, inbuf, &ap_req); if(ret) goto out; if(server == NULL){ ret = _krb5_principalname2krb5_principal(context, &service, ap_req.ticket.sname, ap_req.ticket.realm); if (ret) goto out; server = service; } if (ap_req.ap_options.use_session_key && (*auth_context)->keyblock == NULL) { krb5_set_error_string(context, "krb5_rd_req: user to user auth " "without session key given"); ret = KRB5KRB_AP_ERR_NOKEY; goto out; } if((*auth_context)->keyblock){ ret = krb5_copy_keyblock(context, (*auth_context)->keyblock, &o->keyblock); if (ret) goto out; } else if(inctx->keyblock){ ret = krb5_copy_keyblock(context, inctx->keyblock, &o->keyblock); if (ret) goto out; } else { krb5_keytab keytab = NULL; if (inctx && inctx->keytab) keytab = inctx->keytab; ret = get_key_from_keytab(context, auth_context, &ap_req, server, keytab, &o->keyblock); if(ret) goto out; } ret = krb5_verify_ap_req2(context, auth_context, &ap_req, server, o->keyblock, 0, &o->ap_req_options, &o->ticket, KRB5_KU_AP_REQ_AUTH); if (ret) goto out; /* If there is a PAC, verify its server signature */ if (inctx->check_pac) { krb5_pac pac; krb5_data data; ret = krb5_ticket_get_authorization_data_type(context, o->ticket, KRB5_AUTHDATA_WIN2K_PAC, &data); if (ret == 0) { ret = krb5_pac_parse(context, data.data, data.length, &pac); krb5_data_free(&data); if (ret) goto out; ret = krb5_pac_verify(context, pac, o->ticket->ticket.authtime, o->ticket->client, o->keyblock, NULL); krb5_pac_free(context, pac); if (ret) goto out; } ret = 0; } out: if (ret || outctx == NULL) { krb5_rd_req_out_ctx_free(context, o); } else *outctx = o; free_AP_REQ(&ap_req); if(service) krb5_free_principal(context, service); return ret; }
krb5_error_code sss_extract_pac(krb5_context ctx, krb5_ccache ccache, krb5_principal server_principal, krb5_principal client_principal, krb5_keytab keytab, krb5_authdata ***_pac_authdata) { #ifdef HAVE_PAC_RESPONDER krb5_error_code kerr; krb5_creds mcred; krb5_creds cred; krb5_authdata **pac_authdata = NULL; krb5_pac pac = NULL; int ret; krb5_ticket *ticket = NULL; krb5_keytab_entry entry; memset(&entry, 0, sizeof(entry)); memset(&mcred, 0, sizeof(mcred)); memset(&cred, 0, sizeof(mcred)); mcred.server = server_principal; mcred.client = client_principal; kerr = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcred, &cred); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_retrieve_cred failed.\n"); goto done; } kerr = krb5_decode_ticket(&cred.ticket, &ticket); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_decode_ticket failed.\n"); goto done; } kerr = krb5_server_decrypt_ticket_keytab(ctx, keytab, ticket); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_server_decrypt_ticket_keytab failed.\n"); goto done; } kerr = sss_krb5_find_authdata(ctx, ticket->enc_part2->authorization_data, NULL, KRB5_AUTHDATA_WIN2K_PAC, &pac_authdata); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_find_authdata failed.\n"); goto done; } if (pac_authdata == NULL || pac_authdata[0] == NULL) { DEBUG(SSSDBG_OP_FAILURE, "No PAC authdata available.\n"); kerr = ENOENT; goto done; } if (pac_authdata[1] != NULL) { DEBUG(SSSDBG_OP_FAILURE, "More than one PAC autdata found.\n"); kerr = EINVAL; goto done; } kerr = krb5_pac_parse(ctx, pac_authdata[0]->contents, pac_authdata[0]->length, &pac); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_pac_parse failed.\n"); goto done; } kerr = krb5_kt_get_entry(ctx, keytab, ticket->server, ticket->enc_part.kvno, ticket->enc_part.enctype, &entry); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_kt_get_entry failed.\n"); goto done; } kerr = krb5_pac_verify(ctx, pac, 0, NULL, &entry.key, NULL); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_pac_verify failed.\n"); goto done; } ret = unsetenv("_SSS_LOOPS"); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to unset _SSS_LOOPS, " "sss_pac_make_request will most certainly fail.\n"); } *_pac_authdata = pac_authdata; kerr = 0; done: if (kerr != 0) { krb5_free_authdata(ctx, pac_authdata); } if (entry.magic != 0) { krb5_free_keytab_entry_contents(ctx, &entry); } krb5_pac_free(ctx, pac); if (ticket != NULL) { krb5_free_ticket(ctx, ticket); } krb5_free_cred_contents(ctx, &cred); return kerr; #else return ENOTSUP; #endif }
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; }