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