xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/fwd_tgt.c (revision 004388ebfdfe2ed7dfd2d153a876dfcc22d2c006)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * lib/krb5/krb/get_in_tkt.c
10  *
11  * Copyright 1995 by the Massachusetts Institute of Technology.
12  * All Rights Reserved.
13  *
14  * Export of this software from the United States of America may
15  *   require a specific license from the United States Government.
16  *   It is the responsibility of any person or organization contemplating
17  *   export to obtain such a license before exporting.
18  *
19  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20  * distribute this software and its documentation for any purpose and
21  * without fee is hereby granted, provided that the above copyright
22  * notice appear in all copies and that both that copyright notice and
23  * this permission notice appear in supporting documentation, and that
24  * the name of M.I.T. not be used in advertising or publicity pertaining
25  * to distribution of the software without specific, written prior
26  * permission.  Furthermore if you modify this software you must label
27  * your software as modified software and not distribute it in such a
28  * fashion that it might be confused with the original M.I.T. software.
29  * M.I.T. makes no representations about the suitability of
30  * this software for any purpose.  It is provided "as is" without express
31  * or implied warranty.
32  */
33 
34 #define NEED_SOCKETS
35 #include <k5-int.h>
36 #include <memory.h>
37 
38 /* helper function: convert flags to necessary KDC options */
39 #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
40 
41 /* Get a TGT for use at the remote host */
42 krb5_error_code KRB5_CALLCONV
43 krb5_fwd_tgt_creds(
44     krb5_context context,
45     krb5_auth_context auth_context,
46     char *rhost,
47     krb5_principal client,
48     krb5_principal server,
49     krb5_ccache cc,
50     int forwardable,      /* Should forwarded TGT also be forwardable? */
51     krb5_data *outbuf)
52 {
53     krb5_replay_data replaydata;
54     krb5_data * scratch = 0;
55     krb5_address **addrs = 0;
56     krb5_error_code retval;
57     krb5_creds creds, tgt;
58     krb5_creds *pcreds = 0;
59     krb5_flags kdcoptions;
60     int close_cc = 0;
61     int free_rhost = 0;
62     krb5_enctype enctype = 0;
63     krb5_keyblock *session_key;
64     krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes;
65 
66     memset((char *)&creds, 0, sizeof(creds));
67     memset((char *)&tgt, 0, sizeof(creds));
68 
69     if (cc == 0) {
70 	if ((retval = krb5int_cc_default(context, &cc)))
71 	goto errout;
72 	close_cc = 1;
73     }
74     retval = krb5_auth_con_getkey (context, auth_context, &session_key);
75     if (retval)
76 	goto errout;
77     if (session_key) {
78 	enctype = session_key->enctype;
79 	krb5_free_keyblock (context, session_key);
80 	session_key = NULL;
81     } else if (server) { /* must server be non-NULL when rhost is given? */
82 	/* Try getting credentials to see what the remote side supports.
83 	   Not bulletproof, just a heuristic.  */
84 	krb5_creds in, *out = 0;
85 	memset (&in, 0, sizeof(in));
86 
87 	retval = krb5_copy_principal (context, server, &in.server);
88 	if (retval)
89             goto punt;
90 	retval = krb5_copy_principal (context, client, &in.client);
91 	if (retval)
92             goto punt;
93 	retval = krb5_get_credentials (context, 0, cc, &in, &out);
94 	if (retval)
95             goto punt;
96 	/* Got the credentials.	 Okay, now record the enctype and
97 	   throw them away.  */
98 	enctype = out->keyblock.enctype;
99 	krb5_free_creds (context, out);
100     punt:
101         krb5_free_cred_contents (context, &in);
102     }
103 
104     if ((retval = krb5_copy_principal(context, client, &creds.client)))
105 	goto errout;
106 
107     if ((retval = krb5_build_principal_ext(context, &creds.server,
108 					   client->realm.length,
109 					   client->realm.data,
110 					   KRB5_TGS_NAME_SIZE,
111 					   KRB5_TGS_NAME,
112 					   client->realm.length,
113 					   client->realm.data,
114 					   0)))
115 	goto errout;
116 
117     /* fetch tgt directly from cache */
118     context->use_conf_ktypes = 1;
119     retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_SUPPORTED_KTYPES,
120 				    &creds, &tgt);
121     context->use_conf_ktypes = old_use_conf_ktypes;
122     if (retval)
123 	goto errout;
124 
125     /* tgt->client must be equal to creds.client */
126     if (!krb5_principal_compare(context, tgt.client, creds.client)) {
127 	retval = KRB5_PRINC_NOMATCH;
128 	goto errout;
129     }
130 
131     if (!tgt.ticket.length) {
132 	retval = KRB5_NO_TKT_SUPPLIED;
133 	goto errout;
134     }
135 
136     if (tgt.addresses && *tgt.addresses) {
137 	if (rhost == NULL) {
138 	    if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) {
139 		retval = KRB5_FWD_BAD_PRINCIPAL;
140 		goto errout;
141 	    }
142 
143 	    if (krb5_princ_size(context, server) < 2) {
144 		retval = KRB5_CC_BADNAME;
145 		goto errout;
146 	    }
147 
148 	    rhost = malloc(server->data[1].length+1);
149 	    if (!rhost) {
150 		retval = ENOMEM;
151 		goto errout;
152 	    }
153 	    free_rhost = 1;
154 	    (void) memcpy(rhost, server->data[1].data, server->data[1].length);
155 	    rhost[server->data[1].length] = '\0';
156 	}
157 
158 	retval = krb5_os_hostaddr(context, rhost, &addrs);
159 	if (retval)
160 	    goto errout;
161     }
162 
163     creds.keyblock.enctype = enctype;
164     creds.times = tgt.times;
165     creds.times.starttime = 0;
166     kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED;
167 
168     if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */
169       kdcoptions &= ~(KDC_OPT_FORWARDABLE);
170 
171     if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions,
172 					addrs, &creds, &pcreds))) {
173 	if (enctype) {
174 	    creds.keyblock.enctype = 0;
175 	    if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions,
176                                                 addrs, &creds, &pcreds)))
177 		goto errout;
178 	} else goto errout;
179     }
180 
181     retval = krb5_mk_1cred(context, auth_context, pcreds,
182                            &scratch, &replaydata);
183     krb5_free_creds(context, pcreds);
184 
185     /* Solaris Kerberos: changed this logic from the MIT 1.2.1 version to be
186      * more robust.
187      */
188     if (scratch) {
189 	if (retval)
190 	    krb5_free_data(context, scratch);
191 	else {
192 	    *outbuf = *scratch;
193 	    krb5_xfree(scratch);
194 	}
195     }
196 
197 errout:
198     if (addrs)
199 	krb5_free_addresses(context, addrs);
200     if (close_cc)
201 	(void) krb5_cc_close(context, cc);
202     if (free_rhost)
203 	free(rhost);
204     krb5_free_cred_contents(context, &creds);
205     krb5_free_cred_contents(context, &tgt);
206     return retval;
207 }
208