/* Get a TGT for use at the remote host */ krb5_error_code KRB5_CALLCONV krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, char *rhost, krb5_principal client, krb5_principal server, krb5_ccache cc, int forwardable, krb5_data *outbuf) /* Should forwarded TGT also be forwardable? */ { krb5_replay_data replaydata; krb5_data * scratch = 0; krb5_address **addrs = NULL; krb5_error_code retval; krb5_creds creds, tgt; krb5_creds *pcreds; krb5_flags kdcoptions; int close_cc = 0; int free_rhost = 0; krb5_enctype enctype = 0; krb5_keyblock *session_key; krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; memset((char *)&creds, 0, sizeof(creds)); memset((char *)&tgt, 0, sizeof(creds)); if (cc == 0) { if ((retval = krb5int_cc_default(context, &cc))) goto errout; close_cc = 1; } retval = krb5_auth_con_getkey (context, auth_context, &session_key); if (retval) goto errout; if (session_key) { enctype = session_key->enctype; krb5_free_keyblock (context, session_key); session_key = NULL; } else if (server) { /* must server be non-NULL when rhost is given? */ /* Try getting credentials to see what the remote side supports. Not bulletproof, just a heuristic. */ krb5_creds in, *out = 0; memset (&in, 0, sizeof(in)); retval = krb5_copy_principal (context, server, &in.server); if (retval) goto punt; retval = krb5_copy_principal (context, client, &in.client); if (retval) goto punt; retval = krb5_get_credentials (context, 0, cc, &in, &out); if (retval) goto punt; /* Got the credentials. Okay, now record the enctype and throw them away. */ enctype = out->keyblock.enctype; krb5_free_creds (context, out); punt: krb5_free_cred_contents (context, &in); } if ((retval = krb5_copy_principal(context, client, &creds.client))) goto errout; if ((retval = krb5_build_principal_ext(context, &creds.server, client->realm.length, client->realm.data, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, client->realm.length, client->realm.data, 0))) goto errout; /* fetch tgt directly from cache */ context->use_conf_ktypes = 1; retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_SUPPORTED_KTYPES, &creds, &tgt); context->use_conf_ktypes = old_use_conf_ktypes; if (retval) goto errout; /* tgt->client must be equal to creds.client */ if (!krb5_principal_compare(context, tgt.client, creds.client)) { /* Solaris Kerberos */ char *r_name = NULL; char *t_name = NULL; krb5_error_code r_err, t_err; t_err = krb5_unparse_name(context, tgt.client, &t_name); r_err = krb5_unparse_name(context, creds.client, &r_name); krb5_set_error_message(context, KRB5_PRINC_NOMATCH, dgettext(TEXT_DOMAIN, "Requested principal and ticket don't match: Requested principal is '%s' and TGT principal is '%s'"), r_err ? "unknown" : r_name, t_err ? "unknown" : t_name); if (r_name) krb5_free_unparsed_name(context, r_name); if (t_name) krb5_free_unparsed_name(context, t_name); retval = KRB5_PRINC_NOMATCH; goto errout; } if (!tgt.ticket.length) { retval = KRB5_NO_TKT_SUPPLIED; goto errout; } if (tgt.addresses && *tgt.addresses) { if (rhost == NULL) { if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) { retval = KRB5_FWD_BAD_PRINCIPAL; goto errout; } if (krb5_princ_size(context, server) < 2){ retval = KRB5_CC_BADNAME; goto errout; } rhost = malloc(server->data[1].length+1); if (!rhost) { retval = ENOMEM; goto errout; } free_rhost = 1; /* Solaris Kerberos */ (void) memcpy(rhost, server->data[1].data, server->data[1].length); rhost[server->data[1].length] = '\0'; } retval = krb5_os_hostaddr(context, rhost, &addrs); if (retval) goto errout; } creds.keyblock.enctype = enctype; creds.times = tgt.times; creds.times.starttime = 0; kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED; if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */ kdcoptions &= ~(KDC_OPT_FORWARDABLE); if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, addrs, &creds, &pcreds))) { if (enctype) { creds.keyblock.enctype = 0; if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, addrs, &creds, &pcreds))) goto errout; } else goto errout; } retval = krb5_mk_1cred(context, auth_context, pcreds, &scratch, &replaydata); krb5_free_creds(context, pcreds); /* * Solaris Kerberos: changed this logic from the MIT 1.2.1 version to be * more robust. */ if (scratch) { if (retval) krb5_free_data(context, scratch); else { *outbuf = *scratch; krb5_xfree(scratch); } } errout: if (addrs) krb5_free_addresses(context, addrs); /* Solaris Kerberos */ if (close_cc) (void) krb5_cc_close(context, cc); if (free_rhost) free(rhost); krb5_free_cred_contents(context, &creds); krb5_free_cred_contents(context, &tgt); return retval; }
/** * @brief * Get a TGT for use at the remote host. * * @param[in] context - The Kerberos context. * @param[in] auth_context - Authentication context * @param[in] client - Principal to be copied * @param[in] server - Server of type krb5_principal * @param[in] cc - Credential cache handle * @param[out] outbuf - Replay cache data (NULL if not needed) * * @return krb5_error_code * @retval 0 - success * @retval !=0 - failure */ static krb5_error_code fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, krb5_principal client, krb5_principal server, krb5_ccache cc, krb5_data outbuf) { krb5_replay_data replaydata; krb5_data *scratch = 0; krb5_address **addrs = 0; krb5_flags kdcoptions; krb5_error_code retval; krb5_creds creds, tgt; krb5_creds *pcreds; int free_rhost = 0; char *rhost; memset((char *)&creds, 0, sizeof(creds)); memset((char *)&tgt, 0, sizeof(creds)); if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) return KRB5_FWD_BAD_PRINCIPAL; if (krb5_princ_size(context, server) < 2) return KRB5_CC_BADNAME; rhost = malloc(server->data[1].length+1); if (!rhost) return ENOMEM; free_rhost = 1; memcpy(rhost, server->data[1].data, server->data[1].length); rhost[server->data[1].length] = '\0'; retval = krb5_os_hostaddr(context, rhost, &addrs); if (retval) goto errout; if ((retval = krb5_copy_principal(context, client, &creds.client))) goto errout; if ((retval = krb5_build_principal_ext(context, &creds.server, client->realm.length, client->realm.data, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, client->realm.length, client->realm.data, 0))) goto errout; /* fetch tgt directly from cache */ retval = krb5_cc_retrieve_cred(context, cc, KRB5_TC_SUPPORTED_KTYPES, &creds, &tgt); if (retval) goto errout; /* tgt->client must be equal to creds.client */ if (!krb5_principal_compare(context, tgt.client, creds.client)) { retval = KRB5_PRINC_NOMATCH; goto errout; } if (!tgt.ticket.length) { retval = KRB5_NO_TKT_SUPPLIED; goto errout; } kdcoptions = flags2options(tgt.ticket_flags)| KDC_OPT_FORWARDED; if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, addrs, &creds, &pcreds))) goto errout; retval = krb5_mk_1cred(context, auth_context, pcreds, &scratch, &replaydata); krb5_free_creds(context, pcreds); if (retval) { if (scratch) krb5_free_data(context, scratch); } else { *outbuf = *scratch; free(scratch); } errout: if (addrs) krb5_free_addresses(context, addrs); if (free_rhost) free(rhost); krb5_free_cred_contents(context, &creds); krb5_free_cred_contents(context, &tgt); return retval; }
int auks_krb5_cred_get_fwd(char *ccachefilename, char *serverName, char **p_buffer, size_t * p_buffer_length) { int fstatus = AUKS_ERROR ; /* kerberos related variables */ krb5_error_code err_code; krb5_context context; krb5_ccache ccache; krb5_principal principal; krb5_creds **out_creds_array = NULL; krb5_auth_context auth_context; krb5_flags authopts; krb5_data outbuf; krb5_data *p_outbuf; krb5_replay_data krdata; authopts = AP_OPTS_MUTUAL_REQUIRED; authopts &= (~OPTS_FORWARD_CREDS); authopts &= (~OPTS_FORWARDABLE_CREDS); if ( serverName == NULL ) { auks_error("no host specified"); fstatus = AUKS_ERROR_KRB5_CRED_NO_HOST_SPECIFIED ; goto exit; } /* initialize kerberos context */ err_code = krb5_init_context(&context); if (err_code) { auks_error("unable to initialize kerberos context : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_INIT_CTX ; goto exit; } auks_log("kerberos context successfully initialized"); /* initialize kerberos credential cache structure */ if (ccachefilename == NULL) err_code = krb5_cc_default(context, &ccache); else err_code = krb5_cc_resolve(context,ccachefilename,&ccache); if (err_code) { auks_error("unable to resolve credential cache : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_OPEN_CC ; goto ctx_exit ; } auks_log("credential cache successfully resolved"); /* get principal using credential cache */ err_code = krb5_cc_get_principal(context,ccache,&principal); if (err_code) { auks_error("unable to get principal from credential cache : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_GET_PRINC ; goto cc_exit ; } auks_log("principal successfully extracted from credential cache"); /* initialize kerberos authentication context */ err_code = krb5_auth_con_init(context,&auth_context); if (err_code) { auks_error("unable to initialize kerberos authentication " "context : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_INIT_AUTH_CTX ; goto princ_exit; } auks_log("kerberos authentication context successfully initialized"); /* do replay detection using timestamps */ krb5_auth_con_setflags(context,auth_context,KRB5_AUTH_CONTEXT_RET_TIME); /* get forwarded credential for server */ err_code = krb5_fwd_tgt_creds(context,auth_context,serverName, principal,NULL,NULL,authopts,&outbuf); if (err_code) { auks_error("unable to get serialized and crypted forwarded " "credential for %s from KDC : %s", serverName,error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_GET_FWD_CRED ; goto auth_ctx_exit; } auks_log("serialized and crypted forwarded credential for %s " "successfully got from KDC",serverName); /* desactive replay detection */ krb5_auth_con_setflags(context,auth_context,0); /* decrypt (using session key stored in auth context) and */ /* unserialized forwarded credential in a kerberos credential */ /* structure */ err_code = krb5_rd_cred(context,auth_context,&outbuf,&out_creds_array, &krdata); if (err_code) { auks_error("unable to unserialize and decrypt forwarded " "credential for %s : %s",serverName, error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_RD_CRED ; goto fwd_exit; } auks_log("unserialization and decryption of forwarded " "credential for %s succesfully done",serverName); /* Reinitialize kerberos authentication context in order to */ /* write credential to output buffer */ krb5_auth_con_free(context,auth_context); err_code = krb5_auth_con_init(context,&auth_context); if (err_code) { auks_error("unable to reinitialize kerberos connection " "authentication context : %s",error_message (err_code)); fstatus = AUKS_ERROR_KRB5_CRED_INIT_AUTH_CTX ; goto rd_cred_exit; } auks_log("kerberos connection authentication context " "reinitialization successfully done"); /* no flags */ krb5_auth_con_setflags(context,auth_context,0); /* serialize forwarded credential (no encryption because auth */ /* context session key is nullified) */ err_code = krb5_mk_1cred(context,auth_context,*out_creds_array, &p_outbuf,&krdata); if (err_code) { auks_error("unable to serialize forwarded credential for " "%s : %s",serverName,error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_MK_CRED ; goto rd_cred_exit; } auks_log("forwarded credential for %s successfully serialized", serverName); /* allocate output buffer and store serialized credential */ (*p_buffer) = (char *) malloc(p_outbuf->length * sizeof(char)); if ((*p_buffer) == NULL) { auks_error("unable to allocate serialized credential output " "buffer for %s",serverName); *p_buffer_length = 0 ; fstatus = AUKS_ERROR_KRB5_CRED_MALLOC ; } else { /* copy data */ memcpy(*p_buffer,p_outbuf->data,p_outbuf->length); *p_buffer_length = p_outbuf->length; auks_log("forwarded credential successfully stored " "in output buffer"); fstatus = AUKS_SUCCESS ; } krb5_free_data(context,p_outbuf); rd_cred_exit: krb5_free_creds(context,*out_creds_array); free(out_creds_array); fwd_exit: krb5_free_data_contents(context, &outbuf); auth_ctx_exit: krb5_auth_con_free(context,auth_context); princ_exit: krb5_free_principal(context, principal); cc_exit: krb5_cc_close(context, ccache); ctx_exit: krb5_free_context(context); exit: return fstatus; }
int auks_krb5_cred_deladdr_buffer(char *in_buf,size_t in_buf_len, char** pout_buf,size_t *pout_buf_len) { int fstatus = AUKS_ERROR ; /* kerberos related variables */ krb5_error_code err_code; krb5_context context; krb5_auth_context auth_context; krb5_creds **creds; krb5_data data; krb5_replay_data krdata; krb5_data *p_outbuf; krb5_creds fwd_cred; krb5_creds *p_cred_out = NULL; krb5_address **addresses; char* buffer; size_t length; /* initialize kerberos context */ err_code = krb5_init_context(&context); if (err_code) { auks_error("unable to initialize kerberos context : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_INIT_CTX ; goto exit; } auks_log("kerberos context successfully initialized"); /* initialize a nullified kerberos authentication context in order */ /* to decode credential from buffer */ err_code = krb5_auth_con_init(context, &auth_context); if (err_code) { auks_error("unable to initialize kerberos authentication" " context : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_INIT_AUTH_CTX ; goto ctx_exit; } auks_log("kerberos authentication context successfully initialized"); /* clear kerberos authentication context flags */ krb5_auth_con_setflags(context, auth_context, 0); /* build a kerberos data structure with input buffer */ data.data = in_buf; data.length = in_buf_len; /* build kerberos credential structure using this data structure */ err_code = krb5_rd_cred(context, auth_context, &data,&creds,&krdata); if (err_code) { auks_error("unable to deserialize credential data : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_RD_CRED ; goto auth_ctx_exit; } auks_log("credential data successfully deserialized"); memset(&fwd_cred, 0,sizeof(fwd_cred)); /* copy client principal in futur credential */ err_code = krb5_copy_principal(context,(*creds)->client, &fwd_cred.client); if (err_code) { auks_error("unable to put client principal into " "request cred : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_CP_PRINC ; goto cred_exit; } auks_log("client principal successfully put into request cred"); /* copy krbtgt/... principal in futur credential as required */ /* server principal for TGS */ err_code = krb5_copy_principal(context,(*creds)->server, &fwd_cred.server); if (err_code) { auks_error("unable to put server principal into " "request cred : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_CP_PRINC ; goto cred_exit; } auks_log("server principal successfully put into request cred"); /* get addressless forwarded ticket */ err_code = krb5_get_cred_via_tkt(context,(*creds), ( KDC_OPT_CANONICALIZE | KDC_OPT_FORWARDED | ( (*creds)->ticket_flags & KDC_TKT_COMMON_MASK ) ), addresses=NULL, &fwd_cred,&p_cred_out); if (err_code) { auks_error("unable to get addressless forwarded cred from auks" " cred buffer : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_GET_FWD_CRED ; goto cred_exit; } auks_log("addressless forwarded cred successfully" " got using auks cred buffer"); /* extract credential data */ err_code = krb5_mk_1cred(context,auth_context,p_cred_out, &p_outbuf,&krdata); if (err_code) { auks_error("unable to dump credential into working buffer : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_MK_CRED ; goto fwd_exit; } auks_log("credential successfully dumped into buffer"); /* allocate output buffer */ length = p_outbuf->length; buffer = (char *) malloc(length * sizeof(char)); if (buffer == NULL) { auks_error("unable to allocate memory for credential data " "storage"); fstatus = AUKS_ERROR_KRB5_CRED_MALLOC ; goto mk_exit; } /* copy credential data into output buffer */ memcpy(buffer,p_outbuf->data,length); *pout_buf = buffer; *pout_buf_len = length; auks_log("credential successfully stored in output buffer"); fstatus = AUKS_SUCCESS ; auks_log("in length : %u | out length : %u", in_buf_len, p_outbuf->length); mk_exit: krb5_free_data(context,p_outbuf); fwd_exit: krb5_free_creds(context,p_cred_out); cred_exit: krb5_free_cred_contents(context,&fwd_cred); krb5_free_creds(context, *creds); free(creds); auth_ctx_exit: krb5_auth_con_free(context, auth_context); ctx_exit: krb5_free_context(context); exit: return fstatus; }
int auks_krb5_cred_get(char *ccachefilename,char **pbuffer, size_t * plength) { int fstatus = AUKS_ERROR ; /* kerberos related variables */ krb5_error_code err_code; krb5_context context; krb5_auth_context auth_context; krb5_ccache ccache; krb5_creds read_cred; krb5_cc_cursor cc_cursor; krb5_data *p_outbuf; krb5_replay_data krdata; int read_cred_was_used = 0; int read_cred_is_tgt = 0; char *buffer; size_t length; /* initialize kerberos context */ err_code = krb5_init_context(&context); if (err_code) { auks_error("unable to initialize kerberos context : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_INIT_CTX ; goto exit; } auks_log("kerberos context successfully initialized"); /* initialize kerberos credential cache structure */ if (ccachefilename == NULL) err_code = krb5_cc_default(context, &ccache); else err_code = krb5_cc_resolve(context, ccachefilename,&ccache); if (err_code) { auks_error("unable to resolve credential cache : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_OPEN_CC ; goto ctx_exit ; } auks_log("credential cache successfully resolved"); /* start credential cache sequential reading */ err_code = krb5_cc_start_seq_get(context, ccache,&cc_cursor); if (err_code) { auks_error("unable to start credential cache sequential " "read : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_READ_CC ; goto cc_exit; } auks_log("credential cache sequential read successfully started"); /* look for the first TGT of the cache */ do { err_code = krb5_cc_next_cred(context,ccache, &cc_cursor,&read_cred); if (!err_code) { /* mark read_cred variable as used */ read_cred_was_used = 1; /* just check initial or forwarded tickets (TGTs) */ if ((read_cred.ticket_flags & TKT_FLG_INITIAL) || (read_cred.ticket_flags & TKT_FLG_FORWARDED)) { read_cred_is_tgt = 1 ; break; } } } while (!err_code); /* stop credential cache sequential reading */ err_code = krb5_cc_end_seq_get(context,ccache,&cc_cursor); if (err_code) { auks_error("unable to stop credential cache sequential " "read : %s",error_message(err_code)); } else auks_log("credential cache sequential read " "successfully stopped"); /* extract credential if a TGT was found */ if (!read_cred_is_tgt) { auks_error("no TGT found in credential cache"); fstatus = AUKS_ERROR_KRB5_CRED_NO_TGT_FOUND ; goto seq_exit; } auks_log("TGT found in credential cache"); /* initialize a nullified kerberos authentication context in order */ /* to serialize credential into buffer */ err_code = krb5_auth_con_init(context,&auth_context); if (err_code) { auks_error("unable to initialize kerberos authentication " "context : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_INIT_AUTH_CTX ; goto seq_exit; } auks_log("kerberos authentication context successfully initialized"); /* clear kerberos authentication context flags */ krb5_auth_con_setflags(context,auth_context,0); /* extract credential data */ err_code = krb5_mk_1cred(context,auth_context,&read_cred, &p_outbuf,&krdata); if (err_code) { auks_error("unable to dump credential into working buffer : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_MK_CRED ; goto auth_ctx_exit; } auks_log("credential successfully dumped into buffer"); /* allocate output buffer */ length = p_outbuf->length; buffer = (char *) malloc(length * sizeof(char)); if (buffer == NULL) { auks_error("unable to allocate memory for credential data " "storage"); fstatus = AUKS_ERROR_KRB5_CRED_MALLOC ; goto cred_exit; } /* copy credential data into output buffer */ memcpy(buffer,p_outbuf->data,length); *pbuffer = buffer; *plength = length; auks_log("credential successfully stored in output buffer"); fstatus = AUKS_SUCCESS ; cred_exit: krb5_free_data(context,p_outbuf); auth_ctx_exit: /* free kerberos authentication context */ krb5_auth_con_free(context,auth_context); seq_exit: /* free credential contents */ if (read_cred_was_used) krb5_free_cred_contents(context,&read_cred); cc_exit: krb5_cc_close(context, ccache); ctx_exit: krb5_free_context(context); exit: return fstatus; }