xref: /freebsd/crypto/heimdal/lib/krb5/init_creds_pw.c (revision ed549cb0c53f8438c52593ce811f6fcc812248e9)
1b528cefcSMark Murray /*
2ae771770SStanislav Sedov  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6ae771770SStanislav Sedov  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7ae771770SStanislav Sedov  *
8b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
9b528cefcSMark Murray  * modification, are permitted provided that the following conditions
10b528cefcSMark Murray  * are met:
11b528cefcSMark Murray  *
12b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
13b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
14b528cefcSMark Murray  *
15b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
16b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
17b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
18b528cefcSMark Murray  *
19b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
20b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
21b528cefcSMark Murray  *    without specific prior written permission.
22b528cefcSMark Murray  *
23b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33b528cefcSMark Murray  * SUCH DAMAGE.
34b528cefcSMark Murray  */
35b528cefcSMark Murray 
36b528cefcSMark Murray #include "krb5_locl.h"
37b528cefcSMark Murray 
38c19800e8SDoug Rabson typedef struct krb5_get_init_creds_ctx {
39c19800e8SDoug Rabson     KDCOptions flags;
40c19800e8SDoug Rabson     krb5_creds cred;
41c19800e8SDoug Rabson     krb5_addresses *addrs;
42c19800e8SDoug Rabson     krb5_enctype *etypes;
43c19800e8SDoug Rabson     krb5_preauthtype *pre_auth_types;
44ae771770SStanislav Sedov     char *in_tkt_service;
45c19800e8SDoug Rabson     unsigned nonce;
46c19800e8SDoug Rabson     unsigned pk_nonce;
47c19800e8SDoug Rabson 
48c19800e8SDoug Rabson     krb5_data req_buffer;
49c19800e8SDoug Rabson     AS_REQ as_req;
50c19800e8SDoug Rabson     int pa_counter;
51c19800e8SDoug Rabson 
52ae771770SStanislav Sedov     /* password and keytab_data is freed on completion */
53ae771770SStanislav Sedov     char *password;
54ae771770SStanislav Sedov     krb5_keytab_key_proc_args *keytab_data;
55ae771770SStanislav Sedov 
56ae771770SStanislav Sedov     krb5_pointer *keyseed;
57ae771770SStanislav Sedov     krb5_s2k_proc keyproc;
58c19800e8SDoug Rabson 
59c19800e8SDoug Rabson     krb5_get_init_creds_tristate req_pac;
60c19800e8SDoug Rabson 
61c19800e8SDoug Rabson     krb5_pk_init_ctx pk_init_ctx;
62c19800e8SDoug Rabson     int ic_flags;
63ae771770SStanislav Sedov 
64ae771770SStanislav Sedov     int used_pa_types;
65ae771770SStanislav Sedov #define  USED_PKINIT	1
66ae771770SStanislav Sedov #define  USED_PKINIT_W2K	2
67ae771770SStanislav Sedov #define  USED_ENC_TS_GUESS	4
68ae771770SStanislav Sedov #define  USED_ENC_TS_INFO	8
69ae771770SStanislav Sedov 
70ae771770SStanislav Sedov     METHOD_DATA md;
71ae771770SStanislav Sedov     KRB_ERROR error;
72ae771770SStanislav Sedov     AS_REP as_rep;
73ae771770SStanislav Sedov     EncKDCRepPart enc_part;
74ae771770SStanislav Sedov 
75ae771770SStanislav Sedov     krb5_prompter_fct prompter;
76ae771770SStanislav Sedov     void *prompter_data;
77ae771770SStanislav Sedov 
78ae771770SStanislav Sedov     struct pa_info_data *ppaid;
79ae771770SStanislav Sedov 
80c19800e8SDoug Rabson } krb5_get_init_creds_ctx;
81c19800e8SDoug Rabson 
82ae771770SStanislav Sedov 
83ae771770SStanislav Sedov struct pa_info_data {
84ae771770SStanislav Sedov     krb5_enctype etype;
85ae771770SStanislav Sedov     krb5_salt salt;
86ae771770SStanislav Sedov     krb5_data *s2kparams;
87ae771770SStanislav Sedov };
88ae771770SStanislav Sedov 
89ae771770SStanislav Sedov static void
free_paid(krb5_context context,struct pa_info_data * ppaid)90ae771770SStanislav Sedov free_paid(krb5_context context, struct pa_info_data *ppaid)
91ae771770SStanislav Sedov {
92ae771770SStanislav Sedov     krb5_free_salt(context, ppaid->salt);
93ae771770SStanislav Sedov     if (ppaid->s2kparams)
94ae771770SStanislav Sedov 	krb5_free_data(context, ppaid->s2kparams);
95ae771770SStanislav Sedov }
96ae771770SStanislav Sedov 
97ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
default_s2k_func(krb5_context context,krb5_enctype type,krb5_const_pointer keyseed,krb5_salt salt,krb5_data * s2kparms,krb5_keyblock ** key)98c19800e8SDoug Rabson default_s2k_func(krb5_context context, krb5_enctype type,
99c19800e8SDoug Rabson 		 krb5_const_pointer keyseed,
100c19800e8SDoug Rabson 		 krb5_salt salt, krb5_data *s2kparms,
101c19800e8SDoug Rabson 		 krb5_keyblock **key)
102c19800e8SDoug Rabson {
103c19800e8SDoug Rabson     krb5_error_code ret;
104c19800e8SDoug Rabson     krb5_data password;
105c19800e8SDoug Rabson     krb5_data opaque;
106c19800e8SDoug Rabson 
107ae771770SStanislav Sedov     _krb5_debug(context, 5, "krb5_get_init_creds: using default_s2k_func");
108ae771770SStanislav Sedov 
109c19800e8SDoug Rabson     password.data = rk_UNCONST(keyseed);
110c19800e8SDoug Rabson     password.length = strlen(keyseed);
111c19800e8SDoug Rabson     if (s2kparms)
112c19800e8SDoug Rabson 	opaque = *s2kparms;
113c19800e8SDoug Rabson     else
114c19800e8SDoug Rabson 	krb5_data_zero(&opaque);
115c19800e8SDoug Rabson 
116c19800e8SDoug Rabson     *key = malloc(sizeof(**key));
117c19800e8SDoug Rabson     if (*key == NULL)
118c19800e8SDoug Rabson 	return ENOMEM;
119c19800e8SDoug Rabson     ret = krb5_string_to_key_data_salt_opaque(context, type, password,
120c19800e8SDoug Rabson 					      salt, opaque, *key);
121c19800e8SDoug Rabson     if (ret) {
122c19800e8SDoug Rabson 	free(*key);
123c19800e8SDoug Rabson 	*key = NULL;
124c19800e8SDoug Rabson     }
125c19800e8SDoug Rabson     return ret;
126c19800e8SDoug Rabson }
127c19800e8SDoug Rabson 
128c19800e8SDoug Rabson static void
free_init_creds_ctx(krb5_context context,krb5_init_creds_context ctx)129ae771770SStanislav Sedov free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx)
130c19800e8SDoug Rabson {
131c19800e8SDoug Rabson     if (ctx->etypes)
132c19800e8SDoug Rabson 	free(ctx->etypes);
133c19800e8SDoug Rabson     if (ctx->pre_auth_types)
134c19800e8SDoug Rabson 	free (ctx->pre_auth_types);
135ae771770SStanislav Sedov     if (ctx->in_tkt_service)
136ae771770SStanislav Sedov 	free(ctx->in_tkt_service);
137ae771770SStanislav Sedov     if (ctx->keytab_data)
138ae771770SStanislav Sedov 	free(ctx->keytab_data);
139ae771770SStanislav Sedov     if (ctx->password) {
140ae771770SStanislav Sedov 	memset(ctx->password, 0, strlen(ctx->password));
141ae771770SStanislav Sedov 	free(ctx->password);
142ae771770SStanislav Sedov     }
143ae771770SStanislav Sedov     krb5_data_free(&ctx->req_buffer);
144ae771770SStanislav Sedov     krb5_free_cred_contents(context, &ctx->cred);
145ae771770SStanislav Sedov     free_METHOD_DATA(&ctx->md);
146ae771770SStanislav Sedov     free_AS_REP(&ctx->as_rep);
147ae771770SStanislav Sedov     free_EncKDCRepPart(&ctx->enc_part);
148ae771770SStanislav Sedov     free_KRB_ERROR(&ctx->error);
149c19800e8SDoug Rabson     free_AS_REQ(&ctx->as_req);
150ae771770SStanislav Sedov     if (ctx->ppaid) {
151ae771770SStanislav Sedov 	free_paid(context, ctx->ppaid);
152ae771770SStanislav Sedov 	free(ctx->ppaid);
153ae771770SStanislav Sedov     }
154ae771770SStanislav Sedov     memset(ctx, 0, sizeof(*ctx));
155c19800e8SDoug Rabson }
156b528cefcSMark Murray 
157b528cefcSMark Murray static int
get_config_time(krb5_context context,const char * realm,const char * name,int def)158b528cefcSMark Murray get_config_time (krb5_context context,
1594137ff4cSJacques Vidrine 		 const char *realm,
1604137ff4cSJacques Vidrine 		 const char *name,
161b528cefcSMark Murray 		 int def)
162b528cefcSMark Murray {
163b528cefcSMark Murray     int ret;
164b528cefcSMark Murray 
165b528cefcSMark Murray     ret = krb5_config_get_time (context, NULL,
166b528cefcSMark Murray 				"realms",
167b528cefcSMark Murray 				realm,
168b528cefcSMark Murray 				name,
169b528cefcSMark Murray 				NULL);
170b528cefcSMark Murray     if (ret >= 0)
171b528cefcSMark Murray 	return ret;
172b528cefcSMark Murray     ret = krb5_config_get_time (context, NULL,
173b528cefcSMark Murray 				"libdefaults",
174b528cefcSMark Murray 				name,
175b528cefcSMark Murray 				NULL);
176b528cefcSMark Murray     if (ret >= 0)
177b528cefcSMark Murray 	return ret;
178b528cefcSMark Murray     return def;
179b528cefcSMark Murray }
180b528cefcSMark Murray 
181b528cefcSMark Murray static krb5_error_code
init_cred(krb5_context context,krb5_creds * cred,krb5_principal client,krb5_deltat start_time,krb5_get_init_creds_opt * options)182b528cefcSMark Murray init_cred (krb5_context context,
183b528cefcSMark Murray 	   krb5_creds *cred,
184b528cefcSMark Murray 	   krb5_principal client,
185b528cefcSMark Murray 	   krb5_deltat start_time,
186b528cefcSMark Murray 	   krb5_get_init_creds_opt *options)
187b528cefcSMark Murray {
188b528cefcSMark Murray     krb5_error_code ret;
189b528cefcSMark Murray     int tmp;
19013e3f4d6SMark Murray     krb5_timestamp now;
191b528cefcSMark Murray 
192b528cefcSMark Murray     krb5_timeofday (context, &now);
193b528cefcSMark Murray 
194b528cefcSMark Murray     memset (cred, 0, sizeof(*cred));
195b528cefcSMark Murray 
196b528cefcSMark Murray     if (client)
197b528cefcSMark Murray 	krb5_copy_principal(context, client, &cred->client);
198b528cefcSMark Murray     else {
199b528cefcSMark Murray 	ret = krb5_get_default_principal (context,
200b528cefcSMark Murray 					  &cred->client);
201b528cefcSMark Murray 	if (ret)
202b528cefcSMark Murray 	    goto out;
203b528cefcSMark Murray     }
204b528cefcSMark Murray 
205b528cefcSMark Murray     if (start_time)
206b528cefcSMark Murray 	cred->times.starttime  = now + start_time;
207b528cefcSMark Murray 
208b528cefcSMark Murray     if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
209b528cefcSMark Murray 	tmp = options->tkt_life;
210b528cefcSMark Murray     else
2114137ff4cSJacques Vidrine 	tmp = 10 * 60 * 60;
212b528cefcSMark Murray     cred->times.endtime = now + tmp;
213b528cefcSMark Murray 
2144137ff4cSJacques Vidrine     if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE) &&
2154137ff4cSJacques Vidrine 	options->renew_life > 0) {
2164137ff4cSJacques Vidrine 	cred->times.renew_till = now + options->renew_life;
2174137ff4cSJacques Vidrine     }
218b528cefcSMark Murray 
219b528cefcSMark Murray     return 0;
220b528cefcSMark Murray 
221b528cefcSMark Murray out:
222c19800e8SDoug Rabson     krb5_free_cred_contents (context, cred);
223b528cefcSMark Murray     return ret;
224b528cefcSMark Murray }
225b528cefcSMark Murray 
226b528cefcSMark Murray /*
2278373020dSJacques Vidrine  * Print a message (str) to the user about the expiration in `lr'
2288373020dSJacques Vidrine  */
2298373020dSJacques Vidrine 
2308373020dSJacques Vidrine static void
report_expiration(krb5_context context,krb5_prompter_fct prompter,krb5_data * data,const char * str,time_t now)2318373020dSJacques Vidrine report_expiration (krb5_context context,
2328373020dSJacques Vidrine 		   krb5_prompter_fct prompter,
2338373020dSJacques Vidrine 		   krb5_data *data,
2348373020dSJacques Vidrine 		   const char *str,
235c19800e8SDoug Rabson 		   time_t now)
2368373020dSJacques Vidrine {
237ae771770SStanislav Sedov     char *p = NULL;
2388373020dSJacques Vidrine 
239ae771770SStanislav Sedov     if (asprintf(&p, "%s%s", str, ctime(&now)) < 0 || p == NULL)
240ae771770SStanislav Sedov 	return;
2418373020dSJacques Vidrine     (*prompter)(context, data, NULL, p, 0, NULL);
2428373020dSJacques Vidrine     free(p);
2438373020dSJacques Vidrine }
2448373020dSJacques Vidrine 
2458373020dSJacques Vidrine /*
246ae771770SStanislav Sedov  * Check the context, and in the case there is a expiration warning,
247ae771770SStanislav Sedov  * use the prompter to print the warning.
248ae771770SStanislav Sedov  *
249ae771770SStanislav Sedov  * @param context A Kerberos 5 context.
250ae771770SStanislav Sedov  * @param options An GIC options structure
251ae771770SStanislav Sedov  * @param ctx The krb5_init_creds_context check for expiration.
252b528cefcSMark Murray  */
253b528cefcSMark Murray 
254ae771770SStanislav Sedov static krb5_error_code
process_last_request(krb5_context context,krb5_get_init_creds_opt * options,krb5_init_creds_context ctx)255ae771770SStanislav Sedov process_last_request(krb5_context context,
256ae771770SStanislav Sedov 		     krb5_get_init_creds_opt *options,
257ae771770SStanislav Sedov 		     krb5_init_creds_context ctx)
258b528cefcSMark Murray {
259ae771770SStanislav Sedov     krb5_const_realm realm;
260ae771770SStanislav Sedov     LastReq *lr;
261ae771770SStanislav Sedov     krb5_boolean reported = FALSE;
26213e3f4d6SMark Murray     krb5_timestamp sec;
263b528cefcSMark Murray     time_t t;
264ae771770SStanislav Sedov     size_t i;
265ae771770SStanislav Sedov 
266ae771770SStanislav Sedov     /*
267ae771770SStanislav Sedov      * First check if there is a API consumer.
268ae771770SStanislav Sedov      */
269ae771770SStanislav Sedov 
270ae771770SStanislav Sedov     realm = krb5_principal_get_realm (context, ctx->cred.client);
271ae771770SStanislav Sedov     lr = &ctx->enc_part.last_req;
272ae771770SStanislav Sedov 
273ae771770SStanislav Sedov     if (options && options->opt_private && options->opt_private->lr.func) {
274ae771770SStanislav Sedov 	krb5_last_req_entry **lre;
275ae771770SStanislav Sedov 
276ae771770SStanislav Sedov 	lre = calloc(lr->len + 1, sizeof(**lre));
277ae771770SStanislav Sedov 	if (lre == NULL) {
278ae771770SStanislav Sedov 	    krb5_set_error_message(context, ENOMEM,
279ae771770SStanislav Sedov 				   N_("malloc: out of memory", ""));
280ae771770SStanislav Sedov 	    return ENOMEM;
281ae771770SStanislav Sedov 	}
282ae771770SStanislav Sedov 	for (i = 0; i < lr->len; i++) {
283ae771770SStanislav Sedov 	    lre[i] = calloc(1, sizeof(*lre[i]));
284ae771770SStanislav Sedov 	    if (lre[i] == NULL)
285ae771770SStanislav Sedov 		break;
286ae771770SStanislav Sedov 	    lre[i]->lr_type = lr->val[i].lr_type;
287ae771770SStanislav Sedov 	    lre[i]->value = lr->val[i].lr_value;
288ae771770SStanislav Sedov 	}
289ae771770SStanislav Sedov 
290ae771770SStanislav Sedov 	(*options->opt_private->lr.func)(context, lre,
291ae771770SStanislav Sedov 					 options->opt_private->lr.ctx);
292ae771770SStanislav Sedov 
293ae771770SStanislav Sedov 	for (i = 0; i < lr->len; i++)
294ae771770SStanislav Sedov 	    free(lre[i]);
295ae771770SStanislav Sedov 	free(lre);
296ae771770SStanislav Sedov     }
297ae771770SStanislav Sedov 
298ae771770SStanislav Sedov     /*
299ae771770SStanislav Sedov      * Now check if we should prompt the user
300ae771770SStanislav Sedov      */
301ae771770SStanislav Sedov 
302ae771770SStanislav Sedov     if (ctx->prompter == NULL)
303ae771770SStanislav Sedov         return 0;
304b528cefcSMark Murray 
305b528cefcSMark Murray     krb5_timeofday (context, &sec);
306b528cefcSMark Murray 
307b528cefcSMark Murray     t = sec + get_config_time (context,
308c19800e8SDoug Rabson 			       realm,
309b528cefcSMark Murray 			       "warn_pwexpire",
310b528cefcSMark Murray 			       7 * 24 * 60 * 60);
311b528cefcSMark Murray 
312b528cefcSMark Murray     for (i = 0; i < lr->len; ++i) {
3138373020dSJacques Vidrine 	if (lr->val[i].lr_value <= t) {
3148373020dSJacques Vidrine 	    switch (abs(lr->val[i].lr_type)) {
3158373020dSJacques Vidrine 	    case LR_PW_EXPTIME :
316ae771770SStanislav Sedov 		report_expiration(context, ctx->prompter,
317ae771770SStanislav Sedov 				  ctx->prompter_data,
3188373020dSJacques Vidrine 				  "Your password will expire at ",
3198373020dSJacques Vidrine 				  lr->val[i].lr_value);
3208373020dSJacques Vidrine 		reported = TRUE;
3218373020dSJacques Vidrine 		break;
3228373020dSJacques Vidrine 	    case LR_ACCT_EXPTIME :
323ae771770SStanislav Sedov 		report_expiration(context, ctx->prompter,
324ae771770SStanislav Sedov 				  ctx->prompter_data,
3258373020dSJacques Vidrine 				  "Your account will expire at ",
3268373020dSJacques Vidrine 				  lr->val[i].lr_value);
3278373020dSJacques Vidrine 		reported = TRUE;
3288373020dSJacques Vidrine 		break;
3298373020dSJacques Vidrine 	    }
330b528cefcSMark Murray 	}
331b528cefcSMark Murray     }
332b528cefcSMark Murray 
3338373020dSJacques Vidrine     if (!reported
334ae771770SStanislav Sedov 	&& ctx->enc_part.key_expiration
335ae771770SStanislav Sedov 	&& *ctx->enc_part.key_expiration <= t) {
336ae771770SStanislav Sedov         report_expiration(context, ctx->prompter,
337ae771770SStanislav Sedov 			  ctx->prompter_data,
3388373020dSJacques Vidrine 			  "Your password/account will expire at ",
339ae771770SStanislav Sedov 			  *ctx->enc_part.key_expiration);
340b528cefcSMark Murray     }
341ae771770SStanislav Sedov     return 0;
342b528cefcSMark Murray }
343b528cefcSMark Murray 
344c19800e8SDoug Rabson static krb5_addresses no_addrs = { 0, NULL };
345c19800e8SDoug Rabson 
346b528cefcSMark Murray static krb5_error_code
get_init_creds_common(krb5_context context,krb5_principal client,krb5_deltat start_time,krb5_get_init_creds_opt * options,krb5_init_creds_context ctx)347b528cefcSMark Murray get_init_creds_common(krb5_context context,
348b528cefcSMark Murray 		      krb5_principal client,
349b528cefcSMark Murray 		      krb5_deltat start_time,
350b528cefcSMark Murray 		      krb5_get_init_creds_opt *options,
351ae771770SStanislav Sedov 		      krb5_init_creds_context ctx)
352b528cefcSMark Murray {
353ae771770SStanislav Sedov     krb5_get_init_creds_opt *default_opt = NULL;
354c19800e8SDoug Rabson     krb5_error_code ret;
355c19800e8SDoug Rabson     krb5_enctype *etypes;
356c19800e8SDoug Rabson     krb5_preauthtype *pre_auth_types;
357c19800e8SDoug Rabson 
358c19800e8SDoug Rabson     memset(ctx, 0, sizeof(*ctx));
359adb0ddaeSAssar Westerlund 
360adb0ddaeSAssar Westerlund     if (options == NULL) {
361ae771770SStanislav Sedov 	const char *realm = krb5_principal_get_realm(context, client);
362ae771770SStanislav Sedov 
363ae771770SStanislav Sedov         krb5_get_init_creds_opt_alloc (context, &default_opt);
364ae771770SStanislav Sedov 	options = default_opt;
365ae771770SStanislav Sedov 	krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options);
366adb0ddaeSAssar Westerlund     }
367b528cefcSMark Murray 
368c19800e8SDoug Rabson     if (options->opt_private) {
369ae771770SStanislav Sedov 	if (options->opt_private->password) {
370ae771770SStanislav Sedov 	    ret = krb5_init_creds_set_password(context, ctx,
371ae771770SStanislav Sedov 					       options->opt_private->password);
372ae771770SStanislav Sedov 	    if (ret)
373ae771770SStanislav Sedov 		goto out;
374ae771770SStanislav Sedov 	}
375ae771770SStanislav Sedov 
376ae771770SStanislav Sedov 	ctx->keyproc = options->opt_private->key_proc;
377c19800e8SDoug Rabson 	ctx->req_pac = options->opt_private->req_pac;
378c19800e8SDoug Rabson 	ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
379c19800e8SDoug Rabson 	ctx->ic_flags = options->opt_private->flags;
380c19800e8SDoug Rabson     } else
381c19800e8SDoug Rabson 	ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;
382c19800e8SDoug Rabson 
383ae771770SStanislav Sedov     if (ctx->keyproc == NULL)
384ae771770SStanislav Sedov 	ctx->keyproc = default_s2k_func;
385c19800e8SDoug Rabson 
386ae771770SStanislav Sedov     /* Enterprise name implicitly turns on canonicalize */
387ae771770SStanislav Sedov     if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) ||
388ae771770SStanislav Sedov 	krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL)
389c19800e8SDoug Rabson 	ctx->flags.canonicalize = 1;
390c19800e8SDoug Rabson 
391c19800e8SDoug Rabson     ctx->pre_auth_types = NULL;
392c19800e8SDoug Rabson     ctx->addrs = NULL;
393c19800e8SDoug Rabson     ctx->etypes = NULL;
394c19800e8SDoug Rabson     ctx->pre_auth_types = NULL;
395c19800e8SDoug Rabson 
396ae771770SStanislav Sedov     ret = init_cred(context, &ctx->cred, client, start_time, options);
397ae771770SStanislav Sedov     if (ret) {
398ae771770SStanislav Sedov 	if (default_opt)
399ae771770SStanislav Sedov 	    krb5_get_init_creds_opt_free(context, default_opt);
400b528cefcSMark Murray 	return ret;
401ae771770SStanislav Sedov     }
402ae771770SStanislav Sedov 
403ae771770SStanislav Sedov     ret = krb5_init_creds_set_service(context, ctx, NULL);
404ae771770SStanislav Sedov     if (ret)
405ae771770SStanislav Sedov 	goto out;
406b528cefcSMark Murray 
407b528cefcSMark Murray     if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
408c19800e8SDoug Rabson 	ctx->flags.forwardable = options->forwardable;
409b528cefcSMark Murray 
410b528cefcSMark Murray     if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
411c19800e8SDoug Rabson 	ctx->flags.proxiable = options->proxiable;
412b528cefcSMark Murray 
413b528cefcSMark Murray     if (start_time)
414c19800e8SDoug Rabson 	ctx->flags.postdated = 1;
415c19800e8SDoug Rabson     if (ctx->cred.times.renew_till)
416c19800e8SDoug Rabson 	ctx->flags.renewable = 1;
417c19800e8SDoug Rabson     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
418c19800e8SDoug Rabson 	ctx->addrs = options->address_list;
419c19800e8SDoug Rabson     } else if (options->opt_private) {
420c19800e8SDoug Rabson 	switch (options->opt_private->addressless) {
421c19800e8SDoug Rabson 	case KRB5_INIT_CREDS_TRISTATE_UNSET:
422c19800e8SDoug Rabson #if KRB5_ADDRESSLESS_DEFAULT == TRUE
423c19800e8SDoug Rabson 	    ctx->addrs = &no_addrs;
424c19800e8SDoug Rabson #else
425c19800e8SDoug Rabson 	    ctx->addrs = NULL;
426c19800e8SDoug Rabson #endif
427c19800e8SDoug Rabson 	    break;
428c19800e8SDoug Rabson 	case KRB5_INIT_CREDS_TRISTATE_FALSE:
429c19800e8SDoug Rabson 	    ctx->addrs = NULL;
430c19800e8SDoug Rabson 	    break;
431c19800e8SDoug Rabson 	case KRB5_INIT_CREDS_TRISTATE_TRUE:
432c19800e8SDoug Rabson 	    ctx->addrs = &no_addrs;
433c19800e8SDoug Rabson 	    break;
434c19800e8SDoug Rabson 	}
435c19800e8SDoug Rabson     }
436b528cefcSMark Murray     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
437ae771770SStanislav Sedov 	if (ctx->etypes)
438ae771770SStanislav Sedov 	    free(ctx->etypes);
439ae771770SStanislav Sedov 
440c19800e8SDoug Rabson 	etypes = malloc((options->etype_list_length + 1)
441b528cefcSMark Murray 			* sizeof(krb5_enctype));
442c19800e8SDoug Rabson 	if (etypes == NULL) {
443ae771770SStanislav Sedov 	    ret = ENOMEM;
444ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
445ae771770SStanislav Sedov 	    goto out;
446adb0ddaeSAssar Westerlund 	}
447c19800e8SDoug Rabson 	memcpy (etypes, options->etype_list,
448b528cefcSMark Murray 		options->etype_list_length * sizeof(krb5_enctype));
449c19800e8SDoug Rabson 	etypes[options->etype_list_length] = ETYPE_NULL;
450c19800e8SDoug Rabson 	ctx->etypes = etypes;
451b528cefcSMark Murray     }
452b528cefcSMark Murray     if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
453c19800e8SDoug Rabson 	pre_auth_types = malloc((options->preauth_list_length + 1)
454b528cefcSMark Murray 				* sizeof(krb5_preauthtype));
455c19800e8SDoug Rabson 	if (pre_auth_types == NULL) {
456ae771770SStanislav Sedov 	    ret = ENOMEM;
457ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
458ae771770SStanislav Sedov 	    goto out;
459adb0ddaeSAssar Westerlund 	}
460c19800e8SDoug Rabson 	memcpy (pre_auth_types, options->preauth_list,
461b528cefcSMark Murray 		options->preauth_list_length * sizeof(krb5_preauthtype));
462c19800e8SDoug Rabson 	pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE;
463c19800e8SDoug Rabson 	ctx->pre_auth_types = pre_auth_types;
464b528cefcSMark Murray     }
4655e9cd1aeSAssar Westerlund     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
466c19800e8SDoug Rabson 	ctx->flags.request_anonymous = options->anonymous;
467ae771770SStanislav Sedov     if (default_opt)
468ae771770SStanislav Sedov         krb5_get_init_creds_opt_free(context, default_opt);
469b528cefcSMark Murray     return 0;
470ae771770SStanislav Sedov  out:
471ae771770SStanislav Sedov     if (default_opt)
472ae771770SStanislav Sedov 	krb5_get_init_creds_opt_free(context, default_opt);
473ae771770SStanislav Sedov     return ret;
474b528cefcSMark Murray }
475b528cefcSMark Murray 
476b528cefcSMark Murray static krb5_error_code
change_password(krb5_context context,krb5_principal client,const char * password,char * newpw,size_t newpw_sz,krb5_prompter_fct prompter,void * data,krb5_get_init_creds_opt * old_options)477b528cefcSMark Murray change_password (krb5_context context,
478b528cefcSMark Murray 		 krb5_principal client,
479b528cefcSMark Murray 		 const char *password,
480b528cefcSMark Murray 		 char *newpw,
481b528cefcSMark Murray 		 size_t newpw_sz,
482b528cefcSMark Murray 		 krb5_prompter_fct prompter,
483b528cefcSMark Murray 		 void *data,
484b528cefcSMark Murray 		 krb5_get_init_creds_opt *old_options)
485b528cefcSMark Murray {
486adb0ddaeSAssar Westerlund     krb5_prompt prompts[2];
487b528cefcSMark Murray     krb5_error_code ret;
488b528cefcSMark Murray     krb5_creds cpw_cred;
489b528cefcSMark Murray     char buf1[BUFSIZ], buf2[BUFSIZ];
4904137ff4cSJacques Vidrine     krb5_data password_data[2];
491b528cefcSMark Murray     int result_code;
492b528cefcSMark Murray     krb5_data result_code_string;
493b528cefcSMark Murray     krb5_data result_string;
494b528cefcSMark Murray     char *p;
495ae771770SStanislav Sedov     krb5_get_init_creds_opt *options;
496b528cefcSMark Murray 
497b528cefcSMark Murray     memset (&cpw_cred, 0, sizeof(cpw_cred));
498b528cefcSMark Murray 
499ae771770SStanislav Sedov     ret = krb5_get_init_creds_opt_alloc(context, &options);
500ae771770SStanislav Sedov     if (ret)
501ae771770SStanislav Sedov         return ret;
502ae771770SStanislav Sedov     krb5_get_init_creds_opt_set_tkt_life (options, 60);
503ae771770SStanislav Sedov     krb5_get_init_creds_opt_set_forwardable (options, FALSE);
504ae771770SStanislav Sedov     krb5_get_init_creds_opt_set_proxiable (options, FALSE);
505c19800e8SDoug Rabson     if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)
506ae771770SStanislav Sedov 	krb5_get_init_creds_opt_set_preauth_list (options,
507b528cefcSMark Murray 						  old_options->preauth_list,
508b528cefcSMark Murray 						  old_options->preauth_list_length);
509b528cefcSMark Murray 
510b528cefcSMark Murray     krb5_data_zero (&result_code_string);
511b528cefcSMark Murray     krb5_data_zero (&result_string);
512b528cefcSMark Murray 
513b528cefcSMark Murray     ret = krb5_get_init_creds_password (context,
514b528cefcSMark Murray 					&cpw_cred,
515b528cefcSMark Murray 					client,
516b528cefcSMark Murray 					password,
517b528cefcSMark Murray 					prompter,
518b528cefcSMark Murray 					data,
519b528cefcSMark Murray 					0,
520b528cefcSMark Murray 					"kadmin/changepw",
521ae771770SStanislav Sedov 					options);
522ae771770SStanislav Sedov     krb5_get_init_creds_opt_free(context, options);
523b528cefcSMark Murray     if (ret)
524b528cefcSMark Murray 	goto out;
525b528cefcSMark Murray 
526b528cefcSMark Murray     for(;;) {
5274137ff4cSJacques Vidrine 	password_data[0].data   = buf1;
5284137ff4cSJacques Vidrine 	password_data[0].length = sizeof(buf1);
529b528cefcSMark Murray 
530adb0ddaeSAssar Westerlund 	prompts[0].hidden = 1;
531adb0ddaeSAssar Westerlund 	prompts[0].prompt = "New password: ";
5324137ff4cSJacques Vidrine 	prompts[0].reply  = &password_data[0];
533adb0ddaeSAssar Westerlund 	prompts[0].type   = KRB5_PROMPT_TYPE_NEW_PASSWORD;
534b528cefcSMark Murray 
5354137ff4cSJacques Vidrine 	password_data[1].data   = buf2;
5364137ff4cSJacques Vidrine 	password_data[1].length = sizeof(buf2);
537b528cefcSMark Murray 
538adb0ddaeSAssar Westerlund 	prompts[1].hidden = 1;
539adb0ddaeSAssar Westerlund 	prompts[1].prompt = "Repeat new password: ";
5404137ff4cSJacques Vidrine 	prompts[1].reply  = &password_data[1];
541adb0ddaeSAssar Westerlund 	prompts[1].type   = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
542b528cefcSMark Murray 
543adb0ddaeSAssar Westerlund 	ret = (*prompter) (context, data, NULL, "Changing password",
544adb0ddaeSAssar Westerlund 			   2, prompts);
545adb0ddaeSAssar Westerlund 	if (ret) {
546adb0ddaeSAssar Westerlund 	    memset (buf1, 0, sizeof(buf1));
547adb0ddaeSAssar Westerlund 	    memset (buf2, 0, sizeof(buf2));
548b528cefcSMark Murray 	    goto out;
549adb0ddaeSAssar Westerlund 	}
550b528cefcSMark Murray 
551b528cefcSMark Murray 	if (strcmp (buf1, buf2) == 0)
552b528cefcSMark Murray 	    break;
553adb0ddaeSAssar Westerlund 	memset (buf1, 0, sizeof(buf1));
554adb0ddaeSAssar Westerlund 	memset (buf2, 0, sizeof(buf2));
555b528cefcSMark Murray     }
556b528cefcSMark Murray 
557ae771770SStanislav Sedov     ret = krb5_set_password (context,
558b528cefcSMark Murray 			     &cpw_cred,
559b528cefcSMark Murray 			     buf1,
560ae771770SStanislav Sedov 			     client,
561b528cefcSMark Murray 			     &result_code,
562b528cefcSMark Murray 			     &result_code_string,
563b528cefcSMark Murray 			     &result_string);
564b528cefcSMark Murray     if (ret)
565b528cefcSMark Murray 	goto out;
566ae771770SStanislav Sedov     if (asprintf(&p, "%s: %.*s\n",
567b528cefcSMark Murray 		 result_code ? "Error" : "Success",
568b528cefcSMark Murray 		 (int)result_string.length,
569ae771770SStanislav Sedov 		 result_string.length > 0 ? (char*)result_string.data : "") < 0)
570ae771770SStanislav Sedov     {
571ae771770SStanislav Sedov 	ret = ENOMEM;
572ae771770SStanislav Sedov 	goto out;
573ae771770SStanislav Sedov     }
574b528cefcSMark Murray 
575ae771770SStanislav Sedov     /* return the result */
576ae771770SStanislav Sedov     (*prompter) (context, data, NULL, p, 0, NULL);
577ae771770SStanislav Sedov 
578b528cefcSMark Murray     free (p);
579b528cefcSMark Murray     if (result_code == 0) {
58013e3f4d6SMark Murray 	strlcpy (newpw, buf1, newpw_sz);
581b528cefcSMark Murray 	ret = 0;
582adb0ddaeSAssar Westerlund     } else {
583b528cefcSMark Murray 	ret = ENOTTY;
584ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
585ae771770SStanislav Sedov 			       N_("failed changing password", ""));
586adb0ddaeSAssar Westerlund     }
587b528cefcSMark Murray 
588b528cefcSMark Murray out:
589b528cefcSMark Murray     memset (buf1, 0, sizeof(buf1));
590b528cefcSMark Murray     memset (buf2, 0, sizeof(buf2));
591b528cefcSMark Murray     krb5_data_free (&result_string);
592b528cefcSMark Murray     krb5_data_free (&result_code_string);
593c19800e8SDoug Rabson     krb5_free_cred_contents (context, &cpw_cred);
594b528cefcSMark Murray     return ret;
595b528cefcSMark Murray }
596b528cefcSMark Murray 
597ae771770SStanislav Sedov 
598ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_keyblock_key_proc(krb5_context context,krb5_keytype type,krb5_data * salt,krb5_const_pointer keyseed,krb5_keyblock ** key)599c19800e8SDoug Rabson krb5_keyblock_key_proc (krb5_context context,
600c19800e8SDoug Rabson 			krb5_keytype type,
601c19800e8SDoug Rabson 			krb5_data *salt,
602c19800e8SDoug Rabson 			krb5_const_pointer keyseed,
603c19800e8SDoug Rabson 			krb5_keyblock **key)
604c19800e8SDoug Rabson {
605c19800e8SDoug Rabson     return krb5_copy_keyblock (context, keyseed, key);
606c19800e8SDoug Rabson }
607c19800e8SDoug Rabson 
608c19800e8SDoug Rabson /*
609c19800e8SDoug Rabson  *
610c19800e8SDoug Rabson  */
611c19800e8SDoug Rabson 
612c19800e8SDoug Rabson static krb5_error_code
init_as_req(krb5_context context,KDCOptions opts,const krb5_creds * creds,const krb5_addresses * addrs,const krb5_enctype * etypes,AS_REQ * a)613ae771770SStanislav Sedov init_as_req (krb5_context context,
614c19800e8SDoug Rabson 	     KDCOptions opts,
615c19800e8SDoug Rabson 	     const krb5_creds *creds,
616c19800e8SDoug Rabson 	     const krb5_addresses *addrs,
617c19800e8SDoug Rabson 	     const krb5_enctype *etypes,
618c19800e8SDoug Rabson 	     AS_REQ *a)
619c19800e8SDoug Rabson {
620c19800e8SDoug Rabson     krb5_error_code ret;
621c19800e8SDoug Rabson 
622c19800e8SDoug Rabson     memset(a, 0, sizeof(*a));
623c19800e8SDoug Rabson 
624c19800e8SDoug Rabson     a->pvno = 5;
625c19800e8SDoug Rabson     a->msg_type = krb_as_req;
626c19800e8SDoug Rabson     a->req_body.kdc_options = opts;
627c19800e8SDoug Rabson     a->req_body.cname = malloc(sizeof(*a->req_body.cname));
628c19800e8SDoug Rabson     if (a->req_body.cname == NULL) {
629c19800e8SDoug Rabson 	ret = ENOMEM;
630ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
631c19800e8SDoug Rabson 	goto fail;
632c19800e8SDoug Rabson     }
633c19800e8SDoug Rabson     a->req_body.sname = malloc(sizeof(*a->req_body.sname));
634c19800e8SDoug Rabson     if (a->req_body.sname == NULL) {
635c19800e8SDoug Rabson 	ret = ENOMEM;
636ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
637c19800e8SDoug Rabson 	goto fail;
638c19800e8SDoug Rabson     }
639c19800e8SDoug Rabson 
640c19800e8SDoug Rabson     ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
641c19800e8SDoug Rabson     if (ret)
642c19800e8SDoug Rabson 	goto fail;
643c19800e8SDoug Rabson     ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
644c19800e8SDoug Rabson     if (ret)
645c19800e8SDoug Rabson 	goto fail;
646c19800e8SDoug Rabson 
647c19800e8SDoug Rabson     ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
648c19800e8SDoug Rabson     if (ret)
649c19800e8SDoug Rabson 	goto fail;
650c19800e8SDoug Rabson 
651c19800e8SDoug Rabson     if(creds->times.starttime) {
652c19800e8SDoug Rabson 	a->req_body.from = malloc(sizeof(*a->req_body.from));
653c19800e8SDoug Rabson 	if (a->req_body.from == NULL) {
654c19800e8SDoug Rabson 	    ret = ENOMEM;
655ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
656c19800e8SDoug Rabson 	    goto fail;
657c19800e8SDoug Rabson 	}
658c19800e8SDoug Rabson 	*a->req_body.from = creds->times.starttime;
659c19800e8SDoug Rabson     }
660c19800e8SDoug Rabson     if(creds->times.endtime){
661c19800e8SDoug Rabson 	ALLOC(a->req_body.till, 1);
662c19800e8SDoug Rabson 	*a->req_body.till = creds->times.endtime;
663c19800e8SDoug Rabson     }
664c19800e8SDoug Rabson     if(creds->times.renew_till){
665c19800e8SDoug Rabson 	a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
666c19800e8SDoug Rabson 	if (a->req_body.rtime == NULL) {
667c19800e8SDoug Rabson 	    ret = ENOMEM;
668ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
669c19800e8SDoug Rabson 	    goto fail;
670c19800e8SDoug Rabson 	}
671c19800e8SDoug Rabson 	*a->req_body.rtime = creds->times.renew_till;
672c19800e8SDoug Rabson     }
673c19800e8SDoug Rabson     a->req_body.nonce = 0;
674ae771770SStanislav Sedov     ret = _krb5_init_etype(context,
675ae771770SStanislav Sedov 			   KRB5_PDU_AS_REQUEST,
676c19800e8SDoug Rabson 			   &a->req_body.etype.len,
677c19800e8SDoug Rabson 			   &a->req_body.etype.val,
678c19800e8SDoug Rabson 			   etypes);
679c19800e8SDoug Rabson     if (ret)
680c19800e8SDoug Rabson 	goto fail;
681c19800e8SDoug Rabson 
682c19800e8SDoug Rabson     /*
683c19800e8SDoug Rabson      * This means no addresses
684c19800e8SDoug Rabson      */
685c19800e8SDoug Rabson 
686c19800e8SDoug Rabson     if (addrs && addrs->len == 0) {
687c19800e8SDoug Rabson 	a->req_body.addresses = NULL;
688c19800e8SDoug Rabson     } else {
689c19800e8SDoug Rabson 	a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
690c19800e8SDoug Rabson 	if (a->req_body.addresses == NULL) {
691c19800e8SDoug Rabson 	    ret = ENOMEM;
692ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
693c19800e8SDoug Rabson 	    goto fail;
694c19800e8SDoug Rabson 	}
695c19800e8SDoug Rabson 
696c19800e8SDoug Rabson 	if (addrs)
697c19800e8SDoug Rabson 	    ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
698c19800e8SDoug Rabson 	else {
699c19800e8SDoug Rabson 	    ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
700c19800e8SDoug Rabson 	    if(ret == 0 && a->req_body.addresses->len == 0) {
701c19800e8SDoug Rabson 		free(a->req_body.addresses);
702c19800e8SDoug Rabson 		a->req_body.addresses = NULL;
703c19800e8SDoug Rabson 	    }
704c19800e8SDoug Rabson 	}
705c19800e8SDoug Rabson 	if (ret)
706c19800e8SDoug Rabson 	    goto fail;
707c19800e8SDoug Rabson     }
708c19800e8SDoug Rabson 
709c19800e8SDoug Rabson     a->req_body.enc_authorization_data = NULL;
710c19800e8SDoug Rabson     a->req_body.additional_tickets = NULL;
711c19800e8SDoug Rabson 
712c19800e8SDoug Rabson     a->padata = NULL;
713c19800e8SDoug Rabson 
714c19800e8SDoug Rabson     return 0;
715c19800e8SDoug Rabson  fail:
716c19800e8SDoug Rabson     free_AS_REQ(a);
717c19800e8SDoug Rabson     memset(a, 0, sizeof(*a));
718c19800e8SDoug Rabson     return ret;
719c19800e8SDoug Rabson }
720c19800e8SDoug Rabson 
721c19800e8SDoug Rabson 
722c19800e8SDoug Rabson static krb5_error_code
set_paid(struct pa_info_data * paid,krb5_context context,krb5_enctype etype,krb5_salttype salttype,void * salt_string,size_t salt_len,krb5_data * s2kparams)723c19800e8SDoug Rabson set_paid(struct pa_info_data *paid, krb5_context context,
724c19800e8SDoug Rabson 	 krb5_enctype etype,
725c19800e8SDoug Rabson 	 krb5_salttype salttype, void *salt_string, size_t salt_len,
726c19800e8SDoug Rabson 	 krb5_data *s2kparams)
727c19800e8SDoug Rabson {
728c19800e8SDoug Rabson     paid->etype = etype;
729c19800e8SDoug Rabson     paid->salt.salttype = salttype;
730c19800e8SDoug Rabson     paid->salt.saltvalue.data = malloc(salt_len + 1);
731c19800e8SDoug Rabson     if (paid->salt.saltvalue.data == NULL) {
732ae771770SStanislav Sedov 	krb5_clear_error_message(context);
733c19800e8SDoug Rabson 	return ENOMEM;
734c19800e8SDoug Rabson     }
735c19800e8SDoug Rabson     memcpy(paid->salt.saltvalue.data, salt_string, salt_len);
736c19800e8SDoug Rabson     ((char *)paid->salt.saltvalue.data)[salt_len] = '\0';
737c19800e8SDoug Rabson     paid->salt.saltvalue.length = salt_len;
738c19800e8SDoug Rabson     if (s2kparams) {
739c19800e8SDoug Rabson 	krb5_error_code ret;
740c19800e8SDoug Rabson 
741c19800e8SDoug Rabson 	ret = krb5_copy_data(context, s2kparams, &paid->s2kparams);
742c19800e8SDoug Rabson 	if (ret) {
743ae771770SStanislav Sedov 	    krb5_clear_error_message(context);
744c19800e8SDoug Rabson 	    krb5_free_salt(context, paid->salt);
745c19800e8SDoug Rabson 	    return ret;
746c19800e8SDoug Rabson 	}
747c19800e8SDoug Rabson     } else
748c19800e8SDoug Rabson 	paid->s2kparams = NULL;
749c19800e8SDoug Rabson 
750c19800e8SDoug Rabson     return 0;
751c19800e8SDoug Rabson }
752c19800e8SDoug Rabson 
753c19800e8SDoug Rabson static struct pa_info_data *
pa_etype_info2(krb5_context context,const krb5_principal client,const AS_REQ * asreq,struct pa_info_data * paid,heim_octet_string * data)754c19800e8SDoug Rabson pa_etype_info2(krb5_context context,
755c19800e8SDoug Rabson 	       const krb5_principal client,
756c19800e8SDoug Rabson 	       const AS_REQ *asreq,
757c19800e8SDoug Rabson 	       struct pa_info_data *paid,
758c19800e8SDoug Rabson 	       heim_octet_string *data)
759c19800e8SDoug Rabson {
760c19800e8SDoug Rabson     krb5_error_code ret;
761c19800e8SDoug Rabson     ETYPE_INFO2 e;
762c19800e8SDoug Rabson     size_t sz;
763ae771770SStanislav Sedov     size_t i, j;
764c19800e8SDoug Rabson 
765c19800e8SDoug Rabson     memset(&e, 0, sizeof(e));
766c19800e8SDoug Rabson     ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz);
767c19800e8SDoug Rabson     if (ret)
768c19800e8SDoug Rabson 	goto out;
769c19800e8SDoug Rabson     if (e.len == 0)
770c19800e8SDoug Rabson 	goto out;
771c19800e8SDoug Rabson     for (j = 0; j < asreq->req_body.etype.len; j++) {
772c19800e8SDoug Rabson 	for (i = 0; i < e.len; i++) {
773c19800e8SDoug Rabson 	    if (asreq->req_body.etype.val[j] == e.val[i].etype) {
774c19800e8SDoug Rabson 		krb5_salt salt;
775c19800e8SDoug Rabson 		if (e.val[i].salt == NULL)
776c19800e8SDoug Rabson 		    ret = krb5_get_pw_salt(context, client, &salt);
777c19800e8SDoug Rabson 		else {
778c19800e8SDoug Rabson 		    salt.saltvalue.data = *e.val[i].salt;
779c19800e8SDoug Rabson 		    salt.saltvalue.length = strlen(*e.val[i].salt);
780c19800e8SDoug Rabson 		    ret = 0;
781c19800e8SDoug Rabson 		}
782c19800e8SDoug Rabson 		if (ret == 0)
783c19800e8SDoug Rabson 		    ret = set_paid(paid, context, e.val[i].etype,
784c19800e8SDoug Rabson 				   KRB5_PW_SALT,
785c19800e8SDoug Rabson 				   salt.saltvalue.data,
786c19800e8SDoug Rabson 				   salt.saltvalue.length,
787c19800e8SDoug Rabson 				   e.val[i].s2kparams);
788c19800e8SDoug Rabson 		if (e.val[i].salt == NULL)
789c19800e8SDoug Rabson 		    krb5_free_salt(context, salt);
790c19800e8SDoug Rabson 		if (ret == 0) {
791c19800e8SDoug Rabson 		    free_ETYPE_INFO2(&e);
792c19800e8SDoug Rabson 		    return paid;
793c19800e8SDoug Rabson 		}
794c19800e8SDoug Rabson 	    }
795c19800e8SDoug Rabson 	}
796c19800e8SDoug Rabson     }
797c19800e8SDoug Rabson  out:
798c19800e8SDoug Rabson     free_ETYPE_INFO2(&e);
799c19800e8SDoug Rabson     return NULL;
800c19800e8SDoug Rabson }
801c19800e8SDoug Rabson 
802c19800e8SDoug Rabson static struct pa_info_data *
pa_etype_info(krb5_context context,const krb5_principal client,const AS_REQ * asreq,struct pa_info_data * paid,heim_octet_string * data)803c19800e8SDoug Rabson pa_etype_info(krb5_context context,
804c19800e8SDoug Rabson 	      const krb5_principal client,
805c19800e8SDoug Rabson 	      const AS_REQ *asreq,
806c19800e8SDoug Rabson 	      struct pa_info_data *paid,
807c19800e8SDoug Rabson 	      heim_octet_string *data)
808c19800e8SDoug Rabson {
809c19800e8SDoug Rabson     krb5_error_code ret;
810c19800e8SDoug Rabson     ETYPE_INFO e;
811c19800e8SDoug Rabson     size_t sz;
812ae771770SStanislav Sedov     size_t i, j;
813c19800e8SDoug Rabson 
814c19800e8SDoug Rabson     memset(&e, 0, sizeof(e));
815c19800e8SDoug Rabson     ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz);
816c19800e8SDoug Rabson     if (ret)
817c19800e8SDoug Rabson 	goto out;
818c19800e8SDoug Rabson     if (e.len == 0)
819c19800e8SDoug Rabson 	goto out;
820c19800e8SDoug Rabson     for (j = 0; j < asreq->req_body.etype.len; j++) {
821c19800e8SDoug Rabson 	for (i = 0; i < e.len; i++) {
822c19800e8SDoug Rabson 	    if (asreq->req_body.etype.val[j] == e.val[i].etype) {
823c19800e8SDoug Rabson 		krb5_salt salt;
824c19800e8SDoug Rabson 		salt.salttype = KRB5_PW_SALT;
825c19800e8SDoug Rabson 		if (e.val[i].salt == NULL)
826c19800e8SDoug Rabson 		    ret = krb5_get_pw_salt(context, client, &salt);
827c19800e8SDoug Rabson 		else {
828c19800e8SDoug Rabson 		    salt.saltvalue = *e.val[i].salt;
829c19800e8SDoug Rabson 		    ret = 0;
830c19800e8SDoug Rabson 		}
831c19800e8SDoug Rabson 		if (e.val[i].salttype)
832c19800e8SDoug Rabson 		    salt.salttype = *e.val[i].salttype;
833c19800e8SDoug Rabson 		if (ret == 0) {
834c19800e8SDoug Rabson 		    ret = set_paid(paid, context, e.val[i].etype,
835c19800e8SDoug Rabson 				   salt.salttype,
836c19800e8SDoug Rabson 				   salt.saltvalue.data,
837c19800e8SDoug Rabson 				   salt.saltvalue.length,
838c19800e8SDoug Rabson 				   NULL);
839c19800e8SDoug Rabson 		    if (e.val[i].salt == NULL)
840c19800e8SDoug Rabson 			krb5_free_salt(context, salt);
841c19800e8SDoug Rabson 		}
842c19800e8SDoug Rabson 		if (ret == 0) {
843c19800e8SDoug Rabson 		    free_ETYPE_INFO(&e);
844c19800e8SDoug Rabson 		    return paid;
845c19800e8SDoug Rabson 		}
846c19800e8SDoug Rabson 	    }
847c19800e8SDoug Rabson 	}
848c19800e8SDoug Rabson     }
849c19800e8SDoug Rabson  out:
850c19800e8SDoug Rabson     free_ETYPE_INFO(&e);
851c19800e8SDoug Rabson     return NULL;
852c19800e8SDoug Rabson }
853c19800e8SDoug Rabson 
854c19800e8SDoug Rabson static struct pa_info_data *
pa_pw_or_afs3_salt(krb5_context context,const krb5_principal client,const AS_REQ * asreq,struct pa_info_data * paid,heim_octet_string * data)855c19800e8SDoug Rabson pa_pw_or_afs3_salt(krb5_context context,
856c19800e8SDoug Rabson 		   const krb5_principal client,
857c19800e8SDoug Rabson 		   const AS_REQ *asreq,
858c19800e8SDoug Rabson 		   struct pa_info_data *paid,
859c19800e8SDoug Rabson 		   heim_octet_string *data)
860c19800e8SDoug Rabson {
861c19800e8SDoug Rabson     krb5_error_code ret;
862c19800e8SDoug Rabson     if (paid->etype == ENCTYPE_NULL)
863c19800e8SDoug Rabson 	return NULL;
864c19800e8SDoug Rabson     ret = set_paid(paid, context,
865c19800e8SDoug Rabson 		   paid->etype,
866c19800e8SDoug Rabson 		   paid->salt.salttype,
867c19800e8SDoug Rabson 		   data->data,
868c19800e8SDoug Rabson 		   data->length,
869c19800e8SDoug Rabson 		   NULL);
870c19800e8SDoug Rabson     if (ret)
871c19800e8SDoug Rabson 	return NULL;
872c19800e8SDoug Rabson     return paid;
873c19800e8SDoug Rabson }
874c19800e8SDoug Rabson 
875c19800e8SDoug Rabson 
876c19800e8SDoug Rabson struct pa_info {
877c19800e8SDoug Rabson     krb5_preauthtype type;
878c19800e8SDoug Rabson     struct pa_info_data *(*salt_info)(krb5_context,
879c19800e8SDoug Rabson 				      const krb5_principal,
880c19800e8SDoug Rabson 				      const AS_REQ *,
881c19800e8SDoug Rabson 				      struct pa_info_data *,
882c19800e8SDoug Rabson 				      heim_octet_string *);
883c19800e8SDoug Rabson };
884c19800e8SDoug Rabson 
885c19800e8SDoug Rabson static struct pa_info pa_prefs[] = {
886c19800e8SDoug Rabson     { KRB5_PADATA_ETYPE_INFO2, pa_etype_info2 },
887c19800e8SDoug Rabson     { KRB5_PADATA_ETYPE_INFO, pa_etype_info },
888c19800e8SDoug Rabson     { KRB5_PADATA_PW_SALT, pa_pw_or_afs3_salt },
889c19800e8SDoug Rabson     { KRB5_PADATA_AFS3_SALT, pa_pw_or_afs3_salt }
890c19800e8SDoug Rabson };
891c19800e8SDoug Rabson 
892c19800e8SDoug Rabson static PA_DATA *
find_pa_data(const METHOD_DATA * md,unsigned type)893ae771770SStanislav Sedov find_pa_data(const METHOD_DATA *md, unsigned type)
894c19800e8SDoug Rabson {
895ae771770SStanislav Sedov     size_t i;
896c19800e8SDoug Rabson     if (md == NULL)
897c19800e8SDoug Rabson 	return NULL;
898c19800e8SDoug Rabson     for (i = 0; i < md->len; i++)
899c19800e8SDoug Rabson 	if (md->val[i].padata_type == type)
900c19800e8SDoug Rabson 	    return &md->val[i];
901c19800e8SDoug Rabson     return NULL;
902c19800e8SDoug Rabson }
903c19800e8SDoug Rabson 
904c19800e8SDoug Rabson static struct pa_info_data *
process_pa_info(krb5_context context,const krb5_principal client,const AS_REQ * asreq,struct pa_info_data * paid,METHOD_DATA * md)905c19800e8SDoug Rabson process_pa_info(krb5_context context,
906c19800e8SDoug Rabson 		const krb5_principal client,
907c19800e8SDoug Rabson 		const AS_REQ *asreq,
908c19800e8SDoug Rabson 		struct pa_info_data *paid,
909c19800e8SDoug Rabson 		METHOD_DATA *md)
910c19800e8SDoug Rabson {
911c19800e8SDoug Rabson     struct pa_info_data *p = NULL;
912ae771770SStanislav Sedov     size_t i;
913c19800e8SDoug Rabson 
914c19800e8SDoug Rabson     for (i = 0; p == NULL && i < sizeof(pa_prefs)/sizeof(pa_prefs[0]); i++) {
915c19800e8SDoug Rabson 	PA_DATA *pa = find_pa_data(md, pa_prefs[i].type);
916c19800e8SDoug Rabson 	if (pa == NULL)
917c19800e8SDoug Rabson 	    continue;
918ae771770SStanislav Sedov 	paid->salt.salttype = (krb5_salttype)pa_prefs[i].type;
919c19800e8SDoug Rabson 	p = (*pa_prefs[i].salt_info)(context, client, asreq,
920c19800e8SDoug Rabson 				     paid, &pa->padata_value);
921c19800e8SDoug Rabson     }
922c19800e8SDoug Rabson     return p;
923c19800e8SDoug Rabson }
924c19800e8SDoug Rabson 
925c19800e8SDoug Rabson static krb5_error_code
make_pa_enc_timestamp(krb5_context context,METHOD_DATA * md,krb5_enctype etype,krb5_keyblock * key)926c19800e8SDoug Rabson make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md,
927c19800e8SDoug Rabson 		      krb5_enctype etype, krb5_keyblock *key)
928c19800e8SDoug Rabson {
929c19800e8SDoug Rabson     PA_ENC_TS_ENC p;
930c19800e8SDoug Rabson     unsigned char *buf;
931c19800e8SDoug Rabson     size_t buf_size;
932ae771770SStanislav Sedov     size_t len = 0;
933c19800e8SDoug Rabson     EncryptedData encdata;
934c19800e8SDoug Rabson     krb5_error_code ret;
935c19800e8SDoug Rabson     int32_t usec;
936c19800e8SDoug Rabson     int usec2;
937c19800e8SDoug Rabson     krb5_crypto crypto;
938c19800e8SDoug Rabson 
939c19800e8SDoug Rabson     krb5_us_timeofday (context, &p.patimestamp, &usec);
940c19800e8SDoug Rabson     usec2         = usec;
941c19800e8SDoug Rabson     p.pausec      = &usec2;
942c19800e8SDoug Rabson 
943c19800e8SDoug Rabson     ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
944c19800e8SDoug Rabson     if (ret)
945c19800e8SDoug Rabson 	return ret;
946c19800e8SDoug Rabson     if(buf_size != len)
947c19800e8SDoug Rabson 	krb5_abortx(context, "internal error in ASN.1 encoder");
948c19800e8SDoug Rabson 
949c19800e8SDoug Rabson     ret = krb5_crypto_init(context, key, 0, &crypto);
950c19800e8SDoug Rabson     if (ret) {
951c19800e8SDoug Rabson 	free(buf);
952c19800e8SDoug Rabson 	return ret;
953c19800e8SDoug Rabson     }
954c19800e8SDoug Rabson     ret = krb5_encrypt_EncryptedData(context,
955c19800e8SDoug Rabson 				     crypto,
956c19800e8SDoug Rabson 				     KRB5_KU_PA_ENC_TIMESTAMP,
957c19800e8SDoug Rabson 				     buf,
958c19800e8SDoug Rabson 				     len,
959c19800e8SDoug Rabson 				     0,
960c19800e8SDoug Rabson 				     &encdata);
961c19800e8SDoug Rabson     free(buf);
962c19800e8SDoug Rabson     krb5_crypto_destroy(context, crypto);
963c19800e8SDoug Rabson     if (ret)
964c19800e8SDoug Rabson 	return ret;
965c19800e8SDoug Rabson 
966c19800e8SDoug Rabson     ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
967c19800e8SDoug Rabson     free_EncryptedData(&encdata);
968c19800e8SDoug Rabson     if (ret)
969c19800e8SDoug Rabson 	return ret;
970c19800e8SDoug Rabson     if(buf_size != len)
971c19800e8SDoug Rabson 	krb5_abortx(context, "internal error in ASN.1 encoder");
972c19800e8SDoug Rabson 
973c19800e8SDoug Rabson     ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len);
974c19800e8SDoug Rabson     if (ret)
975c19800e8SDoug Rabson 	free(buf);
976c19800e8SDoug Rabson     return ret;
977c19800e8SDoug Rabson }
978c19800e8SDoug Rabson 
979c19800e8SDoug Rabson static krb5_error_code
add_enc_ts_padata(krb5_context context,METHOD_DATA * md,krb5_principal client,krb5_s2k_proc keyproc,krb5_const_pointer keyseed,krb5_enctype * enctypes,unsigned netypes,krb5_salt * salt,krb5_data * s2kparams)980c19800e8SDoug Rabson add_enc_ts_padata(krb5_context context,
981c19800e8SDoug Rabson 		  METHOD_DATA *md,
982c19800e8SDoug Rabson 		  krb5_principal client,
983ae771770SStanislav Sedov 		  krb5_s2k_proc keyproc,
984c19800e8SDoug Rabson 		  krb5_const_pointer keyseed,
985c19800e8SDoug Rabson 		  krb5_enctype *enctypes,
986c19800e8SDoug Rabson 		  unsigned netypes,
987c19800e8SDoug Rabson 		  krb5_salt *salt,
988c19800e8SDoug Rabson 		  krb5_data *s2kparams)
989c19800e8SDoug Rabson {
990c19800e8SDoug Rabson     krb5_error_code ret;
991c19800e8SDoug Rabson     krb5_salt salt2;
992c19800e8SDoug Rabson     krb5_enctype *ep;
993ae771770SStanislav Sedov     size_t i;
994c19800e8SDoug Rabson 
995c19800e8SDoug Rabson     if(salt == NULL) {
996c19800e8SDoug Rabson 	/* default to standard salt */
997c19800e8SDoug Rabson 	ret = krb5_get_pw_salt (context, client, &salt2);
998ae771770SStanislav Sedov 	if (ret)
999ae771770SStanislav Sedov 	    return ret;
1000c19800e8SDoug Rabson 	salt = &salt2;
1001c19800e8SDoug Rabson     }
1002c19800e8SDoug Rabson     if (!enctypes) {
1003c19800e8SDoug Rabson 	enctypes = context->etypes;
1004c19800e8SDoug Rabson 	netypes = 0;
1005c19800e8SDoug Rabson 	for (ep = enctypes; *ep != ETYPE_NULL; ep++)
1006c19800e8SDoug Rabson 	    netypes++;
1007c19800e8SDoug Rabson     }
1008c19800e8SDoug Rabson 
1009c19800e8SDoug Rabson     for (i = 0; i < netypes; ++i) {
1010c19800e8SDoug Rabson 	krb5_keyblock *key;
1011c19800e8SDoug Rabson 
1012ae771770SStanislav Sedov 	_krb5_debug(context, 5, "krb5_get_init_creds: using ENC-TS with enctype %d", enctypes[i]);
1013ae771770SStanislav Sedov 
1014ae771770SStanislav Sedov 	ret = (*keyproc)(context, enctypes[i], keyseed,
1015c19800e8SDoug Rabson 			 *salt, s2kparams, &key);
1016c19800e8SDoug Rabson 	if (ret)
1017c19800e8SDoug Rabson 	    continue;
1018c19800e8SDoug Rabson 	ret = make_pa_enc_timestamp (context, md, enctypes[i], key);
1019c19800e8SDoug Rabson 	krb5_free_keyblock (context, key);
1020c19800e8SDoug Rabson 	if (ret)
1021c19800e8SDoug Rabson 	    return ret;
1022c19800e8SDoug Rabson     }
1023c19800e8SDoug Rabson     if(salt == &salt2)
1024c19800e8SDoug Rabson 	krb5_free_salt(context, salt2);
1025c19800e8SDoug Rabson     return 0;
1026c19800e8SDoug Rabson }
1027c19800e8SDoug Rabson 
1028c19800e8SDoug Rabson static krb5_error_code
pa_data_to_md_ts_enc(krb5_context context,const AS_REQ * a,const krb5_principal client,krb5_get_init_creds_ctx * ctx,struct pa_info_data * ppaid,METHOD_DATA * md)1029c19800e8SDoug Rabson pa_data_to_md_ts_enc(krb5_context context,
1030c19800e8SDoug Rabson 		     const AS_REQ *a,
1031c19800e8SDoug Rabson 		     const krb5_principal client,
1032c19800e8SDoug Rabson 		     krb5_get_init_creds_ctx *ctx,
1033c19800e8SDoug Rabson 		     struct pa_info_data *ppaid,
1034c19800e8SDoug Rabson 		     METHOD_DATA *md)
1035c19800e8SDoug Rabson {
1036ae771770SStanislav Sedov     if (ctx->keyproc == NULL || ctx->keyseed == NULL)
1037c19800e8SDoug Rabson 	return 0;
1038c19800e8SDoug Rabson 
1039c19800e8SDoug Rabson     if (ppaid) {
1040c19800e8SDoug Rabson 	add_enc_ts_padata(context, md, client,
1041ae771770SStanislav Sedov 			  ctx->keyproc, ctx->keyseed,
1042c19800e8SDoug Rabson 			  &ppaid->etype, 1,
1043c19800e8SDoug Rabson 			  &ppaid->salt, ppaid->s2kparams);
1044c19800e8SDoug Rabson     } else {
1045c19800e8SDoug Rabson 	krb5_salt salt;
1046c19800e8SDoug Rabson 
1047ae771770SStanislav Sedov 	_krb5_debug(context, 5, "krb5_get_init_creds: pa-info not found, guessing salt");
1048ae771770SStanislav Sedov 
1049c19800e8SDoug Rabson 	/* make a v5 salted pa-data */
1050c19800e8SDoug Rabson 	add_enc_ts_padata(context, md, client,
1051ae771770SStanislav Sedov 			  ctx->keyproc, ctx->keyseed,
1052c19800e8SDoug Rabson 			  a->req_body.etype.val, a->req_body.etype.len,
1053c19800e8SDoug Rabson 			  NULL, NULL);
1054c19800e8SDoug Rabson 
1055c19800e8SDoug Rabson 	/* make a v4 salted pa-data */
1056c19800e8SDoug Rabson 	salt.salttype = KRB5_PW_SALT;
1057c19800e8SDoug Rabson 	krb5_data_zero(&salt.saltvalue);
1058c19800e8SDoug Rabson 	add_enc_ts_padata(context, md, client,
1059ae771770SStanislav Sedov 			  ctx->keyproc, ctx->keyseed,
1060c19800e8SDoug Rabson 			  a->req_body.etype.val, a->req_body.etype.len,
1061c19800e8SDoug Rabson 			  &salt, NULL);
1062c19800e8SDoug Rabson     }
1063c19800e8SDoug Rabson     return 0;
1064c19800e8SDoug Rabson }
1065c19800e8SDoug Rabson 
1066c19800e8SDoug Rabson static krb5_error_code
pa_data_to_key_plain(krb5_context context,const krb5_principal client,krb5_get_init_creds_ctx * ctx,krb5_salt salt,krb5_data * s2kparams,krb5_enctype etype,krb5_keyblock ** key)1067c19800e8SDoug Rabson pa_data_to_key_plain(krb5_context context,
1068c19800e8SDoug Rabson 		     const krb5_principal client,
1069c19800e8SDoug Rabson 		     krb5_get_init_creds_ctx *ctx,
1070c19800e8SDoug Rabson 		     krb5_salt salt,
1071c19800e8SDoug Rabson 		     krb5_data *s2kparams,
1072c19800e8SDoug Rabson 		     krb5_enctype etype,
1073c19800e8SDoug Rabson 		     krb5_keyblock **key)
1074c19800e8SDoug Rabson {
1075c19800e8SDoug Rabson     krb5_error_code ret;
1076c19800e8SDoug Rabson 
1077ae771770SStanislav Sedov     ret = (*ctx->keyproc)(context, etype, ctx->keyseed,
1078c19800e8SDoug Rabson 			   salt, s2kparams, key);
1079c19800e8SDoug Rabson     return ret;
1080c19800e8SDoug Rabson }
1081c19800e8SDoug Rabson 
1082c19800e8SDoug Rabson 
1083c19800e8SDoug Rabson static krb5_error_code
pa_data_to_md_pkinit(krb5_context context,const AS_REQ * a,const krb5_principal client,int win2k,krb5_get_init_creds_ctx * ctx,METHOD_DATA * md)1084c19800e8SDoug Rabson pa_data_to_md_pkinit(krb5_context context,
1085c19800e8SDoug Rabson 		     const AS_REQ *a,
1086c19800e8SDoug Rabson 		     const krb5_principal client,
1087ae771770SStanislav Sedov 		     int win2k,
1088c19800e8SDoug Rabson 		     krb5_get_init_creds_ctx *ctx,
1089c19800e8SDoug Rabson 		     METHOD_DATA *md)
1090c19800e8SDoug Rabson {
1091c19800e8SDoug Rabson     if (ctx->pk_init_ctx == NULL)
1092c19800e8SDoug Rabson 	return 0;
1093c19800e8SDoug Rabson #ifdef PKINIT
1094c19800e8SDoug Rabson     return _krb5_pk_mk_padata(context,
1095c19800e8SDoug Rabson 			      ctx->pk_init_ctx,
1096ae771770SStanislav Sedov 			      ctx->ic_flags,
1097ae771770SStanislav Sedov 			      win2k,
1098c19800e8SDoug Rabson 			      &a->req_body,
1099c19800e8SDoug Rabson 			      ctx->pk_nonce,
1100c19800e8SDoug Rabson 			      md);
1101c19800e8SDoug Rabson #else
1102ae771770SStanislav Sedov     krb5_set_error_message(context, EINVAL,
1103ae771770SStanislav Sedov 			   N_("no support for PKINIT compiled in", ""));
1104c19800e8SDoug Rabson     return EINVAL;
1105c19800e8SDoug Rabson #endif
1106c19800e8SDoug Rabson }
1107c19800e8SDoug Rabson 
1108c19800e8SDoug Rabson static krb5_error_code
pa_data_add_pac_request(krb5_context context,krb5_get_init_creds_ctx * ctx,METHOD_DATA * md)1109c19800e8SDoug Rabson pa_data_add_pac_request(krb5_context context,
1110c19800e8SDoug Rabson 			krb5_get_init_creds_ctx *ctx,
1111c19800e8SDoug Rabson 			METHOD_DATA *md)
1112c19800e8SDoug Rabson {
1113ae771770SStanislav Sedov     size_t len = 0, length;
1114c19800e8SDoug Rabson     krb5_error_code ret;
1115c19800e8SDoug Rabson     PA_PAC_REQUEST req;
1116c19800e8SDoug Rabson     void *buf;
1117c19800e8SDoug Rabson 
1118c19800e8SDoug Rabson     switch (ctx->req_pac) {
1119c19800e8SDoug Rabson     case KRB5_INIT_CREDS_TRISTATE_UNSET:
1120c19800e8SDoug Rabson 	return 0; /* don't bother */
1121c19800e8SDoug Rabson     case KRB5_INIT_CREDS_TRISTATE_TRUE:
1122c19800e8SDoug Rabson 	req.include_pac = 1;
1123c19800e8SDoug Rabson 	break;
1124c19800e8SDoug Rabson     case KRB5_INIT_CREDS_TRISTATE_FALSE:
1125c19800e8SDoug Rabson 	req.include_pac = 0;
1126c19800e8SDoug Rabson     }
1127c19800e8SDoug Rabson 
1128c19800e8SDoug Rabson     ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length,
1129c19800e8SDoug Rabson 		       &req, &len, ret);
1130c19800e8SDoug Rabson     if (ret)
1131c19800e8SDoug Rabson 	return ret;
1132c19800e8SDoug Rabson     if(len != length)
1133c19800e8SDoug Rabson 	krb5_abortx(context, "internal error in ASN.1 encoder");
1134c19800e8SDoug Rabson 
1135c19800e8SDoug Rabson     ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PAC_REQUEST, buf, len);
1136c19800e8SDoug Rabson     if (ret)
1137c19800e8SDoug Rabson 	free(buf);
1138c19800e8SDoug Rabson 
1139c19800e8SDoug Rabson     return 0;
1140c19800e8SDoug Rabson }
1141c19800e8SDoug Rabson 
1142c19800e8SDoug Rabson /*
1143c19800e8SDoug Rabson  * Assumes caller always will free `out_md', even on error.
1144c19800e8SDoug Rabson  */
1145c19800e8SDoug Rabson 
1146c19800e8SDoug Rabson static krb5_error_code
process_pa_data_to_md(krb5_context context,const krb5_creds * creds,const AS_REQ * a,krb5_get_init_creds_ctx * ctx,METHOD_DATA * in_md,METHOD_DATA ** out_md,krb5_prompter_fct prompter,void * prompter_data)1147c19800e8SDoug Rabson process_pa_data_to_md(krb5_context context,
1148c19800e8SDoug Rabson 		      const krb5_creds *creds,
1149c19800e8SDoug Rabson 		      const AS_REQ *a,
1150c19800e8SDoug Rabson 		      krb5_get_init_creds_ctx *ctx,
1151c19800e8SDoug Rabson 		      METHOD_DATA *in_md,
1152c19800e8SDoug Rabson 		      METHOD_DATA **out_md,
1153c19800e8SDoug Rabson 		      krb5_prompter_fct prompter,
1154c19800e8SDoug Rabson 		      void *prompter_data)
1155c19800e8SDoug Rabson {
1156c19800e8SDoug Rabson     krb5_error_code ret;
1157c19800e8SDoug Rabson 
1158c19800e8SDoug Rabson     ALLOC(*out_md, 1);
1159c19800e8SDoug Rabson     if (*out_md == NULL) {
1160ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1161c19800e8SDoug Rabson 	return ENOMEM;
1162c19800e8SDoug Rabson     }
1163c19800e8SDoug Rabson     (*out_md)->len = 0;
1164c19800e8SDoug Rabson     (*out_md)->val = NULL;
1165c19800e8SDoug Rabson 
1166ae771770SStanislav Sedov     if (_krb5_have_debug(context, 5)) {
1167ae771770SStanislav Sedov 	unsigned i;
1168ae771770SStanislav Sedov 	_krb5_debug(context, 5, "KDC send %d patypes", in_md->len);
1169ae771770SStanislav Sedov 	for (i = 0; i < in_md->len; i++)
1170ae771770SStanislav Sedov 	    _krb5_debug(context, 5, "KDC send PA-DATA type: %d", in_md->val[i].padata_type);
1171ae771770SStanislav Sedov     }
1172ae771770SStanislav Sedov 
1173c19800e8SDoug Rabson     /*
1174c19800e8SDoug Rabson      * Make sure we don't sent both ENC-TS and PK-INIT pa data, no
1175c19800e8SDoug Rabson      * need to expose our password protecting our PKCS12 key.
1176c19800e8SDoug Rabson      */
1177c19800e8SDoug Rabson 
1178c19800e8SDoug Rabson     if (ctx->pk_init_ctx) {
1179c19800e8SDoug Rabson 
1180ae771770SStanislav Sedov  	_krb5_debug(context, 5, "krb5_get_init_creds: "
1181ae771770SStanislav Sedov 		    "prepareing PKINIT padata (%s)",
1182ae771770SStanislav Sedov  		    (ctx->used_pa_types & USED_PKINIT_W2K) ? "win2k" : "ietf");
1183ae771770SStanislav Sedov 
1184ae771770SStanislav Sedov  	if (ctx->used_pa_types & USED_PKINIT_W2K) {
1185ae771770SStanislav Sedov  	    krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
1186ae771770SStanislav Sedov  				   "Already tried pkinit, looping");
1187ae771770SStanislav Sedov  	    return KRB5_GET_IN_TKT_LOOP;
1188ae771770SStanislav Sedov  	}
1189ae771770SStanislav Sedov 
1190ae771770SStanislav Sedov 	ret = pa_data_to_md_pkinit(context, a, creds->client,
1191ae771770SStanislav Sedov 				   (ctx->used_pa_types & USED_PKINIT),
1192ae771770SStanislav Sedov 				   ctx, *out_md);
1193c19800e8SDoug Rabson 	if (ret)
1194c19800e8SDoug Rabson 	    return ret;
1195c19800e8SDoug Rabson 
1196ae771770SStanislav Sedov 	if (ctx->used_pa_types & USED_PKINIT)
1197ae771770SStanislav Sedov 	    ctx->used_pa_types |= USED_PKINIT_W2K;
1198ae771770SStanislav Sedov  	else
1199ae771770SStanislav Sedov  	    ctx->used_pa_types |= USED_PKINIT;
1200ae771770SStanislav Sedov 
1201c19800e8SDoug Rabson     } else if (in_md->len != 0) {
1202ae771770SStanislav Sedov 	struct pa_info_data *paid, *ppaid;
1203ae771770SStanislav Sedov  	unsigned flag;
1204c19800e8SDoug Rabson 
1205ae771770SStanislav Sedov 	paid = calloc(1, sizeof(*paid));
1206c19800e8SDoug Rabson 
1207ae771770SStanislav Sedov 	paid->etype = ENCTYPE_NULL;
1208ae771770SStanislav Sedov 	ppaid = process_pa_info(context, creds->client, a, paid, in_md);
1209c19800e8SDoug Rabson 
1210ae771770SStanislav Sedov  	if (ppaid)
1211ae771770SStanislav Sedov  	    flag = USED_ENC_TS_INFO;
1212ae771770SStanislav Sedov  	else
1213ae771770SStanislav Sedov  	    flag = USED_ENC_TS_GUESS;
1214ae771770SStanislav Sedov 
1215ae771770SStanislav Sedov  	if (ctx->used_pa_types & flag) {
1216c19800e8SDoug Rabson  	    if (ppaid)
1217c19800e8SDoug Rabson  		free_paid(context, ppaid);
1218ae771770SStanislav Sedov  	    krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
1219ae771770SStanislav Sedov  				   "Already tried ENC-TS-%s, looping",
1220ae771770SStanislav Sedov  				   flag == USED_ENC_TS_INFO ? "info" : "guess");
1221ae771770SStanislav Sedov  	    return KRB5_GET_IN_TKT_LOOP;
1222ae771770SStanislav Sedov  	}
1223ae771770SStanislav Sedov 
1224ae771770SStanislav Sedov 	pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md);
1225ae771770SStanislav Sedov 
1226ae771770SStanislav Sedov 	ctx->used_pa_types |= flag;
1227ae771770SStanislav Sedov 
1228ae771770SStanislav Sedov 	if (ppaid) {
1229ae771770SStanislav Sedov 	    if (ctx->ppaid) {
1230ae771770SStanislav Sedov 		free_paid(context, ctx->ppaid);
1231ae771770SStanislav Sedov 		free(ctx->ppaid);
1232ae771770SStanislav Sedov 	    }
1233ae771770SStanislav Sedov 	    ctx->ppaid = ppaid;
1234ae771770SStanislav Sedov 	} else
1235ae771770SStanislav Sedov 	    free(paid);
1236c19800e8SDoug Rabson     }
1237c19800e8SDoug Rabson 
1238c19800e8SDoug Rabson     pa_data_add_pac_request(context, ctx, *out_md);
1239c19800e8SDoug Rabson 
1240c19800e8SDoug Rabson     if ((*out_md)->len == 0) {
1241c19800e8SDoug Rabson 	free(*out_md);
1242c19800e8SDoug Rabson 	*out_md = NULL;
1243c19800e8SDoug Rabson     }
1244c19800e8SDoug Rabson 
1245c19800e8SDoug Rabson     return 0;
1246c19800e8SDoug Rabson }
1247c19800e8SDoug Rabson 
1248c19800e8SDoug Rabson static krb5_error_code
process_pa_data_to_key(krb5_context context,krb5_get_init_creds_ctx * ctx,krb5_creds * creds,AS_REQ * a,AS_REP * rep,const krb5_krbhst_info * hi,krb5_keyblock ** key)1249c19800e8SDoug Rabson process_pa_data_to_key(krb5_context context,
1250c19800e8SDoug Rabson 		       krb5_get_init_creds_ctx *ctx,
1251c19800e8SDoug Rabson 		       krb5_creds *creds,
1252c19800e8SDoug Rabson 		       AS_REQ *a,
1253ae771770SStanislav Sedov 		       AS_REP *rep,
1254c19800e8SDoug Rabson 		       const krb5_krbhst_info *hi,
1255c19800e8SDoug Rabson 		       krb5_keyblock **key)
1256c19800e8SDoug Rabson {
1257c19800e8SDoug Rabson     struct pa_info_data paid, *ppaid = NULL;
1258c19800e8SDoug Rabson     krb5_error_code ret;
1259c19800e8SDoug Rabson     krb5_enctype etype;
1260c19800e8SDoug Rabson     PA_DATA *pa;
1261c19800e8SDoug Rabson 
1262c19800e8SDoug Rabson     memset(&paid, 0, sizeof(paid));
1263c19800e8SDoug Rabson 
1264ae771770SStanislav Sedov     etype = rep->enc_part.etype;
1265c19800e8SDoug Rabson 
1266ae771770SStanislav Sedov     if (rep->padata) {
1267c19800e8SDoug Rabson 	paid.etype = etype;
1268c19800e8SDoug Rabson 	ppaid = process_pa_info(context, creds->client, a, &paid,
1269ae771770SStanislav Sedov 				rep->padata);
1270c19800e8SDoug Rabson     }
1271ae771770SStanislav Sedov     if (ppaid == NULL)
1272ae771770SStanislav Sedov 	ppaid = ctx->ppaid;
1273c19800e8SDoug Rabson     if (ppaid == NULL) {
1274c19800e8SDoug Rabson 	ret = krb5_get_pw_salt (context, creds->client, &paid.salt);
1275c19800e8SDoug Rabson 	if (ret)
1276c19800e8SDoug Rabson 	    return ret;
1277c19800e8SDoug Rabson 	paid.etype = etype;
1278c19800e8SDoug Rabson 	paid.s2kparams = NULL;
1279ae771770SStanislav Sedov 	ppaid = &paid;
1280c19800e8SDoug Rabson     }
1281c19800e8SDoug Rabson 
1282c19800e8SDoug Rabson     pa = NULL;
1283ae771770SStanislav Sedov     if (rep->padata) {
1284c19800e8SDoug Rabson 	int idx = 0;
1285ae771770SStanislav Sedov 	pa = krb5_find_padata(rep->padata->val,
1286ae771770SStanislav Sedov 			      rep->padata->len,
1287c19800e8SDoug Rabson 			      KRB5_PADATA_PK_AS_REP,
1288c19800e8SDoug Rabson 			      &idx);
1289c19800e8SDoug Rabson 	if (pa == NULL) {
1290c19800e8SDoug Rabson 	    idx = 0;
1291ae771770SStanislav Sedov 	    pa = krb5_find_padata(rep->padata->val,
1292ae771770SStanislav Sedov 				  rep->padata->len,
1293c19800e8SDoug Rabson 				  KRB5_PADATA_PK_AS_REP_19,
1294c19800e8SDoug Rabson 				  &idx);
1295c19800e8SDoug Rabson 	}
1296c19800e8SDoug Rabson     }
1297c19800e8SDoug Rabson     if (pa && ctx->pk_init_ctx) {
1298c19800e8SDoug Rabson #ifdef PKINIT
1299ae771770SStanislav Sedov 	_krb5_debug(context, 5, "krb5_get_init_creds: using PKINIT");
1300ae771770SStanislav Sedov 
1301c19800e8SDoug Rabson 	ret = _krb5_pk_rd_pa_reply(context,
1302c19800e8SDoug Rabson 				   a->req_body.realm,
1303c19800e8SDoug Rabson 				   ctx->pk_init_ctx,
1304c19800e8SDoug Rabson 				   etype,
1305c19800e8SDoug Rabson 				   hi,
1306c19800e8SDoug Rabson 				   ctx->pk_nonce,
1307c19800e8SDoug Rabson 				   &ctx->req_buffer,
1308c19800e8SDoug Rabson 				   pa,
1309c19800e8SDoug Rabson 				   key);
1310c19800e8SDoug Rabson #else
1311c19800e8SDoug Rabson 	ret = EINVAL;
1312ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("no support for PKINIT compiled in", ""));
1313c19800e8SDoug Rabson #endif
1314ae771770SStanislav Sedov     } else if (ctx->keyseed) {
1315ae771770SStanislav Sedov  	_krb5_debug(context, 5, "krb5_get_init_creds: using keyproc");
1316c19800e8SDoug Rabson 	ret = pa_data_to_key_plain(context, creds->client, ctx,
1317ae771770SStanislav Sedov 				   ppaid->salt, ppaid->s2kparams, etype, key);
1318ae771770SStanislav Sedov     } else {
1319c19800e8SDoug Rabson 	ret = EINVAL;
1320ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("No usable pa data type", ""));
1321c19800e8SDoug Rabson     }
1322c19800e8SDoug Rabson 
1323c19800e8SDoug Rabson     free_paid(context, &paid);
1324c19800e8SDoug Rabson     return ret;
1325c19800e8SDoug Rabson }
1326c19800e8SDoug Rabson 
1327ae771770SStanislav Sedov /**
1328ae771770SStanislav Sedov  * Start a new context to get a new initial credential.
1329ae771770SStanislav Sedov  *
1330ae771770SStanislav Sedov  * @param context A Kerberos 5 context.
1331ae771770SStanislav Sedov  * @param client The Kerberos principal to get the credential for, if
1332ae771770SStanislav Sedov  *     NULL is given, the default principal is used as determined by
1333ae771770SStanislav Sedov  *     krb5_get_default_principal().
1334ae771770SStanislav Sedov  * @param prompter
1335ae771770SStanislav Sedov  * @param prompter_data
1336ae771770SStanislav Sedov  * @param start_time the time the ticket should start to be valid or 0 for now.
1337ae771770SStanislav Sedov  * @param options a options structure, can be NULL for default options.
1338ae771770SStanislav Sedov  * @param rctx A new allocated free with krb5_init_creds_free().
1339ae771770SStanislav Sedov  *
1340ae771770SStanislav Sedov  * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message().
1341ae771770SStanislav Sedov  *
1342ae771770SStanislav Sedov  * @ingroup krb5_credential
1343ae771770SStanislav Sedov  */
1344ae771770SStanislav Sedov 
1345ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_init(krb5_context context,krb5_principal client,krb5_prompter_fct prompter,void * prompter_data,krb5_deltat start_time,krb5_get_init_creds_opt * options,krb5_init_creds_context * rctx)1346ae771770SStanislav Sedov krb5_init_creds_init(krb5_context context,
1347ae771770SStanislav Sedov 		     krb5_principal client,
1348ae771770SStanislav Sedov 		     krb5_prompter_fct prompter,
1349c19800e8SDoug Rabson 		     void *prompter_data,
1350ae771770SStanislav Sedov 		     krb5_deltat start_time,
1351ae771770SStanislav Sedov 		     krb5_get_init_creds_opt *options,
1352ae771770SStanislav Sedov 		     krb5_init_creds_context *rctx)
1353c19800e8SDoug Rabson {
1354ae771770SStanislav Sedov     krb5_init_creds_context ctx;
1355c19800e8SDoug Rabson     krb5_error_code ret;
1356c19800e8SDoug Rabson 
1357ae771770SStanislav Sedov     *rctx = NULL;
1358c19800e8SDoug Rabson 
1359ae771770SStanislav Sedov     ctx = calloc(1, sizeof(*ctx));
1360ae771770SStanislav Sedov     if (ctx == NULL) {
1361ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1362ae771770SStanislav Sedov 	return ENOMEM;
1363ae771770SStanislav Sedov     }
1364c19800e8SDoug Rabson 
1365ae771770SStanislav Sedov     ret = get_init_creds_common(context, client, start_time, options, ctx);
1366ae771770SStanislav Sedov     if (ret) {
1367ae771770SStanislav Sedov 	free(ctx);
1368c19800e8SDoug Rabson 	return ret;
1369ae771770SStanislav Sedov     }
1370c19800e8SDoug Rabson 
1371c19800e8SDoug Rabson     /* Set a new nonce. */
1372c19800e8SDoug Rabson     krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce));
1373ae771770SStanislav Sedov     ctx->nonce &= 0x7fffffff;
1374c19800e8SDoug Rabson     /* XXX these just needs to be the same when using Windows PK-INIT */
1375c19800e8SDoug Rabson     ctx->pk_nonce = ctx->nonce;
1376c19800e8SDoug Rabson 
1377ae771770SStanislav Sedov     ctx->prompter = prompter;
1378ae771770SStanislav Sedov     ctx->prompter_data = prompter_data;
1379ae771770SStanislav Sedov 
1380ae771770SStanislav Sedov     *rctx = ctx;
1381ae771770SStanislav Sedov 
1382ae771770SStanislav Sedov     return ret;
1383ae771770SStanislav Sedov }
1384ae771770SStanislav Sedov 
1385ae771770SStanislav Sedov /**
1386ae771770SStanislav Sedov  * Sets the service that the is requested. This call is only neede for
1387ae771770SStanislav Sedov  * special initial tickets, by default the a krbtgt is fetched in the default realm.
1388ae771770SStanislav Sedov  *
1389ae771770SStanislav Sedov  * @param context a Kerberos 5 context.
1390ae771770SStanislav Sedov  * @param ctx a krb5_init_creds_context context.
1391ae771770SStanislav Sedov  * @param service the service given as a string, for example
1392ae771770SStanislav Sedov  *        "kadmind/admin". If NULL, the default krbtgt in the clients
1393ae771770SStanislav Sedov  *        realm is set.
1394ae771770SStanislav Sedov  *
1395ae771770SStanislav Sedov  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
1396ae771770SStanislav Sedov  * @ingroup krb5_credential
1397c19800e8SDoug Rabson  */
1398c19800e8SDoug Rabson 
1399ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_set_service(krb5_context context,krb5_init_creds_context ctx,const char * service)1400ae771770SStanislav Sedov krb5_init_creds_set_service(krb5_context context,
1401ae771770SStanislav Sedov 			    krb5_init_creds_context ctx,
1402ae771770SStanislav Sedov 			    const char *service)
1403ae771770SStanislav Sedov {
1404ae771770SStanislav Sedov     krb5_const_realm client_realm;
1405ae771770SStanislav Sedov     krb5_principal principal;
1406ae771770SStanislav Sedov     krb5_error_code ret;
1407c19800e8SDoug Rabson 
1408ae771770SStanislav Sedov     client_realm = krb5_principal_get_realm (context, ctx->cred.client);
1409ae771770SStanislav Sedov 
1410ae771770SStanislav Sedov     if (service) {
1411ae771770SStanislav Sedov 	ret = krb5_parse_name (context, service, &principal);
1412ae771770SStanislav Sedov 	if (ret)
1413ae771770SStanislav Sedov 	    return ret;
1414ae771770SStanislav Sedov 	krb5_principal_set_realm (context, principal, client_realm);
1415ae771770SStanislav Sedov     } else {
1416ae771770SStanislav Sedov 	ret = krb5_make_principal(context, &principal,
1417ae771770SStanislav Sedov 				  client_realm, KRB5_TGS_NAME, client_realm,
1418ae771770SStanislav Sedov 				  NULL);
1419ae771770SStanislav Sedov 	if (ret)
1420ae771770SStanislav Sedov 	    return ret;
1421ae771770SStanislav Sedov     }
1422ae771770SStanislav Sedov 
1423ae771770SStanislav Sedov     /*
1424ae771770SStanislav Sedov      * This is for Windows RODC that are picky about what name type
1425ae771770SStanislav Sedov      * the server principal have, and the really strange part is that
1426ae771770SStanislav Sedov      * they are picky about the AS-REQ name type and not the TGS-REQ
1427ae771770SStanislav Sedov      * later. Oh well.
1428ae771770SStanislav Sedov      */
1429ae771770SStanislav Sedov 
1430ae771770SStanislav Sedov     if (krb5_principal_is_krbtgt(context, principal))
1431ae771770SStanislav Sedov 	krb5_principal_set_type(context, principal, KRB5_NT_SRV_INST);
1432ae771770SStanislav Sedov 
1433ae771770SStanislav Sedov     krb5_free_principal(context, ctx->cred.server);
1434ae771770SStanislav Sedov     ctx->cred.server = principal;
1435ae771770SStanislav Sedov 
1436ae771770SStanislav Sedov     return 0;
1437ae771770SStanislav Sedov }
1438ae771770SStanislav Sedov 
1439ae771770SStanislav Sedov /**
1440ae771770SStanislav Sedov  * Sets the password that will use for the request.
1441ae771770SStanislav Sedov  *
1442ae771770SStanislav Sedov  * @param context a Kerberos 5 context.
1443ae771770SStanislav Sedov  * @param ctx ctx krb5_init_creds_context context.
1444ae771770SStanislav Sedov  * @param password the password to use.
1445ae771770SStanislav Sedov  *
1446ae771770SStanislav Sedov  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
1447ae771770SStanislav Sedov  * @ingroup krb5_credential
1448ae771770SStanislav Sedov  */
1449ae771770SStanislav Sedov 
1450ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_set_password(krb5_context context,krb5_init_creds_context ctx,const char * password)1451ae771770SStanislav Sedov krb5_init_creds_set_password(krb5_context context,
1452ae771770SStanislav Sedov 			     krb5_init_creds_context ctx,
1453ae771770SStanislav Sedov 			     const char *password)
1454ae771770SStanislav Sedov {
1455ae771770SStanislav Sedov     if (ctx->password) {
1456ae771770SStanislav Sedov 	memset(ctx->password, 0, strlen(ctx->password));
1457ae771770SStanislav Sedov 	free(ctx->password);
1458ae771770SStanislav Sedov     }
1459ae771770SStanislav Sedov     if (password) {
1460ae771770SStanislav Sedov 	ctx->password = strdup(password);
1461ae771770SStanislav Sedov 	if (ctx->password == NULL) {
1462ae771770SStanislav Sedov 	    krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1463ae771770SStanislav Sedov 	    return ENOMEM;
1464ae771770SStanislav Sedov 	}
1465ae771770SStanislav Sedov 	ctx->keyseed = (void *) ctx->password;
1466ae771770SStanislav Sedov     } else {
1467ae771770SStanislav Sedov 	ctx->keyseed = NULL;
1468ae771770SStanislav Sedov 	ctx->password = NULL;
1469ae771770SStanislav Sedov     }
1470ae771770SStanislav Sedov 
1471ae771770SStanislav Sedov     return 0;
1472ae771770SStanislav Sedov }
1473ae771770SStanislav Sedov 
1474ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
keytab_key_proc(krb5_context context,krb5_enctype enctype,krb5_const_pointer keyseed,krb5_salt salt,krb5_data * s2kparms,krb5_keyblock ** key)1475ae771770SStanislav Sedov keytab_key_proc(krb5_context context, krb5_enctype enctype,
1476ae771770SStanislav Sedov 		krb5_const_pointer keyseed,
1477ae771770SStanislav Sedov 		krb5_salt salt, krb5_data *s2kparms,
1478ae771770SStanislav Sedov 		krb5_keyblock **key)
1479ae771770SStanislav Sedov {
1480ae771770SStanislav Sedov     krb5_keytab_key_proc_args *args  = rk_UNCONST(keyseed);
1481ae771770SStanislav Sedov     krb5_keytab keytab = args->keytab;
1482ae771770SStanislav Sedov     krb5_principal principal = args->principal;
1483ae771770SStanislav Sedov     krb5_error_code ret;
1484ae771770SStanislav Sedov     krb5_keytab real_keytab;
1485ae771770SStanislav Sedov     krb5_keytab_entry entry;
1486ae771770SStanislav Sedov 
1487ae771770SStanislav Sedov     if(keytab == NULL)
1488ae771770SStanislav Sedov 	krb5_kt_default(context, &real_keytab);
1489ae771770SStanislav Sedov     else
1490ae771770SStanislav Sedov 	real_keytab = keytab;
1491ae771770SStanislav Sedov 
1492ae771770SStanislav Sedov     ret = krb5_kt_get_entry (context, real_keytab, principal,
1493ae771770SStanislav Sedov 			     0, enctype, &entry);
1494*ed549cb0SCy Schubert     if (ret == 0) {
1495*ed549cb0SCy Schubert         ret = krb5_copy_keyblock(context, &entry.keyblock, key);
1496*ed549cb0SCy Schubert         krb5_kt_free_entry(context, &entry);
1497*ed549cb0SCy Schubert     }
1498ae771770SStanislav Sedov 
1499ae771770SStanislav Sedov     if (keytab == NULL)
1500ae771770SStanislav Sedov 	krb5_kt_close (context, real_keytab);
1501ae771770SStanislav Sedov     return ret;
1502ae771770SStanislav Sedov }
1503ae771770SStanislav Sedov 
1504ae771770SStanislav Sedov 
1505ae771770SStanislav Sedov /**
1506ae771770SStanislav Sedov  * Set the keytab to use for authentication.
1507ae771770SStanislav Sedov  *
1508ae771770SStanislav Sedov  * @param context a Kerberos 5 context.
1509ae771770SStanislav Sedov  * @param ctx ctx krb5_init_creds_context context.
1510ae771770SStanislav Sedov  * @param keytab the keytab to read the key from.
1511ae771770SStanislav Sedov  *
1512ae771770SStanislav Sedov  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
1513ae771770SStanislav Sedov  * @ingroup krb5_credential
1514ae771770SStanislav Sedov  */
1515ae771770SStanislav Sedov 
1516ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_set_keytab(krb5_context context,krb5_init_creds_context ctx,krb5_keytab keytab)1517ae771770SStanislav Sedov krb5_init_creds_set_keytab(krb5_context context,
1518ae771770SStanislav Sedov 			   krb5_init_creds_context ctx,
1519ae771770SStanislav Sedov 			   krb5_keytab keytab)
1520ae771770SStanislav Sedov {
1521ae771770SStanislav Sedov     krb5_keytab_key_proc_args *a;
1522ae771770SStanislav Sedov     krb5_keytab_entry entry;
1523ae771770SStanislav Sedov     krb5_kt_cursor cursor;
1524ae771770SStanislav Sedov     krb5_enctype *etypes = NULL;
1525ae771770SStanislav Sedov     krb5_error_code ret;
1526ae771770SStanislav Sedov     size_t netypes = 0;
1527ae771770SStanislav Sedov     int kvno = 0;
1528ae771770SStanislav Sedov 
1529ae771770SStanislav Sedov     a = malloc(sizeof(*a));
1530ae771770SStanislav Sedov     if (a == NULL) {
1531ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
1532ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
1533ae771770SStanislav Sedov 	return ENOMEM;
1534ae771770SStanislav Sedov     }
1535ae771770SStanislav Sedov 
1536ae771770SStanislav Sedov     a->principal = ctx->cred.client;
1537ae771770SStanislav Sedov     a->keytab    = keytab;
1538ae771770SStanislav Sedov 
1539ae771770SStanislav Sedov     ctx->keytab_data = a;
1540ae771770SStanislav Sedov     ctx->keyseed = (void *)a;
1541ae771770SStanislav Sedov     ctx->keyproc = keytab_key_proc;
1542ae771770SStanislav Sedov 
1543ae771770SStanislav Sedov     /*
1544ae771770SStanislav Sedov      * We need to the KDC what enctypes we support for this keytab,
1545ae771770SStanislav Sedov      * esp if the keytab is really a password based entry, then the
1546ae771770SStanislav Sedov      * KDC might have more enctypes in the database then what we have
1547ae771770SStanislav Sedov      * in the keytab.
1548ae771770SStanislav Sedov      */
1549ae771770SStanislav Sedov 
1550ae771770SStanislav Sedov     ret = krb5_kt_start_seq_get(context, keytab, &cursor);
1551ae771770SStanislav Sedov     if(ret)
1552ae771770SStanislav Sedov 	goto out;
1553ae771770SStanislav Sedov 
1554ae771770SStanislav Sedov     while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0){
1555ae771770SStanislav Sedov 	void *ptr;
1556ae771770SStanislav Sedov 
1557ae771770SStanislav Sedov 	if (!krb5_principal_compare(context, entry.principal, ctx->cred.client))
1558ae771770SStanislav Sedov 	    goto next;
1559ae771770SStanislav Sedov 
1560ae771770SStanislav Sedov 	/* check if we ahve this kvno already */
1561ae771770SStanislav Sedov 	if (entry.vno > kvno) {
1562ae771770SStanislav Sedov 	    /* remove old list of etype */
1563ae771770SStanislav Sedov 	    if (etypes)
1564ae771770SStanislav Sedov 		free(etypes);
1565ae771770SStanislav Sedov 	    etypes = NULL;
1566ae771770SStanislav Sedov 	    netypes = 0;
1567ae771770SStanislav Sedov 	    kvno = entry.vno;
1568ae771770SStanislav Sedov 	} else if (entry.vno != kvno)
1569ae771770SStanislav Sedov 	    goto next;
1570ae771770SStanislav Sedov 
1571ae771770SStanislav Sedov 	/* check if enctype is supported */
1572ae771770SStanislav Sedov 	if (krb5_enctype_valid(context, entry.keyblock.keytype) != 0)
1573ae771770SStanislav Sedov 	    goto next;
1574ae771770SStanislav Sedov 
1575ae771770SStanislav Sedov 	/* add enctype to supported list */
1576ae771770SStanislav Sedov 	ptr = realloc(etypes, sizeof(etypes[0]) * (netypes + 2));
1577ae771770SStanislav Sedov 	if (ptr == NULL)
1578ae771770SStanislav Sedov 	    goto next;
1579ae771770SStanislav Sedov 
1580ae771770SStanislav Sedov 	etypes = ptr;
1581ae771770SStanislav Sedov 	etypes[netypes] = entry.keyblock.keytype;
1582ae771770SStanislav Sedov 	etypes[netypes + 1] = ETYPE_NULL;
1583ae771770SStanislav Sedov 	netypes++;
1584ae771770SStanislav Sedov     next:
1585ae771770SStanislav Sedov 	krb5_kt_free_entry(context, &entry);
1586ae771770SStanislav Sedov     }
1587ae771770SStanislav Sedov     krb5_kt_end_seq_get(context, keytab, &cursor);
1588ae771770SStanislav Sedov 
1589ae771770SStanislav Sedov     if (etypes) {
1590ae771770SStanislav Sedov 	if (ctx->etypes)
1591ae771770SStanislav Sedov 	    free(ctx->etypes);
1592ae771770SStanislav Sedov 	ctx->etypes = etypes;
1593ae771770SStanislav Sedov     }
1594ae771770SStanislav Sedov 
1595ae771770SStanislav Sedov  out:
1596ae771770SStanislav Sedov     return 0;
1597ae771770SStanislav Sedov }
1598ae771770SStanislav Sedov 
1599ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
keyblock_key_proc(krb5_context context,krb5_enctype enctype,krb5_const_pointer keyseed,krb5_salt salt,krb5_data * s2kparms,krb5_keyblock ** key)1600ae771770SStanislav Sedov keyblock_key_proc(krb5_context context, krb5_enctype enctype,
1601ae771770SStanislav Sedov 		  krb5_const_pointer keyseed,
1602ae771770SStanislav Sedov 		  krb5_salt salt, krb5_data *s2kparms,
1603ae771770SStanislav Sedov 		  krb5_keyblock **key)
1604ae771770SStanislav Sedov {
1605ae771770SStanislav Sedov     return krb5_copy_keyblock (context, keyseed, key);
1606ae771770SStanislav Sedov }
1607ae771770SStanislav Sedov 
1608ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_set_keyblock(krb5_context context,krb5_init_creds_context ctx,krb5_keyblock * keyblock)1609ae771770SStanislav Sedov krb5_init_creds_set_keyblock(krb5_context context,
1610ae771770SStanislav Sedov 			     krb5_init_creds_context ctx,
1611ae771770SStanislav Sedov 			     krb5_keyblock *keyblock)
1612ae771770SStanislav Sedov {
1613ae771770SStanislav Sedov     ctx->keyseed = (void *)keyblock;
1614ae771770SStanislav Sedov     ctx->keyproc = keyblock_key_proc;
1615ae771770SStanislav Sedov 
1616ae771770SStanislav Sedov     return 0;
1617ae771770SStanislav Sedov }
1618ae771770SStanislav Sedov 
1619ae771770SStanislav Sedov /**
1620ae771770SStanislav Sedov  * The core loop if krb5_get_init_creds() function family. Create the
1621ae771770SStanislav Sedov  * packets and have the caller send them off to the KDC.
1622ae771770SStanislav Sedov  *
1623ae771770SStanislav Sedov  * If the caller want all work been done for them, use
1624ae771770SStanislav Sedov  * krb5_init_creds_get() instead.
1625ae771770SStanislav Sedov  *
1626ae771770SStanislav Sedov  * @param context a Kerberos 5 context.
1627ae771770SStanislav Sedov  * @param ctx ctx krb5_init_creds_context context.
1628ae771770SStanislav Sedov  * @param in input data from KDC, first round it should be reset by krb5_data_zer().
1629ae771770SStanislav Sedov  * @param out reply to KDC.
1630ae771770SStanislav Sedov  * @param hostinfo KDC address info, first round it can be NULL.
1631ae771770SStanislav Sedov  * @param flags status of the round, if
1632ae771770SStanislav Sedov  *        KRB5_INIT_CREDS_STEP_FLAG_CONTINUE is set, continue one more round.
1633ae771770SStanislav Sedov  *
1634ae771770SStanislav Sedov  * @return 0 for success, or an Kerberos 5 error code, see
1635ae771770SStanislav Sedov  *     krb5_get_error_message().
1636ae771770SStanislav Sedov  *
1637ae771770SStanislav Sedov  * @ingroup krb5_credential
1638ae771770SStanislav Sedov  */
1639ae771770SStanislav Sedov 
1640ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_step(krb5_context context,krb5_init_creds_context ctx,krb5_data * in,krb5_data * out,krb5_krbhst_info * hostinfo,unsigned int * flags)1641ae771770SStanislav Sedov krb5_init_creds_step(krb5_context context,
1642ae771770SStanislav Sedov 		     krb5_init_creds_context ctx,
1643ae771770SStanislav Sedov 		     krb5_data *in,
1644ae771770SStanislav Sedov 		     krb5_data *out,
1645ae771770SStanislav Sedov 		     krb5_krbhst_info *hostinfo,
1646ae771770SStanislav Sedov 		     unsigned int *flags)
1647ae771770SStanislav Sedov {
1648ae771770SStanislav Sedov     krb5_error_code ret;
1649ae771770SStanislav Sedov     size_t len = 0;
1650ae771770SStanislav Sedov     size_t size;
1651ae771770SStanislav Sedov 
1652ae771770SStanislav Sedov     krb5_data_zero(out);
1653ae771770SStanislav Sedov 
1654ae771770SStanislav Sedov     if (ctx->as_req.req_body.cname == NULL) {
1655ae771770SStanislav Sedov 	ret = init_as_req(context, ctx->flags, &ctx->cred,
1656ae771770SStanislav Sedov 			  ctx->addrs, ctx->etypes, &ctx->as_req);
1657ae771770SStanislav Sedov 	if (ret) {
1658ae771770SStanislav Sedov 	    free_init_creds_ctx(context, ctx);
1659ae771770SStanislav Sedov 	    return ret;
1660ae771770SStanislav Sedov 	}
1661ae771770SStanislav Sedov     }
1662ae771770SStanislav Sedov 
1663ae771770SStanislav Sedov #define MAX_PA_COUNTER 10
1664ae771770SStanislav Sedov     if (ctx->pa_counter > MAX_PA_COUNTER) {
1665ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
1666ae771770SStanislav Sedov 			       N_("Looping %d times while getting "
1667ae771770SStanislav Sedov 				  "initial credentials", ""),
1668ae771770SStanislav Sedov 			       ctx->pa_counter);
1669ae771770SStanislav Sedov 	return KRB5_GET_IN_TKT_LOOP;
1670ae771770SStanislav Sedov     }
1671c19800e8SDoug Rabson     ctx->pa_counter++;
1672c19800e8SDoug Rabson 
1673ae771770SStanislav Sedov     _krb5_debug(context, 5, "krb5_get_init_creds: loop %d", ctx->pa_counter);
1674ae771770SStanislav Sedov 
1675ae771770SStanislav Sedov     /* Lets process the input packet */
1676ae771770SStanislav Sedov     if (in && in->length) {
1677ae771770SStanislav Sedov 	krb5_kdc_rep rep;
1678ae771770SStanislav Sedov 
1679ae771770SStanislav Sedov 	memset(&rep, 0, sizeof(rep));
1680ae771770SStanislav Sedov 
1681ae771770SStanislav Sedov 	_krb5_debug(context, 5, "krb5_get_init_creds: processing input");
1682ae771770SStanislav Sedov 
1683ae771770SStanislav Sedov 	ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size);
1684ae771770SStanislav Sedov 	if (ret == 0) {
1685ae771770SStanislav Sedov 	    krb5_keyblock *key = NULL;
1686ae771770SStanislav Sedov 	    unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC;
1687ae771770SStanislav Sedov 
1688ae771770SStanislav Sedov 	    if (ctx->flags.canonicalize) {
1689ae771770SStanislav Sedov 		eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
1690ae771770SStanislav Sedov 		eflags |= EXTRACT_TICKET_MATCH_REALM;
1691ae771770SStanislav Sedov 	    }
1692ae771770SStanislav Sedov 	    if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK)
1693ae771770SStanislav Sedov 		eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
1694ae771770SStanislav Sedov 
1695ae771770SStanislav Sedov 	    ret = process_pa_data_to_key(context, ctx, &ctx->cred,
1696ae771770SStanislav Sedov 					 &ctx->as_req, &rep.kdc_rep, hostinfo, &key);
1697ae771770SStanislav Sedov 	    if (ret) {
1698ae771770SStanislav Sedov 		free_AS_REP(&rep.kdc_rep);
1699ae771770SStanislav Sedov 		goto out;
1700ae771770SStanislav Sedov 	    }
1701ae771770SStanislav Sedov 
1702ae771770SStanislav Sedov 	    _krb5_debug(context, 5, "krb5_get_init_creds: extracting ticket");
1703ae771770SStanislav Sedov 
1704ae771770SStanislav Sedov 	    ret = _krb5_extract_ticket(context,
1705ae771770SStanislav Sedov 				       &rep,
1706ae771770SStanislav Sedov 				       &ctx->cred,
1707ae771770SStanislav Sedov 				       key,
1708ae771770SStanislav Sedov 				       NULL,
1709ae771770SStanislav Sedov 				       KRB5_KU_AS_REP_ENC_PART,
1710ae771770SStanislav Sedov 				       NULL,
1711ae771770SStanislav Sedov 				       ctx->nonce,
1712ae771770SStanislav Sedov 				       eflags,
1713ae771770SStanislav Sedov 				       NULL,
1714ae771770SStanislav Sedov 				       NULL);
1715ae771770SStanislav Sedov 	    krb5_free_keyblock(context, key);
1716ae771770SStanislav Sedov 
1717ae771770SStanislav Sedov 	    *flags = 0;
1718ae771770SStanislav Sedov 
1719ae771770SStanislav Sedov 	    if (ret == 0)
1720ae771770SStanislav Sedov 		ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part);
1721ae771770SStanislav Sedov 
1722ae771770SStanislav Sedov 	    free_AS_REP(&rep.kdc_rep);
1723ae771770SStanislav Sedov 	    free_EncASRepPart(&rep.enc_part);
1724ae771770SStanislav Sedov 
1725ae771770SStanislav Sedov 	    return ret;
1726ae771770SStanislav Sedov 
1727ae771770SStanislav Sedov 	} else {
1728ae771770SStanislav Sedov 	    /* let's try to parse it as a KRB-ERROR */
1729ae771770SStanislav Sedov 
1730ae771770SStanislav Sedov 	    _krb5_debug(context, 5, "krb5_get_init_creds: got an error");
1731ae771770SStanislav Sedov 
1732ae771770SStanislav Sedov 	    free_KRB_ERROR(&ctx->error);
1733ae771770SStanislav Sedov 
1734ae771770SStanislav Sedov 	    ret = krb5_rd_error(context, in, &ctx->error);
1735ae771770SStanislav Sedov 	    if(ret && in->length && ((char*)in->data)[0] == 4)
1736ae771770SStanislav Sedov 		ret = KRB5KRB_AP_ERR_V4_REPLY;
1737ae771770SStanislav Sedov 	    if (ret) {
1738ae771770SStanislav Sedov 		_krb5_debug(context, 5, "krb5_get_init_creds: failed to read error");
1739ae771770SStanislav Sedov 		goto out;
1740ae771770SStanislav Sedov 	    }
1741ae771770SStanislav Sedov 
1742ae771770SStanislav Sedov 	    ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred);
1743ae771770SStanislav Sedov 
1744ae771770SStanislav Sedov 	    _krb5_debug(context, 5, "krb5_get_init_creds: KRB-ERROR %d", ret);
1745ae771770SStanislav Sedov 
1746ae771770SStanislav Sedov 	    /*
1747ae771770SStanislav Sedov 	     * If no preauth was set and KDC requires it, give it one
1748ae771770SStanislav Sedov 	     * more try.
1749ae771770SStanislav Sedov 	     */
1750ae771770SStanislav Sedov 
1751ae771770SStanislav Sedov 	    if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) {
1752ae771770SStanislav Sedov 
1753ae771770SStanislav Sedov 	        free_METHOD_DATA(&ctx->md);
1754ae771770SStanislav Sedov 	        memset(&ctx->md, 0, sizeof(ctx->md));
1755ae771770SStanislav Sedov 
1756ae771770SStanislav Sedov 		if (ctx->error.e_data) {
1757ae771770SStanislav Sedov 		    ret = decode_METHOD_DATA(ctx->error.e_data->data,
1758ae771770SStanislav Sedov 					     ctx->error.e_data->length,
1759ae771770SStanislav Sedov 					     &ctx->md,
1760ae771770SStanislav Sedov 					     NULL);
1761ae771770SStanislav Sedov 		    if (ret)
1762ae771770SStanislav Sedov 			krb5_set_error_message(context, ret,
1763ae771770SStanislav Sedov 					       N_("Failed to decode METHOD-DATA", ""));
1764ae771770SStanislav Sedov 		} else {
1765ae771770SStanislav Sedov 		    krb5_set_error_message(context, ret,
1766ae771770SStanislav Sedov 					   N_("Preauth required but no preauth "
1767ae771770SStanislav Sedov 					      "options send by KDC", ""));
1768ae771770SStanislav Sedov 		}
1769ae771770SStanislav Sedov 	    } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) {
1770ae771770SStanislav Sedov 		/*
1771ae771770SStanislav Sedov 		 * Try adapt to timeskrew when we are using pre-auth, and
1772ae771770SStanislav Sedov 		 * if there was a time skew, try again.
1773ae771770SStanislav Sedov 		 */
1774ae771770SStanislav Sedov 		krb5_set_real_time(context, ctx->error.stime, -1);
1775ae771770SStanislav Sedov 		if (context->kdc_sec_offset)
1776ae771770SStanislav Sedov 		    ret = 0;
1777ae771770SStanislav Sedov 
1778ae771770SStanislav Sedov 		_krb5_debug(context, 10, "init_creds: err skew updateing kdc offset to %d",
1779ae771770SStanislav Sedov 			    context->kdc_sec_offset);
1780ae771770SStanislav Sedov 
1781ae771770SStanislav Sedov 		ctx->used_pa_types = 0;
1782ae771770SStanislav Sedov 
1783ae771770SStanislav Sedov 	    } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) {
1784ae771770SStanislav Sedov 	        /* client referal to a new realm */
1785ae771770SStanislav Sedov 
1786ae771770SStanislav Sedov 		if (ctx->error.crealm == NULL) {
1787ae771770SStanislav Sedov 		    krb5_set_error_message(context, ret,
1788ae771770SStanislav Sedov 					   N_("Got a client referral, not but no realm", ""));
1789ae771770SStanislav Sedov 		    goto out;
1790ae771770SStanislav Sedov 		}
1791ae771770SStanislav Sedov 		_krb5_debug(context, 5,
1792ae771770SStanislav Sedov 			    "krb5_get_init_creds: got referal to realm %s",
1793ae771770SStanislav Sedov 			    *ctx->error.crealm);
1794ae771770SStanislav Sedov 
1795ae771770SStanislav Sedov 		ret = krb5_principal_set_realm(context,
1796ae771770SStanislav Sedov 					       ctx->cred.client,
1797ae771770SStanislav Sedov 					       *ctx->error.crealm);
1798ae771770SStanislav Sedov 
1799ae771770SStanislav Sedov 		ctx->used_pa_types = 0;
1800ae771770SStanislav Sedov 	    }
1801ae771770SStanislav Sedov 	    if (ret)
1802ae771770SStanislav Sedov 		goto out;
1803ae771770SStanislav Sedov 	}
1804ae771770SStanislav Sedov     }
1805ae771770SStanislav Sedov 
1806c19800e8SDoug Rabson     if (ctx->as_req.padata) {
1807c19800e8SDoug Rabson 	free_METHOD_DATA(ctx->as_req.padata);
1808c19800e8SDoug Rabson 	free(ctx->as_req.padata);
1809c19800e8SDoug Rabson 	ctx->as_req.padata = NULL;
1810c19800e8SDoug Rabson     }
1811c19800e8SDoug Rabson 
1812c19800e8SDoug Rabson     /* Set a new nonce. */
1813c19800e8SDoug Rabson     ctx->as_req.req_body.nonce = ctx->nonce;
1814c19800e8SDoug Rabson 
1815c19800e8SDoug Rabson     /* fill_in_md_data */
1816ae771770SStanislav Sedov     ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx,
1817ae771770SStanislav Sedov 				&ctx->md, &ctx->as_req.padata,
1818ae771770SStanislav Sedov 				ctx->prompter, ctx->prompter_data);
1819c19800e8SDoug Rabson     if (ret)
1820c19800e8SDoug Rabson 	goto out;
1821c19800e8SDoug Rabson 
1822c19800e8SDoug Rabson     krb5_data_free(&ctx->req_buffer);
1823c19800e8SDoug Rabson 
1824c19800e8SDoug Rabson     ASN1_MALLOC_ENCODE(AS_REQ,
1825c19800e8SDoug Rabson 		       ctx->req_buffer.data, ctx->req_buffer.length,
1826c19800e8SDoug Rabson 		       &ctx->as_req, &len, ret);
1827c19800e8SDoug Rabson     if (ret)
1828c19800e8SDoug Rabson 	goto out;
1829c19800e8SDoug Rabson     if(len != ctx->req_buffer.length)
1830c19800e8SDoug Rabson 	krb5_abortx(context, "internal error in ASN.1 encoder");
1831c19800e8SDoug Rabson 
1832ae771770SStanislav Sedov     out->data = ctx->req_buffer.data;
1833ae771770SStanislav Sedov     out->length = ctx->req_buffer.length;
1834ae771770SStanislav Sedov 
1835ae771770SStanislav Sedov     *flags = KRB5_INIT_CREDS_STEP_FLAG_CONTINUE;
1836ae771770SStanislav Sedov 
1837ae771770SStanislav Sedov     return 0;
1838ae771770SStanislav Sedov  out:
1839ae771770SStanislav Sedov     return ret;
1840ae771770SStanislav Sedov }
1841ae771770SStanislav Sedov 
1842ae771770SStanislav Sedov /**
1843ae771770SStanislav Sedov  * Extract the newly acquired credentials from krb5_init_creds_context
1844ae771770SStanislav Sedov  * context.
1845ae771770SStanislav Sedov  *
1846ae771770SStanislav Sedov  * @param context A Kerberos 5 context.
1847ae771770SStanislav Sedov  * @param ctx
1848ae771770SStanislav Sedov  * @param cred credentials, free with krb5_free_cred_contents().
1849ae771770SStanislav Sedov  *
1850ae771770SStanislav Sedov  * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message().
1851ae771770SStanislav Sedov  */
1852ae771770SStanislav Sedov 
1853ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_get_creds(krb5_context context,krb5_init_creds_context ctx,krb5_creds * cred)1854ae771770SStanislav Sedov krb5_init_creds_get_creds(krb5_context context,
1855ae771770SStanislav Sedov 			  krb5_init_creds_context ctx,
1856ae771770SStanislav Sedov 			  krb5_creds *cred)
1857ae771770SStanislav Sedov {
1858ae771770SStanislav Sedov     return krb5_copy_creds_contents(context, &ctx->cred, cred);
1859ae771770SStanislav Sedov }
1860ae771770SStanislav Sedov 
1861ae771770SStanislav Sedov /**
1862ae771770SStanislav Sedov  * Get the last error from the transaction.
1863ae771770SStanislav Sedov  *
1864ae771770SStanislav Sedov  * @return Returns 0 or an error code
1865ae771770SStanislav Sedov  *
1866ae771770SStanislav Sedov  * @ingroup krb5_credential
1867ae771770SStanislav Sedov  */
1868ae771770SStanislav Sedov 
1869ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_get_error(krb5_context context,krb5_init_creds_context ctx,KRB_ERROR * error)1870ae771770SStanislav Sedov krb5_init_creds_get_error(krb5_context context,
1871ae771770SStanislav Sedov 			  krb5_init_creds_context ctx,
1872ae771770SStanislav Sedov 			  KRB_ERROR *error)
1873ae771770SStanislav Sedov {
1874ae771770SStanislav Sedov     krb5_error_code ret;
1875ae771770SStanislav Sedov 
1876ae771770SStanislav Sedov     ret = copy_KRB_ERROR(&ctx->error, error);
1877ae771770SStanislav Sedov     if (ret)
1878ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1879ae771770SStanislav Sedov 
1880ae771770SStanislav Sedov     return ret;
1881ae771770SStanislav Sedov }
1882ae771770SStanislav Sedov 
1883ae771770SStanislav Sedov /**
1884ae771770SStanislav Sedov  * Free the krb5_init_creds_context allocated by krb5_init_creds_init().
1885ae771770SStanislav Sedov  *
1886ae771770SStanislav Sedov  * @param context A Kerberos 5 context.
1887ae771770SStanislav Sedov  * @param ctx The krb5_init_creds_context to free.
1888ae771770SStanislav Sedov  *
1889ae771770SStanislav Sedov  * @ingroup krb5_credential
1890ae771770SStanislav Sedov  */
1891ae771770SStanislav Sedov 
1892ae771770SStanislav Sedov KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_init_creds_free(krb5_context context,krb5_init_creds_context ctx)1893ae771770SStanislav Sedov krb5_init_creds_free(krb5_context context,
1894ae771770SStanislav Sedov 		     krb5_init_creds_context ctx)
1895ae771770SStanislav Sedov {
1896ae771770SStanislav Sedov     free_init_creds_ctx(context, ctx);
1897ae771770SStanislav Sedov     free(ctx);
1898ae771770SStanislav Sedov }
1899ae771770SStanislav Sedov 
1900ae771770SStanislav Sedov /**
1901ae771770SStanislav Sedov  * Get new credentials as setup by the krb5_init_creds_context.
1902ae771770SStanislav Sedov  *
1903ae771770SStanislav Sedov  * @param context A Kerberos 5 context.
1904ae771770SStanislav Sedov  * @param ctx The krb5_init_creds_context to process.
1905ae771770SStanislav Sedov  *
1906ae771770SStanislav Sedov  * @ingroup krb5_credential
1907ae771770SStanislav Sedov  */
1908ae771770SStanislav Sedov 
1909ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_get(krb5_context context,krb5_init_creds_context ctx)1910ae771770SStanislav Sedov krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx)
1911ae771770SStanislav Sedov {
1912ae771770SStanislav Sedov     krb5_sendto_ctx stctx = NULL;
1913ae771770SStanislav Sedov     krb5_krbhst_info *hostinfo = NULL;
1914ae771770SStanislav Sedov     krb5_error_code ret;
1915ae771770SStanislav Sedov     krb5_data in, out;
1916ae771770SStanislav Sedov     unsigned int flags = 0;
1917ae771770SStanislav Sedov 
1918ae771770SStanislav Sedov     krb5_data_zero(&in);
1919ae771770SStanislav Sedov     krb5_data_zero(&out);
1920ae771770SStanislav Sedov 
1921ae771770SStanislav Sedov     ret = krb5_sendto_ctx_alloc(context, &stctx);
1922ae771770SStanislav Sedov     if (ret)
1923ae771770SStanislav Sedov 	goto out;
1924ae771770SStanislav Sedov     krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
1925ae771770SStanislav Sedov 
1926ae771770SStanislav Sedov     while (1) {
1927ae771770SStanislav Sedov 	flags = 0;
1928ae771770SStanislav Sedov 	ret = krb5_init_creds_step(context, ctx, &in, &out, hostinfo, &flags);
1929ae771770SStanislav Sedov 	krb5_data_free(&in);
1930c19800e8SDoug Rabson 	if (ret)
1931c19800e8SDoug Rabson 	    goto out;
1932c19800e8SDoug Rabson 
1933ae771770SStanislav Sedov 	if ((flags & 1) == 0)
1934c19800e8SDoug Rabson 	    break;
1935c19800e8SDoug Rabson 
1936ae771770SStanislav Sedov 	ret = krb5_sendto_context (context, stctx, &out,
1937ae771770SStanislav Sedov 				   ctx->cred.client->realm, &in);
1938c19800e8SDoug Rabson     	if (ret)
1939c19800e8SDoug Rabson 	    goto out;
1940c19800e8SDoug Rabson 
1941c19800e8SDoug Rabson     }
1942c19800e8SDoug Rabson 
1943c19800e8SDoug Rabson  out:
1944c19800e8SDoug Rabson     if (stctx)
1945c19800e8SDoug Rabson 	krb5_sendto_ctx_free(context, stctx);
1946c19800e8SDoug Rabson 
1947c19800e8SDoug Rabson     return ret;
1948c19800e8SDoug Rabson }
1949c19800e8SDoug Rabson 
1950ae771770SStanislav Sedov /**
1951ae771770SStanislav Sedov  * Get new credentials using password.
1952ae771770SStanislav Sedov  *
1953ae771770SStanislav Sedov  * @ingroup krb5_credential
1954ae771770SStanislav Sedov  */
1955ae771770SStanislav Sedov 
1956ae771770SStanislav Sedov 
1957ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_init_creds_password(krb5_context context,krb5_creds * creds,krb5_principal client,const char * password,krb5_prompter_fct prompter,void * data,krb5_deltat start_time,const char * in_tkt_service,krb5_get_init_creds_opt * options)1958b528cefcSMark Murray krb5_get_init_creds_password(krb5_context context,
1959b528cefcSMark Murray 			     krb5_creds *creds,
1960b528cefcSMark Murray 			     krb5_principal client,
1961b528cefcSMark Murray 			     const char *password,
1962b528cefcSMark Murray 			     krb5_prompter_fct prompter,
1963b528cefcSMark Murray 			     void *data,
1964b528cefcSMark Murray 			     krb5_deltat start_time,
1965b528cefcSMark Murray 			     const char *in_tkt_service,
1966ae771770SStanislav Sedov 			     krb5_get_init_creds_opt *options)
1967b528cefcSMark Murray {
1968ae771770SStanislav Sedov     krb5_init_creds_context ctx;
1969b528cefcSMark Murray     char buf[BUFSIZ];
1970c19800e8SDoug Rabson     krb5_error_code ret;
1971ae771770SStanislav Sedov     int chpw = 0;
1972b528cefcSMark Murray 
1973ae771770SStanislav Sedov  again:
1974ae771770SStanislav Sedov     ret = krb5_init_creds_init(context, client, prompter, data, start_time, options, &ctx);
1975b528cefcSMark Murray     if (ret)
1976ae771770SStanislav Sedov 	goto out;
1977b528cefcSMark Murray 
1978ae771770SStanislav Sedov     ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
1979ae771770SStanislav Sedov     if (ret)
1980ae771770SStanislav Sedov 	goto out;
1981ae771770SStanislav Sedov 
1982ae771770SStanislav Sedov     if (prompter != NULL && ctx->password == NULL && password == NULL) {
1983b528cefcSMark Murray 	krb5_prompt prompt;
1984c19800e8SDoug Rabson 	krb5_data password_data;
19858373020dSJacques Vidrine 	char *p, *q;
1986b528cefcSMark Murray 
1987c19800e8SDoug Rabson 	krb5_unparse_name (context, client, &p);
19888373020dSJacques Vidrine 	asprintf (&q, "%s's Password: ", p);
1989b528cefcSMark Murray 	free (p);
19908373020dSJacques Vidrine 	prompt.prompt = q;
1991b528cefcSMark Murray 	password_data.data   = buf;
1992b528cefcSMark Murray 	password_data.length = sizeof(buf);
1993b528cefcSMark Murray 	prompt.hidden = 1;
1994b528cefcSMark Murray 	prompt.reply  = &password_data;
1995adb0ddaeSAssar Westerlund 	prompt.type   = KRB5_PROMPT_TYPE_PASSWORD;
1996b528cefcSMark Murray 
1997adb0ddaeSAssar Westerlund 	ret = (*prompter) (context, data, NULL, NULL, 1, &prompt);
19988373020dSJacques Vidrine 	free (q);
1999b528cefcSMark Murray 	if (ret) {
2000b528cefcSMark Murray 	    memset (buf, 0, sizeof(buf));
2001b528cefcSMark Murray 	    ret = KRB5_LIBOS_PWDINTR;
2002ae771770SStanislav Sedov 	    krb5_clear_error_message (context);
2003ae771770SStanislav Sedov 	    goto out;
2004b528cefcSMark Murray 	}
2005b528cefcSMark Murray 	password = password_data.data;
2006b528cefcSMark Murray     }
2007b528cefcSMark Murray 
2008ae771770SStanislav Sedov     if (password) {
2009ae771770SStanislav Sedov 	ret = krb5_init_creds_set_password(context, ctx, password);
2010ae771770SStanislav Sedov 	if (ret)
2011ae771770SStanislav Sedov 	    goto out;
2012c19800e8SDoug Rabson     }
20138d4ba808SJacques Vidrine 
2014ae771770SStanislav Sedov     ret = krb5_init_creds_get(context, ctx);
2015ae771770SStanislav Sedov 
2016ae771770SStanislav Sedov     if (ret == 0)
2017ae771770SStanislav Sedov 	process_last_request(context, options, ctx);
2018ae771770SStanislav Sedov 
2019ae771770SStanislav Sedov 
2020ae771770SStanislav Sedov     if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) {
2021ae771770SStanislav Sedov 	char buf2[1024];
2022ae771770SStanislav Sedov 
2023ae771770SStanislav Sedov 	/* try to avoid recursion */
2024ae771770SStanislav Sedov 	if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0)
2025ae771770SStanislav Sedov 	   goto out;
2026ae771770SStanislav Sedov 
2027ae771770SStanislav Sedov 	/* don't try to change password where then where none */
2028ae771770SStanislav Sedov 	if (prompter == NULL)
2029ae771770SStanislav Sedov 	    goto out;
2030ae771770SStanislav Sedov 
2031ae771770SStanislav Sedov 	ret = change_password (context,
2032ae771770SStanislav Sedov 			       client,
2033ae771770SStanislav Sedov 			       ctx->password,
2034ae771770SStanislav Sedov 			       buf2,
2035ae771770SStanislav Sedov 			       sizeof(buf),
2036ae771770SStanislav Sedov 			       prompter,
2037ae771770SStanislav Sedov 			       data,
2038ae771770SStanislav Sedov 			       options);
2039ae771770SStanislav Sedov 	if (ret)
2040ae771770SStanislav Sedov 	    goto out;
2041ae771770SStanislav Sedov 	chpw = 1;
2042ae771770SStanislav Sedov 	krb5_init_creds_free(context, ctx);
2043ae771770SStanislav Sedov 	goto again;
2044ae771770SStanislav Sedov     }
2045ae771770SStanislav Sedov 
2046ae771770SStanislav Sedov  out:
2047ae771770SStanislav Sedov     if (ret == 0)
2048ae771770SStanislav Sedov 	krb5_init_creds_get_creds(context, ctx, creds);
2049ae771770SStanislav Sedov 
2050ae771770SStanislav Sedov     if (ctx)
2051ae771770SStanislav Sedov 	krb5_init_creds_free(context, ctx);
2052ae771770SStanislav Sedov 
2053c19800e8SDoug Rabson     memset(buf, 0, sizeof(buf));
2054b528cefcSMark Murray     return ret;
2055b528cefcSMark Murray }
2056b528cefcSMark Murray 
2057ae771770SStanislav Sedov /**
2058ae771770SStanislav Sedov  * Get new credentials using keyblock.
2059ae771770SStanislav Sedov  *
2060ae771770SStanislav Sedov  * @ingroup krb5_credential
2061ae771770SStanislav Sedov  */
2062b528cefcSMark Murray 
2063ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_init_creds_keyblock(krb5_context context,krb5_creds * creds,krb5_principal client,krb5_keyblock * keyblock,krb5_deltat start_time,const char * in_tkt_service,krb5_get_init_creds_opt * options)2064c19800e8SDoug Rabson krb5_get_init_creds_keyblock(krb5_context context,
2065b528cefcSMark Murray 			     krb5_creds *creds,
2066b528cefcSMark Murray 			     krb5_principal client,
2067c19800e8SDoug Rabson 			     krb5_keyblock *keyblock,
2068b528cefcSMark Murray 			     krb5_deltat start_time,
2069b528cefcSMark Murray 			     const char *in_tkt_service,
2070b528cefcSMark Murray 			     krb5_get_init_creds_opt *options)
2071b528cefcSMark Murray {
2072ae771770SStanislav Sedov     krb5_init_creds_context ctx;
2073b528cefcSMark Murray     krb5_error_code ret;
2074b528cefcSMark Murray 
2075ae771770SStanislav Sedov     memset(creds, 0, sizeof(*creds));
2076ae771770SStanislav Sedov 
2077ae771770SStanislav Sedov     ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx);
2078b528cefcSMark Murray     if (ret)
2079b528cefcSMark Murray 	goto out;
2080b528cefcSMark Murray 
2081ae771770SStanislav Sedov     ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
2082ae771770SStanislav Sedov     if (ret)
2083ae771770SStanislav Sedov 	goto out;
20844137ff4cSJacques Vidrine 
2085ae771770SStanislav Sedov     ret = krb5_init_creds_set_keyblock(context, ctx, keyblock);
2086ae771770SStanislav Sedov     if (ret)
2087ae771770SStanislav Sedov 	goto out;
2088ae771770SStanislav Sedov 
2089ae771770SStanislav Sedov     ret = krb5_init_creds_get(context, ctx);
2090ae771770SStanislav Sedov 
2091ae771770SStanislav Sedov     if (ret == 0)
2092ae771770SStanislav Sedov         process_last_request(context, options, ctx);
2093b528cefcSMark Murray 
2094b528cefcSMark Murray  out:
2095ae771770SStanislav Sedov     if (ret == 0)
2096ae771770SStanislav Sedov 	krb5_init_creds_get_creds(context, ctx, creds);
2097ae771770SStanislav Sedov 
2098ae771770SStanislav Sedov     if (ctx)
2099ae771770SStanislav Sedov 	krb5_init_creds_free(context, ctx);
2100ae771770SStanislav Sedov 
2101ae771770SStanislav Sedov     return ret;
2102ae771770SStanislav Sedov }
2103ae771770SStanislav Sedov 
2104ae771770SStanislav Sedov /**
2105ae771770SStanislav Sedov  * Get new credentials using keytab.
2106ae771770SStanislav Sedov  *
2107ae771770SStanislav Sedov  * @ingroup krb5_credential
2108ae771770SStanislav Sedov  */
2109ae771770SStanislav Sedov 
2110ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_init_creds_keytab(krb5_context context,krb5_creds * creds,krb5_principal client,krb5_keytab keytab,krb5_deltat start_time,const char * in_tkt_service,krb5_get_init_creds_opt * options)2111ae771770SStanislav Sedov krb5_get_init_creds_keytab(krb5_context context,
2112ae771770SStanislav Sedov 			   krb5_creds *creds,
2113ae771770SStanislav Sedov 			   krb5_principal client,
2114ae771770SStanislav Sedov 			   krb5_keytab keytab,
2115ae771770SStanislav Sedov 			   krb5_deltat start_time,
2116ae771770SStanislav Sedov 			   const char *in_tkt_service,
2117ae771770SStanislav Sedov 			   krb5_get_init_creds_opt *options)
2118ae771770SStanislav Sedov {
2119ae771770SStanislav Sedov     krb5_init_creds_context ctx;
2120ae771770SStanislav Sedov     krb5_error_code ret;
2121ae771770SStanislav Sedov 
2122ae771770SStanislav Sedov     memset(creds, 0, sizeof(*creds));
2123ae771770SStanislav Sedov 
2124ae771770SStanislav Sedov     ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx);
2125ae771770SStanislav Sedov     if (ret)
2126ae771770SStanislav Sedov 	goto out;
2127ae771770SStanislav Sedov 
2128ae771770SStanislav Sedov     ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
2129ae771770SStanislav Sedov     if (ret)
2130ae771770SStanislav Sedov 	goto out;
2131ae771770SStanislav Sedov 
2132ae771770SStanislav Sedov     ret = krb5_init_creds_set_keytab(context, ctx, keytab);
2133ae771770SStanislav Sedov     if (ret)
2134ae771770SStanislav Sedov 	goto out;
2135ae771770SStanislav Sedov 
2136ae771770SStanislav Sedov     ret = krb5_init_creds_get(context, ctx);
2137ae771770SStanislav Sedov     if (ret == 0)
2138ae771770SStanislav Sedov         process_last_request(context, options, ctx);
2139ae771770SStanislav Sedov 
2140ae771770SStanislav Sedov  out:
2141ae771770SStanislav Sedov     if (ret == 0)
2142ae771770SStanislav Sedov 	krb5_init_creds_get_creds(context, ctx, creds);
2143ae771770SStanislav Sedov 
2144ae771770SStanislav Sedov     if (ctx)
2145ae771770SStanislav Sedov 	krb5_init_creds_free(context, ctx);
2146ae771770SStanislav Sedov 
2147b528cefcSMark Murray     return ret;
2148b528cefcSMark Murray }
2149