From 5af5b2d5e798ab533fdddf6fd5e3722568465ada Mon Sep 17 00:00:00 2001 From: CentOS Buildsys Date: Nov 08 2013 20:08:13 +0000 Subject: import krb5-1.11.3-31.el7.src.rpm --- diff --git a/.krb5.metadata b/.krb5.metadata new file mode 100644 index 0000000..7730c75 --- /dev/null +++ b/.krb5.metadata @@ -0,0 +1,4 @@ +ac6a2109eff848cf8ffac5b30e2b516ebe826a66 SOURCES/krb5-1.11.3-pdf.tar.xz +a6c973b0658d244afdf12a39270227865ac13500 SOURCES/nss_wrapper-0.0-20130719153839Z.git6cb59864.bz2 +28a0a3d3a4a9837fb2a5124bc8aa81efb8fef1e5 SOURCES/krb5-1.11.3.tar.gz +8437e10cbb315529a87f835ccea97ff827d7a310 SOURCES/krb5-1.11.3.tar.gz.asc diff --git a/README.md b/README.md deleted file mode 100644 index 0e7897f..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 - -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/0000-ksu-intermediates.patch b/SOURCES/0000-ksu-intermediates.patch new file mode 100644 index 0000000..d567116 --- /dev/null +++ b/SOURCES/0000-ksu-intermediates.patch @@ -0,0 +1,13 @@ +Collect changes that prevent the ksu collections changes from being directly +pullable from master (or, as of this writing, the proposed changes for master). +--- krb5/src/clients/ksu/main.c ++++ krb5/src/clients/ksu/main.c +@@ -706,7 +706,7 @@ main (argc, argv) + } + + if(set_env_var( "HOME", target_pwd->pw_dir)){ +- fprintf(stderr, _("ksu: couldn't set environment variable USER\n")); ++ fprintf(stderr, _("ksu: couldn't set environment variable HOME\n")); + sweep_up(ksu_context, cc_target); + exit(1); + } diff --git a/SOURCES/0001-Don-t-try-to-stat-not-on-disk-ccache-residuals.patch b/SOURCES/0001-Don-t-try-to-stat-not-on-disk-ccache-residuals.patch new file mode 100644 index 0000000..2a6275c --- /dev/null +++ b/SOURCES/0001-Don-t-try-to-stat-not-on-disk-ccache-residuals.patch @@ -0,0 +1,269 @@ +From 7e0bcb958eb5861cb30a190dcac1e6422d65299e Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Fri, 1 Nov 2013 09:48:13 -0400 +Subject: [PATCH 1/6] Don't try to stat() not-on-disk ccache residuals + +Don't assume that ccache residual names are filenames which we can +stat() usefully. Instead, use helper functions to call the library +routines to try to read the default principal name from caches. +--- + src/clients/ksu/ccache.c | 88 +++++++++++++++++++++++++++++------------------- + src/clients/ksu/ksu.h | 6 ++++ + src/clients/ksu/main.c | 17 +++++----- + 3 files changed, 68 insertions(+), 43 deletions(-) + +diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c +index 9916c75..7917af2 100644 +--- a/src/clients/ksu/ccache.c ++++ b/src/clients/ksu/ccache.c +@@ -60,12 +60,10 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, + { + int i=0; + krb5_ccache * cc_other; +- const char * cc_def_name; +- const char * cc_other_name; ++ const char * cc_other_type; + krb5_error_code retval=0; + krb5_creds ** cc_def_creds_arr = NULL; + krb5_creds ** cc_other_creds_arr = NULL; +- struct stat st_temp; + + cc_other = (krb5_ccache *) xcalloc(1, sizeof (krb5_ccache)); + +@@ -74,10 +72,9 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, + return retval; + } + +- cc_def_name = krb5_cc_get_name(context, cc_def); +- cc_other_name = krb5_cc_get_name(context, *cc_other); ++ cc_other_type = krb5_cc_get_type(context, *cc_other); + +- if ( ! stat(cc_def_name, &st_temp)){ ++ if (krb5_ccache_is_initialized(context, cc_def)) { + if((retval = krb5_get_nonexp_tkts(context,cc_def,&cc_def_creds_arr))){ + return retval; + } +@@ -86,7 +83,8 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, + *stored = krb5_find_princ_in_cred_list(context, cc_def_creds_arr, + primary_principal); + +- if (!lstat( cc_other_name, &st_temp)) ++ if (!krb5_cc_support_switch(context, cc_other_type) && ++ krb5_ccache_name_is_initialized(context, cc_other_tag)) + return EINVAL; + + if (krb5_seteuid(0)||krb5_seteuid(target_uid)) { +@@ -533,24 +531,18 @@ krb5_error_code krb5_ccache_overwrite(context, ccs, cct, primary_principal) + krb5_ccache cct; + krb5_principal primary_principal; + { +- const char * cct_name; +- const char * ccs_name; + krb5_error_code retval=0; + krb5_principal temp_principal; + krb5_creds ** ccs_creds_arr = NULL; + int i=0; +- struct stat st_temp; + +- ccs_name = krb5_cc_get_name(context, ccs); +- cct_name = krb5_cc_get_name(context, cct); +- +- if ( ! stat(ccs_name, &st_temp)){ ++ if (krb5_ccache_is_initialized(context, ccs)) { + if ((retval = krb5_get_nonexp_tkts(context, ccs, &ccs_creds_arr))){ + return retval; + } + } + +- if ( ! stat(cct_name, &st_temp)){ ++ if (krb5_ccache_is_initialized(context, cct)) { + if ((retval = krb5_cc_get_principal(context, cct, &temp_principal))){ + return retval; + } +@@ -649,12 +641,10 @@ krb5_error_code krb5_ccache_copy_restricted (context, cc_def, cc_other_tag, + + int i=0; + krb5_ccache * cc_other; +- const char * cc_def_name; +- const char * cc_other_name; ++ const char * cc_other_type; + krb5_error_code retval=0; + krb5_creds ** cc_def_creds_arr = NULL; + krb5_creds ** cc_other_creds_arr = NULL; +- struct stat st_temp; + + cc_other = (krb5_ccache *) xcalloc(1, sizeof (krb5_ccache)); + +@@ -663,19 +653,17 @@ krb5_error_code krb5_ccache_copy_restricted (context, cc_def, cc_other_tag, + return retval; + } + +- cc_def_name = krb5_cc_get_name(context, cc_def); +- cc_other_name = krb5_cc_get_name(context, *cc_other); ++ cc_other_type = krb5_cc_get_type(context, *cc_other); + +- if ( ! stat(cc_def_name, &st_temp)){ +- if((retval = krb5_get_nonexp_tkts(context,cc_def,&cc_def_creds_arr))){ ++ if (krb5_ccache_is_initialized(context, cc_def)) { ++ retval = krb5_get_nonexp_tkts(context, cc_def, &cc_def_creds_arr); ++ if (retval) + return retval; +- } +- + } + +- if (!lstat( cc_other_name, &st_temp)) { ++ if (!krb5_cc_support_switch(context, cc_other_type) && ++ krb5_ccache_name_is_initialized(context, cc_other_tag)) + return EINVAL; +- } + + if (krb5_seteuid(0)||krb5_seteuid(target_uid)) { + return errno; +@@ -723,12 +711,10 @@ krb5_error_code krb5_ccache_filter (context, cc, prst) + krb5_creds ** cc_creds_arr = NULL; + const char * cc_name; + krb5_boolean stored; +- struct stat st_temp; + + cc_name = krb5_cc_get_name(context, cc); + +- if ( ! stat(cc_name, &st_temp)){ +- ++ if (krb5_ccache_is_initialized(context, cc)) { + if (auth_debug) { + fprintf(stderr,"putting cache %s through a filter for -z option\n", cc_name); + } +@@ -793,12 +779,8 @@ krb5_error_code krb5_find_princ_in_cache (context, cc, princ, found) + { + krb5_error_code retval; + krb5_creds ** creds_list = NULL; +- const char * cc_name; +- struct stat st_temp; + +- cc_name = krb5_cc_get_name(context, cc); +- +- if ( ! stat(cc_name, &st_temp)){ ++ if (krb5_ccache_is_initialized(context, cc)) { + if ((retval = krb5_get_nonexp_tkts(context, cc, &creds_list))){ + return retval; + } +@@ -807,3 +789,41 @@ krb5_error_code krb5_find_princ_in_cache (context, cc, princ, found) + *found = krb5_find_princ_in_cred_list(context, creds_list, princ); + return 0; + } ++ ++extern krb5_boolean ++krb5_ccache_name_is_initialized(krb5_context context, const char *cctag) ++{ ++ krb5_error_code retval = 0; ++ krb5_ccache cc; ++ krb5_principal princ; ++ ++ retval = krb5_cc_resolve(context, cctag, &cc); ++ if (retval) ++ return FALSE; ++ ++ retval = krb5_cc_get_principal(context, cc, &princ); ++ if (retval == 0) ++ krb5_free_principal(context, princ); ++ krb5_cc_close(context, cc); ++ ++ return retval == 0; ++} ++ ++extern krb5_boolean ++krb5_ccache_is_initialized(krb5_context context, krb5_ccache def_cc) ++{ ++ krb5_error_code retval = 0; ++ krb5_boolean result; ++ char *def_cc_name; ++ ++ if (def_cc == NULL) ++ return FALSE; ++ ++ retval = krb5_cc_get_full_name(context, def_cc, &def_cc_name); ++ if (retval) ++ return FALSE; ++ ++ result = krb5_ccache_name_is_initialized(context, def_cc_name); ++ krb5_free_string(context, def_cc_name); ++ return result; ++} +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index f2c0811..2a63c21 100644 +--- a/src/clients/ksu/ksu.h ++++ b/src/clients/ksu/ksu.h +@@ -141,6 +141,12 @@ extern krb5_error_code krb5_store_some_creds + (krb5_context, krb5_ccache, krb5_creds **, krb5_creds **, + krb5_principal, krb5_boolean *); + ++extern krb5_boolean krb5_ccache_name_is_initialized ++(krb5_context, const char *); ++ ++extern krb5_boolean krb5_ccache_is_initialized ++(krb5_context, krb5_ccache); ++ + extern krb5_error_code krb5_ccache_copy_restricted + (krb5_context, krb5_ccache, char *, krb5_principal, + krb5_ccache *, krb5_boolean *, uid_t); +diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c +index 233eb52..e2ca06a 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -112,7 +112,6 @@ main (argc, argv) + extern char * getpass(), *crypt(); + int pargc; + char ** pargv; +- struct stat st_temp; + krb5_boolean stored = FALSE; + krb5_principal kdc_server; + krb5_boolean zero_password; +@@ -265,9 +264,10 @@ main (argc, argv) + if ( strchr(cc_source_tag, ':')){ + cc_source_tag_tmp = strchr(cc_source_tag, ':') + 1; + +- if( stat( cc_source_tag_tmp, &st_temp)){ ++ if (!krb5_ccache_name_is_initialized(ksu_context, ++ cc_source_tag)) { + com_err(prog_name, errno, +- _("while looking for credentials file %s"), ++ _("while looking for credentials cache %s"), + cc_source_tag_tmp); + exit (1); + } +@@ -432,7 +432,8 @@ main (argc, argv) + (long) target_uid, gen_sym()); + cc_target_tag_tmp = strchr(cc_target_tag, ':') + 1; + +- }while ( !stat ( cc_target_tag_tmp, &st_temp)); ++ } while (krb5_ccache_name_is_initialized(ksu_context, ++ cc_target_tag)); + } + + +@@ -884,8 +885,6 @@ static void sweep_up(context, cc) + krb5_ccache cc; + { + krb5_error_code retval; +- const char * cc_name; +- struct stat st_temp; + + krb5_seteuid(0); + if (krb5_seteuid(target_uid) < 0) { +@@ -894,9 +893,9 @@ static void sweep_up(context, cc) + exit(1); + } + +- cc_name = krb5_cc_get_name(context, cc); +- if ( ! stat(cc_name, &st_temp)){ +- if ((retval = krb5_cc_destroy(context, cc))) ++ if (krb5_ccache_is_initialized(context, cc)) { ++ retval = krb5_cc_destroy(context, cc); ++ if (retval) + com_err(prog_name, retval, _("while destroying cache")); + } + } +-- +1.8.4.2 + diff --git a/SOURCES/0002-Use-an-in-memory-cache-until-we-need-the-target-s.patch b/SOURCES/0002-Use-an-in-memory-cache-until-we-need-the-target-s.patch new file mode 100644 index 0000000..7b900de --- /dev/null +++ b/SOURCES/0002-Use-an-in-memory-cache-until-we-need-the-target-s.patch @@ -0,0 +1,321 @@ +From 60295a63fadf04f6cd6db7919aa1dad6fb4f0596 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Wed, 30 Oct 2013 21:45:35 -0400 +Subject: [PATCH 2/6] Use an in-memory cache until we need the target's + +Instead of copying source or obtained creds into the target cache and +changing ownership if everything succeeds, copy them into a MEMORY: +cache and then, if everything succeeds, create the target cache as the +target user. +--- + src/clients/ksu/ksu.h | 1 + + src/clients/ksu/main.c | 133 +++++++++++++++++++++++++++++-------------------- + 2 files changed, 80 insertions(+), 54 deletions(-) + +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index 2a63c21..1d102a1 100644 +--- a/src/clients/ksu/ksu.h ++++ b/src/clients/ksu/ksu.h +@@ -45,6 +45,7 @@ + #define KRB5_DEFAULT_TKT_LIFE 60*60*12 /* 12 hours */ + + #define KRB5_SECONDARY_CACHE "FILE:/tmp/krb5cc_" ++#define KRB5_TEMPORARY_CACHE "MEMORY:_ksu" + + #define KRB5_LOGIN_NAME ".k5login" + #define KRB5_USERS_NAME ".k5users" +diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c +index e2ca06a..fa86c78 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -86,7 +86,7 @@ main (argc, argv) + int statusp=0; + krb5_error_code retval = 0; + krb5_principal client = NULL; +- krb5_ccache cc_target = NULL; ++ krb5_ccache cc_tmp = NULL, cc_target = NULL; + krb5_context ksu_context; + char * cc_target_tag = NULL; + char * target_user = NULL; +@@ -452,14 +452,15 @@ main (argc, argv) + } + + /* +- Only when proper authentication and authorization +- takes place, the target user becomes the owner of the cache. +- */ +- +- /* we continue to run as source uid until +- the middle of the copy, when becomewe become the target user +- The cache is owned by the target user.*/ ++ * Only after proper authentication and authorization has ++ * taken place, do we populate a cache for the target user. ++ */ + ++ /* ++ * We read the set of creds we want to copy from the source ccache as the ++ * source uid, become root for authentication, and then become the target ++ * user to handle authorization and creating the target user's cache. ++ */ + + /* if root ksu's to a regular user, then + then only the credentials for that particular user +@@ -468,19 +469,23 @@ main (argc, argv) + if ((source_uid == 0) && (target_uid != 0)) { + + if ((retval = krb5_ccache_copy_restricted(ksu_context, cc_source, +- cc_target_tag, client, +- &cc_target, &stored, +- target_uid))){ ++ KRB5_TEMPORARY_CACHE, client, ++ &cc_tmp, &stored, ++ 0))){ + com_err(prog_name, retval, _("while copying cache %s to %s"), +- krb5_cc_get_name(ksu_context, cc_source), cc_target_tag); ++ krb5_cc_get_name(ksu_context, cc_source), ++ KRB5_TEMPORARY_CACHE); + exit(1); + } + + } else { +- if ((retval = krb5_ccache_copy(ksu_context, cc_source, cc_target_tag, +- client,&cc_target, &stored, target_uid))) { ++ ++ retval = krb5_ccache_copy(ksu_context, cc_source, KRB5_TEMPORARY_CACHE, ++ client, &cc_tmp, &stored, 0); ++ if (retval) { + com_err(prog_name, retval, _("while copying cache %s to %s"), +- krb5_cc_get_name(ksu_context, cc_source), cc_target_tag); ++ krb5_cc_get_name(ksu_context, cc_source), ++ KRB5_TEMPORARY_CACHE); + exit(1); + } + +@@ -502,7 +507,7 @@ main (argc, argv) + &kdc_server))){ + com_err(prog_name, retval, + _("while creating tgt for local realm")); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + +@@ -510,13 +515,13 @@ main (argc, argv) + "enter it here and are logged\n")); + fprintf(stderr, _(" in remotely using an unsecure " + "(non-encrypted) channel.\n")); +- if (krb5_get_tkt_via_passwd (ksu_context, &cc_target, client, +- kdc_server, &options, +- &zero_password) == FALSE){ ++ if (krb5_get_tkt_via_passwd(ksu_context, &cc_tmp, client, ++ kdc_server, &options, ++ &zero_password) == FALSE){ + + if (zero_password == FALSE){ + fprintf(stderr, _("Goodbye\n")); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + +@@ -535,15 +540,16 @@ main (argc, argv) + if (source_uid && (source_uid != target_uid)) { + char * client_name; + +- auth_val = krb5_auth_check(ksu_context, client, localhostname, &options, +- target_user,cc_target, &path_passwd, target_uid); ++ auth_val = krb5_auth_check(ksu_context, client, localhostname, ++ &options, target_user, cc_tmp, ++ &path_passwd, target_uid); + + /* if Kerberos authentication failed then exit */ + if (auth_val ==FALSE){ + fprintf(stderr, _("Authentication failed.\n")); + syslog(LOG_WARNING, "'%s %s' authentication failed for %s%s", + prog_name,target_user,source_user,ontty()); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + +@@ -576,7 +582,7 @@ main (argc, argv) + + if ((retval = krb5_unparse_name(ksu_context, client, &client_name))) { + com_err(prog_name, retval, _("When unparsing name")); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + +@@ -589,7 +595,7 @@ main (argc, argv) + if (krb5_seteuid(target_uid)) { + com_err(prog_name, errno, _("while switching to target for " + "authorization check")); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + +@@ -597,14 +603,14 @@ main (argc, argv) + cmd, &authorization_val, &exec_cmd))){ + com_err(prog_name,retval, _("while checking authorization")); + krb5_seteuid(0); /*So we have some chance of sweeping up*/ +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + + if (krb5_seteuid(0)) { + com_err(prog_name, errno, _("while switching back from target " + "after authorization check")); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + if (authorization_val == TRUE){ +@@ -646,21 +652,23 @@ main (argc, argv) + + } + +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + } + + if( some_rest_copy){ +- if ((retval = krb5_ccache_filter(ksu_context, cc_target, client))){ ++ retval = krb5_ccache_filter(ksu_context, cc_tmp, client); ++ if (retval) { + com_err(prog_name,retval, _("while calling cc_filter")); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + } + + if (all_rest_copy){ +- if ((retval = krb5_cc_initialize(ksu_context, cc_target, client))){ ++ retval = krb5_cc_initialize(ksu_context, cc_tmp, client); ++ if (retval) { + com_err(prog_name, retval, _("while erasing target cache")); + exit(1); + } +@@ -682,7 +690,7 @@ main (argc, argv) + + if (!standard_shell(target_pwd->pw_shell) && source_uid) { + fprintf(stderr, _("ksu: permission denied (shell).\n")); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + #endif /* HAVE_GETUSERSHELL */ +@@ -692,43 +700,33 @@ main (argc, argv) + if(set_env_var("USER", target_pwd->pw_name)){ + fprintf(stderr, + _("ksu: couldn't set environment variable USER\n")); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + } + + if(set_env_var( "HOME", target_pwd->pw_dir)){ + fprintf(stderr, _("ksu: couldn't set environment variable HOME\n")); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + + if(set_env_var( "SHELL", shell)){ + fprintf(stderr, _("ksu: couldn't set environment variable SHELL\n")); +- sweep_up(ksu_context, cc_target); +- exit(1); +- } +- +- /* set the cc env name to target */ +- +- if(set_env_var( KRB5_ENV_CCNAME, cc_target_tag)){ +- fprintf(stderr, _("ksu: couldn't set environment variable %s\n"), +- KRB5_ENV_CCNAME); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + + /* set permissions */ + if (setgid(target_pwd->pw_gid) < 0) { + perror("ksu: setgid"); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + +- + if (initgroups(target_user, target_pwd->pw_gid)) { + fprintf(stderr, _("ksu: initgroups failed.\n")); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + +@@ -748,22 +746,49 @@ main (argc, argv) + */ + if (setluid((uid_t) pwd->pw_uid) < 0) { + perror("setluid"); +- sweep_up(ksu_context, cc_target); ++ sweep_up(ksu_context, cc_tmp); + exit(1); + } + #endif /* HAVE_SETLUID */ + +- if (setuid(target_pwd->pw_uid) < 0) { ++ if (seteuid(0) < 0 || seteuid(target_pwd->pw_uid) < 0) { ++ perror("ksu: seteuid"); ++ sweep_up(ksu_context, cc_tmp); ++ exit(1); ++ } ++ ++ retval = krb5_ccache_copy(ksu_context, cc_tmp, cc_target_tag, ++ client, &cc_target, &stored, ++ target_pwd->pw_uid); ++ if (retval) { ++ com_err(prog_name, retval, _("while copying cache %s to %s"), ++ krb5_cc_get_name(ksu_context, cc_tmp), cc_target_tag); ++ exit(1); ++ } ++ ++ if (setuid(0) < 0 || setuid(target_pwd->pw_uid) < 0) { + perror("ksu: setuid"); + sweep_up(ksu_context, cc_target); + exit(1); + } + +- if (access( cc_target_tag_tmp, R_OK | W_OK )){ +- com_err(prog_name, errno, +- _("%s does not have correct permissions for %s, %s aborted"), +- target_user, cc_target_tag_tmp, prog_name); +- exit(1); ++ /* set the cc env name to target */ ++ if (stored) { ++ if (krb5_cc_get_full_name(ksu_context, cc_target, ++ &cc_target_tag) == 0) { ++ if (set_env_var(KRB5_ENV_CCNAME, cc_target_tag)){ ++ fprintf(stderr, ++ _("ksu: couldn't set environment variable %s\n"), ++ KRB5_ENV_CCNAME); ++ sweep_up(ksu_context, cc_target); ++ exit(1); ++ } ++ krb5_free_string(ksu_context, cc_target_tag); ++ } else { ++ com_err(prog_name, retval, _("while reading cache name from %s"), ++ cc_target_tag); ++ exit(1); ++ } + } + + if ( cc_source) +-- +1.8.4.2 + diff --git a/SOURCES/0003-Learn-to-destroy-the-ccache-we-re-copying-from.patch b/SOURCES/0003-Learn-to-destroy-the-ccache-we-re-copying-from.patch new file mode 100644 index 0000000..9a55929 --- /dev/null +++ b/SOURCES/0003-Learn-to-destroy-the-ccache-we-re-copying-from.patch @@ -0,0 +1,95 @@ +From b92db8dabc566ba0fee4d122ce4f7fb11fe8a637 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Thu, 31 Oct 2013 15:43:49 -0400 +Subject: [PATCH 3/6] Learn to destroy the ccache we're copying from + +Add a flag to krb5_ccache_copy() which will instruct it to destroy a +source ccache after reading its contents. Using this when we copy the +creds from a MEMORY cache to somewhere else is necessary to avoid having +a subsequent call to krb5_cc_cache_match() select the MEMORY cache when +we're trying to have it search a different location by default. +--- + src/clients/ksu/ccache.c | 10 +++++++++- + src/clients/ksu/ksu.h | 2 +- + src/clients/ksu/main.c | 5 +++-- + 3 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c +index 7917af2..90ba2f2 100644 +--- a/src/clients/ksu/ccache.c ++++ b/src/clients/ksu/ccache.c +@@ -47,12 +47,14 @@ void show_credential(); + */ + + krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, +- primary_principal, cc_out, stored, target_uid) ++ primary_principal, destroy_def, ++ cc_out, stored, target_uid) + /* IN */ + krb5_context context; + krb5_ccache cc_def; + char *cc_other_tag; + krb5_principal primary_principal; ++ krb5_boolean destroy_def; + uid_t target_uid; + /* OUT */ + krb5_ccache *cc_out; +@@ -80,6 +82,12 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, + } + } + ++ if (destroy_def) { ++ retval = krb5_cc_destroy(context, cc_def); ++ if (retval) ++ return retval; ++ } ++ + *stored = krb5_find_princ_in_cred_list(context, cc_def_creds_arr, + primary_principal); + +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index 1d102a1..a889fb9 100644 +--- a/src/clients/ksu/ksu.h ++++ b/src/clients/ksu/ksu.h +@@ -108,7 +108,7 @@ extern krb5_error_code get_best_principal + /* ccache.c */ + extern krb5_error_code krb5_ccache_copy + (krb5_context, krb5_ccache, char *, krb5_principal, +- krb5_ccache *, krb5_boolean *, uid_t); ++ krb5_boolean, krb5_ccache *, krb5_boolean *, uid_t); + + extern krb5_error_code krb5_store_all_creds + (krb5_context, krb5_ccache, krb5_creds **, krb5_creds **); +diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c +index fa86c78..7497a2b 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -28,6 +28,7 @@ + + #include "ksu.h" + #include "adm_proto.h" ++#include "../../lib/krb5/os/os-proto.h" + #include + #include + #include +@@ -481,7 +482,7 @@ main (argc, argv) + } else { + + retval = krb5_ccache_copy(ksu_context, cc_source, KRB5_TEMPORARY_CACHE, +- client, &cc_tmp, &stored, 0); ++ client, FALSE, &cc_tmp, &stored, 0); + if (retval) { + com_err(prog_name, retval, _("while copying cache %s to %s"), + krb5_cc_get_name(ksu_context, cc_source), +@@ -758,7 +759,7 @@ main (argc, argv) + } + + retval = krb5_ccache_copy(ksu_context, cc_tmp, cc_target_tag, +- client, &cc_target, &stored, ++ client, TRUE, &cc_target, &stored, + target_pwd->pw_uid); + if (retval) { + com_err(prog_name, retval, _("while copying cache %s to %s"), +-- +1.8.4.2 + diff --git a/SOURCES/0004-Try-to-use-the-default_ccache_name-d-as-the-target.patch b/SOURCES/0004-Try-to-use-the-default_ccache_name-d-as-the-target.patch new file mode 100644 index 0000000..01d8430 --- /dev/null +++ b/SOURCES/0004-Try-to-use-the-default_ccache_name-d-as-the-target.patch @@ -0,0 +1,149 @@ +From 07f4a0b9c7d68e39a41c085e2f6323093b89ac36 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Wed, 30 Oct 2013 21:47:14 -0400 +Subject: [PATCH 4/6] Try to use the default_ccache_name'd as the target + +Try to use the location named by the default_ccache_name setting as the +target cache. If it's a collection, just create or update a subsidiary +cache. If it's not, then fall back to creating a new cache to try to +avoid destroying the contents of one that might already be there. We +can't really detect this in advance for KEYRING: caches, though. +--- + src/clients/ksu/ksu.h | 2 +- + src/clients/ksu/main.c | 91 ++++++++++++++++++++++++++++++++++++-------------- + 2 files changed, 67 insertions(+), 26 deletions(-) + +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index a889fb9..a195f52 100644 +--- a/src/clients/ksu/ksu.h ++++ b/src/clients/ksu/ksu.h +@@ -44,7 +44,7 @@ + #define KRB5_DEFAULT_OPTIONS 0 + #define KRB5_DEFAULT_TKT_LIFE 60*60*12 /* 12 hours */ + +-#define KRB5_SECONDARY_CACHE "FILE:/tmp/krb5cc_" ++#define KRB5_DEFAULT_SECONDARY_CACHE "FILE:/tmp/krb5cc_%{uid}" + #define KRB5_TEMPORARY_CACHE "MEMORY:_ksu" + + #define KRB5_LOGIN_NAME ".k5login" +diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c +index 7497a2b..58df6a1 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -90,7 +90,10 @@ main (argc, argv) + krb5_ccache cc_tmp = NULL, cc_target = NULL; + krb5_context ksu_context; + char * cc_target_tag = NULL; ++ char * cc_target_tag_conf; ++ krb5_boolean cc_target_switchable; + char * target_user = NULL; ++ char * target_user_uid_str; + char * source_user; + + krb5_ccache cc_source = NULL; +@@ -116,7 +119,6 @@ main (argc, argv) + krb5_boolean stored = FALSE; + krb5_principal kdc_server; + krb5_boolean zero_password; +- char * dir_of_cc_target; + + options.opt = KRB5_DEFAULT_OPTIONS; + options.lifetime = KRB5_DEFAULT_TKT_LIFE; +@@ -420,31 +422,70 @@ main (argc, argv) + } + + if (cc_target_tag == NULL) { +- + cc_target_tag = (char *)xcalloc(KRB5_SEC_BUFFSIZE ,sizeof(char)); +- /* make sure that the new ticket file does not already exist +- This is run as source_uid because it is reasonable to +- require the source user to have write to where the target +- cache will be created.*/ +- +- do { +- snprintf(cc_target_tag, KRB5_SEC_BUFFSIZE, "%s%ld.%d", +- KRB5_SECONDARY_CACHE, +- (long) target_uid, gen_sym()); +- cc_target_tag_tmp = strchr(cc_target_tag, ':') + 1; +- +- } while (krb5_ccache_name_is_initialized(ksu_context, +- cc_target_tag)); +- } +- +- +- dir_of_cc_target = get_dir_of_file(cc_target_tag_tmp); +- +- if (access(dir_of_cc_target, R_OK | W_OK )){ +- fprintf(stderr, +- _("%s does not have correct permissions for %s\n"), +- source_user, cc_target_tag); +- exit(1); ++ if (cc_target_tag == NULL) { ++ com_err(prog_name, retval , _("while allocating memory for the " ++ "target ccache name")); ++ exit(1); ++ } ++ /* Read the configured value. */ ++ if (profile_get_string(ksu_context->profile, KRB5_CONF_LIBDEFAULTS, ++ KRB5_CONF_DEFAULT_CCACHE_NAME, NULL, ++ KRB5_DEFAULT_SECONDARY_CACHE, ++ &cc_target_tag_conf)) { ++ com_err(prog_name, retval , _("while allocating memory for the " ++ "target ccache name")); ++ exit(1); ++ } ++ /* Prepend "FILE:" if a cctype wasn't specified in the config. */ ++ if (strchr(cc_target_tag_conf, ':')) { ++ cc_target_tag_tmp = strdup(cc_target_tag_conf); ++ } else { ++ if (asprintf(&cc_target_tag_tmp, "FILE:%s", ++ cc_target_tag_conf) < 0) ++ cc_target_tag_tmp = NULL; ++ } ++ profile_release_string(cc_target_tag_conf); ++ if (cc_target_tag_tmp == NULL) { ++ com_err(prog_name, retval , _("while allocating memory for the " ++ "target ccache name")); ++ exit(1); ++ } ++ /* Resolve parameters in the configured value for the target user. */ ++ if (asprintf(&target_user_uid_str, "%lu", ++ (unsigned long)target_uid) < 0) { ++ com_err(prog_name, retval , _("while allocating memory for the " ++ "target ccache name")); ++ exit(1); ++ } ++ if (k5_expand_path_tokens_extra(ksu_context, ++ cc_target_tag_tmp, &cc_target_tag_conf, ++ "euid", target_user_uid_str, ++ "uid", target_user_uid_str, ++ "USERID", target_user_uid_str, ++ "username", target_user, ++ NULL) != 0) { ++ com_err(prog_name, retval , _("while allocating memory for the " ++ "target ccache name")); ++ exit(1); ++ } ++ cc_target_tag_tmp[strcspn(cc_target_tag_tmp, ":")] = '\0'; ++ cc_target_switchable = krb5_cc_support_switch(ksu_context, ++ cc_target_tag_tmp); ++ free(cc_target_tag_tmp); ++ /* Try to avoid destroying a target ccache. */ ++ if (cc_target_switchable) { ++ snprintf(cc_target_tag, KRB5_SEC_BUFFSIZE, "%s", ++ cc_target_tag_conf); ++ } else { ++ do { ++ snprintf(cc_target_tag, KRB5_SEC_BUFFSIZE, "%s.%d", ++ cc_target_tag_conf, gen_sym()); ++ } while (krb5_ccache_name_is_initialized(ksu_context, ++ cc_target_tag)); ++ } ++ cc_target_tag_tmp = strchr(cc_target_tag, ':') + 1; ++ krb5_free_string(ksu_context, cc_target_tag_conf); + } + + if (auth_debug){ +-- +1.8.4.2 + diff --git a/SOURCES/0005-Be-more-careful-of-target-ccache-collections.patch b/SOURCES/0005-Be-more-careful-of-target-ccache-collections.patch new file mode 100644 index 0000000..d939cd4 --- /dev/null +++ b/SOURCES/0005-Be-more-careful-of-target-ccache-collections.patch @@ -0,0 +1,179 @@ +From cd193e20361624c8a0dc43634c31c6ac2d3d150d Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Wed, 30 Oct 2013 21:34:27 -0400 +Subject: [PATCH 5/6] Be more careful of target ccache collections + +When copying credentials to a cache collection, take care to avoid +generating multiple caches for a single client principal, but don't +change the primary out from anyone who might already be using the +target collection. +--- + src/clients/ksu/ccache.c | 62 ++++++++++++++++++++++++++++++++++++++++++------ + src/clients/ksu/ksu.h | 2 +- + src/clients/ksu/main.c | 11 +++++++-- + 3 files changed, 65 insertions(+), 10 deletions(-) + +diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c +index 90ba2f2..2a97893 100644 +--- a/src/clients/ksu/ccache.c ++++ b/src/clients/ksu/ccache.c +@@ -48,7 +48,7 @@ void show_credential(); + + krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, + primary_principal, destroy_def, +- cc_out, stored, target_uid) ++ cc_out, stored, reused, target_uid) + /* IN */ + krb5_context context; + krb5_ccache cc_def; +@@ -59,10 +59,12 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, + /* OUT */ + krb5_ccache *cc_out; + krb5_boolean *stored; ++ krb5_boolean *reused; + { + int i=0; + krb5_ccache * cc_other; + const char * cc_other_type; ++ char * saved_cc_default_name; + krb5_error_code retval=0; + krb5_creds ** cc_def_creds_arr = NULL; + krb5_creds ** cc_other_creds_arr = NULL; +@@ -99,9 +101,33 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, + return errno; + } + +- +- if ((retval = krb5_cc_initialize(context, *cc_other, primary_principal))){ +- return retval; ++ if (krb5_cc_support_switch(context, cc_other_type)) { ++ *reused = TRUE; ++ krb5_cc_close(context, *cc_other); ++ saved_cc_default_name = strdup(krb5_cc_default_name(context)); ++ krb5_cc_set_default_name(context, cc_other_tag); ++ if (krb5_cc_cache_match(context, primary_principal, cc_other) != 0) { ++ *reused = FALSE; ++ retval = krb5_cc_new_unique(context, cc_other_type, NULL, ++ cc_other); ++ if (retval) { ++ krb5_cc_set_default_name(context, saved_cc_default_name); ++ free(saved_cc_default_name); ++ return retval; ++ } ++ } ++ retval = krb5_cc_initialize(context, *cc_other, primary_principal); ++ krb5_cc_set_default_name(context, saved_cc_default_name); ++ free(saved_cc_default_name); ++ if (retval) { ++ return retval; ++ } ++ } else { ++ *reused = FALSE; ++ retval = krb5_cc_initialize(context, *cc_other, primary_principal); ++ if (retval) { ++ return retval; ++ } + } + + retval = krb5_store_all_creds(context, * cc_other, cc_def_creds_arr, +@@ -650,6 +676,7 @@ krb5_error_code krb5_ccache_copy_restricted (context, cc_def, cc_other_tag, + int i=0; + krb5_ccache * cc_other; + const char * cc_other_type; ++ char * saved_cc_default_name; + krb5_error_code retval=0; + krb5_creds ** cc_def_creds_arr = NULL; + krb5_creds ** cc_other_creds_arr = NULL; +@@ -677,9 +704,30 @@ krb5_error_code krb5_ccache_copy_restricted (context, cc_def, cc_other_tag, + return errno; + } + +- +- if ((retval = krb5_cc_initialize(context, *cc_other, prst))){ +- return retval; ++ if (krb5_cc_support_switch(context, cc_other_type)) { ++ krb5_cc_close(context, *cc_other); ++ saved_cc_default_name = strdup(krb5_cc_default_name(context)); ++ krb5_cc_set_default_name(context, cc_other_tag); ++ if (krb5_cc_cache_match(context, prst, cc_other) != 0) { ++ retval = krb5_cc_new_unique(context, cc_other_type, NULL, ++ cc_other); ++ if (retval) { ++ krb5_cc_set_default_name(context, saved_cc_default_name); ++ free(saved_cc_default_name); ++ return retval; ++ } ++ } ++ retval = krb5_cc_initialize(context, *cc_other, prst); ++ if (retval) { ++ return retval; ++ } ++ krb5_cc_set_default_name(context, saved_cc_default_name); ++ free(saved_cc_default_name); ++ } else { ++ retval = krb5_cc_initialize(context, *cc_other, prst); ++ if (retval) { ++ return retval; ++ } + } + + retval = krb5_store_some_creds(context, * cc_other, +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index a195f52..b3ef7b9 100644 +--- a/src/clients/ksu/ksu.h ++++ b/src/clients/ksu/ksu.h +@@ -108,7 +108,7 @@ extern krb5_error_code get_best_principal + /* ccache.c */ + extern krb5_error_code krb5_ccache_copy + (krb5_context, krb5_ccache, char *, krb5_principal, +- krb5_boolean, krb5_ccache *, krb5_boolean *, uid_t); ++ krb5_boolean, krb5_ccache *, krb5_boolean *, krb5_boolean *, uid_t); + + extern krb5_error_code krb5_store_all_creds + (krb5_context, krb5_ccache, krb5_creds **, krb5_creds **); +diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c +index 58df6a1..1c0c822 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -117,6 +117,7 @@ main (argc, argv) + int pargc; + char ** pargv; + krb5_boolean stored = FALSE; ++ krb5_boolean reused = FALSE; + krb5_principal kdc_server; + krb5_boolean zero_password; + +@@ -523,7 +524,8 @@ main (argc, argv) + } else { + + retval = krb5_ccache_copy(ksu_context, cc_source, KRB5_TEMPORARY_CACHE, +- client, FALSE, &cc_tmp, &stored, 0); ++ client, FALSE, &cc_tmp, &stored, &reused, ++ 0); + if (retval) { + com_err(prog_name, retval, _("while copying cache %s to %s"), + krb5_cc_get_name(ksu_context, cc_source), +@@ -801,7 +803,7 @@ main (argc, argv) + + retval = krb5_ccache_copy(ksu_context, cc_tmp, cc_target_tag, + client, TRUE, &cc_target, &stored, +- target_pwd->pw_uid); ++ &reused, target_pwd->pw_uid); + if (retval) { + com_err(prog_name, retval, _("while copying cache %s to %s"), + krb5_cc_get_name(ksu_context, cc_tmp), cc_target_tag); +@@ -825,6 +827,11 @@ main (argc, argv) + sweep_up(ksu_context, cc_target); + exit(1); + } ++ if (reused && !keep_target_cache) { ++ print_status(_("Reusing cache %s, it will not be removed.\n"), ++ cc_target_tag); ++ keep_target_cache = TRUE; ++ } + krb5_free_string(ksu_context, cc_target_tag); + } else { + com_err(prog_name, retval, _("while reading cache name from %s"), +-- +1.8.4.2 + diff --git a/SOURCES/0006-Copy-config-entries-to-the-target-ccache.patch b/SOURCES/0006-Copy-config-entries-to-the-target-ccache.patch new file mode 100644 index 0000000..0d931eb --- /dev/null +++ b/SOURCES/0006-Copy-config-entries-to-the-target-ccache.patch @@ -0,0 +1,28 @@ +From 3eeefbd93d0fa7dee9fba9a77fffbc959b83f056 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Tue, 29 Oct 2013 16:27:20 -0400 +Subject: [PATCH 6/6] Copy config entries to the target ccache + +When we try to screen out expired creds while reading them from one +ccache to eventually store in another, also keep configuration entries. +--- + src/clients/ksu/ccache.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c +index 2a97893..83b5e46 100644 +--- a/src/clients/ksu/ccache.c ++++ b/src/clients/ksu/ccache.c +@@ -269,7 +269,8 @@ krb5_error_code krb5_get_nonexp_tkts(context, cc, creds_array) + + while (!(retval = krb5_cc_next_cred(context, cc, &cur, &creds))){ + +- if ((retval = krb5_check_exp(context, creds.times))){ ++ if (!krb5_is_config_principal(context, creds.server) && ++ (retval = krb5_check_exp(context, creds.times))){ + if (retval != KRB5KRB_AP_ERR_TKT_EXPIRED){ + return retval; + } +-- +1.8.4.2 + diff --git a/SOURCES/_kadmind b/SOURCES/_kadmind new file mode 100644 index 0000000..b073cfb --- /dev/null +++ b/SOURCES/_kadmind @@ -0,0 +1,14 @@ +#!/bin/sh +# +# Check for error conditions which the init system expects us to check and +# for other common errors, and exit with the expected status codes. +# +kadmind=/usr/sbin/kadmind +if test -f /var/kerberos/krb5kdc/kpropd.acl ; then + echo $"Error. This appears to be a slave server, found kpropd.acl" + exit 6 +fi +if ! test -x "$kadmind" ; then + exit 5 +fi +exec "$kadmind" "$@" diff --git a/SOURCES/_kpropd b/SOURCES/_kpropd new file mode 100644 index 0000000..1808368 --- /dev/null +++ b/SOURCES/_kpropd @@ -0,0 +1,14 @@ +#!/bin/sh +# +# Check for error conditions which the init system expects us to check and +# for other common errors, and exit with the expected status codes. +# +kpropd=/usr/sbin/kpropd +if ! test -f /var/kerberos/krb5kdc/kpropd.acl ; then + echo $"Error. This does not appear to be a slave server, kpropd.acl not found" + exit 6 +fi +if ! test -x "$kpropd" ; then + exit 5 +fi +exec "$kpropd" "$@" diff --git a/SOURCES/kadm5.acl b/SOURCES/kadm5.acl new file mode 100644 index 0000000..dc93eb0 --- /dev/null +++ b/SOURCES/kadm5.acl @@ -0,0 +1 @@ +*/admin@EXAMPLE.COM * diff --git a/SOURCES/kadmin.service b/SOURCES/kadmin.service new file mode 100644 index 0000000..ede159e --- /dev/null +++ b/SOURCES/kadmin.service @@ -0,0 +1,13 @@ +[Unit] +Description=Kerberos 5 Password-changing and Administration +After=syslog.target network.target + +[Service] +Type=forking +PIDFile=/var/run/kadmind.pid +EnvironmentFile=-/etc/sysconfig/kadmin +ExecStart=/usr/sbin/_kadmind -P /var/run/kadmind.pid $KADMIND_ARGS +ExecReload=/bin/kill -HUP $MAINPID + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/kadmin.sysconfig b/SOURCES/kadmin.sysconfig new file mode 100644 index 0000000..fa72039 --- /dev/null +++ b/SOURCES/kadmin.sysconfig @@ -0,0 +1 @@ +KADMIND_ARGS= diff --git a/SOURCES/kadmind.init b/SOURCES/kadmind.init new file mode 100755 index 0000000..8915e2b --- /dev/null +++ b/SOURCES/kadmind.init @@ -0,0 +1,108 @@ +#!/bin/bash +# +# kadmind Start and stop the Kerberos 5 administrative server. +# +# chkconfig: - 35 65 +# description: Kerberos 5 is a trusted third-party authentication system. \ +# This script starts and stops the Kerberos 5 administrative \ +# server, which should only be run on the master server for a \ +# realm. +# processname: kadmind +# config: /etc/sysconfig/kadmin +# pidfile: /var/run/kadmind.pid +# + +### BEGIN INIT INFO +# Provides: kadmin +# Required-Start: $local_fs $network +# Required-Stop: $local_fs $network +# Should-Start: portreserve +# Default-Start: +# Default-Stop: 0 1 2 3 4 5 6 +# Short-Description: start and stop the Kerberos 5 admin server +# Description: The kadmind service allows administrators to remotely manage \ +# the Kerberos 5 realm database. It should only be run on a \ +# master KDC. +### END INIT INFO + +# Get config. +. /etc/sysconfig/network + +# Get config. +[ -r /etc/sysconfig/kadmin ] && . /etc/sysconfig/kadmin + +# Source function library. +. /etc/init.d/functions +prog="Kerberos 5 Admin Server" +kadmind=/usr/sbin/kadmind +pidfile=/var/run/kadmind.pid + +RETVAL=0 + +# Shell functions to cut down on useless shell instances. +start() { + if [ -f /var/kerberos/krb5kdc/kpropd.acl ] ; then + echo $"Error. This appears to be a slave server, found kpropd.acl" + exit 6 + else + [ -x $kadmind ] || exit 5 + fi + echo -n $"Starting $prog: " + # tell portreserve to release the kerberos-adm port + [ -x /sbin/portrelease ] && /sbin/portrelease kerberos-adm &>/dev/null || : + daemon ${kadmind} ${KRB5REALM:+-r ${KRB5REALM}} -P $pidfile $KADMIND_ARGS + RETVAL=$? + echo + if test $RETVAL -ne 0 ; then + if status -l kadmin ${kadmind} > /dev/null ; then + RETVAL=0 + fi + fi + [ $RETVAL = 0 ] && touch /var/lock/subsys/kadmin +} +stop() { + echo -n $"Stopping $prog: " + killproc ${kadmind} + RETVAL=$? + echo + [ $RETVAL = 0 ] && rm -f /var/lock/subsys/kadmin +} +reload() { + echo -n $"Reopening $prog log file: " + killproc ${kadmind} -HUP + RETVAL=$? + echo +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + status) + status -l kadmin ${kadmind} + RETVAL=$? + ;; + reload) + reload + ;; + condrestart) + if [ -f /var/lock/subsys/kadmin ] ; then + stop + start + fi + ;; + *) + echo $"Usage: $0 {start|stop|status|condrestart|reload|restart}" + RETVAL=2 + ;; +esac + +exit $RETVAL diff --git a/SOURCES/kadmind.logrotate b/SOURCES/kadmind.logrotate new file mode 100644 index 0000000..52a66c4 --- /dev/null +++ b/SOURCES/kadmind.logrotate @@ -0,0 +1,9 @@ +/var/log/kadmind.log { + missingok + notifempty + monthly + rotate 12 + postrotate + /bin/kill -HUP `cat /var/run/kadmind.pid 2>/dev/null` 2> /dev/null || true + endscript +} diff --git a/SOURCES/kdc.conf b/SOURCES/kdc.conf new file mode 100644 index 0000000..e99219a --- /dev/null +++ b/SOURCES/kdc.conf @@ -0,0 +1,12 @@ +[kdcdefaults] + kdc_ports = 88 + kdc_tcp_ports = 88 + +[realms] + EXAMPLE.COM = { + #master_key_type = aes256-cts + acl_file = /var/kerberos/krb5kdc/kadm5.acl + dict_file = /usr/share/dict/words + admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab + supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal + } diff --git a/SOURCES/kerberos-adm.portreserve b/SOURCES/kerberos-adm.portreserve new file mode 100644 index 0000000..eb6080d --- /dev/null +++ b/SOURCES/kerberos-adm.portreserve @@ -0,0 +1 @@ +kerberos-adm/tcp diff --git a/SOURCES/kprop.service b/SOURCES/kprop.service new file mode 100644 index 0000000..959a300 --- /dev/null +++ b/SOURCES/kprop.service @@ -0,0 +1,10 @@ +[Unit] +Description=Kerberos 5 Propagation +After=syslog.target network.target + +[Service] +Type=forking +ExecStart=/usr/sbin/_kpropd -S + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/kpropd.init b/SOURCES/kpropd.init new file mode 100755 index 0000000..b872ee3 --- /dev/null +++ b/SOURCES/kpropd.init @@ -0,0 +1,92 @@ +#!/bin/bash +# +# kpropd.init Start and stop the Kerberos 5 propagation client. +# +# chkconfig: - 35 65 +# description: Kerberos 5 is a trusted third-party authentication system. \ +# This script starts and stops the service that allows this \ +# KDC to receive updates from your master KDC. +# processname: kpropd +# + +### BEGIN INIT INFO +# Provides: kprop +# Required-Start: $local_fs $network +# Required-Stop: $local_fs $network +# Should-Start: portreserve +# Default-Start: +# Default-Stop: 0 1 2 3 4 5 6 +# Short-Description: start and stop the Kerberos 5 propagation client +# Description: The kpropd service accepts database updates pushed to it from \ +# the master KDC. It will never be needed on a master KDC. +### END INIT INFO + +# Get config. +. /etc/sysconfig/network + +# Source function library. +. /etc/init.d/functions + +RETVAL=0 +prog="Kerberos 5 Propagation Server" +kpropd=/usr/sbin/kpropd + +# Shell functions to cut down on useless shell instances. +start() { + [ -f /var/kerberos/krb5kdc/kpropd.acl ] || exit 6 + [ -x $kpropd ] || exit 5 + echo -n $"Starting $prog: " + # tell portreserve to release the krb5_prop port + [ -x /sbin/portrelease ] && /sbin/portrelease krb5_prop &>/dev/null || : + daemon ${kpropd} -S + RETVAL=$? + echo + if test $RETVAL -ne 0 ; then + if status -l kprop ${kpropd} > /dev/null ; then + RETVAL=0 + fi + fi + [ $RETVAL = 0 ] && touch /var/lock/subsys/kprop +} +stop() { + echo -n $"Stopping $prog: " + killproc ${kpropd} + RETVAL=$? + echo + [ $RETVAL = 0 ] && rm -f /var/lock/subsys/kprop +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + # We don't really "do" reload, so treat it as a restart. + restart|force-reload) + stop + start + ;; + reload) + echo "can't reload configuration, you have to restart it" + RETVAL=3 + ;; + status) + status -l kprop ${kpropd} + RETVAL=$? + ;; + condrestart) + if [ -f /var/lock/subsys/kprop ] ; then + stop + start + fi + ;; + *) + echo $"Usage: $0 {start|stop|restart|condrestart|reload|status|force-reload}" + RETVAL=2 + ;; +esac + +exit $RETVAL diff --git a/SOURCES/krb5-1.10-CVE-2013-1418.patch b/SOURCES/krb5-1.10-CVE-2013-1418.patch new file mode 100644 index 0000000..0adb104 --- /dev/null +++ b/SOURCES/krb5-1.10-CVE-2013-1418.patch @@ -0,0 +1,37 @@ +Minor changes to apply to 1.10.3. + +commit c2ccf4197f697c4ff143b8a786acdd875e70a89d +Author: Tom Yu +Date: Mon Nov 4 15:49:03 2013 -0500 + + Multi-realm KDC null deref [CVE-2013-1418] + + If a KDC serves multiple realms, certain requests can cause + setup_server_realm() to dereference a null pointer, crashing the KDC. + + CVSSv2: AV:N/AC:M/Au:N/C:N/I:N/A:P/E:POC/RL:OF/RC:C + + A related but more minor vulnerability requires authentication to + exploit, and is only present if a third-party KDC database module can + dereference a null pointer under certain conditions. + + (back ported from commit 5d2d9a1abe46a2c1a8614d4672d08d9d30a5f8bf) + + ticket: 7757 (new) + version_fixed: 1.10.7 + status: resolved + +diff --git a/src/kdc/main.c b/src/kdc/main.c +index b56ec19..7160607 100644 +--- a/src/kdc/main.c ++++ b/src/kdc/main.c +@@ -140,6 +140,9 @@ setup_server_realm(krb5_principal sprinc) + int kdc_numrealms = handle->kdc_numrealms; + + kret = 0; ++ if (sprinc == NULL) ++ return NULL; ++ + if (kdc_numrealms > 1) { + if (!(newrealm = find_realm_data(handle, sprinc->realm.data, + (krb5_ui_4) sprinc->realm.length))) diff --git a/SOURCES/krb5-1.10-buildconf.patch b/SOURCES/krb5-1.10-buildconf.patch new file mode 100644 index 0000000..25b05ac --- /dev/null +++ b/SOURCES/krb5-1.10-buildconf.patch @@ -0,0 +1,54 @@ +Build binaries in this package as RELRO PIEs, libraries as partial RELRO, +and install shared libraries with the execute bit set on them. Prune out +the -L/usr/lib* and PIE flags where they might leak out and affect +apps which just want to link with the libraries. FIXME: needs to check and +not just assume that the compiler supports using these flags. + +--- krb5/src/config/shlib.conf ++++ krb5/src/config/shlib.conf +@@ -419,7 +419,7 @@ mips-*-netbsd*) + SHLIBEXT=.so + # Linux ld doesn't default to stuffing the SONAME field... + # Use objdump -x to examine the fields of the library +- LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT),--no-undefined' ++ LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT),--no-undefined -Wl,-z,relro' + # + LDCOMBINE_TAIL='-Wl,--version-script binutils.versions && $(PERL) -w $(top_srcdir)/util/export-check.pl $(SHLIB_EXPORT_FILE) $@' + SHLIB_EXPORT_FILE_DEP=binutils.versions +@@ -430,7 +430,8 @@ + SHLIB_EXPFLAGS='$(SHLIB_RPATH_FLAGS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)' + PROFFLAGS=-pg + PROG_RPATH_FLAGS='$(RPATH_FLAG)$(PROG_RPATH)' +- CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CFLAGS) $(LDFLAGS)' ++ CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CFLAGS) -pie -Wl,-z,relro -Wl,-z,now $(LDFLAGS)' ++ INSTALL_SHLIB='${INSTALL} -m755' + CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)' + CXX_LINK_SHARED='$(CXX) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CXXFLAGS) $(LDFLAGS)' + CXX_LINK_STATIC='$(CXX) $(PROG_LIBPATH) $(CXXFLAGS) $(LDFLAGS)' +--- krb5/src/krb5-config.in ++++ krb5/src/krb5-config.in +@@ -189,6 +189,13 @@ if test -n "$do_libs"; then + -e 's#\$(PTHREAD_CFLAGS)#'"$PTHREAD_CFLAGS"'#' \ + -e 's#\$(CFLAGS)##'` + ++ if test `dirname $libdir` = /usr ; then ++ lib_flags=`echo $lib_flags | sed -e "s#-L$libdir##" -e "s#$RPATH_FLAG$libdir##"` ++ fi ++ lib_flags=`echo $lib_flags | sed -e "s#-fPIE##g" -e "s#-pie##g"` ++ lib_flags=`echo $lib_flags | sed -e "s#-Wl,-z,relro##g"` ++ lib_flags=`echo $lib_flags | sed -e "s#-Wl,-z,now##g"` ++ + if test $library = 'kdb'; then + lib_flags="$lib_flags -lkdb5 $KDB5_DB_LIB" + library=krb5 +--- krb5/src/config/pre.in ++++ krb5/src/config/pre.in +@@ -188,7 +188,7 @@ + INSTALL_SCRIPT=@INSTALL_PROGRAM@ + INSTALL_DATA=@INSTALL_DATA@ + INSTALL_SHLIB=@INSTALL_SHLIB@ +-INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755 -o root ++INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755 + ## This is needed because autoconf will sometimes define @exec_prefix@ to be + ## ${prefix}. + prefix=@prefix@ diff --git a/SOURCES/krb5-1.10-doublelog.patch b/SOURCES/krb5-1.10-doublelog.patch new file mode 100644 index 0000000..c20075c --- /dev/null +++ b/SOURCES/krb5-1.10-doublelog.patch @@ -0,0 +1,14 @@ +Don't double-log (actually, don't process /etc/krb5.conf twice) just +because we built with --sysconfdir=/etc. RT#3277 + +--- krb5/src/include/Makefile.in ++++ krb5/src/include/Makefile.in +@@ -67,6 +67,8 @@ PROCESS_REPLACE = -e "s+@KRB5RCTMPDIR+$( + -e "s+@GSSMODULEDIR+$(GSS_MODULE_DIR)+" \ + -e 's+@LOCALSTATEDIR+$(LOCALSTATEDIR)+' \ + -e 's+@SYSCONFDIR+$(SYSCONFDIR)+' \ ++ -e 's+:/etc/krb5.conf:/etc/krb5.conf"+:/etc/krb5.conf"+' \ ++ -e 's+"/etc/krb5.conf:/etc/krb5.conf"+"/etc/krb5.conf"+' \ + -e 's+@DYNOBJEXT+$(DYNOBJEXT)+' + + OSCONFSRC = $(srcdir)/osconf.hin diff --git a/SOURCES/krb5-1.10-kpasswd_tcp.patch b/SOURCES/krb5-1.10-kpasswd_tcp.patch new file mode 100644 index 0000000..fd8da8e --- /dev/null +++ b/SOURCES/krb5-1.10-kpasswd_tcp.patch @@ -0,0 +1,32 @@ +Fall back to TCP on kdc-unresolvable/unreachable errors. We still have +to wait for UDP to fail, so this might not be ideal. RT #5868. + +--- krb5/src/lib/krb5/os/changepw.c ++++ krb5/src/lib/krb5/os/changepw.c +@@ -270,10 +270,22 @@ change_set_password(krb5_context context + &callback_info, &chpw_rep, ss2sa(&remote_addr), + &addrlen, NULL, NULL, NULL); + if (code) { +- /* +- * Here we may want to switch to TCP on some errors. +- * right? +- */ ++ /* if we're not using a stream socket, and it's an error which ++ * might reasonably be specific to a datagram "connection", try ++ * again with a stream socket */ ++ if (!use_tcp) { ++ switch (code) { ++ case KRB5_KDC_UNREACH: ++ case KRB5_REALM_CANT_RESOLVE: ++ case KRB5KRB_ERR_RESPONSE_TOO_BIG: ++ /* should we do this for more result codes than these? */ ++ k5_free_serverlist (&sl); ++ use_tcp = 1; ++ continue; ++ default: ++ break; ++ } ++ } + break; + } + diff --git a/SOURCES/krb5-1.10-kprop-mktemp.patch b/SOURCES/krb5-1.10-kprop-mktemp.patch new file mode 100644 index 0000000..62178df --- /dev/null +++ b/SOURCES/krb5-1.10-kprop-mktemp.patch @@ -0,0 +1,28 @@ +Use an in-memory ccache to silence a compiler warning, for RT#6414. + +--- krb5/src/slave/kprop.c ++++ krb5/src/slave/kprop.c +@@ -202,9 +202,8 @@ void PRS(argc, argv) + void get_tickets(context) + krb5_context context; + { +- char buf[BUFSIZ], *def_realm; ++ char buf[] = "MEMORY:_kproptkt", *def_realm; + krb5_error_code retval; +- static char tkstring[] = "/tmp/kproptktXXXXXX"; + krb5_keytab keytab = NULL; + + /* +@@ -229,11 +228,8 @@ void get_tickets(context) + #endif + + /* +- * Initialize cache file which we're going to be using ++ * Initialize an in-memory cache for temporary use + */ +- (void) mktemp(tkstring); +- snprintf(buf, sizeof(buf), "FILE:%s", tkstring); +- + retval = krb5_cc_resolve(context, buf, &ccache); + if (retval) { + com_err(progname, retval, _("while opening credential cache %s"), buf); diff --git a/SOURCES/krb5-1.10-ksu-path.patch b/SOURCES/krb5-1.10-ksu-path.patch new file mode 100644 index 0000000..48443ef --- /dev/null +++ b/SOURCES/krb5-1.10-ksu-path.patch @@ -0,0 +1,12 @@ +Set the default PATH to the one set by login. + +--- krb5/src/clients/ksu/Makefile.in ++++ krb5/src/clients/ksu/Makefile.in +@@ -1,6 +1,6 @@ + mydir=clients$(S)ksu + BUILDTOP=$(REL)..$(S).. +-DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/bin /local/bin"' ++DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/usr/local/sbin /usr/local/bin /sbin /bin /usr/sbin /usr/bin"' + DEFS= + + PROG_LIBPATH=-L$(TOPLIBD) diff --git a/SOURCES/krb5-1.11-alpha1-init.patch b/SOURCES/krb5-1.11-alpha1-init.patch new file mode 100644 index 0000000..67875e6 --- /dev/null +++ b/SOURCES/krb5-1.11-alpha1-init.patch @@ -0,0 +1,12 @@ +If krb5_init_context() fails, context is going to be NULL anyway. +--- krb5/src/lib/krb5/krb/t_cc_config.c ++++ krb5/src/lib/krb5/krb/t_cc_config.c +@@ -117,7 +117,7 @@ main(int argc, char **argv) + int c; + unsigned int i; + +- bail_on_err(context, "Error initializing Kerberos library", ++ bail_on_err(NULL, "Error initializing Kerberos library", + krb5_init_context(&context)); + bail_on_err(context, "Error getting location of default ccache", + krb5_cc_default(context, &ccache)); diff --git a/SOURCES/krb5-1.11-check_transited.patch b/SOURCES/krb5-1.11-check_transited.patch new file mode 100644 index 0000000..f3ce693 --- /dev/null +++ b/SOURCES/krb5-1.11-check_transited.patch @@ -0,0 +1,56 @@ +commit 0406cd81ef9d18cd505fffabba3ac78901dc797d +Author: Greg Hudson +Date: Wed Sep 25 10:40:23 2013 -0400 + + Support authoritative KDB check_transited methods + + In kdc_check_transited_list, consult the KDB module first. If it + succeeds, treat this as authoritative and do not use the core + transited mechanisms. Modules can return KRB5_PLUGIN_NO_HANDLE to + fall back to core mechanisms. + + ticket: 7709 + +diff --git a/src/include/kdb.h b/src/include/kdb.h +index bc01976..69817bc 100644 +--- a/src/include/kdb.h ++++ b/src/include/kdb.h +@@ -1261,8 +1261,9 @@ typedef struct _kdb_vftabl { + + /* + * Optional: Perform a policy check on a cross-realm ticket's transited +- * field and return an error (other than KRB5_PLUGIN_OP_NOTSUPP) if the +- * check fails. ++ * field. Return 0 if the check authoritatively succeeds, ++ * KRB5_PLUGIN_NO_HANDLE to use the core transited-checking mechanisms, or ++ * another error (other than KRB5_PLUGIN_OP_NOTSUPP) if the check fails. + */ + krb5_error_code (*check_transited_realms)(krb5_context kcontext, + const krb5_data *tr_contents, +diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c +index bc638c1..5409078 100644 +--- a/src/kdc/kdc_util.c ++++ b/src/kdc/kdc_util.c +@@ -1573,16 +1573,14 @@ kdc_check_transited_list(kdc_realm_t *kdc_active_realm, + { + krb5_error_code code; + +- /* Check using krb5.conf */ +- code = krb5_check_transited_list(kdc_context, trans, realm1, realm2); +- if (code) ++ /* Check against the KDB module. Treat this answer as authoritative if the ++ * method is supported and doesn't explicitly pass control. */ ++ code = krb5_db_check_transited_realms(kdc_context, trans, realm1, realm2); ++ if (code != KRB5_PLUGIN_OP_NOTSUPP && code != KRB5_PLUGIN_NO_HANDLE) + return code; + +- /* Check against the KDB module. */ +- code = krb5_db_check_transited_realms(kdc_context, trans, realm1, realm2); +- if (code == KRB5_PLUGIN_OP_NOTSUPP) +- code = 0; +- return code; ++ /* Check using krb5.conf [capaths] or hierarchical relationships. */ ++ return krb5_check_transited_list(kdc_context, trans, realm1, realm2); + } + + krb5_error_code diff --git a/SOURCES/krb5-1.11-dirsrv-accountlock.patch b/SOURCES/krb5-1.11-dirsrv-accountlock.patch new file mode 100644 index 0000000..12d201d --- /dev/null +++ b/SOURCES/krb5-1.11-dirsrv-accountlock.patch @@ -0,0 +1,61 @@ +Treat 'nsAccountLock: true' the same as 'loginDisabled: true'. Updated from +original version filed as RT#5891. + +diff -up krb5-1.8/src/aclocal.m4.dirsrv-accountlock krb5-1.8/src/aclocal.m4 +--- krb5-1.8/src/aclocal.m4.dirsrv-accountlock 2010-03-05 11:03:09.000000000 -0500 ++++ krb5-1.8/src/aclocal.m4 2010-03-05 11:03:10.000000000 -0500 +@@ -1656,6 +1656,15 @@ if test $with_ldap = yes; then + AC_MSG_NOTICE(enabling OpenLDAP database backend module support) + OPENLDAP_PLUGIN=yes + fi ++AC_ARG_WITH([dirsrv-account-locking], ++[ --with-dirsrv-account-locking compile 389/Red Hat/Fedora/Netscape Directory Server database backend module], ++[case "$withval" in ++ yes | no) ;; ++ *) AC_MSG_ERROR(Invalid option value --with-dirsrv-account-locking="$withval") ;; ++esac], with_dirsrv_account_locking=no) ++if test $with_dirsrv_account_locking = yes; then ++ AC_DEFINE(HAVE_DIRSRV_ACCOUNT_LOCKING,1,[Define if LDAP KDB interface should heed 389 DS's nsAccountLock attribute.]) ++fi + ])dnl + dnl + dnl If libkeyutils exists (on Linux) include it and use keyring ccache +diff -up krb5-1.8/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c.dirsrv-accountlock krb5-1.8/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c +--- krb5-1.8/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c.dirsrv-accountlock 2009-11-24 18:52:25.000000000 -0500 ++++ krb5-1.8/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c 2010-03-05 11:03:10.000000000 -0500 +@@ -2101,6 +2101,22 @@ populate_krb5_db_entry(krb5_context cont + goto cleanup; + if ((st=krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data)) != 0) + goto cleanup; ++#ifdef HAVE_DIRSRV_ACCOUNT_LOCKING ++ { ++ krb5_timestamp expiretime=0; ++ char *is_login_disabled=NULL; ++ ++ /* LOGIN DISABLED */ ++ if ((st=krb5_ldap_get_string(ld, ent, "nsAccountLock", &is_login_disabled, ++ &attr_present)) != 0) ++ goto cleanup; ++ if (attr_present == TRUE) { ++ if (strcasecmp(is_login_disabled, "TRUE")== 0) ++ entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX; ++ free (is_login_disabled); ++ } ++ } ++#endif + + if ((st=krb5_read_tkt_policy (context, ldap_context, entry, tktpolname)) !=0) + goto cleanup; +diff -up krb5-1.8/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c.dirsrv-accountlock krb5-1.8/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c +--- krb5-1.8/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c.dirsrv-accountlock 2009-11-24 18:52:25.000000000 -0500 ++++ krb5-1.8/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c 2010-03-05 11:03:10.000000000 -0500 +@@ -59,6 +59,9 @@ char *principal_attributes[] = { "kr + "krbLastFailedAuth", + "krbLoginFailedCount", + "krbLastSuccessfulAuth", ++#ifdef HAVE_DIRSRV_ACCOUNT_LOCKING ++ "nsAccountLock", ++#endif + "krbLastPwdChange", + "krbLastAdminUnlock", + "krbExtraData", diff --git a/SOURCES/krb5-1.11-gss-client-keytab.patch b/SOURCES/krb5-1.11-gss-client-keytab.patch new file mode 100644 index 0000000..3c1e964 --- /dev/null +++ b/SOURCES/krb5-1.11-gss-client-keytab.patch @@ -0,0 +1,131 @@ +Originally http://fedorapeople.org/cgit/simo/public_git/krb5.git/commit/?h=gss_cs&id=a3b9bf20df1d976775ed929d8cb5f4844e03b1bf + +commit a3b9bf20df1d976775ed929d8cb5f4844e03b1bf +Author: Simo Sorce +Date: Thu Mar 28 12:53:01 2013 -0400 + + Add support for client keytab from cred store + + The new credential store extensions added support for specifying a + specific ccache name and also a specific keytab to be used for accepting + security contexts, but did not add a way to specify a client keytab + to be used in conjunction with the Keytab initiation support added also + in 1.11 + + This patch introduces a new URN named client_keytab through which a + specific client_keytab can be set when calling gss_acquire_cred_from() + and Keytab Initiation will use that keytab to initialize credentials. + +diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c +index 4d499e4..8540bf3 100644 +--- a/src/lib/gssapi/krb5/acquire_cred.c ++++ b/src/lib/gssapi/krb5/acquire_cred.c +@@ -636,6 +636,7 @@ acquire_init_cred(krb5_context context, + OM_uint32 *minor_status, + krb5_ccache req_ccache, + gss_buffer_t password, ++ krb5_keytab client_keytab, + krb5_gss_cred_id_rec *cred) + { + krb5_error_code code; +@@ -659,9 +660,13 @@ acquire_init_cred(krb5_context context, + goto error; + } + +- code = krb5_kt_client_default(context, &cred->client_keytab); +- if (code) +- goto error; ++ if (client_keytab != NULL) ++ cred->client_keytab = client_keytab; ++ else { ++ code = krb5_kt_client_default(context, &cred->client_keytab); ++ if (code) ++ goto error; ++ } + + if (password != GSS_C_NO_BUFFER) { + pwdata = make_data(password->value, password->length); +@@ -719,8 +724,9 @@ static OM_uint32 + acquire_cred_context(krb5_context context, OM_uint32 *minor_status, + gss_name_t desired_name, gss_buffer_t password, + OM_uint32 time_req, gss_cred_usage_t cred_usage, +- krb5_ccache ccache, krb5_keytab keytab, +- krb5_boolean iakerb, gss_cred_id_t *output_cred_handle, ++ krb5_ccache ccache, krb5_keytab client_keytab, ++ krb5_keytab keytab, krb5_boolean iakerb, ++ gss_cred_id_t *output_cred_handle, + OM_uint32 *time_rec) + { + krb5_gss_cred_id_t cred = NULL; +@@ -787,7 +793,8 @@ acquire_cred_context(krb5_context context, OM_uint32 *minor_status, + * in cred->name if it wasn't set above. + */ + if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { +- ret = acquire_init_cred(context, minor_status, ccache, password, cred); ++ ret = acquire_init_cred(context, minor_status, ccache, password, ++ client_keytab, cred); + if (ret != GSS_S_COMPLETE) + goto error_out; + } +@@ -864,8 +871,8 @@ acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name, + } + + ret = acquire_cred_context(context, minor_status, desired_name, password, +- time_req, cred_usage, ccache, keytab, iakerb, +- output_cred_handle, time_rec); ++ time_req, cred_usage, ccache, NULL, keytab, ++ iakerb, output_cred_handle, time_rec); + + out: + krb5_free_context(context); +@@ -1130,6 +1137,7 @@ krb5_gss_acquire_cred_from(OM_uint32 *minor_status, + { + krb5_context context = NULL; + krb5_error_code code = 0; ++ krb5_keytab client_keytab = NULL; + krb5_keytab keytab = NULL; + krb5_ccache ccache = NULL; + const char *value; +@@ -1162,6 +1170,19 @@ krb5_gss_acquire_cred_from(OM_uint32 *minor_status, + } + } + ++ ret = kg_value_from_cred_store(cred_store, KRB5_CS_CLI_KEYTAB_URN, &value); ++ if (GSS_ERROR(ret)) ++ goto out; ++ ++ if (value) { ++ code = krb5_kt_resolve(context, value, &client_keytab); ++ if (code != 0) { ++ *minor_status = code; ++ ret = GSS_S_CRED_UNAVAIL; ++ goto out; ++ } ++ } ++ + ret = kg_value_from_cred_store(cred_store, KRB5_CS_KEYTAB_URN, &value); + if (GSS_ERROR(ret)) + goto out; +@@ -1176,8 +1197,8 @@ krb5_gss_acquire_cred_from(OM_uint32 *minor_status, + } + + ret = acquire_cred_context(context, minor_status, desired_name, NULL, +- time_req, cred_usage, ccache, keytab, 0, +- output_cred_handle, time_rec); ++ time_req, cred_usage, ccache, client_keytab, ++ keytab, 0, output_cred_handle, time_rec); + + out: + if (ccache != NULL) +diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h +index 8215b10..310ff58 100644 +--- a/src/lib/gssapi/krb5/gssapiP_krb5.h ++++ b/src/lib/gssapi/krb5/gssapiP_krb5.h +@@ -1227,6 +1227,7 @@ data_to_gss(krb5_data *input_k5data, gss_buffer_t output_buffer) + + /* Credential store extensions */ + ++#define KRB5_CS_CLI_KEYTAB_URN "client_keytab" + #define KRB5_CS_KEYTAB_URN "keytab" + #define KRB5_CS_CCACHE_URN "ccache" + diff --git a/SOURCES/krb5-1.11-gss-methods1.patch b/SOURCES/krb5-1.11-gss-methods1.patch new file mode 100644 index 0000000..ad7b07f --- /dev/null +++ b/SOURCES/krb5-1.11-gss-methods1.patch @@ -0,0 +1,38 @@ +commit ee53a887bead08ec1354de3e74659da537f87515 +Author: Simo Sorce +Date: Sat Jul 20 13:19:19 2013 -0400 + + Load cred store functions from GSS modules + + When the credential store feature was implement the related functions + were added to struct gss_config, but the initialization function that + dynamically loads modules was not changed to see if the plugin being + loaded provided such functions. + + This will allow non-builtin mechanism and interposer mechanism to + implement custom credential store extensions if they wish. + + ticket: 7682 + +diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c +index f5b8b15..70cc4ee 100644 +--- a/src/lib/gssapi/mechglue/g_initialize.c ++++ b/src/lib/gssapi/mechglue/g_initialize.c +@@ -680,6 +680,8 @@ build_dynamicMech(void *dl, const gss_OID mech_type) + GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_mech_for_saslname); + /* RFC 5587 */ + GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_attrs_for_mech); ++ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_acquire_cred_from); ++ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_store_cred_into); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_acquire_cred_with_password); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_sec_context_by_mech); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_name_by_mech); +@@ -778,6 +780,8 @@ build_interMech(void *dl, const gss_OID mech_type) + RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_mech_for_saslname); + /* RFC 5587 */ + RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_attrs_for_mech); ++ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred_from); ++ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _store_cred_into); + RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _acquire_cred_with_password); + RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_sec_context_by_mech); + RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_name_by_mech); diff --git a/SOURCES/krb5-1.11-gss-methods2.patch b/SOURCES/krb5-1.11-gss-methods2.patch new file mode 100644 index 0000000..6d6e620 --- /dev/null +++ b/SOURCES/krb5-1.11-gss-methods2.patch @@ -0,0 +1,38 @@ +commit 744d6f873393b6bbd12e1c1884738676a089fa65 +Author: Simo Sorce +Date: Sat Jul 20 13:20:43 2013 -0400 + + Load import/export cred functions from GSS modules + + When the import/export credential feature was implement the related + functions were added to struct gss_config, but the initialization + function that dynamically loads modules was not changed to see if + the plugin being loaded provided such functions. + + This will allow non-builtin mechanism and interposer mechanism to + implement custom import/export credential extensions if they wish. + + ticket: 7682 + +diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c +index 70cc4ee..48a825e 100644 +--- a/src/lib/gssapi/mechglue/g_initialize.c ++++ b/src/lib/gssapi/mechglue/g_initialize.c +@@ -683,6 +683,8 @@ build_dynamicMech(void *dl, const gss_OID mech_type) + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_acquire_cred_from); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_store_cred_into); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_acquire_cred_with_password); ++ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_export_cred); ++ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_import_cred); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_sec_context_by_mech); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_name_by_mech); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_cred_by_mech); +@@ -783,6 +785,8 @@ build_interMech(void *dl, const gss_OID mech_type) + RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred_from); + RESOLVE_GSSI_SYMBOL(dl, mech, gss, _store_cred_into); + RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _acquire_cred_with_password); ++ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_cred); ++ RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_cred); + RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_sec_context_by_mech); + RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_name_by_mech); + RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_cred_by_mech); diff --git a/SOURCES/krb5-1.11-kpasswdtest.patch b/SOURCES/krb5-1.11-kpasswdtest.patch new file mode 100644 index 0000000..f07b225 --- /dev/null +++ b/SOURCES/krb5-1.11-kpasswdtest.patch @@ -0,0 +1,10 @@ +--- krb5-1.11.3/src/kadmin/testing/proto/krb5.conf.proto ++++ krb5-1.11.3/src/kadmin/testing/proto/krb5.conf.proto +@@ -7,6 +7,7 @@ + __REALM__ = { + kdc = __KDCHOST__:1750 + admin_server = __KDCHOST__:1751 ++ kpasswd_server = __KDCHOST__:1752 + database_module = foobar_db2_module_blah + } + diff --git a/SOURCES/krb5-1.11-pam.patch b/SOURCES/krb5-1.11-pam.patch new file mode 100644 index 0000000..9e1d516 --- /dev/null +++ b/SOURCES/krb5-1.11-pam.patch @@ -0,0 +1,753 @@ +Modify ksu so that it performs account and session management on behalf of +the target user account, mimicking the action of regular su. The default +service name is "ksu", because on Fedora at least the configuration used +is determined by whether or not a login shell is being opened, and so +this may need to vary, too. At run-time, ksu's behavior can be reset to +the earlier, non-PAM behavior by setting "use_pam" to false in the [ksu] +section of /etc/krb5.conf. + +When enabled, ksu gains a dependency on libpam. + +Originally RT#5939, though it's changed since then to perform the account +and session management before dropping privileges, and to apply on top of +changes we're proposing for how it handles cache collections. + +diff -up krb5-1.8/src/aclocal.m4.pam krb5-1.8/src/aclocal.m4 +--- krb5-1.8/src/aclocal.m4.pam 2009-11-22 12:00:45.000000000 -0500 ++++ krb5-1.8/src/aclocal.m4 2010-03-05 10:48:08.000000000 -0500 +@@ -1703,3 +1703,70 @@ AC_DEFUN(KRB5_AC_KEYRING_CCACHE,[ + ])) + ])dnl + dnl ++dnl ++dnl Use PAM instead of local crypt() compare for checking local passwords, ++dnl and perform PAM account, session management, and password-changing where ++dnl appropriate. ++dnl ++AC_DEFUN(KRB5_WITH_PAM,[ ++AC_ARG_WITH(pam,[AC_HELP_STRING(--with-pam,[compile with PAM support])], ++ withpam="$withval",withpam=auto) ++AC_ARG_WITH(pam-ksu-service,[AC_HELP_STRING(--with-ksu-service,[PAM service name for ksu ["ksu"]])], ++ withksupamservice="$withval",withksupamservice=ksu) ++old_LIBS="$LIBS" ++if test "$withpam" != no ; then ++ AC_MSG_RESULT([checking for PAM...]) ++ PAM_LIBS= ++ ++ AC_CHECK_HEADERS(security/pam_appl.h) ++ if test "x$ac_cv_header_security_pam_appl_h" != xyes ; then ++ if test "$withpam" = auto ; then ++ AC_MSG_RESULT([Unable to locate security/pam_appl.h.]) ++ withpam=no ++ else ++ AC_MSG_ERROR([Unable to locate security/pam_appl.h.]) ++ fi ++ fi ++ ++ LIBS= ++ unset ac_cv_func_pam_start ++ AC_CHECK_FUNCS(putenv pam_start) ++ if test "x$ac_cv_func_pam_start" = xno ; then ++ unset ac_cv_func_pam_start ++ AC_CHECK_LIB(dl,dlopen) ++ AC_CHECK_FUNCS(pam_start) ++ if test "x$ac_cv_func_pam_start" = xno ; then ++ AC_CHECK_LIB(pam,pam_start) ++ unset ac_cv_func_pam_start ++ unset ac_cv_func_pam_getenvlist ++ AC_CHECK_FUNCS(pam_start pam_getenvlist) ++ if test "x$ac_cv_func_pam_start" = xyes ; then ++ PAM_LIBS="$LIBS" ++ else ++ if test "$withpam" = auto ; then ++ AC_MSG_RESULT([Unable to locate libpam.]) ++ withpam=no ++ else ++ AC_MSG_ERROR([Unable to locate libpam.]) ++ fi ++ fi ++ fi ++ fi ++ if test "$withpam" != no ; then ++ AC_MSG_NOTICE([building with PAM support]) ++ AC_DEFINE(USE_PAM,1,[Define if Kerberos-aware tools should support PAM]) ++ AC_DEFINE_UNQUOTED(KSU_PAM_SERVICE,"$withksupamservice", ++ [Define to the name of the PAM service name to be used by ksu.]) ++ PAM_LIBS="$LIBS" ++ NON_PAM_MAN=".\\\" " ++ PAM_MAN= ++ else ++ PAM_MAN=".\\\" " ++ NON_PAM_MAN= ++ fi ++fi ++LIBS="$old_LIBS" ++AC_SUBST(PAM_LIBS) ++AC_SUBST(PAM_MAN) ++AC_SUBST(NON_PAM_MAN) ++])dnl +diff -up krb5-1.8/src/clients/ksu/main.c.pam krb5-1.8/src/clients/ksu/main.c +--- krb5-1.8/src/clients/ksu/main.c.pam 2009-11-02 22:27:56.000000000 -0500 ++++ krb5-1.8/src/clients/ksu/main.c 2010-03-05 10:48:08.000000000 -0500 +@@ -26,6 +26,7 @@ + * KSU was writen by: Ari Medvinsky, ari@isi.edu + */ + ++#include "autoconf.h" + #include "ksu.h" + #include "adm_proto.h" + #include "../../lib/krb5/os/os-proto.h" +@@ -33,6 +34,10 @@ + #include + #include + ++#ifdef USE_PAM ++#include "pam.h" ++#endif ++ + /* globals */ + char * prog_name; + int auth_debug =0; +@@ -40,6 +45,7 @@ char k5login_path[MAXPATHLEN]; + char k5users_path[MAXPATHLEN]; + char * gb_err = NULL; + int quiet = 0; ++int force_fork = 0; + /***********/ + + #define _DEF_CSH "/bin/csh" +@@ -586,6 +592,25 @@ main (argc, argv) + prog_name,target_user,client_name, + source_user,ontty()); + ++#ifdef USE_PAM ++ if (appl_pam_enabled(ksu_context, "ksu")) { ++ if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL, ++ NULL, source_user, ++ ttyname(STDERR_FILENO)) != 0) { ++ fprintf(stderr, "Access denied for %s.\n", target_user); ++ sweep_up(ksu_context, cc_tmp); ++ exit(1); ++ } ++ if (appl_pam_requires_chauthtok()) { ++ fprintf(stderr, "Password change required for %s.\n", ++ target_user); ++ sweep_up(ksu_context, cc_tmp); ++ exit(1); ++ } ++ force_fork++; ++ } ++#endif ++ + /* Run authorization as target.*/ + if (krb5_seteuid(target_uid)) { + com_err(prog_name, errno, _("while switching to target for " +@@ -651,6 +676,26 @@ + sweep_up(ksu_context, cc_tmp); + exit(1); + } ++#ifdef USE_PAM ++ } else { ++ /* we always do PAM account management, even for root */ ++ if (appl_pam_enabled(ksu_context, "ksu")) { ++ if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL, ++ NULL, source_user, ++ ttyname(STDERR_FILENO)) != 0) { ++ fprintf(stderr, "Access denied for %s.\n", target_user); ++ sweep_up(ksu_context, cc_tmp); ++ exit(1); ++ } ++ if (appl_pam_requires_chauthtok()) { ++ fprintf(stderr, "Password change required for %s.\n", ++ target_user); ++ sweep_up(ksu_context, cc_tmp); ++ exit(1); ++ } ++ force_fork++; ++ } ++#endif + } + + if( some_rest_copy){ +@@ -720,6 +745,32 @@ + exit(1); + } + ++#ifdef USE_PAM ++ if (appl_pam_enabled(ksu_context, "ksu")) { ++ if (appl_pam_session_open() != 0) { ++ fprintf(stderr, "Error opening session for %s.\n", target_user); ++ sweep_up(ksu_context, cc_tmp); ++ exit(1); ++ } ++#ifdef DEBUG ++ if (auth_debug){ ++ printf(" Opened PAM session.\n"); ++ } ++#endif ++ if (appl_pam_cred_init()) { ++ fprintf(stderr, "Error initializing credentials for %s.\n", ++ target_user); ++ sweep_up(ksu_context, cc_tmp); ++ exit(1); ++ } ++#ifdef DEBUG ++ if (auth_debug){ ++ printf(" Initialized PAM credentials.\n"); ++ } ++#endif ++ } ++#endif ++ + /* set permissions */ + if (setgid(target_pwd->pw_gid) < 0) { + perror("ksu: setgid"); +@@ -792,7 +817,7 @@ main (argc, argv) + fprintf(stderr, "program to be execed %s\n",params[0]); + } + +- if( keep_target_cache ) { ++ if( keep_target_cache && !force_fork ) { + execv(params[0], params); + com_err(prog_name, errno, _("while trying to execv %s"), params[0]); + sweep_up(ksu_context, cc_target); +@@ -823,16 +875,35 @@ main (argc, argv) + if (ret_pid == -1) { + com_err(prog_name, errno, _("while calling waitpid")); + } +- sweep_up(ksu_context, cc_target); ++ if( !keep_target_cache ) { ++ sweep_up(ksu_context, cc_target); ++ } + exit (statusp); + case -1: + com_err(prog_name, errno, _("while trying to fork.")); + sweep_up(ksu_context, cc_target); + exit (1); + case 0: ++#ifdef USE_PAM ++ if (appl_pam_enabled(ksu_context, "ksu")) { ++ if (appl_pam_setenv() != 0) { ++ fprintf(stderr, "Error setting up environment for %s.\n", ++ target_user); ++ exit (1); ++ } ++#ifdef DEBUG ++ if (auth_debug){ ++ printf(" Set up PAM environment.\n"); ++ } ++#endif ++ } ++#endif + execv(params[0], params); + com_err(prog_name, errno, _("while trying to execv %s"), + params[0]); ++ if( keep_target_cache ) { ++ sweep_up(ksu_context, cc_target); ++ } + exit (1); + } + } +diff -up krb5-1.8/src/clients/ksu/Makefile.in.pam krb5-1.8/src/clients/ksu/Makefile.in +--- krb5-1.8/src/clients/ksu/Makefile.in.pam 2009-11-22 13:13:29.000000000 -0500 ++++ krb5-1.8/src/clients/ksu/Makefile.in 2010-03-05 11:55:14.000000000 -0500 +@@ -7,12 +7,14 @@ + PROG_RPATH=$(KRB5_LIBDIR) + + KSU_LIBS=@KSU_LIBS@ ++PAM_LIBS=@PAM_LIBS@ + + SRCS = \ + $(srcdir)/krb_auth_su.c \ + $(srcdir)/ccache.c \ + $(srcdir)/authorization.c \ + $(srcdir)/main.c \ ++ $(srcdir)/pam.c \ + $(srcdir)/heuristic.c \ + $(srcdir)/xmalloc.c \ + $(srcdir)/setenv.c +@@ -21,13 +23,17 @@ OBJS = \ + ccache.o \ + authorization.o \ + main.o \ ++ pam.o \ + heuristic.o \ + xmalloc.o @SETENVOBJ@ + + all:: ksu + + ksu: $(OBJS) $(KRB5_BASE_DEPLIBS) +- $(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS) ++ $(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS) $(PAM_LIBS) ++ ++pam.o: pam.c ++ $(CC) $(ALL_CFLAGS) -c $< + + clean:: + $(RM) ksu +diff -up krb5-1.8/src/clients/ksu/pam.c.pam krb5-1.8/src/clients/ksu/pam.c +--- krb5-1.8/src/clients/ksu/pam.c.pam 2010-03-05 10:48:08.000000000 -0500 ++++ krb5-1.8/src/clients/ksu/pam.c 2010-03-05 10:48:08.000000000 -0500 +@@ -0,0 +1,389 @@ ++/* ++ * src/clients/ksu/pam.c ++ * ++ * Copyright 2007,2009,2010 Red Hat, Inc. ++ * ++ * 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. ++ * ++ * Neither the name of Red Hat, Inc. nor the names of its contributors may be ++ * used to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * 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 OWNER 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. ++ * ++ * Convenience wrappers for using PAM. ++ */ ++ ++#include "autoconf.h" ++#ifdef USE_PAM ++#include ++#include ++#include ++#include ++#include ++#include "k5-int.h" ++#include "pam.h" ++ ++#ifndef MAXPWSIZE ++#define MAXPWSIZE 128 ++#endif ++ ++static int appl_pam_started; ++static pid_t appl_pam_starter = -1; ++static int appl_pam_session_opened; ++static int appl_pam_creds_initialized; ++static int appl_pam_pwchange_required; ++static pam_handle_t *appl_pamh; ++static struct pam_conv appl_pam_conv; ++static char *appl_pam_user; ++struct appl_pam_non_interactive_args { ++ const char *user; ++ const char *password; ++}; ++ ++int ++appl_pam_enabled(krb5_context context, const char *section) ++{ ++ int enabled = 1; ++ if ((context != NULL) && (context->profile != NULL)) { ++ if (profile_get_boolean(context->profile, ++ section, ++ USE_PAM_CONFIGURATION_KEYWORD, ++ NULL, ++ enabled, &enabled) != 0) { ++ enabled = 1; ++ } ++ } ++ return enabled; ++} ++ ++void ++appl_pam_cleanup(void) ++{ ++ if (getpid() != appl_pam_starter) { ++ return; ++ } ++#ifdef DEBUG ++ printf("Called to clean up PAM.\n"); ++#endif ++ if (appl_pam_creds_initialized) { ++#ifdef DEBUG ++ printf("Deleting PAM credentials.\n"); ++#endif ++ pam_setcred(appl_pamh, PAM_DELETE_CRED); ++ appl_pam_creds_initialized = 0; ++ } ++ if (appl_pam_session_opened) { ++#ifdef DEBUG ++ printf("Closing PAM session.\n"); ++#endif ++ pam_close_session(appl_pamh, 0); ++ appl_pam_session_opened = 0; ++ } ++ appl_pam_pwchange_required = 0; ++ if (appl_pam_started) { ++#ifdef DEBUG ++ printf("Shutting down PAM.\n"); ++#endif ++ pam_end(appl_pamh, 0); ++ appl_pam_started = 0; ++ appl_pam_starter = -1; ++ free(appl_pam_user); ++ appl_pam_user = NULL; ++ } ++} ++static int ++appl_pam_interactive_converse(int num_msg, const struct pam_message **msg, ++ struct pam_response **presp, void *appdata_ptr) ++{ ++ const struct pam_message *message; ++ struct pam_response *resp; ++ int i, code; ++ char *pwstring, pwbuf[MAXPWSIZE]; ++ unsigned int pwsize; ++ resp = malloc(sizeof(struct pam_response) * num_msg); ++ if (resp == NULL) { ++ return PAM_BUF_ERR; ++ } ++ memset(resp, 0, sizeof(struct pam_response) * num_msg); ++ code = PAM_SUCCESS; ++ for (i = 0; i < num_msg; i++) { ++ message = &(msg[0][i]); /* XXX */ ++ message = msg[i]; /* XXX */ ++ pwstring = NULL; ++ switch (message->msg_style) { ++ case PAM_TEXT_INFO: ++ case PAM_ERROR_MSG: ++ printf("[%s]\n", message->msg ? message->msg : ""); ++ fflush(stdout); ++ resp[i].resp = NULL; ++ resp[i].resp_retcode = PAM_SUCCESS; ++ break; ++ case PAM_PROMPT_ECHO_ON: ++ case PAM_PROMPT_ECHO_OFF: ++ if (message->msg_style == PAM_PROMPT_ECHO_ON) { ++ if (fgets(pwbuf, sizeof(pwbuf), ++ stdin) != NULL) { ++ pwbuf[strcspn(pwbuf, "\r\n")] = '\0'; ++ pwstring = pwbuf; ++ } ++ } else { ++ pwstring = getpass(message->msg ? ++ message->msg : ++ ""); ++ } ++ if ((pwstring != NULL) && (pwstring[0] != '\0')) { ++ pwsize = strlen(pwstring); ++ resp[i].resp = malloc(pwsize + 1); ++ if (resp[i].resp == NULL) { ++ resp[i].resp_retcode = PAM_BUF_ERR; ++ } else { ++ memcpy(resp[i].resp, pwstring, pwsize); ++ resp[i].resp[pwsize] = '\0'; ++ resp[i].resp_retcode = PAM_SUCCESS; ++ } ++ } else { ++ resp[i].resp_retcode = PAM_CONV_ERR; ++ code = PAM_CONV_ERR; ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ *presp = resp; ++ return code; ++} ++static int ++appl_pam_non_interactive_converse(int num_msg, ++ const struct pam_message **msg, ++ struct pam_response **presp, ++ void *appdata_ptr) ++{ ++ const struct pam_message *message; ++ struct pam_response *resp; ++ int i, code; ++ unsigned int pwsize; ++ struct appl_pam_non_interactive_args *args; ++ const char *pwstring; ++ resp = malloc(sizeof(struct pam_response) * num_msg); ++ if (resp == NULL) { ++ return PAM_BUF_ERR; ++ } ++ args = appdata_ptr; ++ memset(resp, 0, sizeof(struct pam_response) * num_msg); ++ code = PAM_SUCCESS; ++ for (i = 0; i < num_msg; i++) { ++ message = &((*msg)[i]); ++ message = msg[i]; ++ pwstring = NULL; ++ switch (message->msg_style) { ++ case PAM_TEXT_INFO: ++ case PAM_ERROR_MSG: ++ break; ++ case PAM_PROMPT_ECHO_ON: ++ case PAM_PROMPT_ECHO_OFF: ++ if (message->msg_style == PAM_PROMPT_ECHO_ON) { ++ /* assume "user" */ ++ pwstring = args->user; ++ } else { ++ /* assume "password" */ ++ pwstring = args->password; ++ } ++ if ((pwstring != NULL) && (pwstring[0] != '\0')) { ++ pwsize = strlen(pwstring); ++ resp[i].resp = malloc(pwsize + 1); ++ if (resp[i].resp == NULL) { ++ resp[i].resp_retcode = PAM_BUF_ERR; ++ } else { ++ memcpy(resp[i].resp, pwstring, pwsize); ++ resp[i].resp[pwsize] = '\0'; ++ resp[i].resp_retcode = PAM_SUCCESS; ++ } ++ } else { ++ resp[i].resp_retcode = PAM_CONV_ERR; ++ code = PAM_CONV_ERR; ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ *presp = resp; ++ return code; ++} ++static int ++appl_pam_start(const char *service, int interactive, ++ const char *login_username, ++ const char *non_interactive_password, ++ const char *hostname, ++ const char *ruser, ++ const char *tty) ++{ ++ static int exit_handler_registered; ++ static struct appl_pam_non_interactive_args args; ++ int ret = 0; ++ if (appl_pam_started && ++ (strcmp(login_username, appl_pam_user) != 0)) { ++ appl_pam_cleanup(); ++ appl_pam_user = NULL; ++ } ++ if (!appl_pam_started) { ++#ifdef DEBUG ++ printf("Starting PAM up (service=\"%s\",user=\"%s\").\n", ++ service, login_username); ++#endif ++ memset(&appl_pam_conv, 0, sizeof(appl_pam_conv)); ++ appl_pam_conv.conv = interactive ? ++ &appl_pam_interactive_converse : ++ &appl_pam_non_interactive_converse; ++ memset(&args, 0, sizeof(args)); ++ args.user = strdup(login_username); ++ args.password = non_interactive_password ? ++ strdup(non_interactive_password) : ++ NULL; ++ appl_pam_conv.appdata_ptr = &args; ++ ret = pam_start(service, login_username, ++ &appl_pam_conv, &appl_pamh); ++ if (ret == 0) { ++ if (hostname != NULL) { ++#ifdef DEBUG ++ printf("Setting PAM_RHOST to \"%s\".\n", hostname); ++#endif ++ pam_set_item(appl_pamh, PAM_RHOST, hostname); ++ } ++ if (ruser != NULL) { ++#ifdef DEBUG ++ printf("Setting PAM_RUSER to \"%s\".\n", ruser); ++#endif ++ pam_set_item(appl_pamh, PAM_RUSER, ruser); ++ } ++ if (tty != NULL) { ++#ifdef DEBUG ++ printf("Setting PAM_TTY to \"%s\".\n", tty); ++#endif ++ pam_set_item(appl_pamh, PAM_TTY, tty); ++ } ++ if (!exit_handler_registered && ++ (atexit(appl_pam_cleanup) != 0)) { ++ pam_end(appl_pamh, 0); ++ appl_pamh = NULL; ++ ret = -1; ++ } else { ++ appl_pam_started = 1; ++ appl_pam_starter = getpid(); ++ appl_pam_user = strdup(login_username); ++ exit_handler_registered = 1; ++ } ++ } ++ } ++ return ret; ++} ++int ++appl_pam_acct_mgmt(const char *service, int interactive, ++ const char *login_username, ++ const char *non_interactive_password, ++ const char *hostname, ++ const char *ruser, ++ const char *tty) ++{ ++ int ret; ++ appl_pam_pwchange_required = 0; ++ ret = appl_pam_start(service, interactive, login_username, ++ non_interactive_password, hostname, ruser, tty); ++ if (ret == 0) { ++#ifdef DEBUG ++ printf("Calling pam_acct_mgmt().\n"); ++#endif ++ ret = pam_acct_mgmt(appl_pamh, 0); ++ switch (ret) { ++ case PAM_IGNORE: ++ ret = 0; ++ break; ++ case PAM_NEW_AUTHTOK_REQD: ++ appl_pam_pwchange_required = 1; ++ ret = 0; ++ break; ++ default: ++ break; ++ } ++ } ++ return ret; ++} ++int ++appl_pam_requires_chauthtok(void) ++{ ++ return appl_pam_pwchange_required; ++} ++int ++appl_pam_session_open(void) ++{ ++ int ret = 0; ++ if (appl_pam_started) { ++#ifdef DEBUG ++ printf("Opening PAM session.\n"); ++#endif ++ ret = pam_open_session(appl_pamh, 0); ++ if (ret == 0) { ++ appl_pam_session_opened = 1; ++ } ++ } ++ return ret; ++} ++int ++appl_pam_setenv(void) ++{ ++ int ret = 0; ++#ifdef HAVE_PAM_GETENVLIST ++#ifdef HAVE_PUTENV ++ int i; ++ char **list; ++ if (appl_pam_started) { ++ list = pam_getenvlist(appl_pamh); ++ for (i = 0; ((list != NULL) && (list[i] != NULL)); i++) { ++#ifdef DEBUG ++ printf("Setting \"%s\" in environment.\n", list[i]); ++#endif ++ putenv(list[i]); ++ } ++ } ++#endif ++#endif ++ return ret; ++} ++int ++appl_pam_cred_init(void) ++{ ++ int ret = 0; ++ if (appl_pam_started) { ++#ifdef DEBUG ++ printf("Initializing PAM credentials.\n"); ++#endif ++ ret = pam_setcred(appl_pamh, PAM_ESTABLISH_CRED); ++ if (ret == 0) { ++ appl_pam_creds_initialized = 1; ++ } ++ } ++ return ret; ++} ++#endif +diff -up krb5-1.8/src/clients/ksu/pam.h.pam krb5-1.8/src/clients/ksu/pam.h +--- krb5-1.8/src/clients/ksu/pam.h.pam 2010-03-05 10:48:08.000000000 -0500 ++++ krb5-1.8/src/clients/ksu/pam.h 2010-03-05 10:48:08.000000000 -0500 +@@ -0,0 +1,57 @@ ++/* ++ * src/clients/ksu/pam.h ++ * ++ * Copyright 2007,2009,2010 Red Hat, Inc. ++ * ++ * 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. ++ * ++ * Neither the name of Red Hat, Inc. nor the names of its contributors may be ++ * used to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * 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 OWNER 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. ++ * ++ * Convenience wrappers for using PAM. ++ */ ++ ++#include ++#ifdef HAVE_SECURITY_PAM_APPL_H ++#include ++#endif ++ ++#define USE_PAM_CONFIGURATION_KEYWORD "use_pam" ++ ++#ifdef USE_PAM ++int appl_pam_enabled(krb5_context context, const char *section); ++int appl_pam_acct_mgmt(const char *service, int interactive, ++ const char *local_username, ++ const char *non_interactive_password, ++ const char *hostname, ++ const char *ruser, ++ const char *tty); ++int appl_pam_requires_chauthtok(void); ++int appl_pam_session_open(void); ++int appl_pam_setenv(void); ++int appl_pam_cred_init(void); ++void appl_pam_cleanup(void); ++#endif +diff -up krb5-1.8/src/configure.in.pam krb5-1.8/src/configure.in +--- krb5-1.8/src/configure.in.pam 2009-12-31 18:13:56.000000000 -0500 ++++ krb5-1.8/src/configure.in 2010-03-05 10:48:08.000000000 -0500 +@@ -1051,6 +1051,8 @@ if test "$ac_cv_lib_socket" = "yes" -a " + + AC_PATH_PROG(GROFF, groff) + ++KRB5_WITH_PAM ++ + # Make localedir work in autoconf 2.5x. + if test "${localedir+set}" != set; then + localedir='$(datadir)/locale' diff --git a/SOURCES/krb5-1.11-run_user_0.patch b/SOURCES/krb5-1.11-run_user_0.patch new file mode 100644 index 0000000..6be760a --- /dev/null +++ b/SOURCES/krb5-1.11-run_user_0.patch @@ -0,0 +1,34 @@ +A hack: if we're looking at creating a ccache directory directly below +the /run/user/0 directory, and /run/user/0 doesn't exist, try to create +it, too. + +--- krb5/src/lib/krb5/ccache/cc_dir.c ++++ krb5/src/lib/krb5/ccache/cc_dir.c +@@ -61,6 +61,8 @@ + + #include + ++#define ROOT_SPECIAL_DCC_PARENT "/run/user/0" ++ + extern const krb5_cc_ops krb5_dcc_ops; + extern const krb5_cc_ops krb5_fcc_ops; + +@@ -239,6 +241,18 @@ + + if (stat(dirname, &st) < 0) { + if (errno == ENOENT) { ++ if (strncmp(dirname, ROOT_SPECIAL_DCC_PARENT "/", ++ sizeof(ROOT_SPECIAL_DCC_PARENT)) == 0 && ++ stat(ROOT_SPECIAL_DCC_PARENT, &st) < 0 && ++ errno == ENOENT) { ++#ifdef USE_SELINUX ++ selabel = krb5int_push_fscreatecon_for(ROOT_SPECIAL_DCC_PARENT); ++#endif ++ status = mkdir(ROOT_SPECIAL_DCC_PARENT, S_IRWXU); ++#ifdef USE_SELINUX ++ krb5int_pop_fscreatecon(selabel); ++#endif ++ } + #ifdef USE_SELINUX + selabel = krb5int_push_fscreatecon_for(dirname); + #endif diff --git a/SOURCES/krb5-1.11-selinux-label.patch b/SOURCES/krb5-1.11-selinux-label.patch new file mode 100644 index 0000000..f832728 --- /dev/null +++ b/SOURCES/krb5-1.11-selinux-label.patch @@ -0,0 +1,1015 @@ +SELinux bases access to files on the domain of the requesting process, +the operation being performed, and the context applied to the file. + +In many cases, applications needn't be SELinux aware to work properly, +because SELinux can apply a default label to a file based on the label +of the directory in which it's created. + +In the case of files such as /etc/krb5.keytab, however, this isn't +sufficient, as /etc/krb5.keytab will almost always need to be given a +label which differs from that of /etc/issue or /etc/resolv.conf. The +the kdb stash file needs a different label than the database for which +it's holding a master key, even though both typically live in the same +directory. + +To give the file the correct label, we can either force a "restorecon" +call to fix a file's label after it's created, or create the file with +the right label, as we attempt to do here. We lean on THREEPARAMOPEN +and define a similar macro named WRITABLEFOPEN with which we replace +several uses of fopen(). + +The file creation context that we're manipulating here is a process-wide +attribute. While for the most part, applications which need to label +files when they're created have tended to be single-threaded, there's +not much we can do to avoid interfering with an application that +manipulates the creation context directly. Right now we're mediating +access using a library-local mutex, but that can only work for consumers +that are part of this package -- an unsuspecting application will still +stomp all over us. + +The selabel APIs for looking up the context should be thread-safe (per +Red Hat #273081), so switching to using them instead of matchpathcon(), +which we used earlier, is some improvement. + +--- krb5/src/aclocal.m4 ++++ krb5/src/aclocal.m4 +@@ -103,6 +103,7 @@ AC_SUBST_FILE(libnodeps_frag) + dnl + KRB5_AC_PRAGMA_WEAK_REF + WITH_LDAP ++KRB5_WITH_SELINUX + KRB5_LIB_PARAMS + KRB5_AC_INITFINI + KRB5_AC_ENABLE_THREADS +@@ -1791,3 +1792,51 @@ AC_SUBST(manlocalstatedir) + AC_SUBST(PAM_MAN) + AC_SUBST(NON_PAM_MAN) + ])dnl ++dnl ++dnl Use libselinux to set file contexts on newly-created files. ++dnl ++AC_DEFUN(KRB5_WITH_SELINUX,[ ++AC_ARG_WITH(selinux,[AC_HELP_STRING(--with-selinux,[compile with SELinux labeling support])], ++ withselinux="$withval",withselinux=auto) ++old_LIBS="$LIBS" ++if test "$withselinux" != no ; then ++ AC_MSG_RESULT([checking for libselinux...]) ++ SELINUX_LIBS= ++ AC_CHECK_HEADERS(selinux/selinux.h selinux/label.h) ++ if test "x$ac_cv_header_selinux_selinux_h" != xyes ; then ++ if test "$withselinux" = auto ; then ++ AC_MSG_RESULT([Unable to locate selinux/selinux.h.]) ++ withselinux=no ++ else ++ AC_MSG_ERROR([Unable to locate selinux/selinux.h.]) ++ fi ++ fi ++ ++ LIBS= ++ unset ac_cv_func_setfscreatecon ++ AC_CHECK_FUNCS(setfscreatecon selabel_open) ++ if test "x$ac_cv_func_setfscreatecon" = xno ; then ++ AC_CHECK_LIB(selinux,setfscreatecon) ++ unset ac_cv_func_setfscreatecon ++ AC_CHECK_FUNCS(setfscreatecon selabel_open) ++ if test "x$ac_cv_func_setfscreatecon" = xyes ; then ++ SELINUX_LIBS="$LIBS" ++ else ++ if test "$withselinux" = auto ; then ++ AC_MSG_RESULT([Unable to locate libselinux.]) ++ withselinux=no ++ else ++ AC_MSG_ERROR([Unable to locate libselinux.]) ++ fi ++ fi ++ fi ++ if test "$withselinux" != no ; then ++ AC_MSG_NOTICE([building with SELinux labeling support]) ++ AC_DEFINE(USE_SELINUX,1,[Define if Kerberos-aware tools should set SELinux file contexts when creating files.]) ++ SELINUX_LIBS="$LIBS" ++ EXTRA_SUPPORT_SYMS="$EXTRA_SUPPORT_SYMS krb5int_labeled_open krb5int_labeled_fopen krb5int_push_fscreatecon_for krb5int_pop_fscreatecon" ++ fi ++fi ++LIBS="$old_LIBS" ++AC_SUBST(SELINUX_LIBS) ++])dnl +--- krb5/src/config/pre.in ++++ krb5/src/config/pre.in +@@ -180,6 +180,7 @@ LD_UNRESOLVED_PREFIX = @LD_UNRESOLVED_PREFIX@ + LD_SHLIBDIR_PREFIX = @LD_SHLIBDIR_PREFIX@ + LDARGS = @LDARGS@ + LIBS = @LIBS@ ++SELINUX_LIBS=@SELINUX_LIBS@ + + INSTALL=@INSTALL@ + INSTALL_STRIP= +@@ -379,7 +380,7 @@ SUPPORT_LIB = -l$(SUPPORT_LIBNAME) + # HESIOD_LIBS is -lhesiod... + HESIOD_LIBS = @HESIOD_LIBS@ + +-KRB5_BASE_LIBS = $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(GEN_LIB) $(LIBS) $(DL_LIB) ++KRB5_BASE_LIBS = $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(GEN_LIB) $(LIBS) $(SELINUX_LIBS) $(DL_LIB) + KDB5_LIBS = $(KDB5_LIB) $(GSSRPC_LIBS) + GSS_LIBS = $(GSS_KRB5_LIB) + # needs fixing if ever used on Mac OS X! +--- krb5/src/configure.in ++++ krb5/src/configure.in +@@ -1053,6 +1053,8 @@ fi + + KRB5_WITH_PAM + ++KRB5_WITH_SELINUX ++ + # Make localedir work in autoconf 2.5x. + if test "${localedir+set}" != set; then + localedir='$(datadir)/locale' +--- krb5/src/include/k5-int.h ++++ krb5/src/include/k5-int.h +@@ -133,6 +133,7 @@ typedef unsigned char u_char; + typedef UINT64_TYPE krb5_ui_8; + typedef INT64_TYPE krb5_int64; + ++#include "k5-label.h" + + #define DEFAULT_PWD_STRING1 "Enter password" + #define DEFAULT_PWD_STRING2 "Re-enter password for verification" +--- krb5/src/include/k5-label.h ++++ krb5/src/include/k5-label.h +@@ -0,0 +1,32 @@ ++#ifndef _KRB5_LABEL_H ++#define _KRB5_LABEL_H ++ ++#ifdef THREEPARAMOPEN ++#undef THREEPARAMOPEN ++#endif ++#ifdef WRITABLEFOPEN ++#undef WRITABLEFOPEN ++#endif ++ ++/* Wrapper functions which help us create files and directories with the right ++ * context labels. */ ++#ifdef USE_SELINUX ++#include ++#include ++#include ++#include ++#include ++FILE *krb5int_labeled_fopen(const char *path, const char *mode); ++int krb5int_labeled_creat(const char *path, mode_t mode); ++int krb5int_labeled_open(const char *path, int flags, ...); ++int krb5int_labeled_mkdir(const char *path, mode_t mode); ++int krb5int_labeled_mknod(const char *path, mode_t mode, dev_t device); ++#define THREEPARAMOPEN(x,y,z) krb5int_labeled_open(x,y,z) ++#define WRITABLEFOPEN(x,y) krb5int_labeled_fopen(x,y) ++void *krb5int_push_fscreatecon_for(const char *pathname); ++void krb5int_pop_fscreatecon(void *previous); ++#else ++#define WRITABLEFOPEN(x,y) fopen(x,y) ++#define THREEPARAMOPEN(x,y,z) open(x,y,z) ++#endif ++#endif +--- krb5/src/include/krb5/krb5.hin ++++ krb5/src/include/krb5/krb5.hin +@@ -87,6 +87,12 @@ + #define THREEPARAMOPEN(x,y,z) open(x,y,z) + #endif + ++#if KRB5_PRIVATE ++#ifndef WRITABLEFOPEN ++#define WRITABLEFOPEN(x,y) fopen(x,y) ++#endif ++#endif ++ + #define KRB5_OLD_CRYPTO + + #include +--- krb5/src/kadmin/dbutil/dump.c ++++ krb5/src/kadmin/dbutil/dump.c +@@ -376,12 +376,21 @@ create_ofile(char *ofile, char **tmpname + { + int fd = -1; + FILE *f; ++#ifdef USE_SELINUX ++ void *selabel; ++#endif + + *tmpname = NULL; + if (asprintf(tmpname, "%s-XXXXXX", ofile) < 0) + goto error; + ++#ifdef USE_SELINUX ++ selabel = krb5int_push_fscreatecon_for(ofile); ++#endif + fd = mkstemp(*tmpname); ++#ifdef USE_SELINUX ++ krb5int_pop_fscreatecon(selabel); ++#endif + if (fd == -1) + goto error; + +@@ -514,7 +514,7 @@ prep_ok_file(krb5_context context, char + return 0; + } + +- *fd = open(file_ok, O_WRONLY | O_CREAT | O_TRUNC, 0600); ++ *fd = THREEPARAMOPEN(file_ok, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (*fd == -1) { + com_err(progname, errno, _("while creating 'ok' file, '%s'"), file_ok); + exit_status++; +--- krb5/src/krb5-config.in ++++ krb5/src/krb5-config.in +@@ -38,6 +38,7 @@ RPATH_FLAG='@RPATH_FLAG@' + DEFCCNAME='@DEFCCNAME@' + DEFKTNAME='@DEFKTNAME@' + DEFCKTNAME='@DEFCKTNAME@' ++SELINUX_LIBS='@SELINUX_LIBS@' + + LIBS='@LIBS@' + GEN_LIB=@GEN_LIB@ +@@ -218,7 +219,7 @@ + fi + + # If we ever support a flag to generate output suitable for static +- # linking, we would output "-lkrb5support $GEN_LIB $LIBS $DL_LIB" ++ # linking, we would output "-lkrb5support $GEN_LIB $LIBS $SELINUX_LIBS $DL_LIB" + # here. + + echo $lib_flags +--- krb5/src/lib/kadm5/logger.c ++++ krb5/src/lib/kadm5/logger.c +@@ -425,7 +425,7 @@ krb5_klog_init(krb5_context kcontext, ch + * Check for append/overwrite, then open the file. + */ + if (cp[4] == ':' || cp[4] == '=') { +- f = fopen(&cp[5], (cp[4] == ':') ? "a" : "w"); ++ f = WRITABLEFOPEN(&cp[5], (cp[4] == ':') ? "a" : "w"); + if (f) { + set_cloexec_file(f); + log_control.log_entries[i].lfu_filep = f; +@@ -961,7 +961,7 @@ krb5_klog_reopen(krb5_context kcontext) + * In case the old logfile did not get moved out of the + * way, open for append to prevent squashing the old logs. + */ +- f = fopen(log_control.log_entries[lindex].lfu_fname, "a+"); ++ f = WRITABLEFOPEN(log_control.log_entries[lindex].lfu_fname, "a+"); + if (f) { + set_cloexec_file(f); + log_control.log_entries[lindex].lfu_filep = f; +--- krb5/src/lib/krb5/keytab/kt_file.c ++++ krb5/src/lib/krb5/keytab/kt_file.c +@@ -1050,7 +1050,7 @@ krb5_ktfileint_open(krb5_context context + + KTCHECKLOCK(id); + errno = 0; +- KTFILEP(id) = fopen(KTFILENAME(id), ++ KTFILEP(id) = WRITABLEFOPEN(KTFILENAME(id), + (mode == KRB5_LOCKMODE_EXCLUSIVE) ? + fopen_mode_rbplus : fopen_mode_rb); + if (!KTFILEP(id)) { +@@ -1058,7 +1058,7 @@ krb5_ktfileint_open(krb5_context context + /* try making it first time around */ + krb5_create_secure_file(context, KTFILENAME(id)); + errno = 0; +- KTFILEP(id) = fopen(KTFILENAME(id), fopen_mode_rbplus); ++ KTFILEP(id) = WRITABLEFOPEN(KTFILENAME(id), fopen_mode_rbplus); + if (!KTFILEP(id)) + goto report_errno; + writevno = 1; +--- krb5/src/plugins/kdb/db2/adb_openclose.c ++++ krb5/src/plugins/kdb/db2/adb_openclose.c +@@ -201,7 +201,7 @@ osa_adb_init_db(osa_adb_db_t *dbp, char + * POSIX systems + */ + lockp->lockinfo.filename = strdup(lockfilename); +- if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+")) == NULL) { ++ if ((lockp->lockinfo.lockfile = WRITABLEFOPEN(lockfilename, "r+")) == NULL) { + /* + * maybe someone took away write permission so we could only + * get shared locks? +--- krb5/src/plugins/kdb/db2/libdb2/btree/bt_open.c ++++ krb5/src/plugins/kdb/db2/libdb2/btree/bt_open.c +@@ -60,6 +60,7 @@ static char sccsid[] = "@(#)bt_open.c 8. + + #include "k5-platform.h" /* mkstemp? */ + ++#include "k5-int.h" + #include "db-int.h" + #include "btree.h" + +@@ -203,7 +204,7 @@ __bt_open(fname, flags, mode, openinfo, + goto einval; + } + +- if ((t->bt_fd = open(fname, flags | O_BINARY, mode)) < 0) ++ if ((t->bt_fd = THREEPARAMOPEN(fname, flags | O_BINARY, mode)) < 0) + goto err; + + } else { +--- krb5/src/plugins/kdb/db2/libdb2/hash/hash.c ++++ krb5/src/plugins/kdb/db2/libdb2/hash/hash.c +@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)hash.c 8.12 + #include + #endif + ++#include "k5-int.h" + #include "db-int.h" + #include "hash.h" + #include "page.h" +@@ -140,7 +141,7 @@ __kdb2_hash_open(file, flags, mode, info + new_table = 1; + } + if (file) { +- if ((hashp->fp = open(file, flags|O_BINARY, mode)) == -1) ++ if ((hashp->fp = THREEPARAMOPEN(file, flags|O_BINARY, mode)) == -1) + RETURN_ERROR(errno, error0); + (void)fcntl(hashp->fp, F_SETFD, 1); + } +--- krb5/src/plugins/kdb/db2/libdb2/test/Makefile.in ++++ krb5/src/plugins/kdb/db2/libdb2/test/Makefile.in +@@ -12,7 +12,8 @@ PROG_RPATH=$(KRB5_LIBDIR) + + KRB5_RUN_ENV= @KRB5_RUN_ENV@ + +-DB_LIB = -ldb ++DB_LIB = -ldb $(SUPPORT_DEPLIB) ++ + DB_DEPLIB = ../libdb$(DEPLIBEXT) + + all:: +--- krb5/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c ++++ krb5/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c +@@ -179,7 +179,7 @@ done: + + /* set password in the file */ + old_mode = umask(0177); +- pfile = fopen(file_name, "a+"); ++ pfile = WRITABLEFOPEN(file_name, "a+"); + if (pfile == NULL) { + com_err(me, errno, _("Failed to open file %s: %s"), file_name, + strerror (errno)); +@@ -220,6 +220,9 @@ done: + * Delete the existing entry and add the new entry + */ + FILE *newfile; ++#ifdef USE_SELINUX ++ void *selabel; ++#endif + + mode_t omask; + +@@ -231,7 +234,13 @@ done: + } + + omask = umask(077); ++#ifdef USE_SELINUX ++ selabel = krb5int_push_fscreatecon_for(file_name); ++#endif + newfile = fopen(tmp_file, "w"); ++#ifdef USE_SELINUX ++ krb5int_pop_fscreatecon(selabel); ++#endif + umask (omask); + if (newfile == NULL) { + com_err(me, errno, _("Error creating file %s"), tmp_file); +--- krb5/src/slave/kpropd.c ++++ krb5/src/slave/kpropd.c +@@ -437,6 +437,9 @@ void doit(fd) + krb5_enctype etype; + int database_fd; + char host[INET6_ADDRSTRLEN+1]; ++#ifdef USE_SELINUX ++ void *selabel; ++#endif + + signal_wrapper(SIGALRM, alarm_handler); + alarm(params.iprop_resync_timeout); +@@ -515,9 +518,15 @@ void doit(fd) + free(name); + exit(1); + } ++#ifdef USE_SELINUX ++ selabel = krb5int_push_fscreatecon_for(file); ++#endif + omask = umask(077); + lock_fd = open(temp_file_name, O_RDWR|O_CREAT, 0600); + (void) umask(omask); ++#ifdef USE_SELINUX ++ krb5int_pop_fscreatecon(selabel); ++#endif + retval = krb5_lock_file(kpropd_context, lock_fd, + KRB5_LOCKMODE_EXCLUSIVE|KRB5_LOCKMODE_DONTBLOCK); + if (retval) { +--- krb5/src/util/profile/prof_file.c ++++ krb5/src/util/profile/prof_file.c +@@ -30,6 +30,7 @@ + #endif + + #include "k5-platform.h" ++#include "k5-label.h" + + struct global_shared_profile_data { + /* This is the head of the global list of shared trees */ +@@ -418,7 +419,7 @@ static errcode_t write_data_to_file(prf_ + + errno = 0; + +- f = fopen(new_file, "w"); ++ f = WRITABLEFOPEN(new_file, "w"); + if (!f) { + retval = errno; + if (retval == 0) +--- krb5/src/util/support/Makefile.in ++++ krb5/src/util/support/Makefile.in +@@ -54,6 +54,7 @@ IPC_SYMS= \ + + STLIBOBJS= \ + threads.o \ ++ selinux.o \ + init-addrinfo.o \ + plugins.o \ + errors.o \ +@@ -108,7 +109,7 @@ SRCS=\ + + SHLIB_EXPDEPS = + # Add -lm if dumping thread stats, for sqrt. +-SHLIB_EXPLIBS= $(LIBS) $(DL_LIB) ++SHLIB_EXPLIBS= $(LIBS) $(SELINUX_LIBS) $(DL_LIB) + SHLIB_DIRS= + SHLIB_RDIRS=$(KRB5_LIBDIR) + +--- krb5/src/util/support/selinux.c ++++ krb5/src/util/support/selinux.c +@@ -0,0 +1,405 @@ ++/* ++ * Copyright 2007,2008,2009,2011,2012 Red Hat, Inc. 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. ++ * ++ * Neither the name of Red Hat, Inc. nor the names of its contributors may be ++ * used to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * 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 OWNER 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. ++ * ++ * File-opening wrappers for creating correctly-labeled files. So far, we can ++ * assume that this is Linux-specific, so we make many simplifying assumptions. ++ */ ++ ++#include "../../include/autoconf.h" ++ ++#ifdef USE_SELINUX ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef HAVE_SELINUX_LABEL_H ++#include ++#endif ++ ++/* #define DEBUG 1 */ ++ ++/* Mutex used to serialize use of the process-global file creation context. */ ++k5_mutex_t labeled_mutex = K5_MUTEX_PARTIAL_INITIALIZER; ++ ++/* Make sure we finish initializing that mutex before attempting to use it. */ ++k5_once_t labeled_once = K5_ONCE_INIT; ++static void ++label_mutex_init(void) ++{ ++ k5_mutex_finish_init(&labeled_mutex); ++} ++ ++#ifdef HAVE_SELINUX_LABEL_H ++static struct selabel_handle *selabel_ctx; ++static time_t selabel_last_changed; ++ ++MAKE_FINI_FUNCTION(cleanup_fscreatecon); ++ ++static void ++cleanup_fscreatecon(void) ++{ ++ if (selabel_ctx != NULL) { ++ selabel_close(selabel_ctx); ++ selabel_ctx = NULL; ++ } ++} ++#endif ++ ++static security_context_t ++push_fscreatecon(const char *pathname, mode_t mode) ++{ ++ security_context_t previous, configuredsc, currentsc, derivedsc; ++ context_t current, derived; ++ const char *fullpath, *currentuser; ++ ++ previous = NULL; ++ if (is_selinux_enabled()) { ++ if (getfscreatecon(&previous) == 0) { ++ char *genpath; ++ genpath = NULL; ++ if (pathname[0] != '/') { ++ char *wd; ++ size_t len; ++ len = 0; ++ wd = getcwd(NULL, len); ++ if (wd == NULL) { ++ if (previous != NULL) { ++ freecon(previous); ++ } ++ return NULL; ++ } ++ len = strlen(wd) + 1 + strlen(pathname) + 1; ++ genpath = malloc(len); ++ if (genpath == NULL) { ++ free(wd); ++ if (previous != NULL) { ++ freecon(previous); ++ } ++ return NULL; ++ } ++ sprintf(genpath, "%s/%s", wd, pathname); ++ free(wd); ++ fullpath = genpath; ++ } else { ++ fullpath = pathname; ++ } ++#ifdef DEBUG ++ if (isatty(fileno(stderr))) { ++ fprintf(stderr, "Looking up context for " ++ "\"%s\"(%05o).\n", fullpath, mode); ++ } ++#endif ++ configuredsc = NULL; ++#ifdef HAVE_SELINUX_LABEL_H ++ if ((selabel_ctx != NULL) || ++ (selabel_last_changed == 0)) { ++ const char *cpath; ++ struct stat st; ++ int i = -1; ++ cpath = selinux_file_context_path(); ++ if ((cpath == NULL) || ++ ((i = stat(cpath, &st)) != 0) || ++ (st.st_mtime != selabel_last_changed)) { ++ if (selabel_ctx != NULL) { ++ selabel_close(selabel_ctx); ++ selabel_ctx = NULL; ++ } ++ selabel_last_changed = i ? ++ time(NULL) : ++ st.st_mtime; ++ } ++ } ++ if (selabel_ctx == NULL) { ++ selabel_ctx = selabel_open(SELABEL_CTX_FILE, ++ NULL, 0); ++ } ++ if (selabel_ctx != NULL) { ++ if (selabel_lookup(selabel_ctx, &configuredsc, ++ fullpath, mode) != 0) { ++ free(genpath); ++ if (previous != NULL) { ++ freecon(previous); ++ } ++ return NULL; ++ } ++ } ++#else ++ if (matchpathcon(fullpath, mode, &configuredsc) != 0) { ++ free(genpath); ++ if (previous != NULL) { ++ freecon(previous); ++ } ++ return NULL; ++ } ++#endif ++ free(genpath); ++ if (configuredsc == NULL) { ++ if (previous != NULL) { ++ freecon(previous); ++ } ++ return NULL; ++ } ++ currentsc = NULL; ++ getcon(¤tsc); ++ if (currentsc != NULL) { ++ derived = context_new(configuredsc); ++ if (derived != NULL) { ++ current = context_new(currentsc); ++ if (current != NULL) { ++ currentuser = context_user_get(current); ++ if (currentuser != NULL) { ++ if (context_user_set(derived, ++ currentuser) == 0) { ++ derivedsc = context_str(derived); ++ if (derivedsc != NULL) { ++ freecon(configuredsc); ++ configuredsc = strdup(derivedsc); ++ } ++ } ++ } ++ context_free(current); ++ } ++ context_free(derived); ++ } ++ freecon(currentsc); ++ } ++#ifdef DEBUG ++ if (isatty(fileno(stderr))) { ++ fprintf(stderr, "Setting file creation context " ++ "to \"%s\".\n", configuredsc); ++ } ++#endif ++ if (setfscreatecon(configuredsc) != 0) { ++ freecon(configuredsc); ++ if (previous != NULL) { ++ freecon(previous); ++ } ++ return NULL; ++ } ++ freecon(configuredsc); ++#ifdef DEBUG ++ } else { ++ if (isatty(fileno(stderr))) { ++ fprintf(stderr, "Unable to determine " ++ "current context.\n"); ++ } ++#endif ++ } ++ } ++ return previous; ++} ++ ++static void ++pop_fscreatecon(security_context_t previous) ++{ ++ if (is_selinux_enabled()) { ++#ifdef DEBUG ++ if (isatty(fileno(stderr))) { ++ if (previous != NULL) { ++ fprintf(stderr, "Resetting file creation " ++ "context to \"%s\".\n", previous); ++ } else { ++ fprintf(stderr, "Resetting file creation " ++ "context to default.\n"); ++ } ++ } ++#endif ++ setfscreatecon(previous); ++ if (previous != NULL) { ++ freecon(previous); ++ } ++ } ++} ++ ++void * ++krb5int_push_fscreatecon_for(const char *pathname) ++{ ++ struct stat st; ++ void *retval; ++ k5_once(&labeled_once, label_mutex_init); ++ if (k5_mutex_lock(&labeled_mutex) == 0) { ++ if (stat(pathname, &st) != 0) { ++ st.st_mode = S_IRUSR | S_IWUSR; ++ } ++ retval = push_fscreatecon(pathname, st.st_mode); ++ return retval ? retval : (void *) -1; ++ } else { ++ return NULL; ++ } ++} ++ ++void ++krb5int_pop_fscreatecon(void *con) ++{ ++ if (con != NULL) { ++ pop_fscreatecon((con == (void *) -1) ? NULL : con); ++ k5_mutex_unlock(&labeled_mutex); ++ } ++} ++ ++FILE * ++krb5int_labeled_fopen(const char *path, const char *mode) ++{ ++ FILE *fp; ++ int errno_save; ++ security_context_t ctx; ++ ++ if ((strcmp(mode, "r") == 0) || ++ (strcmp(mode, "rb") == 0)) { ++ return fopen(path, mode); ++ } ++ ++ k5_once(&labeled_once, label_mutex_init); ++ if (k5_mutex_lock(&labeled_mutex) == 0) { ++ ctx = push_fscreatecon(path, 0); ++ fp = fopen(path, mode); ++ errno_save = errno; ++ pop_fscreatecon(ctx); ++ k5_mutex_unlock(&labeled_mutex); ++ errno = errno_save; ++ } else { ++ fp = fopen(path, mode); ++ } ++ ++ return fp; ++} ++ ++int ++krb5int_labeled_creat(const char *path, mode_t mode) ++{ ++ int fd; ++ int errno_save; ++ security_context_t ctx; ++ ++ k5_once(&labeled_once, label_mutex_init); ++ if (k5_mutex_lock(&labeled_mutex) == 0) { ++ ctx = push_fscreatecon(path, 0); ++ fd = creat(path, mode); ++ errno_save = errno; ++ pop_fscreatecon(ctx); ++ k5_mutex_unlock(&labeled_mutex); ++ errno = errno_save; ++ } else { ++ fd = creat(path, mode); ++ } ++ return fd; ++} ++ ++int ++krb5int_labeled_mknod(const char *path, mode_t mode, dev_t dev) ++{ ++ int ret; ++ int errno_save; ++ security_context_t ctx; ++ ++ k5_once(&labeled_once, label_mutex_init); ++ if (k5_mutex_lock(&labeled_mutex) == 0) { ++ ctx = push_fscreatecon(path, mode); ++ ret = mknod(path, mode, dev); ++ errno_save = errno; ++ pop_fscreatecon(ctx); ++ k5_mutex_unlock(&labeled_mutex); ++ errno = errno_save; ++ } else { ++ ret = mknod(path, mode, dev); ++ } ++ return ret; ++} ++ ++int ++krb5int_labeled_mkdir(const char *path, mode_t mode) ++{ ++ int ret; ++ int errno_save; ++ security_context_t ctx; ++ ++ k5_once(&labeled_once, label_mutex_init); ++ if (k5_mutex_lock(&labeled_mutex) == 0) { ++ ctx = push_fscreatecon(path, S_IFDIR); ++ ret = mkdir(path, mode); ++ errno_save = errno; ++ pop_fscreatecon(ctx); ++ k5_mutex_unlock(&labeled_mutex); ++ errno = errno_save; ++ } else { ++ ret = mkdir(path, mode); ++ } ++ return ret; ++} ++ ++int ++krb5int_labeled_open(const char *path, int flags, ...) ++{ ++ int fd; ++ int errno_save; ++ security_context_t ctx; ++ mode_t mode; ++ va_list ap; ++ ++ if ((flags & O_CREAT) == 0) { ++ return open(path, flags); ++ } ++ ++ k5_once(&labeled_once, label_mutex_init); ++ if (k5_mutex_lock(&labeled_mutex) == 0) { ++ ctx = push_fscreatecon(path, 0); ++ ++ va_start(ap, flags); ++ mode = va_arg(ap, mode_t); ++ fd = open(path, flags, mode); ++ va_end(ap); ++ ++ errno_save = errno; ++ pop_fscreatecon(ctx); ++ k5_mutex_unlock(&labeled_mutex); ++ errno = errno_save; ++ } else { ++ va_start(ap, flags); ++ mode = va_arg(ap, mode_t); ++ fd = open(path, flags, mode); ++ errno_save = errno; ++ va_end(ap); ++ errno = errno_save; ++ } ++ return fd; ++} ++ ++#endif +--- krb5/src/lib/krb5/rcache/rc_dfl.c ++++ krb5/src/lib/krb5/rcache/rc_dfl.c +@@ -813,6 +813,9 @@ krb5_rc_dfl_expunge_locked(krb5_context + krb5_error_code retval = 0; + krb5_rcache tmp; + krb5_deltat lifespan = t->lifespan; /* save original lifespan */ ++#ifdef USE_SELINUX ++ void *selabel; ++#endif + + if (! t->recovering) { + name = t->name; +@@ -834,7 +837,17 @@ krb5_rc_dfl_expunge_locked(krb5_context + retval = krb5_rc_resolve(context, tmp, 0); + if (retval) + goto cleanup; ++#ifdef USE_SELINUX ++ if (t->d.fn != NULL) ++ selabel = krb5int_push_fscreatecon_for(t->d.fn); ++ else ++ selabel = NULL; ++#endif + retval = krb5_rc_initialize(context, tmp, lifespan); ++#ifdef USE_SELINUX ++ if (selabel != NULL) ++ krb5int_pop_fscreatecon(selabel); ++#endif + if (retval) + goto cleanup; + for (q = t->a; q; q = q->na) { +--- krb5/src/lib/krb5/ccache/cc_dir.c ++++ krb5/src/lib/krb5/ccache/cc_dir.c +@@ -185,10 +185,19 @@ write_primary_file(const char *primary_p + char *newpath = NULL; + FILE *fp = NULL; + int fd = -1, status; ++#ifdef USE_SELINUX ++ void *selabel; ++#endif + + if (asprintf(&newpath, "%s.XXXXXX", primary_path) < 0) + return ENOMEM; ++#ifdef USE_SELINUX ++ selabel = krb5int_push_fscreatecon_for(primary_path); ++#endif + fd = mkstemp(newpath); ++#ifdef USE_SELINUX ++ krb5int_pop_fscreatecon(selabel); ++#endif + if (fd < 0) + goto cleanup; + #ifdef HAVE_CHMOD +@@ -223,10 +232,23 @@ + verify_dir(krb5_context context, const char *dirname) + { + struct stat st; ++ int status; ++#ifdef USE_SELINUX ++ void *selabel; ++#endif + + if (stat(dirname, &st) < 0) { +- if (errno == ENOENT && mkdir(dirname, S_IRWXU) == 0) +- return 0; ++ if (errno == ENOENT) { ++#ifdef USE_SELINUX ++ selabel = krb5int_push_fscreatecon_for(dirname); ++#endif ++ status = mkdir(dirname, S_IRWXU); ++#ifdef USE_SELINUX ++ krb5int_pop_fscreatecon(selabel); ++#endif ++ if (status == 0) ++ return 0; ++ } + krb5_set_error_message(context, KRB5_FCC_NOFILE, + _("Credential cache directory %s does not " + "exist"), dirname); +--- krb5/src/lib/krb5/os/trace.c ++++ krb5/src/lib/krb5/os/trace.c +@@ -401,7 +401,7 @@ krb5_set_trace_filename(krb5_context con + fd = malloc(sizeof(*fd)); + if (fd == NULL) + return ENOMEM; +- *fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0600); ++ *fd = THREEPARAMOPEN(filename, O_WRONLY|O_CREAT|O_APPEND, 0600); + if (*fd == -1) { + free(fd); + return errno; +--- krb5/src/plugins/kdb/db2/kdb_db2.c ++++ krb5/src/plugins/kdb/db2/kdb_db2.c +@@ -683,8 +683,8 @@ + if (retval) + return retval; + +- dbc->db_lf_file = open(dbc->db_lf_name, O_CREAT | O_RDWR | O_TRUNC, +- 0600); ++ dbc->db_lf_file = THREEPARAMOPEN(dbc->db_lf_name, ++ O_CREAT | O_RDWR | O_TRUNC, 0600); + if (dbc->db_lf_file < 0) { + retval = errno; + goto cleanup; +--- krb5/src/plugins/kdb/db2/libdb2/recno/rec_open.c ++++ krb5/src/plugins/kdb/db2/libdb2/recno/rec_open.c +@@ -51,6 +51,7 @@ + #include + #include + ++#include "k5-int.h" + #include "db-int.h" + #include "recno.h" + +@@ -68,7 +69,8 @@ + int rfd = -1, sverrno; + + /* Open the user's file -- if this fails, we're done. */ +- if (fname != NULL && (rfd = open(fname, flags | O_BINARY, mode)) < 0) ++ if (fname != NULL && ++ (rfd = THREEPARAMOPEN(fname, flags | O_BINARY, mode)) < 0) + return (NULL); + + if (fname != NULL && fcntl(rfd, F_SETFD, 1) == -1) { +--- krb5/src/kdc/main.c ++++ krb5/src/kdc/main.c +@@ -905,7 +905,7 @@ write_pid_file(const char *path) + FILE *file; + unsigned long pid; + +- file = fopen(path, "w"); ++ file = WRITABLEFOPEN(path, "w"); + if (file == NULL) + return errno; + pid = (unsigned long) getpid(); +--- krb5/src/lib/kdb/kdb_log.c ++++ krb5/src/lib/kdb/kdb_log.c +@@ -566,7 +566,7 @@ ulog_map(krb5_context context, const cha + return (errno); + } + +- ulogfd = open(logname, O_RDWR | O_CREAT, 0600); ++ ulogfd = THREEPARAMOPEN(logname, O_RDWR | O_CREAT, 0600); + if (ulogfd == -1) { + return (errno); + } +--- krb5/src/util/gss-kernel-lib/Makefile.in ++++ krb5/src/util/gss-kernel-lib/Makefile.in +@@ -60,6 +60,7 @@ HEADERS= \ + gssapi_err_generic.h \ + k5-int.h \ + k5-int-pkinit.h \ ++ k5-label.h \ + k5-thread.h \ + k5-platform.h \ + k5-buf.h \ +@@ -166,10 +167,12 @@ gssapi_generic.h: $(GSS_GENERIC)/gssapi_ + $(CP) $(GSS_GENERIC)/gssapi_generic.h $@ + gssapi_err_generic.h: $(GSS_GENERIC_BUILD)/gssapi_err_generic.h + $(CP) $(GSS_GENERIC_BUILD)/gssapi_err_generic.h $@ +-k5-int.h: $(INCLUDE)/k5-int.h ++k5-int.h: $(INCLUDE)/k5-int.h k5-label.h + $(CP) $(INCLUDE)/k5-int.h $@ + k5-int-pkinit.h: $(INCLUDE)/k5-int-pkinit.h + $(CP) $(INCLUDE)/k5-int-pkinit.h $@ ++k5-label.h: $(INCLUDE)/k5-label.h ++ $(CP) $(INCLUDE)/k5-label.h $@ + k5-thread.h: $(INCLUDE)/k5-thread.h + $(CP) $(INCLUDE)/k5-thread.h $@ + k5-platform.h: $(INCLUDE)/k5-platform.h diff --git a/SOURCES/krb5-1.11.2-arcfour_short.patch b/SOURCES/krb5-1.11.2-arcfour_short.patch new file mode 100644 index 0000000..2f67ae3 --- /dev/null +++ b/SOURCES/krb5-1.11.2-arcfour_short.patch @@ -0,0 +1,122 @@ +Needed by tests for empty-password cases. + +commit 1e123231769fe640f446442cb210664d280ccbac +Author: Greg Hudson +Date: Fri May 24 13:16:52 2013 -0400 + + Fix rc4 string-to-key on unterminated inputs + + The internal UTF-8 to UCS-2 conversion functions did not properly + respect their length arguments, instead assuming that the input string + is terminated with a zero bytes. As a result, + krb5int_arcfour_string_to_key could fail on unterminated inputs. Fix + the underlying support functions to read their inputs only up to the + specified length. + + ticket: 7643 (new) + +diff --git a/src/util/support/utf8_conv.c b/src/util/support/utf8_conv.c +index d580bbc..b8bf989 100644 +--- a/src/util/support/utf8_conv.c ++++ b/src/util/support/utf8_conv.c +@@ -78,7 +78,8 @@ k5_utf8s_to_ucs2s(krb5_ucs2 *ucs2str, + + /* If input ptr is NULL or empty... */ + if (utf8str == NULL || *utf8str == '\0') { +- *ucs2str = 0; ++ if (ucs2str != NULL) ++ *ucs2str = 0; + + return 0; + } +@@ -119,9 +120,7 @@ k5_utf8s_to_ucs2s(krb5_ucs2 *ucs2str, + ucs2len++; /* Count number of wide chars stored/required */ + } + +- assert(ucs2len < count); +- +- if (ucs2str != NULL) { ++ if (ucs2str != NULL && ucs2len < count) { + /* Add null terminator if there's room in the buffer. */ + ucs2str[ucs2len] = 0; + } +@@ -172,12 +171,13 @@ krb5int_utf8cs_to_ucs2s(const char *utf8s, + return ENOMEM; + } + +- len = k5_utf8s_to_ucs2s(*ucs2s, utf8s, chars + 1, 0); ++ len = k5_utf8s_to_ucs2s(*ucs2s, utf8s, chars, 0); + if (len < 0) { + free(*ucs2s); + *ucs2s = NULL; + return EINVAL; + } ++ (*ucs2s)[chars] = 0; + + if (ucs2chars != NULL) { + *ucs2chars = chars; +@@ -223,21 +223,23 @@ krb5int_utf8cs_to_ucs2les(const char *utf8s, + { + ssize_t len; + size_t chars; ++ krb5_ucs2 *ucs2s; + +- chars = krb5int_utf8c_chars(utf8s, utf8slen); ++ *ucs2les = NULL; + +- *ucs2les = (unsigned char *)malloc((chars + 1) * sizeof(krb5_ucs2)); +- if (*ucs2les == NULL) { ++ chars = krb5int_utf8c_chars(utf8s, utf8slen); ++ ucs2s = malloc((chars + 1) * sizeof(krb5_ucs2)); ++ if (ucs2s == NULL) + return ENOMEM; +- } + +- len = k5_utf8s_to_ucs2s((krb5_ucs2 *)*ucs2les, utf8s, chars + 1, 1); ++ len = k5_utf8s_to_ucs2s(ucs2s, utf8s, chars, 1); + if (len < 0) { +- free(*ucs2les); +- *ucs2les = NULL; ++ free(ucs2s); + return EINVAL; + } ++ ucs2s[chars] = 0; + ++ *ucs2les = (unsigned char *)ucs2s; + if (ucs2leslen != NULL) { + *ucs2leslen = chars * sizeof(krb5_ucs2); + } +@@ -402,13 +404,14 @@ krb5int_ucs2cs_to_utf8s(const krb5_ucs2 *ucs2s, + return ENOMEM; + } + +- len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2s, +- (size_t)len + 1, (ssize_t)ucs2slen, 0); ++ len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2s, (size_t)len, ++ (ssize_t)ucs2slen, 0); + if (len < 0) { + free(*utf8s); + *utf8s = NULL; + return EINVAL; + } ++ (*utf8s)[len] = '\0'; + + if (utf8slen != NULL) { + *utf8slen = len; +@@ -438,13 +441,14 @@ krb5int_ucs2lecs_to_utf8s(const unsigned char *ucs2les, + return ENOMEM; + } + +- len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2les, +- (size_t)len + 1, (ssize_t)ucs2leslen, 1); ++ len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2les, (size_t)len, ++ (ssize_t)ucs2leslen, 1); + if (len < 0) { + free(*utf8s); + *utf8s = NULL; + return EINVAL; + } ++ (*utf8s)[len] = '\0'; + + if (utf8slen != NULL) { + *utf8slen = len; diff --git a/SOURCES/krb5-1.11.2-empty_passwords.patch b/SOURCES/krb5-1.11.2-empty_passwords.patch new file mode 100644 index 0000000..3941084 --- /dev/null +++ b/SOURCES/krb5-1.11.2-empty_passwords.patch @@ -0,0 +1,492 @@ +Should fix #960001. Adjusted to apply to 1.11.2, which didn't yet include +some other developments, renames, reformatting, and fewer tests. + +commit f3458ed803ae97b6c6c7c63baeb82b26c4943d4c +Author: Greg Hudson +Date: Thu May 23 15:33:58 2013 -0400 + + Make empty passwords work via init_creds APIs + + In the gak_data value used by krb5_get_as_key_password, separate the + already-known password from the storage we might have allocated to put + it in, so that we no longer use an empty data buffer to determine + whether we know the password. This allows empty passwords to work via + the API. + + Remove the kadm5 test which explicitly uses an empty password. + + Based on a patch from Stef Walter. + + ticket: 7642 + +diff --git a/src/lib/kadm5/unit-test/api.current/init.exp b/src/lib/kadm5/unit-test/api.current/init.exp +index b324df8..d9ae3fb 100644 +--- a/src/lib/kadm5/unit-test/api.current/init.exp ++++ b/src/lib/kadm5/unit-test/api.current/init.exp +@@ -99,33 +99,6 @@ proc test6 {} { + } + if { $RPC } { test6 } + +-test "init 7" +-proc test7 {} { +- global test +- +- send "kadm5_init admin \"\" \$KADM5_ADMIN_SERVICE null \$KADM5_STRUCT_VERSION \$KADM5_API_VERSION_3 server_handle\n" +- +- expect { +- -re "assword\[^\r\n\]*:" { } +- -re "key:$" { } +- eof { +- fail "$test: eof instead of password prompt" +- api_exit +- api_start +- return +- } +- timeout { +- fail "$test: timeout instead of password prompt" +- return +- } +- } +- one_line_succeed_test "admin" +- if {! [cmd {kadm5_destroy $server_handle}]} { +- error_and_restart "$test: couldn't close database" +- } +-} +-if { $RPC } { test7 } +- + test "init 8" + + proc test8 {} { +diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c +index 59614e7..20bc689 100644 +--- a/src/lib/krb5/krb/get_in_tkt.c ++++ b/src/lib/krb5/krb/get_in_tkt.c +@@ -493,8 +493,7 @@ krb5_init_creds_free(krb5_context context, + } + k5_response_items_free(ctx->rctx.items); + free(ctx->in_tkt_service); +- zap(ctx->password.data, ctx->password.length); +- krb5_free_data_contents(context, &ctx->password); ++ zapfree(ctx->gakpw.storage.data, ctx->gakpw.storage.length); + krb5_free_error(context, ctx->err_reply); + krb5_free_pa_data(context, ctx->err_padata); + krb5_free_cred_contents(context, &ctx->cred); +@@ -788,7 +787,7 @@ krb5_init_creds_init(krb5_context context, + ctx->prompter = prompter; + ctx->prompter_data = data; + ctx->gak_fct = krb5_get_as_key_password; +- ctx->gak_data = &ctx->password; ++ ctx->gak_data = &ctx->gakpw; + + ctx->request_time = 0; /* filled in later */ + ctx->start_time = start_time; +diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c +index 22db2b5..a97823f 100644 +--- a/src/lib/krb5/krb/gic_pwd.c ++++ b/src/lib/krb5/krb/gic_pwd.c +@@ -17,22 +17,19 @@ krb5_get_as_key_password(krb5_context context, + void *gak_data, + k5_response_items *ritems) + { +- krb5_data *password; ++ struct gak_password *gp = gak_data; + krb5_error_code ret; + krb5_data defsalt; + char *clientstr; +- char promptstr[1024]; ++ char promptstr[1024], pwbuf[1024]; ++ krb5_data pw; + krb5_prompt prompt; + krb5_prompt_type prompt_type; + const char *rpass; + +- password = (krb5_data *) gak_data; +- assert(password->length > 0); +- + /* If we need to get the AS key via the responder, ask for it. */ + if (as_key == NULL) { +- /* However, if we already have a password, don't ask. */ +- if (password->data[0] != '\0') ++ if (gp->password != NULL) + return 0; + + return k5_response_items_ask_question(ritems, +@@ -55,17 +52,20 @@ krb5_get_as_key_password(krb5_context context, + } + } + +- if (password->data[0] == '\0') { ++ if (gp->password == NULL) { + /* Check the responder for the password. */ + rpass = k5_response_items_get_answer(ritems, + KRB5_RESPONDER_QUESTION_PASSWORD); + if (rpass != NULL) { +- strlcpy(password->data, rpass, password->length); +- password->length = strlen(password->data); ++ ret = alloc_data(&gp->storage, strlen(rpass)); ++ if (ret) ++ return ret; ++ memcpy(gp->storage.data, rpass, strlen(rpass)); ++ gp->password = &gp->storage; + } + } + +- if (password->data[0] == '\0') { ++ if (gp->password == NULL) { + if (prompter == NULL) + return(EIO); + +@@ -76,9 +76,10 @@ krb5_get_as_key_password(krb5_context context, + clientstr); + free(clientstr); + ++ pw = make_data(pwbuf, sizeof(pwbuf)); + prompt.prompt = promptstr; + prompt.hidden = 1; +- prompt.reply = password; ++ prompt.reply = &pw; + prompt_type = KRB5_PROMPT_TYPE_PASSWORD; + + /* PROMPTER_INVOCATION */ +@@ -87,6 +88,12 @@ krb5_get_as_key_password(krb5_context context, + krb5int_set_prompt_types(context, 0); + if (ret) + return(ret); ++ ++ ret = krb5int_copy_data_contents(context, &pw, &gp->storage); ++ zap(pw.data, pw.length); ++ if (ret) ++ return ret; ++ gp->password = &gp->storage; + } + + if (salt == NULL) { +@@ -98,7 +105,7 @@ krb5_get_as_key_password(krb5_context context, + defsalt.length = 0; + } + +- ret = krb5_c_string_to_key_with_params(context, etype, password, salt, ++ ret = krb5_c_string_to_key_with_params(context, etype, gp->password, salt, + params->data?params:NULL, as_key); + + if (defsalt.length) +@@ -118,16 +125,11 @@ krb5_init_creds_set_password(krb5_context context, + if (s == NULL) + return ENOMEM; + +- if (ctx->password.data != NULL) { +- zap(ctx->password.data, ctx->password.length); +- krb5_free_data_contents(context, &ctx->password); +- } +- +- ctx->password.data = s; +- ctx->password.length = strlen(s); ++ zapfree(ctx->gakpw.storage.data, ctx->gakpw.storage.length); ++ ctx->gakpw.storage = string2data(s); ++ ctx->gakpw.password = &ctx->gakpw.storage; + ctx->gak_fct = krb5_get_as_key_password; +- ctx->gak_data = &ctx->password; +- ++ ctx->gak_data = &ctx->gakpw; + return 0; + } + +@@ -257,6 +259,7 @@ krb5_get_init_creds_password(krb5_context context, + int tries; + krb5_creds chpw_creds; + krb5_get_init_creds_opt *chpw_opts = NULL; ++ struct gak_password gakpw; + krb5_data pw0, pw1; + char banner[1024], pw0array[1024], pw1array[1024]; + krb5_prompt prompt[2]; +@@ -267,29 +270,18 @@ krb5_get_init_creds_password(krb5_context context, + use_master = 0; + as_reply = NULL; + memset(&chpw_creds, 0, sizeof(chpw_creds)); ++ memset(&gakpw, 0, sizeof(gakpw)); + +- pw0.data = pw0array; +- +- if (password && password[0]) { +- if (strlcpy(pw0.data, password, sizeof(pw0array)) >= sizeof(pw0array)) { +- ret = EINVAL; +- goto cleanup; +- } +- pw0.length = strlen(password); +- } else { +- pw0.data[0] = '\0'; +- pw0.length = sizeof(pw0array); ++ if (password != NULL) { ++ pw0 = string2data((char *)password); ++ gakpw.password = &pw0; + } + +- pw1.data = pw1array; +- pw1.data[0] = '\0'; +- pw1.length = sizeof(pw1array); +- + /* first try: get the requested tkt from any kdc */ + + ret = krb5int_get_init_creds(context, creds, client, prompter, data, + start_time, in_tkt_service, options, +- krb5_get_as_key_password, (void *) &pw0, ++ krb5_get_as_key_password, &gakpw, + &use_master, &as_reply); + + /* check for success */ +@@ -318,7 +310,7 @@ krb5_get_init_creds_password(krb5_context context, + } + ret2 = krb5int_get_init_creds(context, creds, client, prompter, data, + start_time, in_tkt_service, options, +- krb5_get_as_key_password, (void *) &pw0, ++ krb5_get_as_key_password, &gakpw, + &use_master, &as_reply); + + if (ret2 == 0) { +@@ -365,15 +357,21 @@ krb5_get_init_creds_password(krb5_context context, + if ((ret = krb5int_get_init_creds(context, &chpw_creds, client, + prompter, data, + start_time, "kadmin/changepw", chpw_opts, +- krb5_get_as_key_password, (void *) &pw0, ++ krb5_get_as_key_password, &gakpw, + &use_master, NULL))) + goto cleanup; + ++ pw0.data = pw0array; ++ pw0.data[0] = '\0'; ++ pw0.length = sizeof(pw0array); + prompt[0].prompt = _("Enter new password"); + prompt[0].hidden = 1; + prompt[0].reply = &pw0; + prompt_types[0] = KRB5_PROMPT_TYPE_NEW_PASSWORD; + ++ pw1.data = pw1array; ++ pw1.data[0] = '\0'; ++ pw1.length = sizeof(pw1array); + prompt[1].prompt = _("Enter it again"); + prompt[1].hidden = 1; + prompt[1].reply = &pw1; +@@ -460,10 +458,11 @@ krb5_get_init_creds_password(krb5_context context, + is final. */ + + TRACE_GIC_PWD_CHANGED(context); ++ gakpw.password = &pw0; + ret = krb5int_get_init_creds(context, creds, client, prompter, data, + start_time, in_tkt_service, options, +- krb5_get_as_key_password, (void *) &pw0, ++ krb5_get_as_key_password, &gakpw, + &use_master, &as_reply); + if (ret) + goto cleanup; + +@@ -474,6 +473,7 @@ cleanup: + + if (chpw_opts) + krb5_get_init_creds_opt_free(context, chpw_opts); ++ zapfree(gakpw.storage.data, gakpw.storage.length); + memset(pw0array, 0, sizeof(pw0array)); + memset(pw1array, 0, sizeof(pw1array)); + krb5_free_cred_contents(context, &chpw_creds); +@@ -512,21 +512,17 @@ krb5_get_in_tkt_with_password(krb5_context context, krb5_flags options, + krb5_creds *creds, krb5_kdc_rep **ret_as_reply) + { + krb5_error_code retval; +- krb5_data pw0; +- char pw0array[1024]; ++ struct gak_password gakpw; ++ krb5_data pw; + char * server; + krb5_principal server_princ, client_princ; + int use_master = 0; + krb5_get_init_creds_opt *opts = NULL; + +- pw0.data = pw0array; +- if (password && password[0]) { +- if (strlcpy(pw0.data, password, sizeof(pw0array)) >= sizeof(pw0array)) +- return EINVAL; +- pw0.length = strlen(password); +- } else { +- pw0.data[0] = '\0'; +- pw0.length = sizeof(pw0array); ++ memset(&gakpw, 0, sizeof(gakpw)); ++ if (password != NULL) { ++ pw = string2data((char *)password); ++ gakpw.password = &pw; + } + retval = krb5int_populate_gic_opt(context, &opts, + options, addrs, ktypes, +@@ -544,10 +540,11 @@ krb5_get_in_tkt_with_password(krb5_context context, krb5_flags options, + retval = krb5int_get_init_creds(context, creds, creds->client, + krb5_prompter_posix, NULL, + 0, server, opts, +- krb5_get_as_key_password, &pw0, ++ krb5_get_as_key_password, &gakpw, + &use_master, ret_as_reply); + krb5_free_unparsed_name( context, server); + krb5_get_init_creds_opt_free(context, opts); ++ zapfree(gakpw.storage.data, gakpw.storage.length); + if (retval) { + return (retval); + } +diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h +index d886c7a..4dbb0e9 100644 +--- a/src/lib/krb5/krb/init_creds_ctx.h ++++ b/src/lib/krb5/krb/init_creds_ctx.h +@@ -10,6 +10,11 @@ struct krb5_clpreauth_rock_st { + k5_json_value *cc_config_out; + }; + ++struct gak_password { ++ krb5_data storage; ++ const krb5_data *password; ++}; ++ + struct _krb5_init_creds_context { + krb5_gic_opt_ext *opte; + char *in_tkt_service; +@@ -23,7 +28,7 @@ struct _krb5_init_creds_context { + krb5_deltat renew_life; + krb5_boolean complete; + unsigned int loopcount; +- krb5_data password; ++ struct gak_password gakpw; + krb5_error *err_reply; + krb5_pa_data **err_padata; + krb5_creds cred; +diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in +index 2358c89..91f312e 100644 +--- a/src/tests/Makefile.in ++++ b/src/tests/Makefile.in +@@ -28,6 +28,9 @@ kdbtest: kdbtest.o $(KDB5_DEPLIBS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS) + KADMIN_OPTS= -d $(TEST_DB) -r $(TEST_REALM) -P $(TEST_MKEY) + KTEST_OPTS= $(KADMIN_OPTS) -p $(TEST_PREFIX) -n $(TEST_NUM) -D $(TEST_DEPTH) + ++t_init_creds: t_init_creds.o $(KRB5_BASE_DEPLIBS) ++ $(CC_LINK) -o $@ t_init_creds.o $(KRB5_BASE_LIBS) ++ + hist: hist.o $(KDB5_DEPLIBS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ hist.o $(KDB5_LIBS) $(KADMSRV_LIBS) $(KRB5_BASE_LIBS) + +@@ -73,7 +76,7 @@ kdb_check: kdc.conf krb5.conf + $(RUN_SETUP) $(VALGRIND) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) destroy -f + $(RM) $(TEST_DB)* stash_file + +-check-pytests:: hist ++check-pytests:: hist t_init_creds + $(RUNPYTEST) $(srcdir)/t_general.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_iprop.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_anonpkinit.py $(PYTESTFLAGS) +diff --git a/src/tests/t_general.py b/src/tests/t_general.py +index bb7a543..98e77a2 100755 +--- a/src/tests/t_general.py ++++ b/src/tests/t_general.py +@@ -22,6 +22,15 @@ for realm in multipass_realms(create_host=False): + # Test kinit against kdb keytab + realm.run_as_master([kinit, "-k", "-t", "KDB:", realm.user_princ]) + ++# Test that we can get initial creds with an empty password via the ++# API. We have to disable the "empty" pwqual module to create a ++# principal with an empty password. (Regression test for #7642.) ++conf={'master':{'plugins': {'pwqual': {'disable': 'empty'}}}} ++realm = K5Realm(create_user=False, create_host=False, krb5_conf=conf) ++realm.run_kadminl('addprinc -pw "" user') ++realm.run_as_client(['./t_init_creds', 'user', '']) ++realm.stop() ++ + realm = K5Realm(create_host=False) + + # Create a policy and see if it survives a dump/load. +diff --git a/src/tests/t_init_creds.c b/src/tests/t_init_creds.c +new file mode 100644 +index 0000000..6be8340 +--- /dev/null ++++ b/src/tests/t_init_creds.c +@@ -0,0 +1,88 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* tests/t_init_creds.c - test harness for getting initial creds */ ++/* ++ * Copyright (C) 2013 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. ++ */ ++ ++/* ++ * This program exercises the init_creds APIs in ways kinit doesn't. Right now ++ * it is very simplistic, but it can be extended as needed. ++ */ ++ ++#include ++#include ++ ++static krb5_context ctx; ++ ++static void ++check(krb5_error_code code) ++{ ++ const char *errmsg; ++ ++ if (code) { ++ errmsg = krb5_get_error_message(ctx, code); ++ fprintf(stderr, "%s\n", errmsg); ++ krb5_free_error_message(ctx, errmsg); ++ exit(1); ++ } ++} ++ ++int ++main(int argc, char **argv) ++{ ++ const char *princstr, *password; ++ krb5_principal client; ++ krb5_init_creds_context icc; ++ krb5_creds creds; ++ ++ if (argc != 3) { ++ fprintf(stderr, "Usage: t_init_creds princname password\n"); ++ exit(1); ++ } ++ princstr = argv[1]; ++ password = argv[2]; ++ ++ check(krb5_init_context(&ctx)); ++ check(krb5_parse_name(ctx, princstr, &client)); ++ ++ /* Try once with the traditional interface. */ ++ check(krb5_get_init_creds_password(ctx, &creds, client, password, NULL, ++ NULL, 0, NULL, NULL)); ++ krb5_free_cred_contents(ctx, &creds); ++ ++ /* Try again with the step interface. */ ++ check(krb5_init_creds_init(ctx, client, NULL, NULL, 0, NULL, &icc)); ++ check(krb5_init_creds_set_password(ctx, icc, password)); ++ check(krb5_init_creds_get(ctx, icc)); ++ krb5_init_creds_free(ctx, icc); ++ ++ krb5_free_principal(ctx, client); ++ krb5_free_context(ctx); ++ return 0; ++} diff --git a/SOURCES/krb5-1.11.2-keycheck.patch b/SOURCES/krb5-1.11.2-keycheck.patch new file mode 100644 index 0000000..4b4bd08 --- /dev/null +++ b/SOURCES/krb5-1.11.2-keycheck.patch @@ -0,0 +1,230 @@ +From c7047421487c0e616b881c0922937bc759114233 Mon Sep 17 00:00:00 2001 +From: Nathaniel McCallum +Date: Fri, 3 May 2013 15:44:44 -0400 +Subject: [PATCH 1/3] Check for keys in encrypted timestamp/challenge + +Encrypted timestamp and encrypted challenge cannot succeed if the +client has no long-term key matching the request enctypes, so do not +offer them in that case. + +ticket: 7630 + +NPM - This is a backport from the upstream fix. See upstream commits: + https://github.com/krb5/krb5/commit/e50482720a805ecd8c160e4a8f4a846e6327dca2 + https://github.com/krb5/krb5/commit/9593d1311fa5e6e841c429653ad35a63d17c2fdd +--- + src/kdc/kdc_preauth_ec.c | 23 +++++++++++++++++++++-- + src/kdc/kdc_preauth_encts.c | 22 ++++++++++++++++++++-- + 2 files changed, 41 insertions(+), 4 deletions(-) + +diff --git a/src/kdc/kdc_preauth_ec.c b/src/kdc/kdc_preauth_ec.c +index 9d7236c..db3ad07 100644 +--- a/src/kdc/kdc_preauth_ec.c ++++ b/src/kdc/kdc_preauth_ec.c +@@ -39,8 +39,27 @@ ec_edata(krb5_context context, krb5_kdc_req *request, + krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type, + krb5_kdcpreauth_edata_respond_fn respond, void *arg) + { +- krb5_keyblock *armor_key = cb->fast_armor(context, rock); +- (*respond)(arg, (armor_key == NULL) ? ENOENT : 0, NULL); ++ krb5_boolean have_client_keys = FALSE; ++ krb5_keyblock *armor_key; ++ krb5_key_data *kd; ++ int i; ++ ++ armor_key = cb->fast_armor(context, rock); ++ ++ for (i = 0; i < rock->request->nktypes; i++) { ++ if (krb5_dbe_find_enctype(context, rock->client, ++ rock->request->ktype[i], ++ -1, 0, &kd) == 0) { ++ have_client_keys = TRUE; ++ break; ++ } ++ } ++ ++ /* Encrypted challenge only works with FAST, and requires a client key. */ ++ if (armor_key == NULL || !have_client_keys) ++ (*respond)(arg, ENOENT, NULL); ++ else ++ (*respond)(arg, 0, NULL); + } + + static void +diff --git a/src/kdc/kdc_preauth_encts.c b/src/kdc/kdc_preauth_encts.c +index d708061..adde6e2 100644 +--- a/src/kdc/kdc_preauth_encts.c ++++ b/src/kdc/kdc_preauth_encts.c +@@ -34,9 +34,27 @@ enc_ts_get(krb5_context context, krb5_kdc_req *request, + krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type, + krb5_kdcpreauth_edata_respond_fn respond, void *arg) + { +- krb5_keyblock *armor_key = cb->fast_armor(context, rock); ++ krb5_boolean have_client_keys = FALSE; ++ krb5_keyblock *armor_key; ++ krb5_key_data *kd; ++ int i; ++ ++ armor_key = cb->fast_armor(context, rock); ++ ++ for (i = 0; i < rock->request->nktypes; i++) { ++ if (krb5_dbe_find_enctype(context, rock->client, ++ rock->request->ktype[i], ++ -1, 0, &kd) == 0) { ++ have_client_keys = TRUE; ++ break; ++ } ++ } + +- (*respond)(arg, (armor_key != NULL) ? ENOENT : 0, NULL); ++ /* Encrypted timestamp must not be used with FAST, and requires a key. */ ++ if (armor_key != NULL || !have_client_keys) ++ (*respond)(arg, ENOENT, NULL); ++ else ++ (*respond)(arg, 0, NULL); + } + + static void +-- +1.8.2.1 + + +From 4d19790527e2c9d52bb05abd6048a63a1a8c222c Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Mon, 29 Apr 2013 14:55:31 -0400 +Subject: [PATCH 2/3] Don't send empty etype info from KDC + +RFC 4120 prohibits empty ETYPE-INFO2 sequences (though not ETYPE-INFO +sequences), and our client errors out if it sees an empty sequence of +either. + +ticket: 7630 +--- + src/kdc/kdc_preauth.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c +index 42a37a8..5c3b615 100644 +--- a/src/kdc/kdc_preauth.c ++++ b/src/kdc/kdc_preauth.c +@@ -1404,6 +1404,11 @@ etype_info_helper(krb5_context context, krb5_kdc_req *request, + seen_des++; + } + } ++ ++ /* If the list is empty, don't send it at all. */ ++ if (i == 0) ++ goto cleanup; ++ + if (etype_info2) + retval = encode_krb5_etype_info2(entry, &scratch); + else +-- +1.8.2.1 + + +From a04cf2e89f4101eb6c2ec44ef1948976fe5fe9d3 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Thu, 2 May 2013 16:15:32 -0400 +Subject: [PATCH 3/3] Make AS requests work with no client key + +If we cannot find a client key while preparing an AS reply, give +preauth mechanisms a chance to replace the reply key before erroring +out. + +ticket: 7630 +--- + src/kdc/do_as_req.c | 36 ++++++++++++++++++++---------------- + src/kdc/kdc_preauth.c | 6 ++++++ + 2 files changed, 26 insertions(+), 16 deletions(-) + +diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c +index 79da300..cb91803 100644 +--- a/src/kdc/do_as_req.c ++++ b/src/kdc/do_as_req.c +@@ -195,23 +195,18 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) + useenctype, -1, 0, &client_key)) + break; + } +- if (!(client_key)) { +- /* Cannot find an appropriate key */ +- state->status = "CANT_FIND_CLIENT_KEY"; +- errcode = KRB5KDC_ERR_ETYPE_NOSUPP; +- goto egress; +- } +- state->rock.client_key = client_key; + +- /* convert client.key_data into a real key */ +- if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL, +- client_key, +- &state->client_keyblock, +- NULL))) { +- state->status = "DECRYPT_CLIENT_KEY"; +- goto egress; ++ if (client_key != NULL) { ++ /* Decrypt the client key data entry to get the real reply key. */ ++ errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL, client_key, ++ &state->client_keyblock, NULL); ++ if (errcode) { ++ state->status = "DECRYPT_CLIENT_KEY"; ++ goto egress; ++ } ++ state->client_keyblock.enctype = useenctype; ++ state->rock.client_key = client_key; + } +- state->client_keyblock.enctype = useenctype; + + /* Start assembling the response */ + state->reply.msg_type = KRB5_AS_REP; +@@ -248,6 +243,14 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) + goto egress; + } + ++ /* If we didn't find a client long-term key and no preauth mechanism ++ * replaced the reply key, error out now. */ ++ if (state->client_keyblock.enctype == ENCTYPE_NULL) { ++ state->status = "CANT_FIND_CLIENT_KEY"; ++ errcode = KRB5KDC_ERR_ETYPE_NOSUPP; ++ goto egress; ++ } ++ + errcode = handle_authdata(kdc_context, + state->c_flags, + state->client, +@@ -306,7 +309,8 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) + &state->reply_encpart, 0, + as_encrypting_key, + &state->reply, &response); +- state->reply.enc_part.kvno = client_key->key_data_kvno; ++ if (client_key != NULL) ++ state->reply.enc_part.kvno = client_key->key_data_kvno; + if (errcode) { + state->status = "ENCODE_KDC_REP"; + goto egress; +diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c +index 5c3b615..5d12346 100644 +--- a/src/kdc/kdc_preauth.c ++++ b/src/kdc/kdc_preauth.c +@@ -1473,6 +1473,9 @@ etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata, + krb5_etype_info_entry **entry = NULL; + krb5_data *scratch = NULL; + ++ if (client_key == NULL) ++ return 0; ++ + /* + * Skip PA-ETYPE-INFO completely if AS-REQ lists any "newer" + * enctypes. +@@ -1576,6 +1579,9 @@ return_pw_salt(krb5_context context, krb5_pa_data *in_padata, + krb5_key_data * client_key = rock->client_key; + int i; + ++ if (client_key == NULL) ++ return 0; ++ + for (i = 0; i < request->nktypes; i++) { + if (enctype_requires_etype_info_2(request->ktype[i])) + return 0; +-- +1.8.2.1 + diff --git a/SOURCES/krb5-1.11.2-otp.patch b/SOURCES/krb5-1.11.2-otp.patch new file mode 100644 index 0000000..eab913e --- /dev/null +++ b/SOURCES/krb5-1.11.2-otp.patch @@ -0,0 +1,5163 @@ +From 9a0bb5ada335017c5da35cb41333632ae5577a93 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Tue, 15 Jan 2013 11:11:27 -0500 +Subject: [PATCH 1/4] Add internal KDC_DIR macro + +Define KDC_DIR in osconf.hin and use it for paths within the KDC +directory. +--- + src/include/osconf.hin | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/src/include/osconf.hin b/src/include/osconf.hin +index c3a33c2..90ab86d 100644 +--- a/src/include/osconf.hin ++++ b/src/include/osconf.hin +@@ -58,14 +58,15 @@ + #define DEFAULT_PLUGIN_BASE_DIR "@LIBDIR/krb5/plugins" + #define PLUGIN_EXT "@DYNOBJEXT" + +-#define DEFAULT_KDB_FILE "@LOCALSTATEDIR/krb5kdc/principal" +-#define DEFAULT_KEYFILE_STUB "@LOCALSTATEDIR/krb5kdc/.k5." +-#define KRB5_DEFAULT_ADMIN_ACL "@LOCALSTATEDIR/krb5kdc/krb5_adm.acl" ++#define KDC_DIR "@LOCALSTATEDIR/krb5kdc" ++#define DEFAULT_KDB_FILE KDC_DIR "/principal" ++#define DEFAULT_KEYFILE_STUB KDC_DIR "/.k5." ++#define KRB5_DEFAULT_ADMIN_ACL KDC_DIR "/krb5_adm.acl" + /* Used by old admin server */ +-#define DEFAULT_ADMIN_ACL "@LOCALSTATEDIR/krb5kdc/kadm_old.acl" ++#define DEFAULT_ADMIN_ACL KDC_DIR "/kadm_old.acl" + + /* Location of KDC profile */ +-#define DEFAULT_KDC_PROFILE "@LOCALSTATEDIR/krb5kdc/kdc.conf" ++#define DEFAULT_KDC_PROFILE KDC_DIR "/kdc.conf" + #define KDC_PROFILE_ENV "KRB5_KDC_PROFILE" + + #if TARGET_OS_MAC +@@ -93,8 +94,8 @@ + /* + * Defaults for the KADM5 admin system. + */ +-#define DEFAULT_KADM5_KEYTAB "@LOCALSTATEDIR/krb5kdc/kadm5.keytab" +-#define DEFAULT_KADM5_ACL_FILE "@LOCALSTATEDIR/krb5kdc/kadm5.acl" ++#define DEFAULT_KADM5_KEYTAB KDC_DIR "/kadm5.keytab" ++#define DEFAULT_KADM5_ACL_FILE KDC_DIR "/kadm5.acl" + #define DEFAULT_KADM5_PORT 749 /* assigned by IANA */ + + #define KRB5_DEFAULT_SUPPORTED_ENCTYPES \ +@@ -116,12 +117,12 @@ + * krb5 slave support follows + */ + +-#define KPROP_DEFAULT_FILE "@LOCALSTATEDIR/krb5kdc/slave_datatrans" +-#define KPROPD_DEFAULT_FILE "@LOCALSTATEDIR/krb5kdc/from_master" ++#define KPROP_DEFAULT_FILE KDC_DIR "/slave_datatrans" ++#define KPROPD_DEFAULT_FILE KDC_DIR "/from_master" + #define KPROPD_DEFAULT_KDB5_UTIL "@SBINDIR/kdb5_util" + #define KPROPD_DEFAULT_KPROP "@SBINDIR/kprop" + #define KPROPD_DEFAULT_KRB_DB DEFAULT_KDB_FILE +-#define KPROPD_ACL_FILE "@LOCALSTATEDIR/krb5kdc/kpropd.acl" ++#define KPROPD_ACL_FILE KDC_DIR "/kpropd.acl" + + /* + * GSS mechglue +-- +1.8.2.1 + + +From 4ba748915908a45564d2e8a098cf107e39de3315 Mon Sep 17 00:00:00 2001 +From: Nathaniel McCallum +Date: Tue, 9 Apr 2013 11:17:04 -0400 +Subject: [PATCH 2/4] add k5memdup() + +--- + src/include/k5-int.h | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index 75e6783..7b5ab2c 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -2600,6 +2600,17 @@ k5alloc(size_t len, krb5_error_code *code) + return ptr; + } + ++/* Return a copy of the len bytes of memory at in; set *code to 0 or ENOMEM. */ ++static inline void * ++k5memdup(const void *in, size_t len, krb5_error_code *code) ++{ ++ void *ptr = k5alloc(len, code); ++ ++ if (ptr != NULL) ++ memcpy(ptr, in, len); ++ return ptr; ++} ++ + krb5_error_code KRB5_CALLCONV + krb5_get_credentials_for_user(krb5_context context, krb5_flags options, + krb5_ccache ccache, +-- +1.8.2.1 + + +From f98e3f2569996d84c968852b50f76173203e568f Mon Sep 17 00:00:00 2001 +From: Nathaniel McCallum +Date: Thu, 4 Apr 2013 13:39:21 -0400 +Subject: [PATCH 3/4] add libkrad + +--- + src/configure.in | 2 +- + src/include/Makefile.in | 1 + + src/include/krad.h | 267 ++++++++++++++++++++++ + src/lib/Makefile.in | 2 +- + src/lib/krad/Makefile.in | 74 ++++++ + src/lib/krad/attr.c | 317 ++++++++++++++++++++++++++ + src/lib/krad/attrset.c | 244 ++++++++++++++++++++ + src/lib/krad/client.c | 335 ++++++++++++++++++++++++++++ + src/lib/krad/code.c | 111 +++++++++ + src/lib/krad/deps | 156 +++++++++++++ + src/lib/krad/internal.h | 155 +++++++++++++ + src/lib/krad/libkrad.exports | 23 ++ + src/lib/krad/packet.c | 470 +++++++++++++++++++++++++++++++++++++++ + src/lib/krad/remote.c | 519 +++++++++++++++++++++++++++++++++++++++++++ + src/lib/krad/t_attr.c | 89 ++++++++ + src/lib/krad/t_attrset.c | 98 ++++++++ + src/lib/krad/t_client.c | 126 +++++++++++ + src/lib/krad/t_code.c | 54 +++++ + src/lib/krad/t_daemon.h | 92 ++++++++ + src/lib/krad/t_daemon.py | 76 +++++++ + src/lib/krad/t_packet.c | 194 ++++++++++++++++ + src/lib/krad/t_remote.c | 170 ++++++++++++++ + src/lib/krad/t_test.c | 50 +++++ + src/lib/krad/t_test.h | 60 +++++ + 24 files changed, 3683 insertions(+), 2 deletions(-) + create mode 100644 src/include/krad.h + create mode 100644 src/lib/krad/Makefile.in + create mode 100644 src/lib/krad/attr.c + create mode 100644 src/lib/krad/attrset.c + create mode 100644 src/lib/krad/client.c + create mode 100644 src/lib/krad/code.c + create mode 100644 src/lib/krad/deps + create mode 100644 src/lib/krad/internal.h + create mode 100644 src/lib/krad/libkrad.exports + create mode 100644 src/lib/krad/packet.c + create mode 100644 src/lib/krad/remote.c + create mode 100644 src/lib/krad/t_attr.c + create mode 100644 src/lib/krad/t_attrset.c + create mode 100644 src/lib/krad/t_client.c + create mode 100644 src/lib/krad/t_code.c + create mode 100644 src/lib/krad/t_daemon.h + create mode 100644 src/lib/krad/t_daemon.py + create mode 100644 src/lib/krad/t_packet.c + create mode 100644 src/lib/krad/t_remote.c + create mode 100644 src/lib/krad/t_test.c + create mode 100644 src/lib/krad/t_test.h + +diff --git a/src/configure.in b/src/configure.in +index faf93a1..d8676e5 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -1318,7 +1318,7 @@ dnl lib/krb5/ccache/ccapi + lib/rpc lib/rpc/unit-test + + lib/kadm5 lib/kadm5/clnt lib/kadm5/srv lib/kadm5/unit-test +- ++ lib/krad + lib/apputils + + dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test +diff --git a/src/include/Makefile.in b/src/include/Makefile.in +index c69b809..869b04b 100644 +--- a/src/include/Makefile.in ++++ b/src/include/Makefile.in +@@ -145,5 +145,6 @@ install-headers-unix install:: krb5/krb5.h profile.h + $(INSTALL_DATA) $(srcdir)/krb5/kadm5_hook_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)kadm5_hook_plugin.h + $(INSTALL_DATA) profile.h $(DESTDIR)$(KRB5_INCDIR)$(S)profile.h + $(INSTALL_DATA) $(srcdir)/gssapi.h $(DESTDIR)$(KRB5_INCDIR)$(S)gssapi.h ++ $(INSTALL_DATA) $(srcdir)/krad.h $(DESTDIR)$(KRB5_INCDIR)/krad.h + + depend:: krb5/krb5.h $(BUILT_HEADERS) +diff --git a/src/include/krad.h b/src/include/krad.h +new file mode 100644 +index 0000000..e6d5766 +--- /dev/null ++++ b/src/include/krad.h +@@ -0,0 +1,267 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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. ++ */ ++ ++/* ++ * This API is not considered as stable as the main krb5 API. ++ * ++ * - We may make arbitrary incompatible changes between feature releases ++ * (e.g. from 1.12 to 1.13). ++ * - We will make some effort to avoid making incompatible changes for ++ * bugfix releases, but will make them if necessary. ++ */ ++ ++#ifndef KRAD_H_ ++#define KRAD_H_ ++ ++#include ++#include ++#include ++#include ++ ++#define KRAD_PACKET_SIZE_MAX 4096 ++ ++#define KRAD_SERVICE_TYPE_LOGIN 1 ++#define KRAD_SERVICE_TYPE_FRAMED 2 ++#define KRAD_SERVICE_TYPE_CALLBACK_LOGIN 3 ++#define KRAD_SERVICE_TYPE_CALLBACK_FRAMED 4 ++#define KRAD_SERVICE_TYPE_OUTBOUND 5 ++#define KRAD_SERVICE_TYPE_ADMINISTRATIVE 6 ++#define KRAD_SERVICE_TYPE_NAS_PROMPT 7 ++#define KRAD_SERVICE_TYPE_AUTHENTICATE_ONLY 8 ++#define KRAD_SERVICE_TYPE_CALLBACK_NAS_PROMPT 9 ++#define KRAD_SERVICE_TYPE_CALL_CHECK 10 ++#define KRAD_SERVICE_TYPE_CALLBACK_ADMINISTRATIVE 11 ++ ++typedef struct krad_attrset_st krad_attrset; ++typedef struct krad_packet_st krad_packet; ++typedef struct krad_client_st krad_client; ++typedef unsigned char krad_code; ++typedef unsigned char krad_attr; ++ ++/* Called when a response is received or the request times out. */ ++typedef void ++(*krad_cb)(krb5_error_code retval, const krad_packet *request, ++ const krad_packet *response, void *data); ++ ++/* ++ * Called to iterate over a set of requests. Either the callback will be ++ * called until it returns NULL, or it will be called with cancel = TRUE to ++ * terminate in the middle of an iteration. ++ */ ++typedef const krad_packet * ++(*krad_packet_iter_cb)(void *data, krb5_boolean cancel); ++ ++/* ++ * Code ++ */ ++ ++/* Convert a code name to its number. Only works for codes defined ++ * by RFC 2875 or 2882. Returns 0 if the name was not found. */ ++krad_code ++krad_code_name2num(const char *name); ++ ++/* Convert a code number to its name. Only works for attributes defined ++ * by RFC 2865 or 2882. Returns NULL if the name was not found. */ ++const char * ++krad_code_num2name(krad_code code); ++ ++/* ++ * Attribute ++ */ ++ ++/* Convert an attribute name to its number. Only works for attributes defined ++ * by RFC 2865. Returns 0 if the name was not found. */ ++krad_attr ++krad_attr_name2num(const char *name); ++ ++/* Convert an attribute number to its name. Only works for attributes defined ++ * by RFC 2865. Returns NULL if the name was not found. */ ++const char * ++krad_attr_num2name(krad_attr type); ++ ++/* ++ * Attribute set ++ */ ++ ++/* Create a new attribute set. */ ++krb5_error_code ++krad_attrset_new(krb5_context ctx, krad_attrset **set); ++ ++/* Create a deep copy of an attribute set. */ ++krb5_error_code ++krad_attrset_copy(const krad_attrset *set, krad_attrset **copy); ++ ++/* Free an attribute set. */ ++void ++krad_attrset_free(krad_attrset *set); ++ ++/* Add an attribute to a set. */ ++krb5_error_code ++krad_attrset_add(krad_attrset *set, krad_attr type, const krb5_data *data); ++ ++/* Add a four-octet unsigned number attribute to the given set. */ ++krb5_error_code ++krad_attrset_add_number(krad_attrset *set, krad_attr type, krb5_ui_4 num); ++ ++/* Delete the specified attribute. */ ++void ++krad_attrset_del(krad_attrset *set, krad_attr type, size_t indx); ++ ++/* Get the specified attribute. */ ++const krb5_data * ++krad_attrset_get(const krad_attrset *set, krad_attr type, size_t indx); ++ ++/* ++ * Packet ++ */ ++ ++/* Determine the bytes needed from the socket to get the whole packet. Don't ++ * cache the return value as it can change! Returns -1 on EBADMSG. */ ++ssize_t ++krad_packet_bytes_needed(const krb5_data *buffer); ++ ++/* Free a packet. */ ++void ++krad_packet_free(krad_packet *pkt); ++ ++/* ++ * Create a new request packet. ++ * ++ * This function takes the attributes specified in set and converts them into a ++ * radius packet. The packet will have a randomized id. If cb is not NULL, it ++ * will be called passing data as the argument to iterate over a set of ++ * outstanding requests. In this case, the id will be both random and unique ++ * across the set of requests. ++ */ ++krb5_error_code ++krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, ++ const krad_attrset *set, krad_packet_iter_cb cb, ++ void *data, krad_packet **request); ++ ++/* ++ * Create a new response packet. ++ * ++ * This function is similar to krad_packet_new_requst() except that it crafts a ++ * packet in response to a request packet. This new packet will borrow values ++ * from the request such as the id and the authenticator. ++ */ ++krb5_error_code ++krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code, ++ const krad_attrset *set, const krad_packet *request, ++ krad_packet **response); ++ ++/* ++ * Decode a request radius packet from krb5_data. ++ * ++ * The resulting decoded packet will be a request packet stored in *reqpkt. ++ * ++ * If cb is NULL, *duppkt will always be NULL. ++ * ++ * If cb is not NULL, it will be called (with the data argument) to iterate ++ * over a set of requests currently being processed. In this case, if the ++ * packet is a duplicate of an already received request, the original request ++ * will be set in *duppkt. ++ */ ++krb5_error_code ++krad_packet_decode_request(krb5_context ctx, const char *secret, ++ const krb5_data *buffer, krad_packet_iter_cb cb, ++ void *data, const krad_packet **duppkt, ++ krad_packet **reqpkt); ++ ++/* ++ * Decode a response radius packet from krb5_data. ++ * ++ * The resulting decoded packet will be a response packet stored in *rsppkt. ++ * ++ * If cb is NULL, *reqpkt will always be NULL. ++ * ++ * If cb is not NULL, it will be called (with the data argument) to iterate ++ * over a set of requests awaiting responses. In this case, if the response ++ * packet matches one of these requests, the original request will be set in ++ * *reqpkt. ++ */ ++krb5_error_code ++krad_packet_decode_response(krb5_context ctx, const char *secret, ++ const krb5_data *buffer, krad_packet_iter_cb cb, ++ void *data, const krad_packet **reqpkt, ++ krad_packet **rsppkt); ++ ++/* Encode packet. */ ++const krb5_data * ++krad_packet_encode(const krad_packet *pkt); ++ ++/* Get the code for the given packet. */ ++krad_code ++krad_packet_get_code(const krad_packet *pkt); ++ ++/* Get the specified attribute. */ ++const krb5_data * ++krad_packet_get_attr(const krad_packet *pkt, krad_attr type, size_t indx); ++ ++/* ++ * Client ++ */ ++ ++/* Create a new client. */ ++krb5_error_code ++krad_client_new(krb5_context kctx, verto_ctx *vctx, krad_client **client); ++ ++/* Free the client. */ ++void ++krad_client_free(krad_client *client); ++ ++/* ++ * Send a request to a radius server. ++ * ++ * The remote host may be specified by one of the following formats: ++ * - /path/to/unix.socket ++ * - IPv4 ++ * - IPv4:port ++ * - IPv4:service ++ * - [IPv6] ++ * - [IPv6]:port ++ * - [IPv6]:service ++ * - hostname ++ * - hostname:port ++ * - hostname:service ++ * ++ * The timeout parameter (milliseconds) is the total timeout across all remote ++ * hosts (when DNS returns multiple entries) and all retries. ++ * ++ * The cb function will be called with the data argument when either a response ++ * is received or the request times out on all possible remote hosts. ++ * ++ * If the remote host is a unix domain socket, retries is ignored due to ++ * guaranteed delivery. ++ */ ++krb5_error_code ++krad_client_send(krad_client *rc, krad_code code, const krad_attrset *attrs, ++ const char *remote, const char *secret, int timeout, ++ size_t retries, krad_cb cb, void *data); ++ ++#endif /* KRAD_H_ */ +diff --git a/src/lib/Makefile.in b/src/lib/Makefile.in +index 485db40..4dde514 100644 +--- a/src/lib/Makefile.in ++++ b/src/lib/Makefile.in +@@ -1,5 +1,5 @@ + mydir=lib +-SUBDIRS=crypto krb5 gssapi rpc kdb kadm5 apputils ++SUBDIRS=crypto krb5 gssapi rpc kdb kadm5 apputils krad + WINSUBDIRS=crypto krb5 gssapi + BUILDTOP=$(REL).. + +diff --git a/src/lib/krad/Makefile.in b/src/lib/krad/Makefile.in +new file mode 100644 +index 0000000..75431a0 +--- /dev/null ++++ b/src/lib/krad/Makefile.in +@@ -0,0 +1,74 @@ ++mydir=lib$(S)krad ++BUILDTOP=$(REL)..$(S).. ++RELDIR=krad ++ ++RUN_SETUP=@KRB5_RUN_ENV@ ++PROG_LIBPATH=-L$(TOPLIBD) ++PROG_RPATH=$(KRB5_LIBDIR) ++ ++SHLIB_EXPLIBS=$(KRB5_BASE_LIBS) $(VERTO_LIBS) ++SHLIB_EXPDEPLIBS=$(KRB5_BASE_DEPLIBS) $(VERTO_DEPLIB) ++SHLIB_DIRS=-L$(TOPLIBD) ++SHLIB_RDIRS=$(KRB5_LIBDIR) ++ ++LIBBASE=krad ++LIBMAJOR=0 ++LIBMINOR=0 ++ ++STLIBOBJS=attr.o attrset.o client.o code.o packet.o remote.o ++LIBOBJS=$(OUTPRE)attr.$(OBJEXT) \ ++ $(OUTPRE)attrset.$(OBJEXT) \ ++ $(OUTPRE)client.$(OBJEXT) \ ++ $(OUTPRE)code.$(OBJEXT) \ ++ $(OUTPRE)packet.$(OBJEXT) \ ++ $(OUTPRE)remote.$(OBJEXT) ++SRCS=attr.c attrset.c client.c code.c packet.c remote.c \ ++ t_attr.c t_attrset.c t_client.c t_code.c t_packet.c t_remote.c t_test.c ++ ++STOBJLISTS=OBJS.ST ++ ++all-unix:: all-liblinks ++install-unix:: install-libs ++ ++clean-unix:: clean-liblinks clean-libs clean-libobjs ++ ++check-unix:: t_attr t_attrset t_code t_packet t_remote t_client ++ $(RUN_SETUP) $(VALGRIND) ./t_attr ++ $(RUN_SETUP) $(VALGRIND) ./t_attrset ++ $(RUN_SETUP) $(VALGRIND) ./t_code ++ $(RUN_SETUP) $(VALGRIND) ./t_packet $(PYTHON) $(srcdir)/t_daemon.py ++ $(RUN_SETUP) $(VALGRIND) ./t_remote $(PYTHON) $(srcdir)/t_daemon.py ++ $(RUN_SETUP) $(VALGRIND) ./t_client $(PYTHON) $(srcdir)/t_daemon.py ++ ++TESTDEPS=t_test.o $(KRB5_BASE_DEPLIBS) ++TESTLIBS=t_test.o $(KRB5_BASE_LIBS) ++ ++T_ATTR_OBJS=attr.o t_attr.o ++t_attr: $(T_ATTR_OBJS) $(TESTDEPS) ++ $(CC_LINK) -o $@ $(T_ATTR_OBJS) $(TESTLIBS) ++ ++T_ATTRSET_OBJS=attr.o attrset.o t_attrset.o ++t_attrset: $(T_ATTRSET_OBJS) $(TESTDEPS) ++ $(CC_LINK) -o $@ $(T_ATTRSET_OBJS) $(TESTLIBS) ++ ++T_CODE_OBJS=code.o t_code.o ++t_code: $(T_CODE_OBJS) $(TESTDEPS) ++ $(CC_LINK) -o $@ $(T_CODE_OBJS) $(TESTLIBS) ++ ++T_PACKET_OBJS=attr.o attrset.o code.o packet.o t_packet.o ++t_packet: $(T_PACKET_OBJS) $(TESTDEPS) ++ $(CC_LINK) -o $@ $(T_PACKET_OBJS) $(TESTLIBS) ++ ++T_REMOTE_OBJS=attr.o attrset.o code.o packet.o remote.o t_remote.o ++t_remote: $(T_REMOTE_OBJS) $(TESTDEPS) $(VERTO_DEPLIB) ++ $(CC_LINK) -o $@ $(T_REMOTE_OBJS) $(TESTLIBS) $(VERTO_LIBS) ++ ++T_CLIENT_OBJS=attr.o attrset.o code.o packet.o remote.o client.o t_client.o ++t_client: $(T_CLIENT_OBJS) $(TESTDEPS) $(VERTO_DEPLIB) ++ $(CC_LINK) -o $@ $(T_CLIENT_OBJS) $(TESTLIBS) $(VERTO_LIBS) ++ ++clean-unix:: clean-libobjs ++ $(RM) *.o t_attr t_attrset t_code t_packet t_remote t_client ++ ++@lib_frag@ ++@libobj_frag@ +diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c +new file mode 100644 +index 0000000..9c13d9d +--- /dev/null ++++ b/src/lib/krad/attr.c +@@ -0,0 +1,317 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/attr.c - RADIUS attribute functions for libkrad */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 ++#include "internal.h" ++ ++#include ++ ++/* RFC 2865 */ ++#define BLOCKSIZE 16 ++ ++typedef krb5_error_code ++(*attribute_transform_fn)(krb5_context ctx, const char *secret, ++ const unsigned char *auth, const krb5_data *in, ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); ++ ++typedef struct { ++ const char *name; ++ unsigned char minval; ++ unsigned char maxval; ++ attribute_transform_fn encode; ++ attribute_transform_fn decode; ++} attribute_record; ++ ++static krb5_error_code ++user_password_encode(krb5_context ctx, const char *secret, ++ const unsigned char *auth, const krb5_data *in, ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); ++ ++static krb5_error_code ++user_password_decode(krb5_context ctx, const char *secret, ++ const unsigned char *auth, const krb5_data *in, ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); ++ ++static const attribute_record attributes[UCHAR_MAX] = { ++ {"User-Name", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"User-Password", 1, 128, user_password_encode, user_password_decode}, ++ {"CHAP-Password", 17, 17, NULL, NULL}, ++ {"NAS-IP-Address", 4, 4, NULL, NULL}, ++ {"NAS-Port", 4, 4, NULL, NULL}, ++ {"Service-Type", 4, 4, NULL, NULL}, ++ {"Framed-Protocol", 4, 4, NULL, NULL}, ++ {"Framed-IP-Address", 4, 4, NULL, NULL}, ++ {"Framed-IP-Netmask", 4, 4, NULL, NULL}, ++ {"Framed-Routing", 4, 4, NULL, NULL}, ++ {"Filter-Id", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Framed-MTU", 4, 4, NULL, NULL}, ++ {"Framed-Compression", 4, 4, NULL, NULL}, ++ {"Login-IP-Host", 4, 4, NULL, NULL}, ++ {"Login-Service", 4, 4, NULL, NULL}, ++ {"Login-TCP-Port", 4, 4, NULL, NULL}, ++ {NULL, 0, 0, NULL, NULL}, /* Unassigned */ ++ {"Reply-Message", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Callback-Number", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Callback-Id", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {NULL, 0, 0, NULL, NULL}, /* Unassigned */ ++ {"Framed-Route", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Framed-IPX-Network", 4, 4, NULL, NULL}, ++ {"State", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Class", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Vendor-Specific", 5, MAX_ATTRSIZE, NULL, NULL}, ++ {"Session-Timeout", 4, 4, NULL, NULL}, ++ {"Idle-Timeout", 4, 4, NULL, NULL}, ++ {"Termination-Action", 4, 4, NULL, NULL}, ++ {"Called-Station-Id", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Calling-Station-Id", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"NAS-Identifier", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Proxy-State", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Login-LAT-Service", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Login-LAT-Node", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {"Login-LAT-Group", 32, 32, NULL, NULL}, ++ {"Framed-AppleTalk-Link", 4, 4, NULL, NULL}, ++ {"Framed-AppleTalk-Network", 4, 4, NULL, NULL}, ++ {"Framed-AppleTalk-Zone", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */ ++ {"CHAP-Challenge", 5, MAX_ATTRSIZE, NULL, NULL}, ++ {"NAS-Port-Type", 4, 4, NULL, NULL}, ++ {"Port-Limit", 4, 4, NULL, NULL}, ++ {"Login-LAT-Port", 1, MAX_ATTRSIZE, NULL, NULL}, ++}; ++ ++/* Encode User-Password attribute. */ ++static krb5_error_code ++user_password_encode(krb5_context ctx, const char *secret, ++ const unsigned char *auth, const krb5_data *in, ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen) ++{ ++ const unsigned char *indx; ++ krb5_error_code retval; ++ unsigned int seclen; ++ krb5_checksum sum; ++ size_t blck, len, i; ++ krb5_data tmp; ++ ++ /* Copy the input buffer to the (zero-padded) output buffer. */ ++ len = (in->length + BLOCKSIZE - 1) / BLOCKSIZE * BLOCKSIZE; ++ if (len > MAX_ATTRSIZE) ++ return ENOBUFS; ++ memset(outbuf, 0, len); ++ memcpy(outbuf, in->data, in->length); ++ ++ /* Create our temporary space for processing each block. */ ++ seclen = strlen(secret); ++ retval = alloc_data(&tmp, seclen + BLOCKSIZE); ++ if (retval != 0) ++ return retval; ++ ++ memcpy(tmp.data, secret, seclen); ++ for (blck = 0, indx = auth; blck * BLOCKSIZE < len; blck++) { ++ memcpy(tmp.data + seclen, indx, BLOCKSIZE); ++ ++ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp, ++ &sum); ++ if (retval != 0) { ++ zap(tmp.data, tmp.length); ++ zap(outbuf, len); ++ krb5_free_data_contents(ctx, &tmp); ++ return retval; ++ } ++ ++ for (i = 0; i < BLOCKSIZE; i++) ++ outbuf[blck * BLOCKSIZE + i] ^= sum.contents[i]; ++ krb5_free_checksum_contents(ctx, &sum); ++ ++ indx = &outbuf[blck * BLOCKSIZE]; ++ } ++ ++ zap(tmp.data, tmp.length); ++ krb5_free_data_contents(ctx, &tmp); ++ *outlen = len; ++ return 0; ++} ++ ++/* Decode User-Password attribute. */ ++static krb5_error_code ++user_password_decode(krb5_context ctx, const char *secret, ++ const unsigned char *auth, const krb5_data *in, ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen) ++{ ++ const unsigned char *indx; ++ krb5_error_code retval; ++ unsigned int seclen; ++ krb5_checksum sum; ++ ssize_t blck, i; ++ krb5_data tmp; ++ ++ if (in->length % BLOCKSIZE != 0) ++ return EINVAL; ++ if (in->length > MAX_ATTRSIZE) ++ return ENOBUFS; ++ ++ /* Create our temporary space for processing each block. */ ++ seclen = strlen(secret); ++ retval = alloc_data(&tmp, seclen + BLOCKSIZE); ++ if (retval != 0) ++ return retval; ++ ++ memcpy(tmp.data, secret, seclen); ++ for (blck = 0, indx = auth; blck * BLOCKSIZE < in->length; blck++) { ++ memcpy(tmp.data + seclen, indx, BLOCKSIZE); ++ ++ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, ++ &tmp, &sum); ++ if (retval != 0) { ++ zap(tmp.data, tmp.length); ++ zap(outbuf, in->length); ++ krb5_free_data_contents(ctx, &tmp); ++ return retval; ++ } ++ ++ for (i = 0; i < BLOCKSIZE; i++) { ++ outbuf[blck * BLOCKSIZE + i] = in->data[blck * BLOCKSIZE + i] ^ ++ sum.contents[i]; ++ } ++ krb5_free_checksum_contents(ctx, &sum); ++ ++ indx = (const unsigned char *)&in->data[blck * BLOCKSIZE]; ++ } ++ ++ /* Strip off trailing NULL bytes. */ ++ *outlen = in->length; ++ while (*outlen > 0 && outbuf[*outlen - 1] == '\0') ++ (*outlen)--; ++ ++ krb5_free_data_contents(ctx, &tmp); ++ return 0; ++} ++ ++krb5_error_code ++kr_attr_valid(krad_attr type, const krb5_data *data) ++{ ++ const attribute_record *ar; ++ ++ if (type == 0) ++ return EINVAL; ++ ++ ar = &attributes[type - 1]; ++ return (data->length >= ar->minval && data->length <= ar->maxval) ? 0 : ++ EMSGSIZE; ++} ++ ++krb5_error_code ++kr_attr_encode(krb5_context ctx, const char *secret, ++ const unsigned char *auth, krad_attr type, ++ const krb5_data *in, unsigned char outbuf[MAX_ATTRSIZE], ++ size_t *outlen) ++{ ++ krb5_error_code retval; ++ ++ retval = kr_attr_valid(type, in); ++ if (retval != 0) ++ return retval; ++ ++ if (attributes[type - 1].encode == NULL) { ++ if (in->length > MAX_ATTRSIZE) ++ return ENOBUFS; ++ ++ *outlen = in->length; ++ memcpy(outbuf, in->data, in->length); ++ return 0; ++ } ++ ++ return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen); ++} ++ ++krb5_error_code ++kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth, ++ krad_attr type, const krb5_data *in, ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen) ++{ ++ krb5_error_code retval; ++ ++ retval = kr_attr_valid(type, in); ++ if (retval != 0) ++ return retval; ++ ++ if (attributes[type - 1].encode == NULL) { ++ if (in->length > MAX_ATTRSIZE) ++ return ENOBUFS; ++ ++ *outlen = in->length; ++ memcpy(outbuf, in->data, in->length); ++ return 0; ++ } ++ ++ return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen); ++} ++ ++krad_attr ++krad_attr_name2num(const char *name) ++{ ++ unsigned char i; ++ ++ for (i = 0; i < UCHAR_MAX; i++) { ++ if (attributes[i].name == NULL) ++ continue; ++ ++ if (strcmp(attributes[i].name, name) == 0) ++ return i + 1; ++ } ++ ++ return 0; ++} ++ ++const char * ++krad_attr_num2name(krad_attr type) ++{ ++ if (type == 0) ++ return NULL; ++ ++ return attributes[type - 1].name; ++} +diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c +new file mode 100644 +index 0000000..fbd0621 +--- /dev/null ++++ b/src/lib/krad/attrset.c +@@ -0,0 +1,244 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/attrset.c - RADIUS attribute set functions for libkrad */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 ++#include ++#include "internal.h" ++ ++#include ++ ++TAILQ_HEAD(attr_head, attr_st); ++ ++typedef struct attr_st attr; ++struct attr_st { ++ TAILQ_ENTRY(attr_st) list; ++ krad_attr type; ++ krb5_data attr; ++ char buffer[MAX_ATTRSIZE]; ++}; ++ ++struct krad_attrset_st { ++ krb5_context ctx; ++ struct attr_head list; ++}; ++ ++krb5_error_code ++krad_attrset_new(krb5_context ctx, krad_attrset **set) ++{ ++ krad_attrset *tmp; ++ ++ tmp = calloc(1, sizeof(krad_attrset)); ++ if (tmp == NULL) ++ return ENOMEM; ++ tmp->ctx = ctx; ++ TAILQ_INIT(&tmp->list); ++ ++ *set = tmp; ++ return 0; ++} ++ ++void ++krad_attrset_free(krad_attrset *set) ++{ ++ attr *a; ++ ++ if (set == NULL) ++ return; ++ ++ while (!TAILQ_EMPTY(&set->list)) { ++ a = TAILQ_FIRST(&set->list); ++ TAILQ_REMOVE(&set->list, a, list); ++ zap(a->buffer, sizeof(a->buffer)); ++ free(a); ++ } ++ ++ free(set); ++} ++ ++krb5_error_code ++krad_attrset_add(krad_attrset *set, krad_attr type, const krb5_data *data) ++{ ++ krb5_error_code retval; ++ attr *tmp; ++ ++ retval = kr_attr_valid(type, data); ++ if (retval != 0) ++ return retval; ++ ++ tmp = calloc(1, sizeof(attr)); ++ if (tmp == NULL) ++ return ENOMEM; ++ ++ tmp->type = type; ++ tmp->attr = make_data(tmp->buffer, data->length); ++ memcpy(tmp->attr.data, data->data, data->length); ++ ++ TAILQ_INSERT_TAIL(&set->list, tmp, list); ++ return 0; ++} ++ ++krb5_error_code ++krad_attrset_add_number(krad_attrset *set, krad_attr type, krb5_ui_4 num) ++{ ++ krb5_data data; ++ ++ num = htonl(num); ++ data = make_data(&num, sizeof(num)); ++ return krad_attrset_add(set, type, &data); ++} ++ ++void ++krad_attrset_del(krad_attrset *set, krad_attr type, size_t indx) ++{ ++ attr *a; ++ ++ TAILQ_FOREACH(a, &set->list, list) { ++ if (a->type == type && indx-- == 0) { ++ TAILQ_REMOVE(&set->list, a, list); ++ zap(a->buffer, sizeof(a->buffer)); ++ free(a); ++ return; ++ } ++ } ++} ++ ++const krb5_data * ++krad_attrset_get(const krad_attrset *set, krad_attr type, size_t indx) ++{ ++ attr *a; ++ ++ TAILQ_FOREACH(a, &set->list, list) { ++ if (a->type == type && indx-- == 0) ++ return &a->attr; ++ } ++ ++ return NULL; ++} ++ ++krb5_error_code ++krad_attrset_copy(const krad_attrset *set, krad_attrset **copy) ++{ ++ krb5_error_code retval; ++ krad_attrset *tmp; ++ attr *a; ++ ++ retval = krad_attrset_new(set->ctx, &tmp); ++ if (retval != 0) ++ return retval; ++ ++ TAILQ_FOREACH(a, &set->list, list) { ++ retval = krad_attrset_add(tmp, a->type, &a->attr); ++ if (retval != 0) { ++ krad_attrset_free(tmp); ++ return retval; ++ } ++ } ++ ++ *copy = tmp; ++ return 0; ++} ++ ++krb5_error_code ++kr_attrset_encode(const krad_attrset *set, const char *secret, ++ const unsigned char *auth, ++ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen) ++{ ++ unsigned char buffer[MAX_ATTRSIZE]; ++ krb5_error_code retval; ++ size_t i = 0, attrlen; ++ attr *a; ++ ++ if (set == NULL) { ++ *outlen = 0; ++ return 0; ++ } ++ ++ TAILQ_FOREACH(a, &set->list, list) { ++ retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr, ++ buffer, &attrlen); ++ if (retval != 0) ++ return retval; ++ ++ if (i + attrlen + 2 > MAX_ATTRSETSIZE) ++ return EMSGSIZE; ++ ++ outbuf[i++] = a->type; ++ outbuf[i++] = attrlen + 2; ++ memcpy(&outbuf[i], buffer, attrlen); ++ i += attrlen; ++ } ++ ++ *outlen = i; ++ return 0; ++} ++ ++krb5_error_code ++kr_attrset_decode(krb5_context ctx, const krb5_data *in, const char *secret, ++ const unsigned char *auth, krad_attrset **set_out) ++{ ++ unsigned char buffer[MAX_ATTRSIZE]; ++ krb5_data tmp; ++ krb5_error_code retval; ++ krad_attr type; ++ krad_attrset *set; ++ size_t i, len; ++ ++ *set_out = NULL; ++ ++ retval = krad_attrset_new(ctx, &set); ++ if (retval != 0) ++ return retval; ++ ++ for (i = 0; i + 2 < in->length; ) { ++ type = in->data[i++]; ++ tmp = make_data(&in->data[i + 1], in->data[i] - 2); ++ i += tmp.length + 1; ++ ++ retval = (in->length < i) ? EBADMSG : 0; ++ if (retval != 0) ++ goto cleanup; ++ ++ retval = kr_attr_decode(ctx, secret, auth, type, &tmp, buffer, &len); ++ if (retval != 0) ++ goto cleanup; ++ ++ tmp = make_data(buffer, len); ++ retval = krad_attrset_add(set, type, &tmp); ++ if (retval != 0) ++ goto cleanup; ++ } ++ ++ *set_out = set; ++ set = NULL; ++ ++cleanup: ++ zap(buffer, sizeof(buffer)); ++ krad_attrset_free(set); ++ return retval; ++} +diff --git a/src/lib/krad/client.c b/src/lib/krad/client.c +new file mode 100644 +index 0000000..0c37680 +--- /dev/null ++++ b/src/lib/krad/client.c +@@ -0,0 +1,335 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/client.c - Client request code for libkrad */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 ++#include "internal.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++LIST_HEAD(server_head, server_st); ++ ++typedef struct remote_state_st remote_state; ++typedef struct request_st request; ++typedef struct server_st server; ++ ++struct remote_state_st { ++ const krad_packet *packet; ++ krad_remote *remote; ++}; ++ ++struct request_st { ++ krad_client *rc; ++ ++ krad_code code; ++ krad_attrset *attrs; ++ int timeout; ++ size_t retries; ++ krad_cb cb; ++ void *data; ++ ++ remote_state *remotes; ++ ssize_t current; ++ ssize_t count; ++}; ++ ++struct server_st { ++ krad_remote *serv; ++ time_t last; ++ LIST_ENTRY(server_st) list; ++}; ++ ++struct krad_client_st { ++ krb5_context kctx; ++ verto_ctx *vctx; ++ struct server_head servers; ++}; ++ ++/* Return either a pre-existing server that matches the address info and the ++ * secret, or create a new one. */ ++static krb5_error_code ++get_server(krad_client *rc, const struct addrinfo *ai, const char *secret, ++ krad_remote **out) ++{ ++ krb5_error_code retval; ++ time_t currtime; ++ server *srv; ++ ++ if (time(&currtime) == (time_t)-1) ++ return errno; ++ ++ LIST_FOREACH(srv, &rc->servers, list) { ++ if (kr_remote_equals(srv->serv, ai, secret)) { ++ srv->last = currtime; ++ *out = srv->serv; ++ return 0; ++ } ++ } ++ ++ srv = calloc(1, sizeof(server)); ++ if (srv == NULL) ++ return ENOMEM; ++ srv->last = currtime; ++ ++ retval = kr_remote_new(rc->kctx, rc->vctx, ai, secret, &srv->serv); ++ if (retval != 0) { ++ free(srv); ++ return retval; ++ } ++ ++ LIST_INSERT_HEAD(&rc->servers, srv, list); ++ *out = srv->serv; ++ return 0; ++} ++ ++/* Free a request. */ ++static void ++request_free(request *req) ++{ ++ krad_attrset_free(req->attrs); ++ free(req->remotes); ++ free(req); ++} ++ ++/* Create a request. */ ++static krb5_error_code ++request_new(krad_client *rc, krad_code code, const krad_attrset *attrs, ++ const struct addrinfo *ai, const char *secret, int timeout, ++ size_t retries, krad_cb cb, void *data, request **req) ++{ ++ const struct addrinfo *tmp; ++ krb5_error_code retval; ++ request *rqst; ++ size_t i; ++ ++ if (ai == NULL) ++ return EINVAL; ++ ++ rqst = calloc(1, sizeof(request)); ++ if (rqst == NULL) ++ return ENOMEM; ++ ++ for (tmp = ai; tmp != NULL; tmp = tmp->ai_next) ++ rqst->count++; ++ ++ rqst->rc = rc; ++ rqst->code = code; ++ rqst->cb = cb; ++ rqst->data = data; ++ rqst->timeout = timeout / rqst->count; ++ rqst->retries = retries; ++ ++ retval = krad_attrset_copy(attrs, &rqst->attrs); ++ if (retval != 0) { ++ request_free(rqst); ++ return retval; ++ } ++ ++ rqst->remotes = calloc(rqst->count + 1, sizeof(remote_state)); ++ if (rqst->remotes == NULL) { ++ request_free(rqst); ++ return ENOMEM; ++ } ++ ++ i = 0; ++ for (tmp = ai; tmp != NULL; tmp = tmp->ai_next) { ++ retval = get_server(rc, tmp, secret, &rqst->remotes[i++].remote); ++ if (retval != 0) { ++ request_free(rqst); ++ return retval; ++ } ++ } ++ ++ *req = rqst; ++ return 0; ++} ++ ++/* Close remotes that haven't been used in a while. */ ++static void ++age(struct server_head *head, time_t currtime) ++{ ++ server *srv, *tmp; ++ ++ LIST_FOREACH_SAFE(srv, head, list, tmp) { ++ if (currtime == (time_t)-1 || currtime - srv->last > 60 * 60) { ++ LIST_REMOVE(srv, list); ++ kr_remote_free(srv->serv); ++ free(srv); ++ } ++ } ++} ++ ++/* Handle a response from a server (or related errors). */ ++static void ++on_response(krb5_error_code retval, const krad_packet *reqp, ++ const krad_packet *rspp, void *data) ++{ ++ request *req = data; ++ time_t currtime; ++ size_t i; ++ ++ /* Do nothing if we are already completed. */ ++ if (req->count < 0) ++ return; ++ ++ /* If we have timed out and have more remotes to try, do so. */ ++ if (retval == ETIMEDOUT && req->remotes[++req->current].remote != NULL) { ++ retval = kr_remote_send(req->remotes[req->current].remote, req->code, ++ req->attrs, on_response, req, req->timeout, ++ req->retries, ++ &req->remotes[req->current].packet); ++ if (retval == 0) ++ return; ++ } ++ ++ /* Mark the request as complete. */ ++ req->count = -1; ++ ++ /* Inform the callback. */ ++ req->cb(retval, reqp, rspp, req->data); ++ ++ /* Cancel the outstanding packets. */ ++ for (i = 0; req->remotes[i].remote != NULL; i++) ++ kr_remote_cancel(req->remotes[i].remote, req->remotes[i].packet); ++ ++ /* Age out servers that haven't been used in a while. */ ++ if (time(&currtime) != (time_t)-1) ++ age(&req->rc->servers, currtime); ++ ++ request_free(req); ++} ++ ++krb5_error_code ++krad_client_new(krb5_context kctx, verto_ctx *vctx, krad_client **out) ++{ ++ krad_client *tmp; ++ ++ tmp = calloc(1, sizeof(krad_client)); ++ if (tmp == NULL) ++ return ENOMEM; ++ ++ tmp->kctx = kctx; ++ tmp->vctx = vctx; ++ ++ *out = tmp; ++ return 0; ++} ++ ++void ++krad_client_free(krad_client *rc) ++{ ++ if (rc == NULL) ++ return; ++ ++ age(&rc->servers, -1); ++ free(rc); ++} ++ ++static krb5_error_code ++resolve_remote(const char *remote, struct addrinfo **ai) ++{ ++ const char *svc = "radius"; ++ krb5_error_code retval; ++ struct addrinfo hints; ++ char *sep, *srv; ++ ++ /* Isolate the port number if it exists. */ ++ srv = strdup(remote); ++ if (srv == NULL) ++ return ENOMEM; ++ ++ if (srv[0] == '[') { ++ /* IPv6 */ ++ sep = strrchr(srv, ']'); ++ if (sep != NULL && sep[1] == ':') { ++ sep[1] = '\0'; ++ svc = &sep[2]; ++ } ++ } else { ++ /* IPv4 or DNS */ ++ sep = strrchr(srv, ':'); ++ if (sep != NULL && sep[1] != '\0') { ++ sep[0] = '\0'; ++ svc = &sep[1]; ++ } ++ } ++ ++ /* Perform the lookup. */ ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_socktype = SOCK_DGRAM; ++ retval = gai_error_code(getaddrinfo(srv, svc, &hints, ai)); ++ free(srv); ++ return retval; ++} ++ ++krb5_error_code ++krad_client_send(krad_client *rc, krad_code code, const krad_attrset *attrs, ++ const char *remote, const char *secret, int timeout, ++ size_t retries, krad_cb cb, void *data) ++{ ++ struct addrinfo usock, *ai = NULL; ++ krb5_error_code retval; ++ struct sockaddr_un ua; ++ request *req; ++ ++ if (remote[0] == '/') { ++ ua.sun_family = AF_UNIX; ++ snprintf(ua.sun_path, sizeof(ua.sun_path), "%s", remote); ++ memset(&usock, 0, sizeof(usock)); ++ usock.ai_family = AF_UNIX; ++ usock.ai_socktype = SOCK_STREAM; ++ usock.ai_addr = (struct sockaddr *)&ua; ++ usock.ai_addrlen = sizeof(ua); ++ ++ retval = request_new(rc, code, attrs, &usock, secret, timeout, retries, ++ cb, data, &req); ++ } else { ++ retval = resolve_remote(remote, &ai); ++ if (retval == 0) { ++ retval = request_new(rc, code, attrs, ai, secret, timeout, retries, ++ cb, data, &req); ++ freeaddrinfo(ai); ++ } ++ } ++ if (retval != 0) ++ return retval; ++ ++ retval = kr_remote_send(req->remotes[req->current].remote, req->code, ++ req->attrs, on_response, req, req->timeout, ++ req->retries, &req->remotes[req->current].packet); ++ if (retval != 0) { ++ request_free(req); ++ return retval; ++ } ++ ++ return 0; ++} +diff --git a/src/lib/krad/code.c b/src/lib/krad/code.c +new file mode 100644 +index 0000000..16871bb +--- /dev/null ++++ b/src/lib/krad/code.c +@@ -0,0 +1,111 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/code.c - RADIUS code name table for libkrad */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "internal.h" ++ ++#include ++ ++static const char *codes[UCHAR_MAX] = { ++ "Access-Request", ++ "Access-Accept", ++ "Access-Reject", ++ "Accounting-Request", ++ "Accounting-Response", ++ "Accounting-Status", ++ "Password-Request", ++ "Password-Ack", ++ "Password-Reject", ++ "Accounting-Message", ++ "Access-Challenge", ++ "Status-Server", ++ "Status-Client", ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ "Resource-Free-Request", ++ "Resource-Free-Response", ++ "Resource-Query-Request", ++ "Resource-Query-Response", ++ "Alternate-Resource-Reclaim-Request", ++ "NAS-Reboot-Request", ++ "NAS-Reboot-Response", ++ NULL, ++ "Next-Passcode", ++ "New-Pin", ++ "Terminate-Session", ++ "Password-Expired", ++ "Event-Request", ++ "Event-Response", ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ "Disconnect-Request", ++ "Disconnect-Ack", ++ "Disconnect-Nak", ++ "Change-Filters-Request", ++ "Change-Filters-Ack", ++ "Change-Filters-Nak", ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ "IP-Address-Allocate", ++ "IP-Address-Release", ++}; ++ ++krad_code ++krad_code_name2num(const char *name) ++{ ++ unsigned char i; ++ ++ for (i = 0; i < UCHAR_MAX; i++) { ++ if (codes[i] == NULL) ++ continue; ++ ++ if (strcmp(codes[i], name) == 0) ++ return ++i; ++ } ++ ++ return 0; ++} ++ ++const char * ++krad_code_num2name(krad_code code) ++{ ++ if (code == 0) ++ return NULL; ++ ++ return codes[code - 1]; ++} +diff --git a/src/lib/krad/deps b/src/lib/krad/deps +new file mode 100644 +index 0000000..8171f94 +--- /dev/null ++++ b/src/lib/krad/deps +@@ -0,0 +1,156 @@ ++# ++# Generated makefile dependencies follow. ++# ++attr.so attr.po $(OUTPRE)attr.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(VERTO_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/krad.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 attr.c internal.h ++attrset.so attrset.po $(OUTPRE)attrset.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(VERTO_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-queue.h \ ++ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ ++ $(top_srcdir)/include/krad.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 \ ++ attrset.c internal.h ++client.so client.po $(OUTPRE)client.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(VERTO_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-queue.h \ ++ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ ++ $(top_srcdir)/include/krad.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 \ ++ client.c internal.h ++code.so code.po $(OUTPRE)code.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(VERTO_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/krad.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 code.c internal.h ++packet.so packet.po $(OUTPRE)packet.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(VERTO_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/krad.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 internal.h packet.c ++remote.so remote.po $(OUTPRE)remote.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(VERTO_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-queue.h \ ++ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ ++ $(top_srcdir)/include/krad.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 \ ++ internal.h remote.c ++t_attr.so t_attr.po $(OUTPRE)t_attr.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(VERTO_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/krad.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 internal.h t_attr.c \ ++ t_test.h ++t_attrset.so t_attrset.po $(OUTPRE)t_attrset.$(OBJEXT): \ ++ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ ++ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ ++ $(COM_ERR_DEPS) $(VERTO_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/krad.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 \ ++ internal.h t_attrset.c t_test.h ++t_client.so t_client.po $(OUTPRE)t_client.$(OBJEXT): \ ++ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ ++ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ ++ $(COM_ERR_DEPS) $(VERTO_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/krad.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 \ ++ internal.h t_client.c t_daemon.h t_test.h ++t_code.so t_code.po $(OUTPRE)t_code.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(VERTO_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/krad.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 internal.h t_code.c \ ++ t_test.h ++t_packet.so t_packet.po $(OUTPRE)t_packet.$(OBJEXT): \ ++ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ ++ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ ++ $(COM_ERR_DEPS) $(VERTO_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/krad.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 \ ++ internal.h t_daemon.h t_packet.c t_test.h ++t_remote.so t_remote.po $(OUTPRE)t_remote.$(OBJEXT): \ ++ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ ++ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ ++ $(COM_ERR_DEPS) $(VERTO_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/krad.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 \ ++ internal.h t_daemon.h t_remote.c t_test.h ++t_test.so t_test.po $(OUTPRE)t_test.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(VERTO_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/krad.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 internal.h t_test.c \ ++ t_test.h +diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h +new file mode 100644 +index 0000000..996a893 +--- /dev/null ++++ b/src/lib/krad/internal.h +@@ -0,0 +1,155 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/internal.h - Internal declarations for libkrad */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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. ++ */ ++ ++#ifndef INTERNAL_H_ ++#define INTERNAL_H_ ++ ++#include ++#include "krad.h" ++ ++#include ++ ++#include ++#include ++#include ++ ++#ifndef UCHAR_MAX ++#define UCHAR_MAX 255 ++#endif ++ ++/* RFC 2865 */ ++#define MAX_ATTRSIZE (UCHAR_MAX - 2) ++#define MAX_ATTRSETSIZE (KRAD_PACKET_SIZE_MAX - 20) ++ ++typedef struct krad_remote_st krad_remote; ++ ++/* Validate constraints of an attribute. */ ++krb5_error_code ++kr_attr_valid(krad_attr type, const krb5_data *data); ++ ++/* Encode an attribute. */ ++krb5_error_code ++kr_attr_encode(krb5_context ctx, const char *secret, const unsigned char *auth, ++ krad_attr type, const krb5_data *in, ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); ++ ++/* Decode an attribute. */ ++krb5_error_code ++kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth, ++ krad_attr type, const krb5_data *in, ++ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); ++ ++/* Encode the attributes into the buffer. */ ++krb5_error_code ++kr_attrset_encode(const krad_attrset *set, const char *secret, ++ const unsigned char *auth, ++ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen); ++ ++/* Decode attributes from a buffer. */ ++krb5_error_code ++kr_attrset_decode(krb5_context ctx, const krb5_data *in, const char *secret, ++ const unsigned char *auth, krad_attrset **set); ++ ++/* Create a new remote object which manages a socket and the state of ++ * outstanding requests. */ ++krb5_error_code ++kr_remote_new(krb5_context kctx, verto_ctx *vctx, const struct addrinfo *info, ++ const char *secret, krad_remote **rr); ++ ++/* Free a remote object. */ ++void ++kr_remote_free(krad_remote *rr); ++ ++/* ++ * Send the packet to the remote. The cb will be called when a response is ++ * received, the request times out, the request is canceled or an error occurs. ++ * ++ * The timeout parameter is the total timeout across all retries in ++ * milliseconds. ++ * ++ * If the cb is called with a retval of ETIMEDOUT it indicates that the alloted ++ * time has elapsed. However, in the case of a timeout, we continue to listen ++ * for the packet until krad_remote_cancel() is called or a response is ++ * received. This means that cb will always be called twice in the event of a ++ * timeout. This permits you to pursue other remotes while still listening for ++ * a response from the first one. ++ */ ++krb5_error_code ++kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs, ++ krad_cb cb, void *data, int timeout, size_t retries, ++ const krad_packet **pkt); ++ ++/* Remove packet from the queue of requests awaiting responses. */ ++void ++kr_remote_cancel(krad_remote *rr, const krad_packet *pkt); ++ ++/* Determine if this remote object refers to the remote resource identified ++ * by the addrinfo struct and the secret. */ ++krb5_boolean ++kr_remote_equals(const krad_remote *rr, const struct addrinfo *info, ++ const char *secret); ++ ++/* Adapted from lib/krb5/os/sendto_kdc.c. */ ++static inline krb5_error_code ++gai_error_code(int err) ++{ ++ switch (err) { ++ case 0: ++ return 0; ++ case EAI_BADFLAGS: ++ case EAI_FAMILY: ++ case EAI_SOCKTYPE: ++ case EAI_SERVICE: ++#ifdef EAI_ADDRFAMILY ++ case EAI_ADDRFAMILY: ++#endif ++ return EINVAL; ++ case EAI_AGAIN: ++ return EAGAIN; ++ case EAI_MEMORY: ++ return ENOMEM; ++#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME ++ case EAI_NODATA: ++#endif ++ case EAI_NONAME: ++ return EADDRNOTAVAIL; ++#ifdef EAI_OVERFLOW ++ case EAI_OVERFLOW: ++ return EOVERFLOW; ++#endif ++#ifdef EAI_SYSTEM ++ case EAI_SYSTEM: ++ return errno; ++#endif ++ default: ++ return EINVAL; ++ } ++} ++ ++#endif /* INTERNAL_H_ */ +diff --git a/src/lib/krad/libkrad.exports b/src/lib/krad/libkrad.exports +new file mode 100644 +index 0000000..fe3f159 +--- /dev/null ++++ b/src/lib/krad/libkrad.exports +@@ -0,0 +1,23 @@ ++krad_code_name2num ++krad_code_num2name ++krad_attr_name2num ++krad_attr_num2name ++krad_attrset_new ++krad_attrset_copy ++krad_attrset_free ++krad_attrset_add ++krad_attrset_add_number ++krad_attrset_del ++krad_attrset_get ++krad_packet_bytes_needed ++krad_packet_free ++krad_packet_new_request ++krad_packet_new_response ++krad_packet_decode_request ++krad_packet_decode_response ++krad_packet_encode ++krad_packet_get_code ++krad_packet_get_attr ++krad_client_new ++krad_client_free ++krad_client_send +diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c +new file mode 100644 +index 0000000..6e6b27e +--- /dev/null ++++ b/src/lib/krad/packet.c +@@ -0,0 +1,470 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/packet.c - Packet functions for libkrad */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "internal.h" ++ ++#include ++ ++#include ++ ++typedef unsigned char uchar; ++ ++/* RFC 2865 */ ++#define OFFSET_CODE 0 ++#define OFFSET_ID 1 ++#define OFFSET_LENGTH 2 ++#define OFFSET_AUTH 4 ++#define OFFSET_ATTR 20 ++#define AUTH_FIELD_SIZE (OFFSET_ATTR - OFFSET_AUTH) ++ ++#define offset(d, o) (&(d)->data[o]) ++#define pkt_code_get(p) (*(krad_code *)offset(&(p)->pkt, OFFSET_CODE)) ++#define pkt_code_set(p, v) (*(krad_code *)offset(&(p)->pkt, OFFSET_CODE)) = v ++#define pkt_id_get(p) (*(uchar *)offset(&(p)->pkt, OFFSET_ID)) ++#define pkt_id_set(p, v) (*(uchar *)offset(&(p)->pkt, OFFSET_ID)) = v ++#define pkt_len_get(p) load_16_be(offset(&(p)->pkt, OFFSET_LENGTH)) ++#define pkt_len_set(p, v) store_16_be(v, offset(&(p)->pkt, OFFSET_LENGTH)) ++#define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH)) ++#define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR)) ++ ++struct krad_packet_st { ++ char buffer[KRAD_PACKET_SIZE_MAX]; ++ krad_attrset *attrset; ++ krb5_data pkt; ++}; ++ ++typedef struct { ++ uchar x[(UCHAR_MAX + 1) / 8]; ++} idmap; ++ ++/* Ensure the map is empty. */ ++static inline void ++idmap_init(idmap *map) ++{ ++ memset(map, 0, sizeof(*map)); ++} ++ ++/* Set an id as already allocated. */ ++static inline void ++idmap_set(idmap *map, uchar id) ++{ ++ map->x[id / 8] |= 1 << (id % 8); ++} ++ ++/* Determine whether or not an id is used. */ ++static inline krb5_boolean ++idmap_isset(const idmap *map, uchar id) ++{ ++ return (map->x[id / 8] & (1 << (id % 8))) != 0; ++} ++ ++/* Find an unused id starting the search at the value specified in id. ++ * NOTE: For optimal security, the initial value of id should be random. */ ++static inline krb5_error_code ++idmap_find(const idmap *map, uchar *id) ++{ ++ krb5_int16 i; ++ ++ for (i = *id; i >= 0 && i <= UCHAR_MAX; *id % 2 == 0 ? i++ : i--) { ++ if (!idmap_isset(map, i)) ++ goto success; ++ } ++ ++ for (i = *id; i >= 0 && i <= UCHAR_MAX; *id % 2 == 1 ? i++ : i--) { ++ if (!idmap_isset(map, i)) ++ goto success; ++ } ++ ++ return ERANGE; ++ ++success: ++ *id = i; ++ return 0; ++} ++ ++/* Generate size bytes of random data into the buffer. */ ++static inline krb5_error_code ++randomize(krb5_context ctx, void *buffer, unsigned int size) ++{ ++ krb5_data rdata = make_data(buffer, size); ++ return krb5_c_random_make_octets(ctx, &rdata); ++} ++ ++/* Generate a radius packet id. */ ++static krb5_error_code ++id_generate(krb5_context ctx, krad_packet_iter_cb cb, void *data, uchar *id) ++{ ++ krb5_error_code retval; ++ const krad_packet *tmp; ++ idmap used; ++ uchar i; ++ ++ retval = randomize(ctx, &i, sizeof(i)); ++ if (retval != 0) { ++ if (cb != NULL) ++ (*cb)(data, TRUE); ++ return retval; ++ } ++ ++ if (cb != NULL) { ++ idmap_init(&used); ++ for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) ++ idmap_set(&used, tmp->pkt.data[1]); ++ ++ retval = idmap_find(&used, &i); ++ if (retval != 0) ++ return retval; ++ } ++ ++ *id = i; ++ return 0; ++} ++ ++/* Generate a random authenticator field. */ ++static krb5_error_code ++auth_generate_random(krb5_context ctx, uchar *rauth) ++{ ++ krb5_ui_4 trunctime; ++ time_t currtime; ++ ++ /* Get the least-significant four bytes of the current time. */ ++ currtime = time(NULL); ++ if (currtime == (time_t)-1) ++ return errno; ++ trunctime = (krb5_ui_4)currtime; ++ memcpy(rauth, &trunctime, sizeof(trunctime)); ++ ++ /* Randomize the rest of the buffer. */ ++ return randomize(ctx, rauth + sizeof(trunctime), ++ AUTH_FIELD_SIZE - sizeof(trunctime)); ++} ++ ++/* Generate a response authenticator field. */ ++static krb5_error_code ++auth_generate_response(krb5_context ctx, const char *secret, ++ const krad_packet *response, const uchar *auth, ++ uchar *rauth) ++{ ++ krb5_error_code retval; ++ krb5_checksum hash; ++ krb5_data data; ++ ++ /* Allocate the temporary buffer. */ ++ retval = alloc_data(&data, response->pkt.length + strlen(secret)); ++ if (retval != 0) ++ return retval; ++ ++ /* Encoded RADIUS packet with the request's ++ * authenticator and the secret at the end. */ ++ memcpy(data.data, response->pkt.data, response->pkt.length); ++ memcpy(data.data + OFFSET_AUTH, auth, AUTH_FIELD_SIZE); ++ memcpy(data.data + response->pkt.length, secret, strlen(secret)); ++ ++ /* Hash it. */ ++ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data, ++ &hash); ++ free(data.data); ++ if (retval != 0) ++ return retval; ++ ++ memcpy(rauth, hash.contents, AUTH_FIELD_SIZE); ++ krb5_free_checksum_contents(ctx, &hash); ++ return 0; ++} ++ ++/* Create a new packet. */ ++static krad_packet * ++packet_new() ++{ ++ krad_packet *pkt; ++ ++ pkt = calloc(1, sizeof(krad_packet)); ++ if (pkt == NULL) ++ return NULL; ++ pkt->pkt = make_data(pkt->buffer, sizeof(pkt->buffer)); ++ ++ return pkt; ++} ++ ++/* Set the attrset object by decoding the packet. */ ++static krb5_error_code ++packet_set_attrset(krb5_context ctx, const char *secret, krad_packet *pkt) ++{ ++ krb5_data tmp; ++ ++ tmp = make_data(pkt_attr(pkt), pkt->pkt.length - OFFSET_ATTR); ++ return kr_attrset_decode(ctx, &tmp, secret, pkt_auth(pkt), &pkt->attrset); ++} ++ ++ssize_t ++krad_packet_bytes_needed(const krb5_data *buffer) ++{ ++ size_t len; ++ ++ if (buffer->length < OFFSET_AUTH) ++ return OFFSET_AUTH - buffer->length; ++ ++ len = load_16_be(offset(buffer, OFFSET_LENGTH)); ++ if (len > KRAD_PACKET_SIZE_MAX) ++ return -1; ++ ++ return buffer->length > len ? 0 : len - buffer->length; ++} ++ ++void ++krad_packet_free(krad_packet *pkt) ++{ ++ if (pkt) ++ krad_attrset_free(pkt->attrset); ++ free(pkt); ++} ++ ++/* Create a new request packet. */ ++krb5_error_code ++krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, ++ const krad_attrset *set, krad_packet_iter_cb cb, ++ void *data, krad_packet **request) ++{ ++ krb5_error_code retval; ++ krad_packet *pkt; ++ uchar id; ++ size_t attrset_len; ++ ++ pkt = packet_new(); ++ if (pkt == NULL) { ++ if (cb != NULL) ++ (*cb)(data, TRUE); ++ return ENOMEM; ++ } ++ ++ /* Generate the ID. */ ++ retval = id_generate(ctx, cb, data, &id); ++ if (retval != 0) ++ goto error; ++ pkt_id_set(pkt, id); ++ ++ /* Generate the authenticator. */ ++ retval = auth_generate_random(ctx, pkt_auth(pkt)); ++ if (retval != 0) ++ goto error; ++ ++ /* Encode the attributes. */ ++ retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt), ++ &attrset_len); ++ if (retval != 0) ++ goto error; ++ ++ /* Set the code, ID and length. */ ++ pkt->pkt.length = attrset_len + OFFSET_ATTR; ++ pkt_code_set(pkt, code); ++ pkt_len_set(pkt, pkt->pkt.length); ++ ++ /* Copy the attrset for future use. */ ++ retval = packet_set_attrset(ctx, secret, pkt); ++ if (retval != 0) ++ goto error; ++ ++ *request = pkt; ++ return 0; ++ ++error: ++ free(pkt); ++ return retval; ++} ++ ++/* Create a new request packet. */ ++krb5_error_code ++krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code, ++ const krad_attrset *set, const krad_packet *request, ++ krad_packet **response) ++{ ++ krb5_error_code retval; ++ krad_packet *pkt; ++ size_t attrset_len; ++ ++ pkt = packet_new(); ++ if (pkt == NULL) ++ return ENOMEM; ++ ++ /* Encode the attributes. */ ++ retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt), ++ &attrset_len); ++ if (retval != 0) ++ goto error; ++ ++ /* Set the code, ID and length. */ ++ pkt->pkt.length = attrset_len + OFFSET_ATTR; ++ pkt_code_set(pkt, code); ++ pkt_id_set(pkt, pkt_id_get(request)); ++ pkt_len_set(pkt, pkt->pkt.length); ++ ++ /* Generate the authenticator. */ ++ retval = auth_generate_response(ctx, secret, pkt, pkt_auth(request), ++ pkt_auth(pkt)); ++ if (retval != 0) ++ goto error; ++ ++ /* Copy the attrset for future use. */ ++ retval = packet_set_attrset(ctx, secret, pkt); ++ if (retval != 0) ++ goto error; ++ ++ *response = pkt; ++ return 0; ++ ++error: ++ free(pkt); ++ return retval; ++} ++ ++/* Decode a packet. */ ++static krb5_error_code ++decode_packet(krb5_context ctx, const char *secret, const krb5_data *buffer, ++ krad_packet **pkt) ++{ ++ krb5_error_code retval; ++ krad_packet *tmp; ++ krb5_ui_2 len; ++ ++ tmp = packet_new(); ++ if (tmp == NULL) { ++ retval = ENOMEM; ++ goto error; ++ } ++ ++ /* Ensure a proper message length. */ ++ retval = buffer->length < OFFSET_ATTR ? EMSGSIZE : 0; ++ if (retval != 0) ++ goto error; ++ len = load_16_be(offset(buffer, OFFSET_LENGTH)); ++ retval = len < OFFSET_ATTR ? EBADMSG : 0; ++ if (retval != 0) ++ goto error; ++ retval = (len > buffer->length || len > tmp->pkt.length) ? EBADMSG : 0; ++ if (retval != 0) ++ goto error; ++ ++ /* Copy over the buffer. */ ++ tmp->pkt.length = len; ++ memcpy(tmp->pkt.data, buffer->data, len); ++ ++ /* Parse the packet to ensure it is well-formed. */ ++ retval = packet_set_attrset(ctx, secret, tmp); ++ if (retval != 0) ++ goto error; ++ ++ *pkt = tmp; ++ return 0; ++ ++error: ++ krad_packet_free(tmp); ++ return retval; ++} ++ ++krb5_error_code ++krad_packet_decode_request(krb5_context ctx, const char *secret, ++ const krb5_data *buffer, krad_packet_iter_cb cb, ++ void *data, const krad_packet **duppkt, ++ krad_packet **reqpkt) ++{ ++ const krad_packet *tmp = NULL; ++ krb5_error_code retval; ++ ++ retval = decode_packet(ctx, secret, buffer, reqpkt); ++ if (cb != NULL && retval == 0) { ++ for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) { ++ if (pkt_id_get(*reqpkt) == pkt_id_get(tmp)) ++ break; ++ } ++ } ++ ++ if (cb != NULL && (retval != 0 || tmp != NULL)) ++ (*cb)(data, TRUE); ++ ++ *duppkt = tmp; ++ return retval; ++} ++ ++krb5_error_code ++krad_packet_decode_response(krb5_context ctx, const char *secret, ++ const krb5_data *buffer, krad_packet_iter_cb cb, ++ void *data, const krad_packet **reqpkt, ++ krad_packet **rsppkt) ++{ ++ uchar auth[AUTH_FIELD_SIZE]; ++ const krad_packet *tmp = NULL; ++ krb5_error_code retval; ++ ++ retval = decode_packet(ctx, secret, buffer, rsppkt); ++ if (cb != NULL && retval == 0) { ++ for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) { ++ if (pkt_id_get(*rsppkt) != pkt_id_get(tmp)) ++ continue; ++ ++ /* Response */ ++ retval = auth_generate_response(ctx, secret, *rsppkt, ++ pkt_auth(tmp), auth); ++ if (retval != 0) { ++ krad_packet_free(*rsppkt); ++ break; ++ } ++ ++ /* If the authenticator matches, then the response is valid. */ ++ if (memcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) == 0) ++ break; ++ } ++ } ++ ++ if (cb != NULL && (retval != 0 || tmp != NULL)) ++ (*cb)(data, TRUE); ++ ++ *reqpkt = tmp; ++ return retval; ++} ++ ++const krb5_data * ++krad_packet_encode(const krad_packet *pkt) ++{ ++ return &pkt->pkt; ++} ++ ++krad_code ++krad_packet_get_code(const krad_packet *pkt) ++{ ++ if (pkt == NULL) ++ return 0; ++ ++ return pkt_code_get(pkt); ++} ++ ++const krb5_data * ++krad_packet_get_attr(const krad_packet *pkt, krad_attr type, size_t indx) ++{ ++ return krad_attrset_get(pkt->attrset, type, indx); ++} +diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c +new file mode 100644 +index 0000000..74d9865 +--- /dev/null ++++ b/src/lib/krad/remote.c +@@ -0,0 +1,519 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/remote.c - Protocol code for libkrad */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 ++#include ++#include "internal.h" ++ ++#include ++#include ++ ++#include ++ ++#define FLAGS_READ (VERTO_EV_FLAG_PERSIST | VERTO_EV_FLAG_IO_CLOSE_FD | \ ++ VERTO_EV_FLAG_IO_ERROR | VERTO_EV_FLAG_IO_READ) ++#define FLAGS_WRITE (FLAGS_READ | VERTO_EV_FLAG_IO_WRITE) ++ ++TAILQ_HEAD(request_head, request_st); ++ ++typedef struct request_st request; ++struct request_st { ++ TAILQ_ENTRY(request_st) list; ++ krad_remote *rr; ++ krad_packet *request; ++ krad_cb cb; ++ void *data; ++ verto_ev *timer; ++ int timeout; ++ size_t retries; ++ size_t sent; ++}; ++ ++struct krad_remote_st { ++ krb5_context kctx; ++ verto_ctx *vctx; ++ verto_ev *io; ++ char *secret; ++ struct addrinfo *info; ++ struct request_head list; ++ char buffer_[KRAD_PACKET_SIZE_MAX]; ++ krb5_data buffer; ++}; ++ ++static void ++on_io(verto_ctx *ctx, verto_ev *ev); ++ ++/* Iterate over the set of outstanding packets. */ ++static const krad_packet * ++iterator(request **out) ++{ ++ request *tmp = *out; ++ ++ if (tmp == NULL) ++ return NULL; ++ ++ *out = TAILQ_NEXT(tmp, list); ++ return tmp->request; ++} ++ ++/* Create a new request. */ ++static krb5_error_code ++request_new(krad_remote *rr, krad_packet *rqst, int timeout, size_t retries, ++ krad_cb cb, void *data, request **out) ++{ ++ request *tmp; ++ ++ tmp = calloc(1, sizeof(request)); ++ if (tmp == NULL) ++ return ENOMEM; ++ ++ tmp->rr = rr; ++ tmp->request = rqst; ++ tmp->cb = cb; ++ tmp->data = data; ++ tmp->timeout = timeout; ++ tmp->retries = retries; ++ ++ *out = tmp; ++ return 0; ++} ++ ++/* Finish a request, calling the callback and freeing it. */ ++static inline void ++request_finish(request *req, krb5_error_code retval, ++ const krad_packet *response) ++{ ++ if (retval != ETIMEDOUT) ++ TAILQ_REMOVE(&req->rr->list, req, list); ++ ++ req->cb(retval, req->request, response, req->data); ++ ++ if (retval != ETIMEDOUT) { ++ krad_packet_free(req->request); ++ verto_del(req->timer); ++ free(req); ++ } ++} ++ ++/* Handle when packets receive no response within their alloted time. */ ++static void ++on_timeout(verto_ctx *ctx, verto_ev *ev) ++{ ++ request *req = verto_get_private(ev); ++ ++ req->timer = NULL; /* Void the timer event. */ ++ ++ /* If we have more retries to perform, resend the packet. */ ++ if (req->retries-- > 1) { ++ req->sent = 0; ++ verto_set_flags(req->rr->io, FLAGS_WRITE); ++ return; ++ } ++ ++ request_finish(req, ETIMEDOUT, NULL); ++} ++ ++/* Connect to the remote host. */ ++static krb5_error_code ++remote_connect(krad_remote *rr) ++{ ++ int i, sock = -1; ++ verto_ev *ev; ++ ++ sock = socket(rr->info->ai_family, rr->info->ai_socktype, ++ rr->info->ai_protocol); ++ if (sock < 0) ++ return errno; ++ ++ i = connect(sock, rr->info->ai_addr, rr->info->ai_addrlen); ++ if (i < 0) { ++ i = errno; ++ close(sock); ++ return i; ++ } ++ ++ ev = verto_add_io(rr->vctx, FLAGS_READ, on_io, sock); ++ if (ev == NULL) { ++ close(sock); ++ return ENOMEM; ++ } ++ ++ rr->io = ev; ++ verto_set_private(rr->io, rr, NULL); ++ return 0; ++} ++ ++/* Disconnect and reconnect to the remote host. */ ++static krb5_error_code ++remote_reconnect(krad_remote *rr, int errnum) ++{ ++ krb5_error_code retval; ++ const krb5_data *tmp; ++ request *r; ++ ++ verto_del(rr->io); ++ rr->io = NULL; ++ retval = remote_connect(rr); ++ if (retval != 0) ++ return retval; ++ ++ TAILQ_FOREACH(r, &rr->list, list) { ++ tmp = krad_packet_encode(r->request); ++ ++ if (r->sent == tmp->length) { ++ /* Error out sent requests. */ ++ request_finish(r, errnum, NULL); ++ } else { ++ /* Reset partially sent requests. */ ++ r->sent = 0; ++ } ++ } ++ ++ return 0; ++} ++ ++/* Close the connection and call the callbacks of all oustanding requests. */ ++static void ++remote_shutdown(krad_remote *rr, int errnum) ++{ ++ verto_del(rr->io); ++ rr->io = NULL; ++ while (!TAILQ_EMPTY(&rr->list)) ++ request_finish(TAILQ_FIRST(&rr->list), errnum, NULL); ++} ++ ++/* Write data to the socket. */ ++static void ++on_io_write(krad_remote *rr) ++{ ++ const krb5_data *tmp; ++ request *r; ++ int i; ++ ++ TAILQ_FOREACH(r, &rr->list, list) { ++ tmp = krad_packet_encode(r->request); ++ ++ /* If the packet has already been sent, do nothing. */ ++ if (r->sent == tmp->length) ++ continue; ++ ++ /* Send the packet. */ ++ i = sendto(verto_get_fd(rr->io), tmp->data + r->sent, ++ tmp->length - r->sent, 0, NULL, 0); ++ if (i < 0) { ++ /* Should we try again? */ ++ if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ENOBUFS || ++ errno == EINTR) ++ return; ++ ++ /* In this case, we need to re-connect. */ ++ i = remote_reconnect(rr, errno); ++ if (i == 0) ++ return; ++ ++ /* Do a full reset. */ ++ remote_shutdown(rr, i); ++ return; ++ } ++ ++ /* SOCK_STREAM permits partial writes. */ ++ if (rr->info->ai_socktype == SOCK_STREAM) ++ r->sent += i; ++ else if (i == (int)tmp->length) ++ r->sent = i; ++ ++ /* If the packet was completely sent, set a timeout. */ ++ if (r->sent == tmp->length) { ++ verto_del(r->timer); ++ r->timer = verto_add_timeout(rr->vctx, VERTO_EV_FLAG_NONE, ++ on_timeout, r->timeout); ++ if (r->timer == NULL) ++ request_finish(r, ENOMEM, NULL); ++ else ++ verto_set_private(r->timer, r, NULL); ++ } ++ ++ return; ++ } ++ ++ verto_set_flags(rr->io, FLAGS_READ); ++} ++ ++/* Read data from the socket. */ ++static void ++on_io_read(krad_remote *rr) ++{ ++ const krad_packet *req = NULL; ++ krad_packet *rsp = NULL; ++ krb5_error_code retval; ++ ssize_t pktlen; ++ request *tmp, *r; ++ int i; ++ ++ pktlen = sizeof(rr->buffer_); ++ if (rr->info->ai_socktype == SOCK_STREAM) { ++ pktlen = krad_packet_bytes_needed(&rr->buffer); ++ if (pktlen < 0) { ++ retval = remote_reconnect(rr, EBADMSG); ++ if (retval != 0) ++ remote_shutdown(rr, retval); ++ return; ++ } ++ } ++ ++ /* Read the packet. */ ++ i = recv(verto_get_fd(rr->io), rr->buffer.data + rr->buffer.length, ++ pktlen - rr->buffer.length, 0); ++ if (i < 0) { ++ /* Should we try again? */ ++ if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) ++ return; ++ ++ if (errno == ECONNREFUSED || errno == ECONNRESET || ++ errno == ENOTCONN) { ++ /* ++ * When doing UDP against a local socket, the kernel will notify ++ * when the daemon closes. But not against remote sockets. We want ++ * to treat them both the same. Returning here will cause an ++ * eventual timeout. ++ */ ++ if (rr->info->ai_socktype != SOCK_STREAM) ++ return; ++ } ++ ++ /* In this case, we need to re-connect. */ ++ i = remote_reconnect(rr, errno); ++ if (i == 0) ++ return; ++ ++ /* Do a full reset. */ ++ remote_shutdown(rr, i); ++ return; ++ } ++ ++ /* If we have a partial read or just the header, try again. */ ++ rr->buffer.length += i; ++ pktlen = krad_packet_bytes_needed(&rr->buffer); ++ if (rr->info->ai_socktype == SOCK_STREAM && pktlen > 0) ++ return; ++ ++ /* Decode the packet. */ ++ tmp = TAILQ_FIRST(&rr->list); ++ retval = krad_packet_decode_response(rr->kctx, rr->secret, &rr->buffer, ++ (krad_packet_iter_cb)iterator, &tmp, ++ &req, &rsp); ++ rr->buffer.length = 0; ++ if (retval != 0) ++ return; ++ ++ /* Match the response with an outstanding request. */ ++ if (req != NULL) { ++ TAILQ_FOREACH(r, &rr->list, list) { ++ if (r->request == req && ++ r->sent == krad_packet_encode(req)->length) { ++ request_finish(r, 0, rsp); ++ break; ++ } ++ } ++ } ++ ++ krad_packet_free(rsp); ++} ++ ++/* Handle when IO is ready on the socket. */ ++static void ++on_io(verto_ctx *ctx, verto_ev *ev) ++{ ++ krad_remote *rr; ++ ++ rr = verto_get_private(ev); ++ ++ if (verto_get_fd_state(ev) & VERTO_EV_FLAG_IO_WRITE) ++ on_io_write(rr); ++ else ++ on_io_read(rr); ++} ++ ++krb5_error_code ++kr_remote_new(krb5_context kctx, verto_ctx *vctx, const struct addrinfo *info, ++ const char *secret, krad_remote **rr) ++{ ++ krb5_error_code retval = ENOMEM; ++ krad_remote *tmp = NULL; ++ ++ tmp = calloc(1, sizeof(krad_remote)); ++ if (tmp == NULL) ++ goto error; ++ tmp->kctx = kctx; ++ tmp->vctx = vctx; ++ tmp->buffer = make_data(tmp->buffer_, 0); ++ TAILQ_INIT(&tmp->list); ++ ++ tmp->secret = strdup(secret); ++ if (tmp->secret == NULL) ++ goto error; ++ ++ tmp->info = k5memdup(info, sizeof(*info), &retval); ++ if (tmp->info == NULL) ++ goto error; ++ ++ tmp->info->ai_addr = k5memdup(info->ai_addr, info->ai_addrlen, &retval); ++ if (tmp->info == NULL) ++ goto error; ++ tmp->info->ai_next = NULL; ++ tmp->info->ai_canonname = NULL; ++ ++ retval = remote_connect(tmp); ++ if (retval != 0) ++ goto error; ++ ++ *rr = tmp; ++ return 0; ++ ++error: ++ kr_remote_free(tmp); ++ return retval; ++} ++ ++void ++kr_remote_free(krad_remote *rr) ++{ ++ if (rr == NULL) ++ return; ++ ++ while (!TAILQ_EMPTY(&rr->list)) ++ request_finish(TAILQ_FIRST(&rr->list), ECANCELED, NULL); ++ ++ free(rr->secret); ++ if (rr->info != NULL) ++ free(rr->info->ai_addr); ++ free(rr->info); ++ verto_del(rr->io); ++ free(rr); ++} ++ ++krb5_error_code ++kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs, ++ krad_cb cb, void *data, int timeout, size_t retries, ++ const krad_packet **pkt) ++{ ++ krad_packet *tmp = NULL; ++ krb5_error_code retval; ++ request *r; ++ ++ r = TAILQ_FIRST(&rr->list); ++ retval = krad_packet_new_request(rr->kctx, rr->secret, code, attrs, ++ (krad_packet_iter_cb)iterator, &r, &tmp); ++ if (retval != 0) ++ goto error; ++ ++ TAILQ_FOREACH(r, &rr->list, list) { ++ if (r->request == tmp) { ++ retval = EALREADY; ++ goto error; ++ } ++ } ++ ++ if (rr->io == NULL) { ++ retval = remote_connect(rr); ++ if (retval != 0) ++ goto error; ++ } ++ ++ if (rr->info->ai_socktype == SOCK_STREAM) ++ retries = 0; ++ timeout = timeout / (retries + 1); ++ retval = request_new(rr, tmp, timeout, retries, cb, data, &r); ++ if (retval != 0) ++ goto error; ++ ++ if ((verto_get_flags(rr->io) & VERTO_EV_FLAG_IO_WRITE) == 0) ++ verto_set_flags(rr->io, FLAGS_WRITE); ++ ++ TAILQ_INSERT_TAIL(&rr->list, r, list); ++ if (pkt != NULL) ++ *pkt = tmp; ++ return 0; ++ ++error: ++ krad_packet_free(tmp); ++ return retval; ++} ++ ++void ++kr_remote_cancel(krad_remote *rr, const krad_packet *pkt) ++{ ++ request *r; ++ ++ TAILQ_FOREACH(r, &rr->list, list) { ++ if (r->request == pkt) { ++ request_finish(r, ECANCELED, NULL); ++ return; ++ } ++ } ++} ++ ++krb5_boolean ++kr_remote_equals(const krad_remote *rr, const struct addrinfo *info, ++ const char *secret) ++{ ++ struct sockaddr_un *a, *b; ++ ++ if (strcmp(rr->secret, secret) != 0) ++ return FALSE; ++ ++ if (info->ai_addrlen != rr->info->ai_addrlen) ++ return FALSE; ++ ++ if (info->ai_family != rr->info->ai_family) ++ return FALSE; ++ ++ if (info->ai_socktype != rr->info->ai_socktype) ++ return FALSE; ++ ++ if (info->ai_protocol != rr->info->ai_protocol) ++ return FALSE; ++ ++ if (info->ai_flags != rr->info->ai_flags) ++ return FALSE; ++ ++ if (memcmp(rr->info->ai_addr, info->ai_addr, info->ai_addrlen) != 0) { ++ /* AF_UNIX fails the memcmp() test due to uninitialized bytes after the ++ * socket name. */ ++ if (info->ai_family != AF_UNIX) ++ return FALSE; ++ ++ a = (struct sockaddr_un *)info->ai_addr; ++ b = (struct sockaddr_un *)rr->info->ai_addr; ++ if (strncmp(a->sun_path, b->sun_path, sizeof(a->sun_path)) != 0) ++ return FALSE; ++ } ++ ++ return TRUE; ++} +diff --git a/src/lib/krad/t_attr.c b/src/lib/krad/t_attr.c +new file mode 100644 +index 0000000..e80d77b +--- /dev/null ++++ b/src/lib/krad/t_attr.c +@@ -0,0 +1,89 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/t_attr.c - Attribute test program */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "t_test.h" ++ ++const static char encoded[] = { ++ 0xba, 0xfc, 0xed, 0x50, 0xe1, 0xeb, 0xa6, 0xc3, ++ 0xc1, 0x75, 0x20, 0xe9, 0x10, 0xce, 0xc2, 0xcb ++}; ++ ++const static unsigned char auth[] = { ++ 0xac, 0x9d, 0xc1, 0x62, 0x08, 0xc4, 0xc7, 0x8b, ++ 0xa1, 0x2f, 0x25, 0x0a, 0xc4, 0x1d, 0x36, 0x41 ++}; ++ ++int ++main() ++{ ++ unsigned char outbuf[MAX_ATTRSETSIZE]; ++ const char *decoded = "accept"; ++ const char *secret = "foo"; ++ krb5_error_code retval; ++ krb5_context ctx; ++ const char *tmp; ++ krb5_data in; ++ size_t len; ++ ++ noerror(krb5_init_context(&ctx)); ++ ++ /* Make sure User-Name is 1. */ ++ insist(krad_attr_name2num("User-Name") == 1); ++ ++ /* Make sure 2 is User-Password. */ ++ tmp = krad_attr_num2name(2); ++ insist(tmp != NULL); ++ insist(strcmp(tmp, "User-Password") == 0); ++ ++ /* Test decoding. */ ++ in = make_data((void *)encoded, sizeof(encoded)); ++ noerror(kr_attr_decode(ctx, secret, auth, ++ krad_attr_name2num("User-Password"), ++ &in, outbuf, &len)); ++ insist(len == strlen(decoded)); ++ insist(memcmp(outbuf, decoded, len) == 0); ++ ++ /* Test encoding. */ ++ in = string2data((char *)decoded); ++ retval = kr_attr_encode(ctx, secret, auth, ++ krad_attr_name2num("User-Password"), ++ &in, outbuf, &len); ++ insist(retval == 0); ++ insist(len == sizeof(encoded)); ++ insist(memcmp(outbuf, encoded, len) == 0); ++ ++ /* Test constraint. */ ++ in.length = 100; ++ insist(kr_attr_valid(krad_attr_name2num("User-Password"), &in) == 0); ++ in.length = 200; ++ insist(kr_attr_valid(krad_attr_name2num("User-Password"), &in) != 0); ++ ++ krb5_free_context(ctx); ++ return 0; ++} +diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c +new file mode 100644 +index 0000000..afae5e4 +--- /dev/null ++++ b/src/lib/krad/t_attrset.c +@@ -0,0 +1,98 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/t_attrset.c - Attribute set test program */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "t_test.h" ++ ++const static unsigned char auth[] = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++ ++const static char encpass[] = { ++ 0x58, 0x8d, 0xff, 0xda, 0x37, 0xf9, 0xe4, 0xca, ++ 0x19, 0xae, 0x49, 0xb7, 0x16, 0x6d, 0x58, 0x27 ++}; ++ ++int ++main() ++{ ++ unsigned char buffer[KRAD_PACKET_SIZE_MAX], encoded[MAX_ATTRSETSIZE]; ++ const char *username = "testUser", *password = "accept"; ++ const krb5_data *tmpp; ++ krad_attrset *set; ++ krb5_context ctx; ++ size_t len = 0, encode_len; ++ krb5_data tmp; ++ ++ noerror(krb5_init_context(&ctx)); ++ noerror(krad_attrset_new(ctx, &set)); ++ ++ /* Add username. */ ++ tmp = string2data((char *)username); ++ noerror(krad_attrset_add(set, krad_attr_name2num("User-Name"), &tmp)); ++ ++ /* Add password. */ ++ tmp = string2data((char *)password); ++ noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp)); ++ ++ /* Encode attrset. */ ++ noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len)); ++ krad_attrset_free(set); ++ ++ /* Manually encode User-Name. */ ++ encoded[len + 0] = krad_attr_name2num("User-Name"); ++ encoded[len + 1] = strlen(username) + 2; ++ memcpy(encoded + len + 2, username, strlen(username)); ++ len += encoded[len + 1]; ++ ++ /* Manually encode User-Password. */ ++ encoded[len + 0] = krad_attr_name2num("User-Password"); ++ encoded[len + 1] = sizeof(encpass) + 2; ++ memcpy(encoded + len + 2, encpass, sizeof(encpass)); ++ len += encoded[len + 1]; ++ ++ /* Compare output. */ ++ insist(len == encode_len); ++ insist(memcmp(encoded, buffer, len) == 0); ++ ++ /* Decode output. */ ++ tmp = make_data(buffer, len); ++ noerror(kr_attrset_decode(ctx, &tmp, "foo", auth, &set)); ++ ++ /* Test getting an attribute. */ ++ tmp = string2data((char *)username); ++ tmpp = krad_attrset_get(set, krad_attr_name2num("User-Name"), 0); ++ insist(tmpp != NULL); ++ insist(tmpp->length == tmp.length); ++ insist(strncmp(tmpp->data, tmp.data, tmp.length) == 0); ++ ++ krad_attrset_free(set); ++ krb5_free_context(ctx); ++ return 0; ++} +diff --git a/src/lib/krad/t_client.c b/src/lib/krad/t_client.c +new file mode 100644 +index 0000000..3d0fda9 +--- /dev/null ++++ b/src/lib/krad/t_client.c +@@ -0,0 +1,126 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/t_client.c - Client request test program */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "t_daemon.h" ++ ++#define EVENT_COUNT 4 ++ ++static struct ++{ ++ int count; ++ struct event events[EVENT_COUNT]; ++} record; ++ ++static verto_ctx *vctx; ++ ++static void ++callback(krb5_error_code retval, const krad_packet *request, ++ const krad_packet *response, void *data) ++{ ++ struct event *evt; ++ ++ evt = &record.events[record.count++]; ++ evt->error = retval != 0; ++ if (evt->error) ++ evt->result.retval = retval; ++ else ++ evt->result.code = krad_packet_get_code(response); ++ verto_break(vctx); ++} ++ ++int ++main(int argc, const char **argv) ++{ ++ krad_attrset *attrs; ++ krad_client *rc; ++ krb5_context kctx; ++ krb5_data tmp; ++ ++ if (!daemon_start(argc, argv)) { ++ fprintf(stderr, "Unable to start pyrad daemon, skipping test...\n"); ++ return 0; ++ } ++ ++ noerror(krb5_init_context(&kctx)); ++ vctx = verto_new(NULL, VERTO_EV_TYPE_IO | VERTO_EV_TYPE_TIMEOUT); ++ insist(vctx != NULL); ++ noerror(krad_client_new(kctx, vctx, &rc)); ++ ++ tmp = string2data("testUser"); ++ noerror(krad_attrset_new(kctx, &attrs)); ++ noerror(krad_attrset_add(attrs, krad_attr_name2num("User-Name"), &tmp)); ++ ++ /* Test accept. */ ++ tmp = string2data("accept"); ++ noerror(krad_attrset_add(attrs, krad_attr_name2num("User-Password"), ++ &tmp)); ++ noerror(krad_client_send(rc, krad_code_name2num("Access-Request"), attrs, ++ "localhost", "foo", 1000, 3, callback, NULL)); ++ verto_run(vctx); ++ ++ /* Test reject. */ ++ tmp = string2data("reject"); ++ krad_attrset_del(attrs, krad_attr_name2num("User-Password"), 0); ++ noerror(krad_attrset_add(attrs, krad_attr_name2num("User-Password"), ++ &tmp)); ++ noerror(krad_client_send(rc, krad_code_name2num("Access-Request"), attrs, ++ "localhost", "foo", 1000, 3, callback, NULL)); ++ verto_run(vctx); ++ ++ /* Test timeout. */ ++ daemon_stop(); ++ noerror(krad_client_send(rc, krad_code_name2num("Access-Request"), attrs, ++ "localhost", "foo", 1000, 3, callback, NULL)); ++ verto_run(vctx); ++ ++ /* Test outstanding packet freeing. */ ++ noerror(krad_client_send(rc, krad_code_name2num("Access-Request"), attrs, ++ "localhost", "foo", 1000, 3, callback, NULL)); ++ krad_client_free(rc); ++ rc = NULL; ++ ++ /* Verify the results. */ ++ insist(record.count == EVENT_COUNT); ++ insist(record.events[0].error == FALSE); ++ insist(record.events[0].result.code == ++ krad_code_name2num("Access-Accept")); ++ insist(record.events[1].error == FALSE); ++ insist(record.events[1].result.code == ++ krad_code_name2num("Access-Reject")); ++ insist(record.events[2].error == TRUE); ++ insist(record.events[2].result.retval == ETIMEDOUT); ++ insist(record.events[3].error == TRUE); ++ insist(record.events[3].result.retval == ECANCELED); ++ ++ krad_attrset_free(attrs); ++ krad_client_free(rc); ++ verto_free(vctx); ++ krb5_free_context(kctx); ++ return 0; ++} +diff --git a/src/lib/krad/t_code.c b/src/lib/krad/t_code.c +new file mode 100644 +index 0000000..b245a7e +--- /dev/null ++++ b/src/lib/krad/t_code.c +@@ -0,0 +1,54 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/t_code.c - RADIUS code table test program */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "t_test.h" ++ ++int ++main() ++{ ++ const char *tmp; ++ ++ insist(krad_code_name2num("Access-Request") == 1); ++ insist(krad_code_name2num("Access-Accept") == 2); ++ insist(krad_code_name2num("Access-Reject") == 3); ++ ++ tmp = krad_code_num2name(1); ++ insist(tmp != NULL); ++ insist(strcmp(tmp, "Access-Request") == 0); ++ ++ tmp = krad_code_num2name(2); ++ insist(tmp != NULL); ++ insist(strcmp(tmp, "Access-Accept") == 0); ++ ++ tmp = krad_code_num2name(3); ++ insist(tmp != NULL); ++ insist(strcmp(tmp, "Access-Reject") == 0); ++ ++ return 0; ++} +diff --git a/src/lib/krad/t_daemon.h b/src/lib/krad/t_daemon.h +new file mode 100644 +index 0000000..7c345a6 +--- /dev/null ++++ b/src/lib/krad/t_daemon.h +@@ -0,0 +1,92 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/t_daemon.h - Daemonization helper for RADIUS test programs */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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. ++ */ ++ ++#ifndef T_DAEMON_H_ ++#define T_DAEMON_H_ ++ ++#include "t_test.h" ++#include ++#include ++#include ++#include ++ ++static pid_t daemon_pid; ++ ++static void ++daemon_stop(void) ++{ ++ if (daemon_pid == 0) ++ return; ++ kill(daemon_pid, SIGTERM); ++ waitpid(daemon_pid, NULL, 0); ++ daemon_pid = 0; ++} ++ ++static krb5_boolean ++daemon_start(int argc, const char **argv) ++{ ++ sigset_t set; ++ int sig; ++ ++ if (argc != 3 || argv == NULL) ++ return FALSE; ++ ++ if (daemon_pid != 0) ++ return TRUE; ++ ++ if (sigemptyset(&set) != 0) ++ return FALSE; ++ ++ if (sigaddset(&set, SIGUSR1) != 0) ++ return FALSE; ++ ++ if (sigaddset(&set, SIGCHLD) != 0) ++ return FALSE; ++ ++ if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) ++ return FALSE; ++ ++ daemon_pid = fork(); ++ if (daemon_pid == 0) { ++ close(STDOUT_FILENO); ++ open("/dev/null", O_WRONLY); ++ exit(execlp(argv[1], argv[1], argv[2], NULL)); ++ } ++ ++ if (sigwait(&set, &sig) != 0 || sig == SIGCHLD) { ++ daemon_stop(); ++ daemon_pid = 0; ++ return FALSE; ++ } ++ ++ atexit(daemon_stop); ++ return TRUE; ++} ++ ++#endif /* T_DAEMON_H_ */ +diff --git a/src/lib/krad/t_daemon.py b/src/lib/krad/t_daemon.py +new file mode 100644 +index 0000000..d62bc29 +--- /dev/null ++++ b/src/lib/krad/t_daemon.py +@@ -0,0 +1,76 @@ ++#!/usr/bin/python ++# ++# Copyright 2013 Red Hat, Inc. All rights reserved. ++# ++# Redistribution and use in source and binary forms, with or without ++# modification, are permitted provided that the following conditions are met: ++# ++# 1. Redistributions of source code must retain the above copyright ++# notice, this list of conditions and the following disclaimer. ++# ++# 2. 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 OWNER ++# 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. ++ ++import StringIO ++import os ++import sys ++import signal ++ ++try: ++ from pyrad import dictionary, packet, server ++except ImportError: ++ sys.stdout.write("pyrad not found!\n") ++ sys.exit(0) ++ ++# We could use a dictionary file, but since we need ++# such few attributes, we'll just include them here ++DICTIONARY = """ ++ATTRIBUTE\tUser-Name\t1\tstring ++ATTRIBUTE\tUser-Password\t2\toctets ++ATTRIBUTE\tNAS-Identifier\t32\tstring ++""" ++ ++class TestServer(server.Server): ++ def _HandleAuthPacket(self, pkt): ++ server.Server._HandleAuthPacket(self, pkt) ++ ++ passwd = [] ++ ++ print "Request: " ++ for key in pkt.keys(): ++ if key == "User-Password": ++ passwd = map(pkt.PwDecrypt, pkt[key]) ++ print "\t%s\t%s" % (key, passwd) ++ else: ++ print "\t%s\t%s" % (key, pkt[key]) ++ ++ reply = self.CreateReplyPacket(pkt) ++ if passwd == ['accept']: ++ reply.code = packet.AccessAccept ++ print "Response: %s" % "Access-Accept" ++ else: ++ reply.code = packet.AccessReject ++ print "Response: %s" % "Access-Reject" ++ print ++ self.SendReplyPacket(pkt.fd, reply) ++ ++srv = TestServer(addresses=["localhost"], ++ hosts={"127.0.0.1": ++ server.RemoteHost("127.0.0.1", "foo", "localhost")}, ++ dict=dictionary.Dictionary(StringIO.StringIO(DICTIONARY))) ++os.kill(os.getppid(), signal.SIGUSR1) ++srv.Run() +diff --git a/src/lib/krad/t_packet.c b/src/lib/krad/t_packet.c +new file mode 100644 +index 0000000..0a92e9c +--- /dev/null ++++ b/src/lib/krad/t_packet.c +@@ -0,0 +1,194 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/t_packet.c - RADIUS packet test program */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "t_daemon.h" ++ ++#define ACCEPT_PACKET 0 ++#define REJECT_PACKET 1 ++ ++static krad_packet *packets[3]; ++ ++static const krad_packet * ++iterator(void *data, krb5_boolean cancel) ++{ ++ krad_packet *tmp; ++ int *i = data; ++ ++ if (cancel || packets[*i] == NULL) ++ return NULL; ++ ++ tmp = packets[*i]; ++ *i += 1; ++ return tmp; ++} ++ ++static krb5_error_code ++make_packet(krb5_context ctx, const krb5_data *username, ++ const krb5_data *password, krad_packet **pkt) ++{ ++ krad_attrset *set = NULL; ++ krad_packet *tmp = NULL; ++ krb5_error_code retval; ++ const krb5_data *data; ++ int i = 0; ++ ++ retval = krad_attrset_new(ctx, &set); ++ if (retval != 0) ++ goto out; ++ ++ retval = krad_attrset_add(set, krad_attr_name2num("User-Name"), username); ++ if (retval != 0) ++ goto out; ++ ++ retval = krad_attrset_add(set, krad_attr_name2num("User-Password"), ++ password); ++ if (retval != 0) ++ goto out; ++ ++ retval = krad_packet_new_request(ctx, "foo", ++ krad_code_name2num("Access-Request"), ++ set, iterator, &i, &tmp); ++ if (retval != 0) ++ goto out; ++ ++ data = krad_packet_get_attr(tmp, krad_attr_name2num("User-Name"), 0); ++ if (data == NULL) { ++ retval = ENOENT; ++ goto out; ++ } ++ ++ if (data->length != username->length || ++ memcmp(data->data, username->data, data->length) != 0) { ++ retval = EINVAL; ++ goto out; ++ } ++ ++ *pkt = tmp; ++ tmp = NULL; ++ ++out: ++ krad_attrset_free(set); ++ krad_packet_free(tmp); ++ return retval; ++} ++ ++static krb5_error_code ++do_auth(krb5_context ctx, struct addrinfo *ai, const char *secret, ++ const krad_packet *rqst, krb5_boolean *auth) ++{ ++ const krad_packet *req = NULL; ++ char tmp[KRAD_PACKET_SIZE_MAX]; ++ const krb5_data *request; ++ krad_packet *rsp = NULL; ++ krb5_error_code retval; ++ krb5_data response; ++ int sock = -1, i; ++ ++ response = make_data(tmp, sizeof(tmp)); ++ ++ sock = socket(ai->ai_family, ai->ai_socktype, 0); ++ if (sock < 0) { ++ retval = errno; ++ goto out; ++ } ++ ++ request = krad_packet_encode(rqst); ++ if (sendto(sock, request->data, request->length, 0, ai->ai_addr, ++ ai->ai_addrlen) < 0) { ++ retval = errno; ++ goto out; ++ } ++ ++ i = recv(sock, response.data, sizeof(tmp), 0); ++ if (i < 0) { ++ retval = errno; ++ goto out; ++ } ++ response.length = i; ++ ++ i = 0; ++ retval = krad_packet_decode_response(ctx, secret, &response, iterator, &i, ++ &req, &rsp); ++ if (retval != 0) ++ goto out; ++ ++ if (req != rqst) { ++ retval = EBADMSG; ++ goto out; ++ } ++ ++ *auth = krad_packet_get_code(rsp) == krad_code_name2num("Access-Accept"); ++ ++out: ++ krad_packet_free(rsp); ++ if (sock >= 0) ++ close(sock); ++ return retval; ++} ++ ++int ++main(int argc, const char **argv) ++{ ++ struct addrinfo *ai = NULL, hints; ++ krb5_data username, password; ++ krb5_boolean auth = FALSE; ++ krb5_context ctx; ++ ++ username = string2data("testUser"); ++ ++ if (!daemon_start(argc, argv)) { ++ fprintf(stderr, "Unable to start pyrad daemon, skipping test...\n"); ++ return 0; ++ } ++ ++ noerror(krb5_init_context(&ctx)); ++ ++ password = string2data("accept"); ++ noerror(make_packet(ctx, &username, &password, &packets[ACCEPT_PACKET])); ++ ++ password = string2data("reject"); ++ noerror(make_packet(ctx, &username, &password, &packets[REJECT_PACKET])); ++ ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_family = AF_INET; ++ hints.ai_socktype = SOCK_DGRAM; ++ noerror(gai_error_code(getaddrinfo("127.0.0.1", "radius", &hints, &ai))); ++ ++ noerror(do_auth(ctx, ai, "foo", packets[ACCEPT_PACKET], &auth)); ++ insist(auth == TRUE); ++ ++ noerror(do_auth(ctx, ai, "foo", packets[REJECT_PACKET], &auth)); ++ insist(auth == FALSE); ++ ++ krad_packet_free(packets[ACCEPT_PACKET]); ++ krad_packet_free(packets[REJECT_PACKET]); ++ krb5_free_context(ctx); ++ freeaddrinfo(ai); ++ return 0; ++} +diff --git a/src/lib/krad/t_remote.c b/src/lib/krad/t_remote.c +new file mode 100644 +index 0000000..a521ecb +--- /dev/null ++++ b/src/lib/krad/t_remote.c +@@ -0,0 +1,170 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/t_remote.c - Protocol test program */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "t_daemon.h" ++ ++#define EVENT_COUNT 6 ++ ++static struct ++{ ++ int count; ++ struct event events[EVENT_COUNT]; ++} record; ++ ++static krad_attrset *set; ++static krad_remote *rr; ++static verto_ctx *vctx; ++ ++static void ++callback(krb5_error_code retval, const krad_packet *request, ++ const krad_packet *response, void *data) ++{ ++ struct event *evt; ++ ++ evt = &record.events[record.count++]; ++ evt->error = retval != 0; ++ if (evt->error) ++ evt->result.retval = retval; ++ else ++ evt->result.code = krad_packet_get_code(response); ++ verto_break(vctx); ++} ++ ++static void ++remote_new(krb5_context kctx, krad_remote **remote) ++{ ++ struct addrinfo *ai = NULL, hints; ++ ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_family = AF_INET; ++ hints.ai_socktype = SOCK_DGRAM; ++ noerror(gai_error_code(getaddrinfo("127.0.0.1", "radius", &hints, &ai))); ++ ++ noerror(kr_remote_new(kctx, vctx, ai, "foo", remote)); ++ insist(kr_remote_equals(*remote, ai, "foo")); ++ freeaddrinfo(ai); ++} ++ ++static krb5_error_code ++do_auth(const char *password, const krad_packet **pkt) ++{ ++ const krad_packet *tmppkt; ++ krb5_error_code retval; ++ krb5_data tmp = string2data((char *)password); ++ ++ retval = krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp); ++ if (retval != 0) ++ return retval; ++ ++ retval = kr_remote_send(rr, krad_code_name2num("Access-Request"), set, ++ callback, NULL, 1000, 3, &tmppkt); ++ krad_attrset_del(set, krad_attr_name2num("User-Password"), 0); ++ if (retval != 0) ++ return retval; ++ ++ if (pkt != NULL) ++ *pkt = tmppkt; ++ return 0; ++} ++ ++static void ++test_timeout(verto_ctx *ctx, verto_ev *ev) ++{ ++ static const krad_packet *pkt; ++ ++ noerror(do_auth("accept", &pkt)); ++ kr_remote_cancel(rr, pkt); ++} ++ ++int ++main(int argc, const char **argv) ++{ ++ krb5_context kctx = NULL; ++ krb5_data tmp; ++ ++ if (!daemon_start(argc, argv)) { ++ fprintf(stderr, "Unable to start pyrad daemon, skipping test...\n"); ++ return 0; ++ } ++ ++ /* Initialize. */ ++ noerror(krb5_init_context(&kctx)); ++ vctx = verto_new(NULL, VERTO_EV_TYPE_IO | VERTO_EV_TYPE_TIMEOUT); ++ insist(vctx != NULL); ++ remote_new(kctx, &rr); ++ ++ /* Create attribute set. */ ++ noerror(krad_attrset_new(kctx, &set)); ++ tmp = string2data("testUser"); ++ noerror(krad_attrset_add(set, krad_attr_name2num("User-Name"), &tmp)); ++ ++ /* Send accept packet. */ ++ noerror(do_auth("accept", NULL)); ++ verto_run(vctx); ++ ++ /* Send reject packet. */ ++ noerror(do_auth("reject", NULL)); ++ verto_run(vctx); ++ ++ /* Send canceled packet. */ ++ insist(verto_add_timeout(vctx, VERTO_EV_FLAG_NONE, test_timeout, 0) != ++ NULL); ++ verto_run(vctx); ++ ++ /* Test timeout. */ ++ daemon_stop(); ++ noerror(do_auth("accept", NULL)); ++ verto_run(vctx); ++ ++ /* Test outstanding packet freeing. */ ++ noerror(do_auth("accept", NULL)); ++ kr_remote_free(rr); ++ krad_attrset_free(set); ++ ++ /* Verify the results. */ ++ insist(record.count == EVENT_COUNT); ++ insist(record.events[0].error == FALSE); ++ insist(record.events[0].result.code == ++ krad_code_name2num("Access-Accept")); ++ insist(record.events[1].error == FALSE); ++ insist(record.events[1].result.code == ++ krad_code_name2num("Access-Reject")); ++ insist(record.events[2].error == TRUE); ++ insist(record.events[2].result.retval == ECANCELED); ++ insist(record.events[3].error == TRUE); ++ insist(record.events[3].result.retval == ETIMEDOUT); ++ insist(record.events[4].error == TRUE); ++ insist(record.events[4].result.retval == ECANCELED); ++ insist(record.events[5].error == TRUE); ++ insist(record.events[5].result.retval == ECANCELED); ++ ++ verto_free(vctx); ++ krb5_free_context(kctx); ++ return 0; ++} +diff --git a/src/lib/krad/t_test.c b/src/lib/krad/t_test.c +new file mode 100644 +index 0000000..152bc77 +--- /dev/null ++++ b/src/lib/krad/t_test.c +@@ -0,0 +1,50 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/t_test.c - Utility functions for libkrad tests */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "t_test.h" ++ ++void ++noerror_impl(const char *file, int line, const char *cmd, int retval) ++{ ++ if (retval == 0) ++ return; ++ ++ fprintf(stderr, "%s:%d: %s:\n\t%s\n", file, line, strerror(retval), cmd); ++ exit(1); ++} ++ ++void ++insist_impl(const char *file, int line, const char *cmd, krb5_boolean result) ++{ ++ if (result) ++ return; ++ ++ fprintf(stderr, "%s:%d: insist failed:\n\t%s\n", file, line, cmd); ++ exit(1); ++} +diff --git a/src/lib/krad/t_test.h b/src/lib/krad/t_test.h +new file mode 100644 +index 0000000..f44742f +--- /dev/null ++++ b/src/lib/krad/t_test.h +@@ -0,0 +1,60 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krad/t_test.h - Shared declarations for libkrad test programs */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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. ++ */ ++ ++#ifndef T_TEST_H_ ++#define T_TEST_H_ ++ ++#include "internal.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define insist(x) insist_impl(__FILE__, __LINE__, #x, x) ++#define noerror(x) noerror_impl(__FILE__, __LINE__, #x, x) ++ ++struct event { ++ krb5_boolean error; ++ union ++ { ++ krb5_error_code retval; ++ krad_code code; ++ } result; ++}; ++ ++void ++noerror_impl(const char *file, int line, const char *cmd, int retval); ++ ++void ++insist_impl(const char *file, int line, const char *cmd, krb5_boolean result); ++ ++#endif /* T_TEST_H_ */ +-- +1.8.2.1 + + +From 01c7bae6c9a962ffd38f9d5f70fdde7b9e6eb929 Mon Sep 17 00:00:00 2001 +From: Nathaniel McCallum +Date: Tue, 9 Apr 2013 12:24:47 -0400 +Subject: [PATCH 4/4] add otp plugin + +--- + src/Makefile.in | 1 + + src/configure.in | 1 + + src/kdc/kdc_preauth.c | 2 + + src/plugins/preauth/otp/Makefile.in | 39 +++ + src/plugins/preauth/otp/deps | 26 ++ + src/plugins/preauth/otp/main.c | 379 ++++++++++++++++++++++++ + src/plugins/preauth/otp/otp.exports | 1 + + src/plugins/preauth/otp/otp_state.c | 560 ++++++++++++++++++++++++++++++++++++ + src/plugins/preauth/otp/otp_state.h | 59 ++++ + 9 files changed, 1068 insertions(+) + create mode 100644 src/plugins/preauth/otp/Makefile.in + create mode 100644 src/plugins/preauth/otp/deps + create mode 100644 src/plugins/preauth/otp/main.c + create mode 100644 src/plugins/preauth/otp/otp.exports + create mode 100644 src/plugins/preauth/otp/otp_state.c + create mode 100644 src/plugins/preauth/otp/otp_state.h + +diff --git a/src/Makefile.in b/src/Makefile.in +index 2c65831..0b9d355 100644 +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -12,6 +12,7 @@ SUBDIRS=util include lib \ + plugins/kadm5_hook/test \ + plugins/kdb/db2 \ + @ldap_plugin_dir@ \ ++ plugins/preauth/otp \ + plugins/preauth/pkinit \ + kdc kadmin slave clients appl tests \ + config-files man doc @po@ +diff --git a/src/configure.in b/src/configure.in +index d8676e5..520e0c8 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -1337,6 +1337,7 @@ dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test + plugins/kdb/db2/libdb2/test + plugins/kdb/hdb + plugins/preauth/cksum_body ++ plugins/preauth/otp + plugins/preauth/securid_sam2 + plugins/preauth/wpse + plugins/authdata/greet +diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c +index 42a37a8..afbf1f6 100644 +--- a/src/kdc/kdc_preauth.c ++++ b/src/kdc/kdc_preauth.c +@@ -238,6 +238,8 @@ get_plugin_vtables(krb5_context context, + /* Auto-register encrypted challenge and (if possible) pkinit. */ + k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "pkinit", + "preauth"); ++ k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "otp", ++ "preauth"); + k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH, + "encrypted_challenge", + kdcpreauth_encrypted_challenge_initvt); +diff --git a/src/plugins/preauth/otp/Makefile.in b/src/plugins/preauth/otp/Makefile.in +new file mode 100644 +index 0000000..43bd2ba +--- /dev/null ++++ b/src/plugins/preauth/otp/Makefile.in +@@ -0,0 +1,39 @@ ++mydir=plugins$(S)preauth$(S)otp ++BUILDTOP=$(REL)..$(S)..$(S).. ++KRB5_CONFIG_SETUP = KRB5_CONFIG=$(top_srcdir)/config-files/krb5.conf ; export KRB5_CONFIG ; ++PROG_LIBPATH=-L$(TOPLIBD) ++PROG_RPATH=$(KRB5_LIBDIR) ++MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR) ++DEFS=@DEFS@ ++ ++LIBBASE=otp ++LIBMAJOR=0 ++LIBMINOR=0 ++SO_EXT=.so ++RELDIR=../plugins/preauth/otp ++ ++SHLIB_EXPDEPS = $(VERTO_DEPLIBS) $(KRB5_BASE_DEPLIBS) \ ++ $(TOPLIBD)/libkrad$(SHLIBEXT) ++ ++SHLIB_EXPLIBS= -lkrad $(VERTO_LIBS) $(KRB5_BASE_LIBS) ++ ++SHLIB_DIRS=-L$(TOPLIBD) ++SHLIB_RDIRS=$(KRB5_LIBDIR) ++STOBJLISTS=OBJS.ST ++STLIBOBJS = \ ++ otp_state.o \ ++ main.o ++ ++SRCS = \ ++ $(srcdir)/otp_state.c \ ++ $(srcdir)/main.c ++ ++all-unix:: all-liblinks ++install-unix:: install-libs ++clean-unix:: clean-liblinks clean-libs clean-libobjs ++ ++clean:: ++ $(RM) lib$(LIBBASE)$(SO_EXT) ++ ++@libnover_frag@ ++@libobj_frag@ +diff --git a/src/plugins/preauth/otp/deps b/src/plugins/preauth/otp/deps +new file mode 100644 +index 0000000..3352126 +--- /dev/null ++++ b/src/plugins/preauth/otp/deps +@@ -0,0 +1,26 @@ ++# ++# Generated makefile dependencies follow. ++# ++otp_state.so otp_state.po $(OUTPRE)otp_state.$(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-json.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/krb5/preauth_plugin.h \ ++ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ ++ otp_state.c otp_state.h ++main.so main.po $(OUTPRE)main.$(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-json.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/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ ++ $(top_srcdir)/include/socket-utils.h main.c otp_state.h +diff --git a/src/plugins/preauth/otp/main.c b/src/plugins/preauth/otp/main.c +new file mode 100644 +index 0000000..2f7470e +--- /dev/null ++++ b/src/plugins/preauth/otp/main.c +@@ -0,0 +1,379 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* plugins/preauth/otp/main.c - OTP kdcpreauth module definition */ ++/* ++ * Copyright 2011 NORDUnet A/S. All rights reserved. ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "k5-json.h" ++#include ++#include "otp_state.h" ++ ++#include ++#include ++ ++static krb5_preauthtype otp_pa_type_list[] = ++ { KRB5_PADATA_OTP_REQUEST, 0 }; ++ ++struct request_state { ++ krb5_kdcpreauth_verify_respond_fn respond; ++ void *arg; ++}; ++ ++static krb5_error_code ++decrypt_encdata(krb5_context context, krb5_keyblock *armor_key, ++ krb5_pa_otp_req *req, krb5_data *out) ++{ ++ krb5_error_code retval; ++ krb5_data plaintext; ++ ++ if (req == NULL) ++ return EINVAL; ++ ++ retval = alloc_data(&plaintext, req->enc_data.ciphertext.length); ++ if (retval) ++ return retval; ++ ++ retval = krb5_c_decrypt(context, armor_key, KRB5_KEYUSAGE_PA_OTP_REQUEST, ++ NULL, &req->enc_data, &plaintext); ++ if (retval != 0) { ++ com_err("otp", retval, "Unable to decrypt encData in PA-OTP-REQUEST"); ++ free(plaintext.data); ++ return retval; ++ } ++ ++ *out = plaintext; ++ return 0; ++} ++ ++static krb5_error_code ++nonce_verify(krb5_context ctx, krb5_keyblock *armor_key, ++ const krb5_data *nonce) ++{ ++ krb5_error_code retval; ++ krb5_timestamp ts; ++ krb5_data *er = NULL; ++ ++ if (armor_key == NULL || nonce->data == NULL) { ++ retval = EINVAL; ++ goto out; ++ } ++ ++ /* Decode the PA-OTP-ENC-REQUEST structure. */ ++ retval = decode_krb5_pa_otp_enc_req(nonce, &er); ++ if (retval != 0) ++ goto out; ++ ++ /* Make sure the nonce is exactly the same size as the one generated. */ ++ if (er->length != armor_key->length + sizeof(krb5_timestamp)) ++ goto out; ++ ++ /* Check to make sure the timestamp at the beginning is still valid. */ ++ ts = load_32_be(er->data); ++ retval = krb5_check_clockskew(ctx, ts); ++ ++out: ++ krb5_free_data(ctx, er); ++ return retval; ++} ++ ++static krb5_error_code ++timestamp_verify(krb5_context ctx, const krb5_data *nonce) ++{ ++ krb5_error_code retval = EINVAL; ++ krb5_pa_enc_ts *et = NULL; ++ ++ if (nonce->data == NULL) ++ goto out; ++ ++ /* Decode the PA-ENC-TS-ENC structure. */ ++ retval = decode_krb5_pa_enc_ts(nonce, &et); ++ if (retval != 0) ++ goto out; ++ ++ /* Check the clockskew. */ ++ retval = krb5_check_clockskew(ctx, et->patimestamp); ++ ++out: ++ krb5_free_pa_enc_ts(ctx, et); ++ return retval; ++} ++ ++static krb5_error_code ++nonce_generate(krb5_context ctx, unsigned int length, krb5_data *nonce_out) ++{ ++ krb5_data nonce; ++ krb5_error_code retval; ++ krb5_timestamp now; ++ ++ retval = krb5_timeofday(ctx, &now); ++ if (retval != 0) ++ return retval; ++ ++ retval = alloc_data(&nonce, sizeof(now) + length); ++ if (retval != 0) ++ return retval; ++ ++ retval = krb5_c_random_make_octets(ctx, &nonce); ++ if (retval != 0) { ++ free(nonce.data); ++ return retval; ++ } ++ ++ store_32_be(now, nonce.data); ++ *nonce_out = nonce; ++ return 0; ++} ++ ++static void ++on_response(void *data, krb5_error_code retval, otp_response response) ++{ ++ struct request_state rs = *(struct request_state *)data; ++ ++ free(data); ++ ++ if (retval == 0 && response != otp_response_success) ++ retval = KRB5_PREAUTH_FAILED; ++ ++ rs.respond(rs.arg, retval, NULL, NULL, NULL); ++} ++ ++static krb5_error_code ++otp_init(krb5_context context, krb5_kdcpreauth_moddata *moddata_out, ++ const char **realmnames) ++{ ++ krb5_error_code retval; ++ otp_state *state; ++ ++ retval = otp_state_new(context, &state); ++ if (retval) ++ return retval; ++ *moddata_out = (krb5_kdcpreauth_moddata)state; ++ return 0; ++} ++ ++static void ++otp_fini(krb5_context context, krb5_kdcpreauth_moddata moddata) ++{ ++ otp_state_free((otp_state *)moddata); ++} ++ ++static int ++otp_flags(krb5_context context, krb5_preauthtype pa_type) ++{ ++ return PA_REPLACES_KEY; ++} ++ ++static void ++otp_edata(krb5_context context, krb5_kdc_req *request, ++ krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, ++ krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type, ++ krb5_kdcpreauth_edata_respond_fn respond, void *arg) ++{ ++ krb5_otp_tokeninfo ti, *tis[2] = { &ti, NULL }; ++ krb5_keyblock *armor_key = NULL; ++ krb5_pa_otp_challenge chl; ++ krb5_pa_data *pa = NULL; ++ krb5_error_code retval; ++ krb5_data *encoding; ++ char *config; ++ ++ /* Determine if otp is enabled for the user. */ ++ retval = cb->get_string(context, rock, "otp", &config); ++ if (retval != 0 || config == NULL) ++ goto out; ++ cb->free_string(context, rock, config); ++ ++ /* Get the armor key. This indicates the length of random data to use in ++ * the nonce. */ ++ armor_key = cb->fast_armor(context, rock); ++ if (armor_key == NULL) { ++ retval = ENOENT; ++ goto out; ++ } ++ ++ /* Build the (mostly empty) challenge. */ ++ memset(&ti, 0, sizeof(ti)); ++ memset(&chl, 0, sizeof(chl)); ++ chl.tokeninfo = tis; ++ ti.format = -1; ++ ti.length = -1; ++ ti.iteration_count = -1; ++ ++ /* Generate the nonce. */ ++ retval = nonce_generate(context, armor_key->length, &chl.nonce); ++ if (retval != 0) ++ goto out; ++ ++ /* Build the output pa-data. */ ++ retval = encode_krb5_pa_otp_challenge(&chl, &encoding); ++ if (retval != 0) ++ goto out; ++ pa = k5alloc(sizeof(krb5_pa_data), &retval); ++ if (pa == NULL) { ++ krb5_free_data(context, encoding); ++ goto out; ++ } ++ pa->pa_type = KRB5_PADATA_OTP_CHALLENGE; ++ pa->contents = (krb5_octet *)encoding->data; ++ pa->length = encoding->length; ++ free(encoding); ++ ++out: ++ (*respond)(arg, retval, pa); ++} ++ ++static void ++otp_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, ++ krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa, ++ krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, ++ krb5_kdcpreauth_moddata moddata, ++ krb5_kdcpreauth_verify_respond_fn respond, void *arg) ++{ ++ krb5_keyblock *armor_key = NULL; ++ krb5_pa_otp_req *req = NULL; ++ struct request_state *rs; ++ krb5_error_code retval; ++ krb5_data d, plaintext; ++ char *config; ++ ++ enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; ++ ++ /* Get the FAST armor key. */ ++ armor_key = cb->fast_armor(context, rock); ++ if (armor_key == NULL) { ++ retval = KRB5KDC_ERR_PREAUTH_FAILED; ++ com_err("otp", retval, "No armor key found when verifying padata"); ++ goto error; ++ } ++ ++ /* Decode the request. */ ++ d = make_data(pa->contents, pa->length); ++ retval = decode_krb5_pa_otp_req(&d, &req); ++ if (retval != 0) { ++ com_err("otp", retval, "Unable to decode OTP request"); ++ goto error; ++ } ++ ++ /* Decrypt the nonce from the request. */ ++ retval = decrypt_encdata(context, armor_key, req, &plaintext); ++ if (retval != 0) { ++ com_err("otp", retval, "Unable to decrypt nonce"); ++ goto error; ++ } ++ ++ /* Verify the nonce or timestamp. */ ++ retval = nonce_verify(context, armor_key, &plaintext); ++ if (retval != 0) ++ retval = timestamp_verify(context, &plaintext); ++ krb5_free_data_contents(context, &plaintext); ++ if (retval != 0) { ++ com_err("otp", retval, "Unable to verify nonce or timestamp"); ++ goto error; ++ } ++ ++ /* Create the request state. */ ++ rs = k5alloc(sizeof(struct request_state), &retval); ++ if (rs == NULL) ++ goto error; ++ rs->arg = arg; ++ rs->respond = respond; ++ ++ /* Get the principal's OTP configuration string. */ ++ retval = cb->get_string(context, rock, "otp", &config); ++ if (config == NULL) ++ retval = KRB5_PREAUTH_FAILED; ++ if (retval != 0) { ++ free(rs); ++ goto error; ++ } ++ ++ /* Send the request. */ ++ otp_state_verify((otp_state *)moddata, cb->event_context(context, rock), ++ request->client, config, req, on_response, rs); ++ cb->free_string(context, rock, config); ++ ++ k5_free_pa_otp_req(context, req); ++ return; ++ ++error: ++ k5_free_pa_otp_req(context, req); ++ (*respond)(arg, retval, NULL, NULL, NULL); ++} ++ ++static krb5_error_code ++otp_return_padata(krb5_context context, krb5_pa_data *padata, ++ krb5_data *req_pkt, krb5_kdc_req *request, ++ krb5_kdc_rep *reply, krb5_keyblock *encrypting_key, ++ krb5_pa_data **send_pa_out, krb5_kdcpreauth_callbacks cb, ++ krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata, ++ krb5_kdcpreauth_modreq modreq) ++{ ++ krb5_keyblock *armor_key = NULL; ++ ++ if (padata->length == 0) ++ return 0; ++ ++ /* Get the armor key. */ ++ armor_key = cb->fast_armor(context, rock); ++ if (!armor_key) { ++ com_err("otp", ENOENT, "No armor key found when returning padata"); ++ return ENOENT; ++ } ++ ++ /* Replace the reply key with the FAST armor key. */ ++ krb5_free_keyblock_contents(context, encrypting_key); ++ return krb5_copy_keyblock_contents(context, armor_key, encrypting_key); ++} ++ ++krb5_error_code ++kdcpreauth_otp_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable); ++ ++krb5_error_code ++kdcpreauth_otp_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable) ++{ ++ krb5_kdcpreauth_vtable vt; ++ ++ if (maj_ver != 1) ++ return KRB5_PLUGIN_VER_NOTSUPP; ++ ++ vt = (krb5_kdcpreauth_vtable)vtable; ++ vt->name = "otp"; ++ vt->pa_type_list = otp_pa_type_list; ++ vt->init = otp_init; ++ vt->fini = otp_fini; ++ vt->flags = otp_flags; ++ vt->edata = otp_edata; ++ vt->verify = otp_verify; ++ vt->return_padata = otp_return_padata; ++ ++ com_err("otp", 0, "Loaded"); ++ ++ return 0; ++} +diff --git a/src/plugins/preauth/otp/otp.exports b/src/plugins/preauth/otp/otp.exports +new file mode 100644 +index 0000000..26aa19d +--- /dev/null ++++ b/src/plugins/preauth/otp/otp.exports +@@ -0,0 +1 @@ ++kdcpreauth_otp_initvt +diff --git a/src/plugins/preauth/otp/otp_state.c b/src/plugins/preauth/otp/otp_state.c +new file mode 100644 +index 0000000..95f88e0 +--- /dev/null ++++ b/src/plugins/preauth/otp/otp_state.c +@@ -0,0 +1,560 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* plugins/preauth/otp/otp_state.c - Verify OTP token values using RADIUS */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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 "otp_state.h" ++ ++#include ++#include ++ ++#include ++ ++#ifndef HOST_NAME_MAX ++/* SUSv2 */ ++#define HOST_NAME_MAX 255 ++#endif ++ ++#define DEFAULT_TYPE_NAME "DEFAULT" ++#define DEFAULT_SOCKET_FMT KDC_DIR "/%s.socket" ++#define DEFAULT_TIMEOUT 5 ++#define DEFAULT_RETRIES 3 ++ ++typedef struct token_type_st { ++ char *name; ++ char *server; ++ char *secret; ++ int timeout; ++ size_t retries; ++ krb5_boolean strip_realm; ++} token_type; ++ ++typedef struct token_st { ++ const token_type *type; ++ krb5_data username; ++} token; ++ ++typedef struct request_st { ++ otp_state *state; ++ token *tokens; ++ ssize_t index; ++ otp_cb cb; ++ void *data; ++ krad_attrset *attrs; ++} request; ++ ++struct otp_state_st { ++ krb5_context ctx; ++ token_type *types; ++ krad_client *radius; ++ krad_attrset *attrs; ++}; ++ ++static void request_send(request *req); ++ ++/* Free the contents of a single token type. */ ++static void ++token_type_free(token_type *type) ++{ ++ if (type == NULL) ++ return; ++ ++ free(type->name); ++ free(type->server); ++ free(type->secret); ++} ++ ++/* Construct the internal default token type. */ ++static krb5_error_code ++token_type_default(token_type *out) ++{ ++ char *name = NULL, *server = NULL, *secret = NULL; ++ ++ memset(out, 0, sizeof(*out)); ++ ++ name = strdup(DEFAULT_TYPE_NAME); ++ if (name == NULL) ++ goto oom; ++ if (asprintf(&server, DEFAULT_SOCKET_FMT, name) < 0) ++ goto oom; ++ secret = strdup(""); ++ if (secret == NULL) ++ goto oom; ++ ++ out->name = name; ++ out->server = server; ++ out->secret = secret; ++ out->timeout = DEFAULT_TIMEOUT * 1000; ++ out->retries = DEFAULT_RETRIES; ++ out->strip_realm = FALSE; ++ return 0; ++ ++oom: ++ free(name); ++ free(server); ++ free(secret); ++ return ENOMEM; ++} ++ ++/* Decode a single token type from the profile. */ ++static krb5_error_code ++token_type_decode(profile_t profile, const char *name, token_type *out) ++{ ++ krb5_error_code retval; ++ char *server = NULL, *name_copy = NULL, *secret = NULL; ++ const char *default_secret; ++ int strip_realm, timeout, retries; ++ ++ memset(out, 0, sizeof(*out)); ++ ++ /* Set the name. */ ++ name_copy = strdup(name); ++ if (name_copy == NULL) ++ return ENOMEM; ++ ++ /* Set strip_realm. */ ++ retval = profile_get_boolean(profile, "otp", name, "strip_realm", TRUE, ++ &strip_realm); ++ if (retval != 0) ++ goto cleanup; ++ ++ /* Set the server. */ ++ retval = profile_get_string(profile, "otp", name, "server", NULL, &server); ++ if (retval != 0) ++ goto cleanup; ++ if (server == NULL && asprintf(&server, DEFAULT_SOCKET_FMT, name) < 0) { ++ retval = ENOMEM; ++ goto cleanup; ++ } ++ ++ /* Get the secret (optional for Unix-domain sockets). */ ++ default_secret = (*server == '/') ? "" : NULL; ++ retval = profile_get_string(profile, "otp", name, "secret", default_secret, ++ &secret); ++ if (retval != 0) ++ goto cleanup; ++ if (secret == NULL) { ++ com_err("otp", EINVAL, "Secret not specified in token type '%s'", ++ name); ++ retval = EINVAL; ++ goto cleanup; ++ } ++ ++ /* Get the timeout (profile value in seconds, result in milliseconds). */ ++ retval = profile_get_integer(profile, "otp", name, "timeout", ++ DEFAULT_TIMEOUT, &timeout); ++ if (retval != 0) ++ goto cleanup; ++ timeout *= 1000; ++ ++ /* Get the number of retries. */ ++ retval = profile_get_integer(profile, "otp", name, "retries", ++ DEFAULT_RETRIES, &retries); ++ if (retval != 0) ++ goto cleanup; ++ ++ out->name = name_copy; ++ out->server = server; ++ out->secret = secret; ++ out->timeout = timeout; ++ out->retries = retries; ++ out->strip_realm = strip_realm; ++ name_copy = server = secret = NULL; ++ ++cleanup: ++ free(name_copy); ++ free(server); ++ free(secret); ++ return retval; ++} ++ ++/* Free an array of token types. */ ++static void ++token_types_free(token_type *types) ++{ ++ size_t i; ++ ++ if (types == NULL) ++ return; ++ ++ for (i = 0; types[i].server != NULL; i++) ++ token_type_free(&types[i]); ++ ++ free(types); ++} ++ ++/* Decode an array of token types from the profile. */ ++static krb5_error_code ++token_types_decode(profile_t profile, token_type **out) ++{ ++ const char *hier[2] = { "otp", NULL }; ++ token_type *types = NULL; ++ char **names = NULL; ++ krb5_error_code retval; ++ size_t i, pos; ++ krb5_boolean have_default = FALSE; ++ ++ retval = profile_get_subsection_names(profile, hier, &names); ++ if (retval != 0) ++ return retval; ++ ++ /* Check if any of the profile subsections overrides the default. */ ++ for (i = 0; names[i] != NULL; i++) { ++ if (strcmp(names[i], DEFAULT_TYPE_NAME) == 0) ++ have_default = TRUE; ++ } ++ ++ /* Leave space for the default (possibly) and the terminator. */ ++ types = k5alloc((i + 2) * sizeof(token_type), &retval); ++ if (types == NULL) ++ goto cleanup; ++ ++ /* If no default has been specified, use our internal default. */ ++ pos = 0; ++ if (!have_default) { ++ retval = token_type_default(&types[pos++]); ++ if (retval != 0) ++ goto cleanup; ++ } ++ ++ /* Decode each profile section into a token type element. */ ++ for (i = 0; names[i] != NULL; i++) { ++ retval = token_type_decode(profile, names[i], &types[pos++]); ++ if (retval != 0) ++ goto cleanup; ++ } ++ ++ *out = types; ++ types = NULL; ++ ++cleanup: ++ profile_free_list(names); ++ token_types_free(types); ++ return retval; ++} ++ ++/* Free the contents of a single token. */ ++static void ++token_free_contents(token *t) ++{ ++ if (t != NULL) ++ free(t->username.data); ++} ++ ++/* Decode a single token from a JSON token object. */ ++static krb5_error_code ++token_decode(krb5_context ctx, krb5_const_principal princ, ++ const token_type *types, k5_json_object obj, token *out) ++{ ++ const char *typename = DEFAULT_TYPE_NAME; ++ const token_type *type = NULL; ++ char *username = NULL; ++ krb5_error_code retval; ++ k5_json_value val; ++ size_t i; ++ int flags; ++ ++ memset(out, 0, sizeof(*out)); ++ ++ /* Find the token type. */ ++ val = k5_json_object_get(obj, "type"); ++ if (val != NULL && k5_json_get_tid(val) == K5_JSON_TID_STRING) ++ typename = k5_json_string_utf8(val); ++ for (i = 0; types[i].server != NULL; i++) { ++ if (strcmp(typename, types[i].name) == 0) ++ type = &types[i]; ++ } ++ if (type == NULL) ++ return EINVAL; ++ ++ /* Get the username, either from obj or from unparsing the principal. */ ++ val = k5_json_object_get(obj, "username"); ++ if (val != NULL && k5_json_get_tid(val) == K5_JSON_TID_STRING) { ++ username = strdup(k5_json_string_utf8(val)); ++ if (username == NULL) ++ return ENOMEM; ++ } else { ++ flags = type->strip_realm ? KRB5_PRINCIPAL_UNPARSE_NO_REALM : 0; ++ retval = krb5_unparse_name_flags(ctx, princ, flags, &username); ++ if (retval != 0) ++ return retval; ++ } ++ ++ out->type = type; ++ out->username = string2data(username); ++ return 0; ++} ++ ++/* Free an array of tokens. */ ++static void ++tokens_free(token *tokens) ++{ ++ size_t i; ++ ++ if (tokens == NULL) ++ return; ++ ++ for (i = 0; tokens[i].type != NULL; i++) ++ token_free_contents(&tokens[i]); ++ ++ free(tokens); ++} ++ ++/* Decode an array of tokens from the configuration string. */ ++static krb5_error_code ++tokens_decode(krb5_context ctx, krb5_const_principal princ, ++ const token_type *types, const char *config, token **out) ++{ ++ krb5_error_code retval; ++ k5_json_value arr, obj; ++ token *tokens; ++ ssize_t len, i, j; ++ ++ if (config == NULL) ++ config = "[{}]"; ++ ++ arr = k5_json_decode(config); ++ if (arr == NULL) ++ return ENOMEM; ++ ++ if (k5_json_get_tid(arr) != K5_JSON_TID_ARRAY || ++ (len = k5_json_array_length(arr)) == 0) { ++ k5_json_release(arr); ++ ++ arr = k5_json_decode("[{}]"); ++ if (arr == NULL) ++ return ENOMEM; ++ ++ if (k5_json_get_tid(arr) != K5_JSON_TID_ARRAY) { ++ k5_json_release(arr); ++ return ENOMEM; ++ } ++ ++ len = k5_json_array_length(arr); ++ } ++ ++ tokens = calloc(len + 1, sizeof(token)); ++ if (tokens == NULL) { ++ k5_json_release(arr); ++ return ENOMEM; ++ } ++ ++ for (i = 0, j = 0; i < len; i++) { ++ obj = k5_json_array_get(arr, i); ++ if (k5_json_get_tid(obj) != K5_JSON_TID_OBJECT) ++ continue; ++ ++ retval = token_decode(ctx, princ, types, obj, &tokens[j++]); ++ if (retval != 0) { ++ k5_json_release(arr); ++ while (--j > 0) ++ token_free_contents(&tokens[j]); ++ free(tokens); ++ return retval; ++ } ++ } ++ ++ k5_json_release(arr); ++ *out = tokens; ++ return 0; ++} ++ ++static void ++request_free(request *req) ++{ ++ if (req == NULL) ++ return; ++ ++ krad_attrset_free(req->attrs); ++ tokens_free(req->tokens); ++ free(req); ++} ++ ++krb5_error_code ++otp_state_new(krb5_context ctx, otp_state **out) ++{ ++ char hostname[HOST_NAME_MAX + 1]; ++ krb5_error_code retval; ++ profile_t profile; ++ krb5_data hndata; ++ otp_state *self; ++ ++ retval = gethostname(hostname, sizeof(hostname)); ++ if (retval != 0) ++ return retval; ++ ++ self = calloc(1, sizeof(otp_state)); ++ if (self == NULL) ++ return ENOMEM; ++ ++ retval = krb5_get_profile(ctx, &profile); ++ if (retval != 0) ++ goto error; ++ ++ retval = token_types_decode(profile, &self->types); ++ profile_abandon(profile); ++ if (retval != 0) ++ goto error; ++ ++ retval = krad_attrset_new(ctx, &self->attrs); ++ if (retval != 0) ++ goto error; ++ ++ hndata = make_data(hostname, strlen(hostname)); ++ retval = krad_attrset_add(self->attrs, ++ krad_attr_name2num("NAS-Identifier"), &hndata); ++ if (retval != 0) ++ goto error; ++ ++ retval = krad_attrset_add_number(self->attrs, ++ krad_attr_name2num("Service-Type"), ++ KRAD_SERVICE_TYPE_AUTHENTICATE_ONLY); ++ if (retval != 0) ++ goto error; ++ ++ self->ctx = ctx; ++ *out = self; ++ return 0; ++ ++error: ++ otp_state_free(self); ++ return retval; ++} ++ ++void ++otp_state_free(otp_state *self) ++{ ++ if (self == NULL) ++ return; ++ ++ krad_attrset_free(self->attrs); ++ token_types_free(self->types); ++ free(self); ++} ++ ++static void ++callback(krb5_error_code retval, const krad_packet *rqst, ++ const krad_packet *resp, void *data) ++{ ++ request *req = data; ++ ++ req->index++; ++ ++ if (retval != 0) ++ goto error; ++ ++ /* If we received an accept packet, success! */ ++ if (krad_packet_get_code(resp) == ++ krad_code_name2num("Access-Accept")) { ++ req->cb(req->data, retval, otp_response_success); ++ request_free(req); ++ return; ++ } ++ ++ /* If we have no more tokens to try, failure! */ ++ if (req->tokens[req->index].type == NULL) ++ goto error; ++ ++ /* Try the next token. */ ++ request_send(req); ++ ++error: ++ req->cb(req->data, retval, otp_response_fail); ++ request_free(req); ++} ++ ++static void ++request_send(request *req) ++{ ++ krb5_error_code retval; ++ token *tok = &req->tokens[req->index]; ++ const token_type *t = tok->type; ++ ++ retval = krad_attrset_add(req->attrs, krad_attr_name2num("User-Name"), ++ &tok->username); ++ if (retval != 0) ++ goto error; ++ ++ retval = krad_client_send(req->state->radius, ++ krad_code_name2num("Access-Request"), req->attrs, ++ t->server, t->secret, t->timeout, t->retries, ++ callback, req); ++ krad_attrset_del(req->attrs, krad_attr_name2num("User-Name"), 0); ++ if (retval != 0) ++ goto error; ++ ++ return; ++ ++error: ++ req->cb(req->data, retval, otp_response_fail); ++ request_free(req); ++} ++ ++void ++otp_state_verify(otp_state *state, verto_ctx *ctx, krb5_const_principal princ, ++ const char *config, const krb5_pa_otp_req *req, ++ otp_cb cb, void *data) ++{ ++ krb5_error_code retval; ++ request *rqst = NULL; ++ ++ if (state->radius == NULL) { ++ retval = krad_client_new(state->ctx, ctx, &state->radius); ++ if (retval != 0) ++ goto error; ++ } ++ ++ rqst = calloc(1, sizeof(request)); ++ if (rqst == NULL) { ++ (*cb)(data, ENOMEM, otp_response_fail); ++ return; ++ } ++ rqst->state = state; ++ rqst->data = data; ++ rqst->cb = cb; ++ ++ retval = krad_attrset_copy(state->attrs, &rqst->attrs); ++ if (retval != 0) ++ goto error; ++ ++ retval = krad_attrset_add(rqst->attrs, krad_attr_name2num("User-Password"), ++ &req->otp_value); ++ if (retval != 0) ++ goto error; ++ ++ retval = tokens_decode(state->ctx, princ, state->types, config, ++ &rqst->tokens); ++ if (retval != 0) ++ goto error; ++ ++ request_send(rqst); ++ return; ++ ++error: ++ (*cb)(data, retval, otp_response_fail); ++ request_free(rqst); ++} +diff --git a/src/plugins/preauth/otp/otp_state.h b/src/plugins/preauth/otp/otp_state.h +new file mode 100644 +index 0000000..4247d0b +--- /dev/null ++++ b/src/plugins/preauth/otp/otp_state.h +@@ -0,0 +1,59 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* plugins/preauth/otp/otp_state.h - Internal declarations for OTP module */ ++/* ++ * Copyright 2013 Red Hat, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. 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 OWNER ++ * 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. ++ */ ++ ++#ifndef OTP_H_ ++#define OTP_H_ ++ ++#include ++#include ++ ++#include ++ ++typedef enum otp_response { ++ otp_response_fail = 0, ++ otp_response_success ++ /* Other values reserved for responses like next token or new pin. */ ++} otp_response; ++ ++typedef struct otp_state_st otp_state; ++typedef void ++(*otp_cb)(void *data, krb5_error_code retval, otp_response response); ++ ++krb5_error_code ++otp_state_new(krb5_context ctx, otp_state **self); ++ ++void ++otp_state_free(otp_state *self); ++ ++void ++otp_state_verify(otp_state *state, verto_ctx *ctx, krb5_const_principal princ, ++ const char *config, const krb5_pa_otp_req *request, ++ otp_cb cb, void *data); ++ ++#endif /* OTP_H_ */ +-- +1.8.2.1 + diff --git a/SOURCES/krb5-1.11.2-skew1.patch b/SOURCES/krb5-1.11.2-skew1.patch new file mode 100644 index 0000000..c7dc919 --- /dev/null +++ b/SOURCES/krb5-1.11.2-skew1.patch @@ -0,0 +1,115 @@ +>From 8f6d12bae1a0f1d274593c4a06dfa5948aa61418 Mon Sep 17 00:00:00 2001 +From: Stef Walter +Date: Thu, 23 May 2013 08:38:20 +0200 +Subject: [PATCH 1/2] krb5: Refator duplicate code for setting the AS REQ nonce + +--- + src/lib/krb5/krb/get_in_tkt.c | 64 +++++++++++++++++++++++-------------------- + 1 file changed, 35 insertions(+), 29 deletions(-) + +diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c +index 828b0fb..1058112 100644 +--- a/src/lib/krb5/krb/get_in_tkt.c ++++ b/src/lib/krb5/krb/get_in_tkt.c +@@ -650,6 +650,34 @@ cleanup: + return code; + } + ++static krb5_error_code ++update_req_before_encoding(krb5_context context, krb5_init_creds_context ctx) ++{ ++ krb5_error_code code = 0; ++ unsigned char random_buf[4]; ++ krb5_data random_data; ++ ++ /* ++ * RFC 6113 requires a new nonce for the inner request on each try. It's ++ * permitted to change the nonce even for non-FAST as well. ++ */ ++ random_data.length = 4; ++ random_data.data = (char *)random_buf; ++ code = krb5_c_random_make_octets(context, &random_data); ++ if (code != 0) ++ goto cleanup; ++ ++ /* ++ * See RT ticket 3196 at MIT. If we set the high bit, we may have ++ * compatibility problems with Heimdal, because we (incorrectly) encode ++ * this value as signed. ++ */ ++ ctx->request->nonce = 0x7fffffff & load_32_n(random_buf); ++ ++cleanup: ++ return code; ++} ++ + /** + * Throw away any state related to specific realm either at the beginning of a + * request, or when a realm changes, or when we start to use FAST after +@@ -664,8 +692,6 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, + krb5_pa_data **padata) + { + krb5_error_code code = 0; +- unsigned char random_buf[4]; +- krb5_data random_data; + krb5_timestamp from; + + if (ctx->preauth_to_use) { +@@ -693,18 +719,10 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, + goto cleanup; + } + +- /* Set the request nonce. */ +- random_data.length = 4; +- random_data.data = (char *)random_buf; +- code = krb5_c_random_make_octets(context, &random_data); +- if (code !=0) ++ code = update_req_before_encoding(context, ctx); ++ if (code != 0) + goto cleanup; +- /* +- * See RT ticket 3196 at MIT. If we set the high bit, we may have +- * compatibility problems with Heimdal, because we (incorrectly) encode +- * this value as signed. +- */ +- ctx->request->nonce = 0x7fffffff & load_32_n(random_buf); ++ + krb5_free_principal(context, ctx->request->server); + ctx->request->server = NULL; + +@@ -1188,28 +1206,16 @@ init_creds_step_request(krb5_context context, + { + krb5_error_code code; + krb5_boolean got_real; +- char random_buf[4]; +- krb5_data random_data; + + if (ctx->loopcount >= MAX_IN_TKT_LOOPS) { + code = KRB5_GET_IN_TKT_LOOP; + goto cleanup; + } +- /* +- * RFC 6113 requires a new nonce for the inner request on each try. It's +- * permitted to change the nonce even for non-FAST so we do here. +- */ +- random_data.length = 4; +- random_data.data = (char *)random_buf; +- code = krb5_c_random_make_octets(context, &random_data); +- if (code !=0) ++ ++ code = update_req_before_encoding(context, ctx); ++ if (code != 0) + goto cleanup; +- /* +- * See RT ticket 3196 at MIT. If we set the high bit, we may have +- * compatibility problems with Heimdal, because we (incorrectly) encode +- * this value as signed. +- */ +- ctx->request->nonce = 0x7fffffff & load_32_n(random_buf); ++ + krb5_free_data(context, ctx->inner_request_body); + ctx->inner_request_body = NULL; + code = encode_krb5_kdc_req_body(ctx->request, &ctx->inner_request_body); +-- +1.8.1.4 + diff --git a/SOURCES/krb5-1.11.2-skew2.patch b/SOURCES/krb5-1.11.2-skew2.patch new file mode 100644 index 0000000..d5063bd --- /dev/null +++ b/SOURCES/krb5-1.11.2-skew2.patch @@ -0,0 +1,144 @@ +>From 51ab359d7cc6643cfd4fac28def2e1c756553201 Mon Sep 17 00:00:00 2001 +From: Stef Walter +Date: Thu, 23 May 2013 08:44:43 +0200 +Subject: [PATCH 2/2] krb5: Fix ticket start and end time to respect skew + +Since the kerberos protocol uses timestamp rather than duration deltas +for its starttime, endtime, and renewtime KDC AS REQ fields, we have +to calculate these with respect to the offsets we know about received +from the server. + +Leverage the unauthenticated server time we received during preauth when +calculating these these timestamps from the duration deltas we use +in our krb5 api and tools. + +In order to do this we have to update certain fields of the AS REQ +each time we encode it for sending to the KDC. +--- + src/lib/krb5/krb/get_in_tkt.c | 44 +++++++++++++++++++++++-------------------- + src/lib/krb5/krb/int-proto.h | 5 +++++ + src/lib/krb5/krb/preauth2.c | 8 ++++++++ + 3 files changed, 37 insertions(+), 20 deletions(-) + +diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c +index 1058112..694c9b0b 100644 +--- a/src/lib/krb5/krb/get_in_tkt.c ++++ b/src/lib/krb5/krb/get_in_tkt.c +@@ -656,6 +656,8 @@ update_req_before_encoding(krb5_context context, krb5_init_creds_context ctx) + krb5_error_code code = 0; + unsigned char random_buf[4]; + krb5_data random_data; ++ krb5_timestamp from; ++ krb5_int32 unused; + + /* + * RFC 6113 requires a new nonce for the inner request on each try. It's +@@ -674,6 +676,28 @@ update_req_before_encoding(krb5_context context, krb5_init_creds_context ctx) + */ + ctx->request->nonce = 0x7fffffff & load_32_n(random_buf); + ++ code = k5_preauth_get_time(context, &ctx->preauth_rock, TRUE, &ctx->request_time, &unused); ++ if (code != 0) ++ goto cleanup; ++ ++ /* Omit request start time in the common case. MIT and Heimdal KDCs will ++ * ignore it for non-postdated tickets anyway. */ ++ from = krb5int_addint32(ctx->request_time, ctx->start_time); ++ if (ctx->start_time != 0) ++ ctx->request->from = from; ++ ctx->request->till = krb5int_addint32(from, ctx->tkt_life); ++ ++ if (ctx->renew_life > 0) { ++ ctx->request->rtime = ++ krb5int_addint32(from, ctx->renew_life); ++ if (ctx->request->rtime < ctx->request->till) { ++ /* don't ask for a smaller renewable time than the lifetime */ ++ ctx->request->rtime = ctx->request->till; ++ } ++ ctx->request->kdc_options &= ~(KDC_OPT_RENEWABLE_OK); ++ } else ++ ctx->request->rtime = 0; ++ + cleanup: + return code; + } +@@ -692,7 +716,6 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, + krb5_pa_data **padata) + { + krb5_error_code code = 0; +- krb5_timestamp from; + + if (ctx->preauth_to_use) { + krb5_free_pa_data(context, ctx->preauth_to_use); +@@ -732,8 +755,6 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, + if (code != 0) + goto cleanup; + +- ctx->request_time = time(NULL); +- + code = krb5int_fast_as_armor(context, ctx->fast_state, + ctx->opte, ctx->request); + if (code != 0) +@@ -747,23 +768,6 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, + /* give the preauth plugins a chance to prep the request body */ + krb5_preauth_prepare_request(context, ctx->opte, ctx->request); + +- /* Omit request start time in the common case. MIT and Heimdal KDCs will +- * ignore it for non-postdated tickets anyway. */ +- from = krb5int_addint32(ctx->request_time, ctx->start_time); +- if (ctx->start_time != 0) +- ctx->request->from = from; +- ctx->request->till = krb5int_addint32(from, ctx->tkt_life); +- +- if (ctx->renew_life > 0) { +- ctx->request->rtime = +- krb5int_addint32(from, ctx->renew_life); +- if (ctx->request->rtime < ctx->request->till) { +- /* don't ask for a smaller renewable time than the lifetime */ +- ctx->request->rtime = ctx->request->till; +- } +- ctx->request->kdc_options &= ~(KDC_OPT_RENEWABLE_OK); +- } else +- ctx->request->rtime = 0; + code = krb5int_fast_prep_req_body(context, ctx->fast_state, + ctx->request, + &ctx->outer_request_body); +diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h +index 3326154..83a47c0 100644 +--- a/src/lib/krb5/krb/int-proto.h ++++ b/src/lib/krb5/krb/int-proto.h +@@ -142,6 +142,11 @@ krb5_preauth_supply_preauth_data(krb5_context context, + const char *value); + + krb5_error_code ++k5_preauth_get_time(krb5_context context, krb5_clpreauth_rock rock, ++ krb5_boolean allow_unauth_time, krb5_timestamp *time_out, ++ krb5_int32 *usec_out); ++ ++krb5_error_code + clpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable); + +diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c +index 747611e..167f611 100644 +--- a/src/lib/krb5/krb/preauth2.c ++++ b/src/lib/krb5/krb/preauth2.c +@@ -397,6 +397,15 @@ get_preauth_time(krb5_context context, krb5_clpreauth_rock rock, + krb5_boolean allow_unauth_time, krb5_timestamp *time_out, + krb5_int32 *usec_out) + { ++ return k5_preauth_get_time(context, rock, allow_unauth_time, ++ time_out, usec_out); ++} ++ ++krb5_error_code ++k5_preauth_get_time(krb5_context context, krb5_clpreauth_rock rock, ++ krb5_boolean allow_unauth_time, krb5_timestamp *time_out, ++ krb5_int32 *usec_out) ++{ + if (rock->pa_offset_state != NO_OFFSET && + (allow_unauth_time || rock->pa_offset_state == AUTH_OFFSET) && + (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME)) { +-- +1.8.1.4 + diff --git a/SOURCES/krb5-1.11.3-gss-ccache-import.patch b/SOURCES/krb5-1.11.3-gss-ccache-import.patch new file mode 100644 index 0000000..2bfd927 --- /dev/null +++ b/SOURCES/krb5-1.11.3-gss-ccache-import.patch @@ -0,0 +1,131 @@ +Tweaked for 1.11.3. + +commit 48dd01f29b893a958a64dcf6eb0b734e8463425b +Author: Greg Hudson +Date: Mon Oct 7 09:51:56 2013 -0400 + + Fix GSSAPI krb5 cred ccache import + + json_to_ccache was incorrectly indexing the JSON array when restoring + a memory ccache. Fix it. + + Add test coverage for a multi-cred ccache by exporting/importing the + synthesized S4U2Proxy delegated cred in t_s4u2proxy_krb5.c; move + export_import_cred from t_export_cred.c to common.c to facilitate + this. Make a note in t_export_cred.py that this case is covered in + t_s4u.py. + + ticket: 7706 + target_version: 1.11.4 + +diff --git a/src/lib/gssapi/krb5/import_cred.c b/src/lib/gssapi/krb5/import_cred.c +index 973b9d0..f0a0373 100644 +--- a/src/lib/gssapi/krb5/import_cred.c ++++ b/src/lib/gssapi/krb5/import_cred.c +@@ -486,7 +486,7 @@ json_to_ccache(krb5_context context, k5_json_value v, krb5_ccache *ccache_out, + + /* Add remaining array entries to the ccache as credentials. */ + for (i = 1; i < len; i++) { +- if (json_to_creds(context, k5_json_array_get(array, 1), &creds)) ++ if (json_to_creds(context, k5_json_array_get(array, i), &creds)) + goto invalid; + ret = krb5_cc_store_cred(context, ccache, &creds); + krb5_free_cred_contents(context, &creds); +diff --git a/src/tests/gssapi/common.c b/src/tests/gssapi/common.c +index 19a781a..231f44a 100644 +--- a/src/tests/gssapi/common.c ++++ b/src/tests/gssapi/common.c +@@ -149,6 +149,20 @@ establish_contexts(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred, + } + + void ++export_import_cred(gss_cred_id_t *cred) ++{ ++ OM_uint32 major, minor; ++ gss_buffer_desc buf; ++ ++ major = gss_export_cred(&minor, *cred, &buf); ++ check_gsserr("gss_export_cred", major, minor); ++ (void)gss_release_cred(&minor, cred); ++ major = gss_import_cred(&minor, &buf, cred); ++ check_gsserr("gss_import_cred", major, minor); ++ (void)gss_release_buffer(&minor, &buf); ++} ++ ++void + display_canon_name(const char *tag, gss_name_t name, gss_OID mech) + { + gss_name_t canon; +diff --git a/src/tests/gssapi/common.h b/src/tests/gssapi/common.h +index 54c0d36..ae11b51 100644 +--- a/src/tests/gssapi/common.h ++++ b/src/tests/gssapi/common.h +@@ -62,6 +62,10 @@ void establish_contexts(gss_OID imech, gss_cred_id_t icred, + * 'p:principalname', or 'h:host@service' (or just 'h:service'). */ + gss_name_t import_name(const char *str); + ++/* Export *cred to a token, then release *cred and replace it by re-importing ++ * the token. */ ++void export_import_cred(gss_cred_id_t *cred); ++ + /* Display name as canonicalized to mech, preceded by tag. */ + void display_canon_name(const char *tag, gss_name_t name, gss_OID mech); + +diff --git a/src/tests/gssapi/t_export_cred.c b/src/tests/gssapi/t_export_cred.c +index 5214cd5..4d7c028 100644 +--- a/src/tests/gssapi/t_export_cred.c ++++ b/src/tests/gssapi/t_export_cred.c +@@ -37,22 +37,6 @@ usage(void) + exit(1); + } + +-/* Export *cred to a token, then release *cred and replace it by re-importing +- * the token. */ +-static void +-export_import_cred(gss_cred_id_t *cred) +-{ +- OM_uint32 major, minor; +- gss_buffer_desc buf; +- +- major = gss_export_cred(&minor, *cred, &buf); +- check_gsserr("gss_export_cred", major, minor); +- (void)gss_release_cred(&minor, cred); +- major = gss_import_cred(&minor, &buf, cred); +- check_gsserr("gss_import_cred", major, minor); +- (void)gss_release_buffer(&minor, &buf); +-} +- + int + main(int argc, char *argv[]) + { +diff --git a/src/tests/gssapi/t_export_cred.py b/src/tests/gssapi/t_export_cred.py +index 53dd13c..6988359 100644 +--- a/src/tests/gssapi/t_export_cred.py ++++ b/src/tests/gssapi/t_export_cred.py +@@ -1,7 +1,10 @@ + #!/usr/bin/python + from k5test import * + +-# Test gss_export_cred and gss_import_cred. ++# Test gss_export_cred and gss_import_cred for initiator creds, ++# acceptor creds, and traditional delegated creds. t_s4u.py tests ++# exporting and importing a synthesized S4U2Proxy delegated ++# credential. + + # Make up a filename to hold user's initial credentials. + def ccache_savefile(realm): +diff --git a/src/tests/gssapi/t_s4u2proxy_krb5.c b/src/tests/gssapi/t_s4u2proxy_krb5.c +index 3ad1086..483d915 100644 +--- a/src/tests/gssapi/t_s4u2proxy_krb5.c ++++ b/src/tests/gssapi/t_s4u2proxy_krb5.c +@@ -117,6 +117,10 @@ main(int argc, char *argv[]) + goto cleanup; + } + ++ /* Take the opportunity to test cred export/import on the synthesized ++ * S4U2Proxy delegated cred. */ ++ export_import_cred(&deleg_cred); ++ + /* Store the delegated credentials. */ + ret = krb5_cc_resolve(context, storage_ccname, &storage_ccache); + check_k5err(context, "krb5_cc_resolve", ret); diff --git a/SOURCES/krb5-1.11.3-prompter1.patch b/SOURCES/krb5-1.11.3-prompter1.patch new file mode 100644 index 0000000..e8d393d --- /dev/null +++ b/SOURCES/krb5-1.11.3-prompter1.patch @@ -0,0 +1,91 @@ +commit a8eec52a13ba108b8855aef8cf9dafeb37811d2e +Author: Nalin Dahyabhai +Date: Fri Mar 15 12:05:56 2013 -0400 + + Add PEM password prompter callback in PKINIT + + Supply a callack to PEM_read_bio_PrivateKey() using the prompter to + request a password for encrypted PEM data. Otherwise OpenSSL will use + the controlling terminal. + + [ghudson@mit.edu: minor style cleanup, commit message] + + ticket: 7590 + +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index 6dbda9b..7186ce8 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -656,11 +656,50 @@ cleanup: + return retval; + } + ++struct get_key_cb_data { ++ krb5_context context; ++ pkinit_identity_crypto_context id_cryptoctx; ++ char *filename; ++}; ++ ++static int ++get_key_cb(char *buf, int size, int rwflag, void *userdata) ++{ ++ struct get_key_cb_data *data = userdata; ++ pkinit_identity_crypto_context id_cryptoctx; ++ krb5_data rdat; ++ krb5_prompt kprompt; ++ krb5_prompt_type prompt_type; ++ krb5_error_code retval; ++ char *prompt; ++ ++ if (asprintf(&prompt, "%s %s", _("Pass phrase for"), data->filename) < 0) ++ return -1; ++ rdat.data = buf; ++ rdat.length = size; ++ kprompt.prompt = prompt; ++ kprompt.hidden = 1; ++ kprompt.reply = &rdat; ++ prompt_type = KRB5_PROMPT_TYPE_PREAUTH; ++ ++ /* PROMPTER_INVOCATION */ ++ k5int_set_prompt_types(data->context, &prompt_type); ++ id_cryptoctx = data->id_cryptoctx; ++ retval = data->id_cryptoctx->prompter(data->context, ++ id_cryptoctx->prompter_data, NULL, ++ NULL, 1, &kprompt); ++ k5int_set_prompt_types(data->context, 0); ++ free(prompt); ++ return retval ? -1 : (int)rdat.length; ++} ++ + static krb5_error_code +-get_key(char *filename, EVP_PKEY **retkey) ++get_key(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, ++ char *filename, EVP_PKEY **retkey) + { + EVP_PKEY *pkey = NULL; + BIO *tmp = NULL; ++ struct get_key_cb_data cb_data; + int code; + krb5_error_code retval; + +@@ -676,7 +715,10 @@ get_key(char *filename, EVP_PKEY **retkey) + retval = errno; + goto cleanup; + } +- pkey = (EVP_PKEY *) PEM_read_bio_PrivateKey(tmp, NULL, NULL, NULL); ++ cb_data.context = context; ++ cb_data.id_cryptoctx = id_cryptoctx; ++ cb_data.filename = filename; ++ pkey = PEM_read_bio_PrivateKey(tmp, NULL, get_key_cb, &cb_data); + if (pkey == NULL) { + retval = EIO; + pkiDebug("failed to read private key from %s\n", filename); +@@ -4333,7 +4375,7 @@ pkinit_load_fs_cert_and_key(krb5_context context, + pkiDebug("failed to load user's certificate from '%s'\n", certname); + goto cleanup; + } +- retval = get_key(keyname, &y); ++ retval = get_key(context, id_cryptoctx, keyname, &y); + if (retval != 0 || y == NULL) { + pkiDebug("failed to load user's private key from '%s'\n", keyname); + goto cleanup; diff --git a/SOURCES/krb5-1.11.3-prompter2.patch b/SOURCES/krb5-1.11.3-prompter2.patch new file mode 100644 index 0000000..015284d --- /dev/null +++ b/SOURCES/krb5-1.11.3-prompter2.patch @@ -0,0 +1,55 @@ +Don't call a prompter function if it's NULL, as it can be, depending on +which code path we were called from. Part of the larger responder retrofit +coming in 1.12 (RT#7680). + +--- krb5-1.11.3/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ krb5-1.11.3/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -673,6 +673,8 @@ get_key_cb(char *buf, int size, int rwfl + krb5_error_code retval; + char *prompt; + ++ if (data->id_cryptoctx->prompter == NULL) ++ return -1; + if (asprintf(&prompt, "%s %s", _("Pass phrase for"), data->filename) < 0) + return -1; + rdat.data = buf; +@@ -3739,10 +3741,15 @@ pkinit_login(krb5_context context, + prompt_type = KRB5_PROMPT_TYPE_PREAUTH; + + /* PROMPTER_INVOCATION */ +- k5int_set_prompt_types(context, &prompt_type); +- r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data, +- NULL, NULL, 1, &kprompt); +- k5int_set_prompt_types(context, 0); ++ if (id_cryptoctx->prompter == NULL) { ++ r = KRB5_LIBOS_CANTREADPWD; ++ rdat.data = NULL; ++ } else { ++ k5int_set_prompt_types(context, &prompt_type); ++ r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data, ++ NULL, NULL, 1, &kprompt); ++ k5int_set_prompt_types(context, 0); ++ } + free(prompt); + } + +@@ -4307,10 +4314,15 @@ pkinit_get_certs_pkcs12(krb5_context con + prompt_type = KRB5_PROMPT_TYPE_PREAUTH; + + /* PROMPTER_INVOCATION */ +- k5int_set_prompt_types(context, &prompt_type); +- r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data, +- NULL, NULL, 1, &kprompt); +- k5int_set_prompt_types(context, 0); ++ if (*id_cryptoctx->prompter == NULL) { ++ retval = KRB5_LIBOS_CANTREADPWD; ++ goto cleanup; ++ } else { ++ k5int_set_prompt_types(context, &prompt_type); ++ r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data, ++ NULL, NULL, 1, &kprompt); ++ k5int_set_prompt_types(context, 0); ++ } + + ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL); + if (ret == 0) { diff --git a/SOURCES/krb5-1.11.3-skew3.patch b/SOURCES/krb5-1.11.3-skew3.patch new file mode 100644 index 0000000..0fe0b28 --- /dev/null +++ b/SOURCES/krb5-1.11.3-skew3.patch @@ -0,0 +1,28 @@ +commit 3b1b31a57cd932eda928932e67f5f2857929f429 +Author: Greg Hudson +Date: Sun Jun 2 15:36:40 2013 -0400 + + Fix spurious clock skew caused by preauth delay + + Commit 37b0e55e21926c7875b7176e24e13005920915a6 (#7063) prevented + clock skew caused by preauth delay by recording the time of the + initial request. However, it failed to take into account delay + between requests due to prompting during preauthentication. Fix this + by recording the request time for each request. + + ticket: 7656 (new) + +diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c +index ff455d3..0dd497e 100644 +--- a/src/lib/krb5/krb/get_in_tkt.c ++++ b/src/lib/krb5/krb/get_in_tkt.c +@@ -1256,6 +1256,9 @@ init_creds_step_request(krb5_context context, + } + } + ++ /* Remember when we sent this request (after any preauth delay). */ ++ ctx->request_time = time(NULL); ++ + if (ctx->encoded_previous_request != NULL) { + krb5_free_data(context, ctx->encoded_previous_request); + ctx->encoded_previous_request = NULL; diff --git a/SOURCES/krb5-1.3.1-dns.patch b/SOURCES/krb5-1.3.1-dns.patch new file mode 100644 index 0000000..5d27689 --- /dev/null +++ b/SOURCES/krb5-1.3.1-dns.patch @@ -0,0 +1,12 @@ +We want to be able to use --with-netlib and --enable-dns at the same time. +RT#2022 +--- krb5-1.3.1/src/aclocal.m4 2003-11-24 11:17:30.000000000 -0500 ++++ krb5-1.3.1/src/aclocal.m4 2003-11-24 11:18:45.000000000 -0500 +@@ -647,6 +647,7 @@ + LIBS="$LIBS $withval" + AC_MSG_RESULT("netlib will use \'$withval\'") + fi ++ KRB5_AC_ENABLE_DNS + ],dnl + [AC_LIBRARY_NET] + )])dnl diff --git a/SOURCES/krb5-1.3.4-send-pr-tempfile.patch b/SOURCES/krb5-1.3.4-send-pr-tempfile.patch new file mode 100644 index 0000000..a9ffa31 --- /dev/null +++ b/SOURCES/krb5-1.3.4-send-pr-tempfile.patch @@ -0,0 +1,41 @@ +Use mktemp to create our temporary files instead of basing them on our PID. +Only portable if you assume the presence of a mktemp helper. +diff -ur krb5-1.3.4/src/util/send-pr/send-pr.sh krb5-1.3.4/src/util/send-pr/send-pr.sh +--- krb5-1.3.4/src/util/send-pr/send-pr.sh 1997-03-20 01:13:56.000000000 +0100 ++++ krb5-1.3.4/src/util/send-pr/send-pr.sh 2004-09-20 11:28:56.000000000 +0200 +@@ -96,9 +96,9 @@ + fi + fi + +-TEMP=$TMPDIR/p$$ +-BAD=$TMPDIR/pbad$$ +-REF=$TMPDIR/pf$$ ++TEMP=`mktemp "$TMPDIR"/p.XXXXXX` || exit 1 ++BAD=`mktemp "$TMPDIR"/pbad.XXXXXX` || exit 1 ++REF=`mktemp "$TMPDIR"/pf.XXXXXX` || exit 1 + + # find a user name + if [ "$LOGNAME" = "" ]; then +@@ -122,9 +122,10 @@ + else + # Must use temp file due to incompatibilities in quoting behavior + # and to protect shell metacharacters in the expansion of $LOGNAME +- $PASSWD | grep "^$LOGNAME:" | awk -F: '{print $5}' | sed -e 's/,.*//' > $TEMP +- ORIGINATOR="`cat $TEMP`" +- rm -f $TEMP ++ TEMP2=`mktemp "$TMPDIR"/plogname.XXXXXX` || exit 1 ++ $PASSWD | grep "^$LOGNAME:" | awk -F: '{print $5}' | sed -e 's/,.*//' > $TEMP2 ++ ORIGINATOR="`cat $TEMP2`" ++ rm -f $TEMP2 + fi + + if [ -n "$ORGANIZATION" ]; then +@@ -280,7 +281,7 @@ + # Catch some signals. ($xs kludge needed by Sun /bin/sh) + xs=0 + trap 'rm -f $REF $TEMP; exit $xs' 0 +-trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP; xs=1; exit' 1 2 3 13 15 ++trap 'echo "$COMMAND: Aborting ..."; rm -f "$REF" "$BAD" "$TEMP"; xs=1; exit' 1 2 3 13 15 + + # If they told us to use a specific file, then do so. + if [ -n "$IN_FILE" ]; then diff --git a/SOURCES/krb5-1.7-ktany.patch b/SOURCES/krb5-1.7-ktany.patch new file mode 100644 index 0000000..902f328 --- /dev/null +++ b/SOURCES/krb5-1.7-ktany.patch @@ -0,0 +1,351 @@ +Adds an "ANY" keytab type which is a list of other keytab locations to search +when searching for a specific entry. When iterated through, it only presents +the contents of the first keytab. + +diff -up /dev/null krb5-1.7/src/lib/krb5/keytab/kt_any.c +--- /dev/null 2009-06-04 10:34:55.169007373 -0400 ++++ krb5-1.7/src/lib/krb5/keytab/kt_any.c 2009-06-04 13:54:36.000000000 -0400 +@@ -0,0 +1,292 @@ ++/* ++ * lib/krb5/keytab/kt_any.c ++ * ++ * Copyright 1998, 1999 by the Massachusetts Institute of Technology. ++ * All Rights Reserved. ++ * ++ * Export of this software from the United States of America may ++ * require a specific license from the United States Government. ++ * It is the responsibility of any person or organization contemplating ++ * export to obtain such a license before exporting. ++ * ++ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and ++ * distribute this software and its documentation for any purpose and ++ * without fee is hereby granted, provided that the above copyright ++ * notice appear in all copies and that both that copyright notice and ++ * this permission notice appear in supporting documentation, and that ++ * the name of M.I.T. not be used in advertising or publicity pertaining ++ * to distribution of the software without specific, written prior ++ * permission. M.I.T. makes no representations about the suitability of ++ * this software for any purpose. It is provided "as is" without express ++ * or implied warranty. ++ * ++ * ++ * krb5_kta_ops ++ */ ++ ++#include "k5-int.h" ++ ++typedef struct _krb5_ktany_data { ++ char *name; ++ krb5_keytab *choices; ++ int nchoices; ++} krb5_ktany_data; ++ ++typedef struct _krb5_ktany_cursor_data { ++ int which; ++ krb5_kt_cursor cursor; ++} krb5_ktany_cursor_data; ++ ++static krb5_error_code krb5_ktany_resolve ++ (krb5_context, ++ const char *, ++ krb5_keytab *); ++static krb5_error_code krb5_ktany_get_name ++ (krb5_context context, ++ krb5_keytab id, ++ char *name, ++ unsigned int len); ++static krb5_error_code krb5_ktany_close ++ (krb5_context context, ++ krb5_keytab id); ++static krb5_error_code krb5_ktany_get_entry ++ (krb5_context context, ++ krb5_keytab id, ++ krb5_const_principal principal, ++ krb5_kvno kvno, ++ krb5_enctype enctype, ++ krb5_keytab_entry *entry); ++static krb5_error_code krb5_ktany_start_seq_get ++ (krb5_context context, ++ krb5_keytab id, ++ krb5_kt_cursor *cursorp); ++static krb5_error_code krb5_ktany_next_entry ++ (krb5_context context, ++ krb5_keytab id, ++ krb5_keytab_entry *entry, ++ krb5_kt_cursor *cursor); ++static krb5_error_code krb5_ktany_end_seq_get ++ (krb5_context context, ++ krb5_keytab id, ++ krb5_kt_cursor *cursor); ++static void cleanup ++ (krb5_context context, ++ krb5_ktany_data *data, ++ int nchoices); ++ ++struct _krb5_kt_ops krb5_kta_ops = { ++ 0, ++ "ANY", /* Prefix -- this string should not appear anywhere else! */ ++ krb5_ktany_resolve, ++ krb5_ktany_get_name, ++ krb5_ktany_close, ++ krb5_ktany_get_entry, ++ krb5_ktany_start_seq_get, ++ krb5_ktany_next_entry, ++ krb5_ktany_end_seq_get, ++ NULL, ++ NULL, ++ NULL, ++}; ++ ++static krb5_error_code ++krb5_ktany_resolve(context, name, id) ++ krb5_context context; ++ const char *name; ++ krb5_keytab *id; ++{ ++ const char *p, *q; ++ char *copy; ++ krb5_error_code kerror; ++ krb5_ktany_data *data; ++ int i; ++ ++ /* Allocate space for our data and remember a copy of the name. */ ++ if ((data = (krb5_ktany_data *)malloc(sizeof(krb5_ktany_data))) == NULL) ++ return(ENOMEM); ++ if ((data->name = (char *)malloc(strlen(name) + 1)) == NULL) { ++ krb5_xfree(data); ++ return(ENOMEM); ++ } ++ strcpy(data->name, name); ++ ++ /* Count the number of choices and allocate memory for them. */ ++ data->nchoices = 1; ++ for (p = name; (q = strchr(p, ',')) != NULL; p = q + 1) ++ data->nchoices++; ++ if ((data->choices = (krb5_keytab *) ++ malloc(data->nchoices * sizeof(krb5_keytab))) == NULL) { ++ krb5_xfree(data->name); ++ krb5_xfree(data); ++ return(ENOMEM); ++ } ++ ++ /* Resolve each of the choices. */ ++ i = 0; ++ for (p = name; (q = strchr(p, ',')) != NULL; p = q + 1) { ++ /* Make a copy of the choice name so we can terminate it. */ ++ if ((copy = (char *)malloc(q - p + 1)) == NULL) { ++ cleanup(context, data, i); ++ return(ENOMEM); ++ } ++ memcpy(copy, p, q - p); ++ copy[q - p] = 0; ++ ++ /* Try resolving the choice name. */ ++ kerror = krb5_kt_resolve(context, copy, &data->choices[i]); ++ krb5_xfree(copy); ++ if (kerror) { ++ cleanup(context, data, i); ++ return(kerror); ++ } ++ i++; ++ } ++ if ((kerror = krb5_kt_resolve(context, p, &data->choices[i]))) { ++ cleanup(context, data, i); ++ return(kerror); ++ } ++ ++ /* Allocate and fill in an ID for the caller. */ ++ if ((*id = (krb5_keytab)malloc(sizeof(**id))) == NULL) { ++ cleanup(context, data, i); ++ return(ENOMEM); ++ } ++ (*id)->ops = &krb5_kta_ops; ++ (*id)->data = (krb5_pointer)data; ++ (*id)->magic = KV5M_KEYTAB; ++ ++ return(0); ++} ++ ++static krb5_error_code ++krb5_ktany_get_name(context, id, name, len) ++ krb5_context context; ++ krb5_keytab id; ++ char *name; ++ unsigned int len; ++{ ++ krb5_ktany_data *data = (krb5_ktany_data *)id->data; ++ ++ if (len < strlen(data->name) + 1) ++ return(KRB5_KT_NAME_TOOLONG); ++ strcpy(name, data->name); ++ return(0); ++} ++ ++static krb5_error_code ++krb5_ktany_close(context, id) ++ krb5_context context; ++ krb5_keytab id; ++{ ++ krb5_ktany_data *data = (krb5_ktany_data *)id->data; ++ ++ cleanup(context, data, data->nchoices); ++ id->ops = 0; ++ krb5_xfree(id); ++ return(0); ++} ++ ++static krb5_error_code ++krb5_ktany_get_entry(context, id, principal, kvno, enctype, entry) ++ krb5_context context; ++ krb5_keytab id; ++ krb5_const_principal principal; ++ krb5_kvno kvno; ++ krb5_enctype enctype; ++ krb5_keytab_entry *entry; ++{ ++ krb5_ktany_data *data = (krb5_ktany_data *)id->data; ++ krb5_error_code kerror = KRB5_KT_NOTFOUND; ++ int i; ++ ++ for (i = 0; i < data->nchoices; i++) { ++ if ((kerror = krb5_kt_get_entry(context, data->choices[i], principal, ++ kvno, enctype, entry)) != ENOENT) ++ return kerror; ++ } ++ return kerror; ++} ++ ++static krb5_error_code ++krb5_ktany_start_seq_get(context, id, cursorp) ++ krb5_context context; ++ krb5_keytab id; ++ krb5_kt_cursor *cursorp; ++{ ++ krb5_ktany_data *data = (krb5_ktany_data *)id->data; ++ krb5_ktany_cursor_data *cdata; ++ krb5_error_code kerror = ENOENT; ++ int i; ++ ++ if ((cdata = (krb5_ktany_cursor_data *) ++ malloc(sizeof(krb5_ktany_cursor_data))) == NULL) ++ return(ENOMEM); ++ ++ /* Find a choice which can handle the serialization request. */ ++ for (i = 0; i < data->nchoices; i++) { ++ if ((kerror = krb5_kt_start_seq_get(context, data->choices[i], ++ &cdata->cursor)) == 0) ++ break; ++ else if (kerror != ENOENT) { ++ krb5_xfree(cdata); ++ return(kerror); ++ } ++ } ++ ++ if (i == data->nchoices) { ++ /* Everyone returned ENOENT, so no go. */ ++ krb5_xfree(cdata); ++ return(kerror); ++ } ++ ++ cdata->which = i; ++ *cursorp = (krb5_kt_cursor)cdata; ++ return(0); ++} ++ ++static krb5_error_code ++krb5_ktany_next_entry(context, id, entry, cursor) ++ krb5_context context; ++ krb5_keytab id; ++ krb5_keytab_entry *entry; ++ krb5_kt_cursor *cursor; ++{ ++ krb5_ktany_data *data = (krb5_ktany_data *)id->data; ++ krb5_ktany_cursor_data *cdata = (krb5_ktany_cursor_data *)*cursor; ++ krb5_keytab choice_id; ++ ++ choice_id = data->choices[cdata->which]; ++ return(krb5_kt_next_entry(context, choice_id, entry, &cdata->cursor)); ++} ++ ++static krb5_error_code ++krb5_ktany_end_seq_get(context, id, cursor) ++ krb5_context context; ++ krb5_keytab id; ++ krb5_kt_cursor *cursor; ++{ ++ krb5_ktany_data *data = (krb5_ktany_data *)id->data; ++ krb5_ktany_cursor_data *cdata = (krb5_ktany_cursor_data *)*cursor; ++ krb5_keytab choice_id; ++ krb5_error_code kerror; ++ ++ choice_id = data->choices[cdata->which]; ++ kerror = krb5_kt_end_seq_get(context, choice_id, &cdata->cursor); ++ krb5_xfree(cdata); ++ return(kerror); ++} ++ ++static void ++cleanup(context, data, nchoices) ++ krb5_context context; ++ krb5_ktany_data *data; ++ int nchoices; ++{ ++ int i; ++ ++ krb5_xfree(data->name); ++ for (i = 0; i < nchoices; i++) ++ krb5_kt_close(context, data->choices[i]); ++ krb5_xfree(data->choices); ++ krb5_xfree(data); ++} +diff -up krb5-1.7/src/lib/krb5/keytab/ktbase.c krb5-1.7/src/lib/krb5/keytab/ktbase.c +--- krb5-1.7/src/lib/krb5/keytab/ktbase.c 2009-02-18 13:18:56.000000000 -0500 ++++ krb5-1.7/src/lib/krb5/keytab/ktbase.c 2009-06-04 13:54:36.000000000 -0400 +@@ -59,14 +59,19 @@ extern const krb5_kt_ops krb5_ktf_ops; + extern const krb5_kt_ops krb5_ktf_writable_ops; + extern const krb5_kt_ops krb5_kts_ops; + extern const krb5_kt_ops krb5_mkt_ops; ++extern const krb5_kt_ops krb5_kta_ops; + + struct krb5_kt_typelist { + const krb5_kt_ops *ops; + const struct krb5_kt_typelist *next; + }; ++static struct krb5_kt_typelist krb5_kt_typelist_any = { ++ &krb5_kta_ops, ++ NULL ++}; + const static struct krb5_kt_typelist krb5_kt_typelist_srvtab = { + &krb5_kts_ops, +- NULL ++ &krb5_kt_typelist_any + }; + const static struct krb5_kt_typelist krb5_kt_typelist_memory = { + &krb5_mkt_ops, +diff -up krb5-1.7/src/lib/krb5/keytab/Makefile.in krb5-1.7/src/lib/krb5/keytab/Makefile.in +--- krb5-1.7/src/lib/krb5/keytab/Makefile.in 2009-01-05 15:27:53.000000000 -0500 ++++ krb5-1.7/src/lib/krb5/keytab/Makefile.in 2009-06-04 13:54:36.000000000 -0400 +@@ -19,6 +19,7 @@ STLIBOBJS= \ + ktfr_entry.o \ + ktremove.o \ + ktfns.o \ ++ kt_any.o \ + kt_file.o \ + kt_memory.o \ + kt_srvtab.o \ +@@ -31,6 +32,7 @@ OBJS= \ + $(OUTPRE)ktfr_entry.$(OBJEXT) \ + $(OUTPRE)ktremove.$(OBJEXT) \ + $(OUTPRE)ktfns.$(OBJEXT) \ ++ $(OUTPRE)kt_any.$(OBJEXT) \ + $(OUTPRE)kt_file.$(OBJEXT) \ + $(OUTPRE)kt_memory.$(OBJEXT) \ + $(OUTPRE)kt_srvtab.$(OBJEXT) \ +@@ -43,6 +45,7 @@ SRCS= \ + $(srcdir)/ktfr_entry.c \ + $(srcdir)/ktremove.c \ + $(srcdir)/ktfns.c \ ++ $(srcdir)/kt_any.c \ + $(srcdir)/kt_file.c \ + $(srcdir)/kt_memory.c \ + $(srcdir)/kt_srvtab.c \ diff --git a/SOURCES/krb5-1.8-api.patch b/SOURCES/krb5-1.8-api.patch new file mode 100644 index 0000000..9cc9cd2 --- /dev/null +++ b/SOURCES/krb5-1.8-api.patch @@ -0,0 +1,30 @@ +Reference docs don't define what happens if you call krb5_realm_compare() with +malformed krb5_principal structures. Define a behavior which keeps it from +crashing if applications don't check ahead of time. + +diff -up krb5-1.8/src/lib/krb5/krb/princ_comp.c.api krb5-1.8/src/lib/krb5/krb/princ_comp.c +--- krb5-1.8/src/lib/krb5/krb/princ_comp.c.api 2009-10-30 20:48:38.000000000 -0400 ++++ krb5-1.8/src/lib/krb5/krb/princ_comp.c 2010-03-05 11:00:55.000000000 -0500 +@@ -41,6 +41,12 @@ realm_compare_flags(krb5_context context + const krb5_data *realm1 = krb5_princ_realm(context, princ1); + const krb5_data *realm2 = krb5_princ_realm(context, princ2); + ++ if ((princ1 == NULL) || (princ2 == NULL)) ++ return FALSE; ++ ++ if ((realm1 == NULL) || (realm2 == NULL)) ++ return FALSE; ++ + if (realm1->length != realm2->length) + return FALSE; + +@@ -92,6 +98,9 @@ krb5_principal_compare_flags(krb5_contex + krb5_principal upn2 = NULL; + krb5_boolean ret = FALSE; + ++ if ((princ1 == NULL) || (princ2 == NULL)) ++ return FALSE; ++ + if (flags & KRB5_PRINCIPAL_COMPARE_ENTERPRISE) { + /* Treat UPNs as if they were real principals */ + if (krb5_princ_type(context, princ1) == KRB5_NT_ENTERPRISE_PRINCIPAL) { diff --git a/SOURCES/krb5-1.9-debuginfo.patch b/SOURCES/krb5-1.9-debuginfo.patch new file mode 100644 index 0000000..ae81f7c --- /dev/null +++ b/SOURCES/krb5-1.9-debuginfo.patch @@ -0,0 +1,26 @@ +We want to keep these y.tab.c files around because the debuginfo points to +them. It would be more elegant at the end to use symbolic links, but that +could mess up people working in the tree on other things. + +--- src/kadmin/cli/Makefile.in ++++ src/kadmin/cli/Makefile.in +@@ -43,3 +43,8 @@ clean-unix:: + # CC_LINK is not meant for compilation and this use may break in the future. + datetest: getdate.c + $(CC_LINK) $(ALL_CFLAGS) -DTEST -o datetest getdate.c ++ ++%.c: %.y ++ $(RM) y.tab.c $@ ++ $(YACC.y) $< ++ $(CP) y.tab.c $@ +--- src/plugins/kdb/ldap/ldap_util/Makefile.in ++++ src/plugins/kdb/ldap/ldap_util/Makefile.in +@@ -22,7 +22,7 @@ $(PROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KR + getdate.c: $(GETDATE) + $(RM) getdate.c y.tab.c + $(YACC) $(GETDATE) +- $(MV) y.tab.c getdate.c ++ $(CP) y.tab.c getdate.c + + install:: + $(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG) diff --git a/SOURCES/krb5-aarch64.patch b/SOURCES/krb5-aarch64.patch new file mode 100644 index 0000000..fd8649e --- /dev/null +++ b/SOURCES/krb5-aarch64.patch @@ -0,0 +1,411 @@ +diff -urN krb5-1.11.1/src/config/config.guess krb5-1.11.1-aarch64/src/config/config.guess +--- krb5-1.11.1/src/config/config.guess 2013-02-21 17:23:19.000000000 -0600 ++++ krb5-1.11.1-aarch64/src/config/config.guess 2013-03-08 01:18:32.742187563 -0600 +@@ -2,9 +2,9 @@ + # Attempt to guess a canonical system name. + # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +-# 2011 Free Software Foundation, Inc. ++# 2011, 2012 Free Software Foundation, Inc. + +-timestamp='2011-08-20' ++timestamp='2012-09-25' + + # This file is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by +@@ -17,9 +17,7 @@ + # General Public License for more details. + # + # You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +-# 02110-1301, USA. ++# along with this program; if not, see . + # + # As a special exception to the GNU General Public License, if you + # distribute this file as part of a program that contains a +@@ -57,8 +55,8 @@ + + Originally written by Per Bothner. + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free +-Software Foundation, Inc. ++2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 ++Free Software Foundation, Inc. + + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." +@@ -145,7 +143,7 @@ + case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or +- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, ++ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward +@@ -202,6 +200,10 @@ + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; ++ *:Bitrig:*:*) ++ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` ++ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} ++ exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} +@@ -304,7 +306,7 @@ + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; +- arm:riscos:*:*|arm:RISCOS:*:*) ++ arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) +@@ -803,9 +805,15 @@ + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; ++ *:MINGW64*:*) ++ echo ${UNAME_MACHINE}-pc-mingw64 ++ exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; ++ i*:MSYS*:*) ++ echo ${UNAME_MACHINE}-pc-msys ++ exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 +@@ -860,6 +868,13 @@ + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; ++ aarch64:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ aarch64_be:Linux:*:*) ++ UNAME_MACHINE=aarch64_be ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; +@@ -894,13 +909,16 @@ + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) +- echo cris-axis-linux-gnu ++ echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) +- echo crisv32-axis-linux-gnu ++ echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + frv:Linux:*:*) +- echo frv-unknown-linux-gnu ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ hexagon:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu +@@ -942,7 +960,7 @@ + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) +- echo or32-unknown-linux-gnu ++ echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu +@@ -983,7 +1001,7 @@ + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) +- echo x86_64-unknown-linux-gnu ++ echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu +@@ -1190,6 +1208,9 @@ + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; ++ x86_64:Haiku:*:*) ++ echo x86_64-unknown-haiku ++ exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; +@@ -1245,7 +1266,7 @@ + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; +- NSE-?:NONSTOP_KERNEL:*:*) ++ NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) +@@ -1314,11 +1335,11 @@ + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; ++ x86_64:VMkernel:*:*) ++ echo ${UNAME_MACHINE}-unknown-esx ++ exit ;; + esac + +-#echo '(No uname command or uname output not recognized.)' 1>&2 +-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 +- + eval $set_cc_for_build + cat >$dummy.c <. + # + # As a special exception to the GNU General Public License, if you + # distribute this file as part of a program that contains a +@@ -76,8 +74,8 @@ + GNU config.sub ($timestamp) + + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free +-Software Foundation, Inc. ++2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 ++Free Software Foundation, Inc. + + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." +@@ -125,13 +123,17 @@ + maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` + case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ +- linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ ++ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; ++ android-linux) ++ os=-linux-android ++ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ++ ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] +@@ -154,7 +156,7 @@ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ +- -apple | -axis | -knuth | -cray | -microblaze) ++ -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; +@@ -223,6 +225,12 @@ + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; ++ -lynx*178) ++ os=-lynxos178 ++ ;; ++ -lynx*5) ++ os=-lynxos5 ++ ;; + -lynx*) + os=-lynxos + ;; +@@ -247,6 +255,7 @@ + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ ++ | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ +@@ -255,14 +264,16 @@ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ ++ | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ ++ | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ +- | maxq | mb | microblaze | mcore | mep | metag \ ++ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ +@@ -293,7 +304,7 @@ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ +- | rx \ ++ | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ +@@ -317,8 +328,7 @@ + c6x) + basic_machine=tic6x-unknown + ;; +- m6811 | m68hc11 | m6812 | m68hc12 | picochip) +- # Motorola 68HC11/12. ++ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; +@@ -331,7 +341,10 @@ + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; +- ++ xgate) ++ basic_machine=$basic_machine-unknown ++ os=-none ++ ;; + xscaleeb) + basic_machine=armeb-unknown + ;; +@@ -354,6 +367,7 @@ + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ ++ | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ +@@ -368,13 +382,15 @@ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ ++ | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ +- | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ ++ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ ++ | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ +@@ -404,7 +420,7 @@ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ +- | romp-* | rs6000-* | rx-* \ ++ | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ +@@ -716,7 +732,6 @@ + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +-# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 +@@ -774,9 +789,13 @@ + basic_machine=ns32k-utek + os=-sysv + ;; +- microblaze) ++ microblaze*) + basic_machine=microblaze-xilinx + ;; ++ mingw64) ++ basic_machine=x86_64-pc ++ os=-mingw64 ++ ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 +@@ -813,6 +832,10 @@ + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; ++ msys) ++ basic_machine=i386-pc ++ os=-msys ++ ;; + mvs) + basic_machine=i370-ibm + os=-mvs +@@ -1334,15 +1357,15 @@ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ +- | -openbsd* | -solidbsd* \ ++ | -bitrig* | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ +- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ +- | -mingw32* | -linux-gnu* | -linux-android* \ +- | -linux-newlib* | -linux-uclibc* \ ++ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ ++ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ ++ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ +@@ -1525,6 +1548,9 @@ + c4x-* | tic4x-*) + os=-coff + ;; ++ hexagon-*) ++ os=-elf ++ ;; + tic54x-*) + os=-coff + ;; +@@ -1552,9 +1578,6 @@ + ;; + m68000-sun) + os=-sunos3 +- # This also exists in the configure program, but was not the +- # default. +- # os=-sunos4 + ;; + m68*-cisco) + os=-aout diff --git a/SOURCES/krb5-cccol-primary.patch b/SOURCES/krb5-cccol-primary.patch new file mode 100644 index 0000000..f64b1f0 --- /dev/null +++ b/SOURCES/krb5-cccol-primary.patch @@ -0,0 +1,85 @@ +commit b874882dc93e5ece4f7218617ed7942656985471 +Author: Greg Hudson +Date: Mon Apr 22 17:00:35 2013 -0400 + + Include default DIR::file ccache in collection + + If the context's default ccache name is a subsidiary file of a + directory collection, include that single cache in the cursor walk + over the DIR type. + + ticket: 7172 + +diff --git a/src/lib/krb5/ccache/cc_dir.c b/src/lib/krb5/ccache/cc_dir.c +index cee21ac..b8231ed 100644 +--- a/src/lib/krb5/ccache/cc_dir.c ++++ b/src/lib/krb5/ccache/cc_dir.c +@@ -266,6 +266,28 @@ get_context_default_dir(krb5_context context, char **dirname_out) + return 0; + } + ++/* ++ * If the default ccache name for context is a subsidiary file in a directory ++ * collection, set *subsidiary_out to the residual value. Otherwise set ++ * *subsidiary_out to NULL. ++ */ ++static krb5_error_code ++get_context_subsidiary_file(krb5_context context, char **subsidiary_out) ++{ ++ const char *defname; ++ char *residual; ++ ++ *subsidiary_out = NULL; ++ defname = krb5_cc_default_name(context); ++ if (defname == NULL || strncmp(defname, "DIR::", 5) != 0) ++ return 0; ++ residual = strdup(defname + 4); ++ if (residual == NULL) ++ return ENOMEM; ++ *subsidiary_out = residual; ++ return 0; ++} ++ + static const char * KRB5_CALLCONV + dcc_get_name(krb5_context context, krb5_ccache cache) + { +@@ -562,6 +584,18 @@ dcc_ptcursor_new(krb5_context context, krb5_cc_ptcursor *cursor_out) + + *cursor_out = NULL; + ++ /* If the default cache is a subsidiary file, make a cursor with the ++ * specified file as the primary but with no directory collection. */ ++ ret = get_context_subsidiary_file(context, &primary); ++ if (ret) ++ goto cleanup; ++ if (primary != NULL) { ++ ret = make_cursor(NULL, primary, NULL, cursor_out); ++ if (ret) ++ free(primary); ++ return ret; ++ } ++ + /* Open the directory for the context's default cache. */ + ret = get_context_default_dir(context, &dirname); + if (ret || dirname == NULL) +@@ -607,16 +641,17 @@ dcc_ptcursor_next(krb5_context context, krb5_cc_ptcursor cursor, + struct stat sb; + + *cache_out = NULL; +- if (data->dir == NULL) /* Empty cursor */ +- return 0; + +- /* Return the primary cache if we haven't yet. */ ++ /* Return the primary or specified subsidiary cache if we haven't yet. */ + if (data->first) { + data->first = FALSE; + if (data->primary != NULL && stat(data->primary + 1, &sb) == 0) + return dcc_resolve(context, cache_out, data->primary); + } + ++ if (data->dir == NULL) /* No directory collection */ ++ return 0; ++ + /* Look for the next filename of the correct form, without repeating the + * primary cache. */ + while ((ent = readdir(data->dir)) != NULL) { diff --git a/SOURCES/krb5-kvno-230379.patch b/SOURCES/krb5-kvno-230379.patch new file mode 100644 index 0000000..ea9b69f --- /dev/null +++ b/SOURCES/krb5-kvno-230379.patch @@ -0,0 +1,53 @@ +From patch attached to http://krbdev.mit.edu/rt/Ticket/Display.html?id=3349, +at http://krbdev.mit.edu/rt/Ticket/Attachment/23851/13214/kvno.diff, adjusted +as needed to apply to 1.10. FIXME: I'd like to better handle cases where we +have a new key with the right version stored later in the keytab file. +Currently, we're setting up to overlook that possibility. + +Note that this only affects the path taken when krb5_rd_rep() is passed a +server principal name, as without a server principal name it already tries +all of the keys it finds in the keytab, regardless of version numbers. + +Index: krb5/src/kadmin/ktutil/ktutil.c +=================================================================== +--- krb5/src/kadmin/ktutil/ktutil.c (revision 3367) ++++ krb5/src/kadmin/ktutil/ktutil.c (working copy) +@@ -155,7 +155,7 @@ + char *princ = NULL; + char *enctype = NULL; + krb5_kvno kvno = 0; +- int use_pass = 0, use_key = 0, i; ++ int use_pass = 0, use_key = 0, use_kvno = 0, i; + + for (i = 1; i < argc; i++) { + if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-p", 2)) { +@@ -164,6 +164,7 @@ + } + if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-k", 2)) { + kvno = (krb5_kvno) atoi(argv[++i]); ++ use_kvno++; + continue; + } + if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-e", 2)) { +@@ -180,7 +181,7 @@ + } + } + +- if (argc != 8 || !(princ && kvno && enctype) || (use_pass+use_key != 1)) { ++ if (argc != 8 || !(princ && use_kvno && enctype) || (use_pass+use_key != 1)) { + fprintf(stderr, _("usage: %s (-key | -password) -p principal " + "-k kvno -e enctype\n"), argv[0]); + return; +Index: krb5/src/lib/krb5/keytab/kt_file.c +=================================================================== +--- krb5/src/lib/krb5/keytab/kt_file.c (revision 3367) ++++ krb5/src/lib/krb5/keytab/kt_file.c (working copy) +@@ -349,7 +349,7 @@ + higher than that. Short-term workaround: only compare + the low 8 bits. */ + +- if (new_entry.vno == (kvno & 0xff)) { ++ if (new_entry.vno == (kvno & 0xff) || new_entry.vno == IGNORE_VNO) { + krb5_kt_free_entry(context, &cur_entry); + cur_entry = new_entry; + break; diff --git a/SOURCES/krb5-master-init_referral.patch b/SOURCES/krb5-master-init_referral.patch new file mode 100644 index 0000000..ae3d3b8 --- /dev/null +++ b/SOURCES/krb5-master-init_referral.patch @@ -0,0 +1,47 @@ +commit a12a5ddb9b932061bad7b83df058c7c6e2e4b044 +Author: Greg Hudson +Date: Thu May 30 11:39:54 2013 -0400 + + Properly handle use_master in k5_init_creds_get + + If we make multiple requests in an initial creds exchange, the + krb5_sendto_kdc call in k5_init_creds_get may flip the use_master + value from 0 to 1 if it detects that the response was from a master + KDC. Don't turn this into a requirement for future requests during + the same exchange, or we may have trouble following AS referrals. + Reported by Sumit Bose. + + ticket: 7650 + +diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c +index 20bc689..ff455d3 100644 +--- a/src/lib/krb5/krb/get_in_tkt.c ++++ b/src/lib/krb5/krb/get_in_tkt.c +@@ -521,7 +521,7 @@ k5_init_creds_get(krb5_context context, krb5_init_creds_context ctx, + krb5_data reply; + krb5_data realm; + unsigned int flags = 0; +- int tcp_only = 0; ++ int tcp_only = 0, master = *use_master; + + request.length = 0; + request.data = NULL; +@@ -545,8 +545,9 @@ k5_init_creds_get(krb5_context context, krb5_init_creds_context ctx, + + krb5_free_data_contents(context, &reply); + ++ master = *use_master; + code = krb5_sendto_kdc(context, &request, &realm, +- &reply, use_master, tcp_only); ++ &reply, &master, tcp_only); + if (code != 0) + break; + +@@ -558,6 +559,7 @@ k5_init_creds_get(krb5_context context, krb5_init_creds_context ctx, + krb5_free_data_contents(context, &reply); + krb5_free_data_contents(context, &realm); + ++ *use_master = master; + return code; + } + diff --git a/SOURCES/krb5-master-kinit-cccol.patch b/SOURCES/krb5-master-kinit-cccol.patch new file mode 100644 index 0000000..58542fd --- /dev/null +++ b/SOURCES/krb5-master-kinit-cccol.patch @@ -0,0 +1,314 @@ +commit d7b94742daae85329067b126d0a4bc5b2ea7e4a0 +Author: Greg Hudson +Date: Thu Sep 26 05:38:46 2013 -0400 + + Improve kinit output credential cache selection + + If kinit chooses a client principal based on anything other than the + current default ccache's principal name, apply collection rules if + possible. When applying collection rules, if we don't find an + existing cache for the client principal, use the default cache if it + is uninitialized, instead of creating a new one. + + ticket: 7689 + +diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c +index 5ceede8..d9033ec 100644 +--- a/src/clients/kinit/kinit.c ++++ b/src/clients/kinit/kinit.c +@@ -466,9 +466,12 @@ k5_begin(opts, k5) + struct k5_data* k5; + { + krb5_error_code code = 0; ++ int success = 0; + int flags = opts->enterprise ? KRB5_PRINCIPAL_PARSE_ENTERPRISE : 0; +- krb5_ccache defcache; +- const char *deftype; ++ krb5_ccache defcache = NULL; ++ krb5_principal defcache_princ = NULL, princ; ++ const char *deftype = NULL; ++ char *defrealm, *name; + + code = krb5_init_context(&k5->ctx); + if (code) { +@@ -477,73 +480,153 @@ k5_begin(opts, k5) + } + errctx = k5->ctx; + +- /* Parse specified principal name now if we got one. */ +- if (opts->principal_name) { +- if ((code = krb5_parse_name_flags(k5->ctx, opts->principal_name, +- flags, &k5->me))) { +- com_err(progname, code, _("when parsing name %s"), +- opts->principal_name); +- return 0; +- } +- } +- + if (opts->k5_out_cache_name) { + code = krb5_cc_resolve(k5->ctx, opts->k5_out_cache_name, &k5->out_cc); + if (code != 0) { + com_err(progname, code, _("resolving ccache %s"), + opts->k5_out_cache_name); +- return 0; ++ goto cleanup; + } + if (opts->verbose) { + fprintf(stderr, _("Using specified cache: %s\n"), + opts->k5_out_cache_name); + } + } else { +- if ((code = krb5_cc_default(k5->ctx, &defcache))) { ++ /* Resolve the default ccache and get its type and default principal ++ * (if it is initialized). */ ++ code = krb5_cc_default(k5->ctx, &defcache); ++ if (code) { + com_err(progname, code, _("while getting default ccache")); +- return 0; ++ goto cleanup; + } + deftype = krb5_cc_get_type(k5->ctx, defcache); +- if (k5->me != NULL && krb5_cc_support_switch(k5->ctx, deftype)) { +- /* Use an existing cache for the specified principal if we can. */ +- code = krb5_cc_cache_match(k5->ctx, k5->me, &k5->out_cc); +- if (code != 0 && code != KRB5_CC_NOTFOUND) { +- com_err(progname, code, _("while searching for ccache for %s"), +- opts->principal_name); +- krb5_cc_close(k5->ctx, defcache); +- return 0; ++ if (krb5_cc_get_principal(k5->ctx, defcache, &defcache_princ) != 0) ++ defcache_princ = NULL; ++ } ++ ++ /* Choose a client principal name. */ ++ if (opts->principal_name != NULL) { ++ /* Use the specified principal name. */ ++ code = krb5_parse_name_flags(k5->ctx, opts->principal_name, flags, ++ &k5->me); ++ if (code) { ++ com_err(progname, code, _("when parsing name %s"), ++ opts->principal_name); ++ goto cleanup; ++ } ++ } else if (opts->anonymous) { ++ /* Use the anonymous principal for the local realm. */ ++ code = krb5_get_default_realm(k5->ctx, &defrealm); ++ if (code) { ++ com_err(progname, code, _("while getting default realm")); ++ goto cleanup; ++ } ++ code = krb5_build_principal_ext(k5->ctx, &k5->me, ++ strlen(defrealm), defrealm, ++ strlen(KRB5_WELLKNOWN_NAMESTR), ++ KRB5_WELLKNOWN_NAMESTR, ++ strlen(KRB5_ANONYMOUS_PRINCSTR), ++ KRB5_ANONYMOUS_PRINCSTR, ++ 0); ++ krb5_free_default_realm(k5->ctx, defrealm); ++ if (code) { ++ com_err(progname, code, _("while building principal")); ++ goto cleanup; ++ } ++ } else if (opts->action == INIT_KT) { ++ /* Use the default host/service name. */ ++ code = krb5_sname_to_principal(k5->ctx, NULL, NULL, KRB5_NT_SRV_HST, ++ &k5->me); ++ if (code) { ++ com_err(progname, code, ++ _("when creating default server principal name")); ++ goto cleanup; ++ } ++ if (k5->me->realm.data[0] == 0) { ++ code = krb5_unparse_name(k5->ctx, k5->me, &k5->name); ++ if (code == 0) { ++ com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN, ++ _("(principal %s)"), k5->name); ++ } else { ++ com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN, ++ _("for local services")); + } +- if (code == KRB5_CC_NOTFOUND) { +- code = krb5_cc_new_unique(k5->ctx, deftype, NULL, &k5->out_cc); +- if (code) { +- com_err(progname, code, _("while generating new ccache")); +- krb5_cc_close(k5->ctx, defcache); +- return 0; +- } +- if (opts->verbose) { +- fprintf(stderr, _("Using new cache: %s\n"), +- krb5_cc_get_name(k5->ctx, k5->out_cc)); +- } +- } else if (opts->verbose) { ++ goto cleanup; ++ } ++ } else if (k5->out_cc != NULL) { ++ /* If the output ccache is initialized, use its principal. */ ++ if (krb5_cc_get_principal(k5->ctx, k5->out_cc, &princ) == 0) ++ k5->me = princ; ++ } else if (defcache_princ != NULL) { ++ /* Use the default cache's principal, and use the default cache as the ++ * output cache. */ ++ k5->out_cc = defcache; ++ defcache = NULL; ++ k5->me = defcache_princ; ++ defcache_princ = NULL; ++ } ++ ++ /* If we still haven't chosen, use the local username. */ ++ if (k5->me == NULL) { ++ name = get_name_from_os(); ++ if (name == NULL) { ++ fprintf(stderr, _("Unable to identify user\n")); ++ goto cleanup; ++ } ++ code = krb5_parse_name_flags(k5->ctx, name, flags, &k5->me); ++ if (code) { ++ com_err(progname, code, _("when parsing name %s"), ++ name); ++ goto cleanup; ++ } ++ } ++ ++ if (k5->out_cc == NULL && krb5_cc_support_switch(k5->ctx, deftype)) { ++ /* Use an existing cache for the client principal if we can. */ ++ code = krb5_cc_cache_match(k5->ctx, k5->me, &k5->out_cc); ++ if (code != 0 && code != KRB5_CC_NOTFOUND) { ++ com_err(progname, code, _("while searching for ccache for %s"), ++ opts->principal_name); ++ goto cleanup; ++ } ++ if (code == 0) { ++ if (opts->verbose) { + fprintf(stderr, _("Using existing cache: %s\n"), + krb5_cc_get_name(k5->ctx, k5->out_cc)); + } +- krb5_cc_close(k5->ctx, defcache); + k5->switch_to_cache = 1; +- } else { +- k5->out_cc = defcache; ++ } else if (defcache_princ != NULL) { ++ /* Create a new cache to avoid overwriting the initialized default ++ * cache. */ ++ code = krb5_cc_new_unique(k5->ctx, deftype, NULL, &k5->out_cc); ++ if (code) { ++ com_err(progname, code, _("while generating new ccache")); ++ goto cleanup; ++ } + if (opts->verbose) { +- fprintf(stderr, _("Using default cache: %s\n"), ++ fprintf(stderr, _("Using new cache: %s\n"), + krb5_cc_get_name(k5->ctx, k5->out_cc)); + } ++ k5->switch_to_cache = 1; ++ } ++ } ++ ++ /* Use the default cache if we haven't picked one yet. */ ++ if (k5->out_cc == NULL) { ++ k5->out_cc = defcache; ++ defcache = NULL; ++ if (opts->verbose) { ++ fprintf(stderr, _("Using default cache: %s\n"), ++ krb5_cc_get_name(k5->ctx, k5->out_cc)); + } + } ++ + if (opts->k5_in_cache_name) { + code = krb5_cc_resolve(k5->ctx, opts->k5_in_cache_name, &k5->in_cc); + if (code != 0) { + com_err(progname, code, _("resolving ccache %s"), + opts->k5_in_cache_name); +- return 0; ++ goto cleanup; + } + if (opts->verbose) { + fprintf(stderr, _("Using specified input cache: %s\n"), +@@ -551,80 +634,24 @@ k5_begin(opts, k5) + } + } + +- if (!k5->me) { +- /* No principal name specified */ +- if (opts->anonymous) { +- char *defrealm; +- code = krb5_get_default_realm(k5->ctx, &defrealm); +- if (code) { +- com_err(progname, code, _("while getting default realm")); +- return 0; +- } +- code = krb5_build_principal_ext(k5->ctx, &k5->me, +- strlen(defrealm), defrealm, +- strlen(KRB5_WELLKNOWN_NAMESTR), +- KRB5_WELLKNOWN_NAMESTR, +- strlen(KRB5_ANONYMOUS_PRINCSTR), +- KRB5_ANONYMOUS_PRINCSTR, +- 0); +- krb5_free_default_realm(k5->ctx, defrealm); +- if (code) { +- com_err(progname, code, _("while building principal")); +- return 0; +- } +- } else { +- if (opts->action == INIT_KT) { +- /* Use the default host/service name */ +- code = krb5_sname_to_principal(k5->ctx, NULL, NULL, +- KRB5_NT_SRV_HST, &k5->me); +- if (code) { +- com_err(progname, code, +- _("when creating default server principal name")); +- return 0; +- } +- if (k5->me->realm.data[0] == 0) { +- code = krb5_unparse_name(k5->ctx, k5->me, &k5->name); +- if (code == 0) { +- com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN, +- _("(principal %s)"), k5->name); +- } else { +- com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN, +- _("for local services")); +- } +- return 0; +- } +- } else { +- /* Get default principal from cache if one exists */ +- code = krb5_cc_get_principal(k5->ctx, k5->out_cc, +- &k5->me); +- if (code) { +- char *name = get_name_from_os(); +- if (!name) { +- fprintf(stderr, _("Unable to identify user\n")); +- return 0; +- } +- if ((code = krb5_parse_name_flags(k5->ctx, name, +- flags, &k5->me))) { +- com_err(progname, code, _("when parsing name %s"), +- name); +- return 0; +- } +- } +- } +- } +- } + + code = krb5_unparse_name(k5->ctx, k5->me, &k5->name); + if (code) { + com_err(progname, code, _("when unparsing name")); +- return 0; ++ goto cleanup; + } + if (opts->verbose) + fprintf(stderr, _("Using principal: %s\n"), k5->name); + + opts->principal_name = k5->name; + +- return 1; ++ success = 1; ++ ++cleanup: ++ if (defcache != NULL) ++ krb5_cc_close(k5->ctx, defcache); ++ krb5_free_principal(k5->ctx, defcache_princ); ++ return success; + } + + static void diff --git a/SOURCES/krb5-master-test_gss_no_udp.patch b/SOURCES/krb5-master-test_gss_no_udp.patch new file mode 100644 index 0000000..866647d --- /dev/null +++ b/SOURCES/krb5-master-test_gss_no_udp.patch @@ -0,0 +1,41 @@ +commit 11bd102c0e3793204111f712e5bd4bf54f2d9573 +Author: Greg Hudson +Date: Wed May 1 14:40:31 2013 -0400 + + Disable UDP pass of gssrpc tests on all platforms + + The AUTH_GSSAPI flavor of rpc authentication uses IP address channel + bindings. These are broken over UDP, because svcudp_recv() fails to + get the destination address of incoming packets (it tries to use the + recvmsg() msg_name field to get the destination IP address, which + instead gets the source address; see ticket #5540). + + There is no simple or comprehensive way to fix this; using IP_PKTINFO + is a fair amount of code and only works on some platforms. It's also + not very important--nobody should be using AUTH_GSSAPI except perhaps + for compatibility with really old kadmin, and kadmin only runs over + TCP. Since the gssrpc tests are closely wedded to AUTH_GSSAPI, the + simplest fix is to only run the TCP pass. + +diff --git a/src/configure.in b/src/configure.in +index 0c8111b..42a5fd5 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -984,16 +984,7 @@ extern void endrpcent();], + AC_MSG_RESULT($k5_cv_type_endrpcent) + AC_DEFINE_UNQUOTED(ENDRPCENT_TYPE, $k5_cv_type_endrpcent, [Define as return type of endrpcent]) + K5_GEN_FILE(include/gssrpc/types.h:include/gssrpc/types.hin) +-changequote(<<, >>) +-case "$krb5_cv_host" in +-*-*-solaris2.[012345]*) +- PASS=tcp +- ;; +-*) +- PASS="tcp udp" +- ;; +-esac +-changequote([, ]) ++PASS=tcp + AC_SUBST(PASS) + + # for pkinit diff --git a/SOURCES/krb5-master-test_no_pmap.patch b/SOURCES/krb5-master-test_no_pmap.patch new file mode 100644 index 0000000..bc6afed --- /dev/null +++ b/SOURCES/krb5-master-test_no_pmap.patch @@ -0,0 +1,244 @@ +commit 5454da3bcaa383f5b47984283f11f010d3d2b73e +Author: Greg Hudson +Date: Wed May 1 13:07:36 2013 -0400 + + Don't use portmapper in RPC tests + + On many Linux systems, due to what is arguably a bug in rpcbind, the + portmapper doesn't allow service registration from non-root processes. + This causes the RPC tests to be frequently skipped. Modify the tests + so that they don't need the portmapper, by grabbing the port number + from the server process and passing it to the client. + +diff --git a/doc/build/doing_build.rst b/doc/build/doing_build.rst +index bc438c8..3c686cc 100644 +--- a/doc/build/doing_build.rst ++++ b/doc/build/doing_build.rst +@@ -149,9 +149,6 @@ However, there are several prerequisites that must be satisfied first: + **-**\ **-disable-rpath**, which renders the build tree less suitable for + installation, but allows testing without interference from + previously installed libraries. +-* In order to test the RPC layer, the local system has to be running +- the portmap daemon and it has to be listening to the regular network +- interface (not just localhost). + + There are additional regression tests available, which are not run + by ``make check``. These tests require manual setup and teardown of +diff --git a/src/lib/rpc/unit-test/client.c b/src/lib/rpc/unit-test/client.c +index a70cf38..6ab4534 100644 +--- a/src/lib/rpc/unit-test/client.c ++++ b/src/lib/rpc/unit-test/client.c +@@ -7,12 +7,15 @@ + + #include + #include ++#include ++#include + #include "autoconf.h" + #ifdef HAVE_UNISTD_H + #include + #endif + #include + #include ++#include + #include + #include + #include "rpc_test.h" +@@ -51,17 +54,19 @@ main(argc, argv) + int argc; + char **argv; + { +- char *host, *target, *echo_arg, **echo_resp, buf[BIG_BUF]; +- char *prot; ++ char *host, *port, *target, *echo_arg, **echo_resp, buf[BIG_BUF]; + CLIENT *clnt; + AUTH *tmp_auth; + struct rpc_err e; +- int i, auth_once; ++ int i, auth_once, sock, use_tcp; + unsigned int count; + extern int optind; + extern char *optarg; + extern int svc_debug_gssapi, misc_debug_gssapi, auth_debug_gssapi; + int c; ++ struct sockaddr_in sin; ++ struct hostent *h; ++ struct timeval tv; + + extern int krb5_gss_dbg_client_expcreds; + krb5_gss_dbg_client_expcreds = 1; +@@ -69,7 +74,7 @@ main(argc, argv) + whoami = argv[0]; + count = 1026; + auth_once = 0; +- prot = NULL; ++ use_tcp = -1; + + while ((c = getopt(argc, argv, "a:m:os:tu")) != -1) { + switch (c) { +@@ -86,39 +91,60 @@ main(argc, argv) + svc_debug_gssapi = atoi(optarg); + break; + case 't': +- prot = "tcp"; ++ use_tcp = 1; + break; + case 'u': +- prot = "udp"; ++ use_tcp = 0; + break; + case '?': + usage(); + break; + } + } +- if (prot == NULL) ++ if (use_tcp == -1) + usage(); + + argv += optind; + argc -= optind; + + switch (argc) { +- case 3: +- count = atoi(argv[2]); ++ case 4: ++ count = atoi(argv[3]); + if (count > BIG_BUF-1) { + fprintf(stderr, "Test count cannot exceed %d.\n", BIG_BUF-1); + usage(); + } +- case 2: ++ case 3: + host = argv[0]; +- target = argv[1]; ++ port = argv[1]; ++ target = argv[2]; + break; + default: + usage(); + } + ++ /* get server address */ ++ h = gethostbyname(host); ++ if (h == NULL) { ++ fprintf(stderr, "Can't resolve hostname %s\n", host); ++ exit(1); ++ } ++ memset(&sin, 0, sizeof(sin)); ++ sin.sin_family = h->h_addrtype; ++ sin.sin_port = ntohs(atoi(port)); ++ memmove(&sin.sin_addr, h->h_addr, sizeof(sin.sin_addr)); ++ + /* client handle to rstat */ +- clnt = clnt_create(host, RPC_TEST_PROG, RPC_TEST_VERS_1, prot); ++ sock = RPC_ANYSOCK; ++ if (use_tcp) { ++ clnt = clnttcp_create(&sin, RPC_TEST_PROG, RPC_TEST_VERS_1, &sock, 0, ++ 0); ++ } else { ++ tv.tv_sec = 5; ++ tv.tv_usec = 0; ++ clnt = clntudp_create(&sin, RPC_TEST_PROG, RPC_TEST_VERS_1, tv, ++ &sock); ++ } + if (clnt == NULL) { + clnt_pcreateerror(whoami); + exit(1); +diff --git a/src/lib/rpc/unit-test/config/unix.exp b/src/lib/rpc/unit-test/config/unix.exp +index f02116e..ba57b70 100644 +--- a/src/lib/rpc/unit-test/config/unix.exp ++++ b/src/lib/rpc/unit-test/config/unix.exp +@@ -112,10 +112,6 @@ proc rpc_test_exit {} { + global server_started + global kill + +- if { [info exists server_started] && $server_started == 0 } { +- return +- } +- + if {[catch { + expect { + -i $server_id +@@ -138,6 +134,7 @@ proc rpc_test_start { } { + global server_id + global server_pid + global server_started ++ global server_port + global env + + if [info exists server_pid] { rpc_test_exit } +@@ -148,25 +145,17 @@ proc rpc_test_start { } { + set server_pid [spawn $SERVER $PROT] + set server_id $spawn_id + set server_started 1 ++ set server_port -1 + + unset env(KRB5_KTNAME) + + set timeout 30 + + expect { ++ -re "port: (\[0-9\]*)\r\n" { ++ set server_port $expect_out(1,string) ++ } + "running" { } +- "Cannot register service" { +- send_error "Server cannot register with portmap/rpcbind!!\n" +- note "+++" +- note "+++ These tests require the ability to register with portmap/rpcbind" +- note "+++ Either the server is not running or it does not" +- note "+++ allow registration using a loopback connection" +- note "+++" +- verbose $expect_out(buffer) 1 +- set server_started 0 +- unsupported "Server registration" +- return +- } + eof { + send_error "server exited!" + verbose $expect_out(buffer) 1 +diff --git a/src/lib/rpc/unit-test/lib/helpers.exp b/src/lib/rpc/unit-test/lib/helpers.exp +index 963fff4..a1b0783 100644 +--- a/src/lib/rpc/unit-test/lib/helpers.exp ++++ b/src/lib/rpc/unit-test/lib/helpers.exp +@@ -170,7 +170,7 @@ proc flush_server {} { + + proc start_client {testname ccname user password lifetime count + {target ""}} { +- global env CLIENT PROT hostname spawn_id verbose ++ global env CLIENT PROT hostname server_port spawn_id verbose + + if {$target == ""} { + set target "server@$hostname" +@@ -180,9 +180,9 @@ proc start_client {testname ccname user password lifetime count + kinit $user $password $lifetime + + if {$verbose > 0} { +- spawn $CLIENT -a 1 -s 1 -m 1 $PROT $hostname $target $count ++ spawn $CLIENT -a 1 -s 1 -m 1 $PROT $hostname $server_port $target $count + } else { +- spawn $CLIENT $PROT $hostname $target $count ++ spawn $CLIENT $PROT $hostname $server_port $target $count + } + + verbose "$testname: client $ccname started" +diff --git a/src/lib/rpc/unit-test/server.c b/src/lib/rpc/unit-test/server.c +index c2cb30c..7451558 100644 +--- a/src/lib/rpc/unit-test/server.c ++++ b/src/lib/rpc/unit-test/server.c +@@ -114,12 +114,13 @@ main(int argc, char **argv) + exit(1); + } + if (!svc_register(transp, RPC_TEST_PROG, RPC_TEST_VERS_1, +- rpc_test_prog_1_svc, prot)) { ++ rpc_test_prog_1_svc, 0)) { + fprintf(stderr, + "unable to register (RPC_TEST_PROG, RPC_TEST_VERS_1, %s).", + prot == IPPROTO_TCP ? "tcp" : "udp"); + exit(1); + } ++ printf("port: %d\n", (int)transp->xp_port); + + if (svcauth_gssapi_set_names(names, 0) == FALSE) { + fprintf(stderr, "unable to set gssapi names\n"); diff --git a/SOURCES/krb5.conf b/SOURCES/krb5.conf new file mode 100644 index 0000000..471c4a1 --- /dev/null +++ b/SOURCES/krb5.conf @@ -0,0 +1,22 @@ +[logging] + default = FILE:/var/log/krb5libs.log + kdc = FILE:/var/log/krb5kdc.log + admin_server = FILE:/var/log/kadmind.log + +[libdefaults] + dns_lookup_realm = false + ticket_lifetime = 24h + renew_lifetime = 7d + forwardable = true + rdns = false +# default_realm = EXAMPLE.COM + +[realms] +# EXAMPLE.COM = { +# kdc = kerberos.example.com +# admin_server = kerberos.example.com +# } + +[domain_realm] +# .example.com = EXAMPLE.COM +# example.com = EXAMPLE.COM diff --git a/SOURCES/krb5_prop.portreserve b/SOURCES/krb5_prop.portreserve new file mode 100644 index 0000000..54eeff2 --- /dev/null +++ b/SOURCES/krb5_prop.portreserve @@ -0,0 +1 @@ +krb5_prop/tcp diff --git a/SOURCES/krb5kdc.init b/SOURCES/krb5kdc.init new file mode 100755 index 0000000..3462ca6 --- /dev/null +++ b/SOURCES/krb5kdc.init @@ -0,0 +1,102 @@ +#!/bin/bash +# +# krb5kdc Start and stop the Kerberos 5 servers. +# +# chkconfig: - 35 65 +# description: Kerberos 5 is a trusted third-party authentication system. \ +# This script starts and stops the server that Kerberos 5 \ +# clients need to connect to in order to obtain credentials. +# processname: krb5kdc +# config: /etc/sysconfig/krb5kdc +# pidfile: /var/run/krb5kdc.pid +# + +### BEGIN INIT INFO +# Provides: krb5kdc +# Required-Start: $local_fs $network +# Required-Stop: $local_fs $network +# Should-Start: portreserve +# Default-Start: +# Default-Stop: 0 1 2 3 4 5 6 +# Short-Description: start and stop the Kerberos 5 KDC +# Description: The krb5kdc is the Kerberos 5 key distribution center, which \ +# issues credentials to Kerberos 5 clients. +### END INIT INFO + +# Get config. +. /etc/sysconfig/network + +# Get config. +[ -r /etc/sysconfig/krb5kdc ] && . /etc/sysconfig/krb5kdc + +# Source function library. +. /etc/rc.d/init.d/functions + +RETVAL=0 +prog="Kerberos 5 KDC" +krb5kdc=/usr/sbin/krb5kdc +pidfile=/var/run/krb5kdc.pid +PATH=/usr/lib64/krb5:/usr/lib/krb5:"$PATH" + +# Shell functions to cut down on useless shell instances. +start() { + [ -x $krb5kdc ] || exit 5 + echo -n $"Starting $prog: " + # tell portreserve to release the kerberos-iv port + [ -x /sbin/portrelease ] && /sbin/portrelease kerberos-iv &>/dev/null || : + daemon ${krb5kdc} ${KRB5REALM:+-r ${KRB5REALM}} -P $pidfile $KRB5KDC_ARGS + RETVAL=$? + echo + if test $RETVAL -ne 0 ; then + if status ${krb5kdc} > /dev/null ; then + RETVAL=0 + fi + fi + [ $RETVAL = 0 ] && touch /var/lock/subsys/krb5kdc +} +stop() { + echo -n $"Stopping $prog: " + killproc ${krb5kdc} + RETVAL=$? + echo + [ $RETVAL = 0 ] && rm -f /var/lock/subsys/krb5kdc +} +reload() { + echo -n $"Reopening $prog log file: " + killproc ${krb5kdc} -HUP + RETVAL=$? + echo +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + reload) + reload + ;; + status) + status ${krb5kdc} + RETVAL=$? + ;; + condrestart) + if [ -f /var/lock/subsys/krb5kdc ] ; then + stop + start + fi + ;; + *) + echo $"Usage: $0 {start|stop|status|reload|restart|condrestart}" + RETVAL=2 + ;; +esac + +exit $RETVAL diff --git a/SOURCES/krb5kdc.logrotate b/SOURCES/krb5kdc.logrotate new file mode 100644 index 0000000..1100ed3 --- /dev/null +++ b/SOURCES/krb5kdc.logrotate @@ -0,0 +1,9 @@ +/var/log/krb5kdc.log { + missingok + notifempty + monthly + rotate 12 + postrotate + /bin/kill -HUP `cat /var/run/krb5kdc.pid 2>/dev/null` 2> /dev/null || true + endscript +} diff --git a/SOURCES/krb5kdc.service b/SOURCES/krb5kdc.service new file mode 100644 index 0000000..bc49204 --- /dev/null +++ b/SOURCES/krb5kdc.service @@ -0,0 +1,13 @@ +[Unit] +Description=Kerberos 5 KDC +After=syslog.target network.target + +[Service] +Type=forking +PIDFile=/var/run/krb5kdc.pid +EnvironmentFile=-/etc/sysconfig/krb5kdc +ExecStart=/usr/sbin/krb5kdc -P /var/run/krb5kdc.pid $KRB5KDC_ARGS +ExecReload=/bin/kill -HUP $MAINPID + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/krb5kdc.sysconfig b/SOURCES/krb5kdc.sysconfig new file mode 100644 index 0000000..791216d --- /dev/null +++ b/SOURCES/krb5kdc.sysconfig @@ -0,0 +1 @@ +KRB5KDC_ARGS= diff --git a/SOURCES/ksu.pamd b/SOURCES/ksu.pamd new file mode 100644 index 0000000..66f5b2c --- /dev/null +++ b/SOURCES/ksu.pamd @@ -0,0 +1,4 @@ +#%PAM-1.0 +auth include su +account include su +session include su diff --git a/SOURCES/noport.c b/SOURCES/noport.c new file mode 100644 index 0000000..c7a0c01 --- /dev/null +++ b/SOURCES/noport.c @@ -0,0 +1,107 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +static int +port_is_okay(unsigned short port) +{ + char *p, *q; + long l; + + p = getenv("NOPORT"); + while ((p != NULL) && (*p != '\0')) { + l = strtol(p, &q, 10); + if ((q == NULL) || (q == p)) { + break; + } + if ((*q == '\0') || (*q == ',')) { + if (port == l) { + errno = ECONNREFUSED; + return -1; + } + } + p = q; + p += strspn(p, ","); + } + return 0; +} + +int +connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + unsigned short port; + static int (*next_connect)(int, const struct sockaddr *, socklen_t); + + if (next_connect == NULL) { + next_connect = dlsym(RTLD_NEXT, "connect"); + if (next_connect == NULL) { + errno = ENOSYS; + return -1; + } + } + + if (getenv("NOPORT") == NULL) { + return next_connect(sockfd, addr, addrlen); + } + + switch (addr->sa_family) { + case AF_INET: + port = ntohs(((struct sockaddr_in *)addr)->sin_port); + if (port_is_okay(port) != 0) { + return -1; + } + break; + case AF_INET6: + port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port); + if (port_is_okay(port) != 0) { + return -1; + } + break; + default: + break; + } + return next_connect(sockfd, addr, addrlen); +} + +ssize_t +sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + unsigned short port; + static int (*next_sendto)(int, const void *, size_t, int, + const struct sockaddr *, socklen_t); + + if (next_sendto == NULL) { + next_sendto = dlsym(RTLD_NEXT, "sendto"); + if (next_sendto == NULL) { + errno = ENOSYS; + return -1; + } + } + + if (getenv("NOPORT") == NULL) { + return next_sendto(sockfd, buf, len, flags, dest_addr, addrlen); + } + + switch (dest_addr->sa_family) { + case AF_INET: + port = ntohs(((struct sockaddr_in *)dest_addr)->sin_port); + if (port_is_okay(port) != 0) { + return -1; + } + break; + case AF_INET6: + port = ntohs(((struct sockaddr_in6 *)dest_addr)->sin6_port); + if (port_is_okay(port) != 0) { + return -1; + } + break; + default: + break; + } + return next_sendto(sockfd, buf, len, flags, dest_addr, addrlen); +} diff --git a/SOURCES/persistent_keyring.patch b/SOURCES/persistent_keyring.patch new file mode 100644 index 0000000..863774c --- /dev/null +++ b/SOURCES/persistent_keyring.patch @@ -0,0 +1,3321 @@ +Pared down from the git commits, with a local copy of k5memdup0() added in +to cc_keyring, and a wrapper 'run' in to k5test.py. + +diff --git a/src/aclocal.m4 b/src/aclocal.m4 +index 2c17e46..7be77c2 100644 +--- a/src/aclocal.m4 ++++ b/src/aclocal.m4 +@@ -89,6 +89,7 @@ KRB5_AC_INITFINI + KRB5_AC_ENABLE_THREADS + KRB5_AC_FIND_DLOPEN + KRB5_AC_KEYRING_CCACHE ++KRB5_AC_PERSISTENT_KEYRING + ])dnl + + dnl Maintainer mode, akin to what automake provides, 'cept we don't +@@ -1664,3 +1659,12 @@ AC_DEFUN(KRB5_AC_KEYRING_CCACHE,[ + ])) + ])dnl + dnl ++dnl If libkeyutils supports persistent keyrings, use them ++AC_DEFUN(KRB5_AC_PERSISTENT_KEYRING,[ ++ AC_CHECK_HEADERS([keyutils.h], ++ AC_CHECK_LIB(keyutils, keyctl_get_persistent, ++ [AC_DEFINE(HAVE_PERSISTENT_KEYRING, 1, ++ [Define if persistent keyrings are supported]) ++ ])) ++])dnl ++dnl +diff --git a/src/lib/krb5/error_tables/k5e1_err.et b/src/lib/krb5/error_tables/k5e1_err.et +index 98374ed..071b7f2 100644 +--- a/src/lib/krb5/error_tables/k5e1_err.et ++++ b/src/lib/krb5/error_tables/k5e1_err.et +@@ -35,4 +35,7 @@ error_code KRB5_PLUGIN_BAD_MODULE_SPEC, "Invalid module specifier" + error_code KRB5_PLUGIN_NAME_NOTFOUND, "Plugin module name not found" + error_code KRB5KDC_ERR_DISCARD, "The KDC should discard this request" + error_code KRB5_DCC_CANNOT_CREATE, "Can't create new subsidiary cache" ++error_code KRB5_KCC_INVALID_ANCHOR, "Invalid keyring anchor name" ++error_code KRB5_KCC_UNKNOWN_VERSION, "Unknown keyring collection version" ++error_code KRB5_KCC_INVALID_UID, "Invalid UID in persistent keyring name" + end +diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c +index fd1bcec..795ccd6 100644 +--- a/src/lib/krb5/ccache/cc_keyring.c ++++ b/src/lib/krb5/ccache/cc_keyring.c +@@ -56,17 +56,42 @@ + */ + + /* +- * Implementation of a credentials cache stored in the Linux keyring facility ++ * This file implements a collection-enabled credential cache type where the ++ * credentials are stored in the Linux keyring facility. + * +- * Some assumptions: ++ * A residual of this type can have three forms: ++ * anchor:collection:subsidiary ++ * anchor:collection ++ * collection + * +- * - A credentials cache "file" == a keyring with separate keys +- * for the information in the ccache (see below) +- * - A credentials cache keyring will contain only keys, +- * not other keyrings +- * - Each Kerberos ticket will have its own key within the ccache keyring +- * - The principal information for the ccache is stored in a +- * special key, which is not counted in the 'numkeys' count ++ * The anchor name is "process", "thread", or "legacy" and determines where we ++ * search for keyring collections. In the third form, the anchor name is ++ * presumed to be "legacy". The anchor keyring for legacy caches is the ++ * session keyring. ++ * ++ * If the subsidiary name is present, the residual identifies a single cache ++ * within a collection. Otherwise, the residual identifies the collection ++ * itself. When a residual identifying a collection is resolved, the ++ * collection's primary key is looked up (or initialized, using the collection ++ * name as the subsidiary name), and the resulting cache's name will use the ++ * first name form and will identify the primary cache. ++ * ++ * Keyring collections are named "_krb_" and are linked from the ++ * anchor keyring. The keys within a keyring collection are links to cache ++ * keyrings, plus a link to one user key named "krb_ccache:primary" which ++ * contains a serialized representation of the collection version (currently 1) ++ * and the primary name of the collection. ++ * ++ * Cache keyrings contain one user key per credential which contains a ++ * serialized representation of the credential. There is also one user key ++ * named "__krb5_princ__" which contains a serialized representation of the ++ * cache's default principal. ++ * ++ * If the anchor name is "legacy", then the initial primary cache (the one ++ * named with the collection name) is also linked to the session keyring, and ++ * we look for a cache in that location when initializing the collection. This ++ * extra link allows that cache to be visible to old versions of the KEYRING ++ * cache type, and allows us to see caches created by that code. + */ + + #include "cc-int.h" +@@ -101,7 +126,20 @@ debug_print(char *fmt, ...) + #endif + + /* +- * We always use "user" key type ++ * We try to use the big_key key type for credentials except in legacy caches. ++ * We fall back to the user key type if the kernel does not support big_key. ++ * If the library doesn't support keyctl_get_persistent(), we don't even try ++ * big_key since the two features were added at the same time. ++ */ ++#ifdef HAVE_PERSISTENT_KEYRING ++#define KRCC_CRED_KEY_TYPE "big_key" ++#else ++#define KRCC_CRED_KEY_TYPE "user" ++#endif ++ ++/* ++ * We use the "user" key type for collection primary names, for cache principal ++ * names, and for credentials in legacy caches. + */ + #define KRCC_KEY_TYPE_USER "user" + +@@ -117,20 +155,6 @@ debug_print(char *fmt, ...) + #define KRCC_SPEC_PRINC_KEYNAME "__krb5_princ__" + + /* +- * XXX The following two really belong in some external +- * header since outside programs will need to use these +- * same names. +- */ +-/* +- * Special name for key to communicate key serial numbers +- * This is used by the Linux gssd process to pass the +- * user's keyring values it gets in an upcall. +- * The format of the contents should be +- * :: +- */ +-#define KRCC_SPEC_IDS_KEYNAME "_gssd_keyring_ids_" +- +-/* + * Special name for the key to communicate the name(s) + * of credentials caches to be used for requests. + * This should currently contain a single name, but +@@ -139,26 +163,55 @@ debug_print(char *fmt, ...) + */ + #define KRCC_SPEC_CCACHE_SET_KEYNAME "__krb5_cc_set__" + ++/* ++ * This name identifies the key containing the name of the current primary ++ * cache within a collection. ++ */ ++#define KRCC_COLLECTION_PRIMARY "krb_ccache:primary" ++ ++/* ++ * If the library context does not specify a keyring collection, unique ccaches ++ * will be created within this collection. ++ */ ++#define KRCC_DEFAULT_UNIQUE_COLLECTION "session:__krb5_unique__" ++ ++/* ++ * Collection keyring names begin with this prefix. We use a prefix so that a ++ * cache keyring with the collection name itself can be linked directly into ++ * the anchor, for legacy session keyring compatibility. ++ */ ++#define KRCC_CCCOL_PREFIX "_krb_" ++ ++/* ++ * For the "persistent" anchor type, we look up or create this fixed keyring ++ * name within the per-UID persistent keyring. ++ */ ++#define KRCC_PERSISTENT_KEYRING_NAME "_krb" ++ ++/* ++ * Keyring name prefix and length of random name part ++ */ ++#define KRCC_NAME_PREFIX "krb_ccache_" ++#define KRCC_NAME_RAND_CHARS 8 ++ ++#define KRCC_COLLECTION_VERSION 1 ++ ++#define KRCC_PERSISTENT_ANCHOR "persistent" ++#define KRCC_PROCESS_ANCHOR "process" ++#define KRCC_THREAD_ANCHOR "thread" ++#define KRCC_SESSION_ANCHOR "session" ++#define KRCC_USER_ANCHOR "user" ++#define KRCC_LEGACY_ANCHOR "legacy" ++ + #define KRB5_OK 0 + + /* Hopefully big enough to hold a serialized credential */ +-#define GUESS_CRED_SIZE 4096 +- +-#define ALLOC(NUM,TYPE) \ +- (((NUM) <= (((size_t)0-1)/ sizeof(TYPE))) \ +- ? (TYPE *) calloc((NUM), sizeof(TYPE)) \ +- : (errno = ENOMEM,(TYPE *) 0)) ++#define MAX_CRED_SIZE (1024*1024) + + #define CHECK_N_GO(ret, errdest) if (ret != KRB5_OK) goto errdest + #define CHECK(ret) if (ret != KRB5_OK) goto errout + #define CHECK_OUT(ret) if (ret != KRB5_OK) return ret + +-typedef struct krb5_krcc_ring_ids { +- key_serial_t session; +- key_serial_t process; +- key_serial_t thread; +-} krb5_krcc_ring_ids_t; +- + typedef struct _krb5_krcc_cursor + { + int numkeys; +@@ -169,7 +222,7 @@ typedef struct _krb5_krcc_cursor + + /* + * This represents a credentials cache "file" +- * where ring_id is the keyring serial number for ++ * where cache_id is the keyring serial number for + * this credentials cache "file". Each key + * in the keyring contains a separate key. + */ +@@ -177,12 +230,11 @@ typedef struct _krb5_krcc_data + { + char *name; /* Name for this credentials cache */ + k5_cc_mutex lock; /* synchronization */ +- key_serial_t parent_id; /* parent keyring of this ccache keyring */ +- key_serial_t ring_id; /* keyring representing ccache */ ++ key_serial_t collection_id; /* collection containing this cache keyring */ ++ key_serial_t cache_id; /* keyring representing ccache */ + key_serial_t princ_id; /* key holding principal info */ +- int numkeys; /* # of keys in this ring +- * (does NOT include principal info) */ + krb5_timestamp changetime; ++ krb5_boolean is_legacy_type; + } krb5_krcc_data; + + /* Passed internally to assure we don't go past the bounds of our buffer */ +@@ -190,6 +242,7 @@ typedef struct _krb5_krcc_buffer_cursor + { + char *bpp; + char *endp; ++ size_t size; /* For dry-run length calculation */ + } krb5_krcc_bc; + + /* Global mutex */ +@@ -258,6 +311,29 @@ static krb5_error_code KRB5_CALLCONV krb5_krcc_lock + static krb5_error_code KRB5_CALLCONV krb5_krcc_unlock + (krb5_context context, krb5_ccache id); + ++static krb5_error_code KRB5_CALLCONV krb5_krcc_ptcursor_new ++(krb5_context context, krb5_cc_ptcursor *cursor_out); ++ ++static krb5_error_code KRB5_CALLCONV krb5_krcc_ptcursor_next ++(krb5_context context, krb5_cc_ptcursor cursor, krb5_ccache *cache_out); ++ ++static krb5_error_code KRB5_CALLCONV krb5_krcc_ptcursor_free ++(krb5_context context, krb5_cc_ptcursor *cursor); ++ ++static krb5_error_code KRB5_CALLCONV krb5_krcc_switch_to ++(krb5_context context, krb5_ccache cache); ++ ++/* Like k5memdup, but add a final null byte. */ ++static inline void * ++k5memdup0(const void *in, size_t len, krb5_error_code *code) ++{ ++ void *ptr = k5alloc(len + 1, code); ++ ++ if (ptr != NULL && len > 0) ++ memcpy(ptr, in, len); ++ return ptr; ++} ++ + /* + * Internal utility functions + */ +@@ -266,8 +331,9 @@ static krb5_error_code krb5_krcc_clearcache + (krb5_context context, krb5_ccache id); + + static krb5_error_code krb5_krcc_new_data +-(const char *, key_serial_t ring, key_serial_t parent_ring, +- krb5_krcc_data **); ++(const char *anchor_name, const char *collection_name, ++ const char *subsidiary_name, key_serial_t cache_id, ++ key_serial_t collection_id, krb5_krcc_data **datapp); + + static krb5_error_code krb5_krcc_save_principal + (krb5_context context, krb5_ccache id, krb5_principal princ); +@@ -275,100 +341,480 @@ static krb5_error_code krb5_krcc_save_principal + static krb5_error_code krb5_krcc_retrieve_principal + (krb5_context context, krb5_ccache id, krb5_principal * princ); + +-static int krb5_krcc_get_ring_ids(krb5_krcc_ring_ids_t *p); +- + /* Routines to parse a key from a keyring into a cred structure */ + static krb5_error_code krb5_krcc_parse +-(krb5_context, krb5_ccache id, krb5_pointer buf, unsigned int len, +- krb5_krcc_bc * bc); ++(krb5_context, krb5_pointer buf, unsigned int len, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_cred +-(krb5_context context, krb5_ccache id, krb5_creds * creds, +- char *payload, int psize); ++(krb5_context context, krb5_creds * creds, char *payload, int psize); + static krb5_error_code krb5_krcc_parse_principal +-(krb5_context context, krb5_ccache id, krb5_principal * princ, +- krb5_krcc_bc * bc); ++(krb5_context context, krb5_principal * princ, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_keyblock +-(krb5_context context, krb5_ccache id, krb5_keyblock * keyblock, +- krb5_krcc_bc * bc); ++(krb5_context context, krb5_keyblock * keyblock, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_times +-(krb5_context context, krb5_ccache id, krb5_ticket_times * t, +- krb5_krcc_bc * bc); ++(krb5_context context, krb5_ticket_times * t, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_krb5data +-(krb5_context context, krb5_ccache id, krb5_data * data, +- krb5_krcc_bc * bc); ++(krb5_context context, krb5_data * data, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_int32 +-(krb5_context context, krb5_ccache id, krb5_int32 * i, krb5_krcc_bc * bc); ++(krb5_context context, krb5_int32 * i, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_octet +-(krb5_context context, krb5_ccache id, krb5_octet * octet, +- krb5_krcc_bc * bc); ++(krb5_context context, krb5_octet * octet, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_addrs +-(krb5_context context, krb5_ccache id, krb5_address *** a, +- krb5_krcc_bc * bc); ++(krb5_context context, krb5_address *** a, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_addr +-(krb5_context context, krb5_ccache id, krb5_address * a, +- krb5_krcc_bc * bc); ++(krb5_context context, krb5_address * a, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_authdata +-(krb5_context context, krb5_ccache id, krb5_authdata *** ad, +- krb5_krcc_bc * bc); ++(krb5_context context, krb5_authdata *** ad, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_authdatum +-(krb5_context context, krb5_ccache id, krb5_authdata * ad, +- krb5_krcc_bc * bc); ++(krb5_context context, krb5_authdata * ad, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_parse_ui_2 +-(krb5_context, krb5_ccache id, krb5_ui_2 * i, krb5_krcc_bc * bc); ++(krb5_context, krb5_ui_2 * i, krb5_krcc_bc * bc); + + /* Routines to unparse a cred structure into keyring key */ + static krb5_error_code krb5_krcc_unparse +-(krb5_context, krb5_ccache id, krb5_pointer buf, unsigned int len, +- krb5_krcc_bc * bc); +-static krb5_error_code krb5_krcc_unparse_cred +-(krb5_context context, krb5_ccache id, krb5_creds * creds, ++(krb5_context, krb5_pointer buf, unsigned int len, krb5_krcc_bc * bc); ++static krb5_error_code krb5_krcc_unparse_cred_alloc ++(krb5_context context, krb5_creds * creds, + char **datapp, unsigned int *lenptr); ++static krb5_error_code krb5_krcc_unparse_cred ++(krb5_context context, krb5_creds * creds, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_principal +-(krb5_context, krb5_ccache id, krb5_principal princ, krb5_krcc_bc * bc); ++(krb5_context, krb5_principal princ, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_keyblock +-(krb5_context, krb5_ccache id, krb5_keyblock * keyblock, +- krb5_krcc_bc * bc); ++(krb5_context, krb5_keyblock * keyblock, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_times +-(krb5_context, krb5_ccache id, krb5_ticket_times * t, krb5_krcc_bc * bc); ++(krb5_context, krb5_ticket_times * t, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_krb5data +-(krb5_context, krb5_ccache id, krb5_data * data, krb5_krcc_bc * bc); ++(krb5_context, krb5_data * data, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_int32 +-(krb5_context, krb5_ccache id, krb5_int32 i, krb5_krcc_bc * bc); ++(krb5_context, krb5_int32 i, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_octet +-(krb5_context, krb5_ccache id, krb5_int32 i, krb5_krcc_bc * bc); ++(krb5_context, krb5_int32 i, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_addrs +-(krb5_context, krb5_ccache, krb5_address ** a, krb5_krcc_bc * bc); ++(krb5_context, krb5_address ** a, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_addr +-(krb5_context, krb5_ccache, krb5_address * a, krb5_krcc_bc * bc); ++(krb5_context, krb5_address * a, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_authdata +-(krb5_context, krb5_ccache, krb5_authdata ** ad, krb5_krcc_bc * bc); ++(krb5_context, krb5_authdata ** ad, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_authdatum +-(krb5_context, krb5_ccache, krb5_authdata * ad, krb5_krcc_bc * bc); ++(krb5_context, krb5_authdata * ad, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_ui_4 +-(krb5_context, krb5_ccache id, krb5_ui_4 i, krb5_krcc_bc * bc); ++(krb5_context, krb5_ui_4 i, krb5_krcc_bc * bc); + static krb5_error_code krb5_krcc_unparse_ui_2 +-(krb5_context, krb5_ccache id, krb5_int32 i, krb5_krcc_bc * bc); ++(krb5_context, krb5_int32 i, krb5_krcc_bc * bc); + static void krb5_krcc_update_change_time + (krb5_krcc_data *); + ++static krb5_error_code ++krb5_krcc_parse_index(krb5_context context, krb5_int32 *version, ++ char **primary, void *payload, int psize); ++static krb5_error_code ++krb5_krcc_unparse_index(krb5_context context, krb5_int32 version, ++ const char *primary, void **datapp, int *lenptr); ++ + /* Note the following is a stub function for Linux */ + extern krb5_error_code krb5_change_cache(void); + + /* +- * Determine how many keys exist in a ccache keyring. +- * Subtracts out the "hidden" key holding the principal information. ++ * GET_PERSISTENT(uid) acquires the persistent keyring for uid, or falls back ++ * to the user keyring if uid matches the current effective uid. ++ */ ++ ++static key_serial_t ++get_persistent_fallback(uid_t uid) ++{ ++ return (uid == geteuid()) ? KEY_SPEC_USER_KEYRING : -1; ++} ++ ++#ifdef HAVE_PERSISTENT_KEYRING ++#define GET_PERSISTENT get_persistent_real ++static key_serial_t ++get_persistent_real(uid_t uid) ++{ ++ key_serial_t key; ++ ++ key = keyctl_get_persistent(uid, KEY_SPEC_PROCESS_KEYRING); ++ return (key == -1 && errno == ENOTSUP) ? get_persistent_fallback(uid) : ++ key; ++} ++#else ++#define GET_PERSISTENT get_persistent_fallback ++#endif ++ ++/* ++ * Find or create a keyring within parent with the given name. If possess is ++ * nonzero, also make sure the key is linked from possess. This is necessary ++ * to ensure that we have possession rights on the key when the parent is the ++ * user or persistent keyring. ++ */ ++static krb5_error_code ++find_or_create_keyring(key_serial_t parent, key_serial_t possess, ++ const char *name, key_serial_t *key_out) ++{ ++ key_serial_t key; ++ ++ *key_out = -1; ++ key = keyctl_search(parent, KRCC_KEY_TYPE_KEYRING, name, possess); ++ if (key == -1) { ++ if (possess != 0) { ++ key = add_key(KRCC_KEY_TYPE_KEYRING, name, NULL, 0, possess); ++ if (key == -1) ++ return errno; ++ if (keyctl_link(key, parent) == -1) ++ return errno; ++ } else { ++ key = add_key(KRCC_KEY_TYPE_KEYRING, name, NULL, 0, parent); ++ if (key == -1) ++ return errno; ++ } ++ } ++ *key_out = key; ++ return 0; ++} ++ ++/* Parse a residual name into an anchor name, a collection name, and possibly a ++ * subsidiary name. */ ++static krb5_error_code ++parse_residual(const char *residual, char **anchor_name_out, ++ char **collection_name_out, char **subsidiary_name_out) ++{ ++ krb5_error_code ret; ++ char *anchor_name = NULL, *collection_name = NULL, *subsidiary_name = NULL; ++ const char *sep; ++ ++ *anchor_name_out = 0; ++ *collection_name_out = NULL; ++ *subsidiary_name_out = NULL; ++ ++ /* Parse out the anchor name. Use the legacy anchor if not present. */ ++ sep = strchr(residual, ':'); ++ if (sep == NULL) { ++ anchor_name = strdup(KRCC_LEGACY_ANCHOR); ++ if (anchor_name == NULL) ++ goto oom; ++ } else { ++ anchor_name = k5memdup0(residual, sep - residual, &ret); ++ if (anchor_name == NULL) ++ goto oom; ++ residual = sep + 1; ++ } ++ ++ /* Parse out the collection and subsidiary name. */ ++ sep = strchr(residual, ':'); ++ if (sep == NULL) { ++ collection_name = strdup(residual); ++ if (collection_name == NULL) ++ goto oom; ++ subsidiary_name = NULL; ++ } else { ++ collection_name = k5memdup0(residual, sep - residual, &ret); ++ if (collection_name == NULL) ++ goto oom; ++ subsidiary_name = strdup(sep + 1); ++ if (subsidiary_name == NULL) ++ goto oom; ++ } ++ ++ *anchor_name_out = anchor_name; ++ *collection_name_out = collection_name; ++ *subsidiary_name_out = subsidiary_name; ++ return 0; ++ ++oom: ++ free(anchor_name); ++ free(collection_name); ++ free(subsidiary_name); ++ return ENOMEM; ++} ++ ++/* ++ * Return true if residual identifies a subsidiary cache which should be linked ++ * into the anchor so it can be visible to old code. This is the case if the ++ * residual has the legacy anchor and the subsidiary name matches the ++ * collection name. ++ */ ++static krb5_boolean ++is_legacy_cache_name(const char *residual) ++{ ++ const char *sep, *aname, *cname, *sname; ++ size_t alen, clen, legacy_len = sizeof(KRCC_LEGACY_ANCHOR) - 1; ++ ++ /* Get pointers to the anchor, collection, and subsidiary names. */ ++ aname = residual; ++ sep = strchr(residual, ':'); ++ if (sep == NULL) ++ return FALSE; ++ alen = sep - aname; ++ cname = sep + 1; ++ sep = strchr(cname, ':'); ++ if (sep == NULL) ++ return FALSE; ++ clen = sep - cname; ++ sname = sep + 1; ++ ++ return alen == legacy_len && clen == strlen(sname) && ++ strncmp(aname, KRCC_LEGACY_ANCHOR, alen) == 0 && ++ strncmp(cname, sname, clen) == 0; ++} ++ ++/* If the default cache name for context is a KEYRING cache, parse its residual ++ * string. Otherwise set all outputs to NULL. */ ++static krb5_error_code ++get_default(krb5_context context, char **anchor_name_out, ++ char **collection_name_out, char **subsidiary_name_out) ++{ ++ const char *defname; ++ ++ *anchor_name_out = *collection_name_out = *subsidiary_name_out = NULL; ++ defname = krb5_cc_default_name(context); ++ if (defname == NULL || strncmp(defname, "KEYRING:", 8) != 0) ++ return 0; ++ return parse_residual(defname + 8, anchor_name_out, collection_name_out, ++ subsidiary_name_out); ++} ++ ++/* Create a residual identifying a subsidiary cache. */ ++static krb5_error_code ++make_subsidiary_residual(const char *anchor_name, const char *collection_name, ++ const char *subsidiary_name, char **residual_out) ++{ ++ if (asprintf(residual_out, "%s:%s:%s", anchor_name, collection_name, ++ subsidiary_name) < 0) { ++ *residual_out = NULL; ++ return ENOMEM; ++ } ++ return 0; ++} ++ ++/* Retrieve or create a keyring for collection_name within the anchor, and set ++ * *collection_id_out to its serial number. */ ++static krb5_error_code ++get_collection(const char *anchor_name, const char *collection_name, ++ key_serial_t *collection_id_out) ++{ ++ krb5_error_code ret; ++ key_serial_t persistent_id, anchor_id, possess_id = 0; ++ char *ckname; ++ long uidnum; ++ ++ *collection_id_out = 0; ++ ++ if (strcmp(anchor_name, KRCC_PERSISTENT_ANCHOR) == 0) { ++ /* ++ * The collection name is a uid (or empty for the current effective ++ * uid), and we look up a fixed keyring name within the persistent ++ * keyring for that uid. We link it to the process keyring to ensure ++ * that we have possession rights on the collection key. ++ */ ++ if (*collection_name != '\0') { ++ errno = 0; ++ uidnum = strtol(collection_name, NULL, 10); ++ if (errno) ++ return KRB5_KCC_INVALID_UID; ++ } else { ++ uidnum = geteuid(); ++ } ++ persistent_id = GET_PERSISTENT(uidnum); ++ if (persistent_id == -1) ++ return KRB5_KCC_INVALID_UID; ++ return find_or_create_keyring(persistent_id, KEY_SPEC_PROCESS_KEYRING, ++ KRCC_PERSISTENT_KEYRING_NAME, ++ collection_id_out); ++ } ++ ++ if (strcmp(anchor_name, KRCC_PROCESS_ANCHOR) == 0) { ++ anchor_id = KEY_SPEC_PROCESS_KEYRING; ++ } else if (strcmp(anchor_name, KRCC_THREAD_ANCHOR) == 0) { ++ anchor_id = KEY_SPEC_THREAD_KEYRING; ++ } else if (strcmp(anchor_name, KRCC_SESSION_ANCHOR) == 0) { ++ anchor_id = KEY_SPEC_SESSION_KEYRING; ++ } else if (strcmp(anchor_name, KRCC_USER_ANCHOR) == 0) { ++ /* The user keyring does not confer possession, so we need to link the ++ * collection to the process keyring to maintain possession rights. */ ++ anchor_id = KEY_SPEC_USER_KEYRING; ++ possess_id = KEY_SPEC_PROCESS_KEYRING; ++ } else if (strcmp(anchor_name, KRCC_LEGACY_ANCHOR) == 0) { ++ anchor_id = KEY_SPEC_SESSION_KEYRING; ++ } else { ++ return KRB5_KCC_INVALID_ANCHOR; ++ } ++ ++ /* Look up the collection keyring name within the anchor keyring. */ ++ if (asprintf(&ckname, "%s%s", KRCC_CCCOL_PREFIX, collection_name) == -1) ++ return ENOMEM; ++ ret = find_or_create_keyring(anchor_id, possess_id, ckname, ++ collection_id_out); ++ free(ckname); ++ return ret; ++} ++ ++/* Store subsidiary_name into the primary index key for collection_id. */ ++static krb5_error_code ++set_primary_name(krb5_context context, key_serial_t collection_id, ++ const char *subsidiary_name) ++{ ++ krb5_error_code ret; ++ key_serial_t key; ++ void *payload = NULL; ++ int payloadlen; ++ ++ ret = krb5_krcc_unparse_index(context, KRCC_COLLECTION_VERSION, ++ subsidiary_name, &payload, &payloadlen); ++ if (ret) ++ return ret; ++ key = add_key(KRCC_KEY_TYPE_USER, KRCC_COLLECTION_PRIMARY, ++ payload, payloadlen, collection_id); ++ free(payload); ++ return (key == -1) ? errno : 0; ++} ++ ++/* ++ * Get or initialize the primary name within collection_id and set ++ * *subsidiary_out to its value. If initializing a legacy collection, look ++ * for a legacy cache and add it to the collection. ++ */ ++static krb5_error_code ++get_primary_name(krb5_context context, const char *anchor_name, ++ const char *collection_name, key_serial_t collection_id, ++ char **subsidiary_out) ++{ ++ krb5_error_code ret; ++ key_serial_t primary_id, legacy; ++ void *payload = NULL; ++ int payloadlen; ++ krb5_int32 version; ++ char *subsidiary_name = NULL; ++ ++ *subsidiary_out = NULL; ++ ++ primary_id = keyctl_search(collection_id, KRCC_KEY_TYPE_USER, ++ KRCC_COLLECTION_PRIMARY, 0); ++ if (primary_id == -1) { ++ /* Initialize the primary key using the collection name. We can't name ++ * a key with the empty string, so map that to an arbitrary string. */ ++ subsidiary_name = strdup((*collection_name == '\0') ? "tkt" : ++ collection_name); ++ if (subsidiary_name == NULL) { ++ ret = ENOMEM; ++ goto cleanup; ++ } ++ ret = set_primary_name(context, collection_id, subsidiary_name); ++ if (ret) ++ goto cleanup; ++ ++ if (strcmp(anchor_name, KRCC_LEGACY_ANCHOR) == 0) { ++ /* Look for a cache created by old code. If we find one, add it to ++ * the collection. */ ++ legacy = keyctl_search(KEY_SPEC_SESSION_KEYRING, ++ KRCC_KEY_TYPE_KEYRING, subsidiary_name, 0); ++ if (legacy != -1 && keyctl_link(legacy, collection_id) == -1) { ++ ret = errno; ++ goto cleanup; ++ } ++ } ++ } else { ++ /* Read, parse, and free the primary key's payload. */ ++ payloadlen = keyctl_read_alloc(primary_id, &payload); ++ if (payloadlen == -1) { ++ ret = errno; ++ goto cleanup; ++ } ++ ret = krb5_krcc_parse_index(context, &version, &subsidiary_name, ++ payload, payloadlen); ++ if (ret) ++ goto cleanup; ++ ++ if (version != KRCC_COLLECTION_VERSION) { ++ ret = KRB5_KCC_UNKNOWN_VERSION; ++ goto cleanup; ++ } ++ } ++ ++ *subsidiary_out = subsidiary_name; ++ subsidiary_name = NULL; ++ ++cleanup: ++ free(payload); ++ free(subsidiary_name); ++ return ret; ++} ++ ++/* ++ * Create a keyring with a unique random name within collection_id. Set ++ * *subsidiary to its name and *cache_id_out to its key serial number. + */ +-static int KRB5_CALLCONV +-krb5_krcc_getkeycount(key_serial_t cred_ring) ++static krb5_error_code ++unique_keyring(krb5_context context, key_serial_t collection_id, ++ char **subsidiary_out, key_serial_t *cache_id_out) + { +- int res, nkeys; ++ key_serial_t key; ++ krb5_error_code ret; ++ char uniquename[sizeof(KRCC_NAME_PREFIX) + KRCC_NAME_RAND_CHARS]; ++ int prefixlen = sizeof(KRCC_NAME_PREFIX) - 1; ++ int tries; ++ ++ *subsidiary_out = NULL; ++ *cache_id_out = 0; ++ ++ memcpy(uniquename, KRCC_NAME_PREFIX, sizeof(KRCC_NAME_PREFIX)); ++ k5_cc_mutex_lock(context, &krb5int_krcc_mutex); ++ ++ /* Loop until we successfully create a new ccache keyring with ++ * a unique name, or we get an error. Limit to 100 tries. */ ++ tries = 100; ++ while (tries-- > 0) { ++ ret = krb5int_random_string(context, uniquename + prefixlen, ++ KRCC_NAME_RAND_CHARS); ++ if (ret) ++ goto cleanup; ++ ++ key = keyctl_search(collection_id, KRCC_KEY_TYPE_KEYRING, uniquename, ++ 0); ++ if (key < 0) { ++ /* Name does not already exist. Create it to reserve the name. */ ++ key = add_key(KRCC_KEY_TYPE_KEYRING, uniquename, NULL, 0, ++ collection_id); ++ if (key < 0) { ++ ret = errno; ++ goto cleanup; ++ } ++ break; ++ } ++ } + +- res = keyctl_read(cred_ring, NULL, 0); +- if (res > 0) +- nkeys = (res / sizeof(key_serial_t)) - 1; +- else +- nkeys = 0; +- return(nkeys); ++ if (tries <= 0) { ++ ret = KRB5_CC_BADNAME; ++ goto cleanup; ++ } ++ ++ *subsidiary_out = strdup(uniquename); ++ if (*subsidiary_out == NULL) { ++ ret = ENOMEM; ++ goto cleanup; ++ } ++ *cache_id_out = key; ++ ret = KRB5_OK; ++cleanup: ++ k5_cc_mutex_unlock(context, &krb5int_krcc_mutex); ++ return ret; ++} ++ ++static krb5_error_code ++add_cred_key(const char *name, const void *payload, size_t plen, ++ key_serial_t cache_id, krb5_boolean legacy_type) ++{ ++ key_serial_t key; ++ ++ if (!legacy_type) { ++ /* Try the preferred cred key type; fall back if no kernel support. */ ++ key = add_key(KRCC_CRED_KEY_TYPE, name, payload, plen, cache_id); ++ if (key != -1) ++ return 0; ++ else if (errno != EINVAL && errno != ENODEV) ++ return errno; ++ } ++ /* Use the user key type. */ ++ key = add_key(KRCC_KEY_TYPE_USER, name, payload, plen, cache_id); ++ return (key == -1) ? errno : 0; + } + + /* +@@ -388,24 +834,40 @@ static krb5_error_code KRB5_CALLCONV + krb5_krcc_initialize(krb5_context context, krb5_ccache id, + krb5_principal princ) + { ++ krb5_krcc_data *data = (krb5_krcc_data *)id->data; + krb5_error_code kret; ++ const char *cache_name, *p; + + DEBUG_PRINT(("krb5_krcc_initialize: entered\n")); + +- kret = k5_cc_mutex_lock(context, &((krb5_krcc_data *) id->data)->lock); +- if (kret) +- return kret; ++ k5_cc_mutex_lock(context, &data->lock); + + kret = krb5_krcc_clearcache(context, id); + if (kret != KRB5_OK) + goto out; + ++ if (!data->cache_id) { ++ /* The key didn't exist at resolve time. Check again and create the ++ * key if it still isn't there. */ ++ p = strrchr(data->name, ':'); ++ cache_name = (p != NULL) ? p + 1 : data->name; ++ kret = find_or_create_keyring(data->collection_id, 0, cache_name, ++ &data->cache_id); ++ if (kret) ++ goto out; ++ } ++ ++ /* If this is the legacy cache in a legacy session collection, link it ++ * directly to the session keyring so that old code can see it. */ ++ if (is_legacy_cache_name(data->name)) ++ (void)keyctl_link(data->cache_id, KEY_SPEC_SESSION_KEYRING); ++ + kret = krb5_krcc_save_principal(context, id, princ); + if (kret == KRB5_OK) + krb5_change_cache(); + + out: +- k5_cc_mutex_unlock(context, &((krb5_krcc_data *) id->data)->lock); ++ k5_cc_mutex_unlock(context, &data->lock); + return kret; + } + +@@ -460,14 +922,14 @@ krb5_krcc_clearcache(krb5_context context, krb5_ccache id) + + d = (krb5_krcc_data *) id->data; + +- DEBUG_PRINT(("krb5_krcc_clearcache: ring_id %d, princ_id %d, " +- "numkeys is %d\n", d->ring_id, d->princ_id, d->numkeys)); ++ DEBUG_PRINT(("krb5_krcc_clearcache: cache_id %d, princ_id %d\n", ++ d->cache_id, d->princ_id)); + +- res = keyctl_clear(d->ring_id); +- if (res != 0) { +- return errno; ++ if (d->cache_id) { ++ res = keyctl_clear(d->cache_id); ++ if (res != 0) ++ return errno; + } +- d->numkeys = 0; + d->princ_id = 0; + krb5_krcc_update_change_time(d); + +@@ -484,7 +946,7 @@ krb5_krcc_clearcache(krb5_context context, krb5_ccache id) + static krb5_error_code KRB5_CALLCONV + krb5_krcc_destroy(krb5_context context, krb5_ccache id) + { +- krb5_error_code kret; ++ krb5_error_code kret = 0; + krb5_krcc_data *d; + int res; + +@@ -492,30 +954,67 @@ krb5_krcc_destroy(krb5_context context, krb5_ccache id) + + d = (krb5_krcc_data *) id->data; + +- kret = k5_cc_mutex_lock(context, &d->lock); +- if (kret) +- return kret; ++ k5_cc_mutex_lock(context, &d->lock); + + krb5_krcc_clearcache(context, id); +- free(d->name); +- res = keyctl_unlink(d->ring_id, d->parent_id); +- if (res < 0) { +- kret = errno; +- DEBUG_PRINT(("krb5_krcc_destroy: unlinking key %d from ring %d: %s", +- d->ring_id, d->parent_id, error_message(errno))); +- goto cleanup; ++ if (d->cache_id) { ++ res = keyctl_unlink(d->cache_id, d->collection_id); ++ if (res < 0) { ++ kret = errno; ++ DEBUG_PRINT(("unlinking key %d from ring %d: %s", ++ d->cache_id, d->collection_id, error_message(errno))); ++ } ++ /* If this is a legacy cache, unlink it from the session anchor. */ ++ if (is_legacy_cache_name(d->name)) ++ (void)keyctl_unlink(d->cache_id, KEY_SPEC_SESSION_KEYRING); + } +-cleanup: ++ + k5_cc_mutex_unlock(context, &d->lock); + k5_cc_mutex_destroy(&d->lock); ++ free(d->name); + free(d); + free(id); + + krb5_change_cache(); + +- return KRB5_OK; ++ return kret; + } + ++/* Create a cache handle for a cache ID. */ ++static krb5_error_code ++make_cache(key_serial_t collection_id, key_serial_t cache_id, ++ const char *anchor_name, const char *collection_name, ++ const char *subsidiary_name, krb5_ccache *cache_out) ++{ ++ krb5_error_code ret; ++ krb5_ccache ccache = NULL; ++ krb5_krcc_data *d; ++ key_serial_t pkey = 0; ++ ++ /* Determine the key containing principal information, if present. */ ++ pkey = keyctl_search(cache_id, KRCC_KEY_TYPE_USER, KRCC_SPEC_PRINC_KEYNAME, ++ 0); ++ if (pkey < 0) ++ pkey = 0; ++ ++ ccache = malloc(sizeof(struct _krb5_ccache)); ++ if (!ccache) ++ return ENOMEM; ++ ++ ret = krb5_krcc_new_data(anchor_name, collection_name, subsidiary_name, ++ cache_id, collection_id, &d); ++ if (ret) { ++ free(ccache); ++ return ret; ++ } ++ ++ d->princ_id = pkey; ++ ccache->ops = &krb5_krcc_ops; ++ ccache->data = d; ++ ccache->magic = KV5M_CCACHE; ++ *cache_out = ccache; ++ return 0; ++} + + /* + * Requires: +@@ -538,101 +1037,42 @@ cleanup: + */ + + static krb5_error_code KRB5_CALLCONV +-krb5_krcc_resolve(krb5_context context, krb5_ccache * id, const char *full_residual) ++krb5_krcc_resolve(krb5_context context, krb5_ccache *id, const char *residual) + { +- krb5_ccache lid; +- krb5_error_code kret; +- krb5_krcc_data *d; +- key_serial_t key; +- key_serial_t pkey = 0; +- int nkeys = 0; +- int res; +- krb5_krcc_ring_ids_t ids; +- key_serial_t ring_id; +- const char *residual; ++ krb5_error_code ret; ++ key_serial_t collection_id, cache_id; ++ char *anchor_name = NULL, *collection_name = NULL, *subsidiary_name = NULL; + +- DEBUG_PRINT(("krb5_krcc_resolve: entered with name '%s'\n", +- full_residual)); ++ ret = parse_residual(residual, &anchor_name, &collection_name, ++ &subsidiary_name); ++ if (ret) ++ goto cleanup; ++ ret = get_collection(anchor_name, collection_name, &collection_id); ++ if (ret) ++ goto cleanup; + +- res = krb5_krcc_get_ring_ids(&ids); +- if (res) { +- kret = EINVAL; +- DEBUG_PRINT(("krb5_krcc_resolve: Error getting ring id values!\n")); +- return kret; ++ if (subsidiary_name == NULL) { ++ /* Retrieve or initialize the primary name for the collection. */ ++ ret = get_primary_name(context, anchor_name, collection_name, ++ collection_id, &subsidiary_name); ++ if (ret) ++ goto cleanup; + } + +- if (strncmp(full_residual, "thread:", 7) == 0) { +- residual = full_residual + 7; +- ring_id = ids.thread; +- } else if (strncmp(full_residual, "process:", 8) == 0) { +- residual = full_residual + 8; +- ring_id = ids.process; +- } else { +- residual = full_residual; +- ring_id = ids.session; +- } ++ /* Look up the cache keyring ID, if the cache is already initialized. */ ++ cache_id = keyctl_search(collection_id, KRCC_KEY_TYPE_KEYRING, ++ subsidiary_name, 0); ++ if (cache_id < 0) ++ cache_id = 0; + +- DEBUG_PRINT(("krb5_krcc_resolve: searching ring %d for residual '%s'\n", +- ring_id, residual)); ++ ret = make_cache(collection_id, cache_id, anchor_name, collection_name, ++ subsidiary_name, id); + +- /* +- * Use keyctl_search instead of request_key. If we're supposed +- * to be looking for a process ccache, we shouldn't find a +- * thread ccache. +- * XXX But should we look in the session ring if we don't find it +- * in the process ring? Same goes for thread. Should we look in +- * the process and session rings if not found in the thread ring? +- * +- */ +- key = keyctl_search(ring_id, KRCC_KEY_TYPE_KEYRING, residual, 0); +- if (key < 0) { +- key = add_key(KRCC_KEY_TYPE_KEYRING, residual, NULL, 0, ring_id); +- if (key < 0) { +- kret = errno; +- DEBUG_PRINT(("krb5_krcc_resolve: Error adding new " +- "keyring '%s': %s\n", residual, strerror(errno))); +- return kret; +- } +- DEBUG_PRINT(("krb5_krcc_resolve: new keyring '%s', " +- "key %d, added to keyring %d\n", +- residual, key, ring_id)); +- } else { +- DEBUG_PRINT(("krb5_krcc_resolve: found existing " +- "key %d, with name '%s' in keyring %d\n", +- key, residual, ring_id)); +- /* Determine key containing principal information */ +- pkey = keyctl_search(key, KRCC_KEY_TYPE_USER, +- KRCC_SPEC_PRINC_KEYNAME, 0); +- if (pkey < 0) { +- DEBUG_PRINT(("krb5_krcc_resolve: Error locating principal " +- "info for existing ccache in ring %d: %s\n", +- key, strerror(errno))); +- pkey = 0; +- } +- /* Determine how many keys exist */ +- nkeys = krb5_krcc_getkeycount(key); +- } +- +- lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache)); +- if (lid == NULL) +- return KRB5_CC_NOMEM; +- +- +- kret = krb5_krcc_new_data(residual, key, ring_id, &d); +- if (kret) { +- free(lid); +- return kret; +- } +- +- DEBUG_PRINT(("krb5_krcc_resolve: ring_id %d, princ_id %d, " +- "nkeys %d\n", key, pkey, nkeys)); +- d->princ_id = pkey; +- d->numkeys = nkeys; +- lid->ops = &krb5_krcc_ops; +- lid->data = d; +- lid->magic = KV5M_CCACHE; +- *id = lid; +- return KRB5_OK; ++cleanup: ++ free(anchor_name); ++ free(collection_name); ++ free(subsidiary_name); ++ return ret; + } + + /* +@@ -653,47 +1093,37 @@ krb5_krcc_start_seq_get(krb5_context context, krb5_ccache id, + krb5_cc_cursor * cursor) + { + krb5_krcc_cursor krcursor; +- krb5_error_code kret; + krb5_krcc_data *d; +- unsigned int size; +- int res; ++ void *keys; ++ long size; + + DEBUG_PRINT(("krb5_krcc_start_seq_get: entered\n")); + + d = id->data; +- kret = k5_cc_mutex_lock(context, &d->lock); +- if (kret) +- return kret; +- +- /* +- * Determine how many keys currently exist and update numkeys. +- * We cannot depend on the current value of numkeys because +- * the ccache may have been updated elsewhere +- */ +- d->numkeys = krb5_krcc_getkeycount(d->ring_id); ++ k5_cc_mutex_lock(context, &d->lock); + +- size = sizeof(*krcursor) + ((d->numkeys + 1) * sizeof(key_serial_t)); +- +- krcursor = (krb5_krcc_cursor) malloc(size); +- if (krcursor == NULL) { ++ if (!d->cache_id) { + k5_cc_mutex_unlock(context, &d->lock); +- return KRB5_CC_NOMEM; ++ return KRB5_FCC_NOFILE; + } + +- krcursor->keys = (key_serial_t *) ((char *) krcursor + sizeof(*krcursor)); +- res = keyctl_read(d->ring_id, (char *) krcursor->keys, +- ((d->numkeys + 1) * sizeof(key_serial_t))); +- if (res < 0 || res > ((d->numkeys + 1) * sizeof(key_serial_t))) { +- DEBUG_PRINT(("Read %d bytes from keyring, numkeys %d: %s\n", +- res, d->numkeys, strerror(errno))); +- free(krcursor); ++ size = keyctl_read_alloc(d->cache_id, &keys); ++ if (size == -1) { ++ DEBUG_PRINT(("Error getting from keyring: %s\n", strerror(errno))); + k5_cc_mutex_unlock(context, &d->lock); + return KRB5_CC_IO; + } + +- krcursor->numkeys = d->numkeys; +- krcursor->currkey = 0; ++ krcursor = calloc(1, sizeof(*krcursor)); ++ if (krcursor == NULL) { ++ free(keys); ++ k5_cc_mutex_unlock(context, &d->lock); ++ return KRB5_CC_NOMEM; ++ } ++ + krcursor->princ_id = d->princ_id; ++ krcursor->numkeys = size / sizeof(key_serial_t); ++ krcursor->keys = keys; + + k5_cc_mutex_unlock(context, &d->lock); + *cursor = (krb5_cc_cursor) krcursor; +@@ -741,14 +1171,14 @@ krb5_krcc_next_cred(krb5_context context, krb5_ccache id, + memset(creds, 0, sizeof(krb5_creds)); + + /* If we're pointing past the end of the keys array, there are no more */ +- if (krcursor->currkey > krcursor->numkeys) ++ if (krcursor->currkey >= krcursor->numkeys) + return KRB5_CC_END; + + /* If we're pointing at the entry with the principal, skip it */ + if (krcursor->keys[krcursor->currkey] == krcursor->princ_id) { + krcursor->currkey++; + /* Check if we have now reached the end */ +- if (krcursor->currkey > krcursor->numkeys) ++ if (krcursor->currkey >= krcursor->numkeys) + return KRB5_CC_END; + } + +@@ -763,7 +1193,7 @@ krb5_krcc_next_cred(krb5_context context, krb5_ccache id, + } + krcursor->currkey++; + +- kret = krb5_krcc_parse_cred(context, id, creds, payload, psize); ++ kret = krb5_krcc_parse_cred(context, creds, payload, psize); + + freepayload: + if (payload) free(payload); +@@ -787,19 +1217,24 @@ static krb5_error_code KRB5_CALLCONV + krb5_krcc_end_seq_get(krb5_context context, krb5_ccache id, + krb5_cc_cursor * cursor) + { ++ krb5_krcc_cursor krcursor = (krb5_krcc_cursor)*cursor; + DEBUG_PRINT(("krb5_krcc_end_seq_get: entered\n")); + +- free(*cursor); +- *cursor = 0L; ++ if (krcursor != NULL) { ++ free(krcursor->keys); ++ free(krcursor); ++ } ++ *cursor = NULL; + return KRB5_OK; + } + + /* Utility routine: Creates the back-end data for a keyring cache. + + Call with the global list lock held. */ +-static krb5_error_code +-krb5_krcc_new_data(const char *name, key_serial_t ring, +- key_serial_t parent_ring, krb5_krcc_data ** datapp) ++static krb5_error_code ++krb5_krcc_new_data(const char *anchor_name, const char *collection_name, ++ const char *subsidiary_name, key_serial_t cache_id, ++ key_serial_t collection_id, krb5_krcc_data **datapp) + { + krb5_error_code kret; + krb5_krcc_data *d; +@@ -814,17 +1249,18 @@ krb5_krcc_new_data(const char *name, key_serial_t ring, + return kret; + } + +- d->name = strdup(name); +- if (d->name == NULL) { ++ kret = make_subsidiary_residual(anchor_name, collection_name, ++ subsidiary_name, &d->name); ++ if (kret) { + k5_cc_mutex_destroy(&d->lock); + free(d); +- return KRB5_CC_NOMEM; ++ return kret; + } + d->princ_id = 0; +- d->ring_id = ring; +- d->parent_id = parent_ring; +- d->numkeys = 0; ++ d->cache_id = cache_id; ++ d->collection_id = collection_id; + d->changetime = 0; ++ d->is_legacy_type = (strcmp(anchor_name, KRCC_LEGACY_ANCHOR) == 0); + krb5_krcc_update_change_time(d); + + *datapp = d; +@@ -846,82 +1282,73 @@ krb5_krcc_new_data(const char *name, key_serial_t ring, + static krb5_error_code KRB5_CALLCONV + krb5_krcc_generate_new(krb5_context context, krb5_ccache * id) + { +- krb5_ccache lid; +- char uniquename[8]; ++ krb5_ccache lid = NULL; + krb5_error_code kret; ++ char *anchor_name = NULL, *collection_name = NULL, *subsidiary_name = NULL; ++ char *new_subsidiary_name = NULL, *new_residual = NULL; + krb5_krcc_data *d; +- key_serial_t ring_id = KEY_SPEC_SESSION_KEYRING; +- key_serial_t key; ++ key_serial_t collection_id; ++ key_serial_t cache_id = 0; + + DEBUG_PRINT(("krb5_krcc_generate_new: entered\n")); + ++ /* Determine the collection in which we will create the cache.*/ ++ kret = get_default(context, &anchor_name, &collection_name, ++ &subsidiary_name); ++ if (kret) ++ return kret; ++ if (anchor_name == NULL) { ++ kret = parse_residual(KRCC_DEFAULT_UNIQUE_COLLECTION, &anchor_name, ++ &collection_name, &subsidiary_name); ++ if (kret) ++ return kret; ++ } ++ if (subsidiary_name != NULL) { ++ krb5_set_error_message(context, KRB5_DCC_CANNOT_CREATE, ++ _("Can't create new subsidiary cache because " ++ "default cache is already a subsdiary")); ++ kret = KRB5_DCC_CANNOT_CREATE; ++ goto cleanup; ++ } ++ + /* Allocate memory */ + lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache)); +- if (lid == NULL) +- return KRB5_CC_NOMEM; ++ if (lid == NULL) { ++ kret = ENOMEM; ++ goto cleanup; ++ } + + lid->ops = &krb5_krcc_ops; + +- kret = k5_cc_mutex_lock(context, &krb5int_krcc_mutex); +- if (kret) { +- free(lid); +- return kret; +- } +- +-/* XXX These values are platform-specific and should not be here! */ +-/* XXX There is a bug in FC5 where these are not included in errno.h */ +-#ifndef ENOKEY +-#define ENOKEY 126 /* Required key not available */ +-#endif +-#ifndef EKEYEXPIRED +-#define EKEYEXPIRED 127 /* Key has expired */ +-#endif +-#ifndef EKEYREVOKED +-#define EKEYREVOKED 128 /* Key has been revoked */ +-#endif +-#ifndef EKEYREJECTED +-#define EKEYREJECTED 129 /* Key was rejected by service */ +-#endif ++ /* Make a unique keyring within the chosen collection. */ ++ kret = get_collection(anchor_name, collection_name, &collection_id); ++ if (kret) ++ goto cleanup; ++ kret = unique_keyring(context, collection_id, &new_subsidiary_name, ++ &cache_id); ++ if (kret) ++ goto cleanup; + +- /* +- * Loop until we successfully create a new ccache keyring with +- * a unique name, or we get an error. +- */ +- while (1) { +- kret = krb5int_random_string(context, uniquename, sizeof(uniquename)); +- if (kret) { +- k5_cc_mutex_unlock(context, &krb5int_krcc_mutex); +- free(lid); +- return kret; +- } ++ kret = krb5_krcc_new_data(anchor_name, collection_name, ++ new_subsidiary_name, cache_id, collection_id, ++ &d); ++ if (kret) ++ goto cleanup; + +- DEBUG_PRINT(("krb5_krcc_generate_new: searching for name '%s'\n", +- uniquename)); +- key = keyctl_search(ring_id, KRCC_KEY_TYPE_KEYRING, uniquename, 0); +- /*XXX*/ DEBUG_PRINT(("krb5_krcc_generate_new: after searching for '%s', key = %d, errno = %d\n", uniquename, key, errno)); +- if (key < 0 && errno == ENOKEY) { +- /* name does not already exist, create it to reserve the name */ +- key = add_key(KRCC_KEY_TYPE_KEYRING, uniquename, NULL, 0, ring_id); +- if (key < 0) { +- kret = errno; +- DEBUG_PRINT(("krb5_krcc_generate_new: '%s' trying to " +- "create '%s'\n", strerror(errno), uniquename)); +- k5_cc_mutex_unlock(context, &krb5int_krcc_mutex); +- return kret; +- } +- break; +- } +- } ++ lid->data = d; ++ krb5_change_cache(); + +- kret = krb5_krcc_new_data(uniquename, key, ring_id, &d); +- k5_cc_mutex_unlock(context, &krb5int_krcc_mutex); ++cleanup: ++ free(anchor_name); ++ free(collection_name); ++ free(subsidiary_name); ++ free(new_subsidiary_name); ++ free(new_residual); + if (kret) { + free(lid); + return kret; + } +- lid->data = d; + *id = lid; +- krb5_change_cache(); + return KRB5_OK; + } + +@@ -1023,14 +1450,16 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds) + krb5_krcc_data *d = (krb5_krcc_data *) id->data; + char *payload = NULL; + unsigned int payloadlen; +- key_serial_t newkey; + char *keyname = NULL; + + DEBUG_PRINT(("krb5_krcc_store: entered\n")); + +- kret = k5_cc_mutex_lock(context, &d->lock); +- if (kret) +- return kret; ++ k5_cc_mutex_lock(context, &d->lock); ++ ++ if (!d->cache_id) { ++ k5_cc_mutex_unlock(context, &d->lock); ++ return KRB5_FCC_NOFILE; ++ } + + /* Get the service principal name and use it as the key name */ + kret = krb5_unparse_name(context, creds->server, &keyname); +@@ -1040,24 +1469,19 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds) + } + + /* Serialize credential into memory */ +- kret = krb5_krcc_unparse_cred(context, id, creds, &payload, &payloadlen); ++ kret = krb5_krcc_unparse_cred_alloc(context, creds, &payload, &payloadlen); + if (kret != KRB5_OK) + goto errout; + + /* Add new key (credentials) into keyring */ + DEBUG_PRINT(("krb5_krcc_store: adding new key '%s' to keyring %d\n", +- keyname, d->ring_id)); +- newkey = add_key(KRCC_KEY_TYPE_USER, keyname, payload, +- payloadlen, d->ring_id); +- if (newkey < 0) { +- kret = errno; +- DEBUG_PRINT(("Error adding user key '%s': %s\n", +- keyname, strerror(kret))); +- } else { +- d->numkeys++; +- kret = KRB5_OK; +- krb5_krcc_update_change_time(d); +- } ++ keyname, d->cache_id)); ++ kret = add_cred_key(keyname, payload, payloadlen, d->cache_id, ++ d->is_legacy_type); ++ if (kret) ++ goto errout; ++ ++ krb5_krcc_update_change_time(d); + + errout: + if (keyname) +@@ -1073,36 +1497,30 @@ static krb5_error_code KRB5_CALLCONV + krb5_krcc_last_change_time(krb5_context context, krb5_ccache id, + krb5_timestamp *change_time) + { +- krb5_error_code ret = 0; + krb5_krcc_data *data = (krb5_krcc_data *) id->data; + +- *change_time = 0; +- +- ret = k5_cc_mutex_lock(context, &data->lock); +- if (!ret) { +- *change_time = data->changetime; +- k5_cc_mutex_unlock(context, &data->lock); +- } +- +- return ret; ++ k5_cc_mutex_lock(context, &data->lock); ++ *change_time = data->changetime; ++ k5_cc_mutex_unlock(context, &data->lock); ++ return 0; + } + + static krb5_error_code KRB5_CALLCONV + krb5_krcc_lock(krb5_context context, krb5_ccache id) + { +- krb5_error_code ret = 0; + krb5_krcc_data *data = (krb5_krcc_data *) id->data; +- ret = k5_cc_mutex_lock(context, &data->lock); +- return ret; ++ ++ k5_cc_mutex_lock(context, &data->lock); ++ return 0; + } + + static krb5_error_code KRB5_CALLCONV + krb5_krcc_unlock(krb5_context context, krb5_ccache id) + { +- krb5_error_code ret = 0; + krb5_krcc_data *data = (krb5_krcc_data *) id->data; +- ret = k5_cc_mutex_unlock(context, &data->lock); +- return ret; ++ ++ k5_cc_mutex_unlock(context, &data->lock); ++ return 0; + } + + +@@ -1112,7 +1530,7 @@ krb5_krcc_save_principal(krb5_context context, krb5_ccache id, + { + krb5_krcc_data *d; + krb5_error_code kret; +- char *payload; ++ char *payload = NULL; + key_serial_t newkey; + unsigned int payloadsize; + krb5_krcc_bc bc; +@@ -1121,14 +1539,19 @@ krb5_krcc_save_principal(krb5_context context, krb5_ccache id, + + d = (krb5_krcc_data *) id->data; + +- payload = malloc(GUESS_CRED_SIZE); ++ /* Do a dry run first to calculate the size. */ ++ bc.bpp = bc.endp = NULL; ++ bc.size = 0; ++ kret = krb5_krcc_unparse_principal(context, princ, &bc); ++ CHECK_N_GO(kret, errout); ++ ++ /* Allocate a buffer and serialize for real. */ ++ payload = malloc(bc.size); + if (payload == NULL) + return KRB5_CC_NOMEM; +- + bc.bpp = payload; +- bc.endp = payload + GUESS_CRED_SIZE; +- +- kret = krb5_krcc_unparse_principal(context, id, princ, &bc); ++ bc.endp = payload + bc.size; ++ kret = krb5_krcc_unparse_principal(context, princ, &bc); + CHECK_N_GO(kret, errout); + + /* Add new key into keyring */ +@@ -1140,14 +1563,14 @@ krb5_krcc_save_principal(krb5_context context, krb5_ccache id, + rc = krb5_unparse_name(context, princ, &princname); + DEBUG_PRINT(("krb5_krcc_save_principal: adding new key '%s' " + "to keyring %d for principal '%s'\n", +- KRCC_SPEC_PRINC_KEYNAME, d->ring_id, ++ KRCC_SPEC_PRINC_KEYNAME, d->cache_id, + rc ? "" : princname)); + if (rc == 0) + krb5_free_unparsed_name(context, princname); + } + #endif + newkey = add_key(KRCC_KEY_TYPE_USER, KRCC_SPEC_PRINC_KEYNAME, payload, +- payloadsize, d->ring_id); ++ payloadsize, d->cache_id); + if (newkey < 0) { + kret = errno; + DEBUG_PRINT(("Error adding principal key: %s\n", strerror(kret))); +@@ -1172,11 +1595,9 @@ krb5_krcc_retrieve_principal(krb5_context context, krb5_ccache id, + int psize; + krb5_krcc_bc bc; + +- kret = k5_cc_mutex_lock(context, &d->lock); +- if (kret) +- return kret; ++ k5_cc_mutex_lock(context, &d->lock); + +- if (!d->princ_id) { ++ if (!d->cache_id || !d->princ_id) { + princ = 0L; + kret = KRB5_FCC_NOFILE; + goto errout; +@@ -1191,7 +1612,7 @@ krb5_krcc_retrieve_principal(krb5_context context, krb5_ccache id, + } + bc.bpp = payload; + bc.endp = (char *)payload + psize; +- kret = krb5_krcc_parse_principal(context, id, princ, &bc); ++ kret = krb5_krcc_parse_principal(context, princ, &bc); + + errout: + if (payload) +@@ -1200,57 +1621,195 @@ errout: + return kret; + } + +-static int +-krb5_krcc_get_ring_ids(krb5_krcc_ring_ids_t *p) +-{ +- key_serial_t ids_key; +- char ids_buf[128]; +- key_serial_t session, process, thread; +- long val; ++struct krcc_ptcursor_data { ++ key_serial_t collection_id; ++ char *anchor_name; ++ char *collection_name; ++ char *subsidiary_name; ++ char *primary_name; ++ krb5_boolean first; ++ long num_keys; ++ long next_key; ++ key_serial_t *keys; ++}; + +- DEBUG_PRINT(("krb5_krcc_get_ring_ids: entered\n")); ++static krb5_error_code KRB5_CALLCONV ++krb5_krcc_ptcursor_new(krb5_context context, krb5_cc_ptcursor *cursor_out) ++{ ++ struct krcc_ptcursor_data *data; ++ krb5_cc_ptcursor cursor; ++ krb5_error_code ret; ++ long size; ++ ++ *cursor_out = NULL; ++ ++ cursor = k5alloc(sizeof(struct krb5_cc_ptcursor_s), &ret); ++ if (cursor == NULL) ++ return ENOMEM; ++ data = k5alloc(sizeof(struct krcc_ptcursor_data), &ret); ++ if (data == NULL) ++ goto error; ++ cursor->ops = &krb5_krcc_ops; ++ cursor->data = data; ++ data->first = TRUE; ++ ++ ret = get_default(context, &data->anchor_name, &data->collection_name, ++ &data->subsidiary_name); ++ if (ret) ++ goto error; ++ ++ /* If there is no default collection, return an empty cursor. */ ++ if (data->anchor_name == NULL) { ++ *cursor_out = cursor; ++ return 0; ++ } + +- if (!p) +- return EINVAL; ++ ret = get_collection(data->anchor_name, data->collection_name, ++ &data->collection_id); ++ if (ret) ++ goto error; ++ ++ if (data->subsidiary_name == NULL) { ++ ret = get_primary_name(context, data->anchor_name, ++ data->collection_name, data->collection_id, ++ &data->primary_name); ++ if (ret) ++ goto error; ++ ++ size = keyctl_read_alloc(data->collection_id, (void **)&data->keys); ++ if (size == -1) { ++ ret = errno; ++ goto error; ++ } ++ data->num_keys = size / sizeof(key_serial_t); ++ } + +- /* Use the defaults in case we find no ids key */ +- p->session = KEY_SPEC_SESSION_KEYRING; +- p->process = KEY_SPEC_PROCESS_KEYRING; +- p->thread = KEY_SPEC_THREAD_KEYRING; ++ *cursor_out = cursor; ++ return 0; + +- /* +- * Note that in the "normal" case, this will not be found. +- * The Linux gssd creates this key while creating a +- * context to communicate the user's key serial numbers. +- */ +- ids_key = request_key(KRCC_KEY_TYPE_USER, KRCC_SPEC_IDS_KEYNAME, NULL, 0); +- if (ids_key < 0) +- goto out; ++error: ++ krb5_krcc_ptcursor_free(context, &cursor); ++ return ret; ++} + +- DEBUG_PRINT(("krb5_krcc_get_ring_ids: processing '%s' key %d\n", +- KRCC_SPEC_IDS_KEYNAME, ids_key)); +- /* +- * Read and parse the ids file +- */ +- memset(ids_buf, '\0', sizeof(ids_buf)); +- val = keyctl_read(ids_key, ids_buf, sizeof(ids_buf)); +- if (val > sizeof(ids_buf)) +- goto out; ++static krb5_error_code KRB5_CALLCONV ++krb5_krcc_ptcursor_next(krb5_context context, krb5_cc_ptcursor cursor, ++ krb5_ccache *cache_out) ++{ ++ krb5_error_code ret; ++ struct krcc_ptcursor_data *data; ++ key_serial_t key, cache_id = 0; ++ const char *first_name, *keytype, *sep, *subsidiary_name; ++ size_t keytypelen; ++ char *description = NULL; ++ ++ *cache_out = NULL; ++ ++ data = cursor->data; ++ ++ /* No keyring available */ ++ if (data->collection_id == 0) ++ return 0; ++ ++ if (data->first) { ++ /* Look for the primary cache for a collection cursor, or the ++ * subsidiary cache for a subsidiary cursor. */ ++ data->first = FALSE; ++ first_name = (data->primary_name != NULL) ? data->primary_name : ++ data->subsidiary_name; ++ cache_id = keyctl_search(data->collection_id, KRCC_KEY_TYPE_KEYRING, ++ first_name, 0); ++ if (cache_id != -1) { ++ return make_cache(data->collection_id, cache_id, data->anchor_name, ++ data->collection_name, first_name, cache_out); ++ } ++ } + +- val = sscanf(ids_buf, "%d:%d:%d", &session, &process, &thread); +- if (val != 3) +- goto out; ++ /* A subsidiary cursor yields at most the first cache. */ ++ if (data->subsidiary_name != NULL) ++ return 0; ++ ++ keytype = KRCC_KEY_TYPE_KEYRING ";"; ++ keytypelen = strlen(keytype); ++ ++ for (; data->next_key < data->num_keys; data->next_key++) { ++ /* Free any previously retrieved key description. */ ++ free(description); ++ description = NULL; ++ ++ /* ++ * Get the key description, which should have the form: ++ * typename;UID;GID;permissions;description ++ */ ++ key = data->keys[data->next_key]; ++ if (keyctl_describe_alloc(key, &description) < 0) ++ continue; ++ sep = strrchr(description, ';'); ++ if (sep == NULL) ++ continue; ++ subsidiary_name = sep + 1; ++ ++ /* Skip this key if it isn't a keyring. */ ++ if (strncmp(description, keytype, keytypelen) != 0) ++ continue; ++ ++ /* Don't repeat the primary cache. */ ++ if (strcmp(subsidiary_name, data->primary_name) == 0) ++ continue; ++ ++ /* We found a valid key */ ++ data->next_key++; ++ ret = make_cache(data->collection_id, key, data->anchor_name, ++ data->collection_name, subsidiary_name, cache_out); ++ free(description); ++ return ret; ++ } + +- p->session = session; +- p->process = process; +- p->thread = thread; ++ free(description); ++ return 0; ++} + +-out: +- DEBUG_PRINT(("krb5_krcc_get_ring_ids: returning %d:%d:%d\n", +- p->session, p->process, p->thread)); ++static krb5_error_code KRB5_CALLCONV ++krb5_krcc_ptcursor_free(krb5_context context, krb5_cc_ptcursor *cursor) ++{ ++ struct krcc_ptcursor_data *data = (*cursor)->data; ++ ++ if (data != NULL) { ++ free(data->anchor_name); ++ free(data->collection_name); ++ free(data->subsidiary_name); ++ free(data->primary_name); ++ free(data->keys); ++ free(data); ++ } ++ free(*cursor); ++ *cursor = NULL; + return 0; + } + ++static krb5_error_code KRB5_CALLCONV ++krb5_krcc_switch_to(krb5_context context, krb5_ccache cache) ++{ ++ krb5_krcc_data *data = cache->data; ++ krb5_error_code ret; ++ char *anchor_name = NULL, *collection_name = NULL, *subsidiary_name = NULL; ++ key_serial_t collection_id; ++ ++ ret = parse_residual(data->name, &anchor_name, &collection_name, ++ &subsidiary_name); ++ if (ret) ++ goto cleanup; ++ ret = get_collection(anchor_name, collection_name, &collection_id); ++ if (ret) ++ goto cleanup; ++ ret = set_primary_name(context, collection_id, subsidiary_name); ++cleanup: ++ free(anchor_name); ++ free(collection_name); ++ free(subsidiary_name); ++ return ret; ++} ++ + /* + * =============================================================== + * INTERNAL functions to parse a credential from a key payload +@@ -1271,8 +1830,8 @@ out: + * KRB5_CC_END - there were not len bytes available + */ + static krb5_error_code +-krb5_krcc_parse(krb5_context context, krb5_ccache id, krb5_pointer buf, +- unsigned int len, krb5_krcc_bc * bc) ++krb5_krcc_parse(krb5_context context, krb5_pointer buf, unsigned int len, ++ krb5_krcc_bc * bc) + { + DEBUG_PRINT(("krb5_krcc_parse: entered\n")); + +@@ -1290,8 +1849,8 @@ krb5_krcc_parse(krb5_context context, krb5_ccache id, krb5_pointer buf, + * and parse it into a credential structure. + */ + static krb5_error_code +-krb5_krcc_parse_cred(krb5_context context, krb5_ccache id, krb5_creds * creds, +- char *payload, int psize) ++krb5_krcc_parse_cred(krb5_context context, krb5_creds * creds, char *payload, ++ int psize) + { + krb5_error_code kret; + krb5_octet octet; +@@ -1301,36 +1860,36 @@ krb5_krcc_parse_cred(krb5_context context, krb5_ccache id, krb5_creds * creds, + /* Parse the pieces of the credential */ + bc.bpp = payload; + bc.endp = bc.bpp + psize; +- kret = krb5_krcc_parse_principal(context, id, &creds->client, &bc); ++ kret = krb5_krcc_parse_principal(context, &creds->client, &bc); + CHECK_N_GO(kret, out); + +- kret = krb5_krcc_parse_principal(context, id, &creds->server, &bc); ++ kret = krb5_krcc_parse_principal(context, &creds->server, &bc); + CHECK_N_GO(kret, cleanclient); + +- kret = krb5_krcc_parse_keyblock(context, id, &creds->keyblock, &bc); ++ kret = krb5_krcc_parse_keyblock(context, &creds->keyblock, &bc); + CHECK_N_GO(kret, cleanserver); + +- kret = krb5_krcc_parse_times(context, id, &creds->times, &bc); ++ kret = krb5_krcc_parse_times(context, &creds->times, &bc); + CHECK_N_GO(kret, cleanserver); + +- kret = krb5_krcc_parse_octet(context, id, &octet, &bc); ++ kret = krb5_krcc_parse_octet(context, &octet, &bc); + CHECK_N_GO(kret, cleanserver); + creds->is_skey = octet; + +- kret = krb5_krcc_parse_int32(context, id, &int32, &bc); ++ kret = krb5_krcc_parse_int32(context, &int32, &bc); + CHECK_N_GO(kret, cleanserver); + creds->ticket_flags = int32; + +- kret = krb5_krcc_parse_addrs(context, id, &creds->addresses, &bc); ++ kret = krb5_krcc_parse_addrs(context, &creds->addresses, &bc); + CHECK_N_GO(kret, cleanblock); + +- kret = krb5_krcc_parse_authdata(context, id, &creds->authdata, &bc); ++ kret = krb5_krcc_parse_authdata(context, &creds->authdata, &bc); + CHECK_N_GO(kret, cleanaddrs); + +- kret = krb5_krcc_parse_krb5data(context, id, &creds->ticket, &bc); ++ kret = krb5_krcc_parse_krb5data(context, &creds->ticket, &bc); + CHECK_N_GO(kret, cleanauthdata); + +- kret = krb5_krcc_parse_krb5data(context, id, &creds->second_ticket, &bc); ++ kret = krb5_krcc_parse_krb5data(context, &creds->second_ticket, &bc); + CHECK_N_GO(kret, cleanticket); + + kret = KRB5_OK; +@@ -1355,8 +1914,8 @@ out: + } + + static krb5_error_code +-krb5_krcc_parse_principal(krb5_context context, krb5_ccache id, +- krb5_principal * princ, krb5_krcc_bc * bc) ++krb5_krcc_parse_principal(krb5_context context, krb5_principal * princ, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + register krb5_principal tmpprinc; +@@ -1364,12 +1923,12 @@ krb5_krcc_parse_principal(krb5_context context, krb5_ccache id, + int i; + + /* Read principal type */ +- kret = krb5_krcc_parse_int32(context, id, &type, bc); ++ kret = krb5_krcc_parse_int32(context, &type, bc); + if (kret != KRB5_OK) + return kret; + + /* Read the number of components */ +- kret = krb5_krcc_parse_int32(context, id, &length, bc); ++ kret = krb5_krcc_parse_int32(context, &length, bc); + if (kret != KRB5_OK) + return kret; + +@@ -1380,12 +1939,7 @@ krb5_krcc_parse_principal(krb5_context context, krb5_ccache id, + if (tmpprinc == NULL) + return KRB5_CC_NOMEM; + if (length) { +- size_t msize = length; +- if (msize != length) { +- free(tmpprinc); +- return KRB5_CC_NOMEM; +- } +- tmpprinc->data = ALLOC(msize, krb5_data); ++ tmpprinc->data = calloc(length, sizeof(krb5_data)); + if (tmpprinc->data == 0) { + free(tmpprinc); + return KRB5_CC_NOMEM; +@@ -1396,15 +1950,12 @@ krb5_krcc_parse_principal(krb5_context context, krb5_ccache id, + tmpprinc->length = length; + tmpprinc->type = type; + +- kret = krb5_krcc_parse_krb5data(context, id, +- krb5_princ_realm(context, tmpprinc), bc); ++ kret = krb5_krcc_parse_krb5data(context, &tmpprinc->realm, bc); + i = 0; + CHECK(kret); + + for (i = 0; i < length; i++) { +- kret = krb5_krcc_parse_krb5data(context, id, +- krb5_princ_component(context, tmpprinc, +- i), bc); ++ kret = krb5_krcc_parse_krb5data(context, &tmpprinc->data[i], bc); + CHECK(kret); + } + *princ = tmpprinc; +@@ -1412,16 +1963,16 @@ krb5_krcc_parse_principal(krb5_context context, krb5_ccache id, + + errout: + while (--i >= 0) +- free(krb5_princ_component(context, tmpprinc, i)->data); +- free(krb5_princ_realm(context, tmpprinc)->data); ++ free(tmpprinc->data[i].data); ++ free(tmpprinc->realm.data); + free(tmpprinc->data); + free(tmpprinc); + return kret; + } + + static krb5_error_code +-krb5_krcc_parse_keyblock(krb5_context context, krb5_ccache id, +- krb5_keyblock * keyblock, krb5_krcc_bc * bc) ++krb5_krcc_parse_keyblock(krb5_context context, krb5_keyblock * keyblock, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + krb5_ui_2 ui2; +@@ -1430,26 +1981,22 @@ krb5_krcc_parse_keyblock(krb5_context context, krb5_ccache id, + keyblock->magic = KV5M_KEYBLOCK; + keyblock->contents = 0; + +- kret = krb5_krcc_parse_ui_2(context, id, &ui2, bc); ++ kret = krb5_krcc_parse_ui_2(context, &ui2, bc); + CHECK(kret); + keyblock->enctype = ui2; + +- kret = krb5_krcc_parse_int32(context, id, &int32, bc); ++ kret = krb5_krcc_parse_int32(context, &int32, bc); + CHECK(kret); + if (int32 < 0) + return KRB5_CC_NOMEM; + keyblock->length = int32; +- /* Overflow check. */ +- if (keyblock->length != int32) +- return KRB5_CC_NOMEM; + if (keyblock->length == 0) + return KRB5_OK; +- keyblock->contents = ALLOC(keyblock->length, krb5_octet); ++ keyblock->contents = malloc(keyblock->length); + if (keyblock->contents == NULL) + return KRB5_CC_NOMEM; + +- kret = krb5_krcc_parse(context, id, keyblock->contents, +- keyblock->length, bc); ++ kret = krb5_krcc_parse(context, keyblock->contents, keyblock->length, bc); + CHECK(kret); + + return KRB5_OK; +@@ -1460,25 +2007,25 @@ errout: + } + + static krb5_error_code +-krb5_krcc_parse_times(krb5_context context, krb5_ccache id, +- krb5_ticket_times * t, krb5_krcc_bc * bc) ++krb5_krcc_parse_times(krb5_context context, krb5_ticket_times * t, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + krb5_int32 i; + +- kret = krb5_krcc_parse_int32(context, id, &i, bc); ++ kret = krb5_krcc_parse_int32(context, &i, bc); + CHECK(kret); + t->authtime = i; + +- kret = krb5_krcc_parse_int32(context, id, &i, bc); ++ kret = krb5_krcc_parse_int32(context, &i, bc); + CHECK(kret); + t->starttime = i; + +- kret = krb5_krcc_parse_int32(context, id, &i, bc); ++ kret = krb5_krcc_parse_int32(context, &i, bc); + CHECK(kret); + t->endtime = i; + +- kret = krb5_krcc_parse_int32(context, id, &i, bc); ++ kret = krb5_krcc_parse_int32(context, &i, bc); + CHECK(kret); + t->renew_till = i; + +@@ -1488,8 +2035,8 @@ errout: + } + + static krb5_error_code +-krb5_krcc_parse_krb5data(krb5_context context, krb5_ccache id, +- krb5_data * data, krb5_krcc_bc * bc) ++krb5_krcc_parse_krb5data(krb5_context context, krb5_data * data, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + krb5_int32 len; +@@ -1497,12 +2044,12 @@ krb5_krcc_parse_krb5data(krb5_context context, krb5_ccache id, + data->magic = KV5M_DATA; + data->data = 0; + +- kret = krb5_krcc_parse_int32(context, id, &len, bc); ++ kret = krb5_krcc_parse_int32(context, &len, bc); + CHECK(kret); + if (len < 0) + return KRB5_CC_NOMEM; + data->length = len; +- if (data->length != len || data->length + 1 == 0) ++ if (data->length + 1 == 0) + return KRB5_CC_NOMEM; + + if (data->length == 0) { +@@ -1514,8 +2061,7 @@ krb5_krcc_parse_krb5data(krb5_context context, krb5_ccache id, + if (data->data == NULL) + return KRB5_CC_NOMEM; + +- kret = krb5_krcc_parse(context, id, data->data, (unsigned) data->length, +- bc); ++ kret = krb5_krcc_parse(context, data->data, (unsigned) data->length, bc); + CHECK(kret); + + data->data[data->length] = 0; /* Null terminate, just in case.... */ +@@ -1527,13 +2073,12 @@ errout: + } + + static krb5_error_code +-krb5_krcc_parse_int32(krb5_context context, krb5_ccache id, krb5_int32 * i, +- krb5_krcc_bc * bc) ++krb5_krcc_parse_int32(krb5_context context, krb5_int32 * i, krb5_krcc_bc * bc) + { + krb5_error_code kret; + unsigned char buf[4]; + +- kret = krb5_krcc_parse(context, id, buf, 4, bc); ++ kret = krb5_krcc_parse(context, buf, 4, bc); + if (kret) + return kret; + *i = load_32_be(buf); +@@ -1541,15 +2086,14 @@ krb5_krcc_parse_int32(krb5_context context, krb5_ccache id, krb5_int32 * i, + } + + static krb5_error_code +-krb5_krcc_parse_octet(krb5_context context, krb5_ccache id, krb5_octet * i, +- krb5_krcc_bc * bc) ++krb5_krcc_parse_octet(krb5_context context, krb5_octet * i, krb5_krcc_bc * bc) + { +- return krb5_krcc_parse(context, id, (krb5_pointer) i, 1, bc); ++ return krb5_krcc_parse(context, (krb5_pointer) i, 1, bc); + } + + static krb5_error_code +-krb5_krcc_parse_addrs(krb5_context context, krb5_ccache id, +- krb5_address *** addrs, krb5_krcc_bc * bc) ++krb5_krcc_parse_addrs(krb5_context context, krb5_address *** addrs, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + krb5_int32 length; +@@ -1559,18 +2103,17 @@ krb5_krcc_parse_addrs(krb5_context context, krb5_ccache id, + *addrs = 0; + + /* Read the number of components */ +- kret = krb5_krcc_parse_int32(context, id, &length, bc); ++ kret = krb5_krcc_parse_int32(context, &length, bc); + CHECK(kret); + + /* + * Make *addrs able to hold length pointers to krb5_address structs + * Add one extra for a null-terminated list + */ +- msize = length; +- msize += 1; +- if (msize == 0 || msize - 1 != length || length < 0) ++ msize = (size_t)length + 1; ++ if (msize == 0 || length < 0) + return KRB5_CC_NOMEM; +- *addrs = ALLOC(msize, krb5_address *); ++ *addrs = calloc(msize, sizeof(krb5_address *)); + if (*addrs == NULL) + return KRB5_CC_NOMEM; + +@@ -1580,7 +2123,7 @@ krb5_krcc_parse_addrs(krb5_context context, krb5_ccache id, + krb5_free_addresses(context, *addrs); + return KRB5_CC_NOMEM; + } +- kret = krb5_krcc_parse_addr(context, id, (*addrs)[i], bc); ++ kret = krb5_krcc_parse_addr(context, (*addrs)[i], bc); + CHECK(kret); + } + +@@ -1592,7 +2135,7 @@ errout: + } + + static krb5_error_code +-krb5_krcc_parse_addr(krb5_context context, krb5_ccache id, krb5_address * addr, ++krb5_krcc_parse_addr(krb5_context context, krb5_address * addr, + krb5_krcc_bc * bc) + { + krb5_error_code kret; +@@ -1602,22 +2145,15 @@ krb5_krcc_parse_addr(krb5_context context, krb5_ccache id, krb5_address * addr, + addr->magic = KV5M_ADDRESS; + addr->contents = 0; + +- kret = krb5_krcc_parse_ui_2(context, id, &ui2, bc); ++ kret = krb5_krcc_parse_ui_2(context, &ui2, bc); + CHECK(kret); + addr->addrtype = ui2; + +- kret = krb5_krcc_parse_int32(context, id, &int32, bc); ++ kret = krb5_krcc_parse_int32(context, &int32, bc); + CHECK(kret); + if ((int32 & VALID_INT_BITS) != int32) /* Overflow int??? */ + return KRB5_CC_NOMEM; + addr->length = int32; +- /* +- * Length field is "unsigned int", which may be smaller +- * than 32 bits. +- */ +- if (addr->length != int32) +- return KRB5_CC_NOMEM; /* XXX */ +- + if (addr->length == 0) + return KRB5_OK; + +@@ -1625,7 +2161,7 @@ krb5_krcc_parse_addr(krb5_context context, krb5_ccache id, krb5_address * addr, + if (addr->contents == NULL) + return KRB5_CC_NOMEM; + +- kret = krb5_krcc_parse(context, id, addr->contents, addr->length, bc); ++ kret = krb5_krcc_parse(context, addr->contents, addr->length, bc); + CHECK(kret); + + return KRB5_OK; +@@ -1636,8 +2172,8 @@ errout: + } + + static krb5_error_code +-krb5_krcc_parse_authdata(krb5_context context, krb5_ccache id, +- krb5_authdata *** a, krb5_krcc_bc * bc) ++krb5_krcc_parse_authdata(krb5_context context, krb5_authdata *** a, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + krb5_int32 length; +@@ -1647,7 +2183,7 @@ krb5_krcc_parse_authdata(krb5_context context, krb5_ccache id, + *a = 0; + + /* Read the number of components */ +- kret = krb5_krcc_parse_int32(context, id, &length, bc); ++ kret = krb5_krcc_parse_int32(context, &length, bc); + CHECK(kret); + + if (length == 0) +@@ -1657,11 +2193,10 @@ krb5_krcc_parse_authdata(krb5_context context, krb5_ccache id, + * Make *a able to hold length pointers to krb5_authdata structs + * Add one extra for a null-terminated list + */ +- msize = length; +- msize += 1; +- if (msize == 0 || msize - 1 != length || length < 0) ++ msize = (size_t)length + 1; ++ if (msize == 0 || length < 0) + return KRB5_CC_NOMEM; +- *a = ALLOC(msize, krb5_authdata *); ++ *a = calloc(msize, sizeof(krb5_authdata *)); + if (*a == NULL) + return KRB5_CC_NOMEM; + +@@ -1672,7 +2207,7 @@ krb5_krcc_parse_authdata(krb5_context context, krb5_ccache id, + *a = NULL; + return KRB5_CC_NOMEM; + } +- kret = krb5_krcc_parse_authdatum(context, id, (*a)[i], bc); ++ kret = krb5_krcc_parse_authdatum(context, (*a)[i], bc); + CHECK(kret); + } + +@@ -1686,8 +2221,8 @@ errout: + } + + static krb5_error_code +-krb5_krcc_parse_authdatum(krb5_context context, krb5_ccache id, +- krb5_authdata * a, krb5_krcc_bc * bc) ++krb5_krcc_parse_authdatum(krb5_context context, krb5_authdata * a, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + krb5_int32 int32; +@@ -1696,21 +2231,14 @@ krb5_krcc_parse_authdatum(krb5_context context, krb5_ccache id, + a->magic = KV5M_AUTHDATA; + a->contents = NULL; + +- kret = krb5_krcc_parse_ui_2(context, id, &ui2, bc); ++ kret = krb5_krcc_parse_ui_2(context, &ui2, bc); + CHECK(kret); + a->ad_type = (krb5_authdatatype) ui2; +- kret = krb5_krcc_parse_int32(context, id, &int32, bc); ++ kret = krb5_krcc_parse_int32(context, &int32, bc); + CHECK(kret); + if ((int32 & VALID_INT_BITS) != int32) /* Overflow int??? */ + return KRB5_CC_NOMEM; + a->length = int32; +- /* +- * Value could have gotten truncated if int is +- * smaller than 32 bits. +- */ +- if (a->length != int32) +- return KRB5_CC_NOMEM; /* XXX */ +- + if (a->length == 0) + return KRB5_OK; + +@@ -1718,7 +2246,7 @@ krb5_krcc_parse_authdatum(krb5_context context, krb5_ccache id, + if (a->contents == NULL) + return KRB5_CC_NOMEM; + +- kret = krb5_krcc_parse(context, id, a->contents, a->length, bc); ++ kret = krb5_krcc_parse(context, a->contents, a->length, bc); + CHECK(kret); + + return KRB5_OK; +@@ -1730,13 +2258,12 @@ errout: + } + + static krb5_error_code +-krb5_krcc_parse_ui_2(krb5_context context, krb5_ccache id, krb5_ui_2 * i, +- krb5_krcc_bc * bc) ++krb5_krcc_parse_ui_2(krb5_context context, krb5_ui_2 * i, krb5_krcc_bc * bc) + { + krb5_error_code kret; + unsigned char buf[2]; + +- kret = krb5_krcc_parse(context, id, buf, 2, bc); ++ kret = krb5_krcc_parse(context, buf, 2, bc); + if (kret) + return kret; + *i = load_16_be(buf); +@@ -1756,9 +2283,15 @@ krb5_krcc_parse_ui_2(krb5_context context, krb5_ccache id, krb5_ui_2 * i, + * system errors + */ + static krb5_error_code +-krb5_krcc_unparse(krb5_context context, krb5_ccache id, krb5_pointer buf, +- unsigned int len, krb5_krcc_bc * bc) ++krb5_krcc_unparse(krb5_context context, krb5_pointer buf, unsigned int len, ++ krb5_krcc_bc * bc) + { ++ if (bc->bpp == NULL) { ++ /* This is a dry run; just increase size and return. */ ++ bc->size += len; ++ return KRB5_OK; ++ } ++ + if (bc->bpp + len > bc->endp) + return KRB5_CC_WRITE; + +@@ -1769,29 +2302,26 @@ krb5_krcc_unparse(krb5_context context, krb5_ccache id, krb5_pointer buf, + } + + static krb5_error_code +-krb5_krcc_unparse_principal(krb5_context context, krb5_ccache id, +- krb5_principal princ, krb5_krcc_bc * bc) ++krb5_krcc_unparse_principal(krb5_context context, krb5_principal princ, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + krb5_int32 i, length, tmp, type; + +- type = krb5_princ_type(context, princ); +- tmp = length = krb5_princ_size(context, princ); ++ type = princ->type; ++ tmp = length = princ->length; + +- kret = krb5_krcc_unparse_int32(context, id, type, bc); ++ kret = krb5_krcc_unparse_int32(context, type, bc); + CHECK_OUT(kret); + +- kret = krb5_krcc_unparse_int32(context, id, tmp, bc); ++ kret = krb5_krcc_unparse_int32(context, tmp, bc); + CHECK_OUT(kret); + +- kret = krb5_krcc_unparse_krb5data(context, id, +- krb5_princ_realm(context, princ), bc); ++ kret = krb5_krcc_unparse_krb5data(context, &princ->realm, bc); + CHECK_OUT(kret); + + for (i = 0; i < length; i++) { +- kret = krb5_krcc_unparse_krb5data(context, id, +- krb5_princ_component(context, princ, +- i), bc); ++ kret = krb5_krcc_unparse_krb5data(context, &princ->data[i], bc); + CHECK_OUT(kret); + } + +@@ -1799,67 +2329,65 @@ krb5_krcc_unparse_principal(krb5_context context, krb5_ccache id, + } + + static krb5_error_code +-krb5_krcc_unparse_keyblock(krb5_context context, krb5_ccache id, +- krb5_keyblock * keyblock, krb5_krcc_bc * bc) ++krb5_krcc_unparse_keyblock(krb5_context context, krb5_keyblock * keyblock, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + +- kret = krb5_krcc_unparse_ui_2(context, id, keyblock->enctype, bc); ++ kret = krb5_krcc_unparse_ui_2(context, keyblock->enctype, bc); + CHECK_OUT(kret); +- kret = krb5_krcc_unparse_ui_4(context, id, keyblock->length, bc); ++ kret = krb5_krcc_unparse_ui_4(context, keyblock->length, bc); + CHECK_OUT(kret); +- return krb5_krcc_unparse(context, id, (char *) keyblock->contents, ++ return krb5_krcc_unparse(context, (char *) keyblock->contents, + keyblock->length, bc); + } + + static krb5_error_code +-krb5_krcc_unparse_times(krb5_context context, krb5_ccache id, +- krb5_ticket_times * t, krb5_krcc_bc * bc) ++krb5_krcc_unparse_times(krb5_context context, krb5_ticket_times * t, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + +- kret = krb5_krcc_unparse_int32(context, id, t->authtime, bc); ++ kret = krb5_krcc_unparse_int32(context, t->authtime, bc); + CHECK_OUT(kret); +- kret = krb5_krcc_unparse_int32(context, id, t->starttime, bc); ++ kret = krb5_krcc_unparse_int32(context, t->starttime, bc); + CHECK_OUT(kret); +- kret = krb5_krcc_unparse_int32(context, id, t->endtime, bc); ++ kret = krb5_krcc_unparse_int32(context, t->endtime, bc); + CHECK_OUT(kret); +- kret = krb5_krcc_unparse_int32(context, id, t->renew_till, bc); ++ kret = krb5_krcc_unparse_int32(context, t->renew_till, bc); + CHECK_OUT(kret); + return 0; + } + + static krb5_error_code +-krb5_krcc_unparse_krb5data(krb5_context context, krb5_ccache id, +- krb5_data * data, krb5_krcc_bc * bc) ++krb5_krcc_unparse_krb5data(krb5_context context, krb5_data * data, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + +- kret = krb5_krcc_unparse_ui_4(context, id, data->length, bc); ++ kret = krb5_krcc_unparse_ui_4(context, data->length, bc); + CHECK_OUT(kret); +- return krb5_krcc_unparse(context, id, data->data, data->length, bc); ++ return krb5_krcc_unparse(context, data->data, data->length, bc); + } + + static krb5_error_code +-krb5_krcc_unparse_int32(krb5_context context, krb5_ccache id, krb5_int32 i, +- krb5_krcc_bc * bc) ++krb5_krcc_unparse_int32(krb5_context context, krb5_int32 i, krb5_krcc_bc * bc) + { +- return krb5_krcc_unparse_ui_4(context, id, (krb5_ui_4) i, bc); ++ return krb5_krcc_unparse_ui_4(context, (krb5_ui_4) i, bc); + } + + static krb5_error_code +-krb5_krcc_unparse_octet(krb5_context context, krb5_ccache id, krb5_int32 i, +- krb5_krcc_bc * bc) ++krb5_krcc_unparse_octet(krb5_context context, krb5_int32 i, krb5_krcc_bc * bc) + { + krb5_octet ibuf; + + ibuf = (krb5_octet) i; +- return krb5_krcc_unparse(context, id, (char *) &ibuf, 1, bc); ++ return krb5_krcc_unparse(context, (char *) &ibuf, 1, bc); + } + + static krb5_error_code +-krb5_krcc_unparse_addrs(krb5_context context, krb5_ccache id, +- krb5_address ** addrs, krb5_krcc_bc * bc) ++krb5_krcc_unparse_addrs(krb5_context context, krb5_address ** addrs, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + krb5_address **temp; +@@ -1872,10 +2400,10 @@ krb5_krcc_unparse_addrs(krb5_context context, krb5_ccache id, + length += 1; + } + +- kret = krb5_krcc_unparse_int32(context, id, length, bc); ++ kret = krb5_krcc_unparse_int32(context, length, bc); + CHECK_OUT(kret); + for (i = 0; i < length; i++) { +- kret = krb5_krcc_unparse_addr(context, id, addrs[i], bc); ++ kret = krb5_krcc_unparse_addr(context, addrs[i], bc); + CHECK_OUT(kret); + } + +@@ -1883,21 +2411,21 @@ krb5_krcc_unparse_addrs(krb5_context context, krb5_ccache id, + } + + static krb5_error_code +-krb5_krcc_unparse_addr(krb5_context context, krb5_ccache id, +- krb5_address * addr, krb5_krcc_bc * bc) ++krb5_krcc_unparse_addr(krb5_context context, krb5_address * addr, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + +- kret = krb5_krcc_unparse_ui_2(context, id, addr->addrtype, bc); ++ kret = krb5_krcc_unparse_ui_2(context, addr->addrtype, bc); + CHECK_OUT(kret); +- kret = krb5_krcc_unparse_ui_4(context, id, addr->length, bc); ++ kret = krb5_krcc_unparse_ui_4(context, addr->length, bc); + CHECK_OUT(kret); +- return krb5_krcc_unparse(context, id, (char *) addr->contents, ++ return krb5_krcc_unparse(context, (char *) addr->contents, + addr->length, bc); + } + + static krb5_error_code +-krb5_krcc_unparse_authdata(krb5_context context, krb5_ccache id, ++krb5_krcc_unparse_authdata(krb5_context context, + krb5_authdata ** a, krb5_krcc_bc * bc) + { + krb5_error_code kret; +@@ -1909,47 +2437,45 @@ krb5_krcc_unparse_authdata(krb5_context context, krb5_ccache id, + length++; + } + +- kret = krb5_krcc_unparse_int32(context, id, length, bc); ++ kret = krb5_krcc_unparse_int32(context, length, bc); + CHECK_OUT(kret); + for (i = 0; i < length; i++) { +- kret = krb5_krcc_unparse_authdatum(context, id, a[i], bc); ++ kret = krb5_krcc_unparse_authdatum(context, a[i], bc); + CHECK_OUT(kret); + } + return KRB5_OK; + } + + static krb5_error_code +-krb5_krcc_unparse_authdatum(krb5_context context, krb5_ccache id, +- krb5_authdata * a, krb5_krcc_bc * bc) ++krb5_krcc_unparse_authdatum(krb5_context context, krb5_authdata * a, ++ krb5_krcc_bc * bc) + { + krb5_error_code kret; + +- kret = krb5_krcc_unparse_ui_2(context, id, a->ad_type, bc); ++ kret = krb5_krcc_unparse_ui_2(context, a->ad_type, bc); + CHECK_OUT(kret); +- kret = krb5_krcc_unparse_ui_4(context, id, a->length, bc); ++ kret = krb5_krcc_unparse_ui_4(context, a->length, bc); + CHECK_OUT(kret); +- return krb5_krcc_unparse(context, id, (krb5_pointer) a->contents, ++ return krb5_krcc_unparse(context, (krb5_pointer) a->contents, + a->length, bc); + } + + static krb5_error_code +-krb5_krcc_unparse_ui_4(krb5_context context, krb5_ccache id, krb5_ui_4 i, +- krb5_krcc_bc * bc) ++krb5_krcc_unparse_ui_4(krb5_context context, krb5_ui_4 i, krb5_krcc_bc * bc) + { + unsigned char buf[4]; + + store_32_be(i, buf); +- return krb5_krcc_unparse(context, id, buf, 4, bc); ++ return krb5_krcc_unparse(context, buf, 4, bc); + } + + static krb5_error_code +-krb5_krcc_unparse_ui_2(krb5_context context, krb5_ccache id, krb5_int32 i, +- krb5_krcc_bc * bc) ++krb5_krcc_unparse_ui_2(krb5_context context, krb5_int32 i, krb5_krcc_bc * bc) + { + unsigned char buf[2]; + + store_16_be(i, buf); +- return krb5_krcc_unparse(context, id, buf, 2, bc); ++ return krb5_krcc_unparse(context, buf, 2, bc); + } + + /* +@@ -1965,11 +2491,55 @@ krb5_krcc_unparse_ui_2(krb5_context context, krb5_ccache id, krb5_int32 i, + * Caller is responsible for freeing returned buffer. + */ + static krb5_error_code +-krb5_krcc_unparse_cred(krb5_context context, krb5_ccache id, +- krb5_creds * creds, char **datapp, unsigned int *lenptr) ++krb5_krcc_unparse_cred(krb5_context context, krb5_creds * creds, ++ krb5_krcc_bc *bc) + { + krb5_error_code kret; +- char *buf; ++ ++ kret = krb5_krcc_unparse_principal(context, creds->client, bc); ++ CHECK_OUT(kret); ++ ++ kret = krb5_krcc_unparse_principal(context, creds->server, bc); ++ CHECK_OUT(kret); ++ ++ kret = krb5_krcc_unparse_keyblock(context, &creds->keyblock, bc); ++ CHECK_OUT(kret); ++ ++ kret = krb5_krcc_unparse_times(context, &creds->times, bc); ++ CHECK_OUT(kret); ++ ++ kret = krb5_krcc_unparse_octet(context, (krb5_int32) creds->is_skey, bc); ++ CHECK_OUT(kret); ++ ++ kret = krb5_krcc_unparse_int32(context, creds->ticket_flags, bc); ++ CHECK_OUT(kret); ++ ++ kret = krb5_krcc_unparse_addrs(context, creds->addresses, bc); ++ CHECK_OUT(kret); ++ ++ kret = krb5_krcc_unparse_authdata(context, creds->authdata, bc); ++ CHECK_OUT(kret); ++ ++ kret = krb5_krcc_unparse_krb5data(context, &creds->ticket, bc); ++ CHECK_OUT(kret); ++ CHECK(kret); ++ ++ kret = krb5_krcc_unparse_krb5data(context, &creds->second_ticket, bc); ++ CHECK_OUT(kret); ++ ++ /* Success! */ ++ kret = KRB5_OK; ++ ++errout: ++ return kret; ++} ++ ++static krb5_error_code ++krb5_krcc_unparse_cred_alloc(krb5_context context, krb5_creds * creds, ++ char **datapp, unsigned int *lenptr) ++{ ++ krb5_error_code kret; ++ char *buf = NULL; + krb5_krcc_bc bc; + + if (!creds || !datapp || !lenptr) +@@ -1978,43 +2548,102 @@ krb5_krcc_unparse_cred(krb5_context context, krb5_ccache id, + *datapp = NULL; + *lenptr = 0; + +- buf = malloc(GUESS_CRED_SIZE); ++ /* Do a dry run first to calculate the size. */ ++ bc.bpp = bc.endp = NULL; ++ bc.size = 0; ++ kret = krb5_krcc_unparse_cred(context, creds, &bc); ++ CHECK(kret); ++ if (bc.size > MAX_CRED_SIZE) ++ return KRB5_CC_WRITE; ++ ++ /* Allocate a buffer and unparse for real. */ ++ buf = malloc(bc.size); + if (buf == NULL) + return KRB5_CC_NOMEM; +- + bc.bpp = buf; +- bc.endp = buf + GUESS_CRED_SIZE; ++ bc.endp = buf + bc.size; ++ kret = krb5_krcc_unparse_cred(context, creds, &bc); ++ CHECK(kret); + +- kret = krb5_krcc_unparse_principal(context, id, creds->client, &bc); +- CHECK_N_GO(kret, errout); ++ /* Success! */ ++ *datapp = buf; ++ *lenptr = bc.bpp - buf; ++ buf = NULL; ++ kret = KRB5_OK; + +- kret = krb5_krcc_unparse_principal(context, id, creds->server, &bc); +- CHECK_N_GO(kret, errout); ++errout: ++ free(buf); ++ return kret; ++} + +- kret = krb5_krcc_unparse_keyblock(context, id, &creds->keyblock, &bc); +- CHECK_N_GO(kret, errout); ++static krb5_error_code ++krb5_krcc_parse_index(krb5_context context, krb5_int32 *version, ++ char **primary, void *payload, int psize) ++{ ++ krb5_error_code kret; ++ krb5_krcc_bc bc; ++ krb5_data data; + +- kret = krb5_krcc_unparse_times(context, id, &creds->times, &bc); +- CHECK_N_GO(kret, errout); ++ bc.bpp = payload; ++ bc.endp = bc.bpp + psize; + +- kret = krb5_krcc_unparse_octet(context, id, (krb5_int32) creds->is_skey, +- &bc); +- CHECK_N_GO(kret, errout); ++ kret = krb5_krcc_parse_int32(context, version, &bc); ++ CHECK_OUT(kret); + +- kret = krb5_krcc_unparse_int32(context, id, creds->ticket_flags, &bc); +- CHECK_N_GO(kret, errout); ++ kret = krb5_krcc_parse_krb5data(context, &data, &bc); ++ CHECK_OUT(kret); + +- kret = krb5_krcc_unparse_addrs(context, id, creds->addresses, &bc); +- CHECK_N_GO(kret, errout); ++ *primary = (char *)data.data; ++ return KRB5_OK; ++} + +- kret = krb5_krcc_unparse_authdata(context, id, creds->authdata, &bc); +- CHECK_N_GO(kret, errout); ++static krb5_error_code ++krb5_krcc_unparse_index_internal(krb5_context context, krb5_int32 version, ++ const char *primary, krb5_krcc_bc *bc) ++{ ++ krb5_error_code kret; ++ krb5_data data; + +- kret = krb5_krcc_unparse_krb5data(context, id, &creds->ticket, &bc); +- CHECK_N_GO(kret, errout); ++ data.length = strlen(primary) + 1; ++ data.data = (void *)primary; + +- kret = krb5_krcc_unparse_krb5data(context, id, &creds->second_ticket, &bc); +- CHECK_N_GO(kret, errout); ++ kret = krb5_krcc_unparse_int32(context, version, bc); ++ CHECK_OUT(kret); ++ ++ kret = krb5_krcc_unparse_krb5data(context, &data, bc); ++ CHECK_OUT(kret); ++ ++ return KRB5_OK; ++} ++ ++static krb5_error_code ++krb5_krcc_unparse_index(krb5_context context, krb5_int32 version, ++ const char *primary, void **datapp, int *lenptr) ++{ ++ krb5_error_code kret; ++ krb5_krcc_bc bc; ++ char *buf; ++ ++ if (!primary || !datapp || !lenptr) ++ return EINVAL; ++ ++ *datapp = NULL; ++ *lenptr = 0; ++ ++ /* Do a dry run first to calculate the size. */ ++ bc.bpp = bc.endp = NULL; ++ bc.size = 0; ++ kret = krb5_krcc_unparse_index_internal(context, version, primary, &bc); ++ CHECK_OUT(kret); ++ ++ buf = malloc(bc.size); ++ if (buf == NULL) ++ return ENOMEM; ++ ++ bc.bpp = buf; ++ bc.endp = buf + bc.size; ++ kret = krb5_krcc_unparse_index_internal(context, version, primary, &bc); ++ CHECK(kret); + + /* Success! */ + *datapp = buf; +@@ -2022,6 +2651,8 @@ krb5_krcc_unparse_cred(krb5_context context, krb5_ccache id, + kret = KRB5_OK; + + errout: ++ if (kret) ++ free(buf); + return kret; + } + +@@ -2065,15 +2696,15 @@ const krb5_cc_ops krb5_krcc_ops = { + krb5_krcc_remove_cred, + krb5_krcc_set_flags, + krb5_krcc_get_flags, /* added after 1.4 release */ +- NULL, +- NULL, +- NULL, ++ krb5_krcc_ptcursor_new, ++ krb5_krcc_ptcursor_next, ++ krb5_krcc_ptcursor_free, + NULL, /* move */ + krb5_krcc_last_change_time, /* lastchange */ + NULL, /* wasdefault */ + krb5_krcc_lock, + krb5_krcc_unlock, +- NULL, /* switch_to */ ++ krb5_krcc_switch_to, + }; + + #else /* !USE_KEYRING_CCACHE */ +diff --git a/src/lib/krb5/ccache/t_cc.c b/src/lib/krb5/ccache/t_cc.c +index e14ae7f..6069cab 100644 +--- a/src/lib/krb5/ccache/t_cc.c ++++ b/src/lib/krb5/ccache/t_cc.c +@@ -25,6 +25,7 @@ + */ + + #include "k5-int.h" ++#include "cc-int.h" + #include + #include + #include "autoconf.h" +@@ -331,14 +332,14 @@ check_registered(krb5_context context, const char *prefix) + if(kret != KRB5_OK) { + if(kret == KRB5_CC_UNKNOWN_TYPE) + return 0; +- com_err("Checking on credential type", kret,prefix); ++ com_err("Checking on credential type", kret, "%s", prefix); + fflush(stderr); + return 0; + } + + kret = krb5_cc_close(context, id); + if(kret != KRB5_OK) { +- com_err("Checking on credential type - closing", kret,prefix); ++ com_err("Checking on credential type - closing", kret, "%s", prefix); + fflush(stderr); + } + +@@ -425,8 +426,8 @@ main(void) + test_misc(context); + do_test(context, ""); + +- if(check_registered(context, "KEYRING:")) +- do_test(context, "KEYRING:"); ++ if (check_registered(context, "KEYRING:process:")) ++ do_test(context, "KEYRING:process:"); + else + printf("Skiping KEYRING: test - unregistered type\n"); + +diff --git a/src/lib/krb5/ccache/t_cccol.c b/src/lib/krb5/ccache/t_cccol.c +new file mode 100644 +index 0000000..444806e +--- /dev/null ++++ b/src/lib/krb5/ccache/t_cccol.c +@@ -0,0 +1,363 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krb5/ccache/t_cccol.py - Test ccache collection via API */ ++/* ++ * Copyright (C) 2013 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 ++#include ++#include ++#include ++#include ++ ++static krb5_context ctx; ++ ++/* Check that code is 0. Display an error message first if it is not. */ ++static void ++check(krb5_error_code code) ++{ ++ const char *errmsg; ++ ++ if (code != 0) { ++ errmsg = krb5_get_error_message(ctx, code); ++ fprintf(stderr, "%s\n", errmsg); ++ krb5_free_error_message(ctx, errmsg); ++ } ++ assert(code == 0); ++} ++ ++/* Construct a list of the names of each credential cache in the collection. */ ++static void ++get_collection_names(char ***list_out, size_t *count_out) ++{ ++ krb5_cccol_cursor cursor; ++ krb5_ccache cache; ++ char **list = NULL; ++ size_t count = 0; ++ char *name; ++ ++ check(krb5_cccol_cursor_new(ctx, &cursor)); ++ while (1) { ++ check(krb5_cccol_cursor_next(ctx, cursor, &cache)); ++ if (cache == NULL) ++ break; ++ check(krb5_cc_get_full_name(ctx, cache, &name)); ++ krb5_cc_close(ctx, cache); ++ list = realloc(list, (count + 1) * sizeof(*list)); ++ assert(list != NULL); ++ list[count++] = name; ++ } ++ krb5_cccol_cursor_free(ctx, &cursor); ++ *list_out = list; ++ *count_out = count; ++} ++ ++/* Return true if list contains name. */ ++static krb5_boolean ++in_list(char **list, size_t count, const char *name) ++{ ++ size_t i; ++ ++ for (i = 0; i < count; i++) { ++ if (strcmp(list[i], name) == 0) ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++/* Release the memory for a list of credential cache names. */ ++static void ++free_list(char **list, size_t count) ++{ ++ size_t i; ++ ++ for (i = 0; i < count; i++) ++ krb5_free_string(ctx, list[i]); ++ free(list); ++} ++ ++/* ++ * Check that the cache names within the current collection begin with first ++ * (unless first is NULL), that the other elements match the remaining ++ * arguments in some order. others must be the number of additional cache ++ * names. ++ */ ++static void ++check_collection(const char *first, size_t others, ...) ++{ ++ va_list ap; ++ char **list; ++ size_t count, i; ++ const char *name; ++ ++ get_collection_names(&list, &count); ++ if (first != NULL) { ++ assert(strcmp(first, list[0]) == 0); ++ assert(count == others + 1); ++ } else { ++ assert(count == others); ++ } ++ va_start(ap, others); ++ for (i = 0; i < others; i++) { ++ name = va_arg(ap, const char *); ++ assert(in_list(list, count, name)); ++ } ++ va_end(ap); ++ free_list(list, count); ++} ++ ++/* Check that the name of cache matches expected_name. */ ++static void ++check_name(krb5_ccache cache, const char *expected_name) ++{ ++ char *name; ++ ++ check(krb5_cc_get_full_name(ctx, cache, &name)); ++ assert(strcmp(name, expected_name) == 0); ++ krb5_free_string(ctx, name); ++} ++ ++/* Check that when collection_name is resolved, the resulting cache's name ++ * matches expected_name. */ ++static void ++check_primary_name(const char *collection_name, const char *expected_name) ++{ ++ krb5_ccache cache; ++ ++ check(krb5_cc_resolve(ctx, collection_name, &cache)); ++ check_name(cache, expected_name); ++ krb5_cc_close(ctx, cache); ++} ++ ++/* Check that when name is resolved, the resulting cache's principal matches ++ * expected_princ, or has no principal if expected_princ is NULL. */ ++static void ++check_princ(const char *name, krb5_principal expected_princ) ++{ ++ krb5_ccache cache; ++ krb5_principal princ; ++ ++ check(krb5_cc_resolve(ctx, name, &cache)); ++ if (expected_princ != NULL) { ++ check(krb5_cc_get_principal(ctx, cache, &princ)); ++ assert(krb5_principal_compare(ctx, princ, expected_princ)); ++ krb5_free_principal(ctx, princ); ++ } else { ++ assert(krb5_cc_get_principal(ctx, cache, &princ) != 0); ++ } ++ krb5_cc_close(ctx, cache); ++} ++ ++/* Check that krb5_cc_cache_match on princ returns a cache whose name matches ++ * expected_name, or that the match fails if expected_name is NULL. */ ++static void ++check_match(krb5_principal princ, const char *expected_name) ++{ ++ krb5_ccache cache; ++ ++ if (expected_name != NULL) { ++ check(krb5_cc_cache_match(ctx, princ, &cache)); ++ check_name(cache, expected_name); ++ krb5_cc_close(ctx, cache); ++ } else { ++ assert(krb5_cc_cache_match(ctx, princ, &cache) != 0); ++ } ++} ++ ++int ++main(int argc, char **argv) ++{ ++ krb5_ccache ccinitial, ccu1, ccu2; ++ krb5_principal princ1, princ2, princ3; ++ const char *collection_name, *typename; ++ char *initial_primary_name, *unique1_name, *unique2_name; ++ ++ /* ++ * Get the collection name from the command line. This is a ccache name ++ * with collection semantics, like DIR:/path/to/directory. This test ++ * program assumes that the collection is empty to start with. ++ */ ++ assert(argc == 2); ++ collection_name = argv[1]; ++ ++ /* ++ * Set the default ccache for the context to be the collection name, so the ++ * library can find the collection. ++ */ ++ check(krb5_init_context(&ctx)); ++ check(krb5_cc_set_default_name(ctx, collection_name)); ++ ++ /* ++ * Resolve the collection name. Since the collection is empty, this should ++ * generate a subsidiary name of an uninitialized cache. Getting the name ++ * of the resulting cache should give us the subsidiary name, not the ++ * collection name. This resulting subsidiary name should be consistent if ++ * we resolve the collection name again, and the collection should still be ++ * empty since we haven't initialized the cache. ++ */ ++ check(krb5_cc_resolve(ctx, collection_name, &ccinitial)); ++ check(krb5_cc_get_full_name(ctx, ccinitial, &initial_primary_name)); ++ assert(strcmp(initial_primary_name, collection_name) != 0); ++ check_primary_name(collection_name, initial_primary_name); ++ check_collection(NULL, 0); ++ check_princ(collection_name, NULL); ++ check_princ(initial_primary_name, NULL); ++ ++ /* ++ * Before initializing the primary ccache, generate and initialize two ++ * unique caches of the collection's type. Check that the cache names ++ * resolve to the generated caches and appear in the collection. (They ++ * might appear before being initialized; that's not currently considered ++ * important). The primary cache for the collection should remain as the ++ * unitialized cache from the previous step. ++ */ ++ typename = krb5_cc_get_type(ctx, ccinitial); ++ check(krb5_cc_new_unique(ctx, typename, NULL, &ccu1)); ++ check(krb5_cc_get_full_name(ctx, ccu1, &unique1_name)); ++ check(krb5_parse_name(ctx, "princ1@X", &princ1)); ++ check(krb5_cc_initialize(ctx, ccu1, princ1)); ++ check_princ(unique1_name, princ1); ++ check_match(princ1, unique1_name); ++ check_collection(NULL, 1, unique1_name); ++ check(krb5_cc_new_unique(ctx, typename, NULL, &ccu2)); ++ check(krb5_cc_get_full_name(ctx, ccu2, &unique2_name)); ++ check(krb5_parse_name(ctx, "princ2@X", &princ2)); ++ check(krb5_cc_initialize(ctx, ccu2, princ2)); ++ check_princ(unique2_name, princ2); ++ check_match(princ1, unique1_name); ++ check_match(princ2, unique2_name); ++ check_collection(NULL, 2, unique1_name, unique2_name); ++ assert(strcmp(unique1_name, initial_primary_name) != 0); ++ assert(strcmp(unique1_name, collection_name) != 0); ++ assert(strcmp(unique2_name, initial_primary_name) != 0); ++ assert(strcmp(unique2_name, collection_name) != 0); ++ assert(strcmp(unique2_name, unique1_name) != 0); ++ check_primary_name(collection_name, initial_primary_name); ++ ++ /* ++ * Initialize the initial primary cache. Make sure it didn't change names, ++ * that the previously retrieved name and the collection name both resolve ++ * to the initialized cache, and that it now appears first in the ++ * collection. ++ */ ++ check(krb5_parse_name(ctx, "princ3@X", &princ3)); ++ check(krb5_cc_initialize(ctx, ccinitial, princ3)); ++ check_name(ccinitial, initial_primary_name); ++ check_princ(initial_primary_name, princ3); ++ check_princ(collection_name, princ3); ++ check_match(princ3, initial_primary_name); ++ check_collection(initial_primary_name, 2, unique1_name, unique2_name); ++ ++ /* ++ * Switch the primary cache to each cache we have open. One each switch, ++ * check the primary name, check that the collection resolves to the ++ * expected cache, and check that the new primary name appears first in the ++ * collection. ++ */ ++ check(krb5_cc_switch(ctx, ccu1)); ++ check_primary_name(collection_name, unique1_name); ++ check_princ(collection_name, princ1); ++ check_collection(unique1_name, 2, initial_primary_name, unique2_name); ++ check(krb5_cc_switch(ctx, ccu2)); ++ check_primary_name(collection_name, unique2_name); ++ check_princ(collection_name, princ2); ++ check_collection(unique2_name, 2, initial_primary_name, unique1_name); ++ check(krb5_cc_switch(ctx, ccinitial)); ++ check_primary_name(collection_name, initial_primary_name); ++ check_princ(collection_name, princ3); ++ check_collection(initial_primary_name, 2, unique1_name, unique2_name); ++ ++ /* ++ * Temporarily set the context default ccache to a subsidiary name, and ++ * check that iterating over the collection yields that subsidiary cache ++ * and no others. ++ */ ++ check(krb5_cc_set_default_name(ctx, unique1_name)); ++ check_collection(unique1_name, 0); ++ check(krb5_cc_set_default_name(ctx, collection_name)); ++ ++ /* ++ * Destroy the primary cache. Make sure this causes both the initial ++ * primary name and the collection name to resolve to an uninitialized ++ * cache. Make sure the primary name doesn't change and doesn't appear in ++ * the collection any more. ++ */ ++ check(krb5_cc_destroy(ctx, ccinitial)); ++ check_princ(initial_primary_name, NULL); ++ check_princ(collection_name, NULL); ++ check_primary_name(collection_name, initial_primary_name); ++ check_match(princ1, unique1_name); ++ check_match(princ2, unique2_name); ++ check_match(princ3, NULL); ++ check_collection(NULL, 2, unique1_name, unique2_name); ++ ++ /* ++ * Switch to the first unique cache after destroying the primary cache. ++ * Check that the collection name resolves to this cache and that the new ++ * primary name appears first in the collection. ++ */ ++ check(krb5_cc_switch(ctx, ccu1)); ++ check_primary_name(collection_name, unique1_name); ++ check_princ(collection_name, princ1); ++ check_collection(unique1_name, 1, unique2_name); ++ ++ /* ++ * Destroy the second unique cache (which is not the current primary), ++ * check that it is on longer initialized, and check that it no longer ++ * appears in the collection. Check that destroying the non-primary cache ++ * doesn't affect the primary name. ++ */ ++ check(krb5_cc_destroy(ctx, ccu2)); ++ check_princ(unique2_name, NULL); ++ check_match(princ2, NULL); ++ check_collection(unique1_name, 0); ++ check_primary_name(collection_name, unique1_name); ++ check_match(princ1, unique1_name); ++ check_princ(collection_name, princ1); ++ ++ /* ++ * Destroy the first unique cache. Check that the collection is empty and ++ * still has the same primary name. ++ */ ++ check(krb5_cc_destroy(ctx, ccu1)); ++ check_princ(unique1_name, NULL); ++ check_princ(collection_name, NULL); ++ check_primary_name(collection_name, unique1_name); ++ check_match(princ1, NULL); ++ check_collection(NULL, 0); ++ ++ krb5_free_string(ctx, initial_primary_name); ++ krb5_free_string(ctx, unique1_name); ++ krb5_free_string(ctx, unique2_name); ++ krb5_free_principal(ctx, princ1); ++ krb5_free_principal(ctx, princ2); ++ krb5_free_principal(ctx, princ3); ++ krb5_free_context(ctx); ++ return 0; ++} +diff --git a/src/lib/krb5/ccache/t_cccol.py b/src/lib/krb5/ccache/t_cccol.py +index 8c459dd..e762625 100644 +--- a/src/lib/krb5/ccache/t_cccol.py ++++ b/src/lib/krb5/ccache/t_cccol.py +@@ -1,6 +1,46 @@ + #!/usr/bin/python + from k5test import * + ++realm = K5Realm(create_kdb=False) ++ ++keyctl = which('keyctl') ++out = realm.run([klist, '-c', 'KEYRING:process:abcd'], expected_code=1) ++test_keyring = (keyctl is not None and ++ 'Unknown credential cache type' not in out) ++ ++# Run the collection test program against each collection-enabled type. ++realm.run(['./t_cccol', 'DIR:' + os.path.join(realm.testdir, 'cc')]) ++if test_keyring: ++ # Use the test directory as the collection name to avoid colliding ++ # with other build trees. ++ cname = realm.testdir ++ ++ # Remove any keys left behind by previous failed test runs. ++ realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname]) ++ realm.run(['keyctl', 'purge', 'keyring', cname]) ++ out = realm.run(['keyctl', 'list', '@u']) ++ if ('keyring: _krb_' + cname + '\n') in out: ++ id = realm.run(['keyctl', 'search', '@u', 'keyring', '_krb_' + cname]) ++ realm.run(['keyctl', 'unlink', id.strip(), '@u']) ++ ++ # Run test program over each subtype, cleaning up as we go. Don't ++ # test the persistent subtype, since it supports only one ++ # collection and might be in actual use. ++ realm.run(['./t_cccol', 'KEYRING:' + cname]) ++ realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname]) ++ realm.run(['./t_cccol', 'KEYRING:legacy:' + cname]) ++ realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname]) ++ realm.run(['./t_cccol', 'KEYRING:session:' + cname]) ++ realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname]) ++ realm.run(['./t_cccol', 'KEYRING:user:' + cname]) ++ id = realm.run(['keyctl', 'search', '@u', 'keyring', '_krb_' + cname]) ++ realm.run(['keyctl', 'unlink', id.strip(), '@u']) ++ realm.run(['./t_cccol', 'KEYRING:process:abcd']) ++ realm.run(['./t_cccol', 'KEYRING:thread:abcd']) ++ ++realm.stop() ++ ++# Test cursor semantics using real ccaches. + realm = K5Realm(create_host=False) + + realm.addprinc('alice', password('alice')) +@@ -11,12 +51,25 @@ dccname = 'DIR:%s' % ccdir + duser = 'DIR::%s/tkt1' % ccdir + dalice = 'DIR::%s/tkt2' % ccdir + dbob = 'DIR::%s/tkt3' % ccdir ++dnoent = 'DIR::%s/noent' % ccdir + realm.kinit('user', password('user'), flags=['-c', duser]) + realm.kinit('alice', password('alice'), flags=['-c', dalice]) + realm.kinit('bob', password('bob'), flags=['-c', dbob]) + ++if test_keyring: ++ cname = realm.testdir ++ realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname]) ++ krccname = 'KEYRING:session:' + cname ++ kruser = '%s:tkt1' % krccname ++ kralice = '%s:tkt2' % krccname ++ krbob = '%s:tkt3' % krccname ++ krnoent = '%s:noent' % krccname ++ realm.kinit('user', password('user'), flags=['-c', kruser]) ++ realm.kinit('alice', password('alice'), flags=['-c', kralice]) ++ realm.kinit('bob', password('bob'), flags=['-c', krbob]) ++ + def cursor_test(testname, args, expected): +- outlines = realm.run_as_client(['./t_cccursor'] + args).splitlines() ++ outlines = realm.run(['./t_cccursor'] + args).splitlines() + outlines.sort() + expected.sort() + if outlines != expected: +@@ -30,21 +83,33 @@ cursor_test('file-default2', [realm.ccache], [fccname]) + cursor_test('file-default3', [fccname], [fccname]) + + cursor_test('dir', [dccname], [duser, dalice, dbob]) ++cursor_test('dir-subsidiary', [duser], [duser]) ++cursor_test('dir-nofile', [dnoent], []) ++ ++if test_keyring: ++ cursor_test('keyring', [krccname], [kruser, kralice, krbob]) ++ cursor_test('keyring-subsidiary', [kruser], [kruser]) ++ cursor_test('keyring-noent', [krnoent], []) + + mfoo = 'MEMORY:foo' + mbar = 'MEMORY:bar' + cursor_test('filemem', [fccname, mfoo, mbar], [fccname, mfoo, mbar]) + cursor_test('dirmem', [dccname, mfoo], [duser, dalice, dbob, mfoo]) ++if test_keyring: ++ cursor_test('keyringmem', [krccname, mfoo], [kruser, kralice, krbob, mfoo]) + + # Test krb5_cccol_have_content. +-realm.run_as_client(['./t_cccursor', dccname, 'CONTENT']) +-realm.run_as_client(['./t_cccursor', fccname, 'CONTENT']) +-realm.run_as_client(['./t_cccursor', realm.ccache, 'CONTENT']) +-realm.run_as_client(['./t_cccursor', mfoo, 'CONTENT'], expected_code=1) ++realm.run(['./t_cccursor', dccname, 'CONTENT']) ++realm.run(['./t_cccursor', fccname, 'CONTENT']) ++realm.run(['./t_cccursor', realm.ccache, 'CONTENT']) ++realm.run(['./t_cccursor', mfoo, 'CONTENT'], expected_code=1) ++if test_keyring: ++ realm.run(['./t_cccursor', krccname, 'CONTENT']) ++ realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname]) + + # Make sure FILE doesn't yield a nonexistent default cache. +-realm.run_as_client([kdestroy]) ++realm.run([kdestroy]) + cursor_test('noexist', [], []) +-realm.run_as_client(['./t_cccursor', fccname, 'CONTENT'], expected_code=1) ++realm.run(['./t_cccursor', fccname, 'CONTENT'], expected_code=1) + + success('Renewing credentials') +diff --git a/src/util/k5test.py b/src/util/k5test.py +index 3400154..aead832 100644 +--- a/src/util/k5test.py ++++ b/src/util/k5test.py +@@ -142,6 +133,9 @@ Scripts may use the following functions and variables: + added newline) in testlog, and write it to stdout if running + verbosely. + ++* which(progname): Return the location of progname in the executable ++ path, or None if it is not found. ++ + * password(name): Return a weakly random password based on name. The + password will be consistent across calls with the same name. + +@@ -388,6 +374,16 @@ def output(msg, force_verbose=False): + sys.stdout.write(msg) + + ++# Return the location of progname in the executable path, or None if ++# it is not found. ++def which(progname): ++ for dir in os.environ["PATH"].split(os.pathsep): ++ path = os.path.join(dir, progname) ++ if os.access(path, os.X_OK): ++ return path ++ return None ++ ++ + def password(name): + """Choose a weakly random password from name, consistent across calls.""" + return name + str(os.getpid()) +@@ -880,6 +880,11 @@ class K5Realm(object): + env['KPROP_PORT'] = str(self.portbase + 3) + return env + ++ def run(self, args, env=None, **keywords): ++ if env is None: ++ env = self.env_client ++ return _run_cmd(args, env, **keywords) ++ + def run_as_client(self, args, **keywords): + return _run_cmd(args, self.env_client, **keywords) + +diff --git a/src/lib/krb5/ccache/Makefile.in b/src/lib/krb5/ccache/Makefile.in +index f64226b..ad53e65 100644 +--- a/src/lib/krb5/ccache/Makefile.in ++++ b/src/lib/krb5/ccache/Makefile.in +@@ -71,6 +66,7 @@ SRCS= $(srcdir)/ccbase.c \ + + EXTRADEPSRCS= \ + $(srcdir)/t_cc.c \ ++ $(srcdir)/t_cccol.c \ + $(srcdir)/t_cccursor.c + + ##DOS##OBJS=$(OBJS) $(OUTPRE)ccfns.$(OBJEXT) +@@ -108,6 +104,10 @@ T_CC_OBJS=t_cc.o + t_cc: $(T_CC_OBJS) $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o t_cc $(T_CC_OBJS) $(KRB5_BASE_LIBS) + ++T_CCCOL_OBJS = t_cccol.o ++t_cccol: $(T_CCCOL_OBJS) $(KRB5_BASE_DEPLIBS) ++ $(CC_LINK) -o $@ $(T_CCCOL_OBJS) $(KRB5_BASE_LIBS) ++ + T_CCCURSOR_OBJS = t_cccursor.o + t_cccursor: $(T_CCCURSOR_OBJS) $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ $(T_CCCURSOR_OBJS) $(KRB5_BASE_LIBS) +@@ -116,11 +116,11 @@ check-unix:: t_cc + KRB5_CONFIG=$(srcdir)/t_krb5.conf ; export KRB5_CONFIG ;\ + $(RUN_SETUP) $(VALGRIND) ./t_cc + +-check-pytests:: t_cccursor ++check-pytests:: t_cccursor t_cccol + $(RUNPYTEST) $(srcdir)/t_cccol.py $(PYTESTFLAGS) + + clean-unix:: +- $(RM) t_cc t_cc.o t_cccursor t_cccursor.o ++ $(RM) t_cc t_cc.o t_cccursor t_cccursor.o t_cccol t_cccol.o + + ##WIN32## $(OUTPRE)cc_mslsa.$(OBJEXT): cc_mslsa.c $(top_srcdir)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) + diff --git a/SPECS/krb5.spec b/SPECS/krb5.spec new file mode 100644 index 0000000..8588d3c --- /dev/null +++ b/SPECS/krb5.spec @@ -0,0 +1,3142 @@ +%global WITH_LDAP 1 +%global WITH_DIRSRV 1 +%if 0%{?fedora} >= 17 || 0%{?rhel} > 6 +# These next two *will* change. +%global WITH_OPENSSL 1 +%global WITH_NSS 0 +%global WITH_SYSVERTO 1 +%else +%global WITH_OPENSSL 1 +%global WITH_NSS 0 +%global WITH_SYSVERTO 0 +%endif +# The "move everything to /usr" feature landed in Fedora 17, but we didn't +# catch up until the Fedora 18 development cycle, at which point we found +# that some packages were hard-coding paths. +%if 0%{?fedora} > 17 || 0%{?rhel} > 6 +%global separate_usr 0 +%else +%global separate_usr 1 +%endif +# Systemd landed in Fedora 15, but this package was cut over for Fedora 16. +%if 0%{?fedora} >= 16 || 0%{?rhel} > 6 +%global WITH_SYSTEMD 1 +%else +%global WITH_SYSTEMD 0 +%endif +# Set this so that find-lang.sh will recognize the .po files. +%global gettext_domain mit-krb5 +# Guess where the -libs subpackage's docs are going to go. +%define libsdocdir %{?_pkgdocdir:%(echo %{_pkgdocdir} | sed -e s,krb5,krb5-libs,g)}%{!?_pkgdocdir:%{_docdir}/%{name}-libs-%{version}} +# Figure out where the default ccache lives and how we set it. +%if 0%{?fedora} > 18 && 0%{?fedora} < 20 +%global compile_default_ccache_name 1 +%global compiled_default_ccache_name DIR:/run/user/%%{uid}/krb5cc +%endif +%if 0%{?fedora} >= 20 || 0%{?rhel} > 6 +%global configure_default_ccache_name 1 +%global configured_default_ccache_name KEYRING:persistent:%%{uid} +%endif + +Summary: The Kerberos network authentication system +Name: krb5 +Version: 1.11.3 +Release: 31%{?dist} +# Maybe we should explode from the now-available-to-everybody tarball instead? +# http://web.mit.edu/kerberos/dist/krb5/1.11/krb5-1.11.3-signed.tar +Source0: krb5-%{version}.tar.gz +Source1: krb5-%{version}.tar.gz.asc +# Use a dummy krb5-%{version}-pdf.tar.xz the first time through, then +# tar cvJf $RPM_SOURCE_DIR/krb5-%%{version}-pdf.tar.xz build-pdf/*.pdf +# after the build phase finishes. +Source3: krb5-%{version}-pdf.tar.xz +Source2: kprop.service +Source4: kadmin.service +Source5: krb5kdc.service +Source6: krb5.conf +Source7: _kpropd +Source8: _kadmind +Source10: kdc.conf +Source11: kadm5.acl +Source19: krb5kdc.sysconfig +Source20: kadmin.sysconfig +Source29: ksu.pamd +Source31: kerberos-adm.portreserve +Source32: krb5_prop.portreserve +Source33: krb5kdc.logrotate +Source34: kadmind.logrotate +Source36: kpropd.init +Source37: kadmind.init +Source38: krb5kdc.init + +BuildRequires: cmake +# Carry this locally until it's available in a packaged form. +Source100: nss_wrapper-0.0-20130719153839Z.git6cb59864.bz2 +Source101: noport.c + +Patch6: krb5-1.10-ksu-path.patch +Patch12: krb5-1.7-ktany.patch +Patch16: krb5-1.10-buildconf.patch +Patch23: krb5-1.3.1-dns.patch +Patch29: krb5-1.10-kprop-mktemp.patch +Patch30: krb5-1.3.4-send-pr-tempfile.patch +Patch39: krb5-1.8-api.patch +Patch56: krb5-1.10-doublelog.patch +Patch59: krb5-1.10-kpasswd_tcp.patch +Patch60: krb5-1.11-pam.patch +Patch63: krb5-1.11-selinux-label.patch +Patch71: krb5-1.11-dirsrv-accountlock.patch +Patch86: krb5-1.9-debuginfo.patch +Patch105: krb5-kvno-230379.patch +Patch113: krb5-1.11-alpha1-init.patch +Patch116: http://ausil.fedorapeople.org/aarch64/krb5/krb5-aarch64.patch +Patch117: krb5-1.11-gss-client-keytab.patch +Patch121: krb5-cccol-primary.patch +Patch123: krb5-1.11.2-empty_passwords.patch +Patch124: krb5-1.11.2-arcfour_short.patch +Patch125: krb5-1.11.2-skew1.patch +Patch126: krb5-1.11.2-skew2.patch +Patch127: krb5-master-test_gss_no_udp.patch +Patch128: krb5-master-test_no_pmap.patch +Patch129: krb5-1.11-run_user_0.patch +Patch130: krb5-master-init_referral.patch +Patch131: krb5-1.11.3-skew3.patch +Patch132: krb5-1.11-gss-methods1.patch +Patch133: krb5-1.11-gss-methods2.patch +Patch134: krb5-1.11-kpasswdtest.patch +Patch135: krb5-1.11-check_transited.patch +Patch136: krb5-1.11.3-prompter1.patch +Patch137: krb5-1.11.3-prompter2.patch +Patch138: krb5-1.11.3-gss-ccache-import.patch +Patch139: krb5-1.10-CVE-2013-1418.patch + +# Patches for otp plugin backport +Patch201: krb5-1.11.2-keycheck.patch +Patch202: krb5-1.11.2-otp.patch + +# Patches for kernel-persistent-keyring support (backport) +Patch301: persistent_keyring.patch +Patch302: krb5-master-kinit-cccol.patch + +Patch400: 0000-ksu-intermediates.patch +Patch401: 0001-Don-t-try-to-stat-not-on-disk-ccache-residuals.patch +Patch402: 0002-Use-an-in-memory-cache-until-we-need-the-target-s.patch +Patch403: 0003-Learn-to-destroy-the-ccache-we-re-copying-from.patch +Patch404: 0004-Try-to-use-the-default_ccache_name-d-as-the-target.patch +Patch405: 0005-Be-more-careful-of-target-ccache-collections.patch +Patch406: 0006-Copy-config-entries-to-the-target-ccache.patch + +License: MIT +URL: http://web.mit.edu/kerberos/www/ +Group: System Environment/Libraries +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: autoconf, bison, flex, gawk, gettext, sed +%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6 +BuildRequires: libcom_err-devel, libss-devel +%endif +BuildRequires: gzip, ncurses-devel, tar +BuildRequires: python-sphinx +# The texlive package got a lot more complicated here. +%if 0%{?fedora} > 17 || 0%{?rhel} > 6 +# Taken from \usepackage directives produced by sphinx: +BuildRequires: tex(babel.sty) +BuildRequires: tex(bookmark.sty) +BuildRequires: tex(fancybox.sty) +BuildRequires: tex(fncychap.sty) +BuildRequires: tex(fontenc.sty) +BuildRequires: tex(framed.sty) +BuildRequires: tex(hyperref.sty) +BuildRequires: tex(ifthen.sty) +BuildRequires: tex(inputenc.sty) +BuildRequires: tex(longtable.sty) +BuildRequires: tex(multirow.sty) +BuildRequires: tex(times.sty) +BuildRequires: tex(titlesec.sty) +BuildRequires: tex(threeparttable.sty) +BuildRequires: tex(wrapfig.sty) +BuildRequires: tex(report.cls) +%else +BuildRequires: texlive-texmf, texlive-texmf-latex +%endif +# Typical fonts, and the commands which we need to have present. +BuildRequires: texlive, texlive-latex, texlive-texmf-fonts +BuildRequires: /usr/bin/pdflatex /usr/bin/makeindex +BuildRequires: keyutils, keyutils-libs-devel >= 1.5.8 +BuildRequires: libselinux-devel +BuildRequires: pam-devel +%if %{WITH_SYSTEMD} +BuildRequires: systemd-units +%endif +# For the test framework. +BuildRequires: perl, dejagnu, tcl-devel +BuildRequires: net-tools, rpcbind +%if 0%{?fedora} >= 13 || 0%{?rhel} > 6 +BuildRequires: hostname +BuildRequires: iproute +%endif + +%if %{WITH_LDAP} +BuildRequires: openldap-devel +%endif +%if %{WITH_OPENSSL} || %{WITH_NSS} +BuildRequires: openssl-devel >= 0.9.8 +%endif +%if %{WITH_NSS} +BuildRequires: nss-devel >= 3.13 +%endif +%if %{WITH_SYSVERTO} +BuildRequires: libverto-devel +%endif + +%description +Kerberos V5 is a trusted-third-party network authentication system, +which can improve your network's security by eliminating the insecure +practice of sending passwords over the network in unencrypted form. + +%package devel +Summary: Development files needed to compile Kerberos 5 programs +Group: Development/Libraries +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6 +Requires: libcom_err-devel +%endif +Requires: keyutils-libs-devel, libselinux-devel +Requires: libverto-devel + +%description devel +Kerberos is a network authentication system. The krb5-devel package +contains the header files and libraries needed for compiling Kerberos +5 programs. If you want to develop Kerberos-aware programs, you need +to install this package. + +%package libs +Summary: The shared libraries used by Kerberos 5 +Group: System Environment/Libraries +%if 0%{?rhel} == 6 +# Some of the older libsmbclient builds here incorrectly called +# krb5_locate_kdc(), which was mistakenly exported in 1.9. +Conflicts: libsmbclient < 3.5.10-124 +%endif +Requires: coreutils, gawk, grep, sed +Requires: keyutils-libs >= 1.5.8 + +%description libs +Kerberos is a network authentication system. The krb5-libs package +contains the shared libraries needed by Kerberos 5. If you are using +Kerberos, you need to install this package. + +%package server +Group: System Environment/Daemons +Summary: The KDC and related programs for Kerberos 5 +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Requires(post): chkconfig +%if %{WITH_SYSTEMD} +Requires(post): systemd-sysv +Requires(post): systemd-units +Requires(preun): systemd-units +Requires(postun): systemd-units +%else +Requires(preun): chkconfig +# portreserve is used by init scripts for kadmind, kpropd, and krb5kdc +Requires: portreserve +%endif +Requires(post): initscripts +Requires(postun): initscripts +# we need 'status -l' to work, and that option was added in 8.99 +Requires: initscripts >= 8.99-1 +# used by the triggers +Requires: chkconfig +# we drop files in its directory, but we don't want to own that directory +Requires: logrotate +Requires(preun): initscripts +# mktemp is used by krb5-send-pr +Requires: coreutils +# we specify /usr/share/dict/words as the default dict_file in kdc.conf +Requires: /usr/share/dict/words +%if %{WITH_SYSVERTO} +# for run-time, and for parts of the test suite +BuildRequires: libverto-module-base +Requires: libverto-module-base +%endif + +%description server +Kerberos is a network authentication system. The krb5-server package +contains the programs that must be installed on a Kerberos 5 key +distribution center (KDC). If you are installing a Kerberos 5 KDC, +you need to install this package (in other words, most people should +NOT install this package). + +%package server-ldap +Group: System Environment/Daemons +Summary: The LDAP storage plugin for the Kerberos 5 KDC +Requires: %{name}-server%{?_isa} = %{version}-%{release} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} + +%description server-ldap +Kerberos is a network authentication system. The krb5-server package +contains the programs that must be installed on a Kerberos 5 key +distribution center (KDC). If you are installing a Kerberos 5 KDC, +and you wish to use a directory server to store the data for your +realm, you need to install this package. + +%package workstation +Summary: Kerberos 5 programs for use on workstations +Group: System Environment/Base +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +# mktemp is used by krb5-send-pr +Requires: coreutils + +%description workstation +Kerberos is a network authentication system. The krb5-workstation +package contains the basic Kerberos programs (kinit, klist, kdestroy, +kpasswd). If your network uses Kerberos, this package should be +installed on every workstation. + +%if 0%{?fedora} >= 17 || 0%{?rhel} > 6 +%package pkinit +%else +%package pkinit-openssl +%endif +Summary: The PKINIT module for Kerberos 5 +Group: System Environment/Libraries +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +%if 0%{?fedora} >= 17 || 0%{?rhel} >= 6 +Obsoletes: krb5-pkinit-openssl < %{version}-%{release} +Provides: krb5-pkinit-openssl = %{version}-%{release} +%endif + +%if 0%{?fedora} >= 17 || 0%{?rhel} > 6 +%description pkinit +%else +%description pkinit-openssl +%endif +Kerberos is a network authentication system. The krb5-pkinit +package contains the PKINIT plugin, which allows clients +to obtain initial credentials from a KDC using a private key and a +certificate. + +%prep +%setup -q -n %{name}-%{version} -a 3 -a 100 +ln -s NOTICE LICENSE + +%patch301 -p1 -b .persistent-keyring +%patch302 -p1 -b .kinit-cccol + +%patch400 -p1 -b .intermediates +%patch401 -p1 -b .Don-t-try-to-stat-not-on-disk-ccache-residuals +%patch402 -p1 -b .Use-an-in-memory-cache-until-we-need-the-target-s +%patch403 -p1 -b .Learn-to-destroy-the-ccache-we-re-copying-from +%patch404 -p1 -b .Try-to-use-the-default_ccache_name-d-as-the-target +%patch405 -p1 -b .Be-more-careful-of-target-ccache-collections +%patch406 -p1 -b .Copy-config-entries-to-the-target-ccache + +%patch60 -p1 -b .pam + +%patch63 -p1 -b .selinux-label + +%patch6 -p1 -b .ksu-path +%patch12 -p1 -b .ktany +%patch16 -p1 -b .buildconf %{?_rawbuild} +%patch23 -p1 -b .dns %{?_rawbuild} +%patch29 -p1 -b .kprop-mktemp +%patch30 -p1 -b .send-pr-tempfile +%patch39 -p1 -b .api +%patch56 -p1 -b .doublelog +%patch59 -p1 -b .kpasswd_tcp +%patch71 -p1 -b .dirsrv-accountlock %{?_rawbuild} +%patch86 -p0 -b .debuginfo +%patch105 -p1 -b .kvno +%patch113 -p1 -b .init +%patch116 -p1 -b .aarch64 +%patch117 -p1 -b .gss-client-keytab +%patch121 -p1 -b .cccol-primary +%patch123 -p1 -b .empty_passwords +%patch124 -p1 -b .arcfour_short +%patch125 -p1 -b .skew1 +%patch126 -p1 -b .skew2 +%patch127 -p1 -b .test_gss_no_udp +%patch128 -p1 -b .test_no_pmap + +# Apply when the hard-wired or configured default location is +# DIR:/run/user/%%{uid}/krb5cc. +%patch129 -p1 -b .run_user_0 + +%patch130 -p1 -b .init_referral +%patch131 -p1 -b .skew3 +%patch132 -p1 -b .gss-methods1 +%patch133 -p1 -b .gss-methods2 +%patch134 -p1 -b .kpasswdtest +%patch135 -p1 -b .check_transited +%patch136 -p1 -b .prompter1 +%patch137 -p1 -b .prompter2 +%patch138 -p1 -b .gss-ccache-import +%patch139 -p1 -b .CVE-2013-1418 + +%patch201 -p1 -b .keycheck +%patch202 -p1 -b .otp + +# Take the execute bit off of documentation. +chmod -x doc/krb5-protocol/*.txt + +# Generate an FDS-compatible LDIF file. +inldif=src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif +cat > 60kerberos.ldif << EOF +# This is a variation on kerberos.ldif which 389 Directory Server will like. +dn: cn=schema +EOF +egrep -iv '(^$|^dn:|^changetype:|^add:)' $inldif | \ +sed -r 's,^ , ,g' | \ +sed -r 's,^ , ,g' >> 60kerberos.ldif +touch -r $inldif 60kerberos.ldif + +# Rebuild the configure scripts. +pushd src +#autoheader +#autoconf +./util/reconf --verbose +popd + +# Create build space for the test wrapper. +mkdir -p nss_wrapper/build + +# Mess with some of the default ports that we use for testing, so that multiple +# builds going on the same host don't step on each other. +cfg="src/kadmin/testing/proto/kdc.conf.proto \ + src/kadmin/testing/proto/krb5.conf.proto \ + src/lib/kadm5/unit-test/api.current/init-v2.exp \ + src/util/k5test.py \ + src/tests/kdc_realm/input_conf/*.conf \ + src/tests/mk_migr/ldap_backend/input_conf/*.conf \ + src/tests/mk_migr/db2_backend/input_conf/*.conf" +LONG_BIT=`getconf LONG_BIT` +PORT=`expr 61000 + $LONG_BIT - 48` +sed -i -e s,61000,`expr "$PORT" + 0`,g $cfg +PORT=`expr 1750 + $LONG_BIT - 48` +sed -i -e s,1750,`expr "$PORT" + 0`,g $cfg +sed -i -e s,1751,`expr "$PORT" + 1`,g $cfg +sed -i -e s,1752,`expr "$PORT" + 2`,g $cfg +PORT=`expr 8888 + $LONG_BIT - 48` +sed -i -e s,8888,`expr "$PORT" - 0`,g $cfg +sed -i -e s,8887,`expr "$PORT" - 1`,g $cfg +sed -i -e s,8886,`expr "$PORT" - 2`,g $cfg +PORT=`expr 7777 + $LONG_BIT - 48` +sed -i -e s,7777,`expr "$PORT" + 0`,g $cfg +sed -i -e s,7778,`expr "$PORT" + 1`,g $cfg + +%build +# Go ahead and supply tcl info, because configure doesn't know how to find it. +. %{_libdir}/tclConfig.sh +pushd src +# Keep the old default if the package is built against older releases. +%if 0%{?compile_default_ccache_name} +DEFCCNAME=%{compiled_default_ccache_name}; export DEFCCNAME +%endif +# Work out the CFLAGS and CPPFLAGS which we intend to use. +INCLUDES=-I%{_includedir}/et +CFLAGS="`echo $RPM_OPT_FLAGS $DEFINES $INCLUDES -fPIC -fno-strict-aliasing -fstack-protector-all`" +CPPFLAGS="`echo $DEFINES $INCLUDES`" +%configure \ + CC="%{__cc}" \ + CFLAGS="$CFLAGS" \ + CPPFLAGS="$CPPFLAGS" \ +%if 0%{?fedora} >= 7 || 0%{?rhel} >= 6 + SS_LIB="-lss" \ +%else + SS_LIB="-lss -lncurses" \ +%endif + --enable-shared \ + --localstatedir=%{_var}/kerberos \ + --disable-rpath \ + --without-krb5-config \ + --with-system-et \ + --with-system-ss \ + --with-netlib=-lresolv \ + --with-tcl \ + --enable-dns-for-realm \ +%if %{WITH_LDAP} + --with-ldap \ +%if %{WITH_DIRSRV} + --with-dirsrv-account-locking \ +%endif +%endif +%if %{WITH_OPENSSL} || %{WITH_NSS} + --enable-pkinit \ +%else + --disable-pkinit \ +%endif +%if %{WITH_OPENSSL} + --with-pkinit-crypto-impl=openssl \ +%endif +%if %{WITH_NSS} + --with-crypto-impl=nss \ +%endif +%if %{WITH_SYSVERTO} + --with-system-verto \ +%else + --without-system-verto \ +%endif + --with-pam \ + --with-selinux +# Now build it. +make +popd + +# Build the docs. +make -C src/doc paths.py version.py +cp src/doc/paths.py doc/ +mkdir -p build-man build-html build-pdf +sphinx-build -a -b man -t pathsubs doc build-man +sphinx-build -a -b html -t pathsubs doc build-html +rm -fr build-html/_sources +sphinx-build -a -b latex -t pathsubs doc build-pdf +# Build the PDFs if we didn't have pre-built ones. +for pdf in admin appdev basic build plugindev user ; do + test -s build-pdf/$pdf.pdf || make -C build-pdf +done + +# Build the test wrapper. +pushd nss_wrapper/build +cmake .. +make +popd + +# We need to cut off any access to locally-running nameservers, too. +%{__cc} -fPIC -shared -o noport.so -Wall -Wextra $RPM_SOURCE_DIR/noport.c + +%check +# Alright, this much is still a work in progress. +%if %{?__isa_bits:%{__isa_bits}}%{!?__isa_bits:32} == 64 +if hostname | grep -q build ; then + sleep 600 +fi +%endif + +# Set things up to use the test wrappers. +NSS_WRAPPER_HOSTNAME=test.example.com ; export NSS_WRAPPER_HOSTNAME +NSS_WRAPPER_HOSTS="`pwd`/nss_wrapper/fakehosts" ; export NSS_WRAPPER_HOSTS +echo 127.0.0.1 $NSS_WRAPPER_HOSTNAME $NSS_WRAPPER_HOSTNAME >"$NSS_WRAPPER_HOSTS" +NOPORT=53,111; export NOPORT +LD_PRELOAD=`pwd`/noport.so:`pwd`/nss_wrapper/build/src/libnss_wrapper.so ; export LD_PRELOAD + +# Run the test suite. We can't actually run the whole thing in the build +# system, but we can at least run more than we used to. The build system may +# give us a revoked session keyring, so run affected tests with a new one. +make -C src runenv.py +: make -C src check TMPDIR=%{_tmppath} +keyctl session - make -C src/lib check TMPDIR=%{_tmppath} OFFLINE=yes +make -C src/kdc check TMPDIR=%{_tmppath} +keyctl session - make -C src/appl check TMPDIR=%{_tmppath} +make -C src/clients check TMPDIR=%{_tmppath} +keyctl session - make -C src/util check TMPDIR=%{_tmppath} + +%install +[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT + +# Sample KDC config files (bundled kdc.conf and kadm5.acl). +mkdir -p $RPM_BUILD_ROOT%{_var}/kerberos/krb5kdc +install -pm 600 %{SOURCE10} $RPM_BUILD_ROOT%{_var}/kerberos/krb5kdc/ +install -pm 600 %{SOURCE11} $RPM_BUILD_ROOT%{_var}/kerberos/krb5kdc/ + +# Where per-user keytabs live by default. +mkdir -p $RPM_BUILD_ROOT%{_var}/kerberos/krb5/user + +# Default configuration file for everything. +mkdir -p $RPM_BUILD_ROOT/etc +install -pm 644 %{SOURCE6} $RPM_BUILD_ROOT/etc/krb5.conf + +# Parent of configuration file for list of loadable GSS mechs ("mechs"). This +# location is not relative to sysconfdir, but is hard-coded in g_initialize.c. +mkdir -m 755 -p $RPM_BUILD_ROOT/etc/gss + +# If the default configuration needs to start specifying a default cache +# location, add it now, then fixup the timestamp so that it looks the same. +%if 0%{?configure_default_ccache_name} +DEFCCNAME="%{configured_default_ccache_name}"; export DEFCCNAME +awk '{print} + /^# default_realm/{print " default_ccache_name =", ENVIRON["DEFCCNAME"]}' \ + %{SOURCE6} > $RPM_BUILD_ROOT/etc/krb5.conf +touch -r %{SOURCE6} $RPM_BUILD_ROOT/etc/krb5.conf +grep default_ccache_name $RPM_BUILD_ROOT/etc/krb5.conf +%endif + +# Server init scripts (krb5kdc,kadmind,kpropd) and their sysconfig files. +%if %{WITH_SYSTEMD} +mkdir -p $RPM_BUILD_ROOT%{_unitdir} +for unit in \ + %{SOURCE5}\ + %{SOURCE4} \ + %{SOURCE2} ; do + # In the past, the init script was supposed to be named after the + # service that the started daemon provided. Changing their names + # is an upgrade-time problem I'm in no hurry to deal with. + install -pm 644 ${unit} $RPM_BUILD_ROOT%{_unitdir} +done +mkdir -p $RPM_BUILD_ROOT%{_sbindir} +for wrapper in \ + %{SOURCE7} \ + %{SOURCE8} ; do + install -pm 755 ${wrapper} $RPM_BUILD_ROOT%{_sbindir}/ +done +%else +mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d +for init in \ + %{SOURCE36}\ + %{SOURCE37} \ + %{SOURCE38} ; do + # In the past, the init script was supposed to be named after the + # service that the started daemon provided. Changing their names + # is an upgrade-time problem I'm in no hurry to deal with. + service=`basename ${init} .init` + install -pm 755 ${init} \ + $RPM_BUILD_ROOT/etc/rc.d/init.d/${service%d} +done +# portreserve configuration files. +mkdir -p $RPM_BUILD_ROOT/etc/portreserve +for portreserve in \ + %{SOURCE31} \ + %{SOURCE32} ; do + install -pm 644 ${portreserve} \ + $RPM_BUILD_ROOT/etc/portreserve/`basename ${portreserve} .portreserve` +done +%endif + +mkdir -p $RPM_BUILD_ROOT/etc/sysconfig +for sysconfig in \ + %{SOURCE19}\ + %{SOURCE20} ; do + install -pm 644 ${sysconfig} \ + $RPM_BUILD_ROOT/etc/sysconfig/`basename ${sysconfig} .sysconfig` +done + +# logrotate configuration files +mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d/ +for logrotate in \ + %{SOURCE33} \ + %{SOURCE34} ; do + install -pm 644 ${logrotate} \ + $RPM_BUILD_ROOT/etc/logrotate.d/`basename ${logrotate} .logrotate` +done + +# PAM configuration files. +mkdir -p $RPM_BUILD_ROOT/etc/pam.d/ +for pam in \ + %{SOURCE29} ; do + install -pm 644 ${pam} \ + $RPM_BUILD_ROOT/etc/pam.d/`basename ${pam} .pamd` +done + +# Plug-in directories. +install -pdm 755 $RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/preauth +install -pdm 755 $RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/kdb +install -pdm 755 $RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/authdata + +# The rest of the binaries, headers, libraries, and docs. +make -C src DESTDIR=$RPM_BUILD_ROOT EXAMPLEDIR=%{libsdocdir}/examples install + +# Munge krb5-config yet again. This is totally wrong for 64-bit, but chunks +# of the buildconf patch already conspire to strip out /usr/ from the +# list of link flags, and it helps prevent file conflicts on multilib systems. +sed -r -i -e 's|^libdir=/usr/lib(64)?$|libdir=/usr/lib|g' $RPM_BUILD_ROOT%{_bindir}/krb5-config + +%if %{separate_usr} +# Move specific libraries from %%{_libdir} to /%%{_lib}, and fixup the symlinks. +touch $RPM_BUILD_ROOT/rootfile +rellibdir=.. +while ! test -r $RPM_BUILD_ROOT/%{_libdir}/${rellibdir}/rootfile ; do + rellibdir=../${rellibdir} +done +rm -f $RPM_BUILD_ROOT/rootfile +mkdir -p $RPM_BUILD_ROOT/%{_lib} +for library in libgssapi_krb5 libgssrpc libk5crypto libkrb5 libkrb5support ; do + mv $RPM_BUILD_ROOT/%{_libdir}/${library}.so.* $RPM_BUILD_ROOT/%{_lib}/ + pushd $RPM_BUILD_ROOT/%{_libdir} + ln -fs ${rellibdir}/%{_lib}/${library}.so.*.* ${library}.so + popd +done +%endif + +# Install processed man pages. +for section in 1 5 8 ; do + install -m 644 build-man/*.${section} \ + $RPM_BUILD_ROOT/%{_mandir}/man${section}/ +done + +%find_lang %{gettext_domain} + +%clean +[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT + +%post libs -p /sbin/ldconfig + +%if 0%{?configure_default_ccache_name} +%triggerun libs -- krb5-libs < 1.11.3-16 +# Triggered roughly on the version where this logic was introduced. +# Try to add a default_ccache_name to /etc/krb5.conf, removing the previous +# default which we configured, if we find it. +DEFCCNAME="%{configured_default_ccache_name}"; export DEFCCNAME +tmpfile=`mktemp /etc/krb5.conf.XXXXXX` +if test -z "$tmpfile" ; then + # Give up. + exit 0 +fi +# Remove the default value we previously set. Be very exact about it. +if grep -q default_ccache_name /etc/krb5.conf ; then + sed -r '/^ default_ccache_name = DIR:\/run\/user\/%%\{uid\}\/krb5cc$/d' /etc/krb5.conf > "$tmpfile" + if test -s "$tmpfile" ; then + if touch -r /etc/krb5.conf "$tmpfile" ; then + cat "$tmpfile" > /etc/krb5.conf + touch -r "$tmpfile" /etc/krb5.conf + fi + fi +fi +# Add the new default value, unless there's one set. Don't be too particular +# about it. +if ! grep -q default_ccache_name /etc/krb5.conf ; then + awk ' + /^\[.*\]$/ { + if (libdefaults) { + print " default_ccache_name =", ENVIRON["DEFCCNAME"] + print "" + } + libdefaults=0; + } + /^\[libdefaults\]$/ { libdefaults=1; } + { print }' /etc/krb5.conf > "$tmpfile" + if test -s "$tmpfile" ; then + if touch -r /etc/krb5.conf "$tmpfile" ; then + cat "$tmpfile" > /etc/krb5.conf + touch -r "$tmpfile" /etc/krb5.conf + fi + fi +fi +if test -n "$tmpfile" ; then + rm -f "$tmpfile" +fi +%endif + +%postun libs -p /sbin/ldconfig + +%post server-ldap -p /sbin/ldconfig + +%postun server-ldap -p /sbin/ldconfig + +%post server +# Remove the init script for older servers. +[ -x /etc/rc.d/init.d/krb5server ] && /sbin/chkconfig --del krb5server +%if %{WITH_SYSTEMD} +if [ $1 -eq 1 ] ; then + # Initial installation + /bin/systemctl daemon-reload >/dev/null 2>&1 || : +fi +%else +# Install the new ones. +/sbin/chkconfig --add krb5kdc +/sbin/chkconfig --add kadmin +/sbin/chkconfig --add kprop +%endif +exit 0 + +%preun server +if [ "$1" -eq "0" ] ; then +%if %{WITH_SYSTEMD} + /bin/systemctl --no-reload disable krb5kdc.service > /dev/null 2>&1 || : + /bin/systemctl --no-reload disable kadmin.service > /dev/null 2>&1 || : + /bin/systemctl --no-reload disable kprop.service > /dev/null 2>&1 || : + /bin/systemctl stop krb5kdc.service > /dev/null 2>&1 || : + /bin/systemctl stop kadmin.service > /dev/null 2>&1 || : + /bin/systemctl stop kprop.service > /dev/null 2>&1 || : +%else + /sbin/chkconfig --del krb5kdc + /sbin/chkconfig --del kadmin + /sbin/chkconfig --del kprop + /sbin/service krb5kdc stop > /dev/null 2>&1 || : + /sbin/service kadmin stop > /dev/null 2>&1 || : + /sbin/service kprop stop > /dev/null 2>&1 || : +%endif +fi +exit 0 + +%postun server +%if %{WITH_SYSTEMD} +/bin/systemctl daemon-reload >/dev/null 2>&1 || : +if [ "$1" -ge 1 ] ; then + /bin/systemctl try-restart krb5kdc.service >/dev/null 2>&1 || : + /bin/systemctl try-restart kadmin.service >/dev/null 2>&1 || : + /bin/systemctl try-restart kprop.service >/dev/null 2>&1 || : +fi +%else +if [ "$1" -ge 1 ] ; then + /sbin/service krb5kdc condrestart > /dev/null 2>&1 || : + /sbin/service kadmin condrestart > /dev/null 2>&1 || : + /sbin/service kprop condrestart > /dev/null 2>&1 || : +fi +%endif +exit 0 + +%if %{WITH_SYSTEMD} +%triggerun server -- krb5-server < 1.9.1-13 +# Save the current service runlevel info +# User must manually run +# systemd-sysv-convert --apply krb5kdc +# systemd-sysv-convert --apply kadmin +# systemd-sysv-convert --apply kprop +# to migrate them to systemd targets +/usr/bin/systemd-sysv-convert --save krb5kdc >/dev/null 2>&1 ||: +/usr/bin/systemd-sysv-convert --save kadmin >/dev/null 2>&1 ||: +/usr/bin/systemd-sysv-convert --save kprop >/dev/null 2>&1 ||: + +# Run these because the SysV package being removed won't do them +/sbin/chkconfig --del krb5kdc >/dev/null 2>&1 || : +/sbin/chkconfig --del kadmin >/dev/null 2>&1 || : +/sbin/chkconfig --del kprop >/dev/null 2>&1 || : +/bin/systemctl try-restart krb5kdc.service >/dev/null 2>&1 || : +/bin/systemctl try-restart kadmin.service >/dev/null 2>&1 || : +/bin/systemctl try-restart kprop.service >/dev/null 2>&1 || : +%endif + +%triggerun server -- krb5-server < 1.6.3-100 +if [ "$2" -eq "0" ] ; then + /sbin/install-info --delete %{_infodir}/krb425.info.gz %{_infodir}/dir + /sbin/service krb524 stop > /dev/null 2>&1 || : + /sbin/chkconfig --del krb524 > /dev/null 2>&1 || : +fi +exit 0 + +%files workstation +%defattr(-,root,root,-) +%doc src/config-files/services.append +%doc build-html/* +%doc build-pdf/user.pdf build-pdf/basic.pdf +%attr(0755,root,root) %doc src/config-files/convert-config-files + +# Clients of the KDC, including tools you're likely to need if you're running +# app servers other than those built from this source package. +%{_bindir}/kdestroy +%{_mandir}/man1/kdestroy.1* +%{_bindir}/kinit +%{_mandir}/man1/kinit.1* +%{_bindir}/klist +%{_mandir}/man1/klist.1* +%{_bindir}/kpasswd +%{_mandir}/man1/kpasswd.1* +%{_bindir}/kswitch +%{_mandir}/man1/kswitch.1* + +%{_bindir}/kvno +%{_mandir}/man1/kvno.1* +%{_bindir}/kadmin +%{_mandir}/man1/kadmin.1* +%{_bindir}/k5srvutil +%{_mandir}/man1/k5srvutil.1* +%{_bindir}/ktutil +%{_mandir}/man1/ktutil.1* + +# Doesn't really fit anywhere else. +%attr(4755,root,root) %{_bindir}/ksu +%{_mandir}/man1/ksu.1* +%config(noreplace) /etc/pam.d/ksu + +# Problem-reporting tool. +%{_sbindir}/krb5-send-pr +%dir %{_datadir}/gnats +%{_datadir}/gnats/mit +%{_mandir}/man1/krb5-send-pr.1* + +%files server +%defattr(-,root,root,-) +%docdir %{_mandir} +%doc build-pdf/admin.pdf build-pdf/build.pdf +%if %{WITH_SYSTEMD} +%{_unitdir}/krb5kdc.service +%{_unitdir}/kadmin.service +%{_unitdir}/kprop.service +%else +/etc/rc.d/init.d/krb5kdc +/etc/rc.d/init.d/kadmin +/etc/rc.d/init.d/kprop +%config(noreplace) /etc/portreserve/kerberos-adm +%config(noreplace) /etc/portreserve/krb5_prop +%endif +%config(noreplace) /etc/sysconfig/krb5kdc +%config(noreplace) /etc/sysconfig/kadmin +%config(noreplace) /etc/logrotate.d/krb5kdc +%config(noreplace) /etc/logrotate.d/kadmind + +%dir %{_var}/kerberos +%dir %{_var}/kerberos/krb5kdc +%config(noreplace) %{_var}/kerberos/krb5kdc/kdc.conf +%config(noreplace) %{_var}/kerberos/krb5kdc/kadm5.acl + +%dir %{_libdir}/krb5 +%dir %{_libdir}/krb5/plugins +%dir %{_libdir}/krb5/plugins/kdb +%dir %{_libdir}/krb5/plugins/preauth +%dir %{_libdir}/krb5/plugins/authdata +%{_libdir}/krb5/plugins/preauth/otp.so + + +# Problem-reporting tool. +%{_sbindir}/krb5-send-pr +%dir %{_datadir}/gnats +%{_datadir}/gnats/mit +%{_mandir}/man1/krb5-send-pr.1* + +# KDC binaries and configuration. +%{_mandir}/man5/kadm5.acl.5* +%{_mandir}/man5/kdc.conf.5* +%{_sbindir}/kadmin.local +%{_mandir}/man8/kadmin.local.8* +%{_sbindir}/kadmind +%{_sbindir}/_kadmind +%{_mandir}/man8/kadmind.8* +%{_sbindir}/kdb5_util +%{_mandir}/man8/kdb5_util.8* +%{_sbindir}/kprop +%{_mandir}/man8/kprop.8* +%{_sbindir}/kpropd +%{_sbindir}/_kpropd +%{_mandir}/man8/kpropd.8* +%{_sbindir}/kproplog +%{_mandir}/man8/kproplog.8* +%{_sbindir}/krb5kdc +%{_mandir}/man8/krb5kdc.8* + +# This is here for people who want to test their server, and also +# included in devel package for similar reasons. +%{_bindir}/sclient +%{_mandir}/man1/sclient.1* +%{_sbindir}/sserver +%{_mandir}/man8/sserver.8* + +%if %{WITH_LDAP} +%files server-ldap +%defattr(-,root,root,-) +%docdir %{_mandir} +%doc src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif +%doc src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema +%doc 60kerberos.ldif +%dir %{_libdir}/krb5 +%dir %{_libdir}/krb5/plugins +%dir %{_libdir}/krb5/plugins/kdb +%{_libdir}/krb5/plugins/kdb/kldap.so +%{_libdir}/libkdb_ldap.so +%{_libdir}/libkdb_ldap.so.* +%{_mandir}/man8/kdb5_ldap_util.8.gz +%{_sbindir}/kdb5_ldap_util +%endif + +%files libs -f %{gettext_domain}.lang +%defattr(-,root,root,-) +%doc README NOTICE LICENSE +%docdir %{_mandir} +# This is a hard-coded, not-dependent-on-the-configure-script path. +%dir /etc/gss +%verify(not md5 size mtime) %config(noreplace) /etc/krb5.conf +/%{_mandir}/man5/.k5identity.5* +/%{_mandir}/man5/.k5login.5* +/%{_mandir}/man5/k5identity.5* +/%{_mandir}/man5/k5login.5* +/%{_mandir}/man5/krb5.conf.5* +%if %{separate_usr} +/%{_lib}/libgssapi_krb5.so.* +/%{_lib}/libgssrpc.so.* +/%{_lib}/libk5crypto.so.* +%else +%{_libdir}/libgssapi_krb5.so.* +%{_libdir}/libgssrpc.so.* +%{_libdir}/libk5crypto.so.* +%endif +%{_libdir}/libkadm5clnt_mit.so.* +%{_libdir}/libkadm5srv_mit.so.* +%{_libdir}/libkdb5.so.* +%{_libdir}/libkrad.so.* +%if %{separate_usr} +/%{_lib}/libkrb5.so.* +/%{_lib}/libkrb5support.so.* +%else +%{_libdir}/libkrb5.so.* +%{_libdir}/libkrb5support.so.* +%endif +%dir %{_libdir}/krb5 +%dir %{_libdir}/krb5/plugins +%dir %{_libdir}/krb5/plugins/* +%{_libdir}/krb5/plugins/kdb/db2.so +%dir %{_var}/kerberos +%dir %{_var}/kerberos/krb5 +%dir %{_var}/kerberos/krb5/user +%if ! %{WITH_SYSVERTO} +%{_libdir}/libverto-k5ev.so +%{_libdir}/libverto-k5ev.so.* +# These really shouldn't be here, but until we have a system copy of libverto, +# don't force people who are using libverto to install the KDC just to get the +# shared library. Not that there are any development headers, but anyway. +%{_libdir}/libverto.so +%{_libdir}/libverto.so.* +%endif + +%if 0%{?fedora} >= 17 || 0%{?rhel} > 6 +%files pkinit +%else +%files pkinit-openssl +%endif +%defattr(-,root,root,-) +%dir %{_libdir}/krb5 +%dir %{_libdir}/krb5/plugins +%dir %{_libdir}/krb5/plugins/preauth +%{_libdir}/krb5/plugins/preauth/pkinit.so + +%files devel +%defattr(-,root,root,-) +%docdir %{_mandir} +%doc doc/krb5-protocol +%doc build-pdf/appdev.pdf build-pdf/plugindev.pdf + +%{_includedir}/* +%{_libdir}/libgssapi_krb5.so +%{_libdir}/libgssrpc.so +%{_libdir}/libk5crypto.so +%{_libdir}/libkadm5clnt.so +%{_libdir}/libkadm5clnt_mit.so +%{_libdir}/libkadm5srv.so +%{_libdir}/libkadm5srv_mit.so +%{_libdir}/libkdb5.so +%{_libdir}/libkrad.so +%{_libdir}/libkrb5.so +%{_libdir}/libkrb5support.so + +%{_bindir}/krb5-config +%{_bindir}/sclient +%{_mandir}/man1/krb5-config.1* +%{_mandir}/man1/sclient.1* +%{_mandir}/man8/sserver.8* +%{_sbindir}/sserver + +# Protocol test clients. +%{_bindir}/sim_client +%{_bindir}/gss-client +%{_bindir}/uuclient + +# Protocol test servers. +%{_sbindir}/sim_server +%{_sbindir}/gss-server +%{_sbindir}/uuserver + +%changelog +* Fri Nov 8 2013 Nalin Dahyabhai - 1.11.3-31 +- revise proposed changes for ksu to handle dropping privileges and cases + where we didn't pick up creds from the source ccache + +* Tue Nov 5 2013 Nalin Dahyabhai - 1.11.3-30 +- add currently-proposed changes to teach ksu about credential cache + collections and the default_ccache_name setting (#1015559) + +* Tue Nov 5 2013 Nalin Dahyabhai - 1.11.3-29 +- incorporate upstream patch for remote crash of KDCs which serve multiple + realms simultaneously (#1026981, RT#7756, CVE-2013-1418) + +* Tue Nov 5 2013 Nalin Dahyabhai - 1.11.3-28 +- drop patch to add additional access() checks to ksu - they add to breakage + when non-FILE: caches are in use (#1015559), shouldn't be resulting in any + benefit, and clash with proposed changes to fix its cache handling + +* Tue Oct 22 2013 Nalin Dahyabhai - 1.11.3-27 +- add some minimal description to the top of the wrapper scripts we use + when starting krb5kdc and kadmind to describe why they exist (tooling) + +* Wed Oct 16 2013 Nalin Dahyabhai - 1.11.3-26 +- create and own /etc/gss (#1019937) + +* Tue Oct 15 2013 Nalin Dahyabhai - 1.11.3-25 +- pull up fix for importing previously-exported credential caches in the + gssapi library (RT# 7706, #1019420) + +* Mon Oct 14 2013 Nalin Dahyabhai - 1.11.3-24 +- backport the callback to use the libkrb5 prompter when we can't load PEM + files for PKINIT (RT#7590, includes part of #965721/#1016690) +- extract the rest of the fix #965721/#1016690 from the changes for RT#7680 + +* Mon Oct 14 2013 Nalin Dahyabhai - 1.11.3-23 +- fix trigger scriptlet's invocation of sed (#1016945) + +* Fri Oct 4 2013 Nalin Dahyabhai - 1.11.3-22 +- rebuild with keyutils 1.5.8 (part of #1012043) + +* Wed Oct 2 2013 Nalin Dahyabhai - 1.11.3-21 +- switch to the version of persistent-keyring that was just merged to + master (RT#7711), along with related changes to kinit (RT#7689) +- go back to setting default_ccache_name to a KEYRING type + +* Mon Sep 30 2013 Nalin Dahyabhai - 1.11.3-20 +- pull up fix for not calling a kdb plugin's check-transited-path + method before calling the library's default version, which only knows + how to read what's in the configuration file (RT#7709, #1013664) + +* Thu Sep 26 2013 Nalin Dahyabhai - 1.11.3-19 +- configure --without-krb5-config so that we don't pull in the old default + ccache name when we want to stop setting a default ccache name at configure- + time + +* Wed Sep 25 2013 Nalin Dahyabhai - 1.11.3-18 +- fix broken dependency on awk (should be gawk, rdieter) + +* Wed Sep 25 2013 Nalin Dahyabhai - 1.11.3-17 +- add missing dependency on newer keyutils-libs (#1012034) + +* Tue Sep 24 2013 Nalin Dahyabhai - 1.11.3-16 +- back out setting default_ccache_name to the new default for now, resetting + it to the old default while the kernel/keyutils bits get sorted (sgallagh) + +* Mon Sep 23 2013 Nalin Dahyabhai - 1.11.3-15 +- add explicit build-time dependency on a version of keyutils that's new + enough to include keyctl_get_persistent() (more of #991148) + +* Thu Sep 19 2013 Nalin Dahyabhai - 1.11.3-14 +- incorporate Simo's updated backport of his updated persistent-keyring changes + (more of #991148) + +* Fri Sep 13 2013 Nalin Dahyabhai - 1.11.3-13 +- don't break during %%check when the session keyring is revoked + +* Fri Sep 13 2013 Nalin Dahyabhai - 1.11.3-12 +- pull the newer F21 defaults back to F20 (sgallagh) + +* Mon Sep 9 2013 Nalin Dahyabhai +- only apply the patch to autocreate /run/user/0 when we're hard-wiring the + default ccache location to be under it; otherwise it's unnecessary + +* Mon Sep 9 2013 Nalin Dahyabhai 1.11.3-11 +- don't let comments intended for one scriptlet become part of the "script" + that gets passed to ldconfig as part of another one (Mattias Ellert, #1005675) + +* Fri Sep 6 2013 Nalin Dahyabhai 1.11.3-10 +- incorporate Simo's backport of his persistent-keyring changes (#991148) +- restore build-time default DEFCCNAME on Fedora 21 and later and EL, and + instead set default_ccache_name in the default krb5.conf's [libdefaults] + section (#991148) +- on releases where we expect krb5.conf to be configured with a + default_ccache_name, add it whenever we upgrade from an older version of + the package that wouldn't have included it in its default configuration + file (#991148) + +* Fri Aug 23 2013 Nalin Dahyabhai 1.11.3-9 +- take another stab at accounting for UnversionedDocdirs for the -libs + subpackage (spotted by ssorce) +- switch to just the snapshot of nss_wrapper we were using, since we + no longer need to carry anything that isn't in the cwrap.org repository + (ssorce) + +* Thu Aug 15 2013 Nalin Dahyabhai 1.11.3-8 +- drop a patch we weren't not applying (build tooling) +- wrap kadmind and kpropd in scripts which check for the presence/absence + of files which dictate particular exit codes before exec'ing the actual + binaries, instead of trying to use ConditionPathExists in the unit files + to accomplish that, so that we exit with failure properly when what we + expect isn't actually in effect on the system (#800343) + +* Mon Jul 29 2013 Nalin Dahyabhai 1.11.3-7 +- attempt to account for UnversionedDocdirs for the -libs subpackage + +* Fri Jul 26 2013 Nalin Dahyabhai 1.11.3-6 +- tweak configuration files used during tests to try to reduce the number + of conflicts encountered when builds for multiple arches land on the same + builder + +* Mon Jul 22 2013 Nalin Dahyabhai 1.11.3-5 +- pull up changes to allow GSSAPI modules to provide more functions + (RT#7682, #986564/#986565) + +* Fri Jul 19 2013 Nalin Dahyabhai 1.11.3-4 +- use (a bundled, for now, copy of) nss_wrapper to let us run some of the + self-tests at build-time in more places than we could previously (#978756) +- cover inconsistencies in whether or not there's a local caching nameserver + that's willing to answer when the build environment doesn't have a + resolver configuration, so that nss_wrapper's faking of the local + hostname can be complete + +* Mon Jul 1 2013 Nalin Dahyabhai 1.11.3-3 +- specify dependencies on the same arch of krb5-libs by using the %%{?_isa} + suffix, to avoid dragging 32-bit libraries onto 64-bit systems (#980155) + +* Thu Jun 13 2013 Nalin Dahyabhai 1.11.3-2 +- special-case /run/user/0, attempting to create it when resolving a + directory cache below it fails due to ENOENT and we find that it doesn't + already exist, either, before attempting to create the directory cache + (maybe helping, maybe just making things more confusing for #961235) + +* Tue Jun 4 2013 Nalin Dahyabhai 1.11.3-1 +- update to 1.11.3 + - drop patch for RT#7605, fixed in this release + - drop patch for CVE-2002-2443, fixed in this release + - drop patch for RT#7369, fixed in this release +- pull upstream fix for breaking t_skew.py by adding the patch for #961221 + +* Fri May 31 2013 Nalin Dahyabhai 1.11.2-10 +- respin with updated version of patch for RT#7650 (#969331) + +* Thu May 30 2013 Nalin Dahyabhai 1.11.2-9 +- don't forget to set the SELinux label when creating the directory for + a DIR: ccache +- pull in proposed fix for attempts to get initial creds, which end up + following referrals, incorrectly trying to always use master KDCs if + they talked to a master at any point (should fix RT#7650) + +* Thu May 30 2013 Nalin Dahyabhai 1.11.2-8 +- pull in patches from master to not test GSSRPC-over-UDP and to not + depend on the portmapper, which are areas where our build systems + often give us trouble, too + +* Tue May 28 2013 Nalin Dahyabhai 1.11.2-7 +- backport fix for not being able to verify the list of transited realms + in GSS acceptors (RT#7639, #959685) +- backport fix for not being able to pass an empty password to the + get-init-creds APIs and have them actually use it (RT#7642, #960001) +- add backported proposed fix to use the unauthenticated server time + as the basis for computing the requested credential expiration times, + rather than the client's idea of the current time, which could be + significantly incorrect (#961221) + +* Tue May 21 2013 Nalin Dahyabhai 1.11.2-6 +- pull in upstream fix to start treating a KRB5CCNAME value that begins + with DIR:: the same as it would a DIR: value with just one ccache file + in it (RT#7172, #965574) + +* Mon May 13 2013 Nalin Dahyabhai 1.11.2-5 +- pull up fix for UDP ping-pong flaw in kpasswd service (CVE-2002-2443, + #962531,#962534) + +* Mon Apr 29 2013 Nathaniel McCallum 1.11.2-4 +- Update otp patches +- Merge otp patches into a single patch +- Add keycheck patch + +* Tue Apr 23 2013 Nalin Dahyabhai 1.11.2-3 +- pull the changing of the compiled-in default ccache location to + DIR:/run/user/%%{uid}/krb5cc back into F19, in line with SSSD and + the most recent pam_krb5 build + +* Wed Apr 17 2013 Nalin Dahyabhai 1.11.2-2 +- correct some configuration file paths which the KDC_DIR patch missed + +* Mon Apr 15 2013 Nalin Dahyabhai 1.11.2-1 +- update to 1.11.2 + - drop pulled in patch for RT#7586, included in this release + - drop pulled in patch for RT#7592, included in this release +- pull in fix for keeping track of the message type when parsing FAST requests + in the KDC (RT#7605, #951843) (also #951965) + +* Fri Apr 12 2013 Nalin Dahyabhai 1.11.1-9 +- move the compiled-in default ccache location from the previous default of + FILE:/tmp/krb5cc_%%{uid} to DIR:/run/user/%%{uid}/krb5cc (part of #949588) + +* Tue Apr 09 2013 Nathaniel McCallum - 1.11.1-8 +- Update otp backport patches (libk5radius => libkrad) + +* Wed Apr 3 2013 Nalin Dahyabhai 1.11.1-7 +- when testing the RPC library, treat denials from the local portmapper the + same as a portmapper-not-running situation, to allow other library tests + to be run while building the package + +* Thu Mar 28 2013 Nalin Dahyabhai 1.11.1-6 +- create and own /var/kerberos/krb5/user instead of /var/kerberos/kdc/user, + since that's what the libraries actually look for +- add buildrequires on nss-myhostname, in an attempt to get more of the tests + to run properly during builds +- pull in Simo's patch to recognize "client_keytab" as a key type which can + be passed in to gss_acquire_cred_from() (RT#7598) + +* Tue Mar 26 2013 Nalin Dahyabhai 1.11.1-5 +- pull up Simo's patch to mark the correct mechanism on imported GSSAPI + contexts (RT#7592) +- go back to using reconf to run autoconf and autoheader (part of #925640) +- add temporary patch to use newer config.guess/config.sub (more of #925640) + +* Mon Mar 18 2013 Nalin Dahyabhai +- fix a version comparison to expect newer texlive build requirements when + %%{_rhel} > 6 rather than when it's > 7 + +* Mon Mar 11 2013 Nathaniel McCallum 1.11.1-4 +- Add libverto-devel requires for krb5-devel +- Add otp support + +* Thu Feb 28 2013 Nalin Dahyabhai 1.11.1-3 +- fix a memory leak when acquiring credentials using a keytab (RT#7586, #911110) + +* Wed Feb 27 2013 Nalin Dahyabhai 1.11.1-2 +- prebuild PDF docs to reduce multilib differences (internal tooling, #884065) +- drop the kerberos-iv portreserve file, and drop the rest on systemd systems +- escape uses of macros in comments (more of #884065) + +* Mon Feb 25 2013 Nalin Dahyabhai 1.11.1-1 +- update to 1.11.1 + - drop patch for noticing negative timeouts being passed to the poll() + wrapper in the client transmit functions + +* Fri Feb 8 2013 Nalin Dahyabhai 1.11-2 +- set "rdns = false" in the default krb5.conf (#908323,#908324) + +* Tue Dec 18 2012 Nalin Dahyabhai 1.11-1 +- update to 1.11 release + +* Thu Dec 13 2012 Nalin Dahyabhai 1.11-0.beta2.0 +- update to 1.11 beta 2 + +* Thu Dec 13 2012 Nalin Dahyabhai +- when building with our bundled copy of libverto, package it in with -libs + rather than with -server (#886049) + +* Wed Nov 21 2012 Nalin Dahyabhai 1.11-0.beta1.0 +- update to 1.11 beta 1 + +* Fri Nov 16 2012 Nalin Dahyabhai 1.11-0.alpha1.1 +- handle releases where texlive packaging wasn't yet as complicated as it + is in Fedora 18 +- fix an uninitialized-variable error building one of the test programs + +* Fri Nov 16 2012 Nalin Dahyabhai 1.11-0.alpha1.0 +- move the rather large pile of html and pdf docs to -workstation, so + that just having something that links to the libraries won't drag + them onto a system, and we avoid having to sort out hard-coded paths + that include %%{_libdir} showing up in docs in multilib packages +- actually create %%{_var}/kerberos/kdc/user, so that it can be packaged +- correct the list of packaged man pages +- don't dummy up required tex stylesheets, require them +- require pdflatex and makeindex + +* Thu Nov 15 2012 Nalin Dahyabhai +- update to 1.11 alpha 1 + - drop backported patch for RT #7406 + - drop backported patch for RT #7407 + - drop backported patch for RT #7408 + - the new docs system generates PDFs, so stop including them as sources + - drop backported patch to allow deltat.y to build with the usual + warning flags and the current gcc + - drop backported fix for disabling use of a replay cache when verifying + initial credentials + - drop backported fix for teaching PKINIT clients which trust the KDC's + certificate directly to verify signed-data messages that are signed with + the KDC's certificate, when the blobs don't include a copy of the KDC's + certificate + - drop backported patches to make keytab-based authentication attempts + work better when the client tells the KDC that it supports a particular + cipher, but doesn't have a key for it in the keytab + - drop backported fix for avoiding spurious clock skew when a TGT is + decrypted long after the KDC sent it to the client which decrypts it + - move the cross-referenced HTML docs into the -libs package to avoid + broken internal links + - drop patches to fixup paths in man pages, shouldn't be needed any more + +* Wed Oct 17 2012 Nalin Dahyabhai 1.10.3-7 +- tag a couple of other patches which we still need to be applied during + %%{?_rawbuild} builds (zmraz) + +* Tue Sep 25 2012 Nalin Dahyabhai 1.10.3-6 +- actually pull up the patch for RT#7063, and not some other ticket (#773496) + +* Mon Sep 10 2012 Nalin Dahyabhai 1.10.3-5 +- add patch based on one from Filip Krska to not call poll() with a negative + timeout when the caller's intent is for us to just stop calling it (#838548) + +* Fri Sep 7 2012 Nalin Dahyabhai +- on EL6, conflict with libsmbclient before 3.5.10-124, which is when it + stopped linking with a symbol which we no longer export (#771687) +- pull up patch for RT#7063, in which not noticing a prompt for a long + time throws the client library's idea of the time difference between it + and the KDC really far out of whack (#773496) +- add a backport of more patches to set the client's list of supported enctypes + when using a keytab to be the list of types of keys in the keytab, plus the + list of other types the client supports but for which it doesn't have keys, + in that order, so that KDCs have a better chance of being able to issue + tickets with session keys of types that the client can use (#837855) + +* Thu Sep 6 2012 Nalin Dahyabhai 1.10.3-4 +- cut down the number of times we load SELinux labeling configuration from + a minimum of two times to actually one (more of #845125) + +* Thu Aug 30 2012 Nalin Dahyabhai 1.10.3-3 +- backport patch to disable replay detection in krb5_verify_init_creds() + while reading the AP-REQ that's generated in the same function (RT#7229) + +* Thu Aug 30 2012 Nalin Dahyabhai 1.10.3-2 +- undo rename from krb5-pkinit-openssl to krb5-pkinit on EL6 +- version the Obsoletes: on the krb5-pkinit-openssl to krb5-pkinit rename +- reintroduce the init scripts for non-systemd releases +- forward-port %%{?_rawbuild} annotations from EL6 packaging + +* Thu Aug 9 2012 Nalin Dahyabhai 1.10.3-1 +- update to 1.10.3, rolling in the fixes from MITKRB5-SA-2012-001 + +* Thu Aug 2 2012 Nalin Dahyabhai 1.10.2-7 +- selinux: hang on to the list of selinux contexts, freeing and reloading + it only when the file we read it from is modified, freeing it when the + shared library is being unloaded (#845125) + +* Thu Aug 2 2012 Nalin Dahyabhai 1.10.2-6 +- go back to not messing with library file paths on Fedora 17: it breaks + file path dependencies in other packages, and since Fedora 17 is already + released, breaking that is our fault + +* Tue Jul 31 2012 Nalin Dahyabhai 1.10.2-5 +- add upstream patch to fix freeing an uninitialized pointer and dereferencing + another uninitialized pointer in the KDC (MITKRB5-SA-2012-001, CVE-2012-1014 + and CVE-2012-1015, #844779 and #844777) +- fix a thinko in whether or not we mess around with devel .so symlinks on + systems without a separate /usr (sbose) + +* Fri Jul 27 2012 Fedora Release Engineering - 1.10.2-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Fri Jun 22 2012 Nalin Dahyabhai 1.10.2-3 +- backport a fix to allow a PKINIT client to handle SignedData from a KDC + that's signed with a certificate that isn't in the SignedData, but which + is available as an anchor or intermediate on the client (RT#7183) + +* Tue Jun 5 2012 Nalin Dahyabhai 1.10.2-2 +- back out this labeling change (dwalsh): + - when building the new label for a file we're about to create, also mix + in the current range, in addition to the current user + +* Fri Jun 1 2012 Nalin Dahyabhai 1.10.2-1 +- update to 1.10.2 + - when building the new label for a file we're about to create, also mix + in the current range, in addition to the current user + - also package the PDF format admin, user, and install guides + - drop some PDFs that no longer get built right +- add a backport of Stef's patch to set the client's list of supported + enctypes to match the types of keys that we have when we are using a + keytab to try to get initial credentials, so that a KDC won't send us + an AS reply that we can't encrypt (RT#2131, #748528) +- don't shuffle around any shared libraries on releases with no-separate-/usr, + since /usr/lib is the same place as /lib +- add explicit buildrequires: on 'hostname', for the tests, on systems where + it's in its own package, and require net-tools, which used to provide the + command, everywhere + +* Mon May 7 2012 Nalin Dahyabhai +- skip the setfscreatecon() if fopen() is passed "rb" as the open mode (part + of #819115) + +* Tue May 1 2012 Nalin Dahyabhai 1.10.1-3 +- have -server require /usr/share/dict/words, which we set as the default + dict_file in kdc.conf (#817089) + +* Tue Mar 20 2012 Nalin Dahyabhai 1.10.1-2 +- change back dns_lookup_kdc to the default setting (Stef Walter, #805318) +- comment out example.com examples in default krb5.conf (Stef Walter, #805320) + +* Fri Mar 9 2012 Nalin Dahyabhai 1.10.1-1 +- update to 1.10.1 + - drop the KDC crash fix + - drop the KDC lookaside cache fix + - drop the fix for kadmind RPC ACLs (CVE-2012-1012) + +* Wed Mar 7 2012 Nalin Dahyabhai 1.10-5 +- when removing -workstation, remove our files from the info index while + the file is still there, in %%preun, rather than %%postun, and use the + compressed file's name (#801035) + +* Tue Feb 21 2012 Nathaniel McCallum - 1.10-4 +- Fix string RPC ACLs (RT#7093); CVE-2012-1012 + +* Tue Jan 31 2012 Nathaniel McCallum - 1.10-3 +- Add upstream lookaside cache behavior fix (RT#7082) + +* Mon Jan 30 2012 Nalin Dahyabhai 1.10-2 +- add patch to accept keytab entries with vno==0 as matches when we're + searching for an entry with a specific name/kvno (#230382/#782211,RT#3349) + +* Mon Jan 30 2012 Nalin Dahyabhai 1.10-1 +- update to 1.10 final + +* Thu Jan 26 2012 Nathaniel McCallum - 1.10-0.beta1.2 +- Add upstream crashfix patch (RT#7081) + +* Thu Jan 12 2012 Nalin Dahyabhai 1.10-0.beta1.1 +- update to beta 1 + +* Wed Jan 11 2012 Peter Robinson +- mktemp was long obsoleted by coreutils + +* Wed Jan 4 2012 Nalin Dahyabhai 1.10-0.alpha2.2 +- modify the deltat grammar to also tell gcc (4.7) to suppress + "maybe-uninitialized" warnings in addition to the "uninitialized" warnings + it's already being told to suppress (RT#7080) + +* Tue Dec 20 2011 Nalin Dahyabhai 1.10-0.alpha2.1 +- update to alpha 2 +- drop a couple of patches which were integrated for alpha 2 + +* Tue Dec 13 2011 Nalin Dahyabhai 1.10-0.alpha1.3 +- pull in patch for RT#7046: tag a ccache containing credentials obtained via + S4U2Proxy with the principal name of the proxying principal (part of #761317) + so that the default principal name can be set to that of the client for which + it is proxying, which results in the ccache looking more normal to consumers + of the ccache that don't care that there's proxying going on +- pull in patch for RT#7047: allow tickets obtained via S4U2Proxy to be cached + (more of #761317) +- pull in patch for RT#7048: allow PAC verification to only bother trying to + verify the signature with keys that it's given (still more of #761317) + +* Tue Dec 6 2011 Nalin Dahyabhai 1.10-0.alpha1.2 +- apply upstream patch to fix a null pointer dereference when processing + TGS requests (CVE-2011-1530, #753748) + +* Wed Nov 30 2011 Nalin Dahyabhai 1.10-0.alpha1.1 +- correct a bug in the fix for #754001 so that the file creation context is + consistently reset + +* Tue Nov 15 2011 Nalin Dahyabhai 1.10-0.alpha1.0 +- update to 1.10 alpha 1 +- on newer releases where we can assume NSS >= 3.13, configure PKINIT to build + using NSS +- on newer releases where we build PKINIT using NSS, configure libk5crypto to + build using NSS +- rename krb5-pkinit-openssl to krb5-pkinit on newer releases where we're + expecting to build PKINIT using NSS instead +- during %%check, run check in the library and kdc subdirectories, which + should be able to run inside of the build system without issue + +* Wed Oct 26 2011 Fedora Release Engineering - 1.9.1-19 +- Rebuilt for glibc bug#747377 + +* Tue Oct 18 2011 Nalin Dahyabhai 1.9.1-18 +- apply upstream patch to fix a null pointer dereference with the LDAP kdb + backend (CVE-2011-1527, #744125), an assertion failure with multiple kdb + backends (CVE-2011-1528), and a null pointer dereference with multiple kdb + backends (CVE-2011-1529) (#737711) + +* Thu Oct 13 2011 Nalin Dahyabhai 1.9.1-17 +- pull in patch from trunk to rename krb5int_pac_sign() to krb5_pac_sign() and + make it public (#745533) + +* Fri Oct 7 2011 Nalin Dahyabhai 1.9.1-16 +- kadmin.service: fix #723723 again +- kadmin.service,krb5kdc.service: remove optional use of $KRB5REALM in command + lines, because systemd parsing doesn't handle alternate value shell variable + syntax +- kprop.service: add missing Type=forking so that systemd doesn't assume simple +- kprop.service: expect the ACL configuration to be there, not absent +- handle a harder-to-trigger assertion failure that starts cropping up when we + exit the transmit loop on time (#739853) + +* Sun Oct 2 2011 Tom Callaway 1.9.1-15 +- hardcode pid file as option in krb5kdc.service + +* Fri Sep 30 2011 Tom Callaway 1.9.1-14 +- fix pid path in krb5kdc.service + +* Mon Sep 19 2011 Tom Callaway 1.9.1-13 +- convert to systemd + +* Tue Sep 6 2011 Nalin Dahyabhai 1.9.1-12 +- pull in upstream patch for RT#6952, confusion following referrals for + cross-realm auth (#734341) +- pull in build-time deps for the tests + +* Thu Sep 1 2011 Nalin Dahyabhai 1.9.1-11 +- switch to the upstream patch for #727829 + +* Wed Aug 31 2011 Nalin Dahyabhai 1.9.1-10 +- handle an assertion failure that starts cropping up when the patch for + using poll (#701446) meets servers that aren't running KDCs or against + which the connection fails for other reasons (#727829, #734172) + +* Mon Aug 8 2011 Nalin Dahyabhai 1.9.1-9 +- override the default build rules to not delete temporary y.tab.c files, + so that they can be packaged, allowing debuginfo files which point to them + do so usefully (#729044) + +* Fri Jul 22 2011 Nalin Dahyabhai 1.9.1-8 +- build shared libraries with partial RELRO support (#723995) +- filter out potentially multiple instances of -Wl,-z,relro from krb5-config + output, now that it's in the buildroot's default LDFLAGS +- pull in a patch to fix losing track of the replay cache FD, from SVN by + way of Kevin Coffman + +* Wed Jul 20 2011 Nalin Dahyabhai 1.9.1-7 +- kadmind.init: drop the attempt to detect no-database-present errors (#723723), + which is too fragile in cases where the database has been manually moved or + is accessed through another kdb plugin + +* Tue Jul 19 2011 Nalin Dahyabhai 1.9.1-6 +- backport fixes to teach libkrb5 to use descriptors higher than FD_SETSIZE + to talk to a KDC by using poll() if it's detected at compile-time (#701446, + RT#6905) + +* Thu Jun 23 2011 Nalin Dahyabhai 1.9.1-5 +- pull a fix from SVN to try to avoid triggering a PTR lookup in getaddrinfo() + during krb5_sname_to_principal(), and to let getaddrinfo() decide whether or + not to ask for an IPv6 address based on the set of configured interfaces + (#717378, RT#6922) +- pull a fix from SVN to use AI_ADDRCONFIG more often (RT#6923) + +* Mon Jun 20 2011 Nalin Dahyabhai 1.9.1-4 +- apply upstream patch by way of Burt Holzman to fall back to a non-referral + method in cases where we might be derailed by a KDC that rejects the + canonicalize option (for example, those from the RHEL 2.1 or 3 era) (#715074) + +* Tue Jun 14 2011 Nalin Dahyabhai 1.9.1-3 +- pull a fix from SVN to get libgssrpc clients (e.g. kadmin) authenticating + using the old protocol over IPv4 again (RT#6920) + +* Tue Jun 14 2011 Nalin Dahyabhai +- incorporate a fix to teach the file labeling bits about when replay caches + are expunged (#576093) + +* Thu May 26 2011 Nalin Dahyabhai +- switch to the upstream patch for #707145 + +* Wed May 25 2011 Nalin Dahyabhai 1.9.1-2 +- klist: don't trip over referral entries when invoked with -s (#707145, + RT#6915) + +* Fri May 6 2011 Nalin Dahyabhai +- fixup URL in a comment +- when built with NSS, require 3.12.10 rather than 3.12.9 + +* Thu May 5 2011 Nalin Dahyabhai 1.9.1-1 +- update to 1.9.1: + - drop no-longer-needed patches for CVE-2010-4022, CVE-2011-0281, + CVE-2011-0282, CVE-2011-0283, CVE-2011-0284, CVE-2011-0285 + +* Wed Apr 13 2011 Nalin Dahyabhai 1.9-9 +- kadmind: add upstream patch to fix free() on an invalid pointer (#696343, + MITKRB5-SA-2011-004, CVE-2011-0285) + +* Mon Apr 4 2011 Nalin Dahyabhai +- don't discard the error code from an error message received in response + to a change-password request (#658871, RT#6893) + +* Fri Apr 1 2011 Nalin Dahyabhai +- override INSTALL_SETUID at build-time so that ksu is installed into + the buildroot with the right permissions (part of #225974) + +* Fri Mar 18 2011 Nalin Dahyabhai 1.9-8 +- backport change from SVN to fix a computed-value-not-used warning in + kpropd (#684065) + +* Tue Mar 15 2011 Nalin Dahyabhai 1.9-7 +- turn off NSS as the backend for libk5crypto for now to work around its + DES string2key not working (#679012) +- add revised upstream patch to fix double-free in KDC while returning + typed-data with errors (MITKRB5-SA-2011-003, CVE-2011-0284, #674325) + +* Thu Feb 17 2011 Nalin Dahyabhai +- throw in a not-applied-by-default patch to try to make pkinit debugging + into a run-time boolean option named "pkinit_debug" + +* Wed Feb 16 2011 Nalin Dahyabhai 1.9-6 +- turn on NSS as the backend for libk5crypto, adding nss-devel as a build + dependency when that switch is flipped + +* Wed Feb 9 2011 Nalin Dahyabhai 1.9-5 +- krb5kdc init script: prototype some changes to do a quick spot-check + of the TGS and kadmind keys and warn if there aren't any non-weak keys + on file for them (to flush out parts of #651466) + +* Tue Feb 8 2011 Nalin Dahyabhai 1.9-4 +- add upstream patches to fix standalone kpropd exiting if the per-client + child process exits with an error (MITKRB5-SA-2011-001), a hang or crash + in the KDC when using the LDAP kdb backend, and an uninitialized pointer + use in the KDC (MITKRB5-SA-2011-002) (CVE-2010-4022, #664009, + CVE-2011-0281, #668719, CVE-2011-0282, #668726, CVE-2011-0283, #676126) + +* Mon Feb 07 2011 Fedora Release Engineering - 1.9-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Feb 7 2011 Nalin Dahyabhai +- fix a compile error in the SELinux labeling patch when -DDEBUG is used (Sumit + Bose) + +* Tue Feb 1 2011 Nalin Dahyabhai +- properly advertise that the kpropd init script now supports force-reload + (Zbysek Mraz, #630587) + +* Wed Jan 26 2011 Nalin Dahyabhai 1.9-2 +- pkinit: when verifying signed data, use the CMS APIs for better + interoperability (#636985, RT#6851) + +* Wed Dec 22 2010 Nalin Dahyabhai 1.9-1 +- update to 1.9 final + +* Mon Dec 20 2010 Nalin Dahyabhai 1.9-0.beta3.1 +- fix link flags and permissions on shared libraries (ausil) + +* Thu Dec 16 2010 Nalin Dahyabhai 1.9-0.beta3.0 +- update to 1.9 beta 3 + +* Mon Dec 6 2010 Nalin Dahyabhai 1.9-0.beta2.0 +- update to 1.9 beta 2 + +* Tue Nov 9 2010 Nalin Dahyabhai 1.9-0.beta1.1 +- drop not-needed-since-1.8 build dependency on rsh (ssorce) + +* Fri Nov 5 2010 Nalin Dahyabhai 1.9-0.beta1.0 +- start moving to 1.9 with beta 1 + - drop patches for RT#5755, RT#6762, RT#6774, RT#6775 + - drop no-longer-needed backport patch for #539423 + - drop no-longer-needed patch for CVE-2010-1322 +- if WITH_NSS is set, built with --with-crypto-impl=nss (requires NSS 3.12.9) + +* Tue Oct 5 2010 Nalin Dahyabhai 1.8.3-8 +- incorporate upstream patch to fix uninitialized pointer crash in the KDC's + authorization data handling (CVE-2010-1322, #636335) + +* Mon Oct 4 2010 Nalin Dahyabhai 1.8.3-7 +- rebuild + +* Mon Oct 4 2010 Nalin Dahyabhai 1.8.3-6 +- pull down patches from trunk to implement k5login_authoritative and + k5login_directory settings for krb5.conf (#539423) + +* Wed Sep 29 2010 jkeating - 1.8.3-5 +- Rebuilt for gcc bug 634757 + +* Wed Sep 15 2010 Nalin Dahyabhai 1.8.3-4 +- fix reading of keyUsage extensions when attempting to select pkinit client + certs (part of #629022, RT#6775) +- fix selection of pkinit client certs when one or more don't include a + subjectAltName extension (part of #629022, RT#6774) + +* Fri Sep 3 2010 Nalin Dahyabhai 1.8.3-3 +- build with -fstack-protector-all instead of the default -fstack-protector, + so that we add checking to more functions (i.e., all of them) (#629950) +- also link binaries with -Wl,-z,relro,-z,now (part of #629950) + +* Tue Aug 24 2010 Nalin Dahyabhai 1.8.3-2 +- fix a logic bug in computing key expiration times (RT#6762, #627022) + +* Wed Aug 4 2010 Nalin Dahyabhai 1.8.3-1 +- update to 1.8.3 + - drop backports of fixes for gss context expiration and error table + registration/deregistration mismatch + - drop patch for upstream #6750 + +* Wed Jul 7 2010 Nalin Dahyabhai 1.8.2-3 +- tell krb5kdc and kadmind to create pid files, since they can +- add logrotate configuration files for krb5kdc and kadmind (#462658) +- fix parsing of the pidfile option in the KDC (upstream #6750) + +* Mon Jun 21 2010 Nalin Dahyabhai 1.8.2-2 +- libgssapi: pull in patch from svn to stop returning context-expired errors + when the ticket which was used to set up the context expires (#605366, + upstream #6739) + +* Mon Jun 21 2010 Nalin Dahyabhai +- pull up fix for upstream #6745, in which the gssapi library would add the + wrong error table but subsequently attempt to unload the right one + +* Thu Jun 10 2010 Nalin Dahyabhai 1.8.2-1 +- update to 1.8.2 + - drop patches for CVE-2010-1320, CVE-2010-1321 + +* Tue Jun 1 2010 Nalin Dahyabhai 1.8.1-7 +- rebuild + +* Thu May 27 2010 Nalin Dahyabhai +- ksu: move session management calls to before we drop privileges, like + su does (#596887), and don't skip the PAM account check for root or the + same user (more of #540769) + +* Mon May 24 2010 Nalin Dahyabhai 1.8.1-6 +- make krb5-server-ldap also depend on the same version-release of krb5-libs, + as the other subpackages do, if only to make it clearer than it is when we + just do it through krb5-server +- drop explicit linking with libtinfo for applications that use libss, now + that readline itself links with libtinfo (as of readline-5.2-3, since + fedora 7 or so) +- go back to building without strict aliasing (compiler warnings in gssrpc) + +* Tue May 18 2010 Nalin Dahyabhai 1.8.1-5 +- add patch to correct GSSAPI library null pointer dereference which could be + triggered by malformed client requests (CVE-2010-1321, #582466) + +* Tue May 4 2010 Nalin Dahyabhai 1.8.1-4 +- fix output of kprop's init script's "status" and "reload" commands (#588222) + +* Tue Apr 20 2010 Nalin Dahyabhai 1.8.1-3 +- incorporate patch to fix double-free in the KDC (CVE-2010-1320, #581922) + +* Wed Apr 14 2010 Nalin Dahyabhai 1.8.1-2 +- fix a typo in kerberos.ldif + +* Fri Apr 9 2010 Nalin Dahyabhai 1.8.1-1 +- update to 1.8.1 + - no longer need patches for #555875, #561174, #563431, RT#6661, CVE-2010-0628 +- replace buildrequires on tetex-latex with one on texlive-latex, which is + the package that provides it now + +* Thu Apr 8 2010 Nalin Dahyabhai +- kdc.conf: no more need to suggest a v4 mode, or listening on the v4 port + +* Thu Apr 8 2010 Nalin Dahyabhai +- drop patch to suppress key expiration warnings sent from the KDC in + the last-req field, as the KDC is expected to just be configured to either + send them or not as a particular key approaches expiration (#556495) + +* Tue Mar 23 2010 Nalin Dahyabhai - 1.8-5 +- add upstream fix for denial-of-service in SPNEGO (CVE-2010-0628, #576325) +- kdc.conf: no more need to suggest keeping keys with v4-compatible salting + +* Fri Mar 19 2010 Nalin Dahyabhai - 1.8-4 +- remove the krb5-appl bits (the -workstation-clients and -workstation-servers + subpackages) now that krb5-appl is its own package +- replace our patch for #563431 (kpasswd doesn't fall back to guessing your + principal name using your user name if you don't have a ccache) with the + one upstream uses + +* Fri Mar 12 2010 Nalin Dahyabhai - 1.8-3 +- add documentation for the ticket_lifetime option (#561174) + +* Mon Mar 8 2010 Nalin Dahyabhai - 1.8-2 +- pull up patch to get the client libraries to correctly perform password + changes over IPv6 (Sumit Bose, RT#6661) + +* Fri Mar 5 2010 Nalin Dahyabhai - 1.8-1 +- update to 1.8 + - temporarily bundling the krb5-appl package (split upstream as of 1.8) + until its package review is complete + - profile.d scriptlets are now only needed by -workstation-clients + - adjust paths in init scripts + - drop upstreamed fix for KDC denial of service (CVE-2010-0283) + - drop patch to check the user's password correctly using crypt(), which + isn't a code path we hit when we're using PAM + +* Wed Mar 3 2010 Nalin Dahyabhai - 1.7.1-6 +- fix a null pointer dereference and crash introduced in our PAM patch that + would happen if ftpd was given the name of a user who wasn't known to the + local system, limited to being triggerable by gssapi-authenticated clients by + the default xinetd config (Olivier Fourdan, #569472) + +* Tue Mar 2 2010 Nalin Dahyabhai - 1.7.1-5 +- fix a regression (not labeling a kdb database lock file correctly, #569902) + +* Thu Feb 25 2010 Nalin Dahyabhai - 1.7.1-4 +- move the package changelog to the end to match the usual style (jdennis) +- scrub out references to $RPM_SOURCE_DIR (jdennis) +- include a symlink to the readme with the name LICENSE so that people can + find it more easily (jdennis) + +* Wed Feb 17 2010 Nalin Dahyabhai - 1.7.1-3 +- pull up the change to make kpasswd's behavior better match the docs + when there's no ccache (#563431) + +* Tue Feb 16 2010 Nalin Dahyabhai - 1.7.1-2 +- apply patch from upstream to fix KDC denial of service (CVE-2010-0283, + #566002) + +* Wed Feb 3 2010 Nalin Dahyabhai - 1.7.1-1 +- update to 1.7.1 + - don't trip AD lockout on wrong password (#542687, #554351) + - incorporates fixes for CVE-2009-4212 and CVE-2009-3295 + - fixes gss_krb5_copy_ccache() when SPNEGO is used +- move sim_client/sim_server, gss-client/gss-server, uuclient/uuserver to + the devel subpackage, better lining up with the expected krb5/krb5-appl + split in 1.8 +- drop kvno,kadmin,k5srvutil,ktutil from -workstation-servers, as it already + depends on -workstation which also includes them + +* Mon Jan 25 2010 Nalin Dahyabhai - 1.7-23 +- tighten up default permissions on kdc.conf and kadm5.acl (#558343) + +* Fri Jan 22 2010 Nalin Dahyabhai - 1.7-22 +- use portreserve correctly -- portrelease takes the basename of the file + whose entries should be released, so we need three files, not one + +* Mon Jan 18 2010 Nalin Dahyabhai - 1.7-21 +- suppress warnings of impending password expiration if expiration is more than + seven days away when the KDC reports it via the last-req field, just as we + already do when it reports expiration via the key-expiration field (#556495) +- link with libtinfo rather than libncurses, when we can, in future RHEL + +* Fri Jan 15 2010 Nalin Dahyabhai - 1.7-20 +- krb5_get_init_creds_password: check opte->flags instead of options->flags + when checking whether or not we get to use the prompter callback (#555875) + +* Thu Jan 14 2010 Nalin Dahyabhai - 1.7-19 +- use portreserve to make sure the KDC can always bind to the kerberos-iv + port, kpropd can always bind to the krb5_prop port, and that kadmind can + always bind to the kerberos-adm port (#555279) +- correct inadvertent use of macros in the changelog (rpmlint) + +* Tue Jan 12 2010 Nalin Dahyabhai - 1.7-18 +- add upstream patch for integer underflow during AES and RC4 decryption + (CVE-2009-4212), via Tom Yu (#545015) + +* Wed Jan 6 2010 Nalin Dahyabhai - 1.7-17 +- put the conditional back for the -devel subpackage +- back down to the earlier version of the patch for #551764; the backported + alternate version was incomplete + +* Tue Jan 5 2010 Nalin Dahyabhai - 1.7-16 +- use %%global instead of %%define +- pull up proposed patch for creating previously-not-there lock files for + kdb databases when 'kdb5_util' is called to 'load' (#551764) + +* Mon Jan 4 2010 Dennis Gregorovic +- fix conditional for future RHEL + +* Mon Jan 4 2010 Nalin Dahyabhai - 1.7-15 +- add upstream patch for KDC crash during referral processing (CVE-2009-3295), + via Tom Yu (#545002) + +* Mon Dec 21 2009 Nalin Dahyabhai - 1.7-14 +- refresh patch for #542868 from trunk + +* Thu Dec 10 2009 Nalin Dahyabhai +- move man pages that live in the -libs subpackage into the regular + %%{_mandir} tree where they'll still be found if that package is the + only one installed (#529319) + +* Wed Dec 9 2009 Nalin Dahyabhai - 1.7-13 +- and put it back in + +* Tue Dec 8 2009 Nalin Dahyabhai +- back that last change out + +* Tue Dec 8 2009 Nalin Dahyabhai - 1.7-12 +- try to make gss_krb5_copy_ccache() work correctly for spnego (#542868) + +* Fri Dec 4 2009 Nalin Dahyabhai +- make krb5-config suppress CFLAGS output when called with --libs (#544391) + +* Thu Dec 3 2009 Nalin Dahyabhai - 1.7-11 +- ksu: move account management checks to before we drop privileges, like + su does (#540769) +- selinux: set the user part of file creation contexts to match the current + context instead of what we looked up +- configure with --enable-dns-for-realm instead of --enable-dns, which isn't + recognized any more + +* Fri Nov 20 2009 Nalin Dahyabhai - 1.7-10 +- move /etc/pam.d/ksu from krb5-workstation-servers to krb5-workstation, + where it's actually needed (#538703) + +* Fri Oct 23 2009 Nalin Dahyabhai - 1.7-9 +- add some conditional logic to simplify building on older Fedora releases + +* Tue Oct 13 2009 Nalin Dahyabhai +- don't forget the README + +* Mon Sep 14 2009 Nalin Dahyabhai - 1.7-8 +- specify the location of the subsystem lock when using the status() function + in the kadmind and kpropd init scripts, so that we get the right error when + we're dead but have a lock file - requires initscripts 8.99 (#521772) + +* Tue Sep 8 2009 Nalin Dahyabhai +- if the init script fails to start krb5kdc/kadmind/kpropd because it's already + running (according to status()), return 0 (part of #521772) + +* Mon Aug 24 2009 Nalin Dahyabhai - 1.7-7 +- work around a compile problem with new openssl + +* Fri Aug 21 2009 Tomas Mraz - 1.7-6 +- rebuilt with new openssl + +* Fri Jul 24 2009 Fedora Release Engineering - 1.7-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Tue Jul 7 2009 Nalin Dahyabhai 1.7-5 +- rebuild to pick up the current forms of various patches + +* Mon Jul 6 2009 Nalin Dahyabhai +- simplify the man pages patch by only preprocessing the files we care about + and moving shared configure.in logic into a shared function +- catch the case of ftpd printing file sizes using %%i, when they might be + bigger than an int now + +* Tue Jun 30 2009 Nalin Dahyabhai 1.7-4 +- try to merge and clean up all the large file support for ftp and rcp + - ftpd no longer prints a negative length when sending a large file + from a 32-bit host + +* Tue Jun 30 2009 Nalin Dahyabhai +- pam_rhosts_auth.so's been gone, use pam_rhosts.so instead + +* Mon Jun 29 2009 Nalin Dahyabhai 1.7-3 +- switch buildrequires: and requires: on e2fsprogs-devel into + buildrequires: and requires: on libss-devel, libcom_err-devel, per + sandeen on fedora-devel-list + +* Fri Jun 26 2009 Nalin Dahyabhai +- fix a type mismatch in krb5_copy_error_message() +- ftp: fix some odd use of strlen() +- selinux labeling: use selabel_open() family of functions rather than + matchpathcon(), bail on it if attempting to get the mutex lock fails + +* Tue Jun 16 2009 Nalin Dahyabhai +- compile with %%{?_smp_mflags} (Steve Grubb) +- drop the bit where we munge part of the error table header, as it's not + needed any more + +* Fri Jun 5 2009 Nalin Dahyabhai 1.7-2 +- add and own %%{_libdir}/krb5/plugins/authdata + +* Thu Jun 4 2009 Nalin Dahyabhai 1.7-1 +- update to 1.7 + - no need to work around build issues with ASN1BUF_OMIT_INLINE_FUNCS + - configure recognizes --enable/--disable-pkinit now + - configure can take --disable-rpath now + - no more libdes425, krb524d, krb425.info + - kadmin/k5srvutil/ktutil are user commands now + - new kproplog + - FAST encrypted-challenge plugin is new +- drop static build logic +- drop pam_krb5-specific configuration from the default krb5.conf +- drop only-use-v5 flags being passed to various things started by xinetd +- put %%{krb5prefix}/sbin in everyone's path, too (#504525) + +* Tue May 19 2009 Nalin Dahyabhai 1.6.3-106 +- add an auth stack to ksu's PAM configuration so that pam_setcred() calls + won't just fail + +* Mon May 11 2009 Nalin Dahyabhai 1.6.3-105 +- make PAM support for ksu also set PAM_RUSER + +* Thu Apr 23 2009 Nalin Dahyabhai 1.6.3-104 +- extend PAM support to ksu: perform account and session management for the + target user +- pull up and merge James Leddy's changes to also set PAM_RHOST in PAM-aware + network-facing services + +* Tue Apr 21 2009 Nalin Dahyabhai 1.6.3-103 +- fix a typo in a ksu error message (Marek Mahut) +- "rev" works the way the test suite expects now, so don't disable tests + that use it + +* Mon Apr 20 2009 Nalin Dahyabhai 1.6.3-102 +- add LSB-style init script info + +* Fri Apr 17 2009 Nalin Dahyabhai +- explicitly run the pdf generation script using sh (part of #225974) + +* Tue Apr 7 2009 Nalin Dahyabhai 1.6.3-101 +- add patches for read overflow and null pointer dereference in the + implementation of the SPNEGO mechanism (CVE-2009-0844, CVE-2009-0845) +- add patch for attempt to free uninitialized pointer in libkrb5 + (CVE-2009-0846) +- add patch to fix length validation bug in libkrb5 (CVE-2009-0847) +- put the krb5-user .info file into just -workstation and not also + -workstation-clients + +* Mon Apr 6 2009 Nalin Dahyabhai 1.6.3-100 +- turn off krb4 support (it won't be part of the 1.7 release, but do it now) +- use triggeruns to properly shut down and disable krb524d when -server and + -workstation-servers gets upgraded, because it's gone now +- move the libraries to /%%{_lib}, but leave --libdir alone so that plugins + get installed and are searched for in the same locations (#473333) +- clean up buildprereq/prereqs, explicit mktemp requires, and add the + ldconfig for the -server-ldap subpackage (part of #225974) +- escape possible macros in the changelog (part of #225974) +- fixup summary texts (part of #225974) +- take the execute bit off of the protocol docs (part of #225974) +- unflag init scripts as configuration files (part of #225974) +- make the kpropd init script treat 'reload' as 'restart' (part of #225974) + +* Tue Mar 17 2009 Nalin Dahyabhai 1.6.3-19 +- libgssapi_krb5: backport fix for some errors which can occur when + we fail to set up the server half of a context (CVE-2009-0845) + +* Wed Feb 25 2009 Fedora Release Engineering - 1.6.3-18 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Fri Jan 16 2009 Nalin Dahyabhai 1.6.3-17 +- rebuild + +* Thu Sep 4 2008 Nalin Dahyabhai +- if we successfully change the user's password during an attempt to get + initial credentials, but then fail to get initial creds from a non-master + using the new password, retry against the master (#432334) + +* Tue Aug 5 2008 Tom "spot" Callaway 1.6.3-16 +- fix license tag + +* Wed Jul 16 2008 Nalin Dahyabhai +- clear fuzz out of patches, dropping a man page patch which is no longer + necessary +- quote %%{__cc} where needed because it includes whitespace now +- define ASN1BUF_OMIT_INLINE_FUNCS at compile-time (for now) to keep building + +* Fri Jul 11 2008 Nalin Dahyabhai 1.6.3-15 +- build with -fno-strict-aliasing, which is needed because the library + triggers these warnings +- don't forget to label principal database lock files +- fix the labeling patch so that it doesn't break bootstrapping + +* Sat Jun 14 2008 Tom "spot" Callaway 1.6.3-14 +- generate src/include/krb5/krb5.h before building +- fix conditional for sparcv9 + +* Wed Apr 16 2008 Nalin Dahyabhai 1.6.3-13 +- ftp: use the correct local filename during mget when the 'case' option is + enabled (#442713) + +* Fri Apr 4 2008 Nalin Dahyabhai 1.6.3-12 +- stop exporting kadmin keys to a keytab file when kadmind starts -- the + daemon's been able to use the database directly for a long long time now +- belatedly add aes128,aes256 to the default set of supported key types + +* Tue Apr 1 2008 Nalin Dahyabhai 1.6.3-11 +- libgssapi_krb5: properly export the acceptor subkey when creating a lucid + context (Kevin Coffman, via the nfs4 mailing list) + +* Tue Mar 18 2008 Nalin Dahyabhai 1.6.3-10 +- add fixes from MITKRB5-SA-2008-001 for use of null or dangling pointer + when v4 compatibility is enabled on the KDC (CVE-2008-0062, CVE-2008-0063, + #432620, #432621) +- add fixes from MITKRB5-SA-2008-002 for array out-of-bounds accesses when + high-numbered descriptors are used (CVE-2008-0947, #433596) +- add backport bug fix for an attempt to free non-heap memory in + libgssapi_krb5 (CVE-2007-5901, #415321) +- add backport bug fix for a double-free in out-of-memory situations in + libgssapi_krb5 (CVE-2007-5971, #415351) + +* Tue Mar 18 2008 Nalin Dahyabhai 1.6.3-9 +- rework file labeling patch to not depend on fragile preprocessor trickery, + in another attempt at fixing #428355 and friends + +* Tue Feb 26 2008 Nalin Dahyabhai 1.6.3-8 +- ftp: add patch to fix "runique on" case when globbing fixes applied +- stop adding a redundant but harmless call to initialize the gssapi internals + +* Mon Feb 25 2008 Nalin Dahyabhai +- add patch to suppress double-processing of /etc/krb5.conf when we build + with --sysconfdir=/etc, thereby suppressing double-logging (#231147) + +* Mon Feb 25 2008 Nalin Dahyabhai +- remove a patch, to fix problems with interfaces which are "up" but which + have no address assigned, which conflicted with a different fix for the same + problem in 1.5 (#200979) + +* Mon Feb 25 2008 Nalin Dahyabhai +- ftp: don't lose track of a descriptor on passive get when the server fails to + open a file + +* Mon Feb 25 2008 Nalin Dahyabhai +- in login, allow PAM to interact with the user when they've been strongly + authenticated +- in login, signal PAM when we're changing an expired password that it's an + expired password, so that when cracklib flags a password as being weak it's + treated as an error even if we're running as root + +* Mon Feb 18 2008 Nalin Dahyabhai 1.6.3-7 +- drop netdb patch +- kdb_ldap: add patch to treat 'nsAccountLock: true' as an indication that + the DISALLOW_ALL_TIX flag is set on an entry, for better interop with Fedora, + Netscape, Red Hat Directory Server (Simo Sorce) + +* Wed Feb 13 2008 Nalin Dahyabhai 1.6.3-6 +- patch to avoid depending on to define NI_MAXHOST and NI_MAXSERV + +* Tue Feb 12 2008 Nalin Dahyabhai 1.6.3-5 +- enable patch for key-expiration reporting +- enable patch to make kpasswd fall back to TCP if UDP fails (#251206) +- enable patch to make kpasswd use the right sequence number on retransmit +- enable patch to allow mech-specific creds delegated under spnego to be found + when searching for creds + +* Wed Jan 2 2008 Nalin Dahyabhai 1.6.3-4 +- some init script cleanups + - drop unquoted check and silent exit for "$NETWORKING" (#426852, #242502) + - krb524: don't barf on missing database if it looks like we're using kldap, + same as for kadmin + - return non-zero status for missing files which cause startup to + fail (#242502) + +* Tue Dec 18 2007 Nalin Dahyabhai 1.6.3-3 +- allocate space for the nul-terminator in the local pathname when looking up + a file context, and properly free a previous context (Jose Plans, #426085) + +* Wed Dec 5 2007 Nalin Dahyabhai 1.6.3-2 +- rebuild + +* Tue Oct 23 2007 Nalin Dahyabhai 1.6.3-1 +- update to 1.6.3, dropping now-integrated patches for CVE-2007-3999 + and CVE-2007-4000 (the new pkinit module is built conditionally and goes + into the -pkinit-openssl package, at least for now, to make a buildreq + loop with openssl avoidable) + +* Wed Oct 17 2007 Nalin Dahyabhai 1.6.2-10 +- make proper use of pam_loginuid and pam_selinux in rshd and ftpd + +* Fri Oct 12 2007 Nalin Dahyabhai +- make krb5.conf %%verify(not md5 size mtime) in addition to + %%config(noreplace), like /etc/nsswitch.conf (#329811) + +* Mon Oct 1 2007 Nalin Dahyabhai 1.6.2-9 +- apply the fix for CVE-2007-4000 instead of the experimental patch for + setting ok-as-delegate flags + +* Tue Sep 11 2007 Nalin Dahyabhai 1.6.2-8 +- move the db2 kdb plugin from -server to -libs, because a multilib libkdb + might need it + +* Tue Sep 11 2007 Nalin Dahyabhai 1.6.2-7 +- also perform PAM session and credential management when ftpd accepts a + client using strong authentication, missed earlier +- also label kadmind log files and files created by the db2 plugin + +* Thu Sep 6 2007 Nalin Dahyabhai 1.6.2-6 +- incorporate updated fix for CVE-2007-3999 (CVE-2007-4743) +- fix incorrect call to "test" in the kadmin init script (#252322,#287291) + +* Tue Sep 4 2007 Nalin Dahyabhai 1.6.2-5 +- incorporate fixes for MITKRB5-SA-2007-006 (CVE-2007-3999, CVE-2007-4000) + +* Sat Aug 25 2007 Nalin Dahyabhai 1.6.2-4 +- cover more cases in labeling files on creation +- add missing gawk build dependency + +* Thu Aug 23 2007 Nalin Dahyabhai 1.6.2-3 +- rebuild + +* Thu Jul 26 2007 Nalin Dahyabhai 1.6.2-2 +- kdc.conf: default to listening for TCP clients, too (#248415) + +* Thu Jul 19 2007 Nalin Dahyabhai 1.6.2-1 +- update to 1.6.2 +- add "buildrequires: texinfo-tex" to get texi2pdf + +* Wed Jun 27 2007 Nalin Dahyabhai 1.6.1-8 +- incorporate fixes for MITKRB5-SA-2007-004 (CVE-2007-2442,CVE-2007-2443) + and MITKRB5-SA-2007-005 (CVE-2007-2798) + +* Mon Jun 25 2007 Nalin Dahyabhai 1.6.1-7 +- reintroduce missing %%postun for the non-split_workstation case + +* Mon Jun 25 2007 Nalin Dahyabhai 1.6.1-6 +- rebuild + +* Mon Jun 25 2007 Nalin Dahyabhai 1.6.1-5.1 +- rebuild + +* Sun Jun 24 2007 Nalin Dahyabhai 1.6.1-5 +- add missing pam-devel build requirement, force selinux-or-fail build + +* Sun Jun 24 2007 Nalin Dahyabhai 1.6.1-4 +- rebuild + +* Sun Jun 24 2007 Nalin Dahyabhai 1.6.1-3 +- label all files at creation-time according to the SELinux policy (#228157) + +* Fri Jun 22 2007 Nalin Dahyabhai +- perform PAM account / session management in krshd (#182195,#195922) +- perform PAM authentication and account / session management in ftpd +- perform PAM authentication, account / session management, and password- + changing in login.krb5 (#182195,#195922) + +* Fri Jun 22 2007 Nalin Dahyabhai +- preprocess kerberos.ldif into a format FDS will like better, and include + that as a doc file as well + +* Fri Jun 22 2007 Nalin Dahyabhai +- switch man pages to being generated with the right paths in them +- drop old, incomplete SELinux patch +- add patch from Greg Hudson to make srvtab routines report missing-file errors + at same point that keytab routines do (#241805) + +* Thu May 24 2007 Nalin Dahyabhai 1.6.1-2 +- pull patch from svn to undo unintentional chattiness in ftp +- pull patch from svn to handle NULL krb5_get_init_creds_opt structures + better in a couple of places where they're expected + +* Wed May 23 2007 Nalin Dahyabhai 1.6.1-1 +- update to 1.6.1 + - drop no-longer-needed patches for CVE-2007-0956,CVE-2007-0957,CVE-2007-1216 + - drop patch for sendto bug in 1.6, fixed in 1.6.1 + +* Fri May 18 2007 Nalin Dahyabhai +- kadmind.init: don't fail outright if the default principal database + isn't there if it looks like we might be using the kldap plugin +- kadmind.init: attempt to extract the key for the host-specific kadmin + service when we try to create the keytab + +* Wed May 16 2007 Nalin Dahyabhai 1.6-6 +- omit dependent libraries from the krb5-config --libs output, as using + shared libraries (no more static libraries) makes them unnecessary and + they're not part of the libkrb5 interface (patch by Rex Dieter, #240220) + (strips out libkeyutils, libresolv, libdl) + +* Fri May 4 2007 Nalin Dahyabhai 1.6-5 +- pull in keyutils as a build requirement to get the "KEYRING:" ccache type, + because we've merged + +* Fri May 4 2007 Nalin Dahyabhai 1.6-4 +- fix an uninitialized length value which could cause a crash when parsing + key data coming from a directory server +- correct a typo in the krb5.conf man page ("ldap_server"->"ldap_servers") + +* Fri Apr 13 2007 Nalin Dahyabhai +- move the default acl_file, dict_file, and admin_keytab settings to + the part of the default/example kdc.conf where they'll actually have + an effect (#236417) + +* Thu Apr 5 2007 Nalin Dahyabhai 1.5-24 +- merge security fixes from RHSA-2007:0095 + +* Tue Apr 3 2007 Nalin Dahyabhai 1.6-3 +- add patch to correct unauthorized access via krb5-aware telnet + daemon (#229782, CVE-2007-0956) +- add patch to fix buffer overflow in krb5kdc and kadmind + (#231528, CVE-2007-0957) +- add patch to fix double-free in kadmind (#231537, CVE-2007-1216) + +* Thu Mar 22 2007 Nalin Dahyabhai +- back out buildrequires: keyutils-libs-devel for now + +* Thu Mar 22 2007 Nalin Dahyabhai 1.6-2 +- add buildrequires: on keyutils-libs-devel to enable use of keyring ccaches, + dragging keyutils-libs in as a dependency + +* Mon Mar 19 2007 Nalin Dahyabhai 1.5-23 +- fix bug ID in changelog + +* Thu Mar 15 2007 Nalin Dahyabhai 1.5-22 + +* Thu Mar 15 2007 Nalin Dahyabhai 1.5-21 +- add preliminary patch to fix buffer overflow in krb5kdc and kadmind + (#231528, CVE-2007-0957) +- add preliminary patch to fix double-free in kadmind (#231537, CVE-2007-1216) + +* Wed Feb 28 2007 Nalin Dahyabhai +- add patch to build semi-useful static libraries, but don't apply it unless + we need them + +* Tue Feb 27 2007 Nalin Dahyabhai - 1.5-20 +- temporarily back out %%post changes, fix for #143289 for security update +- add preliminary patch to correct unauthorized access via krb5-aware telnet + +* Mon Feb 19 2007 Nalin Dahyabhai +- make profile.d scriptlets mode 644 instead of 755 (part of #225974) + +* Tue Jan 30 2007 Nalin Dahyabhai 1.6-1 +- clean up quoting of command-line arguments passed to the krsh/krlogin + wrapper scripts + +* Mon Jan 22 2007 Nalin Dahyabhai +- initial update to 1.6, pre-package-reorg +- move workstation daemons to a new subpackage (#81836, #216356, #217301), and + make the new subpackage require xinetd (#211885) + +* Mon Jan 22 2007 Nalin Dahyabhai - 1.5-18 +- make use of install-info more failsafe (Ville Skyttä, #223704) +- preserve timestamps on shell scriptlets at %%install-time + +* Tue Jan 16 2007 Nalin Dahyabhai - 1.5-17 +- move to using pregenerated PDF docs to cure multilib conflicts (#222721) + +* Fri Jan 12 2007 Nalin Dahyabhai - 1.5-16 +- update backport of the preauth module interface (part of #194654) + +* Tue Jan 9 2007 Nalin Dahyabhai - 1.5-14 +- apply fixes from Tom Yu for MITKRB5-SA-2006-002 (CVE-2006-6143) (#218456) +- apply fixes from Tom Yu for MITKRB5-SA-2006-003 (CVE-2006-6144) (#218456) + +* Wed Dec 20 2006 Nalin Dahyabhai - 1.5-12 +- update backport of the preauth module interface + +* Mon Oct 30 2006 Nalin Dahyabhai +- update backport of the preauth module interface +- add proposed patches 4566, 4567 +- add proposed edata reporting interface for KDC +- add temporary placeholder for module global context fixes + +* Mon Oct 23 2006 Nalin Dahyabhai - 1.5-11 +- don't bail from the KDC init script if there's no database, it may be in + a different location than the default (fenlason) +- remove the [kdc] section from the default krb5.conf -- doesn't seem to have + been applicable for a while + +* Wed Oct 18 2006 Nalin Dahyabhai - 1.5-10 +- rename krb5.sh and krb5.csh so that they don't overlap (#210623) +- way-late application of added error info in kadmind.init (#65853) + +* Wed Oct 18 2006 Nalin Dahyabhai - 1.5-9.pal_18695 +- add backport of in-development preauth module interface (#208643) + +* Mon Oct 9 2006 Nalin Dahyabhai - 1.5-9 +- provide docs in PDF format instead of as tex source (Enrico Scholz, #209943) + +* Wed Oct 4 2006 Nalin Dahyabhai - 1.5-8 +- add missing shebang headers to krsh and krlogin wrapper scripts (#209238) + +* Wed Sep 6 2006 Nalin Dahyabhai - 1.5-7 +- set SS_LIB at configure-time so that libss-using apps get working readline + support (#197044) + +* Fri Aug 18 2006 Nalin Dahyabhai - 1.5-6 +- switch to the updated patch for MITKRB-SA-2006-001 + +* Tue Aug 8 2006 Nalin Dahyabhai - 1.5-5 +- apply patch to address MITKRB-SA-2006-001 (CVE-2006-3084) + +* Mon Aug 7 2006 Nalin Dahyabhai - 1.5-4 +- ensure that the gssapi library's been initialized before walking the + internal mechanism list in gss_release_oid(), needed if called from + gss_release_name() right after a gss_import_name() (#198092) + +* Tue Jul 25 2006 Nalin Dahyabhai - 1.5-3 +- rebuild + +* Tue Jul 25 2006 Nalin Dahyabhai - 1.5-2 +- pull up latest revision of patch to reduce lockups in rsh/rshd + +* Mon Jul 17 2006 Nalin Dahyabhai - 1.5-1.2 +- rebuild + +* Wed Jul 12 2006 Jesse Keating - 1.5-1.1 +- rebuild + +* Thu Jul 6 2006 Nalin Dahyabhai 1.5-1 +- build + +* Wed Jul 5 2006 Nalin Dahyabhai 1.5-0 +- update to 1.5 + +* Fri Jun 23 2006 Nalin Dahyabhai 1.4.3-9 +- mark profile.d config files noreplace (Laurent Rineau, #196447) + +* Thu Jun 8 2006 Nalin Dahyabhai 1.4.3-8 +- add buildprereq for autoconf + +* Mon May 22 2006 Nalin Dahyabhai 1.4.3-7 +- further munge krb5-config so that 'libdir=/usr/lib' is given even on 64-bit + architectures, to avoid multilib conflicts; other changes will conspire to + strip out the -L flag which uses this, so it should be harmless (#192692) + +* Fri Apr 28 2006 Nalin Dahyabhai 1.4.3-6 +- adjust the patch which removes the use of rpath to also produce a + krb5-config which is okay in multilib environments (#190118) +- make the name-of-the-tempfile comment which compile_et adds to error code + headers always list the same file to avoid conflicts on multilib installations +- strip SIZEOF_LONG out of krb5.h so that it doesn't conflict on multilib boxes +- strip GSS_SIZEOF_LONG out of gssapi.h so that it doesn't conflict on mulitlib + boxes + +* Fri Apr 14 2006 Stepan Kasal 1.4.3-5 +- Fix formatting typo in kinit.1 (krb5-kinit-man-typo.patch) + +* Fri Feb 10 2006 Jesse Keating 1.4.3-4.1 +- bump again for double-long bug on ppc(64) + +* Mon Feb 6 2006 Nalin Dahyabhai 1.4.3-4 +- give a little bit more information to the user when kinit gets the catch-all + I/O error (#180175) + +* Thu Jan 19 2006 Nalin Dahyabhai 1.4.3-3 +- rebuild properly when pthread_mutexattr_setrobust_np() is defined but not + declared, such as with recent glibc when _GNU_SOURCE isn't being used + +* Thu Jan 19 2006 Matthias Clasen 1.4.3-2 +- Use full paths in krb5.sh to avoid path lookups + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Thu Dec 1 2005 Nalin Dahyabhai +- login: don't truncate passwords before passing them into crypt(), in + case they're significant (#149476) + +* Thu Nov 17 2005 Nalin Dahyabhai 1.4.3-1 +- update to 1.4.3 +- make ksu setuid again (#137934, others) + +* Tue Sep 13 2005 Nalin Dahyabhai 1.4.2-4 +- mark %%{krb5prefix}/man so that files which are packaged within it are + flagged as %%doc (#168163) + +* Tue Sep 6 2005 Nalin Dahyabhai 1.4.2-3 +- add an xinetd configuration file for encryption-only telnetd, parallelling + the kshell/ekshell pair (#167535) + +* Wed Aug 31 2005 Nalin Dahyabhai 1.4.2-2 +- change the default configured encryption type for KDC databases to the + compiled-in default of des3-hmac-sha1 (#57847) + +* Thu Aug 11 2005 Nalin Dahyabhai 1.4.2-1 +- update to 1.4.2, incorporating the fixes for MIT-KRB5-SA-2005-002 and + MIT-KRB5-SA-2005-003 + +* Wed Jun 29 2005 Nalin Dahyabhai 1.4.1-6 +- rebuild + +* Wed Jun 29 2005 Nalin Dahyabhai 1.4.1-5 +- fix telnet client environment variable disclosure the same way NetKit's + telnet client did (CAN-2005-0488) (#159305) +- keep apps which call krb5_principal_compare() or krb5_realm_compare() with + malformed or NULL principal structures from crashing outright (Thomas Biege) + (#161475) + +* Tue Jun 28 2005 Nalin Dahyabhai +- apply fixes from draft of MIT-KRB5-SA-2005-002 (CAN-2005-1174,CAN-2005-1175) + (#157104) +- apply fixes from draft of MIT-KRB5-SA-2005-003 (CAN-2005-1689) (#159755) + +* Fri Jun 24 2005 Nalin Dahyabhai 1.4.1-4 +- fix double-close in keytab handling +- add port of fixes for CAN-2004-0175 to krb5-aware rcp (#151612) + +* Fri May 13 2005 Nalin Dahyabhai 1.4.1-3 +- prevent spurious EBADF in krshd when stdin is closed by the client while + the command is running (#151111) + +* Fri May 13 2005 Martin Stransky 1.4.1-2 +- add deadlock patch, removed old patch + +* Fri May 6 2005 Nalin Dahyabhai 1.4.1-1 +- update to 1.4.1, incorporating fixes for CAN-2005-0468 and CAN-2005-0469 +- when starting the KDC or kadmind, if KRB5REALM is set via the /etc/sysconfig + file for the service, pass it as an argument for the -r flag + +* Wed Mar 23 2005 Nalin Dahyabhai 1.4-3 +- drop krshd patch for now + +* Thu Mar 17 2005 Nalin Dahyabhai +- add draft fix from Tom Yu for slc_add_reply() buffer overflow (CAN-2005-0469) +- add draft fix from Tom Yu for env_opt_add() buffer overflow (CAN-2005-0468) + +* Wed Mar 16 2005 Nalin Dahyabhai 1.4-2 +- don't include into the telnet client when we're not using curses + +* Thu Feb 24 2005 Nalin Dahyabhai 1.4-1 +- update to 1.4 + - v1.4 kadmin client requires a v1.4 kadmind on the server, or use the "-O" + flag to specify that it should communicate with the server using the older + protocol + - new libkrb5support library + - v5passwdd and kadmind4 are gone + - versioned symbols +- pick up $KRB5KDC_ARGS from /etc/sysconfig/krb5kdc, if it exists, and pass + it on to krb5kdc +- pick up $KADMIND_ARGS from /etc/sysconfig/kadmin, if it exists, and pass + it on to kadmind +- pick up $KRB524D_ARGS from /etc/sysconfig/krb524, if it exists, and pass + it on to krb524d *instead of* "-m" +- set "forwardable" in [libdefaults] in the default krb5.conf to match the + default setting which we supply for pam_krb5 +- set a default of 24h for "ticket_lifetime" in [libdefaults], reflecting the + compiled-in default + +* Mon Dec 20 2004 Nalin Dahyabhai 1.3.6-3 +- rebuild + +* Mon Dec 20 2004 Nalin Dahyabhai 1.3.6-2 +- rebuild + +* Mon Dec 20 2004 Nalin Dahyabhai 1.3.6-1 +- update to 1.3.6, which includes the previous fix + +* Mon Dec 20 2004 Nalin Dahyabhai 1.3.5-8 +- apply fix from Tom Yu for MITKRB5-SA-2004-004 (CAN-2004-1189) + +* Fri Dec 17 2004 Martin Stransky 1.3.5-7 +- fix deadlock during file transfer via rsync/krsh +- thanks goes to James Antill for hint + +* Fri Nov 26 2004 Nalin Dahyabhai 1.3.5-6 +- rebuild + +* Mon Nov 22 2004 Nalin Dahyabhai 1.3.5-3 +- fix predictable-tempfile-name bug in krb5-send-pr (CAN-2004-0971, #140036) + +* Tue Nov 16 2004 Nalin Dahyabhai +- silence compiler warning in kprop by using an in-memory ccache with a fixed + name instead of an on-disk ccache with a name generated by tmpnam() + +* Tue Nov 16 2004 Nalin Dahyabhai 1.3.5-2 +- fix globbing patch port mode (#139075) + +* Mon Nov 1 2004 Nalin Dahyabhai 1.3.5-1 +- fix segfault in telnet due to incorrect checking of gethostbyname_r result + codes (#129059) + +* Fri Oct 15 2004 Nalin Dahyabhai +- remove rc4-hmac:norealm and rc4-hmac:onlyrealm from the default list of + supported keytypes in kdc.conf -- they produce exactly the same keys as + rc4-hmac:normal because rc4 string-to-key ignores salts +- nuke kdcrotate -- there are better ways to balance the load on KDCs, and + the SELinux policy for it would have been scary-looking +- update to 1.3.5, mainly to include MITKRB5SA 2004-002 and 2004-003 + +* Tue Aug 31 2004 Nalin Dahyabhai 1.3.4-7 +- rebuild + +* Tue Aug 24 2004 Nalin Dahyabhai 1.3.4-6 +- rebuild + +* Tue Aug 24 2004 Nalin Dahyabhai 1.3.4-5 +- incorporate revised fixes from Tom Yu for CAN-2004-0642, CAN-2004-0644, + CAN-2004-0772 + +* Mon Aug 23 2004 Nalin Dahyabhai 1.3.4-4 +- rebuild + +* Mon Aug 23 2004 Nalin Dahyabhai 1.3.4-3 +- incorporate fixes from Tom Yu for CAN-2004-0642, CAN-2004-0772 + (MITKRB5-SA-2004-002, #130732) +- incorporate fixes from Tom Yu for CAN-2004-0644 (MITKRB5-SA-2004-003, #130732) + +* Tue Jul 27 2004 Nalin Dahyabhai 1.3.4-2 +- fix indexing error in server sorting patch (#127336) + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Mon Jun 14 2004 Nalin Dahyabhai 1.3.4-0.1 +- update to 1.3.4 final + +* Mon Jun 7 2004 Nalin Dahyabhai 1.3.4-0 +- update to 1.3.4 beta1 +- remove MITKRB5-SA-2004-001, included in 1.3.4 + +* Mon Jun 7 2004 Nalin Dahyabhai 1.3.3-8 +- rebuild + +* Fri Jun 4 2004 Nalin Dahyabhai 1.3.3-7 +- rebuild + +* Fri Jun 4 2004 Nalin Dahyabhai 1.3.3-6 +- apply updated patch from MITKRB5-SA-2004-001 (revision 2004-06-02) + +* Tue Jun 1 2004 Nalin Dahyabhai 1.3.3-5 +- rebuild + +* Tue Jun 1 2004 Nalin Dahyabhai 1.3.3-4 +- apply patch from MITKRB5-SA-2004-001 (#125001) + +* Wed May 12 2004 Thomas Woerner 1.3.3-3 +- removed rpath + +* Thu Apr 15 2004 Nalin Dahyabhai 1.3.3-2 +- re-enable large file support, fell out in 1.3-1 +- patch rcp to use long long and %%lld format specifiers when reporting file + sizes on large files + +* Tue Apr 13 2004 Nalin Dahyabhai 1.3.3-1 +- update to 1.3.3 + +* Wed Mar 10 2004 Nalin Dahyabhai 1.3.2-1 +- update to 1.3.2 + +* Mon Mar 8 2004 Nalin Dahyabhai 1.3.1-12 +- rebuild + +* Tue Mar 02 2004 Elliot Lee 1.3.1-11.1 +- rebuilt + +* Fri Feb 13 2004 Elliot Lee 1.3.1-11 +- rebuilt + +* Mon Feb 9 2004 Nalin Dahyabhai 1.3.1-10 +- catch krb4 send_to_kdc cases in kdc preference patch + +* Mon Feb 2 2004 Nalin Dahyabhai 1.3.1-9 +- remove patch to set TERM in klogind which, combined with the upstream fix in + 1.3.1, actually produces the bug now (#114762) + +* Mon Jan 19 2004 Nalin Dahyabhai 1.3.1-8 +- when iterating over lists of interfaces which are "up" from getifaddrs(), + skip over those which have no address (#113347) + +* Mon Jan 12 2004 Nalin Dahyabhai +- prefer the kdc which last replied to a request when sending requests to kdcs + +* Mon Nov 24 2003 Nalin Dahyabhai 1.3.1-7 +- fix combination of --with-netlib and --enable-dns (#82176) + +* Tue Nov 18 2003 Nalin Dahyabhai +- remove libdefault ticket_lifetime option from the default krb5.conf, it is + ignored by libkrb5 + +* Thu Sep 25 2003 Nalin Dahyabhai 1.3.1-6 +- fix bug in patch to make rlogind start login with a clean environment a la + netkit rlogin, spotted and fixed by Scott McClung + +* Tue Sep 23 2003 Nalin Dahyabhai 1.3.1-5 +- include profile.d scriptlets in krb5-devel so that krb5-config will be in + the path if krb5-workstation isn't installed, reported by Kir Kolyshkin + +* Mon Sep 8 2003 Nalin Dahyabhai +- add more etypes (arcfour) to the default enctype list in kdc.conf +- don't apply previous patch, refused upstream + +* Fri Sep 5 2003 Nalin Dahyabhai 1.3.1-4 +- fix 32/64-bit bug storing and retrieving the issue_date in v4 credentials + +* Wed Sep 3 2003 Dan Walsh 1.3.1-3 +- Don't check for write access on /etc/krb5.conf if SELinux + +* Tue Aug 26 2003 Nalin Dahyabhai 1.3.1-2 +- fixup some int/pointer varargs wackiness + +* Tue Aug 5 2003 Nalin Dahyabhai 1.3.1-1 +- rebuild + +* Mon Aug 4 2003 Nalin Dahyabhai 1.3.1-0 +- update to 1.3.1 + +* Thu Jul 24 2003 Nalin Dahyabhai 1.3-2 +- pull fix for non-compliant encoding of salt field in etype-info2 preauth + data from 1.3.1 beta 1, until 1.3.1 is released. + +* Mon Jul 21 2003 Nalin Dahyabhai 1.3-1 +- update to 1.3 + +* Mon Jul 7 2003 Nalin Dahyabhai 1.2.8-4 +- correctly use stdargs + +* Wed Jun 18 2003 Nalin Dahyabhai 1.3-0.beta.4 +- test update to 1.3 beta 4 +- ditch statglue build option +- krb5-devel requires e2fsprogs-devel, which now provides libss and libcom_err + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Wed May 21 2003 Jeremy Katz 1.2.8-2 +- gcc 3.3 doesn't implement varargs.h, include stdarg.h instead + +* Wed Apr 9 2003 Nalin Dahyabhai 1.2.8-1 +- update to 1.2.8 + +* Mon Mar 31 2003 Nalin Dahyabhai 1.2.7-14 +- fix double-free of enc_part2 in krb524d + +* Fri Mar 21 2003 Nalin Dahyabhai 1.2.7-13 +- update to latest patch kit for MITKRB5-SA-2003-004 + +* Wed Mar 19 2003 Nalin Dahyabhai 1.2.7-12 +- add patch included in MITKRB5-SA-2003-003 (CAN-2003-0028) + +* Mon Mar 17 2003 Nalin Dahyabhai 1.2.7-11 +- add patches from patchkit from MITKRB5-SA-2003-004 (CAN-2003-0138 and + CAN-2003-0139) + +* Thu Mar 6 2003 Nalin Dahyabhai 1.2.7-10 +- rebuild + +* Thu Mar 6 2003 Nalin Dahyabhai 1.2.7-9 +- fix buffer underrun in unparsing certain principals (CAN-2003-0082) + +* Tue Feb 4 2003 Nalin Dahyabhai 1.2.7-8 +- add patch to document the reject-bad-transited option in kdc.conf + +* Mon Feb 3 2003 Nalin Dahyabhai +- add patch to fix server-side crashes when principals have no + components (CAN-2003-0072) + +* Thu Jan 23 2003 Nalin Dahyabhai 1.2.7-7 +- add patch from Mark Cox for exploitable bugs in ftp client + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Wed Jan 15 2003 Nalin Dahyabhai 1.2.7-5 +- use PICFLAGS when building code from the ktany patch + +* Thu Jan 9 2003 Bill Nottingham 1.2.7-4 +- debloat + +* Tue Jan 7 2003 Jeremy Katz 1.2.7-3 +- include .so.* symlinks as well as .so.*.* + +* Mon Dec 9 2002 Jakub Jelinek 1.2.7-2 +- always #include to access errno, never do it directly +- enable LFS on a bunch of other 32-bit arches + +* Wed Dec 4 2002 Nalin Dahyabhai +- increase the maximum name length allowed by kuserok() to the higher value + used in development versions + +* Mon Dec 2 2002 Nalin Dahyabhai +- install src/krb524/README as README.krb524 in the -servers package, + includes information about converting for AFS principals + +* Fri Nov 15 2002 Nalin Dahyabhai 1.2.7-1 +- update to 1.2.7 +- disable use of tcl + +* Mon Nov 11 2002 Nalin Dahyabhai +- update to 1.2.7-beta2 (internal only, not for release), dropping dnsparse + and kadmind4 fixes + +* Wed Oct 23 2002 Nalin Dahyabhai 1.2.6-5 +- add patch for buffer overflow in kadmind4 (not used by default) + +* Fri Oct 11 2002 Nalin Dahyabhai 1.2.6-4 +- drop a hunk from the dnsparse patch which is actually redundant (thanks to + Tom Yu) + +* Wed Oct 9 2002 Nalin Dahyabhai 1.2.6-3 +- patch to handle truncated dns responses + +* Mon Oct 7 2002 Nalin Dahyabhai 1.2.6-2 +- remove hashless key types from the default kdc.conf, they're not supposed to + be there, noted by Sam Hartman on krbdev + +* Fri Sep 27 2002 Nalin Dahyabhai 1.2.6-1 +- update to 1.2.6 + +* Fri Sep 13 2002 Nalin Dahyabhai 1.2.5-7 +- use %%{_lib} for the sake of multilib systems + +* Fri Aug 2 2002 Nalin Dahyabhai 1.2.5-6 +- add patch from Tom Yu for exploitable bugs in rpc code used in kadmind + +* Tue Jul 23 2002 Nalin Dahyabhai 1.2.5-5 +- fix bug in krb5.csh which would cause the path check to always succeed + +* Fri Jul 19 2002 Jakub Jelinek 1.2.5-4 +- build even libdb.a with -fPIC and $RPM_OPT_FLAGS. + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Sun May 26 2002 Tim Powers +- automated rebuild + +* Wed May 1 2002 Nalin Dahyabhai 1.2.5-1 +- update to 1.2.5 +- disable statglue + +* Fri Mar 1 2002 Nalin Dahyabhai 1.2.4-1 +- update to 1.2.4 + +* Wed Feb 20 2002 Nalin Dahyabhai 1.2.3-5 +- rebuild in new environment +- reenable statglue + +* Sat Jan 26 2002 Florian La Roche +- prereq chkconfig for the server subpackage + +* Wed Jan 16 2002 Nalin Dahyabhai 1.2.3-3 +- build without -g3, which gives us large static libraries in -devel + +* Tue Jan 15 2002 Nalin Dahyabhai 1.2.3-2 +- reintroduce ld.so.conf munging in the -libs %%post + +* Thu Jan 10 2002 Nalin Dahyabhai 1.2.3-1 +- rename the krb5 package back to krb5-libs; the previous rename caused + something of an uproar +- update to 1.2.3, which includes the FTP and telnetd fixes +- configure without --enable-dns-for-kdc --enable-dns-for-realm, which now set + the default behavior instead of enabling the feature (the feature is enabled + by --enable-dns, which we still use) +- reenable optimizations on Alpha +- support more encryption types in the default kdc.conf (heads-up from post + to comp.protocols.kerberos by Jason Heiss) + +* Fri Aug 3 2001 Nalin Dahyabhai 1.2.2-14 +- rename the krb5-libs package to krb5 (naming a subpackage -libs when there + is no main package is silly) +- move defaults for PAM to the appdefaults section of krb5.conf -- this is + the area where the krb5_appdefault_* functions look for settings) +- disable statglue (warning: breaks binary compatibility with previous + packages, but has to be broken at some point to work correctly with + unpatched versions built with newer versions of glibc) + +* Fri Aug 3 2001 Nalin Dahyabhai 1.2.2-13 +- bump release number and rebuild + +* Wed Aug 1 2001 Nalin Dahyabhai +- add patch to fix telnetd vulnerability + +* Fri Jul 20 2001 Nalin Dahyabhai +- tweak statglue.c to fix stat/stat64 aliasing problems +- be cleaner in use of gcc to build shlibs + +* Wed Jul 11 2001 Nalin Dahyabhai +- use gcc to build shared libraries + +* Wed Jun 27 2001 Nalin Dahyabhai +- add patch to support "ANY" keytab type (i.e., + "default_keytab_name = ANY:FILE:/etc/krb5.keytab,SRVTAB:/etc/srvtab" + patch from Gerald Britton, #42551) +- build with -D_FILE_OFFSET_BITS=64 to get large file I/O in ftpd (#30697) +- patch ftpd to use long long and %%lld format specifiers to support the SIZE + command on large files (also #30697) +- don't use LOG_AUTH as an option value when calling openlog() in ksu (#45965) +- implement reload in krb5kdc and kadmind init scripts (#41911) +- lose the krb5server init script (not using it any more) + +* Sun Jun 24 2001 Elliot Lee +- Bump release + rebuild. + +* Tue May 29 2001 Nalin Dahyabhai +- pass some structures by address instead of on the stack in krb5kdc + +* Tue May 22 2001 Nalin Dahyabhai +- rebuild in new environment + +* Thu Apr 26 2001 Nalin Dahyabhai +- add patch from Tom Yu to fix ftpd overflows (#37731) + +* Wed Apr 18 2001 Than Ngo +- disable optimizations on the alpha again + +* Fri Mar 30 2001 Nalin Dahyabhai +- add in glue code to make sure that libkrb5 continues to provide a + weak copy of stat() + +* Thu Mar 15 2001 Nalin Dahyabhai +- build alpha with -O0 for now + +* Thu Mar 8 2001 Nalin Dahyabhai +- fix the kpropd init script + +* Mon Mar 5 2001 Nalin Dahyabhai +- update to 1.2.2, which fixes some bugs relating to empty ETYPE-INFO +- re-enable optimization on Alpha + +* Thu Feb 8 2001 Nalin Dahyabhai +- build alpha with -O0 for now +- own %%{_var}/kerberos + +* Tue Feb 6 2001 Nalin Dahyabhai +- own the directories which are created for each package (#26342) + +* Tue Jan 23 2001 Nalin Dahyabhai +- gettextize init scripts + +* Fri Jan 19 2001 Nalin Dahyabhai +- add some comments to the ksu patches for the curious +- re-enable optimization on alphas + +* Mon Jan 15 2001 Nalin Dahyabhai +- fix krb5-send-pr (#18932) and move it from -server to -workstation +- buildprereq libtermcap-devel +- temporariliy disable optimization on alphas +- gettextize init scripts + +* Tue Dec 5 2000 Nalin Dahyabhai +- force -fPIC + +* Fri Dec 1 2000 Nalin Dahyabhai +- rebuild in new environment + +* Tue Oct 31 2000 Nalin Dahyabhai +- add bison as a BuildPrereq (#20091) + +* Mon Oct 30 2000 Nalin Dahyabhai +- change /usr/dict/words to /usr/share/dict/words in default kdc.conf (#20000) + +* Thu Oct 5 2000 Nalin Dahyabhai +- apply kpasswd bug fixes from David Wragg + +* Wed Oct 4 2000 Nalin Dahyabhai +- make krb5-libs obsolete the old krb5-configs package (#18351) +- don't quit from the kpropd init script if there's no principal database so + that you can propagate the first time without running kpropd manually +- don't complain if /etc/ld.so.conf doesn't exist in the -libs %%post + +* Tue Sep 12 2000 Nalin Dahyabhai +- fix credential forwarding problem in klogind (goof in KRB5CCNAME handling) + (#11588) +- fix heap corruption bug in FTP client (#14301) + +* Wed Aug 16 2000 Nalin Dahyabhai +- fix summaries and descriptions +- switched the default transfer protocol from PORT to PASV as proposed on + bugzilla (#16134), and to match the regular ftp package's behavior + +* Wed Jul 19 2000 Jeff Johnson +- rebuild to compress man pages. + +* Sat Jul 15 2000 Bill Nottingham +- move initscript back + +* Fri Jul 14 2000 Nalin Dahyabhai +- disable servers by default to keep linuxconf from thinking they need to be + started when they don't + +* Thu Jul 13 2000 Prospector +- automatic rebuild + +* Mon Jul 10 2000 Nalin Dahyabhai +- change cleanup code in post to not tickle chkconfig +- add grep as a Prereq: for -libs + +* Thu Jul 6 2000 Nalin Dahyabhai +- move condrestarts to postun +- make xinetd configs noreplace +- add descriptions to xinetd configs +- add /etc/init.d as a prereq for the -server package +- patch to properly truncate $TERM in krlogind + +* Fri Jun 30 2000 Nalin Dahyabhai +- update to 1.2.1 +- back out Tom Yu's patch, which is a big chunk of the 1.2 -> 1.2.1 update +- start using the official source tarball instead of its contents + +* Thu Jun 29 2000 Nalin Dahyabhai +- Tom Yu's patch to fix compatibility between 1.2 kadmin and 1.1.1 kadmind +- pull out 6.2 options in the spec file (sonames changing in 1.2 means it's not + compatible with other stuff in 6.2, so no need) + +* Wed Jun 28 2000 Nalin Dahyabhai +- tweak graceful start/stop logic in post and preun + +* Mon Jun 26 2000 Nalin Dahyabhai +- update to the 1.2 release +- ditch a lot of our patches which went upstream +- enable use of DNS to look up things at build-time +- disable use of DNS to look up things at run-time in default krb5.conf +- change ownership of the convert-config-files script to root.root +- compress PS docs +- fix some typos in the kinit man page +- run condrestart in server post, and shut down in preun + +* Mon Jun 19 2000 Nalin Dahyabhai +- only remove old krb5server init script links if the init script is there + +* Sat Jun 17 2000 Nalin Dahyabhai +- disable kshell and eklogin by default + +* Thu Jun 15 2000 Nalin Dahyabhai +- patch mkdir/rmdir problem in ftpcmd.y +- add condrestart option to init script +- split the server init script into three pieces and add one for kpropd + +* Wed Jun 14 2000 Nalin Dahyabhai +- make sure workstation servers are all disabled by default +- clean up krb5server init script + +* Fri Jun 9 2000 Nalin Dahyabhai +- apply second set of buffer overflow fixes from Tom Yu +- fix from Dirk Husung for a bug in buffer cleanups in the test suite +- work around possibly broken rev binary in running test suite +- move default realm configs from /var/kerberos to %%{_var}/kerberos + +* Tue Jun 6 2000 Nalin Dahyabhai +- make ksu and v4rcp owned by root + +* Sat Jun 3 2000 Nalin Dahyabhai +- use %%{_infodir} to better comply with FHS +- move .so files to -devel subpackage +- tweak xinetd config files (bugs #11833, #11835, #11836, #11840) +- fix package descriptions again + +* Wed May 24 2000 Nalin Dahyabhai +- change a LINE_MAX to 1024, fix from Ken Raeburn +- add fix for login vulnerability in case anyone rebuilds without krb4 compat +- add tweaks for byte-swapping macros in krb.h, also from Ken +- add xinetd config files +- make rsh and rlogin quieter +- build with debug to fix credential forwarding +- add rsh as a build-time req because the configure scripts look for it to + determine paths + +* Wed May 17 2000 Nalin Dahyabhai +- fix config_subpackage logic + +* Tue May 16 2000 Nalin Dahyabhai +- remove setuid bit on v4rcp and ksu in case the checks previously added + don't close all of the problems in ksu +- apply patches from Jeffrey Schiller to fix overruns Chris Evans found +- reintroduce configs subpackage for use in the errata +- add PreReq: sh-utils + +* Mon May 15 2000 Nalin Dahyabhai +- fix double-free in the kdc (patch merged into MIT tree) +- include convert-config-files script as a documentation file + +* Wed May 03 2000 Nalin Dahyabhai +- patch ksu man page because the -C option never works +- add access() checks and disable debug mode in ksu +- modify default ksu build arguments to specify more directories in CMD_PATH + and to use getusershell() + +* Wed May 03 2000 Bill Nottingham +- fix configure stuff for ia64 + +* Mon Apr 10 2000 Nalin Dahyabhai +- add LDCOMBINE=-lc to configure invocation to use libc versioning (bug #10653) +- change Requires: for/in subpackages to include %%{version} + +* Wed Apr 05 2000 Nalin Dahyabhai +- add man pages for kerberos(1), kvno(1), .k5login(5) +- add kvno to -workstation + +* Mon Apr 03 2000 Nalin Dahyabhai +- Merge krb5-configs back into krb5-libs. The krb5.conf file is marked as + a %%config file anyway. +- Make krb5.conf a noreplace config file. + +* Thu Mar 30 2000 Nalin Dahyabhai +- Make klogind pass a clean environment to children, like NetKit's rlogind does. + +* Wed Mar 08 2000 Nalin Dahyabhai +- Don't enable the server by default. +- Compress info pages. +- Add defaults for the PAM module to krb5.conf + +* Mon Mar 06 2000 Nalin Dahyabhai +- Correct copyright: it's exportable now, provided the proper paperwork is + filed with the government. + +* Fri Mar 03 2000 Nalin Dahyabhai +- apply Mike Friedman's patch to fix format string problems +- don't strip off argv[0] when invoking regular rsh/rlogin + +* Thu Mar 02 2000 Nalin Dahyabhai +- run kadmin.local correctly at startup + +* Mon Feb 28 2000 Nalin Dahyabhai +- pass absolute path to kadm5.keytab if/when extracting keys at startup + +* Sat Feb 19 2000 Nalin Dahyabhai +- fix info page insertions + +* Wed Feb 9 2000 Nalin Dahyabhai +- tweak server init script to automatically extract kadm5 keys if + /var/kerberos/krb5kdc/kadm5.keytab doesn't exist yet +- adjust package descriptions + +* Thu Feb 3 2000 Nalin Dahyabhai +- fix for potentially gzipped man pages + +* Fri Jan 21 2000 Nalin Dahyabhai +- fix comments in krb5-configs + +* Fri Jan 7 2000 Nalin Dahyabhai +- move /usr/kerberos/bin to end of PATH + +* Tue Dec 28 1999 Nalin Dahyabhai +- install kadmin header files + +* Tue Dec 21 1999 Nalin Dahyabhai +- patch around TIOCGTLC defined on alpha and remove warnings from libpty.h +- add installation of info docs +- remove krb4 compat patch because it doesn't fix workstation-side servers + +* Mon Dec 20 1999 Nalin Dahyabhai +- remove hesiod dependency at build-time + +* Sun Dec 19 1999 Nalin Dahyabhai +- rebuild on 1.1.1 + +* Thu Oct 7 1999 Nalin Dahyabhai +- clean up init script for server, verify that it works [jlkatz] +- clean up rotation script so that rc likes it better +- add clean stanza + +* Mon Oct 4 1999 Nalin Dahyabhai +- backed out ncurses and makeshlib patches +- update for krb5-1.1 +- add KDC rotation to rc.boot, based on ideas from Michael's C version + +* Mon Sep 27 1999 Nalin Dahyabhai +- added -lncurses to telnet and telnetd makefiles + +* Mon Jul 5 1999 Nalin Dahyabhai +- added krb5.csh and krb5.sh to /etc/profile.d + +* Tue Jun 22 1999 Nalin Dahyabhai +- broke out configuration files + +* Mon Jun 14 1999 Nalin Dahyabhai +- fixed server package so that it works now + +* Sat May 15 1999 Nalin Dahyabhai +- started changelog (previous package from zedz.net) +- updated existing 1.0.5 RPM from Eos Linux to krb5 1.0.6 +- added --force to makeinfo commands to skip errors during build