2 * lib/krb5/krb/get_fcreds.c
4 * Copyright 1994 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. M.I.T. makes no representations about the suitability of
20 * this software for any purpose. It is provided "as is" without express
21 * or implied warranty.
23 * krb5_get_for_creds()
26 /* XXX This API is going to change; what's here isn't general enough! XXX */
27 /* XXX Once we finalize the API, it should go into func-proto.h and */
28 /* into the API doc. */
30 /* General-purpose forwarding routines. These routines may be put into */
31 /* libkrb5.a to allow widespread use */
37 #define KRB5_DEFAULT_LIFE 60*60*8 /* 8 hours */
38 /* helper function: convert flags to necessary KDC options */
39 #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
41 /* Get a TGT for use at the remote host */
43 krb5_get_for_creds(context, sumtype, rhost, client, enc_key,
46 const krb5_cksumtype sumtype;
48 krb5_principal client;
49 krb5_keyblock *enc_key;
50 int forwardable; /* Should forwarded TGT also be forwardable? */
56 krb5_error_code retval;
57 krb5_kdc_rep *dec_rep = 0;
58 krb5_error *err_reply;
60 krb5_creds creds, tgt;
62 krb5_flags kdcoptions;
64 char *remote_host = 0;
68 memset((char *)&creds, 0, sizeof(creds));
69 memset((char *)&tgsrep, 0, sizeof(tgsrep));
71 if (!rhost || !(hp = gethostbyname(rhost)))
72 return KRB5_ERR_BAD_HOSTNAME;
74 remote_host = (char *) malloc(strlen(hp->h_name)+1);
79 strcpy(remote_host, hp->h_name);
81 if (retval = krb5_get_host_realm(context, remote_host, &hrealms))
84 retval = KRB5_ERR_HOST_REALM_UNKNOWN;
89 for(i=0; hp->h_addr_list[i]; i++);
91 addrs = (krb5_address **) malloc ((i+1)*sizeof(*addrs));
96 memset(addrs, 0, (i+1)*sizeof(*addrs));
98 for(i=0; hp->h_addr_list[i]; i++) {
99 addrs[i] = (krb5_address *) malloc(sizeof(krb5_address));
104 addrs[i]->addrtype = hp->h_addrtype;
105 addrs[i]->length = hp->h_length;
106 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
107 if (!addrs[i]->contents) {
111 memcpy ((char *)addrs[i]->contents, hp->h_addr_list[i],
116 if (retval = krb5_copy_principal(context, client, &creds.client))
119 if (retval = krb5_build_principal_ext(context, &creds.server,
124 client->realm.length,
129 creds.times.starttime = 0;
130 if (retval = krb5_timeofday(context, &now))
133 creds.times.endtime = now + KRB5_DEFAULT_LIFE;
134 creds.times.renew_till = 0;
136 if (retval = krb5_cc_default(context, &cc))
139 /* fetch tgt directly from cache */
140 retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_MATCH_SRV_NAMEONLY,
142 krb5_cc_close(context, cc);
146 /* tgt->client must be equal to creds.client */
147 if (!krb5_principal_compare(context, tgt.client, creds.client)) {
148 retval = KRB5_PRINC_NOMATCH;
152 if (!tgt.ticket.length) {
153 retval = KRB5_NO_TKT_SUPPLIED;
157 kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED;
159 if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */
160 kdcoptions &= ~(KDC_OPT_FORWARDABLE);
162 if (retval = krb5_send_tgs(context, kdcoptions, &creds.times, NULL,
163 sumtype, tgt.server, addrs, creds.authdata,
165 0, /* no second ticket */
169 switch (tgsrep.message_type) {
174 if (!krb5_is_krb_error(&tgsrep.response)) {
175 retval = KRB5KRB_AP_ERR_MSG_TYPE;
178 if (retval = decode_krb5_error(&tgsrep.response, &err_reply))
182 retval = err_reply->error + ERROR_TABLE_BASE_krb5;
184 krb5_free_error(context, err_reply);
188 etype = tgt.keyblock.etype;
189 if (retval = krb5_decode_kdc_rep(context, &tgsrep.response,
195 if (dec_rep->msg_type != KRB5_TGS_REP) {
196 retval = KRB5KRB_AP_ERR_MSG_TYPE;
200 /* now it's decrypted and ready for prime time */
202 if (!krb5_principal_compare(context, dec_rep->client, tgt.client)) {
203 retval = KRB5_KDCREP_MODIFIED;
207 retval = krb5_mk_cred(context, dec_rep, etype, enc_key, 0, 0, outbuf);
215 krb5_free_addresses(context, addrs);
216 krb5_free_cred_contents(context, &creds);
217 if (tgsrep.response.data)
218 free(tgsrep.response.data);
220 krb5_free_kdc_rep(context, dec_rep);