2 Unix SMB/CIFS implementation.
3 simple kerberos5 routines for active directory
4 Copyright (C) Andrew Tridgell 2001
5 Copyright (C) Luke Howard 2002
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #ifndef HAVE_KRB5_SET_REAL_TIME
28 * This function is not in the Heimdal mainline.
30 krb5_error_code
krb5_set_real_time(krb5_context context
, int32_t seconds
, int32_t microseconds
)
35 ret
= krb5_us_timeofday(context
, &sec
, &usec
);
39 context
->kdc_sec_offset
= seconds
- sec
;
40 context
->kdc_usec_offset
= microseconds
- usec
;
46 #if defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES) && !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES)
47 krb5_error_code
krb5_set_default_tgs_ktypes(krb5_context ctx
, const krb5_enctype
*enc
)
49 return krb5_set_default_in_tkt_etypes(ctx
, enc
);
53 #if defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS)
55 void setup_kaddr( krb5_address
*pkaddr
, struct sockaddr
*paddr
)
57 pkaddr
->addr_type
= KRB5_ADDRESS_INET
;
58 pkaddr
->address
.length
= sizeof(((struct sockaddr_in
*)paddr
)->sin_addr
);
59 pkaddr
->address
.data
= (char *)&(((struct sockaddr_in
*)paddr
)->sin_addr
);
61 #elif defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS)
63 void setup_kaddr( krb5_address
*pkaddr
, struct sockaddr
*paddr
)
65 pkaddr
->addrtype
= ADDRTYPE_INET
;
66 pkaddr
->length
= sizeof(((struct sockaddr_in
*)paddr
)->sin_addr
);
67 pkaddr
->contents
= (char *)&(((struct sockaddr_in
*)paddr
)->sin_addr
);
70 __ERROR__XX__UNKNOWN_ADDRTYPE
73 #if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_USE_ENCTYPE) && defined(HAVE_KRB5_STRING_TO_KEY)
74 int create_kerberos_key_from_string(krb5_context context
,
75 krb5_principal host_princ
,
82 krb5_encrypt_block eblock
;
84 ret
= krb5_principal2salt(context
, host_princ
, &salt
);
86 DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret
)));
89 krb5_use_enctype(context
, &eblock
, enctype
);
90 return krb5_string_to_key(context
, &eblock
, key
, password
, &salt
);
92 #elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT)
93 int create_kerberos_key_from_string(krb5_context context
,
94 krb5_principal host_princ
,
102 ret
= krb5_get_pw_salt(context
, host_princ
, &salt
);
104 DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret
)));
107 return krb5_string_to_key_salt(context
, enctype
, password
->data
,
111 __ERROR_XX_UNKNOWN_CREATE_KEY_FUNCTIONS
114 #if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
115 krb5_error_code
get_kerberos_allowed_etypes(krb5_context context
,
116 krb5_enctype
**enctypes
)
118 return krb5_get_permitted_enctypes(context
, enctypes
);
120 #elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES)
121 krb5_error_code
get_kerberos_allowed_etypes(krb5_context context
,
122 krb5_enctype
**enctypes
)
124 return krb5_get_default_in_tkt_etypes(context
, enctypes
);
127 __ERROR_XX_UNKNOWN_GET_ENCTYPES_FUNCTIONS
130 /* the following is defined as krb5_error_code to keep it from
131 being sucked into proto.h */
132 krb5_error_code
free_kerberos_etypes(krb5_context context
,
133 krb5_enctype
*enctypes
)
135 #if defined(HAVE_KRB5_FREE_KTYPES)
136 krb5_free_ktypes(context
, enctypes
);
143 #if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
144 krb5_error_code
krb5_auth_con_setuseruserkey(krb5_context context
,
145 krb5_auth_context auth_context
,
146 krb5_keyblock
*keyblock
)
148 return krb5_auth_con_setkey(context
, auth_context
, keyblock
);
152 void get_auth_data_from_tkt(DATA_BLOB
*auth_data
, krb5_ticket
*tkt
)
154 #if defined(HAVE_KRB5_TKT_ENC_PART2)
156 *auth_data
= data_blob(tkt
->enc_part2
->authorization_data
[0]->contents
,
157 tkt
->enc_part2
->authorization_data
[0]->length
);
159 if (tkt
->ticket
.authorization_data
&& tkt
->ticket
.authorization_data
->len
)
160 *auth_data
= data_blob(tkt
->ticket
.authorization_data
->val
->ad_data
.data
,
161 tkt
->ticket
.authorization_data
->val
->ad_data
.length
);
165 krb5_const_principal
get_principal_from_tkt(krb5_ticket
*tkt
)
167 #if defined(HAVE_KRB5_TKT_ENC_PART2)
168 return tkt
->enc_part2
->client
;
174 #if !defined(HAVE_KRB5_LOCATE_KDC)
175 krb5_error_code
krb5_locate_kdc(krb5_context ctx
, const krb5_data
*realm
, struct sockaddr
**addr_pp
, int *naddrs
, int get_masters
)
177 krb5_krbhst_handle hnd
;
178 krb5_krbhst_info
*hinfo
;
186 rc
= krb5_krbhst_init(ctx
, realm
->data
, KRB5_KRBHST_KDC
, &hnd
);
188 DEBUG(0, ("krb5_locate_kdc: krb5_krbhst_init failed (%s)\n", error_message(rc
)));
192 for ( num_kdcs
= 0; (rc
= krb5_krbhst_next(ctx
, hnd
, &hinfo
) == 0); num_kdcs
++)
195 krb5_krbhst_reset(ctx
, hnd
);
198 DEBUG(0, ("krb5_locate_kdc: zero kdcs found !\n"));
199 krb5_krbhst_free(ctx
, hnd
);
203 sa
= malloc( sizeof(struct sockaddr
) * num_kdcs
);
205 DEBUG(0, ("krb5_locate_kdc: malloc failed\n"));
206 krb5_krbhst_free(ctx
, hnd
);
211 memset(*addr_pp
, '\0', sizeof(struct sockaddr
) * num_kdcs
);
213 for (i
= 0; i
< num_kdcs
&& (rc
= krb5_krbhst_next(ctx
, hnd
, &hinfo
) == 0); i
++) {
214 if (hinfo
->ai
->ai_family
== AF_INET
)
215 memcpy(&sa
[i
], hinfo
->ai
->ai_addr
, sizeof(struct sockaddr
));
218 krb5_krbhst_free(ctx
, hnd
);
227 we can't use krb5_mk_req because w2k wants the service to be in a particular format
229 static krb5_error_code
krb5_mk_req2(krb5_context context
,
230 krb5_auth_context
*auth_context
,
231 const krb5_flags ap_req_options
,
232 const char *principal
,
236 krb5_error_code retval
;
237 krb5_principal server
;
242 retval
= krb5_parse_name(context
, principal
, &server
);
244 DEBUG(1,("Failed to parse principal %s\n", principal
));
248 /* obtain ticket & session key */
249 memset((char *)&creds
, 0, sizeof(creds
));
250 if ((retval
= krb5_copy_principal(context
, server
, &creds
.server
))) {
251 DEBUG(1,("krb5_copy_principal failed (%s)\n",
252 error_message(retval
)));
256 if ((retval
= krb5_cc_get_principal(context
, ccache
, &creds
.client
))) {
257 DEBUG(1,("krb5_cc_get_principal failed (%s)\n",
258 error_message(retval
)));
262 if ((retval
= krb5_get_credentials(context
, 0,
263 ccache
, &creds
, &credsp
))) {
264 DEBUG(1,("krb5_get_credentials failed for %s (%s)\n",
265 principal
, error_message(retval
)));
269 /* cope with the ticket being in the future due to clock skew */
270 if ((unsigned)credsp
->times
.starttime
> time(NULL
)) {
271 time_t t
= time(NULL
);
272 int time_offset
= (unsigned)credsp
->times
.starttime
- t
;
273 DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset
));
274 krb5_set_real_time(context
, t
+ time_offset
+ 1, 0);
278 retval
= krb5_mk_req_extended(context
, auth_context
, ap_req_options
,
279 &in_data
, credsp
, outbuf
);
281 DEBUG(1,("krb5_mk_req_extended failed (%s)\n",
282 error_message(retval
)));
285 krb5_free_creds(context
, credsp
);
288 krb5_free_cred_contents(context
, &creds
);
291 krb5_free_principal(context
, server
);
297 get a kerberos5 ticket for the given service
299 DATA_BLOB
krb5_get_ticket(const char *principal
, time_t time_offset
)
301 krb5_error_code retval
;
304 krb5_context context
;
305 krb5_auth_context auth_context
= NULL
;
307 krb5_enctype enc_types
[] = {
308 #ifdef ENCTYPE_ARCFOUR_HMAC
309 ENCTYPE_ARCFOUR_HMAC
,
315 retval
= krb5_init_context(&context
);
317 DEBUG(1,("krb5_init_context failed (%s)\n",
318 error_message(retval
)));
322 if (time_offset
!= 0) {
323 krb5_set_real_time(context
, time(NULL
) + time_offset
, 0);
326 if ((retval
= krb5_cc_default(context
, &ccdef
))) {
327 DEBUG(1,("krb5_cc_default failed (%s)\n",
328 error_message(retval
)));
332 if ((retval
= krb5_set_default_tgs_ktypes(context
, enc_types
))) {
333 DEBUG(1,("krb5_set_default_tgs_ktypes failed (%s)\n",
334 error_message(retval
)));
338 if ((retval
= krb5_mk_req2(context
,
346 ret
= data_blob(packet
.data
, packet
.length
);
347 /* Hmm, heimdal dooesn't have this - what's the correct call? */
348 /* krb5_free_data_contents(context, &packet); */
349 krb5_free_context(context
);
354 krb5_free_context(context
);
356 return data_blob(NULL
, 0);
359 #else /* HAVE_KRB5 */
360 /* this saves a few linking headaches */
361 DATA_BLOB
krb5_get_ticket(const char *principal
, time_t time_offset
)
363 DEBUG(0,("NO KERBEROS SUPPORT\n"));
364 return data_blob(NULL
, 0);