static krb5_error_code krb5_get_credentials_val_renew_core(krb5_context context, krb5_flags options, krb5_ccache ccache, krb5_creds *in_creds, krb5_creds **out_creds, int which) { krb5_error_code retval; krb5_principal tmp; krb5_creds **tgts = 0; switch(which) { case INT_GC_VALIDATE: retval = krb5_get_cred_from_kdc_validate(context, ccache, in_creds, out_creds, &tgts); break; case INT_GC_RENEW: retval = krb5_get_cred_from_kdc_renew(context, ccache, in_creds, out_creds, &tgts); break; default: /* Should never happen */ retval = 255; break; } if (retval) return retval; if (tgts) krb5_free_tgt_creds(context, tgts); retval = krb5_cc_get_principal(context, ccache, &tmp); if (retval) return retval; retval = krb5_cc_initialize(context, ccache, tmp); if (retval) return retval; retval = krb5_cc_store_cred(context, ccache, *out_creds); return retval; }
int krb_renew_tgts( lList *joblist ) { krb5_error_code rc; static u_long32 next_time = 0; u_long32 now = sge_get_gmt(); lListElem *job; krb5_context context = krb_context(); krb5_timestamp time_now; krb_global_data_t *gsd = krb_gsd(); DENTER(TOP_LAYER, "krb_renew_tgts"); if ((now = sge_get_gmt())<next_time) { DEXIT; return 0; } if ((rc = krb5_timeofday(context, &time_now))) { ERROR((SGE_EVENT, MSG_KRB_KRB5TIMEOFDAYFAILEDX_S , error_message(rc))); DEXIT; return -1; } /* renew job TGT's */ for_each(job, joblist) { krb5_error_code rc; krb5_creds ** tgt_creds = NULL; krb5_data tgtbuf; const char *tgtstr = NULL; tgtbuf.length = 0; /* get TGT out of job entry */ if ((tgtstr = lGetString(job, JB_tgt))) { tgtbuf.data = krb_str2bin(tgtstr, NULL, &tgtbuf.length); if (tgtbuf.length) { /* decrypt the TGT using the daemon key */ if ((rc = krb_decrypt_tgt_creds(&tgtbuf, &tgt_creds))) { ERROR((SGE_EVENT, MSG_KRB_COULDNOTDECRYPTTGTFORJOBXY_DS, sge_u32c(lGetUlong(job, JB_job_number)), error_message(rc))); } if (rc == 0 && tgt_creds) { krb5_creds *tgt = *tgt_creds; /* * If TGT is renewable and TGT expiration time is not past * and is within the SGE renewal threshold and the TGT * renewal period is not past, then renew the TGT */ if (tgt->ticket_flags & KDC_OPT_RENEWABLE && tgt->times.endtime > time_now && tgt->times.renew_till > time_now && tgt->times.endtime < time_now + gsd->tgt_renew_threshold) { krb5_creds *new_creds[2]; krb5_creds creds; memset(new_creds, 0, sizeof(new_creds)); memset(&creds, 0 ,sizeof(creds)); /* renew the TGT */ if (((rc = krb5_copy_principal(context, (*tgt_creds)->server, &creds.server))) || ((rc = krb5_copy_principal(context, (*tgt_creds)->client, &creds.client))) || ((rc = krb5_get_cred_via_tkt(context, tgt, FLAGS2OPTS(tgt->ticket_flags)|KDC_OPT_RENEW, tgt->addresses, &creds, &new_creds[0])))) { ERROR((SGE_EVENT, MSG_KRB_COULDNOTRENEWTGTFORJOBXY_DS, sge_u32c(lGetUlong(job, JB_job_number)), error_message(rc))); } krb5_free_cred_contents(context, &creds); if (rc == 0) { krb5_data outbuf; /* store the new TGT back into the job entry */ outbuf.length = 0; if ((rc = krb_encrypt_tgt_creds(new_creds, &outbuf))) { ERROR((SGE_EVENT, MSG_KRB_COULDNOTECRYPTTGTFORJOBXY_DS, sge_u32c(lGetUlong(job, JB_job_number)), error_message(rc))); } else { lSetString(job, JB_tgt, krb_bin2str(outbuf.data, outbuf.length, NULL)); } /* if we are called by the execd, also store the new TGT in the credentials cache of the user */ if (!strcmp(prognames[EXECD], gsd->progname)) { int retries = MAX_NIS_RETRIES; struct passwd *pw = NULL; while (retries-- && !pw) pw = getpwnam(lGetString(job, JB_owner)); if (pw) { if ((krb_store_forwarded_tgt(pw->pw_uid, lGetUlong(job, JB_job_number), new_creds))) { ERROR((SGE_EVENT, MSG_KRB_COULDNOTSTORERENEWEDTGTFORXJOBY_SD, lGetString(job, JB_owner), sge_u32c(lGetUlong(job, JB_job_number)))); } } else { ERROR((SGE_EVENT, MSG_KRB_COULDNOTGETUSERIDFORXY_SD , lGetString(job, JB_owner), sge_u32c(lGetUlong(job, JB_job_number)))); } } if (outbuf.length) krb5_xfree(outbuf.data); } if (!mconf_get_simulate_jobs()) { job_write_spool_file(job, 0, NULL, SPOOL_DEFAULT);; } if (new_creds[0]) krb5_free_creds(context, new_creds[0]); } } } if (tgtbuf.length) krb5_xfree(tgtbuf.data); if (tgt_creds) krb5_free_tgt_creds(context, tgt_creds); } }
static krb5_error_code krb5_validate_or_renew_creds(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_ccache ccache, char *in_tkt_service, int validate) { krb5_error_code ret; krb5_creds in_creds; /* only client and server need to be filled in */ krb5_creds *out_creds = 0; /* for check before dereferencing below */ krb5_creds **tgts; memset((char *)&in_creds, 0, sizeof(krb5_creds)); in_creds.server = NULL; tgts = NULL; in_creds.client = client; if (in_tkt_service) { /* this is ugly, because so are the data structures involved. I'm in the library, so I'm going to manipulate the data structures directly, otherwise, it will be worse. */ if ((ret = krb5_parse_name(context, in_tkt_service, &in_creds.server))) goto cleanup; /* stuff the client realm into the server principal. realloc if necessary */ if (in_creds.server->realm.length < in_creds.client->realm.length) if ((in_creds.server->realm.data = (char *) realloc(in_creds.server->realm.data, in_creds.client->realm.length)) == NULL) { ret = ENOMEM; goto cleanup; } in_creds.server->realm.length = in_creds.client->realm.length; memcpy(in_creds.server->realm.data, in_creds.client->realm.data, in_creds.client->realm.length); } else { if ((ret = krb5_build_principal_ext(context, &in_creds.server, in_creds.client->realm.length, in_creds.client->realm.data, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, in_creds.client->realm.length, in_creds.client->realm.data, 0))) goto cleanup; } if (validate) ret = krb5_get_cred_from_kdc_validate(context, ccache, &in_creds, &out_creds, &tgts); else ret = krb5_get_cred_from_kdc_renew(context, ccache, &in_creds, &out_creds, &tgts); /* ick. copy the struct contents, free the container */ if (out_creds) { *creds = *out_creds; krb5_xfree(out_creds); } cleanup: if (in_creds.server) krb5_free_principal(context, in_creds.server); if (tgts) krb5_free_tgt_creds(context, tgts); return(ret); }
krb5_error_code KRB5_CALLCONV krb5_get_credentials(krb5_context context, krb5_flags options, krb5_ccache ccache, krb5_creds *in_creds, krb5_creds **out_creds) { krb5_error_code retval; krb5_creds mcreds; krb5_creds *ncreds; krb5_creds **tgts; krb5_flags fields; int not_ktype; retval = krb5_get_credentials_core(context, options, in_creds, &mcreds, &fields); if (retval) return retval; if ((ncreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) return ENOMEM; memset((char *)ncreds, 0, sizeof(krb5_creds)); ncreds->magic = KV5M_CREDS; /* The caller is now responsible for cleaning up in_creds */ if ((retval = krb5_cc_retrieve_cred(context, ccache, fields, &mcreds, ncreds))) { krb5_xfree(ncreds); ncreds = in_creds; } else { *out_creds = ncreds; } if ((retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE) || options & KRB5_GC_CACHED) return retval; if (retval == KRB5_CC_NOT_KTYPE) not_ktype = 1; else not_ktype = 0; retval = krb5_get_cred_from_kdc(context, ccache, ncreds, out_creds, &tgts); if (tgts) { register int i = 0; krb5_error_code rv2; while (tgts[i]) { if ((rv2 = krb5_cc_store_cred(context, ccache, tgts[i]))) { retval = rv2; break; } i++; } krb5_free_tgt_creds(context, tgts); } /* * Translate KRB5_CC_NOTFOUND if we previously got * KRB5_CC_NOT_KTYPE from krb5_cc_retrieve_cred(), in order to * handle the case where there is no TGT in the ccache and the * input enctype didn't match. This handling is necessary because * some callers, such as GSSAPI, iterate through enctypes and * KRB5_CC_NOTFOUND passed through from the * krb5_get_cred_from_kdc() is semantically incorrect, since the * actual failure was the non-existence of a ticket of the correct * enctype rather than the missing TGT. */ if ((retval == KRB5_CC_NOTFOUND || retval == KRB5_CC_NOT_KTYPE) && not_ktype) retval = KRB5_CC_NOT_KTYPE; if (!retval) { /* the purpose of the krb5_get_credentials call is to * obtain a set of credentials for the caller. the * krb5_cc_store_cred() call is to optimize performance * for future calls. Ignore any errors, since the credentials * are still valid even if we fail to store them in the cache. */ krb5_cc_store_cred(context, ccache, *out_creds); } return retval; }
static krb5_error_code krb5_rd_cred_basic(krb5_context context, krb5_data *pcreddata, krb5_key pkey, krb5_replay_data *replaydata, krb5_creds ***pppcreds) { krb5_error_code retval = 0; krb5_cred * pcred = NULL; krb5_int32 ncreds = 0; krb5_int32 i = 0; krb5_cred_enc_part encpart; /* decode cred message */ if ((retval = decode_krb5_cred(pcreddata, &pcred))) return retval; memset(&encpart, 0, sizeof(encpart)); if ((retval = decrypt_credencdata(context, pcred, pkey, &encpart))) goto cleanup_cred; replaydata->timestamp = encpart.timestamp; replaydata->usec = encpart.usec; replaydata->seq = encpart.nonce; /* * Allocate the list of creds. The memory is allocated so that * krb5_free_tgt_creds can be used to free the list. */ for (ncreds = 0; pcred->tickets[ncreds]; ncreds++); if ((*pppcreds = (krb5_creds **)malloc((size_t)(sizeof(krb5_creds *) * (ncreds + 1)))) == NULL) { retval = ENOMEM; goto cleanup_cred; } (*pppcreds)[0] = NULL; /* * For each credential, create a strcture in the list of * credentials and copy the information. */ while (i < ncreds) { krb5_cred_info * pinfo; krb5_creds * pcur; krb5_data * pdata; if ((pcur = (krb5_creds *)calloc(1, sizeof(krb5_creds))) == NULL) { retval = ENOMEM; goto cleanup; } (*pppcreds)[i] = pcur; (*pppcreds)[i+1] = 0; pinfo = encpart.ticket_info[i++]; if ((retval = krb5_copy_principal(context, pinfo->client, &pcur->client))) goto cleanup; if ((retval = krb5_copy_principal(context, pinfo->server, &pcur->server))) goto cleanup; if ((retval = krb5_copy_keyblock_contents(context, pinfo->session, &pcur->keyblock))) goto cleanup; if ((retval = krb5_copy_addresses(context, pinfo->caddrs, &pcur->addresses))) goto cleanup; if ((retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata))) goto cleanup; pcur->ticket = *pdata; free(pdata); pcur->is_skey = FALSE; pcur->magic = KV5M_CREDS; pcur->times = pinfo->times; pcur->ticket_flags = pinfo->flags; pcur->authdata = NULL; /* not used */ memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket)); } /* * NULL terminate the list */ (*pppcreds)[i] = NULL; cleanup: if (retval) { krb5_free_tgt_creds(context, *pppcreds); *pppcreds = NULL; } cleanup_cred: krb5_free_cred(context, pcred); krb5_free_cred_enc_part(context, &encpart); return retval; }
/* * This functions takes as input an KRB_CRED message, validates it, and * outputs the array of the forwarded credentials and replay cache information */ krb5_error_code KRB5_CALLCONV krb5_rd_cred(krb5_context context, krb5_auth_context auth_context, krb5_data *pcreddata, krb5_creds ***pppcreds, krb5_replay_data *outdata) { krb5_error_code retval = 0; krb5_replay_data replaydata; if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && (outdata == NULL)) /* Need a better error */ return KRB5_RC_REQUIRED; if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && (auth_context->rcache == NULL)) return KRB5_RC_REQUIRED; /* * If decrypting with the subsession key fails, perhaps the * credentials are stored in the session key so try decrypting with that. */ if (auth_context->recv_subkey == NULL || (retval = krb5_rd_cred_basic(context, pcreddata, auth_context->recv_subkey, &replaydata, pppcreds))) { retval = krb5_rd_cred_basic(context, pcreddata, auth_context->key, &replaydata, pppcreds); if (retval) return retval; } if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_donot_replay replay; if ((retval = krb5_check_clockskew(context, replaydata.timestamp))) goto error; if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, "_forw", &replay.client))) goto error; replay.server = ""; /* XXX */ replay.msghash = NULL; replay.cusec = replaydata.usec; replay.ctime = replaydata.timestamp; if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) { free(replay.client); goto error; } free(replay.client); } if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { if (auth_context->remote_seq_number != replaydata.seq) { retval = KRB5KRB_AP_ERR_BADORDER; goto error; } auth_context->remote_seq_number++; } if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { outdata->timestamp = replaydata.timestamp; outdata->usec = replaydata.usec; outdata->seq = replaydata.seq; } error:; if (retval) { krb5_free_tgt_creds(context, *pppcreds); *pppcreds = NULL; } return retval; }
/* Produce a list of credentials from a KRB-CRED message and its enc_part. */ static krb5_error_code make_cred_list(krb5_context context, krb5_cred *krbcred, krb5_cred_enc_part *encpart, krb5_creds ***creds_out) { krb5_error_code ret = 0; krb5_creds **list = NULL; krb5_cred_info *info; krb5_data *ticket_data; size_t i, count; *creds_out = NULL; /* Allocate the list of creds. */ for (count = 0; krbcred->tickets[count] != NULL; count++); list = k5calloc(count + 1, sizeof(*list), &ret); if (list == NULL) goto cleanup; /* For each credential, create a strcture in the list of credentials and * copy the information. */ for (i = 0; i < count; i++) { list[i] = k5alloc(sizeof(*list[i]), &ret); if (list[i] == NULL) goto cleanup; info = encpart->ticket_info[i]; ret = krb5_copy_principal(context, info->client, &list[i]->client); if (ret) goto cleanup; ret = krb5_copy_principal(context, info->server, &list[i]->server); if (ret) goto cleanup; ret = krb5_copy_keyblock_contents(context, info->session, &list[i]->keyblock); if (ret) goto cleanup; ret = krb5_copy_addresses(context, info->caddrs, &list[i]->addresses); if (ret) goto cleanup; ret = encode_krb5_ticket(krbcred->tickets[i], &ticket_data); if (ret) goto cleanup; list[i]->ticket = *ticket_data; free(ticket_data); list[i]->is_skey = FALSE; list[i]->magic = KV5M_CREDS; list[i]->times = info->times; list[i]->ticket_flags = info->flags; list[i]->authdata = NULL; list[i]->second_ticket = empty_data(); } *creds_out = list; list = NULL; cleanup: krb5_free_tgt_creds(context, list); return ret; }
/* Validate a KRB-CRED message in creddata, and return a list of forwarded * credentials along with replay cache information. */ krb5_error_code KRB5_CALLCONV krb5_rd_cred(krb5_context context, krb5_auth_context authcon, krb5_data *creddata, krb5_creds ***creds_out, krb5_replay_data *replaydata_out) { krb5_error_code ret = 0; krb5_creds **credlist = NULL; krb5_cred *krbcred = NULL; krb5_cred_enc_part *encpart = NULL; krb5_replay_data rdata; const krb5_int32 flags = authcon->auth_context_flags; *creds_out = NULL; if (((flags & KRB5_AUTH_CONTEXT_RET_TIME) || (flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && replaydata_out == NULL) return KRB5_RC_REQUIRED; ret = decode_krb5_cred(creddata, &krbcred); if (ret) goto cleanup; ret = decrypt_encpart(context, &krbcred->enc_part, authcon, &encpart); if (ret) goto cleanup; ret = make_cred_list(context, krbcred, encpart, &credlist); if (ret) goto cleanup; if (authcon->recv_subkey != NULL || authcon->key != NULL) { rdata.timestamp = encpart->timestamp; ret = k5_privsafe_check_replay(context, authcon, &rdata, &krbcred->enc_part, NULL); if (ret) goto cleanup; } if (flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { if (authcon->remote_seq_number != (uint32_t)encpart->nonce) { ret = KRB5KRB_AP_ERR_BADORDER; goto cleanup; } authcon->remote_seq_number++; } *creds_out = credlist; credlist = NULL; if ((flags & KRB5_AUTH_CONTEXT_RET_TIME) || (flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { replaydata_out->timestamp = encpart->timestamp; replaydata_out->usec = encpart->usec; replaydata_out->seq = encpart->nonce; } cleanup: krb5_free_tgt_creds(context, credlist); krb5_free_cred(context, krbcred); krb5_free_cred_enc_part(context, encpart); free(encpart); /* krb5_free_cred_enc_part doesn't do this */ return ret; }