diff options
author | Cy Schubert <cy@FreeBSD.org> | 2018-04-03 19:36:00 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2018-04-03 19:36:00 +0000 |
commit | b0e4d68d5124581ae353493d69bea352de4cff8a (patch) | |
tree | 43300ec43e83eccd367fd76fdfdefba2dcd7d8f4 /src/lib/krb5/krb | |
parent | 33a9b234e7087f573ef08cd7318c6497ba08b439 (diff) |
Notes
Diffstat (limited to 'src/lib/krb5/krb')
29 files changed, 664 insertions, 404 deletions
diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 0fe02a95d09e..55f82b147d8c 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -364,6 +364,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/t_in_ccache.c \ $(srcdir)/t_response_items.c \ $(srcdir)/t_sname_match.c \ + $(srcdir)/t_valid_times.c \ $(srcdir)/t_vfy_increds.c # Someday, when we have a "maintainer mode", do this right: @@ -457,9 +458,12 @@ t_response_items: t_response_items.o response_items.o $(KRB5_BASE_DEPLIBS) t_sname_match: t_sname_match.o sname_match.o $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o $@ t_sname_match.o sname_match.o $(KRB5_BASE_LIBS) +t_valid_times: t_valid_times.o valid_times.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ t_valid_times.o valid_times.o $(KRB5_BASE_LIBS) + TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand t_authdata t_pac \ - t_in_ccache t_cc_config t_copy_context \ - t_princ t_etypes t_vfy_increds t_response_items t_sname_match + t_in_ccache t_cc_config t_copy_context t_princ t_etypes t_vfy_increds \ + t_response_items t_sname_match t_valid_times check-unix: $(TEST_PROGS) $(RUN_TEST_LOCAL_CONF) ./t_kerb \ @@ -496,6 +500,7 @@ check-unix: $(TEST_PROGS) $(RUN_TEST) ./t_response_items $(RUN_TEST) ./t_copy_context $(RUN_TEST) ./t_sname_match + $(RUN_TEST) ./t_valid_times check-pytests: t_expire_warn t_vfy_increds $(RUNPYTEST) $(srcdir)/t_expire_warn.py $(PYTESTFLAGS) @@ -522,8 +527,9 @@ clean: $(OUTPRE)t_ad_fx_armor$(EXEEXT) $(OUTPRE)t_ad_fx_armor.$(OBJEXT) \ $(OUTPRE)t_vfy_increds$(EXEEXT) $(OUTPRE)t_vfy_increds.$(OBJEXT) \ $(OUTPRE)t_response_items$(EXEEXT) \ - $(OUTPRE)t_response_items.$(OBJEXT) $(OUTPRE)t_sname_match$(EXEEXT) \ - $(OUTPRE)t_sname_match.$(OBJEXT) \ + $(OUTPRE)t_response_items.$(OBJEXT) \ + $(OUTPRE)t_sname_match$(EXEEXT) $(OUTPRE)t_sname_match.$(OBJEXT) \ + $(OUTPRE)t_valid_times$(EXEEXT) $(OUTPRE)t_valid_times.$(OBJECT) \ $(OUTPRE)t_parse_host_string$(EXEEXT) \ $(OUTPRE)t_parse_host_string.$(OBJEXT) diff --git a/src/lib/krb5/krb/deltat.c b/src/lib/krb5/krb/deltat.c index 2c8b90b54ce3..6e6616e99ff8 100644 --- a/src/lib/krb5/krb/deltat.c +++ b/src/lib/krb5/krb/deltat.c @@ -72,7 +72,6 @@ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif #include "k5-int.h" @@ -153,7 +152,7 @@ static int mylex(int *intp, struct param *tmv); static int yyparse(struct param *); -#line 157 "deltat.c" /* yacc.c:339 */ +#line 156 "deltat.c" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus @@ -197,10 +196,10 @@ extern int yydebug; typedef union YYSTYPE YYSTYPE; union YYSTYPE { -#line 129 "x-deltat.y" /* yacc.c:355 */ +#line 128 "x-deltat.y" /* yacc.c:355 */ int val; -#line 204 "deltat.c" /* yacc.c:355 */ +#line 203 "deltat.c" /* yacc.c:355 */ }; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 @@ -214,7 +213,7 @@ int yyparse (struct param *tmv); /* Copy the second part of user declarations. */ -#line 218 "deltat.c" /* yacc.c:358 */ +#line 217 "deltat.c" /* yacc.c:358 */ #ifdef short # undef short @@ -512,9 +511,9 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 143, 143, 144, 144, 145, 145, 146, 146, 147, - 148, 150, 151, 152, 153, 154, 155, 156, 157, 162, - 163, 166, 167, 170, 171 + 0, 142, 142, 143, 143, 144, 144, 145, 145, 146, + 147, 149, 150, 151, 152, 153, 154, 155, 156, 161, + 162, 165, 166, 169, 170 }; #endif @@ -1310,93 +1309,93 @@ yyreduce: switch (yyn) { case 6: -#line 145 "x-deltat.y" /* yacc.c:1646 */ +#line 144 "x-deltat.y" /* yacc.c:1646 */ { (yyval.val) = - (yyvsp[0].val); } -#line 1316 "deltat.c" /* yacc.c:1646 */ +#line 1315 "deltat.c" /* yacc.c:1646 */ break; case 9: -#line 147 "x-deltat.y" /* yacc.c:1646 */ +#line 146 "x-deltat.y" /* yacc.c:1646 */ { (yyval.val) = (yyvsp[0].val); } -#line 1322 "deltat.c" /* yacc.c:1646 */ +#line 1321 "deltat.c" /* yacc.c:1646 */ break; case 10: -#line 148 "x-deltat.y" /* yacc.c:1646 */ +#line 147 "x-deltat.y" /* yacc.c:1646 */ { YYERROR; } -#line 1328 "deltat.c" /* yacc.c:1646 */ +#line 1327 "deltat.c" /* yacc.c:1646 */ break; case 11: -#line 150 "x-deltat.y" /* yacc.c:1646 */ +#line 149 "x-deltat.y" /* yacc.c:1646 */ { DO ((yyvsp[-2].val), 0, 0, (yyvsp[0].val)); } -#line 1334 "deltat.c" /* yacc.c:1646 */ +#line 1333 "deltat.c" /* yacc.c:1646 */ break; case 12: -#line 151 "x-deltat.y" /* yacc.c:1646 */ +#line 150 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, (yyvsp[-2].val), 0, (yyvsp[0].val)); } -#line 1340 "deltat.c" /* yacc.c:1646 */ +#line 1339 "deltat.c" /* yacc.c:1646 */ break; case 13: -#line 152 "x-deltat.y" /* yacc.c:1646 */ +#line 151 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, 0, (yyvsp[-2].val), (yyvsp[0].val)); } -#line 1346 "deltat.c" /* yacc.c:1646 */ +#line 1345 "deltat.c" /* yacc.c:1646 */ break; case 14: -#line 153 "x-deltat.y" /* yacc.c:1646 */ +#line 152 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, 0, 0, (yyvsp[-1].val)); } -#line 1352 "deltat.c" /* yacc.c:1646 */ +#line 1351 "deltat.c" /* yacc.c:1646 */ break; case 15: -#line 154 "x-deltat.y" /* yacc.c:1646 */ +#line 153 "x-deltat.y" /* yacc.c:1646 */ { DO ((yyvsp[-6].val), (yyvsp[-4].val), (yyvsp[-2].val), (yyvsp[0].val)); } -#line 1358 "deltat.c" /* yacc.c:1646 */ +#line 1357 "deltat.c" /* yacc.c:1646 */ break; case 16: -#line 155 "x-deltat.y" /* yacc.c:1646 */ +#line 154 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, (yyvsp[-4].val), (yyvsp[-2].val), (yyvsp[0].val)); } -#line 1364 "deltat.c" /* yacc.c:1646 */ +#line 1363 "deltat.c" /* yacc.c:1646 */ break; case 17: -#line 156 "x-deltat.y" /* yacc.c:1646 */ +#line 155 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, (yyvsp[-2].val), (yyvsp[0].val), 0); } -#line 1370 "deltat.c" /* yacc.c:1646 */ +#line 1369 "deltat.c" /* yacc.c:1646 */ break; case 18: -#line 157 "x-deltat.y" /* yacc.c:1646 */ +#line 156 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, 0, 0, (yyvsp[0].val)); } -#line 1376 "deltat.c" /* yacc.c:1646 */ +#line 1375 "deltat.c" /* yacc.c:1646 */ break; case 20: -#line 163 "x-deltat.y" /* yacc.c:1646 */ +#line 162 "x-deltat.y" /* yacc.c:1646 */ { if (HOUR_NOT_OK((yyvsp[-2].val))) YYERROR; DO_SUM((yyval.val), (yyvsp[-2].val) * 3600, (yyvsp[0].val)); } -#line 1383 "deltat.c" /* yacc.c:1646 */ +#line 1382 "deltat.c" /* yacc.c:1646 */ break; case 22: -#line 167 "x-deltat.y" /* yacc.c:1646 */ +#line 166 "x-deltat.y" /* yacc.c:1646 */ { if (MIN_NOT_OK((yyvsp[-2].val))) YYERROR; DO_SUM((yyval.val), (yyvsp[-2].val) * 60, (yyvsp[0].val)); } -#line 1390 "deltat.c" /* yacc.c:1646 */ +#line 1389 "deltat.c" /* yacc.c:1646 */ break; case 23: -#line 170 "x-deltat.y" /* yacc.c:1646 */ +#line 169 "x-deltat.y" /* yacc.c:1646 */ { (yyval.val) = 0; } -#line 1396 "deltat.c" /* yacc.c:1646 */ +#line 1395 "deltat.c" /* yacc.c:1646 */ break; -#line 1400 "deltat.c" /* yacc.c:1646 */ +#line 1399 "deltat.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1624,7 +1623,7 @@ yyreturn: #endif return yyresult; } -#line 173 "x-deltat.y" /* yacc.c:1906 */ +#line 172 "x-deltat.y" /* yacc.c:1906 */ #ifdef __GNUC__ diff --git a/src/lib/krb5/krb/deps b/src/lib/krb5/krb/deps index 6919eaf717aa..f78b47e766e1 100644 --- a/src/lib/krb5/krb/deps +++ b/src/lib/krb5/krb/deps @@ -1236,8 +1236,15 @@ t_walk_rtree.so t_walk_rtree.po $(OUTPRE)t_walk_rtree.$(OBJEXT): \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ t_walk_rtree.c t_kerb.so t_kerb.po $(OUTPRE)t_kerb.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \ - t_kerb.c + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h t_kerb.c t_ser.so t_ser.po $(OUTPRE)t_ser.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ @@ -1283,14 +1290,14 @@ t_pac.so t_pac.po $(OUTPRE)t_pac.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ t_parse_host_string.so t_parse_host_string.po $(OUTPRE)t_parse_host_string.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ - $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ - $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ - $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ - $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ - $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ - $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - t_parse_host_string.c + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-cmocka.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h t_parse_host_string.c t_princ.so t_princ.po $(OUTPRE)t_princ.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ @@ -1389,6 +1396,17 @@ t_sname_match.so t_sname_match.po $(OUTPRE)t_sname_match.$(OBJEXT): \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ t_sname_match.c +t_valid_times.so t_valid_times.po $(OUTPRE)t_valid_times.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ + $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ + $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ + $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ + $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + int-proto.h t_valid_times.c t_vfy_increds.so t_vfy_increds.po $(OUTPRE)t_vfy_increds.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ diff --git a/src/lib/krb5/krb/fwd_tgt.c b/src/lib/krb5/krb/fwd_tgt.c index a217d4c24001..87f63b6bc4c8 100644 --- a/src/lib/krb5/krb/fwd_tgt.c +++ b/src/lib/krb5/krb/fwd_tgt.c @@ -37,8 +37,9 @@ /* Get a TGT for use at the remote host */ krb5_error_code KRB5_CALLCONV krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, - char *rhost, krb5_principal client, krb5_principal server, - krb5_ccache cc, int forwardable, krb5_data *outbuf) + const char *rhost, krb5_principal client, + krb5_principal server, krb5_ccache cc, int forwardable, + krb5_data *outbuf) /* Should forwarded TGT also be forwardable? */ { krb5_replay_data replaydata; @@ -48,8 +49,8 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, krb5_creds creds, tgt; krb5_creds *pcreds; krb5_flags kdcoptions; - int close_cc = 0; - int free_rhost = 0; + krb5_ccache defcc = NULL; + char *def_rhost = NULL; krb5_enctype enctype = 0; krb5_keyblock *session_key; krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; @@ -58,9 +59,9 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, memset(&tgt, 0, sizeof(creds)); if (cc == 0) { - if ((retval = krb5int_cc_default(context, &cc))) + if ((retval = krb5int_cc_default(context, &defcc))) goto errout; - close_cc = 1; + cc = defcc; } retval = krb5_auth_con_getkey (context, auth_context, &session_key); if (retval) @@ -131,11 +132,11 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, goto errout; } - rhost = k5memdup0(server->data[1].data, server->data[1].length, - &retval); - if (rhost == NULL) + def_rhost = k5memdup0(server->data[1].data, server->data[1].length, + &retval); + if (def_rhost == NULL) goto errout; - free_rhost = 1; + rhost = def_rhost; } retval = k5_os_hostaddr(context, rhost, &addrs); @@ -176,10 +177,9 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, errout: if (addrs) krb5_free_addresses(context, addrs); - if (close_cc) - krb5_cc_close(context, cc); - if (free_rhost) - free(rhost); + if (defcc) + krb5_cc_close(context, defcc); + free(def_rhost); krb5_free_cred_contents(context, &creds); krb5_free_cred_contents(context, &tgt); return retval; diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c index 4c0a1a46120a..5b9bb9573e27 100644 --- a/src/lib/krb5/krb/gc_via_tkt.c +++ b/src/lib/krb5/krb/gc_via_tkt.c @@ -287,26 +287,27 @@ krb5int_process_tgs_reply(krb5_context context, retval = KRB5_KDCREP_MODIFIED; if ((in_cred->times.endtime != 0) && - (dec_rep->enc_part2->times.endtime > in_cred->times.endtime)) + ts_after(dec_rep->enc_part2->times.endtime, in_cred->times.endtime)) retval = KRB5_KDCREP_MODIFIED; if ((kdcoptions & KDC_OPT_RENEWABLE) && (in_cred->times.renew_till != 0) && - (dec_rep->enc_part2->times.renew_till > in_cred->times.renew_till)) + ts_after(dec_rep->enc_part2->times.renew_till, + in_cred->times.renew_till)) retval = KRB5_KDCREP_MODIFIED; if ((kdcoptions & KDC_OPT_RENEWABLE_OK) && (dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) && (in_cred->times.endtime != 0) && - (dec_rep->enc_part2->times.renew_till > in_cred->times.endtime)) + ts_after(dec_rep->enc_part2->times.renew_till, in_cred->times.endtime)) retval = KRB5_KDCREP_MODIFIED; if (retval != 0) goto cleanup; if (!in_cred->times.starttime && - !in_clock_skew(dec_rep->enc_part2->times.starttime, - timestamp)) { + !ts_within(dec_rep->enc_part2->times.starttime, timestamp, + context->clockskew)) { retval = KRB5_KDCREP_SKEW; goto cleanup; } diff --git a/src/lib/krb5/krb/gen_save_subkey.c b/src/lib/krb5/krb/gen_save_subkey.c index 61f36aa3665f..bc2c46d30c22 100644 --- a/src/lib/krb5/krb/gen_save_subkey.c +++ b/src/lib/krb5/krb/gen_save_subkey.c @@ -38,7 +38,8 @@ k5_generate_and_save_subkey(krb5_context context, to guarantee randomness, but to make it less likely that multiple sessions could pick the same subkey. */ struct { - krb5_int32 sec, usec; + krb5_timestamp sec; + krb5_int32 usec; } rnd_data; krb5_data d; krb5_error_code retval; diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c index 110abeb2b1bd..69900adfa046 100644 --- a/src/lib/krb5/krb/get_creds.c +++ b/src/lib/krb5/krb/get_creds.c @@ -576,14 +576,6 @@ step_referrals(krb5_context context, krb5_tkt_creds_context ctx) } if (ctx->referral_count == 1) { - /* Cache the referral TGT only if it's from the local realm. - * Make sure to note the associated authdata, if any. */ - code = krb5_copy_authdata(context, ctx->authdata, - &ctx->reply_creds->authdata); - if (code != 0) - return code; - (void) krb5_cc_store_cred(context, ctx->ccache, ctx->reply_creds); - /* The authdata in this TGT will be copied into subsequent TGTs or the * final credentials, so we don't need to request it again. */ krb5_free_authdata(context, ctx->in_creds->authdata); @@ -816,7 +808,7 @@ get_cached_local_tgt(krb5_context context, krb5_tkt_creds_context ctx, return code; /* Check if the TGT is expired before bothering the KDC with it. */ - if (now > tgt->times.endtime) { + if (ts_after(now, tgt->times.endtime)) { krb5_free_creds(context, tgt); return KRB5KRB_AP_ERR_TKT_EXPIRED; } @@ -934,8 +926,9 @@ step_get_tgt(krb5_context context, krb5_tkt_creds_context ctx) /* See where we wound up on the path (or off it). */ path_realm = find_realm_in_path(context, ctx, tgt_realm); if (path_realm != NULL) { - /* We got a realm on the expected path, so we can cache it. */ - (void) krb5_cc_store_cred(context, ctx->ccache, ctx->cur_tgt); + /* Only cache the TGT if we asked for it, to avoid duplicates. */ + if (path_realm == ctx->next_realm) + (void)krb5_cc_store_cred(context, ctx->ccache, ctx->cur_tgt); if (path_realm == ctx->last_realm) { /* We received a TGT for the target realm. */ TRACE_TKT_CREDS_TARGET_TGT(context, ctx->cur_tgt->server); diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index 54badbbc32f8..47a00bf2c702 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -40,24 +40,6 @@ static krb5_error_code sort_krb5_padata_sequence(krb5_context context, krb5_pa_data **padata); /* - * This function performs 32 bit bounded addition so we can generate - * lifetimes without overflowing krb5_int32 - */ -static krb5_int32 -krb5int_addint32 (krb5_int32 x, krb5_int32 y) -{ - if ((x > 0) && (y > (KRB5_INT32_MAX - x))) { - /* sum will be be greater than KRB5_INT32_MAX */ - return KRB5_INT32_MAX; - } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) { - /* sum will be less than KRB5_INT32_MIN */ - return KRB5_INT32_MIN; - } - - return x + y; -} - -/* * Decrypt the AS reply in ctx, populating ctx->reply->enc_part2. If * strengthen_key is not null, combine it with the reply key as specified in * RFC 6113 section 5.4.3. Place the key used in *key_out. @@ -267,28 +249,28 @@ verify_as_reply(krb5_context context, (request->from != 0) && (request->from != as_reply->enc_part2->times.starttime)) || ((request->till != 0) && - (as_reply->enc_part2->times.endtime > request->till)) + ts_after(as_reply->enc_part2->times.endtime, request->till)) || ((request->kdc_options & KDC_OPT_RENEWABLE) && (request->rtime != 0) && - (as_reply->enc_part2->times.renew_till > request->rtime)) + ts_after(as_reply->enc_part2->times.renew_till, request->rtime)) || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) && !(request->kdc_options & KDC_OPT_RENEWABLE) && (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) && (request->till != 0) && - (as_reply->enc_part2->times.renew_till > request->till)) + ts_after(as_reply->enc_part2->times.renew_till, request->till)) ) { return KRB5_KDCREP_MODIFIED; } if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) { - time_offset = as_reply->enc_part2->times.authtime - time_now; + time_offset = ts_delta(as_reply->enc_part2->times.authtime, time_now); retval = krb5_set_time_offsets(context, time_offset, 0); if (retval) return retval; } else { if ((request->from == 0) && - (labs(as_reply->enc_part2->times.starttime - time_now) - > context->clockskew)) + !ts_within(as_reply->enc_part2->times.starttime, time_now, + context->clockskew)) return (KRB5_KDCREP_SKEW); } return 0; @@ -583,7 +565,7 @@ krb5_init_creds_free(krb5_context context, k5_response_items_free(ctx->rctx.items); free(ctx->in_tkt_service); zapfree(ctx->gakpw.storage.data, ctx->gakpw.storage.length); - k5_preauth_request_context_fini(context); + k5_preauth_request_context_fini(context, ctx); krb5_free_error(context, ctx->err_reply); krb5_free_pa_data(context, ctx->err_padata); krb5_free_cred_contents(context, &ctx->cred); @@ -593,7 +575,9 @@ krb5_init_creds_free(krb5_context context, krb5_free_data(context, ctx->inner_request_body); krb5_free_data(context, ctx->encoded_previous_request); krb5int_fast_free_state(context, ctx->fast_state); - krb5_free_pa_data(context, ctx->preauth_to_use); + krb5_free_pa_data(context, ctx->optimistic_padata); + krb5_free_pa_data(context, ctx->method_padata); + krb5_free_pa_data(context, ctx->more_padata); krb5_free_data_contents(context, &ctx->salt); krb5_free_data_contents(context, &ctx->s2kparams); krb5_free_keyblock_contents(context, &ctx->as_key); @@ -760,23 +744,6 @@ k5_init_creds_current_time(krb5_context context, krb5_init_creds_context ctx, } } -/* Choose a random nonce for ctx->request. */ -static krb5_error_code -pick_nonce(krb5_context context, krb5_init_creds_context ctx) -{ - krb5_error_code code = 0; - unsigned char random_buf[4]; - krb5_data random_data = make_data(random_buf, 4); - - /* We incorrectly encode this as signed, so make sure we use an unsigned - * value to avoid interoperability issues. */ - code = krb5_c_random_make_octets(context, &random_data); - if (code != 0) - return code; - ctx->request->nonce = 0x7fffffff & load_32_n(random_buf); - return 0; -} - /* Set the timestamps for ctx->request based on the desired lifetimes. */ static krb5_error_code set_request_times(krb5_context context, krb5_init_creds_context ctx) @@ -790,16 +757,16 @@ set_request_times(krb5_context context, krb5_init_creds_context ctx) return code; /* Omit request start time unless the caller explicitly asked for one. */ - from = krb5int_addint32(now, ctx->start_time); + from = ts_incr(now, ctx->start_time); if (ctx->start_time != 0) ctx->request->from = from; - ctx->request->till = krb5int_addint32(from, ctx->tkt_life); + ctx->request->till = ts_incr(from, ctx->tkt_life); if (ctx->renew_life > 0) { /* Don't ask for a smaller renewable time than the lifetime. */ - ctx->request->rtime = krb5int_addint32(from, ctx->renew_life); - if (ctx->request->rtime < ctx->request->till) + ctx->request->rtime = ts_incr(from, ctx->renew_life); + if (ts_after(ctx->request->till, ctx->request->rtime)) ctx->request->rtime = ctx->request->till; ctx->request->kdc_options &= ~KDC_OPT_RENEWABLE_OK; } else { @@ -809,6 +776,31 @@ set_request_times(krb5_context context, krb5_init_creds_context ctx) return 0; } +static void +read_allowed_preauth_type(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_error_code ret; + krb5_data config; + char *tmp, *p; + krb5_ccache in_ccache = k5_gic_opt_get_in_ccache(ctx->opt); + + ctx->allowed_preauth_type = KRB5_PADATA_NONE; + if (in_ccache == NULL) + return; + memset(&config, 0, sizeof(config)); + if (krb5_cc_get_config(context, in_ccache, ctx->request->server, + KRB5_CC_CONF_PA_TYPE, &config) != 0) + return; + tmp = k5memdup0(config.data, config.length, &ret); + krb5_free_data_contents(context, &config); + if (tmp == NULL) + return; + ctx->allowed_preauth_type = strtol(tmp, &p, 10); + if (p == NULL || *p != '\0') + ctx->allowed_preauth_type = KRB5_PADATA_NONE; + free(tmp); +} + /** * Throw away any pre-authentication realm state and begin with a * unauthenticated or optimistically authenticated request. If fast_upgrade is @@ -820,11 +812,15 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, { krb5_error_code code = 0; - krb5_free_pa_data(context, ctx->preauth_to_use); + krb5_free_pa_data(context, ctx->optimistic_padata); + krb5_free_pa_data(context, ctx->method_padata); + krb5_free_pa_data(context, ctx->more_padata); krb5_free_pa_data(context, ctx->err_padata); krb5_free_error(context, ctx->err_reply); - ctx->preauth_to_use = ctx->err_padata = NULL; + ctx->optimistic_padata = ctx->method_padata = ctx->more_padata = NULL; + ctx->err_padata = NULL; ctx->err_reply = NULL; + ctx->selected_preauth_type = KRB5_PADATA_NONE; krb5int_fast_free_state(context, ctx->fast_state); ctx->fast_state = NULL; @@ -834,14 +830,14 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, if (fast_upgrade) ctx->fast_state->fast_state_flags |= KRB5INT_FAST_DO_FAST; - k5_preauth_request_context_fini(context); - k5_preauth_request_context_init(context); + k5_preauth_request_context_fini(context, ctx); + k5_preauth_request_context_init(context, ctx); krb5_free_data(context, ctx->outer_request_body); ctx->outer_request_body = NULL; if (ctx->opt->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) { code = make_preauth_list(context, ctx->opt->preauth_list, ctx->opt->preauth_list_length, - &ctx->preauth_to_use); + &ctx->optimistic_padata); if (code) goto cleanup; } @@ -867,6 +863,11 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, &ctx->outer_request_body); if (code != 0) goto cleanup; + + /* Read the allowed preauth type for this server principal from the input + * ccache, if the application supplied one. */ + read_allowed_preauth_type(context, ctx); + cleanup: return code; } @@ -1172,31 +1173,6 @@ init_creds_validate_reply(krb5_context context, return 0; } -static void -read_allowed_preauth_type(krb5_context context, krb5_init_creds_context ctx) -{ - krb5_error_code ret; - krb5_data config; - char *tmp, *p; - krb5_ccache in_ccache = k5_gic_opt_get_in_ccache(ctx->opt); - - ctx->allowed_preauth_type = KRB5_PADATA_NONE; - if (in_ccache == NULL) - return; - memset(&config, 0, sizeof(config)); - if (krb5_cc_get_config(context, in_ccache, ctx->request->server, - KRB5_CC_CONF_PA_TYPE, &config) != 0) - return; - tmp = k5memdup0(config.data, config.length, &ret); - krb5_free_data_contents(context, &config); - if (tmp == NULL) - return; - ctx->allowed_preauth_type = strtol(tmp, &p, 10); - if (p == NULL || *p != '\0') - ctx->allowed_preauth_type = KRB5_PADATA_NONE; - free(tmp); -} - static krb5_error_code save_selected_preauth_type(krb5_context context, krb5_ccache ccache, krb5_init_creds_context ctx) @@ -1313,6 +1289,9 @@ init_creds_step_request(krb5_context context, krb5_data *out) { krb5_error_code code; + krb5_preauthtype pa_type; + struct errinfo save = EMPTY_ERRINFO; + uint32_t rcode = (ctx->err_reply == NULL) ? 0 : ctx->err_reply->error; if (ctx->loopcount >= MAX_IN_TKT_LOOPS) { code = KRB5_GET_IN_TKT_LOOP; @@ -1320,7 +1299,7 @@ init_creds_step_request(krb5_context context, } /* RFC 6113 requires a new nonce for the inner request on each try. */ - code = pick_nonce(context, ctx); + code = k5_generate_nonce(context, &ctx->request->nonce); if (code != 0) goto cleanup; @@ -1335,11 +1314,6 @@ init_creds_step_request(krb5_context context, if (code) goto cleanup; - /* Read the allowed patype for this server principal from the in_ccache, - * if the application supplied one. */ - read_allowed_preauth_type(context, ctx); - ctx->selected_preauth_type = KRB5_PADATA_NONE; - /* * Read cached preauth configuration data for this server principal from * the in_ccache, if the application supplied one, and delete any that was @@ -1348,32 +1322,65 @@ init_creds_step_request(krb5_context context, read_cc_config_in_data(context, ctx); clear_cc_config_out_data(context, ctx); - if (ctx->err_reply == NULL) { - /* Either our first attempt, or retrying after KDC_ERR_PREAUTH_REQUIRED - * or KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. */ - code = k5_preauth(context, ctx, ctx->preauth_to_use, - ctx->preauth_required, &ctx->request->padata, - &ctx->selected_preauth_type); - if (code != 0) - goto cleanup; - } else { - if (ctx->preauth_to_use != NULL) { - /* - * Retry after an error other than PREAUTH_NEEDED, - * using ctx->err_padata to figure out what to change. - */ - code = k5_preauth_tryagain(context, ctx, ctx->preauth_to_use, - &ctx->request->padata); - } else { - /* No preauth supplied, so can't query the plugins. */ - code = KRB5KRB_ERR_GENERIC; + ctx->request->padata = NULL; + if (ctx->optimistic_padata != NULL) { + /* Our first attempt, using an optimistic padata list. */ + TRACE_INIT_CREDS_PREAUTH_OPTIMISTIC(context); + code = k5_preauth(context, ctx, ctx->optimistic_padata, TRUE, + &ctx->request->padata, &ctx->selected_preauth_type); + krb5_free_pa_data(context, ctx->optimistic_padata); + ctx->optimistic_padata = NULL; + if (code) { + /* Make an unauthenticated request, and possibly try again using + * the same mechanisms as we tried optimistically. */ + k5_reset_preauth_types_tried(ctx); + krb5_clear_error_message(context); + code = 0; } - if (code != 0) { - /* couldn't come up with anything better */ + } if (ctx->more_padata != NULL) { + /* Continuing after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. */ + TRACE_INIT_CREDS_PREAUTH_MORE(context, ctx->selected_preauth_type); + code = k5_preauth(context, ctx, ctx->more_padata, TRUE, + &ctx->request->padata, &pa_type); + } else if (rcode == KDC_ERR_PREAUTH_FAILED) { + /* Report the KDC-side failure code if we can't try another mech. */ + code = KRB5KDC_ERR_PREAUTH_FAILED; + } else if (rcode && rcode != KDC_ERR_PREAUTH_REQUIRED) { + /* Retrying after an error (possibly mechanism-specific), using error + * padata to figure out what to change. */ + TRACE_INIT_CREDS_PREAUTH_TRYAGAIN(context, ctx->err_reply->error, + ctx->selected_preauth_type); + code = k5_preauth_tryagain(context, ctx, ctx->selected_preauth_type, + ctx->err_reply, ctx->err_padata, + &ctx->request->padata); + if (code) { + krb5_clear_error_message(context); code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5; + } + } + /* Don't continue after a keyboard interrupt. */ + if (code == KRB5_LIBOS_PWDINTR) + goto cleanup; + if (code) { + /* See if we can try a different preauth mech before giving up. */ + k5_save_ctx_error(context, code, &save); + ctx->selected_preauth_type = KRB5_PADATA_NONE; + } + + if (ctx->request->padata == NULL && ctx->method_padata != NULL) { + /* Retrying after KDC_ERR_PREAUTH_REQUIRED, or trying again with a + * different mechanism after a failure. */ + TRACE_INIT_CREDS_PREAUTH(context); + code = k5_preauth(context, ctx, ctx->method_padata, TRUE, + &ctx->request->padata, &ctx->selected_preauth_type); + if (code) { + if (save.code != 0) + code = k5_restore_ctx_error(context, &save); goto cleanup; } } + if (ctx->request->padata == NULL) + TRACE_INIT_CREDS_PREAUTH_NONE(context); /* Remember when we sent this request (after any preauth delay). */ ctx->request_time = time(NULL); @@ -1382,8 +1389,6 @@ init_creds_step_request(krb5_context context, krb5_free_data(context, ctx->encoded_previous_request); ctx->encoded_previous_request = NULL; } - if (ctx->request->padata) - ctx->sent_nontrivial_preauth = TRUE; if (ctx->enc_pa_rep_permitted) { code = add_padata(&ctx->request->padata, KRB5_ENCPADATA_REQ_ENC_PA_REP, NULL, 0); @@ -1411,6 +1416,7 @@ init_creds_step_request(krb5_context context, cleanup: krb5_free_pa_data(context, ctx->request->padata); ctx->request->padata = NULL; + k5_clear_error(&save); return code; } @@ -1438,7 +1444,7 @@ note_req_timestamp(krb5_context context, krb5_init_creds_context ctx, if (k5_time_with_offset(0, 0, &now, &usec) != 0) return; - ctx->pa_offset = kdc_time - now; + ctx->pa_offset = ts_delta(kdc_time, now); ctx->pa_offset_usec = kdc_usec - usec; ctx->pa_offset_state = (ctx->fast_state->armor_key != NULL) ? AUTH_OFFSET : UNAUTH_OFFSET; @@ -1463,6 +1469,18 @@ is_referral(krb5_context context, krb5_error *err, krb5_principal client) return !krb5_realm_compare(context, err->client, client); } +/* Transfer error padata to method data in ctx and sort it according to + * configuration. */ +static krb5_error_code +accept_method_data(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_free_pa_data(context, ctx->method_padata); + ctx->method_padata = ctx->err_padata; + ctx->err_padata = NULL; + return sort_krb5_padata_sequence(context, &ctx->request->client->realm, + ctx->method_padata); +} + static krb5_error_code init_creds_step_reply(krb5_context context, krb5_init_creds_context ctx, @@ -1492,8 +1510,9 @@ init_creds_step_reply(krb5_context context, ctx->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL; if (ctx->err_reply != NULL) { + krb5_free_pa_data(context, ctx->more_padata); krb5_free_pa_data(context, ctx->err_padata); - ctx->err_padata = NULL; + ctx->more_padata = ctx->err_padata = NULL; code = krb5int_fast_process_error(context, ctx->fast_state, &ctx->err_reply, &ctx->err_padata, &retry); @@ -1508,7 +1527,7 @@ init_creds_step_reply(krb5_context context, ctx->restarted = TRUE; code = restart_init_creds_loop(context, ctx, TRUE); } else if (!ctx->restarted && reply_code == KDC_ERR_PREAUTH_FAILED && - !ctx->sent_nontrivial_preauth) { + ctx->selected_preauth_type == KRB5_PADATA_NONE) { /* The KDC didn't like our informational padata (probably a pre-1.7 * MIT krb5 KDC). Retry without it. */ ctx->enc_pa_rep_permitted = FALSE; @@ -1519,23 +1538,30 @@ init_creds_step_reply(krb5_context context, * FAST upgrade. */ ctx->restarted = FALSE; code = restart_init_creds_loop(context, ctx, FALSE); - } else if ((reply_code == KDC_ERR_MORE_PREAUTH_DATA_REQUIRED || - reply_code == KDC_ERR_PREAUTH_REQUIRED) && retry) { - /* reset the list of preauth types to try */ - k5_reset_preauth_types_tried(context); - krb5_free_pa_data(context, ctx->preauth_to_use); - ctx->preauth_to_use = ctx->err_padata; - ctx->err_padata = NULL; + } else if (reply_code == KDC_ERR_PREAUTH_REQUIRED && retry) { note_req_timestamp(context, ctx, ctx->err_reply->stime, ctx->err_reply->susec); - /* This will trigger a new call to k5_preauth(). */ - krb5_free_error(context, ctx->err_reply); - ctx->err_reply = NULL; - code = sort_krb5_padata_sequence(context, - &ctx->request->client->realm, - ctx->preauth_to_use); - ctx->preauth_required = TRUE; - + code = accept_method_data(context, ctx); + } else if (reply_code == KDC_ERR_PREAUTH_FAILED && retry) { + note_req_timestamp(context, ctx, ctx->err_reply->stime, + ctx->err_reply->susec); + if (ctx->method_padata == NULL) { + /* Optimistic preauth failed on the KDC. Allow all mechanisms + * to be tried again using method data. */ + k5_reset_preauth_types_tried(ctx); + } else { + /* Don't try again with the mechanism that failed. */ + code = k5_preauth_note_failed(ctx, ctx->selected_preauth_type); + if (code) + goto cleanup; + } + ctx->selected_preauth_type = KRB5_PADATA_NONE; + /* Accept or update method data if the KDC sent it. */ + if (ctx->err_padata != NULL) + code = accept_method_data(context, ctx); + } else if (reply_code == KDC_ERR_MORE_PREAUTH_DATA_REQUIRED && retry) { + ctx->more_padata = ctx->err_padata; + ctx->err_padata = NULL; } else if (canon_flag && is_referral(context, ctx->err_reply, ctx->request->client)) { TRACE_INIT_CREDS_REFERRAL(context, &ctx->err_reply->client->realm); @@ -1548,14 +1574,13 @@ init_creds_step_reply(krb5_context context, goto cleanup; /* Reset per-realm negotiation state. */ ctx->restarted = FALSE; - ctx->sent_nontrivial_preauth = FALSE; ctx->enc_pa_rep_permitted = TRUE; code = restart_init_creds_loop(context, ctx, FALSE); } else { - if (retry) { + if (retry && ctx->selected_preauth_type != KRB5_PADATA_NONE) { code = 0; } else { - /* error + no hints = give up */ + /* error + no hints (or no preauth mech) = give up */ code = (krb5_error_code)reply_code + ERROR_TABLE_BASE_krb5; } } @@ -1573,7 +1598,6 @@ init_creds_step_reply(krb5_context context, goto cleanup; /* process any preauth data in the as_reply */ - k5_reset_preauth_types_tried(context); code = krb5int_fast_process_response(context, ctx->fast_state, ctx->reply, &strengthen_key); if (code != 0) @@ -1658,7 +1682,7 @@ init_creds_step_reply(krb5_context context, k5_prependmsg(context, code, _("Failed to store credentials")); } - k5_preauth_request_context_fini(context); + k5_preauth_request_context_fini(context, ctx); /* success */ ctx->complete = TRUE; @@ -1685,7 +1709,7 @@ krb5_init_creds_step(krb5_context context, krb5_data *realm, unsigned int *flags) { - krb5_error_code code = 0, code2; + krb5_error_code code, code2; *flags = 0; @@ -1698,6 +1722,10 @@ krb5_init_creds_step(krb5_context context, if (ctx->complete) return EINVAL; + code = k5_preauth_check_context(context, ctx); + if (code) + return code; + if (in->length != 0) { code = init_creds_step_reply(context, ctx, in); if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG) { @@ -1806,7 +1834,8 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out, krb5_creds *creds) { int i; - krb5_int32 starttime; + krb5_timestamp starttime; + krb5_deltat lifetime; krb5_get_init_creds_opt *opt; krb5_error_code retval; @@ -1838,7 +1867,8 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out, if (retval) goto cleanup; if (creds->times.starttime) starttime = creds->times.starttime; - krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime); + lifetime = ts_delta(creds->times.endtime, starttime); + krb5_get_init_creds_opt_set_tkt_life(opt, lifetime); } *out = opt; return 0; diff --git a/src/lib/krb5/krb/gic_opt.c b/src/lib/krb5/krb/gic_opt.c index 3be44d5cd756..ccbe1a65fa5a 100644 --- a/src/lib/krb5/krb/gic_opt.c +++ b/src/lib/krb5/krb/gic_opt.c @@ -12,7 +12,7 @@ #include <TargetConditionals.h> #endif -/* Match struct packing of krb5_get_init_creds_opt on MacOS X. */ +/* Match struct packing of krb5_get_init_creds_opt on macOS. */ #if TARGET_OS_MAC #pragma pack(push,2) #endif diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c index 6f3a29f2c423..3565a7c4c77a 100644 --- a/src/lib/krb5/krb/gic_pwd.c +++ b/src/lib/krb5/krb/gic_pwd.c @@ -211,7 +211,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options, if (ret != 0) return; if (!is_last_req && - (pw_exp < now || (pw_exp - now) > 7 * 24 * 60 * 60)) + (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60)) return; if (!prompter) @@ -221,7 +221,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options, if (ret != 0) return; - delta = pw_exp - now; + delta = ts_delta(pw_exp, now); if (delta < 3600) { snprintf(banner, sizeof(banner), _("Warning: Your password will expire in less than one hour " diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h index 38c01c775b6f..fe769685ba09 100644 --- a/src/lib/krb5/krb/init_creds_ctx.h +++ b/src/lib/krb5/krb/init_creds_ctx.h @@ -6,6 +6,8 @@ #include "k5-json.h" #include "int-proto.h" +typedef struct krb5_preauth_req_context_st *krb5_preauth_req_context; + struct krb5_responder_context_st { k5_response_items *items; }; @@ -48,7 +50,9 @@ struct _krb5_init_creds_context { krb5_data *inner_request_body; /**< For preauth */ krb5_data *encoded_previous_request; struct krb5int_fast_request_state *fast_state; - krb5_pa_data **preauth_to_use; + krb5_pa_data **optimistic_padata; /* from gic options */ + krb5_pa_data **method_padata; /* from PREAUTH_REQUIRED or PREAUTH_FAILED */ + krb5_pa_data **more_padata; /* from MORE_PREAUTH_DATA_REQUIRED */ krb5_boolean default_salt; krb5_data salt; krb5_data s2kparams; @@ -56,8 +60,6 @@ struct _krb5_init_creds_context { krb5_enctype etype; krb5_boolean enc_pa_rep_permitted; krb5_boolean restarted; - krb5_boolean sent_nontrivial_preauth; - krb5_boolean preauth_required; struct krb5_responder_context_st rctx; krb5_preauthtype selected_preauth_type; krb5_preauthtype allowed_preauth_type; @@ -67,6 +69,7 @@ struct _krb5_init_creds_context { krb5_timestamp pa_offset; krb5_int32 pa_offset_usec; enum { NO_OFFSET = 0, UNAUTH_OFFSET, AUTH_OFFSET } pa_offset_state; + krb5_preauth_req_context preauth_reqctx; }; krb5_error_code diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c index cf226fdbabc0..4246c5dd274f 100644 --- a/src/lib/krb5/krb/init_ctx.c +++ b/src/lib/krb5/krb/init_ctx.c @@ -139,7 +139,8 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags, krb5_context ctx = 0; krb5_error_code retval; struct { - krb5_int32 now, now_usec; + krb5_timestamp now; + krb5_int32 now_usec; long pid; } seed_data; krb5_data seed; diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h index 6da74858e210..cda9010e34a3 100644 --- a/src/lib/krb5/krb/int-proto.h +++ b/src/lib/krb5/krb/int-proto.h @@ -83,8 +83,6 @@ krb5int_construct_matching_creds(krb5_context context, krb5_flags options, krb5_creds *in_creds, krb5_creds *mcreds, krb5_flags *fields); -#define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew) - #define IS_TGS_PRINC(p) ((p)->length == 2 && \ data_eq_string((p)->data[0], KRB5_TGS_NAME)) @@ -102,6 +100,9 @@ krb5_get_cred_via_tkt_ext(krb5_context context, krb5_creds *tkt, krb5_keyblock **out_subkey); krb5_error_code +k5_generate_nonce(krb5_context context, int32_t *out); + +krb5_error_code k5_make_tgs_req(krb5_context context, struct krb5int_fast_request_state *, krb5_creds *tkt, krb5_flags kdcoptions, krb5_address *const *address, krb5_pa_data **in_padata, @@ -187,7 +188,8 @@ k5_preauth(krb5_context context, krb5_init_creds_context ctx, krb5_error_code k5_preauth_tryagain(krb5_context context, krb5_init_creds_context ctx, - krb5_pa_data **in_padata, krb5_pa_data ***padata_out); + krb5_preauthtype pa_type, krb5_error *err, + krb5_pa_data **err_padata, krb5_pa_data ***padata_out); void k5_init_preauth_context(krb5_context context); @@ -196,17 +198,25 @@ void k5_free_preauth_context(krb5_context context); void -k5_reset_preauth_types_tried(krb5_context context); +k5_reset_preauth_types_tried(krb5_init_creds_context ctx); + +krb5_error_code +k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type); void k5_preauth_prepare_request(krb5_context context, krb5_get_init_creds_opt *opt, krb5_kdc_req *request); void -k5_preauth_request_context_init(krb5_context context); +k5_preauth_request_context_init(krb5_context context, + krb5_init_creds_context ctx); void -k5_preauth_request_context_fini(krb5_context context); +k5_preauth_request_context_fini(krb5_context context, + krb5_init_creds_context ctx); + +krb5_error_code +k5_preauth_check_context(krb5_context context, krb5_init_creds_context ctx); krb5_error_code k5_response_items_new(k5_response_items **ri_out); diff --git a/src/lib/krb5/krb/mk_req.c b/src/lib/krb5/krb/mk_req.c index 542ef6d4aee5..162c05b5cbd9 100644 --- a/src/lib/krb5/krb/mk_req.c +++ b/src/lib/krb5/krb/mk_req.c @@ -48,8 +48,9 @@ krb5_error_code KRB5_CALLCONV krb5_mk_req(krb5_context context, krb5_auth_context *auth_context, - krb5_flags ap_req_options, char *service, char *hostname, - krb5_data *in_data, krb5_ccache ccache, krb5_data *outbuf) + krb5_flags ap_req_options, const char *service, + const char *hostname, krb5_data *in_data, krb5_ccache ccache, + krb5_data *outbuf) { krb5_error_code retval; krb5_principal server; diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c index 9098927b5acf..0eb19e6bb464 100644 --- a/src/lib/krb5/krb/pac.c +++ b/src/lib/krb5/krb/pac.c @@ -378,7 +378,7 @@ k5_time_to_seconds_since_1970(int64_t ntTime, krb5_timestamp *elapsedSeconds) abstime = ntTime > 0 ? ntTime - NT_TIME_EPOCH : -ntTime; - if (abstime > KRB5_INT32_MAX) + if (abstime > UINT32_MAX) return ERANGE; *elapsedSeconds = abstime; @@ -436,8 +436,7 @@ k5_pac_validate_client(krb5_context context, pac_princname_length % 2) return ERANGE; - ret = krb5int_ucs2lecs_to_utf8s(p, (size_t)pac_princname_length / 2, - &pac_princname, NULL); + ret = k5_utf16le_to_utf8(p, pac_princname_length, &pac_princname); if (ret != 0) return ret; @@ -792,8 +791,8 @@ mspac_verify(krb5_context kcontext, * If the above verification failed, don't fail the whole authentication, * just don't mark the PAC as verified. A checksum mismatch can occur if * the PAC was copied from a cross-realm TGT by an ignorant KDC, and Apple - * Mac OS X Server Open Directory (as of 10.6) generates PACs with no - * server checksum at all. + * macOS Server Open Directory (as of 10.6) generates PACs with no server + * checksum at all. */ return 0; } diff --git a/src/lib/krb5/krb/pac_sign.c b/src/lib/krb5/krb/pac_sign.c index d40df45f99e8..c94899c96a79 100644 --- a/src/lib/krb5/krb/pac_sign.c +++ b/src/lib/krb5/krb/pac_sign.c @@ -38,8 +38,8 @@ k5_insert_client_info(krb5_context context, krb5_error_code ret; krb5_data client_info; char *princ_name_utf8 = NULL; - unsigned char *princ_name_ucs2 = NULL, *p; - size_t princ_name_ucs2_len = 0; + unsigned char *princ_name_utf16 = NULL, *p; + size_t princ_name_utf16_len = 0; uint64_t nt_authtime; /* If we already have a CLIENT_INFO buffer, then just validate it */ @@ -54,13 +54,12 @@ k5_insert_client_info(krb5_context context, if (ret != 0) goto cleanup; - ret = krb5int_utf8s_to_ucs2les(princ_name_utf8, - &princ_name_ucs2, - &princ_name_ucs2_len); + ret = k5_utf8_to_utf16le(princ_name_utf8, &princ_name_utf16, + &princ_name_utf16_len); if (ret != 0) goto cleanup; - client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_ucs2_len; + client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_utf16_len; client_info.data = NULL; ret = k5_pac_add_buffer(context, pac, KRB5_PAC_CLIENT_INFO, @@ -75,16 +74,16 @@ k5_insert_client_info(krb5_context context, store_64_le(nt_authtime, p); p += 8; - /* copy in number of UCS-2 characters in principal name */ - store_16_le(princ_name_ucs2_len, p); + /* copy in number of UTF-16 bytes in principal name */ + store_16_le(princ_name_utf16_len, p); p += 2; /* copy in principal name */ - memcpy(p, princ_name_ucs2, princ_name_ucs2_len); + memcpy(p, princ_name_utf16, princ_name_utf16_len); cleanup: - if (princ_name_ucs2 != NULL) - free(princ_name_ucs2); + if (princ_name_utf16 != NULL) + free(princ_name_utf16); krb5_free_unparsed_name(context, princ_name_utf8); return ret; diff --git a/src/lib/krb5/krb/plugin.c b/src/lib/krb5/krb/plugin.c index 7d64b7c7eda9..31aaf661d9af 100644 --- a/src/lib/krb5/krb/plugin.c +++ b/src/lib/krb5/krb/plugin.c @@ -57,7 +57,10 @@ const char *interface_names[] = { "hostrealm", "audit", "tls", - "kdcauthdata" + "kdcauthdata", + "certauth", + "kadm5_auth", + "kdcpolicy", }; /* Return the context's interface structure for id, or NULL if invalid. */ diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index ca26fb0e3fa5..6b96fa135e1a 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -46,14 +46,18 @@ typedef struct { struct krb5_clpreauth_vtable_st vt; krb5_clpreauth_moddata data; - krb5_clpreauth_modreq req; } *clpreauth_handle; struct krb5_preauth_context_st { - krb5_preauthtype *tried; clpreauth_handle *handles; }; +struct krb5_preauth_req_context_st { + krb5_context orig_context; + krb5_preauthtype *failed; + krb5_clpreauth_modreq *modreqs; +}; + /* Release the memory used by a list of handles. */ static void free_handles(krb5_context context, clpreauth_handle *handles) @@ -71,21 +75,44 @@ free_handles(krb5_context context, clpreauth_handle *handles) free(handles); } -/* Find the handle in handles which can process pa_type. */ -static clpreauth_handle -find_module(clpreauth_handle *handles, krb5_preauthtype pa_type) +/* Return an index into handles which can process pa_type, or -1 if none is + * found found. */ +static int +search_module_list(clpreauth_handle *handles, krb5_preauthtype pa_type) { - clpreauth_handle *hp, h; - krb5_preauthtype *tp; + clpreauth_handle h; + int i, j; - for (hp = handles; *hp != NULL; hp++) { - h = *hp; - for (tp = h->vt.pa_type_list; *tp != 0; tp++) { - if (*tp == pa_type) - return h; + for (i = 0; handles[i] != NULL; i++) { + h = handles[i]; + for (j = 0; h->vt.pa_type_list[j] != 0; j++) { + if (h->vt.pa_type_list[j] == pa_type) + return i; } } - return FALSE; + return -1; +} + +/* Find the handle which can process pa_type, or NULL if none is found. On + * success, set *modreq_out to the corresponding per-request module data. */ +static clpreauth_handle +find_module(krb5_context context, krb5_init_creds_context ctx, + krb5_preauthtype pa_type, krb5_clpreauth_modreq *modreq_out) +{ + krb5_preauth_context pctx = context->preauth_context; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + int i; + + *modreq_out = NULL; + if (pctx == NULL || reqctx == NULL) + return NULL; + + i = search_module_list(pctx->handles, pa_type); + if (i == -1) + return NULL; + + *modreq_out = reqctx->modreqs[i]; + return pctx->handles[i]; } /* Initialize the preauth state for a krb5 context. */ @@ -93,7 +120,8 @@ void k5_init_preauth_context(krb5_context context) { krb5_plugin_initvt_fn *modules = NULL, *mod; - clpreauth_handle *list = NULL, h, h2; + clpreauth_handle *list = NULL, h; + int i; size_t count; krb5_preauthtype *tp; @@ -140,9 +168,10 @@ k5_init_preauth_context(krb5_context context) /* Check for a preauth type conflict with an existing module. */ for (tp = h->vt.pa_type_list; *tp != 0; tp++) { - h2 = find_module(list, *tp); - if (h2 != NULL) { - TRACE_PREAUTH_CONFLICT(context, h->vt.name, h2->vt.name, *tp); + i = search_module_list(list, *tp); + if (i != -1) { + TRACE_PREAUTH_CONFLICT(context, h->vt.name, list[i]->vt.name, + *tp); break; } } @@ -161,10 +190,9 @@ k5_init_preauth_context(krb5_context context) list[count] = NULL; /* Place the constructed preauth context into the krb5 context. */ - context->preauth_context = malloc(sizeof(struct krb5_preauth_context_st)); + context->preauth_context = malloc(sizeof(*context->preauth_context)); if (context->preauth_context == NULL) goto cleanup; - context->preauth_context->tried = NULL; context->preauth_context->handles = list; list = NULL; @@ -173,22 +201,35 @@ cleanup: free_handles(context, list); } -/* - * Reset the memory of which preauth types we have already tried, because we - * are entering a new phase of padata processing (such as the padata in an - * AS-REP). - */ +/* Reset the memory of which preauth types we have already tried. */ void -k5_reset_preauth_types_tried(krb5_context context) +k5_reset_preauth_types_tried(krb5_init_creds_context ctx) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; - if (pctx == NULL) + if (reqctx == NULL) return; - free(pctx->tried); - pctx->tried = NULL; + free(reqctx->failed); + reqctx->failed = NULL; } +/* Add pa_type to the list of types which has previously failed. */ +krb5_error_code +k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type) +{ + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + krb5_preauthtype *newptr; + size_t i; + + for (i = 0; reqctx->failed != NULL && reqctx->failed[i] != 0; i++); + newptr = realloc(reqctx->failed, (i + 2) * sizeof(*newptr)); + if (newptr == NULL) + return ENOMEM; + reqctx->failed = newptr; + reqctx->failed[i] = pa_type; + reqctx->failed[i + 1] = 0; + return 0; +} /* Free the per-krb5_context preauth_context. This means clearing any * plugin-specific context which may have been created, and then @@ -196,11 +237,10 @@ k5_reset_preauth_types_tried(krb5_context context) void k5_free_preauth_context(krb5_context context) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_context pctx = context->preauth_context; if (pctx == NULL) return; - free(pctx->tried); free_handles(context, pctx->handles); free(pctx); context->preauth_context = NULL; @@ -209,10 +249,13 @@ k5_free_preauth_context(krb5_context context) /* Initialize the per-AS-REQ context. This means calling the client_req_init * function to give the plugin a chance to allocate a per-request context. */ void -k5_preauth_request_context_init(krb5_context context) +k5_preauth_request_context_init(krb5_context context, + krb5_init_creds_context ctx) { - struct krb5_preauth_context_st *pctx = context->preauth_context; - clpreauth_handle *hp, h; + krb5_preauth_context pctx = context->preauth_context; + clpreauth_handle h; + krb5_preauth_req_context reqctx; + size_t count, i; if (pctx == NULL) { k5_init_preauth_context(context); @@ -220,30 +263,63 @@ k5_preauth_request_context_init(krb5_context context) if (pctx == NULL) return; } - k5_reset_preauth_types_tried(context); - for (hp = pctx->handles; *hp != NULL; hp++) { - h = *hp; + + reqctx = calloc(1, sizeof(*reqctx)); + if (reqctx == NULL) + return; + reqctx->orig_context = context; + + /* Create an array of per-request module data objects corresponding to the + * preauth context's array of handles. */ + for (count = 0; pctx->handles[count] != NULL; count++); + reqctx->modreqs = calloc(count, sizeof(*reqctx->modreqs)); + for (i = 0; i < count; i++) { + h = pctx->handles[i]; if (h->vt.request_init != NULL) - h->vt.request_init(context, h->data, &h->req); + h->vt.request_init(context, h->data, &reqctx->modreqs[i]); } + ctx->preauth_reqctx = reqctx; } /* Free the per-AS-REQ context. This means clearing any request-specific * context which the plugin may have created. */ void -k5_preauth_request_context_fini(krb5_context context) +k5_preauth_request_context_fini(krb5_context context, + krb5_init_creds_context ctx) { - struct krb5_preauth_context_st *pctx = context->preauth_context; - clpreauth_handle *hp, h; + krb5_preauth_context pctx = context->preauth_context; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + size_t i; + clpreauth_handle h; - if (pctx == NULL) + if (reqctx == NULL) return; - for (hp = pctx->handles; *hp != NULL; hp++) { - h = *hp; - if (h->req != NULL && h->vt.request_fini != NULL) - h->vt.request_fini(context, h->data, h->req); - h->req = NULL; + if (reqctx->orig_context == context && pctx != NULL) { + for (i = 0; pctx->handles[i] != NULL; i++) { + h = pctx->handles[i]; + if (reqctx->modreqs[i] != NULL && h->vt.request_fini != NULL) + h->vt.request_fini(context, h->data, reqctx->modreqs[i]); + } + } else { + TRACE_PREAUTH_WRONG_CONTEXT(context); + } + free(reqctx->modreqs); + free(reqctx->failed); + free(reqctx); + ctx->preauth_reqctx = NULL; +} + +krb5_error_code +k5_preauth_check_context(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + + if (reqctx != NULL && reqctx->orig_context != context) { + k5_setmsg(context, EINVAL, + _("krb5_init_creds calls must use same library context")); + return EINVAL; } + return 0; } /* Return 1 if pa_type is a real preauthentication mechanism according to the @@ -259,6 +335,7 @@ clpreauth_is_real(krb5_context context, clpreauth_handle h, static krb5_error_code clpreauth_prep_questions(krb5_context context, clpreauth_handle h, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, krb5_kdc_req *req, krb5_data *req_body, @@ -266,35 +343,35 @@ clpreauth_prep_questions(krb5_context context, clpreauth_handle h, { if (h->vt.prep_questions == NULL) return 0; - return h->vt.prep_questions(context, h->data, h->req, opt, cb, rock, req, + return h->vt.prep_questions(context, h->data, modreq, opt, cb, rock, req, req_body, prev_req, pa_data); } static krb5_error_code clpreauth_process(krb5_context context, clpreauth_handle h, - krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, - krb5_clpreauth_rock rock, krb5_kdc_req *req, - krb5_data *req_body, krb5_data *prev_req, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_kdc_req *req, krb5_data *req_body, krb5_data *prev_req, krb5_pa_data *pa_data, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***pa_data_out) { - return h->vt.process(context, h->data, h->req, opt, cb, rock, req, + return h->vt.process(context, h->data, modreq, opt, cb, rock, req, req_body, prev_req, pa_data, prompter, prompter_data, pa_data_out); } static krb5_error_code clpreauth_tryagain(krb5_context context, clpreauth_handle h, - krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, - krb5_clpreauth_rock rock, krb5_kdc_req *req, - krb5_data *req_body, krb5_data *prev_req, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_kdc_req *req, krb5_data *req_body, krb5_data *prev_req, krb5_preauthtype pa_type, krb5_error *error, krb5_pa_data **error_padata, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***pa_data_out) { if (h->vt.tryagain == NULL) return 0; - return h->vt.tryagain(context, h->data, h->req, opt, cb, rock, req, + return h->vt.tryagain(context, h->data, modreq, opt, cb, rock, req, req_body, prev_req, pa_type, error, error_padata, prompter, prompter_data, pa_data_out); } @@ -420,7 +497,7 @@ responder_get_answer(krb5_context context, krb5_clpreauth_rock rock, krb5_init_creds_context ctx = (krb5_init_creds_context)rock; /* Don't let plugins get the raw password. */ - if (question && strcmp(KRB5_RESPONDER_QUESTION_PASSWORD, question) == 0) + if (strcmp(KRB5_RESPONDER_QUESTION_PASSWORD, question) == 0) return NULL; return k5_response_items_get_answer(ctx->rctx.items, question); } @@ -495,7 +572,7 @@ void k5_preauth_prepare_request(krb5_context context, krb5_get_init_creds_opt *opt, krb5_kdc_req *req) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_context pctx = context->preauth_context; clpreauth_handle *hp, h; krb5_enctype *ep; @@ -548,28 +625,17 @@ pa_type_allowed(krb5_init_creds_context ctx, krb5_preauthtype pa_type) pa_type == ctx->allowed_preauth_type; } -/* - * If pa_type has already been tried as a real preauth type for this - * authentication, return true. Otherwise ass pa_type to the list of tried - * types and return false. - */ +/* Return true if pa_type previously failed during this authentication. */ static krb5_boolean -already_tried(krb5_context context, krb5_preauthtype pa_type) +previously_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type) { - struct krb5_preauth_context_st *pctx = context->preauth_context; - size_t count; - krb5_preauthtype *newptr; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + size_t i; - for (count = 0; pctx->tried != NULL && pctx->tried[count] != 0; count++) { - if (pctx->tried[count] == pa_type) + for (i = 0; reqctx->failed != NULL && reqctx->failed[i] != 0; i++) { + if (reqctx->failed[i] == pa_type) return TRUE; } - newptr = realloc(pctx->tried, (count + 2) * sizeof(*newptr)); - if (newptr == NULL) - return FALSE; - pctx->tried = newptr; - pctx->tried[count] = pa_type; - pctx->tried[count + 1] = ENCTYPE_NULL; return FALSE; } @@ -580,16 +646,13 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, krb5_pa_data ***out_pa_list, int *out_pa_list_size, krb5_preauthtype *out_type) { - struct krb5_preauth_context_st *pctx = context->preauth_context; struct errinfo save = EMPTY_ERRINFO; krb5_pa_data *pa, **pa_ptr, **mod_pa; krb5_error_code ret = 0; + krb5_clpreauth_modreq modreq; clpreauth_handle h; int real, i; - if (pctx == NULL) - return ENOENT; - /* Process all informational padata types, then the first real preauth type * we succeed on. */ for (real = 0; real <= 1; real++) { @@ -598,17 +661,17 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, /* Restrict real mechanisms to the chosen one if we have one. */ if (real && !pa_type_allowed(ctx, pa->pa_type)) continue; - h = find_module(pctx->handles, pa->pa_type); + h = find_module(context, ctx, pa->pa_type, &modreq); if (h == NULL) continue; /* Make sure this type is for the current pass. */ if (clpreauth_is_real(context, h, pa->pa_type) != real) continue; - /* Only try a real mechanism once per authentication. */ - if (real && already_tried(context, pa->pa_type)) + /* Don't try a real mechanism again after failure. */ + if (real && previously_failed(ctx, pa->pa_type)) continue; mod_pa = NULL; - ret = clpreauth_process(context, h, ctx->opt, &callbacks, + ret = clpreauth_process(context, h, modreq, ctx->opt, &callbacks, (krb5_clpreauth_rock)ctx, ctx->request, ctx->inner_request_body, ctx->encoded_previous_request, pa, @@ -625,6 +688,9 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, } free(mod_pa); } + /* Don't continue to try mechanisms after a keyboard interrupt. */ + if (ret == KRB5_LIBOS_PWDINTR) + goto cleanup; if (ret == 0 && real) { /* Stop now and record which real padata type we answered. */ *out_type = pa->pa_type; @@ -633,6 +699,12 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, /* Save the first error we get from a real preauth type. */ k5_save_ctx_error(context, ret, &save); } + if (real && ret) { + /* Don't try this mechanism again for this authentication. */ + ret = k5_preauth_note_failed(ctx, pa->pa_type); + if (ret) + goto cleanup; + } } } @@ -850,45 +922,54 @@ add_s4u_x509_user_padata(krb5_context context, krb5_s4u_userid *userid, } /* - * If one of the modules can adjust its AS_REQ data using the contents of the - * err_reply, return 0. If it's the sort of correction which requires that we - * ask the user another question, we let the calling application deal with it. + * If the module for pa_type can adjust its AS_REQ data using the contents of + * err and err_padata, return 0 with *padata_out set to a padata list for the + * next request. If it's the sort of correction which requires that we ask the + * user another question, we let the calling application deal with it. */ krb5_error_code k5_preauth_tryagain(krb5_context context, krb5_init_creds_context ctx, - krb5_pa_data **in_padata, krb5_pa_data ***padata_out) + krb5_preauthtype pa_type, krb5_error *err, + krb5_pa_data **err_padata, krb5_pa_data ***padata_out) { - struct krb5_preauth_context_st *pctx = context->preauth_context; krb5_error_code ret; krb5_pa_data **mod_pa; + krb5_clpreauth_modreq modreq; clpreauth_handle h; - int i; + int count; *padata_out = NULL; - if (pctx == NULL) - return KRB5KRB_ERR_GENERIC; - TRACE_PREAUTH_TRYAGAIN_INPUT(context, in_padata); + TRACE_PREAUTH_TRYAGAIN_INPUT(context, pa_type, err_padata); - for (i = 0; in_padata[i] != NULL; i++) { - h = find_module(pctx->handles, in_padata[i]->pa_type); - if (h == NULL) - continue; - mod_pa = NULL; - ret = clpreauth_tryagain(context, h, ctx->opt, &callbacks, - (krb5_clpreauth_rock)ctx, ctx->request, - ctx->inner_request_body, - ctx->encoded_previous_request, - in_padata[i]->pa_type, - ctx->err_reply, ctx->err_padata, - ctx->prompter, ctx->prompter_data, &mod_pa); - if (ret == 0 && mod_pa != NULL) { - TRACE_PREAUTH_TRYAGAIN_OUTPUT(context, mod_pa); - *padata_out = mod_pa; - return 0; - } + h = find_module(context, ctx, pa_type, &modreq); + if (h == NULL) + return KRB5KRB_ERR_GENERIC; + mod_pa = NULL; + ret = clpreauth_tryagain(context, h, modreq, ctx->opt, &callbacks, + (krb5_clpreauth_rock)ctx, ctx->request, + ctx->inner_request_body, + ctx->encoded_previous_request, pa_type, err, + err_padata, ctx->prompter, ctx->prompter_data, + &mod_pa); + TRACE_PREAUTH_TRYAGAIN(context, h->vt.name, pa_type, ret); + if (!ret && mod_pa == NULL) + ret = KRB5KRB_ERR_GENERIC; + if (ret) { + k5_preauth_note_failed(ctx, pa_type); + return ret; } - return KRB5KRB_ERR_GENERIC; + + for (count = 0; mod_pa[count] != NULL; count++); + ret = copy_cookie(context, err_padata, &mod_pa, &count); + if (ret) { + krb5_free_pa_data(context, mod_pa); + return ret; + } + + TRACE_PREAUTH_TRYAGAIN_OUTPUT(context, mod_pa); + *padata_out = mod_pa; + return 0; } /* Compile the set of response items for in_padata by invoke each module's @@ -897,9 +978,9 @@ static krb5_error_code fill_response_items(krb5_context context, krb5_init_creds_context ctx, krb5_pa_data **in_padata) { - struct krb5_preauth_context_st *pctx = context->preauth_context; krb5_error_code ret; krb5_pa_data *pa; + krb5_clpreauth_modreq modreq; clpreauth_handle h; int i; @@ -908,11 +989,11 @@ fill_response_items(krb5_context context, krb5_init_creds_context ctx, pa = in_padata[i]; if (!pa_type_allowed(ctx, pa->pa_type)) continue; - h = find_module(pctx->handles, pa->pa_type); + h = find_module(context, ctx, pa->pa_type, &modreq); if (h == NULL) continue; - ret = clpreauth_prep_questions(context, h, ctx->opt, &callbacks, - (krb5_clpreauth_rock)ctx, + ret = clpreauth_prep_questions(context, h, modreq, ctx->opt, + &callbacks, (krb5_clpreauth_rock)ctx, ctx->request, ctx->inner_request_body, ctx->encoded_previous_request, pa); if (ret) @@ -1004,7 +1085,7 @@ krb5_preauth_supply_preauth_data(krb5_context context, krb5_get_init_creds_opt *opt, const char *attr, const char *value) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_context pctx = context->preauth_context; clpreauth_handle *hp, h; krb5_error_code ret; diff --git a/src/lib/krb5/krb/preauth_ec.c b/src/lib/krb5/krb/preauth_ec.c index b1978336a063..c1aa9090fb6c 100644 --- a/src/lib/krb5/krb/preauth_ec.c +++ b/src/lib/krb5/krb/preauth_ec.c @@ -58,6 +58,8 @@ ec_process(krb5_context context, krb5_clpreauth_moddata moddata, krb5_keyblock *challenge_key = NULL, *armor_key, *as_key; armor_key = cb->fast_armor(context, rock); + if (armor_key == NULL) + return ENOENT; retval = cb->get_as_key(context, rock, &as_key); if (retval == 0 && padata->length) { krb5_enc_data *enc = NULL; diff --git a/src/lib/krb5/krb/send_tgs.c b/src/lib/krb5/krb/send_tgs.c index f6fdf68d4725..e43a5cc5b135 100644 --- a/src/lib/krb5/krb/send_tgs.c +++ b/src/lib/krb5/krb/send_tgs.c @@ -28,6 +28,25 @@ #include "int-proto.h" #include "fast.h" +/* Choose a random nonce for an AS or TGS request. */ +krb5_error_code +k5_generate_nonce(krb5_context context, int32_t *out) +{ + krb5_error_code ret; + unsigned char random_buf[4]; + krb5_data random_data = make_data(random_buf, 4); + + *out = 0; + + /* We and Heimdal incorrectly encode nonces as signed, so make sure we use + * a non-negative value to avoid interoperability issues. */ + ret = krb5_c_random_make_octets(context, &random_data); + if (ret) + return ret; + *out = 0x7FFFFFFF & load_32_n(random_buf); + return 0; +} + /* Construct an AP-REQ message for a TGS request. */ static krb5_error_code tgs_construct_ap_req(krb5_context context, krb5_data *checksum_data, @@ -156,10 +175,13 @@ k5_make_tgs_req(krb5_context context, req.till = desired->times.endtime ? desired->times.endtime : tgt->times.endtime; req.rtime = desired->times.renew_till; + ret = k5_generate_nonce(context, &req.nonce); + if (ret) + return ret; + *nonce_out = req.nonce; ret = krb5_timeofday(context, &time_now); if (ret) return ret; - *nonce_out = req.nonce = (krb5_int32)time_now; *timestamp_out = time_now; req.addresses = (krb5_address **)addrs; diff --git a/src/lib/krb5/krb/sendauth.c b/src/lib/krb5/krb/sendauth.c index f7e6777411aa..149e25dd7362 100644 --- a/src/lib/krb5/krb/sendauth.c +++ b/src/lib/krb5/krb/sendauth.c @@ -131,22 +131,21 @@ krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, This isn't strong cryptographically; the point here is not to guarantee randomness, but to make it less likely that multiple sessions could pick the same subkey. */ - char rnd_data[1024]; + struct sockaddr_storage rnd_data; GETPEERNAME_ARG3_TYPE len2; - krb5_data d; - d.length = sizeof (rnd_data); - d.data = rnd_data; - len2 = sizeof (rnd_data); - if (getpeername (*(int*)fd, (GETPEERNAME_ARG2_TYPE *) rnd_data, - &len2) == 0) { + krb5_data d = make_data(&rnd_data, sizeof(rnd_data)); + + len2 = sizeof(rnd_data); + if (getpeername(*(int *)fd, ss2sa(&rnd_data), &len2) == 0) { d.length = len2; - (void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); + (void)krb5_c_random_add_entropy( + context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); } - len2 = sizeof (rnd_data); - if (getsockname (*(int*)fd, (GETSOCKNAME_ARG2_TYPE *) rnd_data, - &len2) == 0) { + len2 = sizeof(rnd_data); + if (getsockname(*(int *)fd, ss2sa(&rnd_data), &len2) == 0) { d.length = len2; - (void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); + (void)krb5_c_random_add_entropy( + context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); } } diff --git a/src/lib/krb5/krb/str_conv.c b/src/lib/krb5/krb/str_conv.c index 3ab7eacac1c0..f0a2ae20bab5 100644 --- a/src/lib/krb5/krb/str_conv.c +++ b/src/lib/krb5/krb/str_conv.c @@ -207,7 +207,7 @@ krb5_error_code KRB5_CALLCONV krb5_timestamp_to_string(krb5_timestamp timestamp, char *buffer, size_t buflen) { size_t ret; - time_t timestamp2 = timestamp; + time_t timestamp2 = ts2tt(timestamp); struct tm tmbuf; const char *fmt = "%c"; /* This is to get around gcc -Wall warning that the year returned might be two digits */ @@ -229,7 +229,7 @@ krb5_timestamp_to_sfstring(krb5_timestamp timestamp, char *buffer, size_t buflen struct tm *tmp; size_t i; size_t ndone; - time_t timestamp2 = timestamp; + time_t timestamp2 = ts2tt(timestamp); struct tm tmbuf; static const char * const sftime_format_table[] = { diff --git a/src/lib/krb5/krb/t_expire_warn.py b/src/lib/krb5/krb/t_expire_warn.py index e021379ab1cf..aed39e3995ab 100755 --- a/src/lib/krb5/krb/t_expire_warn.py +++ b/src/lib/krb5/krb/t_expire_warn.py @@ -39,15 +39,10 @@ realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '3 days', 'days']) output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '0']) if output: fail('Unexpected output for noexpire') -output = realm.run(['./t_expire_warn', 'minutes', 'pass', '0']) -if ' less than one hour on ' not in output: - fail('Expected warning not seen for minutes') -output = realm.run(['./t_expire_warn', 'hours', 'pass', '0']) -if ' hours on ' not in output: - fail('Expected warning not seen for hours') -output = realm.run(['./t_expire_warn', 'days', 'pass', '0']) -if ' days on ' not in output: - fail('Expected warning not seen for days') +realm.run(['./t_expire_warn', 'minutes', 'pass', '0'], + expected_msg=' less than one hour on ') +realm.run(['./t_expire_warn', 'hours', 'pass', '0'], expected_msg=' hours on ') +realm.run(['./t_expire_warn', 'days', 'pass', '0'], expected_msg=' days on ') # Check for expected expire callback behavior. These tests are # carefully agnostic about whether the KDC supports last_req fields, diff --git a/src/lib/krb5/krb/t_kerb.c b/src/lib/krb5/krb/t_kerb.c index 60cfb5b15115..74ac14d9ab64 100644 --- a/src/lib/krb5/krb/t_kerb.c +++ b/src/lib/krb5/krb/t_kerb.c @@ -5,16 +5,8 @@ */ #include "autoconf.h" -#include "krb5.h" -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> +#include "k5-int.h" #include <time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> #include "com_err.h" @@ -37,7 +29,7 @@ test_string_to_timestamp(krb5_context ctx, char *ktime) com_err("krb5_string_to_timestamp", retval, 0); return; } - t = (time_t) timestamp; + t = ts2tt(timestamp); printf("Parsed time was %s", ctime(&t)); } diff --git a/src/lib/krb5/krb/t_parse_host_string.c b/src/lib/krb5/krb/t_parse_host_string.c index 76dd20f817b0..001b77389555 100644 --- a/src/lib/krb5/krb/t_parse_host_string.c +++ b/src/lib/krb5/krb/t_parse_host_string.c @@ -31,10 +31,7 @@ */ #include "k5-int.h" -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <cmocka.h> +#include "k5-cmocka.h" #include <malloc.h> /* Call k5_parse_host_string() and check the result against the expected code, diff --git a/src/lib/krb5/krb/t_valid_times.c b/src/lib/krb5/krb/t_valid_times.c new file mode 100644 index 000000000000..1b469ffc252f --- /dev/null +++ b/src/lib/krb5/krb/t_valid_times.c @@ -0,0 +1,109 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/krb5/krb/t_valid_times.c - test program for krb5int_validate_times() */ +/* + * Copyright (C) 2017 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "k5-int.h" +#include "int-proto.h" + +#define BOUNDARY (uint32_t)INT32_MIN + +int +main() +{ + krb5_error_code ret; + krb5_context context; + krb5_ticket_times times = { 0, 0, 0, 0 }; + + ret = krb5_init_context(&context); + assert(!ret); + + /* Current time is within authtime and end time. */ + ret = krb5_set_debugging_time(context, 1000, 0); + times.authtime = 500; + times.endtime = 1500; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime, but within clock skew. */ + times.starttime = 1100; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime by more than clock skew. */ + times.starttime = 1400; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_NYV); + + /* Current time is after end time, but within clock skew. */ + times.starttime = 500; + times.endtime = 800; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is after end time by more than clock skew. */ + times.endtime = 600; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED); + + /* Current time is within starttime and endtime; current time and + * endtime are across y2038 boundary. */ + ret = krb5_set_debugging_time(context, BOUNDARY - 100, 0); + assert(!ret); + times.starttime = BOUNDARY - 200; + times.endtime = BOUNDARY + 500; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime, but by less than clock skew. */ + times.starttime = BOUNDARY + 100; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime by more than clock skew. */ + times.starttime = BOUNDARY + 250; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_NYV); + + /* Current time is after endtime, but by less than clock skew. */ + ret = krb5_set_debugging_time(context, BOUNDARY + 100, 0); + assert(!ret); + times.starttime = BOUNDARY - 1000; + times.endtime = BOUNDARY - 100; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is after endtime by more than clock skew. */ + times.endtime = BOUNDARY - 300; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED); + + return 0; +} diff --git a/src/lib/krb5/krb/valid_times.c b/src/lib/krb5/krb/valid_times.c index d63122183eff..294761a882c5 100644 --- a/src/lib/krb5/krb/valid_times.c +++ b/src/lib/krb5/krb/valid_times.c @@ -47,10 +47,10 @@ krb5int_validate_times(krb5_context context, krb5_ticket_times *times) else starttime = times->authtime; - if (starttime - currenttime > context->clockskew) + if (ts_after(starttime, ts_incr(currenttime, context->clockskew))) return KRB5KRB_AP_ERR_TKT_NYV; /* ticket not yet valid */ - if ((currenttime - times->endtime) > context->clockskew) + if (ts_after(currenttime, ts_incr(times->endtime, context->clockskew))) return KRB5KRB_AP_ERR_TKT_EXPIRED; /* ticket expired */ return 0; diff --git a/src/lib/krb5/krb/vfy_increds.c b/src/lib/krb5/krb/vfy_increds.c index 9786d63b5cb1..b4878ba3852e 100644 --- a/src/lib/krb5/krb/vfy_increds.c +++ b/src/lib/krb5/krb/vfy_increds.c @@ -120,7 +120,7 @@ get_vfy_cred(krb5_context context, krb5_creds *creds, krb5_principal server, ret = krb5_timeofday(context, &in_creds.times.endtime); if (ret) goto cleanup; - in_creds.times.endtime += 5*60; + in_creds.times.endtime = ts_incr(in_creds.times.endtime, 5 * 60); ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds); if (ret) goto cleanup; diff --git a/src/lib/krb5/krb/x-deltat.y b/src/lib/krb5/krb/x-deltat.y index f9cc2bb46959..da11b88077aa 100644 --- a/src/lib/krb5/krb/x-deltat.y +++ b/src/lib/krb5/krb/x-deltat.y @@ -44,7 +44,6 @@ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif #include "k5-int.h" |