int krb5_kdc_process_request(krb5_context context, krb5_kdc_configuration *config, unsigned char *buf, size_t len, krb5_data *reply, krb5_boolean *prependlength, const char *from, struct sockaddr *addr, int datagram_reply) { KDC_REQ req; Ticket ticket; DigestREQ digestreq; krb5_error_code ret; size_t i; gettimeofday(&_kdc_now, NULL); if(decode_AS_REQ(buf, len, &req, &i) == 0){ krb5_data req_buffer; req_buffer.data = buf; req_buffer.length = len; ret = _kdc_as_rep(context, config, &req, &req_buffer, reply, from, addr, datagram_reply); free_AS_REQ(&req); return ret; }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){ ret = _kdc_tgs_rep(context, config, &req, reply, from, addr); free_TGS_REQ(&req); return ret; }else if(decode_Ticket(buf, len, &ticket, &i) == 0){ ret = _kdc_do_524(context, config, &ticket, reply, from, addr); free_Ticket(&ticket); return ret; }else if(decode_DigestREQ(buf, len, &digestreq, &i) == 0){ ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr); free_DigestREQ(&digestreq); return ret; } else if(_kdc_maybe_version4(buf, len)){ *prependlength = FALSE; /* elbitapmoc sdrawkcab XXX */ _kdc_do_version4(context, config, buf, len, reply, from, (struct sockaddr_in*)addr); return 0; } else if (config->enable_kaserver) { ret = _kdc_do_kaserver(context, config, buf, len, reply, from, (struct sockaddr_in*)addr); return ret; } return -1; }
static void copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) { Ticket ticket; size_t len; int ret; ret = decode_Ticket(v5cred->ticket.data, v5cred->ticket.length, &ticket, &len); if (ret == 0) { strncpy(dest, ticket.realm, destlen - 1); dest[destlen - 1] = '\0'; free_Ticket(&ticket); } }
/* FIXME */ PyObject *creds_parse(krb5CredsObject *self, PyObject *args) { krb5_error_code ret; PyObject *tuple; Ticket t; size_t len; char *s; int error = 0; if ((tuple = PyTuple_New(3)) == NULL) { error = 1; goto out; }; decode_Ticket(self->creds.ticket.data, self->creds.ticket.length, &t, &len); ret = krb5_enctype_to_string(self->context, t.enc_part.etype, &s); if (ret != 0) { asprintf(&s, "unknown (%d)", t.enc_part.etype); } PyTuple_SetItem(tuple, 0, PyString_FromString(s)); free(s); if (t.enc_part.kvno) PyTuple_SetItem(tuple, 1, PyInt_FromLong(*t.enc_part.kvno)); else PyTuple_SetItem(tuple, 1, PyInt_FromLong(-1)); ret = krb5_unparse_name(self->context, self->creds.server, &s); if (ret) krb5_exception(self->context, 1, ret, "krb5_unparse_name"); PyTuple_SetItem(tuple, 2, PyString_FromString(s)); free(s); //PyTuple_SetItem(tuple, 0, PyInt_FromLong(entry.vno)); //PyTuple_SetItem(tuple, 1, PyString_FromString(etype)); //PyTuple_SetItem(tuple, 2, PyString_FromString(principal)); //PyTuple_SetItem(tuple, 3, PyInt_FromLong(entry.timestamp)); //PyTuple_SetItem(tuple, 4, PyString_FromString(entry.keyblock.keyvalue.data)); out: if (error) return NULL; else return tuple; }
krb5_error_code KRB5_LIB_FUNCTION krb5_build_ap_req (krb5_context context, krb5_enctype enctype, krb5_creds *cred, krb5_flags ap_options, krb5_data authenticator, krb5_data *retdata) { krb5_error_code ret = 0; AP_REQ ap; Ticket t; size_t len; ap.pvno = 5; ap.msg_type = krb_ap_req; memset(&ap.ap_options, 0, sizeof(ap.ap_options)); ap.ap_options.use_session_key = (ap_options & AP_OPTS_USE_SESSION_KEY) > 0; ap.ap_options.mutual_required = (ap_options & AP_OPTS_MUTUAL_REQUIRED) > 0; ap.ticket.tkt_vno = 5; copy_Realm(&cred->server->realm, &ap.ticket.realm); copy_PrincipalName(&cred->server->name, &ap.ticket.sname); decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len); copy_EncryptedData(&t.enc_part, &ap.ticket.enc_part); free_Ticket(&t); ap.authenticator.etype = enctype; ap.authenticator.kvno = NULL; ap.authenticator.cipher = authenticator; ASN1_MALLOC_ENCODE(AP_REQ, retdata->data, retdata->length, &ap, &len, ret); if(ret == 0 && retdata->length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); free_AP_REQ(&ap); return ret; }
static void print_and_decode_tkt (krb5_context context, krb5_data *ticket, krb5_principal server, krb5_enctype enctype) { krb5_error_code ret; krb5_crypto crypto; krb5_data dec_data; size_t len; EncTicketPart decr_part; krb5_keyblock key; Ticket tkt; ret = decode_Ticket (ticket->data, ticket->length, &tkt, &len); if (ret) krb5_err (context, 1, ret, "decode_Ticket"); ret = krb5_string_to_key (context, enctype, "foo", server, &key); if (ret) krb5_err (context, 1, ret, "krb5_string_to_key"); ret = krb5_crypto_init(context, &key, 0, &crypto); if (ret) krb5_err (context, 1, ret, "krb5_crypto_init"); ret = krb5_decrypt_EncryptedData (context, crypto, KRB5_KU_TICKET, &tkt.enc_part, &dec_data); krb5_crypto_destroy (context, crypto); if (ret) krb5_err (context, 1, ret, "krb5_decrypt_EncryptedData"); ret = decode_EncTicketPart (dec_data.data, dec_data.length, &decr_part, &len); krb5_data_free (&dec_data); if (ret) krb5_err (context, 1, ret, "krb5_decode_EncTicketPart"); free_EncTicketPart(&decr_part); }
static int v5_to_kt(krb5_creds *cred, uid_t uid, struct kafs_token *kt, int local524) { int kvno, ret; kt->ticket = NULL; /* check if des key */ if (cred->session.keyvalue.length != 8) return EINVAL; if (local524) { Ticket t; unsigned char *buf; size_t buf_len; size_t len; kvno = KAFS_RXKAD_2B_KVNO; ret = decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len); if (ret) return ret; if (t.tkt_vno != 5) return -1; ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_len, &t.enc_part, &len, ret); free_Ticket(&t); if (ret) return ret; if(buf_len != len) { free(buf); return KRB5KRB_ERR_GENERIC; } kt->ticket = buf; kt->ticket_len = buf_len; } else { kvno = KAFS_RXKAD_K5_KVNO; kt->ticket = malloc(cred->ticket.length); if (kt->ticket == NULL) return ENOMEM; kt->ticket_len = cred->ticket.length; memcpy(kt->ticket, cred->ticket.data, kt->ticket_len); ret = 0; } /* * Build a struct ClearToken */ kt->ct.AuthHandle = kvno; memcpy(kt->ct.HandShakeKey, cred->session.keyvalue.data, 8); kt->ct.ViceId = uid; kt->ct.BeginTimestamp = cred->times.starttime; kt->ct.EndTimestamp = cred->times.endtime; _kafs_fixup_viceid(&kt->ct, uid); return 0; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_ccache cache; krb5_creds *out; int optidx = 0; int32_t nametype = KRB5_NT_UNKNOWN; krb5_get_creds_opt opt; krb5_principal server = NULL; krb5_principal impersonate; setprogname(argv[0]); ret = krb5_init_context(&context); if (ret) errx(1, "krb5_init_context failed: %d", ret); if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage (0); if (version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; if (debug_flag) { ret = krb5_set_debug_dest(context, getprogname(), "STDERR"); if (ret) krb5_warn(context, ret, "krb5_set_debug_dest"); } if (cache_str) { ret = krb5_cc_resolve(context, cache_str, &cache); if (ret) krb5_err(context, 1, ret, "%s", cache_str); } else { ret = krb5_cc_default (context, &cache); if (ret) krb5_err(context, 1, ret, "krb5_cc_resolve"); } ret = krb5_get_creds_opt_alloc(context, &opt); if (ret) krb5_err(context, 1, ret, "krb5_get_creds_opt_alloc"); if (etype_str) { krb5_enctype enctype; ret = krb5_string_to_enctype(context, etype_str, &enctype); if (ret) krb5_errx(context, 1, N_("unrecognized enctype: %s", ""), etype_str); krb5_get_creds_opt_set_enctype(context, opt, enctype); } if (impersonate_str) { ret = krb5_parse_name(context, impersonate_str, &impersonate); if (ret) krb5_err(context, 1, ret, "krb5_parse_name %s", impersonate_str); krb5_get_creds_opt_set_impersonate(context, opt, impersonate); krb5_get_creds_opt_add_options(context, opt, KRB5_GC_NO_STORE); krb5_free_principal(context, impersonate); } if (out_cache_str) krb5_get_creds_opt_add_options(context, opt, KRB5_GC_NO_STORE); if (forwardable_flag) krb5_get_creds_opt_add_options(context, opt, KRB5_GC_FORWARDABLE); if (!transit_flag) krb5_get_creds_opt_add_options(context, opt, KRB5_GC_NO_TRANSIT_CHECK); if (canonicalize_flag) krb5_get_creds_opt_add_options(context, opt, KRB5_GC_CANONICALIZE); if (!store_flag) krb5_get_creds_opt_add_options(context, opt, KRB5_GC_NO_STORE); if (cached_only_flag) krb5_get_creds_opt_add_options(context, opt, KRB5_GC_CACHED); if (delegation_cred_str) { krb5_ccache id; krb5_creds c, mc; Ticket ticket; krb5_cc_clear_mcred(&mc); ret = krb5_cc_get_principal(context, cache, &mc.server); if (ret) krb5_err(context, 1, ret, "krb5_cc_get_principal"); ret = krb5_cc_resolve(context, delegation_cred_str, &id); if(ret) krb5_err(context, 1, ret, "krb5_cc_resolve"); ret = krb5_cc_retrieve_cred(context, id, 0, &mc, &c); if(ret) krb5_err(context, 1, ret, "krb5_cc_retrieve_cred"); ret = decode_Ticket(c.ticket.data, c.ticket.length, &ticket, NULL); if (ret) { krb5_clear_error_message(context); krb5_err(context, 1, ret, "decode_Ticket"); } krb5_free_cred_contents(context, &c); ret = krb5_get_creds_opt_set_ticket(context, opt, &ticket); if(ret) krb5_err(context, 1, ret, "krb5_get_creds_opt_set_ticket"); free_Ticket(&ticket); krb5_cc_close(context, id); krb5_free_principal(context, mc.server); krb5_get_creds_opt_add_options(context, opt, KRB5_GC_CONSTRAINED_DELEGATION); } if (nametype_str != NULL) { ret = krb5_parse_nametype(context, nametype_str, &nametype); if (ret) krb5_err(context, 1, ret, "krb5_parse_nametype"); } if (nametype == KRB5_NT_SRV_HST || nametype == KRB5_NT_SRV_HST_NEEDS_CANON) is_hostbased_flag = 1; if (is_hostbased_flag) { const char *sname = NULL; const char *hname = NULL; if (nametype_str != NULL && nametype != KRB5_NT_SRV_HST && nametype != KRB5_NT_SRV_HST_NEEDS_CANON) krb5_errx(context, 1, "--hostbased not compatible with " "non-hostbased --name-type"); if (is_canonical_flag) nametype = KRB5_NT_SRV_HST; else nametype = KRB5_NT_SRV_HST_NEEDS_CANON; /* * Host-based service names can have more than one component. * * RFC5179 did not, but should have, assign a Kerberos name-type * corresponding to GSS_C_NT_DOMAINBASED. But it's basically a * host-based service name type with one additional component. * * So that's how we're treating host-based service names here: * two or more components. */ if (argc == 0) { usage(1); } else if (argc == 1) { krb5_principal server2; /* * In this case the one argument is a principal name, not the * service name. * * We parse the argument as a principal name, extract the service * and hostname components, use krb5_sname_to_principal(), then * extract the service and hostname components from that. */ ret = krb5_parse_name(context, argv[0], &server); if (ret) krb5_err(context, 1, ret, "krb5_parse_name %s", argv[0]); sname = krb5_principal_get_comp_string(context, server, 0); /* * If a single-component principal name is given, then we'll * default the hostname, as krb5_principal_get_comp_string() * returns NULL in this case. */ hname = krb5_principal_get_comp_string(context, server, 1); ret = krb5_sname_to_principal(context, hname, sname, KRB5_NT_SRV_HST, &server2); sname = krb5_principal_get_comp_string(context, server2, 0); hname = krb5_principal_get_comp_string(context, server2, 1); /* * Modify the original with the new sname/hname. This way we * retain any additional principal name components from the given * principal name. * * The name-type is set further below. */ ret = krb5_principal_set_comp_string(context, server, 0, sname); if (ret) krb5_err(context, 1, ret, "krb5_principal_set_comp_string %s", argv[0]); ret = krb5_principal_set_comp_string(context, server, 1, hname); if (ret) krb5_err(context, 1, ret, "krb5_principal_set_comp_string %s", argv[0]); krb5_free_principal(context, server2); } else { size_t i; /* * In this case the arguments are principal name components. * * The service and hostname components can be defaulted by passing * empty strings. */ sname = argv[0]; if (*sname == '\0') sname = NULL; hname = argv[1]; if (hname == NULL || *hname == '\0') hname = NULL; ret = krb5_sname_to_principal(context, hname, sname, KRB5_NT_SRV_HST, &server); if (ret) krb5_err(context, 1, ret, "krb5_sname_to_principal"); for (i = 2; i < argc; i++) { ret = krb5_principal_set_comp_string(context, server, i, argv[i]); if (ret) krb5_err(context, 1, ret, "krb5_principal_set_comp_string"); } } } else if (argc == 1) { ret = krb5_parse_name(context, argv[0], &server); if (ret) krb5_err(context, 1, ret, "krb5_parse_name %s", argv[0]); } else { usage(1); } if (nametype != KRB5_NT_UNKNOWN) server->name.name_type = (NAME_TYPE)nametype; ret = krb5_get_creds(context, opt, cache, server, &out); if (ret) krb5_err(context, 1, ret, "krb5_get_creds"); if (out_cache_str) { krb5_ccache id; ret = krb5_cc_resolve(context, out_cache_str, &id); if(ret) krb5_err(context, 1, ret, "krb5_cc_resolve"); ret = krb5_cc_initialize(context, id, out->client); if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_store_cred(context, id, out); if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); krb5_cc_close(context, id); } krb5_free_creds(context, out); krb5_free_principal(context, server); krb5_get_creds_opt_free(context, opt); krb5_cc_close (context, cache); krb5_free_context (context); return 0; }
static krb5_error_code KRB5_CALLCONV scc_store_cred(krb5_context context, krb5_ccache id, krb5_creds *creds) { sqlite_uint64 credid; krb5_scache *s = SCACHE(id); krb5_error_code ret; krb5_data data; ret = make_database(context, s); if (ret) return ret; ret = encode_creds(context, creds, &data); if (ret) return ret; sqlite3_bind_int(s->icred, 1, s->cid); { krb5_enctype etype = 0; int kvno = 0; Ticket t; size_t len; ret = decode_Ticket(creds->ticket.data, creds->ticket.length, &t, &len); if (ret == 0) { if(t.enc_part.kvno) kvno = *t.enc_part.kvno; etype = t.enc_part.etype; free_Ticket(&t); } sqlite3_bind_int(s->icred, 2, kvno); sqlite3_bind_int(s->icred, 3, etype); } sqlite3_bind_blob(s->icred, 4, data.data, data.length, free_data); sqlite3_bind_int(s->icred, 5, time(NULL)); ret = exec_stmt(context, s->db, "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO); if (ret) return ret; do { ret = sqlite3_step(s->icred); } while (ret == SQLITE_ROW); sqlite3_reset(s->icred); if (ret != SQLITE_DONE) { ret = KRB5_CC_IO; krb5_set_error_message(context, ret, N_("Failed to add credential: %s", ""), sqlite3_errmsg(s->db)); goto rollback; } credid = sqlite3_last_insert_rowid(s->db); { bind_principal(context, s->db, s->iprincipal, 1, creds->server); sqlite3_bind_int(s->iprincipal, 2, 1); sqlite3_bind_int(s->iprincipal, 3, credid); do { ret = sqlite3_step(s->iprincipal); } while (ret == SQLITE_ROW); sqlite3_reset(s->iprincipal); if (ret != SQLITE_DONE) { ret = KRB5_CC_IO; krb5_set_error_message(context, ret, N_("Failed to add principal: %s", ""), sqlite3_errmsg(s->db)); goto rollback; } } { bind_principal(context, s->db, s->iprincipal, 1, creds->client); sqlite3_bind_int(s->iprincipal, 2, 0); sqlite3_bind_int(s->iprincipal, 3, credid); do { ret = sqlite3_step(s->iprincipal); } while (ret == SQLITE_ROW); sqlite3_reset(s->iprincipal); if (ret != SQLITE_DONE) { ret = KRB5_CC_IO; krb5_set_error_message(context, ret, N_("Failed to add principal: %s", ""), sqlite3_errmsg(s->db)); goto rollback; } } ret = exec_stmt(context, s->db, "COMMIT", KRB5_CC_IO); if (ret) return ret; return 0; rollback: exec_stmt(context, s->db, "ROLLBACK", 0); return ret; }
krb5_error_code _krb5_mk_req_internal(krb5_context context, krb5_auth_context *auth_context, const krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_data *outbuf, krb5_key_usage checksum_usage, krb5_key_usage encrypt_usage) { krb5_error_code ret; krb5_data authenticator; Checksum c; Checksum *c_opt; krb5_auth_context ac; if(auth_context) { if(*auth_context == NULL) ret = krb5_auth_con_init(context, auth_context); else ret = 0; ac = *auth_context; } else ret = krb5_auth_con_init(context, &ac); if(ret) return ret; if(ac->local_subkey == NULL && (ap_req_options & AP_OPTS_USE_SUBKEY)) { ret = krb5_auth_con_generatelocalsubkey(context, ac, &in_creds->session); if(ret) goto out; } #if 0 { /* This is somewhat bogus since we're possibly overwriting a value specified by the user, but it's the easiest way to make the code use a compatible enctype */ Ticket ticket; krb5_keytype ticket_keytype; ret = decode_Ticket(in_creds->ticket.data, in_creds->ticket.length, &ticket, NULL); krb5_enctype_to_keytype (context, ticket.enc_part.etype, &ticket_keytype); if (ticket_keytype == in_creds->session.keytype) krb5_auth_setenctype(context, ac, ticket.enc_part.etype); free_Ticket(&ticket); } #endif krb5_free_keyblock(context, ac->keyblock); ret = krb5_copy_keyblock(context, &in_creds->session, &ac->keyblock); if (ret) goto out; /* it's unclear what type of checksum we can use. try the best one, except: * a) if it's configured differently for the current realm, or * b) if the session key is des-cbc-crc */ if (in_data) { if(ac->keyblock->keytype == ETYPE_DES_CBC_CRC) { /* this is to make DCE secd (and older MIT kdcs?) happy */ ret = krb5_create_checksum(context, NULL, 0, CKSUMTYPE_RSA_MD4, in_data->data, in_data->length, &c); } else if(ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5 || ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5_56) { /* this is to make MS kdc happy */ ret = krb5_create_checksum(context, NULL, 0, CKSUMTYPE_RSA_MD5, in_data->data, in_data->length, &c); } else { krb5_crypto crypto; ret = krb5_crypto_init(context, ac->keyblock, 0, &crypto); if (ret) goto out; ret = krb5_create_checksum(context, crypto, checksum_usage, 0, in_data->data, in_data->length, &c); krb5_crypto_destroy(context, crypto); } c_opt = &c; } else { c_opt = NULL; } if (ret) goto out; ret = krb5_build_authenticator (context, ac, ac->keyblock->keytype, in_creds, c_opt, NULL, &authenticator, encrypt_usage); if (c_opt) free_Checksum (c_opt); if (ret) goto out; ret = krb5_build_ap_req (context, ac->keyblock->keytype, in_creds, ap_req_options, authenticator, outbuf); out: if(auth_context == NULL) krb5_auth_con_free(context, ac); return ret; }
static void print_cred_verbose(krb5_context context, krb5_creds *cred) { int j; char *str; krb5_error_code ret; krb5_timestamp sec; krb5_timeofday (context, &sec); ret = krb5_unparse_name(context, cred->server, &str); if(ret) exit(1); printf(N_("Server: %s\n", ""), str); free (str); ret = krb5_unparse_name(context, cred->client, &str); if(ret) exit(1); printf(N_("Client: %s\n", ""), str); free (str); { Ticket t; size_t len; char *s; decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len); ret = krb5_enctype_to_string(context, t.enc_part.etype, &s); printf(N_("Ticket etype: ", "")); if (ret == 0) { printf("%s", s); free(s); } else { printf(N_("unknown-enctype(%d)", ""), t.enc_part.etype); } if(t.enc_part.kvno) printf(N_(", kvno %d", ""), *t.enc_part.kvno); printf("\n"); if(cred->session.keytype != t.enc_part.etype) { ret = krb5_enctype_to_string(context, cred->session.keytype, &str); if(ret) krb5_warn(context, ret, "session keytype"); else { printf(N_("Session key: %s\n", "enctype"), str); free(str); } } free_Ticket(&t); printf(N_("Ticket length: %lu\n", ""), (unsigned long)cred->ticket.length); } printf(N_("Auth time: %s\n", ""), printable_time_long(cred->times.authtime)); if(cred->times.authtime != cred->times.starttime) printf(N_("Start time: %s\n", ""), printable_time_long(cred->times.starttime)); printf(N_("End time: %s", ""), printable_time_long(cred->times.endtime)); if(sec > cred->times.endtime) printf(N_(" (expired)", "")); printf("\n"); if(cred->flags.b.renewable) printf(N_("Renew till: %s\n", ""), printable_time_long(cred->times.renew_till)); { char flags[1024]; unparse_flags(TicketFlags2int(cred->flags.b), asn1_TicketFlags_units(), flags, sizeof(flags)); printf(N_("Ticket flags: %s\n", ""), flags); } printf(N_("Addresses: ", "")); if (cred->addresses.len != 0) { for(j = 0; j < cred->addresses.len; j++){ char buf[128]; size_t len; if(j) printf(", "); ret = krb5_print_address(&cred->addresses.val[j], buf, sizeof(buf), &len); if(ret == 0) printf("%s", buf); } } else { printf(N_("addressless", "")); } printf("\n\n"); }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_ccache src_cc = NULL; krb5_ccache dst_cc = NULL; krb5_cc_cursor cursor; krb5_principal me = NULL; krb5_creds cred; const char *during; Ticket t; size_t len; int make_kvno_absent = 0; int opt; memset(&cred, 0, sizeof (cred)); during = "init_context"; ret = krb5_init_context(&context); if (ret) goto err; while ((opt = getopt(argc, argv, "c:n")) != -1) { switch (opt) { case 'c': during = "cc_resolve of source ccache"; ret = krb5_cc_resolve(context, optarg, &src_cc); if (ret) goto err; break; case 'n': make_kvno_absent++; break; case 'h': default: fprintf(stderr, "Usage: %s [-n] [-c ccache]\n" "\tThis utility edits a ccache, setting all ticket\n" "\tenc_part kvnos to zero or absent (if -n is set).\n", argv[0]); return 1; } } if (!src_cc) { during = "cc_default"; ret = krb5_cc_default(context, &src_cc); if (ret) goto err; } during = "cc_get_principal"; ret = krb5_cc_get_principal(context, src_cc, &me); if (ret) goto err; if (optind != argc) { fprintf(stderr, "Usage: %s [-n] [-c ccache]\n" "\tThis utility edits a ccache, setting all ticket\n" "\tenc_part kvnos to zero or absent (if -n is set).\n", argv[0]); return 1; } during = "cc_new_unique of temporary ccache"; ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, src_cc), NULL, &dst_cc); during = "cc_initialize of temporary ccache"; ret = krb5_cc_initialize(context, dst_cc, me); if (ret) goto err; during = "cc_start_seq_get"; ret = krb5_cc_start_seq_get(context, src_cc, &cursor); if (ret) goto err; while ((ret = krb5_cc_next_cred(context, src_cc, &cursor, &cred)) == 0) { krb5_data data; during = "decode_Ticket"; memset(&t, 0, sizeof (t)); ret = decode_Ticket(cred.ticket.data, cred.ticket.length, &t, &len); if (ret == ASN1_MISSING_FIELD) continue; if (ret) goto err; if (t.enc_part.kvno) { *t.enc_part.kvno = 0; if (make_kvno_absent) { free(t.enc_part.kvno); t.enc_part.kvno = NULL; } /* * The new Ticket has to need less or same space as before, so * we reuse cred->icket.data. */ during = "encode_Ticket"; ASN1_MALLOC_ENCODE(Ticket, data.data, data.length, &t, &len, ret); if (ret) { free_Ticket(&t); goto err; } krb5_data_free(&cred.ticket); cred.ticket = data; } free_Ticket(&t); during = "cc_store_cred"; ret = krb5_cc_store_cred(context, dst_cc, &cred); if (ret) goto err; krb5_free_cred_contents(context, &cred); memset(&cred, 0, sizeof (cred)); } during = "cc_next_cred"; if (ret != KRB5_CC_END) goto err; during = "cc_end_seq_get"; ret = krb5_cc_end_seq_get(context, src_cc, &cursor); if (ret) goto err; during = "cc_move"; ret = krb5_cc_move(context, dst_cc, src_cc); if (ret) goto err; dst_cc = NULL; during = "cc_switch"; ret = krb5_cc_switch(context, src_cc); if (ret) goto err; err: (void) krb5_free_principal(context, me); if (src_cc) (void) krb5_cc_close(context, src_cc); if (dst_cc) (void) krb5_cc_destroy(context, dst_cc); if (ret) { fprintf(stderr, "Failed while doing %s (%d)\n", during, ret); ret = 1; } return (ret); }
static void do_v5_kvno (int count, char *names[], char * ccache_name, char *etype_str, char *keytab_name, char *sname) { krb5_error_code ret; krb5_context context = 0; int i, errors; krb5_enctype etype; krb5_ccache ccache; krb5_principal me; krb5_creds in_creds, *out_creds = NULL; Ticket ticket; size_t len; char *princ = NULL; krb5_keytab keytab = NULL; ret = krb5_init_context(&context); if (ret) errx(1, "krb5_init_context failed: %d", ret); if (etype_str) { ret = krb5_string_to_enctype(context, etype_str, &etype); if (ret) krb5_err(context, 1, ret, "Failed to convert encryption type %s", etype_str); } else { etype = 0; } if (ccache_name) ret = krb5_cc_resolve(context, ccache_name, &ccache); else ret = krb5_cc_default(context, &ccache); if (ret) krb5_err(context, 1, ret, "Failed to open credentials cache %s", (ccache_name) ? ccache_name : "(Default)"); if (keytab_name) { ret = krb5_kt_resolve(context, keytab_name, &keytab); if (ret) krb5_err(context, 1, ret, "Can't resolve keytab %s", keytab_name); } ret = krb5_cc_get_principal(context, ccache, &me); if (ret) krb5_err(context, 1, ret, "krb5_cc_get_principal"); errors = 0; for (i = 0; i < count; i++) { memset(&in_creds, 0, sizeof(in_creds)); memset(&ticket, 0, sizeof(ticket)); in_creds.client = me; if (sname != NULL) { ret = krb5_sname_to_principal(context, names[i], sname, KRB5_NT_SRV_HST, &in_creds.server); } else { ret = krb5_parse_name(context, names[i], &in_creds.server); } if (ret) { if (!quiet_flag) krb5_warn(context, ret, "Couldn't parse principal name %s", names[i]); errors++; continue; } ret = krb5_unparse_name(context, in_creds.server, &princ); if (ret) { krb5_warn(context, ret, "Couldn't format parsed principal name for '%s'", names[i]); errors++; goto next; } in_creds.session.keytype = etype; ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds); if (ret) { krb5_warn(context, ret, "Couldn't get credentials for %s", princ); errors++; goto next; } ret = decode_Ticket(out_creds->ticket.data, out_creds->ticket.length, &ticket, &len); if (ret) { krb5_err(context, 1, ret, "Can't decode ticket for %s", princ); errors++; goto next; continue; } if (keytab) { krb5_keytab_entry kte; krb5_crypto crypto; krb5_data dec_data; EncTicketPart decr_part; ret = krb5_kt_get_entry(context, keytab, in_creds.server, (ticket.enc_part.kvno != NULL)? *ticket.enc_part.kvno : 0, ticket.enc_part.etype, &kte); if (ret) { krb5_warn(context, ret, "Can't decrypt ticket for %s", princ); if (!quiet_flag) printf("%s: kvno = %d, keytab entry invalid", princ, (ticket.enc_part.kvno != NULL)? *ticket.enc_part.kvno : 0); errors ++; goto next; } ret = krb5_crypto_init(context, &kte.keyblock, 0, &crypto); if (ret) { krb5_warn(context, ret, "krb5_crypto_init"); errors ++; krb5_kt_free_entry(context, &kte); goto next; } ret = krb5_decrypt_EncryptedData (context, crypto, KRB5_KU_TICKET, &ticket.enc_part, &dec_data); krb5_crypto_destroy(context, crypto); krb5_kt_free_entry(context, &kte); if (ret) { krb5_warn(context, ret, "krb5_decrypt_EncryptedData"); errors ++; goto next; } ret = decode_EncTicketPart(dec_data.data, dec_data.length, &decr_part, &len); krb5_data_free(&dec_data); if (ret) { krb5_warn(context, ret, "decode_EncTicketPart"); errors ++; goto next; } if (!quiet_flag) printf("%s: kvno = %d, keytab entry valid\n", princ, (ticket.enc_part.kvno != NULL)? *ticket.enc_part.kvno : 0); free_EncTicketPart(&decr_part); } else { if (!quiet_flag) printf("%s: kvno = %d\n", princ, (ticket.enc_part.kvno != NULL)? *ticket.enc_part.kvno : 0); } next: if (out_creds) { krb5_free_creds(context, out_creds); out_creds = NULL; } if (princ) { krb5_free_unparsed_name(context, princ); princ = NULL; } krb5_free_principal(context, in_creds.server); free_Ticket(&ticket); } if (keytab) krb5_kt_close(context, keytab); krb5_free_principal(context, me); krb5_cc_close(context, ccache); krb5_free_context(context); if (errors) exit(1); exit(0); }
static void test_dh2key(krb5_context context, int i, struct testcase *c) { krb5_error_code ret; krb5_keyblock key; krb5_principal client, server; Ticket ticket; AlgorithmIdentifier ai; size_t size; memset(&ticket, 0, sizeof(&ticket)); ai.algorithm = *c->oid; ai.parameters = NULL; ret = decode_Ticket(c->ticket.data, c->ticket.length, &ticket, &size); if (ret) krb5_errx(context, 1, "decode ticket: %d", ret); ret = krb5_parse_name(context, c->client, &client); if (ret) krb5_err(context, 1, ret, "parse_name: %s", c->client); ret = krb5_parse_name(context, c->server, &server); if (ret) krb5_err(context, 1, ret, "parse_name: %s", c->server); if (verbose_flag) { char *str; hex_encode(c->Z.data, c->Z.length, &str); printf("Z: %s\n", str); free(str); printf("client: %s\n", c->client); printf("server: %s\n", c->server); printf("enctype: %d\n", (int)c->enctype); hex_encode(c->as_req.data, c->as_req.length, &str); printf("as-req: %s\n", str); free(str); hex_encode(c->pk_as_rep.data, c->pk_as_rep.length, &str); printf("pk-as-rep: %s\n", str); free(str); hex_encode(c->ticket.data, c->ticket.length, &str); printf("ticket: %s\n", str); free(str); } ret = _krb5_pk_kdf(context, &ai, c->Z.data, c->Z.length, client, server, c->enctype, &c->as_req, &c->pk_as_rep, &ticket, &key); krb5_free_principal(context, client); krb5_free_principal(context, server); if (ret) krb5_err(context, 1, ret, "_krb5_pk_kdf: %d", i); if (verbose_flag) { char *str; hex_encode(key.keyvalue.data, key.keyvalue.length, &str); printf("key: %s\n", str); free(str); } if (key.keyvalue.length != c->key.length || memcmp(key.keyvalue.data, c->key.data, c->key.length) != 0) krb5_errx(context, 1, "resulting key wrong: %d", i); krb5_free_keyblock_contents(context, &key); free_Ticket(&ticket); }
krb5_error_code KRB5_LIB_FUNCTION krb5_get_forwarded_creds (krb5_context context, krb5_auth_context auth_context, krb5_ccache ccache, krb5_flags flags, const char *hostname, krb5_creds *in_creds, krb5_data *out_data) { krb5_error_code ret; krb5_creds *out_creds; krb5_addresses addrs, *paddrs; KRB_CRED cred; KrbCredInfo *krb_cred_info; EncKrbCredPart enc_krb_cred_part; size_t len; unsigned char *buf; size_t buf_size; krb5_kdc_flags kdc_flags; krb5_crypto crypto; struct addrinfo *ai; int save_errno; krb5_creds *ticket; char *realm; if (in_creds->client && in_creds->client->realm) realm = in_creds->client->realm; else realm = in_creds->server->realm; addrs.len = 0; addrs.val = NULL; paddrs = &addrs; /* * If tickets are address-less, forward address-less tickets. */ ret = _krb5_get_krbtgt (context, ccache, realm, &ticket); if(ret == 0) { if (ticket->addresses.len == 0) paddrs = NULL; krb5_free_creds (context, ticket); } if (paddrs != NULL) { ret = getaddrinfo (hostname, NULL, NULL, &ai); if (ret) { save_errno = errno; krb5_set_error_string(context, "resolving %s: %s", hostname, gai_strerror(ret)); return krb5_eai_to_heim_errno(ret, save_errno); } ret = add_addrs (context, &addrs, ai); freeaddrinfo (ai); if (ret) return ret; } kdc_flags.b = int2KDCOptions(flags); ret = krb5_get_kdc_cred (context, ccache, kdc_flags, paddrs, NULL, in_creds, &out_creds); krb5_free_addresses (context, &addrs); if (ret) { return ret; } memset (&cred, 0, sizeof(cred)); cred.pvno = 5; cred.msg_type = krb_cred; ALLOC_SEQ(&cred.tickets, 1); if (cred.tickets.val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out2; } ret = decode_Ticket(out_creds->ticket.data, out_creds->ticket.length, cred.tickets.val, &len); if (ret) goto out3; memset (&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part)); ALLOC_SEQ(&enc_krb_cred_part.ticket_info, 1); if (enc_krb_cred_part.ticket_info.val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_timestamp sec; int32_t usec; krb5_us_timeofday (context, &sec, &usec); ALLOC(enc_krb_cred_part.timestamp, 1); if (enc_krb_cred_part.timestamp == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } *enc_krb_cred_part.timestamp = sec; ALLOC(enc_krb_cred_part.usec, 1); if (enc_krb_cred_part.usec == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } *enc_krb_cred_part.usec = usec; } else { enc_krb_cred_part.timestamp = NULL; enc_krb_cred_part.usec = NULL; } if (auth_context->local_address && auth_context->local_port) { krb5_boolean noaddr; krb5_const_realm realm; realm = krb5_principal_get_realm(context, out_creds->server); krb5_appdefault_boolean(context, NULL, realm, "no-addresses", paddrs == NULL, &noaddr); if (!noaddr) { ret = krb5_make_addrport (context, &enc_krb_cred_part.s_address, auth_context->local_address, auth_context->local_port); if (ret) goto out4; } } if (auth_context->remote_address) { if (auth_context->remote_port) { krb5_boolean noaddr; krb5_const_realm realm; realm = krb5_principal_get_realm(context, out_creds->server); /* Is this correct, and should we use the paddrs == NULL trick here as well? Having an address-less ticket may indicate that we don't know our own global address, but it does not necessary mean that we don't know the server's. */ krb5_appdefault_boolean(context, NULL, realm, "no-addresses", FALSE, &noaddr); if (!noaddr) { ret = krb5_make_addrport (context, &enc_krb_cred_part.r_address, auth_context->remote_address, auth_context->remote_port); if (ret) goto out4; } } else { ALLOC(enc_krb_cred_part.r_address, 1); if (enc_krb_cred_part.r_address == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } ret = krb5_copy_address (context, auth_context->remote_address, enc_krb_cred_part.r_address); if (ret) goto out4; } } /* fill ticket_info.val[0] */ enc_krb_cred_part.ticket_info.len = 1; krb_cred_info = enc_krb_cred_part.ticket_info.val; copy_EncryptionKey (&out_creds->session, &krb_cred_info->key); ALLOC(krb_cred_info->prealm, 1); copy_Realm (&out_creds->client->realm, krb_cred_info->prealm); ALLOC(krb_cred_info->pname, 1); copy_PrincipalName(&out_creds->client->name, krb_cred_info->pname); ALLOC(krb_cred_info->flags, 1); *krb_cred_info->flags = out_creds->flags.b; ALLOC(krb_cred_info->authtime, 1); *krb_cred_info->authtime = out_creds->times.authtime; ALLOC(krb_cred_info->starttime, 1); *krb_cred_info->starttime = out_creds->times.starttime; ALLOC(krb_cred_info->endtime, 1); *krb_cred_info->endtime = out_creds->times.endtime; ALLOC(krb_cred_info->renew_till, 1); *krb_cred_info->renew_till = out_creds->times.renew_till; ALLOC(krb_cred_info->srealm, 1); copy_Realm (&out_creds->server->realm, krb_cred_info->srealm); ALLOC(krb_cred_info->sname, 1); copy_PrincipalName (&out_creds->server->name, krb_cred_info->sname); ALLOC(krb_cred_info->caddr, 1); copy_HostAddresses (&out_creds->addresses, krb_cred_info->caddr); krb5_free_creds (context, out_creds); /* encode EncKrbCredPart */ ASN1_MALLOC_ENCODE(EncKrbCredPart, buf, buf_size, &enc_krb_cred_part, &len, ret); free_EncKrbCredPart (&enc_krb_cred_part); if (ret) { free_KRB_CRED(&cred); return ret; } if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); if (auth_context->flags & KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED) { cred.enc_part.etype = ENCTYPE_NULL; cred.enc_part.kvno = NULL; cred.enc_part.cipher.data = buf; cred.enc_part.cipher.length = buf_size; } else { krb5_keyblock *key; if (auth_context->local_subkey) key = auth_context->local_subkey; else if (auth_context->remote_subkey) key = auth_context->remote_subkey; else key = auth_context->keyblock; ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) { free(buf); free_KRB_CRED(&cred); return ret; } ret = krb5_encrypt_EncryptedData (context, crypto, KRB5_KU_KRB_CRED, buf, len, 0, &cred.enc_part); free(buf); krb5_crypto_destroy(context, crypto); if (ret) { free_KRB_CRED(&cred); return ret; } } ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &cred, &len, ret); free_KRB_CRED (&cred); if (ret) return ret; if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); out_data->length = len; out_data->data = buf; return 0; out4: free_EncKrbCredPart(&enc_krb_cred_part); out3: free_KRB_CRED(&cred); out2: krb5_free_creds (context, out_creds); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_get_forwarded_creds (krb5_context context, krb5_auth_context auth_context, krb5_ccache ccache, krb5_flags flags, const char *hostname, krb5_creds *in_creds, krb5_data *out_data) { krb5_error_code ret; krb5_creds *out_creds; krb5_addresses addrs, *paddrs; KRB_CRED cred; KrbCredInfo *krb_cred_info; EncKrbCredPart enc_krb_cred_part; size_t len; unsigned char *buf; size_t buf_size; krb5_kdc_flags kdc_flags; krb5_crypto crypto; struct addrinfo *ai; krb5_creds *ticket; paddrs = NULL; addrs.len = 0; addrs.val = NULL; ret = krb5_get_credentials(context, 0, ccache, in_creds, &ticket); if(ret == 0) { if (ticket->addresses.len) paddrs = &addrs; krb5_free_creds (context, ticket); } else { krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, krb5_principal_get_realm(context, in_creds->client), "no-addresses", KRB5_ADDRESSLESS_DEFAULT, &noaddr); if (!noaddr) paddrs = &addrs; } /* * If tickets have addresses, get the address of the remote host. */ if (paddrs != NULL) { ret = getaddrinfo (hostname, NULL, NULL, &ai); if (ret) { krb5_error_code ret2 = krb5_eai_to_heim_errno(ret, errno); krb5_set_error_message(context, ret2, N_("resolving host %s failed: %s", "hostname, error"), hostname, gai_strerror(ret)); return ret2; } ret = add_addrs (context, &addrs, ai); freeaddrinfo (ai); if (ret) return ret; } kdc_flags.b = int2KDCOptions(flags); ret = krb5_get_kdc_cred (context, ccache, kdc_flags, paddrs, NULL, in_creds, &out_creds); krb5_free_addresses (context, &addrs); if (ret) return ret; memset (&cred, 0, sizeof(cred)); cred.pvno = 5; cred.msg_type = krb_cred; ALLOC_SEQ(&cred.tickets, 1); if (cred.tickets.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out2; } ret = decode_Ticket(out_creds->ticket.data, out_creds->ticket.length, cred.tickets.val, &len); if (ret) goto out3; memset (&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part)); ALLOC_SEQ(&enc_krb_cred_part.ticket_info, 1); if (enc_krb_cred_part.ticket_info.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_timestamp sec; int32_t usec; krb5_us_timeofday (context, &sec, &usec); ALLOC(enc_krb_cred_part.timestamp, 1); if (enc_krb_cred_part.timestamp == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } *enc_krb_cred_part.timestamp = sec; ALLOC(enc_krb_cred_part.usec, 1); if (enc_krb_cred_part.usec == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } *enc_krb_cred_part.usec = usec; } else { enc_krb_cred_part.timestamp = NULL; enc_krb_cred_part.usec = NULL; } if (auth_context->local_address && auth_context->local_port && paddrs) { ret = krb5_make_addrport (context, &enc_krb_cred_part.s_address, auth_context->local_address, auth_context->local_port); if (ret) goto out4; } if (auth_context->remote_address) { if (auth_context->remote_port) { krb5_boolean noaddr; krb5_const_realm srealm; srealm = krb5_principal_get_realm(context, out_creds->server); /* Is this correct, and should we use the paddrs == NULL trick here as well? Having an address-less ticket may indicate that we don't know our own global address, but it does not necessary mean that we don't know the server's. */ krb5_appdefault_boolean(context, NULL, srealm, "no-addresses", FALSE, &noaddr); if (!noaddr) { ret = krb5_make_addrport (context, &enc_krb_cred_part.r_address, auth_context->remote_address, auth_context->remote_port); if (ret) goto out4; } } else { ALLOC(enc_krb_cred_part.r_address, 1); if (enc_krb_cred_part.r_address == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } ret = krb5_copy_address (context, auth_context->remote_address, enc_krb_cred_part.r_address); if (ret) goto out4; } } /* fill ticket_info.val[0] */ enc_krb_cred_part.ticket_info.len = 1; krb_cred_info = enc_krb_cred_part.ticket_info.val; copy_EncryptionKey (&out_creds->session, &krb_cred_info->key); ALLOC(krb_cred_info->prealm, 1); copy_Realm (&out_creds->client->realm, krb_cred_info->prealm); ALLOC(krb_cred_info->pname, 1); copy_PrincipalName(&out_creds->client->name, krb_cred_info->pname); ALLOC(krb_cred_info->flags, 1); *krb_cred_info->flags = out_creds->flags.b; ALLOC(krb_cred_info->authtime, 1); *krb_cred_info->authtime = out_creds->times.authtime; ALLOC(krb_cred_info->starttime, 1); *krb_cred_info->starttime = out_creds->times.starttime; ALLOC(krb_cred_info->endtime, 1); *krb_cred_info->endtime = out_creds->times.endtime; ALLOC(krb_cred_info->renew_till, 1); *krb_cred_info->renew_till = out_creds->times.renew_till; ALLOC(krb_cred_info->srealm, 1); copy_Realm (&out_creds->server->realm, krb_cred_info->srealm); ALLOC(krb_cred_info->sname, 1); copy_PrincipalName (&out_creds->server->name, krb_cred_info->sname); ALLOC(krb_cred_info->caddr, 1); copy_HostAddresses (&out_creds->addresses, krb_cred_info->caddr); krb5_free_creds (context, out_creds); /* encode EncKrbCredPart */ ASN1_MALLOC_ENCODE(EncKrbCredPart, buf, buf_size, &enc_krb_cred_part, &len, ret); free_EncKrbCredPart (&enc_krb_cred_part); if (ret) { free_KRB_CRED(&cred); return ret; } if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /** * Some older of the MIT gssapi library used clear-text tickets * (warped inside AP-REQ encryption), use the krb5_auth_context * flag KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED to support those * tickets. The session key is used otherwise to encrypt the * forwarded ticket. */ if (auth_context->flags & KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED) { cred.enc_part.etype = KRB5_ENCTYPE_NULL; cred.enc_part.kvno = NULL; cred.enc_part.cipher.data = buf; cred.enc_part.cipher.length = buf_size; } else { /* * Here older versions then 0.7.2 of Heimdal used the local or * remote subkey. That is wrong, the session key should be * used. Heimdal 0.7.2 and newer have code to try both in the * receiving end. */ ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto); if (ret) { free(buf); free_KRB_CRED(&cred); return ret; } ret = krb5_encrypt_EncryptedData (context, crypto, KRB5_KU_KRB_CRED, buf, len, 0, &cred.enc_part); free(buf); krb5_crypto_destroy(context, crypto); if (ret) { free_KRB_CRED(&cred); return ret; } } ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &cred, &len, ret); free_KRB_CRED (&cred); if (ret) return ret; if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); out_data->length = len; out_data->data = buf; return 0; out4: free_EncKrbCredPart(&enc_krb_cred_part); out3: free_KRB_CRED(&cred); out2: krb5_free_creds (context, out_creds); return ret; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_ccache cache; krb5_creds *out; int optidx = 0; krb5_get_creds_opt opt; krb5_principal server; krb5_principal impersonate = NULL; setprogname (argv[0]); ret = krb5_init_context (&context); if (ret) errx(1, "krb5_init_context failed: %d", ret); if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage (0); if(version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; if (argc != 1) usage (1); if(cache_str) { ret = krb5_cc_resolve(context, cache_str, &cache); if (ret) krb5_err (context, 1, ret, "%s", cache_str); } else { ret = krb5_cc_default (context, &cache); if (ret) krb5_err (context, 1, ret, "krb5_cc_resolve"); } ret = krb5_get_creds_opt_alloc(context, &opt); if (ret) krb5_err (context, 1, ret, "krb5_get_creds_opt_alloc"); if (etype_str) { krb5_enctype enctype; ret = krb5_string_to_enctype(context, etype_str, &enctype); if (ret) krb5_errx (context, 1, N_("unrecognized enctype: %s", ""), etype_str); krb5_get_creds_opt_set_enctype(context, opt, enctype); } if (impersonate_str) { ret = krb5_parse_name(context, impersonate_str, &impersonate); if (ret) krb5_err (context, 1, ret, "krb5_parse_name %s", impersonate_str); krb5_get_creds_opt_set_impersonate(context, opt, impersonate); krb5_get_creds_opt_add_options(context, opt, KRB5_GC_NO_STORE); } if (out_cache_str) krb5_get_creds_opt_add_options(context, opt, KRB5_GC_NO_STORE); if (forwardable_flag) krb5_get_creds_opt_add_options(context, opt, KRB5_GC_FORWARDABLE); if (!transit_flag) krb5_get_creds_opt_add_options(context, opt, KRB5_GC_NO_TRANSIT_CHECK); if (canonicalize_flag) krb5_get_creds_opt_add_options(context, opt, KRB5_GC_CANONICALIZE); if (delegation_cred_str) { krb5_ccache id; krb5_creds c, mc; Ticket ticket; krb5_cc_clear_mcred(&mc); ret = krb5_cc_get_principal(context, cache, &mc.server); if (ret) krb5_err (context, 1, ret, "krb5_cc_get_principal"); ret = krb5_cc_resolve(context, delegation_cred_str, &id); if(ret) krb5_err (context, 1, ret, "krb5_cc_resolve"); ret = krb5_cc_retrieve_cred(context, id, 0, &mc, &c); if(ret) krb5_err (context, 1, ret, "krb5_cc_retrieve_cred"); ret = decode_Ticket(c.ticket.data, c.ticket.length, &ticket, NULL); if (ret) { krb5_clear_error_message(context); krb5_err (context, 1, ret, "decode_Ticket"); } krb5_free_cred_contents(context, &c); ret = krb5_get_creds_opt_set_ticket(context, opt, &ticket); if(ret) krb5_err (context, 1, ret, "krb5_get_creds_opt_set_ticket"); free_Ticket(&ticket); krb5_cc_close (context, id); krb5_free_principal(context, mc.server); krb5_get_creds_opt_add_options(context, opt, KRB5_GC_CONSTRAINED_DELEGATION); } ret = krb5_parse_name(context, argv[0], &server); if (ret) krb5_err (context, 1, ret, "krb5_parse_name %s", argv[0]); if (nametype_str) { int32_t nametype; ret = krb5_parse_nametype(context, nametype_str, &nametype); if (ret) krb5_err(context, 1, ret, "krb5_parse_nametype"); server->name.name_type = (NAME_TYPE)nametype; } ret = krb5_get_creds(context, opt, cache, server, &out); if (ret) krb5_err (context, 1, ret, "krb5_get_creds"); if (out_cache_str) { krb5_ccache id; ret = krb5_cc_resolve(context, out_cache_str, &id); if(ret) krb5_err (context, 1, ret, "krb5_cc_resolve"); ret = krb5_cc_initialize(context, id, out->client); if(ret) krb5_err (context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_store_cred(context, id, out); if(ret) krb5_err (context, 1, ret, "krb5_cc_store_cred"); krb5_cc_close (context, id); } krb5_free_creds(context, out); krb5_free_principal(context, server); krb5_get_creds_opt_free(context, opt); krb5_cc_close (context, cache); krb5_free_context (context); return 0; }
static krb5_error_code get_cred_kdc_usage(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, krb5_addresses *addresses, krb5_creds *in_creds, krb5_creds *krbtgt, krb5_creds *out_creds, krb5_key_usage usage) { TGS_REQ req; krb5_data enc; krb5_data resp; krb5_kdc_rep rep; KRB_ERROR error; krb5_error_code ret; unsigned nonce; krb5_keyblock *subkey = NULL; size_t len; Ticket second_ticket; int send_to_kdc_flags = 0; krb5_data_zero(&resp); krb5_data_zero(&enc); krb5_generate_random_block(&nonce, sizeof(nonce)); nonce &= 0xffffffff; if(flags.b.enc_tkt_in_skey){ ret = decode_Ticket(in_creds->second_ticket.data, in_creds->second_ticket.length, &second_ticket, &len); if(ret) return ret; } ret = init_tgs_req (context, id, addresses, flags, flags.b.enc_tkt_in_skey ? &second_ticket : NULL, in_creds, krbtgt, nonce, &subkey, &req, usage); if(flags.b.enc_tkt_in_skey) free_Ticket(&second_ticket); if (ret) goto out; ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret); if (ret) goto out; if(enc.length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /* don't free addresses */ req.req_body.addresses = NULL; free_TGS_REQ(&req); /* * Send and receive */ again: ret = krb5_sendto_kdc_flags (context, &enc, &krbtgt->server->name.name_string.val[1], &resp, send_to_kdc_flags); if(ret) goto out; memset(&rep, 0, sizeof(rep)); if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0){ ret = krb5_copy_principal(context, in_creds->client, &out_creds->client); if(ret) goto out; ret = krb5_copy_principal(context, in_creds->server, &out_creds->server); if(ret) goto out; /* this should go someplace else */ out_creds->times.endtime = in_creds->times.endtime; ret = _krb5_extract_ticket(context, &rep, out_creds, &krbtgt->session, NULL, KRB5_KU_TGS_REP_ENC_PART_SESSION, &krbtgt->addresses, nonce, TRUE, flags.b.request_anonymous, decrypt_tkt_with_subkey, subkey); krb5_free_kdc_rep(context, &rep); } else if(krb5_rd_error(context, &resp, &error) == 0) { ret = krb5_error_from_rd_error(context, &error, in_creds); krb5_free_error_contents(context, &error); if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG && !(send_to_kdc_flags & KRB5_KRBHST_FLAGS_LARGE_MSG)) { send_to_kdc_flags |= KRB5_KRBHST_FLAGS_LARGE_MSG; krb5_data_free(&resp); goto again; } } else if(resp.data && ((char*)resp.data)[0] == 4) { ret = KRB5KRB_AP_ERR_V4_REPLY; krb5_clear_error_string(context); } else { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_clear_error_string(context); } out: krb5_data_free(&resp); krb5_data_free(&enc); if(subkey){ krb5_free_keyblock_contents(context, subkey); free(subkey); } return ret; }
static krb5_error_code get_cred_kdc(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, krb5_addresses *addresses, krb5_creds *in_creds, krb5_creds *krbtgt, krb5_principal impersonate_principal, Ticket *second_ticket, krb5_creds *out_creds) { TGS_REQ req; krb5_data enc; krb5_data resp; krb5_kdc_rep rep; KRB_ERROR error; krb5_error_code ret; unsigned nonce; krb5_keyblock *subkey = NULL; size_t len; Ticket second_ticket_data; METHOD_DATA padata; krb5_data_zero(&resp); krb5_data_zero(&enc); padata.val = NULL; padata.len = 0; krb5_generate_random_block(&nonce, sizeof(nonce)); nonce &= 0xffffffff; if(flags.b.enc_tkt_in_skey && second_ticket == NULL){ ret = decode_Ticket(in_creds->second_ticket.data, in_creds->second_ticket.length, &second_ticket_data, &len); if(ret) return ret; second_ticket = &second_ticket_data; } if (impersonate_principal) { krb5_crypto crypto; PA_S4U2Self self; krb5_data data; void *buf; size_t size; self.name = impersonate_principal->name; self.realm = impersonate_principal->realm; self.auth = estrdup("Kerberos"); ret = _krb5_s4u2self_to_checksumdata(context, &self, &data); if (ret) { free(self.auth); goto out; } ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto); if (ret) { free(self.auth); krb5_data_free(&data); goto out; } ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0, data.data, data.length, &self.cksum); krb5_crypto_destroy(context, crypto); krb5_data_free(&data); if (ret) { free(self.auth); goto out; } ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret); free(self.auth); free_Checksum(&self.cksum); if (ret) goto out; if (len != size) krb5_abortx(context, "internal asn1 error"); ret = krb5_padata_add(context, &padata, KRB5_PADATA_FOR_USER, buf, len); if (ret) goto out; } ret = init_tgs_req (context, id, addresses, flags, second_ticket, in_creds, krbtgt, nonce, &padata, &subkey, &req); if (ret) goto out; ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret); if (ret) goto out; if(enc.length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /* don't free addresses */ req.req_body.addresses = NULL; free_TGS_REQ(&req); /* * Send and receive */ { krb5_sendto_ctx stctx; ret = krb5_sendto_ctx_alloc(context, &stctx); if (ret) return ret; krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); ret = krb5_sendto_context (context, stctx, &enc, krbtgt->server->name.name_string.val[1], &resp); krb5_sendto_ctx_free(context, stctx); } if(ret) goto out; memset(&rep, 0, sizeof(rep)); if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0) { unsigned eflags = 0; ret = krb5_copy_principal(context, in_creds->client, &out_creds->client); if(ret) goto out2; ret = krb5_copy_principal(context, in_creds->server, &out_creds->server); if(ret) goto out2; /* this should go someplace else */ out_creds->times.endtime = in_creds->times.endtime; /* XXX should do better testing */ if (flags.b.constrained_delegation || impersonate_principal) eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; ret = _krb5_extract_ticket(context, &rep, out_creds, &krbtgt->session, NULL, 0, &krbtgt->addresses, nonce, eflags, decrypt_tkt_with_subkey, subkey); out2: krb5_free_kdc_rep(context, &rep); } else if(krb5_rd_error(context, &resp, &error) == 0) { ret = krb5_error_from_rd_error(context, &error, in_creds); krb5_free_error_contents(context, &error); } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) { ret = KRB5KRB_AP_ERR_V4_REPLY; krb5_clear_error_message(context); } else { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_clear_error_message(context); } out: if (second_ticket == &second_ticket_data) free_Ticket(&second_ticket_data); free_METHOD_DATA(&padata); krb5_data_free(&resp); krb5_data_free(&enc); if(subkey) krb5_free_keyblock(context, subkey); return ret; }
int decode_KRB_CRED(const unsigned char *p, size_t len, KRB_CRED *data, size_t *size) { size_t ret = 0, reallen; size_t l; int e; memset(data, 0, sizeof(*data)); reallen = 0; e = der_match_tag_and_length (p, len, ASN1_C_APPL, CONS, 22, &reallen, &l); FORW; { int dce_fix; if((dce_fix = fix_dce(reallen, &len)) < 0) return ASN1_BAD_FORMAT; e = der_match_tag_and_length (p, len, ASN1_C_UNIV, CONS, UT_Sequence,&reallen, &l); FORW; { int dce_fix; if((dce_fix = fix_dce(reallen, &len)) < 0) return ASN1_BAD_FORMAT; { size_t newlen, oldlen; e = der_match_tag (p, len, ASN1_C_CONTEXT, CONS, 0, &l); if (e) return e; else { p += l; len -= l; ret += l; e = der_get_length (p, len, &newlen, &l); FORW; { int dce_fix; oldlen = len; if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; e = decode_integer(p, len, &(data)->pvno, &l); FORW; if(dce_fix){ e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); FORW; }else len = oldlen - newlen; } } } { size_t newlen, oldlen; e = der_match_tag (p, len, ASN1_C_CONTEXT, CONS, 1, &l); if (e) return e; else { p += l; len -= l; ret += l; e = der_get_length (p, len, &newlen, &l); FORW; { int dce_fix; oldlen = len; if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; e = decode_MESSAGE_TYPE(p, len, &(data)->msg_type, &l); FORW; if(dce_fix){ e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); FORW; }else len = oldlen - newlen; } } } { size_t newlen, oldlen; e = der_match_tag (p, len, ASN1_C_CONTEXT, CONS, 2, &l); if (e) return e; else { p += l; len -= l; ret += l; e = der_get_length (p, len, &newlen, &l); FORW; { int dce_fix; oldlen = len; if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; e = der_match_tag_and_length (p, len, ASN1_C_UNIV, CONS, UT_Sequence,&reallen, &l); FORW; if(len < reallen) return ASN1_OVERRUN; len = reallen; { size_t origlen = len; int oldret = ret; ret = 0; (&(data)->tickets)->len = 0; (&(data)->tickets)->val = NULL; while(ret < origlen) { (&(data)->tickets)->len++; (&(data)->tickets)->val = realloc((&(data)->tickets)->val, sizeof(*((&(data)->tickets)->val)) * (&(data)->tickets)->len); e = decode_Ticket(p, len, &(&(data)->tickets)->val[(&(data)->tickets)->len-1], &l); FORW; len = origlen - ret; } ret += oldret; } if(dce_fix){ e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); FORW; }else len = oldlen - newlen; } } } { size_t newlen, oldlen; e = der_match_tag (p, len, ASN1_C_CONTEXT, CONS, 3, &l); if (e) return e; else { p += l; len -= l; ret += l; e = der_get_length (p, len, &newlen, &l); FORW; { int dce_fix; oldlen = len; if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; e = decode_EncryptedData(p, len, &(data)->enc_part, &l); FORW; if(dce_fix){ e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); FORW; }else len = oldlen - newlen; } } } if(dce_fix){ e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); FORW; } } if(dce_fix){ e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); FORW; } } if(size) *size = ret; return 0; fail: free_KRB_CRED(data); return e; }