From 4be1486ccbb292ac9efa259c4a1516fd31ecf1cc Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Mar 05 2015 13:10:52 +0000 Subject: import krb5-1.12.2-14.el7 --- diff --git a/.gitignore b/.gitignore index ef7abd8..4f90bbf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -SOURCES/krb5-1.11.3-pdf.tar.xz -SOURCES/krb5-1.11.3.tar.gz -SOURCES/nss_wrapper-0.0-20130719153839Z.git6cb59864.bz2 +SOURCES/krb5-1.12.2-pdf.tar.xz +SOURCES/krb5-1.12.2.tar.gz +SOURCES/nss_wrapper-0.0-20140204195100.git3d58327.tar.xz +SOURCES/socket_wrapper-0.0-20140204194748.gitf3b2ece.tar.xz diff --git a/.krb5.metadata b/.krb5.metadata index 2369e1a..050653a 100644 --- a/.krb5.metadata +++ b/.krb5.metadata @@ -1,3 +1,4 @@ -ac6a2109eff848cf8ffac5b30e2b516ebe826a66 SOURCES/krb5-1.11.3-pdf.tar.xz -28a0a3d3a4a9837fb2a5124bc8aa81efb8fef1e5 SOURCES/krb5-1.11.3.tar.gz -a6c973b0658d244afdf12a39270227865ac13500 SOURCES/nss_wrapper-0.0-20130719153839Z.git6cb59864.bz2 +ad1f5d4fe9b90b4549e639050c278b176df85e0c SOURCES/krb5-1.12.2-pdf.tar.xz +6f24800d48d36a33305387a9b6340884b05573b1 SOURCES/krb5-1.12.2.tar.gz +7e2c80565c726a6be9a62615752196710e2e2faa SOURCES/nss_wrapper-0.0-20140204195100.git3d58327.tar.xz +ca7b62bd60d45817a059063bb0efd68cd1ecc889 SOURCES/socket_wrapper-0.0-20140204194748.gitf3b2ece.tar.xz diff --git a/SOURCES/0000-Refactor-cm-functions-in-sendto_kdc.c.patch b/SOURCES/0000-Refactor-cm-functions-in-sendto_kdc.c.patch new file mode 100644 index 0000000..ff332b1 --- /dev/null +++ b/SOURCES/0000-Refactor-cm-functions-in-sendto_kdc.c.patch @@ -0,0 +1,436 @@ +Tweaked a bit to apply to 1.12: +* krb5_int64 hadn't been replaced by int64_t yet. + +commit 346883c48f1b9e09b1af2cf73e3b96ee8f934072 +Author: Greg Hudson +Date: Wed Mar 26 13:21:45 2014 -0400 + + Refactor cm functions in sendto_kdc.c + + Move get_curtime_ms and the cm functions near the top of the file + right after structure definitions. Except for cm_select_or_poll, + define each cm function separately for poll and for select, since the + implementations don't share much in common. Instead of + cm_unset_write, define cm_read and cm_write functions to put an fd in + read-only or write-only state. Remove the ssflags argument from + cm_add_fd and just expect the caller to make a subsequent call to + cm_read or cm_write. Always select for exceptions when using select. + (Polling for exceptions is implicit with poll). + + With these changes, we no longer select/poll for reading on a TCP + connection until we are done writing to it. So in service_tcp_fd, + remove the check for unexpected read events. + +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index e60a375..e773a0a 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -59,8 +59,7 @@ + + typedef krb5_int64 time_ms; + +-/* Since fd_set is large on some platforms (8K on AIX 5.2), this probably +- * shouldn't be allocated in automatic storage. */ ++/* This can be pretty large, so should not be stack-allocated. */ + struct select_state { + #ifdef USE_POLL + struct pollfd fds[MAX_POLLFDS]; +@@ -107,6 +106,183 @@ struct conn_state { + time_ms endtime; + }; + ++/* Get current time in milliseconds. */ ++static krb5_error_code ++get_curtime_ms(time_ms *time_out) ++{ ++ struct timeval tv; ++ ++ if (gettimeofday(&tv, 0)) ++ return errno; ++ *time_out = (time_ms)tv.tv_sec * 1000 + tv.tv_usec / 1000; ++ return 0; ++} ++ ++#ifdef USE_POLL ++ ++/* Find a pollfd in selstate by fd, or abort if we can't find it. */ ++static inline struct pollfd * ++find_pollfd(struct select_state *selstate, int fd) ++{ ++ int i; ++ ++ for (i = 0; i < selstate->nfds; i++) { ++ if (selstate->fds[i].fd == fd) ++ return &selstate->fds[i]; ++ } ++ abort(); ++} ++ ++static void ++cm_init_selstate(struct select_state *selstate) ++{ ++ selstate->nfds = 0; ++} ++ ++static krb5_boolean ++cm_add_fd(struct select_state *selstate, int fd) ++{ ++ if (selstate->nfds >= MAX_POLLFDS) ++ return FALSE; ++ selstate->fds[selstate->nfds].fd = fd; ++ selstate->fds[selstate->nfds].events = 0; ++ selstate->nfds++; ++ return TRUE; ++} ++ ++static void ++cm_remove_fd(struct select_state *selstate, int fd) ++{ ++ struct pollfd *pfd = find_pollfd(selstate, fd); ++ ++ *pfd = selstate->fds[selstate->nfds - 1]; ++ selstate->nfds--; ++} ++ ++/* Poll for reading (and not writing) on fd the next time we poll. */ ++static void ++cm_read(struct select_state *selstate, int fd) ++{ ++ find_pollfd(selstate, fd)->events = POLLIN; ++} ++ ++/* Poll for writing (and not reading) on fd the next time we poll. */ ++static void ++cm_write(struct select_state *selstate, int fd) ++{ ++ find_pollfd(selstate, fd)->events = POLLOUT; ++} ++ ++/* Get the output events for fd in the form of ssflags. */ ++static unsigned int ++cm_get_ssflags(struct select_state *selstate, int fd) ++{ ++ struct pollfd *pfd = find_pollfd(selstate, fd); ++ ++ return ((pfd->revents & POLLIN) ? SSF_READ : 0) | ++ ((pfd->revents & POLLOUT) ? SSF_WRITE : 0) | ++ ((pfd->revents & POLLERR) ? SSF_EXCEPTION : 0); ++} ++ ++#else /* not USE_POLL */ ++ ++static void ++cm_init_selstate(struct select_state *selstate) ++{ ++ selstate->nfds = 0; ++ selstate->max = 0; ++ FD_ZERO(&selstate->rfds); ++ FD_ZERO(&selstate->wfds); ++ FD_ZERO(&selstate->xfds); ++} ++ ++static krb5_boolean ++cm_add_fd(struct select_state *selstate, int fd) ++{ ++#ifndef _WIN32 /* On Windows FD_SETSIZE is a count, not a max value. */ ++ if (fd >= FD_SETSIZE) ++ return FALSE; ++#endif ++ FD_SET(fd, &selstate->xfds); ++ if (selstate->max <= fd) ++ selstate->max = fd + 1; ++ selstate->nfds++; ++ return TRUE; ++} ++ ++static void ++cm_remove_fd(struct select_state *selstate, int fd) ++{ ++ FD_CLR(fd, &selstate->rfds); ++ FD_CLR(fd, &selstate->wfds); ++ FD_CLR(fd, &selstate->xfds); ++ if (selstate->max == fd + 1) { ++ while (selstate->max > 0 && ++ !FD_ISSET(selstate->max - 1, &selstate->rfds) && ++ !FD_ISSET(selstate->max - 1, &selstate->wfds) && ++ !FD_ISSET(selstate->max - 1, &selstate->xfds)) ++ selstate->max--; ++ } ++ selstate->nfds--; ++} ++ ++/* Select for reading (and not writing) on fd the next time we select. */ ++static void ++cm_read(struct select_state *selstate, int fd) ++{ ++ FD_SET(fd, &selstate->rfds); ++ FD_CLR(fd, &selstate->wfds); ++} ++ ++/* Select for writing (and not reading) on fd the next time we select. */ ++static void ++cm_write(struct select_state *selstate, int fd) ++{ ++ FD_CLR(fd, &selstate->rfds); ++ FD_SET(fd, &selstate->wfds); ++} ++ ++/* Get the events for fd from selstate after a select. */ ++static unsigned int ++cm_get_ssflags(struct select_state *selstate, int fd) ++{ ++ return (FD_ISSET(fd, &selstate->rfds) ? SSF_READ : 0) | ++ (FD_ISSET(fd, &selstate->wfds) ? SSF_WRITE : 0) | ++ (FD_ISSET(fd, &selstate->xfds) ? SSF_EXCEPTION : 0); ++} ++ ++#endif /* not USE_POLL */ ++ ++static krb5_error_code ++cm_select_or_poll(const struct select_state *in, time_ms endtime, ++ struct select_state *out, int *sret) ++{ ++#ifndef USE_POLL ++ struct timeval tv; ++#endif ++ krb5_error_code retval; ++ time_ms curtime, interval; ++ ++ retval = get_curtime_ms(&curtime); ++ if (retval != 0) ++ return retval; ++ interval = (curtime < endtime) ? endtime - curtime : 0; ++ ++ /* We don't need a separate copy of the selstate for poll, but use one for ++ * consistency with how we use select. */ ++ *out = *in; ++ ++#ifdef USE_POLL ++ *sret = poll(out->fds, out->nfds, interval); ++#else ++ tv.tv_sec = interval / 1000; ++ tv.tv_usec = interval % 1000 * 1000; ++ *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, &tv); ++#endif ++ ++ return (*sret < 0) ? SOCKET_ERRNO : 0; ++} ++ + static int + in_addrlist(struct server_entry *entry, struct serverlist *list) + { +@@ -251,18 +427,6 @@ cleanup: + return retval; + } + +-/* Get current time in milliseconds. */ +-static krb5_error_code +-get_curtime_ms(time_ms *time_out) +-{ +- struct timeval tv; +- +- if (gettimeofday(&tv, 0)) +- return errno; +- *time_out = (time_ms)tv.tv_sec * 1000 + tv.tv_usec / 1000; +- return 0; +-} +- + /* + * Notes: + * +@@ -283,144 +447,6 @@ get_curtime_ms(time_ms *time_out) + * connections already in progress + */ + +-static void +-cm_init_selstate(struct select_state *selstate) +-{ +- selstate->nfds = 0; +-#ifndef USE_POLL +- selstate->max = 0; +- FD_ZERO(&selstate->rfds); +- FD_ZERO(&selstate->wfds); +- FD_ZERO(&selstate->xfds); +-#endif +-} +- +-static krb5_boolean +-cm_add_fd(struct select_state *selstate, int fd, unsigned int ssflags) +-{ +-#ifdef USE_POLL +- if (selstate->nfds >= MAX_POLLFDS) +- return FALSE; +- selstate->fds[selstate->nfds].fd = fd; +- selstate->fds[selstate->nfds].events = 0; +- if (ssflags & SSF_READ) +- selstate->fds[selstate->nfds].events |= POLLIN; +- if (ssflags & SSF_WRITE) +- selstate->fds[selstate->nfds].events |= POLLOUT; +-#else +-#ifndef _WIN32 /* On Windows FD_SETSIZE is a count, not a max value. */ +- if (fd >= FD_SETSIZE) +- return FALSE; +-#endif +- if (ssflags & SSF_READ) +- FD_SET(fd, &selstate->rfds); +- if (ssflags & SSF_WRITE) +- FD_SET(fd, &selstate->wfds); +- if (ssflags & SSF_EXCEPTION) +- FD_SET(fd, &selstate->xfds); +- if (selstate->max <= fd) +- selstate->max = fd + 1; +-#endif +- selstate->nfds++; +- return TRUE; +-} +- +-static void +-cm_remove_fd(struct select_state *selstate, int fd) +-{ +-#ifdef USE_POLL +- int i; +- +- /* Find the FD in the array and move the last entry to its place. */ +- assert(selstate->nfds > 0); +- for (i = 0; i < selstate->nfds && selstate->fds[i].fd != fd; i++); +- assert(i < selstate->nfds); +- selstate->fds[i] = selstate->fds[selstate->nfds - 1]; +-#else +- FD_CLR(fd, &selstate->rfds); +- FD_CLR(fd, &selstate->wfds); +- FD_CLR(fd, &selstate->xfds); +- if (selstate->max == 1 + fd) { +- while (selstate->max > 0 +- && ! FD_ISSET(selstate->max-1, &selstate->rfds) +- && ! FD_ISSET(selstate->max-1, &selstate->wfds) +- && ! FD_ISSET(selstate->max-1, &selstate->xfds)) +- selstate->max--; +- } +-#endif +- selstate->nfds--; +-} +- +-static void +-cm_unset_write(struct select_state *selstate, int fd) +-{ +-#ifdef USE_POLL +- int i; +- +- for (i = 0; i < selstate->nfds && selstate->fds[i].fd != fd; i++); +- assert(i < selstate->nfds); +- selstate->fds[i].events &= ~POLLOUT; +-#else +- FD_CLR(fd, &selstate->wfds); +-#endif +-} +- +-static krb5_error_code +-cm_select_or_poll(const struct select_state *in, time_ms endtime, +- struct select_state *out, int *sret) +-{ +-#ifndef USE_POLL +- struct timeval tv; +-#endif +- krb5_error_code retval; +- time_ms curtime, interval; +- +- retval = get_curtime_ms(&curtime); +- if (retval != 0) +- return retval; +- interval = (curtime < endtime) ? endtime - curtime : 0; +- +- /* We don't need a separate copy of the selstate for poll, but use one for +- * consistency with how we use select. */ +- *out = *in; +- +-#ifdef USE_POLL +- *sret = poll(out->fds, out->nfds, interval); +-#else +- tv.tv_sec = interval / 1000; +- tv.tv_usec = interval % 1000 * 1000; +- *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, &tv); +-#endif +- +- return (*sret < 0) ? SOCKET_ERRNO : 0; +-} +- +-static unsigned int +-cm_get_ssflags(struct select_state *selstate, int fd) +-{ +- unsigned int ssflags = 0; +-#ifdef USE_POLL +- int i; +- +- for (i = 0; i < selstate->nfds && selstate->fds[i].fd != fd; i++); +- assert(i < selstate->nfds); +- if (selstate->fds[i].revents & POLLIN) +- ssflags |= SSF_READ; +- if (selstate->fds[i].revents & POLLOUT) +- ssflags |= SSF_WRITE; +- if (selstate->fds[i].revents & POLLERR) +- ssflags |= SSF_EXCEPTION; +-#else +- if (FD_ISSET(fd, &selstate->rfds)) +- ssflags |= SSF_READ; +- if (FD_ISSET(fd, &selstate->wfds)) +- ssflags |= SSF_WRITE; +- if (FD_ISSET(fd, &selstate->xfds)) +- ssflags |= SSF_EXCEPTION; +-#endif +- return ssflags; +-} +- + static int service_tcp_fd(krb5_context context, struct conn_state *conn, + struct select_state *selstate, int ssflags); + static int service_udp_fd(krb5_context context, struct conn_state *conn, +@@ -600,7 +626,6 @@ start_connection(krb5_context context, struct conn_state *state, + struct sendto_callback_info *callback_info) + { + int fd, e; +- unsigned int ssflags; + static const int one = 1; + static const struct linger lopt = { 0, 0 }; + +@@ -676,15 +701,17 @@ start_connection(krb5_context context, struct conn_state *state, + state->state = READING; + } + } +- ssflags = SSF_READ | SSF_EXCEPTION; +- if (state->state == CONNECTING || state->state == WRITING) +- ssflags |= SSF_WRITE; +- if (!cm_add_fd(selstate, state->fd, ssflags)) { ++ ++ if (!cm_add_fd(selstate, state->fd)) { + (void) closesocket(state->fd); + state->fd = INVALID_SOCKET; + state->state = FAILED; + return -1; + } ++ if (state->state == CONNECTING || state->state == WRITING) ++ cm_write(selstate, state->fd); ++ else ++ cm_read(selstate, state->fd); + + return 0; + } +@@ -768,9 +795,8 @@ service_tcp_fd(krb5_context context, struct conn_state *conn, + ssize_t nwritten, nread; + SOCKET_WRITEV_TEMP tmp; + +- /* Check for a socket exception or readable data before we expect it. */ +- if (ssflags & SSF_EXCEPTION || +- ((ssflags & SSF_READ) && conn->state != READING)) ++ /* Check for a socket exception. */ ++ if (ssflags & SSF_EXCEPTION) + goto kill_conn; + + switch (conn->state) { +@@ -810,7 +836,7 @@ service_tcp_fd(krb5_context context, struct conn_state *conn, + } + if (conn->x.out.sg_count == 0) { + /* Done writing, switch to reading. */ +- cm_unset_write(selstate, conn->fd); ++ cm_read(selstate, conn->fd); + conn->state = READING; + conn->x.in.bufsizebytes_read = 0; + conn->x.in.bufsize = 0; diff --git a/SOURCES/0000-ksu-intermediates.patch b/SOURCES/0000-ksu-intermediates.patch deleted file mode 100644 index d567116..0000000 --- a/SOURCES/0000-ksu-intermediates.patch +++ /dev/null @@ -1,13 +0,0 @@ -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-leak-the-creds-we-don-t-plan-to-copy-over.patch b/SOURCES/0001-Don-t-leak-the-creds-we-don-t-plan-to-copy-over.patch deleted file mode 100644 index 9e5757a..0000000 --- a/SOURCES/0001-Don-t-leak-the-creds-we-don-t-plan-to-copy-over.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 5733669cb88800f0e24c53b12a09034bbf342442 Mon Sep 17 00:00:00 2001 -From: Nalin Dahyabhai -Date: Mon, 17 Feb 2014 17:14:20 -0500 -Subject: [PATCH 1/4] Don't leak the creds we don't plan to copy over - ---- - src/lib/krb5/krb/vfy_increds.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/lib/krb5/krb/vfy_increds.c b/src/lib/krb5/krb/vfy_increds.c -index e88a37f..4833992 100644 ---- a/src/lib/krb5/krb/vfy_increds.c -+++ b/src/lib/krb5/krb/vfy_increds.c -@@ -69,9 +69,9 @@ copy_creds_except(krb5_context context, krb5_ccache incc, - - while (!(ret = krb5_cc_next_cred(context, incc, &cur, &creds))) { - if (krb5_principal_compare(context, princ, creds.server)) -- continue; -- -- ret = krb5_cc_store_cred(context, outcc, &creds); -+ ret = 0; -+ else -+ ret = krb5_cc_store_cred(context, outcc, &creds); - krb5_free_cred_contents(context, &creds); - if (ret) - goto cleanup; --- -1.9.0 - 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 deleted file mode 100644 index b3153c8..0000000 --- a/SOURCES/0001-Don-t-try-to-stat-not-on-disk-ccache-residuals.patch +++ /dev/null @@ -1,316 +0,0 @@ -From a787aa8259e44a3aec5b03ff9773c9ea4f4bc7f5 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/heuristic.c | 13 ++----- - src/clients/ksu/ksu.h | 6 ++++ - src/clients/ksu/main.c | 17 +++++---- - 4 files changed, 70 insertions(+), 54 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/heuristic.c b/src/clients/ksu/heuristic.c -index c7e691c..bfde451 100644 ---- a/src/clients/ksu/heuristic.c -+++ b/src/clients/ksu/heuristic.c -@@ -404,12 +404,8 @@ krb5_error_code find_either_ticket (context, cc, client, end_server, found) - krb5_principal kdc_server; - krb5_error_code retval; - krb5_boolean temp_found = FALSE; -- const char * cc_source_name; -- struct stat st_temp; - -- cc_source_name = krb5_cc_get_name(context, cc); -- -- if ( ! stat(cc_source_name, &st_temp)){ -+ if (krb5_ccache_is_initialized(context, cc)) { - - retval = find_ticket(context, cc, client, end_server, &temp_found); - if (retval) -@@ -546,7 +542,6 @@ krb5_error_code get_best_princ_for_target(context, source_uid, target_uid, - { - - princ_info princ_trials[10]; -- const char * cc_source_name; - krb5_principal cc_def_princ = NULL; - krb5_principal temp_client; - krb5_principal target_client; -@@ -558,7 +553,6 @@ krb5_error_code get_best_princ_for_target(context, source_uid, target_uid, - struct stat tb; - int count =0; - int i; -- struct stat st_temp; - - *path_out = 0; - -@@ -566,10 +560,7 @@ krb5_error_code get_best_princ_for_target(context, source_uid, target_uid, - if (options->princ) - return 0; - -- cc_source_name = krb5_cc_get_name(context, cc_source); -- -- -- if (! stat(cc_source_name, &st_temp)) { -+ if (krb5_ccache_is_initialized(context, cc_source)) { - retval = krb5_cc_get_principal(context, cc_source, &cc_def_princ); - if (retval) - return retval; -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/0001-In-ksu-merge-krb5_ccache_copy-and-_restricted.patch b/SOURCES/0001-In-ksu-merge-krb5_ccache_copy-and-_restricted.patch new file mode 100644 index 0000000..ac7baa1 --- /dev/null +++ b/SOURCES/0001-In-ksu-merge-krb5_ccache_copy-and-_restricted.patch @@ -0,0 +1,230 @@ +From 74e775ac6d937c9d22be4fc1d429e5e62705fb7d Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Thu, 24 Jul 2014 15:39:53 -0400 +Subject: [PATCH 1/7] In ksu, merge krb5_ccache_copy() and _restricted() + +Other than whether or not they limit the creds it stores to the new +ccache based on the principal name of the client for whom the creds were +issued, there's no meaningful difference between what these two +functions do. Merge them. +--- + src/clients/ksu/ccache.c | 106 ++++++----------------------------------------- + src/clients/ksu/ksu.h | 6 +-- + src/clients/ksu/main.c | 27 ++++-------- + 3 files changed, 22 insertions(+), 117 deletions(-) + +diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c +index 9916c75..118fc53 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, restrict_creds, cc_out, ++ stored, target_uid) + /* IN */ + krb5_context context; + krb5_ccache cc_def; + char *cc_other_tag; + krb5_principal primary_principal; ++ krb5_boolean restrict_creds; + uid_t target_uid; + /* OUT */ + krb5_ccache *cc_out; +@@ -83,9 +85,6 @@ 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)) + return EINVAL; + +@@ -98,8 +97,16 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, + return retval; + } + +- retval = krb5_store_all_creds(context, * cc_other, cc_def_creds_arr, +- cc_other_creds_arr); ++ if (restrict_creds) { ++ retval = krb5_store_some_creds(context, *cc_other, cc_def_creds_arr, ++ cc_other_creds_arr, primary_principal, ++ stored); ++ } else { ++ *stored = krb5_find_princ_in_cred_list(context, cc_def_creds_arr, ++ primary_principal); ++ retval = krb5_store_all_creds(context, *cc_other, cc_def_creds_arr, ++ cc_other_creds_arr); ++ } + + if (cc_def_creds_arr){ + while (cc_def_creds_arr[i]){ +@@ -623,93 +630,6 @@ krb5_error_code krb5_store_some_creds(context, cc, creds_def, creds_other, prst, + *stored = temp_stored; + return 0; + } +-/****************************************************************** +-krb5_cache_copy_restricted +- +-gets rid of any expired tickets in the secondary cache, +-copies the default cache into the secondary cache, +-only credentials that are for prst are copied. +- +-the algorithm may look a bit funny, +-but I had to do it this way, since cc_remove function did not come +-with k5 beta 3 release. +-************************************************************************/ +- +-krb5_error_code krb5_ccache_copy_restricted (context, cc_def, cc_other_tag, +- prst, cc_out, stored, target_uid) +- krb5_context context; +- krb5_ccache cc_def; +- char *cc_other_tag; +- krb5_principal prst; +- uid_t target_uid; +- /* OUT */ +- krb5_ccache *cc_out; +- krb5_boolean *stored; +-{ +- +- int i=0; +- krb5_ccache * cc_other; +- const char * cc_def_name; +- const char * cc_other_name; +- 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)); +- +- if ((retval = krb5_cc_resolve(context, cc_other_tag, cc_other))){ +- com_err(prog_name, retval, _("resolving ccache %s"), 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); +- +- if ( ! stat(cc_def_name, &st_temp)){ +- if((retval = krb5_get_nonexp_tkts(context,cc_def,&cc_def_creds_arr))){ +- return retval; +- } +- +- } +- +- if (!lstat( cc_other_name, &st_temp)) { +- return EINVAL; +- } +- +- if (krb5_seteuid(0)||krb5_seteuid(target_uid)) { +- return errno; +- } +- +- +- if ((retval = krb5_cc_initialize(context, *cc_other, prst))){ +- return retval; +- } +- +- retval = krb5_store_some_creds(context, * cc_other, +- cc_def_creds_arr, cc_other_creds_arr, prst, stored); +- +- +- +- if (cc_def_creds_arr){ +- while (cc_def_creds_arr[i]){ +- krb5_free_creds(context, cc_def_creds_arr[i]); +- i++; +- } +- } +- +- i=0; +- +- if(cc_other_creds_arr){ +- while (cc_other_creds_arr[i]){ +- krb5_free_creds(context, cc_other_creds_arr[i]); +- i++; +- } +- } +- +- *cc_out = *cc_other; +- return retval; +-} + + krb5_error_code krb5_ccache_filter (context, cc, prst) + krb5_context context; +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index f2c0811..9e0c613 100644 +--- a/src/clients/ksu/ksu.h ++++ b/src/clients/ksu/ksu.h +@@ -107,7 +107,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 **); +@@ -141,10 +141,6 @@ extern krb5_error_code krb5_store_some_creds + (krb5_context, krb5_ccache, krb5_creds **, krb5_creds **, + krb5_principal, krb5_boolean *); + +-extern krb5_error_code krb5_ccache_copy_restricted +-(krb5_context, krb5_ccache, char *, krb5_principal, +- krb5_ccache *, krb5_boolean *, uid_t); +- + extern krb5_error_code krb5_ccache_refresh + (krb5_context, krb5_ccache); + +diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c +index 233eb52..62f3bc0 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -117,6 +117,7 @@ main (argc, argv) + krb5_principal kdc_server; + krb5_boolean zero_password; + char * dir_of_cc_target; ++ krb5_boolean restrict_creds; + + options.opt = KRB5_DEFAULT_OPTIONS; + options.lifetime = KRB5_DEFAULT_TKT_LIFE; +@@ -464,25 +465,13 @@ main (argc, argv) + then only the credentials for that particular user + should be copied */ + +- 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))){ +- com_err(prog_name, retval, _("while copying cache %s to %s"), +- krb5_cc_get_name(ksu_context, cc_source), cc_target_tag); +- exit(1); +- } +- +- } else { +- if ((retval = krb5_ccache_copy(ksu_context, cc_source, cc_target_tag, +- client,&cc_target, &stored, target_uid))) { +- com_err(prog_name, retval, _("while copying cache %s to %s"), +- krb5_cc_get_name(ksu_context, cc_source), cc_target_tag); +- exit(1); +- } +- ++ restrict_creds = (source_uid == 0) && (target_uid != 0); ++ retval = krb5_ccache_copy(ksu_context, cc_source, cc_target_tag, client, ++ restrict_creds, &cc_target, &stored, target_uid); ++ if (retval) { ++ com_err(prog_name, retval, _("while copying cache %s to %s"), ++ krb5_cc_get_name(ksu_context, cc_source), cc_target_tag); ++ exit(1); + } + + /* Become root for authentication*/ +-- +2.0.4 + diff --git a/SOURCES/0001-Simplify-sendto_kdc.c.patch b/SOURCES/0001-Simplify-sendto_kdc.c.patch new file mode 100644 index 0000000..51c512d --- /dev/null +++ b/SOURCES/0001-Simplify-sendto_kdc.c.patch @@ -0,0 +1,421 @@ +From 42b3c2ed11c1e62c1691f868a6796983f93c3beb Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Wed, 9 Apr 2014 13:19:03 -0400 +Subject: [PATCH 01/13] Simplify sendto_kdc.c + +* Get rid of the "x" member of conn_state, which used to be a union + but hasn't been since r14742. +* Define a structure type for the "out" member of conn_state. +* Rename incoming_krb5_message to incoming_message for brevity. +* Make the "pos" member of incoming_message an offset instead of a + pointer, simplifying several present and future computations. +* Use "in" and "out" aliases to the conn_state in and out members + where it improves brevity. +* Rename set_conn_state_msg_length to set_transport_message and give + it a descriptive comment. +* Call set_transport_message from start_connection only, instead of + once in add_connection and perhaps again in start_connection. To + make this possible, pass the original message argument to maybe_send + and start_connection. +* Use make_data and empty_data helpers where appropriate. +--- + src/lib/krb5/os/sendto_kdc.c | 159 +++++++++++++++++++++---------------------- + 1 file changed, 79 insertions(+), 80 deletions(-) + +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index 67e2a60..5f781d3 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -76,30 +76,30 @@ static const char *const state_strings[] = { + + /* connection states */ + enum conn_states { INITIALIZING, CONNECTING, WRITING, READING, FAILED }; +-struct incoming_krb5_message { ++struct incoming_message { + size_t bufsizebytes_read; + size_t bufsize; ++ size_t pos; + char *buf; +- char *pos; + unsigned char bufsizebytes[4]; + size_t n_left; + }; + ++struct outgoing_message { ++ sg_buf sgbuf[2]; ++ sg_buf *sgp; ++ int sg_count; ++ unsigned char msg_len_buf[4]; ++}; ++ + struct conn_state { + SOCKET fd; + enum conn_states state; + int (*service)(krb5_context context, struct conn_state *, + struct select_state *, int); + struct remote_address addr; +- struct { +- struct { +- sg_buf sgbuf[2]; +- sg_buf *sgp; +- int sg_count; +- unsigned char msg_len_buf[4]; +- } out; +- struct incoming_krb5_message in; +- } x; ++ struct incoming_message in; ++ struct outgoing_message out; + krb5_data callback_buffer; + size_t server_index; + struct conn_state *next; +@@ -461,30 +461,31 @@ static int service_tcp_fd(krb5_context context, struct conn_state *conn, + static int service_udp_fd(krb5_context context, struct conn_state *conn, + struct select_state *selstate, int ssflags); + ++/* Set up the actual message we will send across the underlying transport to ++ * communicate the payload message, using one or both of state->out.sgbuf. */ + static void +-set_conn_state_msg_length (struct conn_state *state, const krb5_data *message) ++set_transport_message(struct conn_state *state, const krb5_data *message) + { +- if (!message || message->length == 0) ++ struct outgoing_message *out = &state->out; ++ ++ if (message == NULL || message->length == 0) + return; + + if (state->addr.type == SOCK_STREAM) { +- store_32_be(message->length, state->x.out.msg_len_buf); +- SG_SET(&state->x.out.sgbuf[0], state->x.out.msg_len_buf, 4); +- SG_SET(&state->x.out.sgbuf[1], message->data, message->length); +- state->x.out.sg_count = 2; +- ++ store_32_be(message->length, out->msg_len_buf); ++ SG_SET(&out->sgbuf[0], out->msg_len_buf, 4); ++ SG_SET(&out->sgbuf[1], message->data, message->length); ++ out->sg_count = 2; + } else { +- +- SG_SET(&state->x.out.sgbuf[0], message->data, message->length); +- SG_SET(&state->x.out.sgbuf[1], 0, 0); +- state->x.out.sg_count = 1; +- ++ SG_SET(&out->sgbuf[0], message->data, message->length); ++ SG_SET(&out->sgbuf[1], NULL, 0); ++ out->sg_count = 1; + } + } + + static krb5_error_code + add_connection(struct conn_state **conns, struct addrinfo *ai, +- size_t server_index, const krb5_data *message, char **udpbufp) ++ size_t server_index, char **udpbufp) + { + struct conn_state *state, **tailptr; + +@@ -492,28 +493,26 @@ add_connection(struct conn_state **conns, struct addrinfo *ai, + if (state == NULL) + return ENOMEM; + state->state = INITIALIZING; +- state->x.out.sgp = state->x.out.sgbuf; ++ state->out.sgp = state->out.sgbuf; + state->addr.type = ai->ai_socktype; + state->addr.family = ai->ai_family; + state->addr.len = ai->ai_addrlen; + memcpy(&state->addr.saddr, ai->ai_addr, ai->ai_addrlen); + state->fd = INVALID_SOCKET; + state->server_index = server_index; +- SG_SET(&state->x.out.sgbuf[1], 0, 0); ++ SG_SET(&state->out.sgbuf[1], NULL, 0); + if (ai->ai_socktype == SOCK_STREAM) { + state->service = service_tcp_fd; +- set_conn_state_msg_length (state, message); + } else { + state->service = service_udp_fd; +- set_conn_state_msg_length (state, message); + + if (*udpbufp == NULL) { + *udpbufp = malloc(MAX_DGRAM_SIZE); + if (*udpbufp == 0) + return ENOMEM; + } +- state->x.in.buf = *udpbufp; +- state->x.in.bufsize = MAX_DGRAM_SIZE; ++ state->in.buf = *udpbufp; ++ state->in.bufsize = MAX_DGRAM_SIZE; + } + + /* Chain the new state onto the tail of the list. */ +@@ -597,7 +596,7 @@ resolve_server(krb5_context context, const struct serverlist *servers, + ai.ai_family = entry->family; + ai.ai_addrlen = entry->addrlen; + ai.ai_addr = (struct sockaddr *)&entry->addr; +- return add_connection(conns, &ai, ind, message, udpbufp); ++ return add_connection(conns, &ai, ind, udpbufp); + } + + memset(&hint, 0, sizeof(hint)); +@@ -617,12 +616,12 @@ resolve_server(krb5_context context, const struct serverlist *servers, + /* Add each address with the preferred socktype. */ + retval = 0; + for (a = addrs; a != 0 && retval == 0; a = a->ai_next) +- retval = add_connection(conns, a, ind, message, udpbufp); ++ retval = add_connection(conns, a, ind, udpbufp); + if (retval == 0 && entry->socktype == 0 && socktype2 != 0) { + /* Add each address again with the non-preferred socktype. */ + for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { + a->ai_socktype = socktype2; +- retval = add_connection(conns, a, ind, message, udpbufp); ++ retval = add_connection(conns, a, ind, udpbufp); + } + } + freeaddrinfo(addrs); +@@ -631,7 +630,7 @@ resolve_server(krb5_context context, const struct serverlist *servers, + + static int + start_connection(krb5_context context, struct conn_state *state, +- struct select_state *selstate, ++ const krb5_data *message, struct select_state *selstate, + struct sendto_callback_info *callback_info) + { + int fd, e; +@@ -689,13 +688,14 @@ start_connection(krb5_context context, struct conn_state *state, + return -3; + } + +- set_conn_state_msg_length(state, &state->callback_buffer); ++ message = &state->callback_buffer; + } ++ set_transport_message(state, message); + + if (state->addr.type == SOCK_DGRAM) { + /* Send it now. */ + ssize_t ret; +- sg_buf *sg = &state->x.out.sgbuf[0]; ++ sg_buf *sg = &state->out.sgbuf[0]; + + TRACE_SENDTO_KDC_UDP_SEND_INITIAL(context, &state->addr); + ret = send(state->fd, SG_BUF(sg), SG_LEN(sg), 0); +@@ -731,14 +731,16 @@ start_connection(krb5_context context, struct conn_state *state, + next connection. */ + static int + maybe_send(krb5_context context, struct conn_state *conn, +- struct select_state *selstate, ++ const krb5_data *message, struct select_state *selstate, + struct sendto_callback_info *callback_info) + { + sg_buf *sg; + ssize_t ret; + +- if (conn->state == INITIALIZING) +- return start_connection(context, conn, selstate, callback_info); ++ if (conn->state == INITIALIZING) { ++ return start_connection(context, conn, message, selstate, ++ callback_info); ++ } + + /* Did we already shut down this channel? */ + if (conn->state == FAILED) { +@@ -752,7 +754,7 @@ maybe_send(krb5_context context, struct conn_state *conn, + } + + /* UDP - retransmit after a previous attempt timed out. */ +- sg = &conn->x.out.sgbuf[0]; ++ sg = &conn->out.sgbuf[0]; + TRACE_SENDTO_KDC_UDP_SEND_RETRY(context, &conn->addr); + ret = send(conn->fd, SG_BUF(sg), SG_LEN(sg), 0); + if (ret < 0 || (size_t) ret != SG_LEN(sg)) { +@@ -803,6 +805,8 @@ service_tcp_fd(krb5_context context, struct conn_state *conn, + int e = 0; + ssize_t nwritten, nread; + SOCKET_WRITEV_TEMP tmp; ++ struct incoming_message *in = &conn->in; ++ struct outgoing_message *out = &conn->out; + + /* Check for a socket exception. */ + if (ssflags & SSF_EXCEPTION) +@@ -825,68 +829,68 @@ service_tcp_fd(krb5_context context, struct conn_state *conn, + /* Fall through. */ + case WRITING: + TRACE_SENDTO_KDC_TCP_SEND(context, &conn->addr); +- nwritten = SOCKET_WRITEV(conn->fd, conn->x.out.sgp, +- conn->x.out.sg_count, tmp); ++ nwritten = SOCKET_WRITEV(conn->fd, out->sgp, out->sg_count, tmp); + if (nwritten < 0) { + TRACE_SENDTO_KDC_TCP_ERROR_SEND(context, &conn->addr, + SOCKET_ERRNO); + goto kill_conn; + } + while (nwritten) { +- sg_buf *sgp = conn->x.out.sgp; ++ sg_buf *sgp = out->sgp; + if ((size_t) nwritten < SG_LEN(sgp)) { + SG_ADVANCE(sgp, (size_t) nwritten); + nwritten = 0; + } else { + nwritten -= SG_LEN(sgp); +- conn->x.out.sgp++; +- conn->x.out.sg_count--; ++ out->sgp++; ++ out->sg_count--; + } + } +- if (conn->x.out.sg_count == 0) { ++ if (out->sg_count == 0) { + /* Done writing, switch to reading. */ + cm_read(selstate, conn->fd); + conn->state = READING; +- conn->x.in.bufsizebytes_read = 0; +- conn->x.in.bufsize = 0; +- conn->x.in.buf = 0; +- conn->x.in.pos = 0; +- conn->x.in.n_left = 0; ++ in->bufsizebytes_read = 0; ++ in->bufsize = 0; ++ in->pos = 0; ++ in->buf = NULL; ++ in->n_left = 0; + } + return 0; + + case READING: +- if (conn->x.in.bufsizebytes_read == 4) { ++ if (in->bufsizebytes_read == 4) { + /* Reading data. */ +- nread = SOCKET_READ(conn->fd, conn->x.in.pos, conn->x.in.n_left); ++ nread = SOCKET_READ(conn->fd, &in->buf[in->pos], in->n_left); + if (nread <= 0) { + e = nread ? SOCKET_ERRNO : ECONNRESET; + TRACE_SENDTO_KDC_TCP_ERROR_RECV(context, &conn->addr, e); + goto kill_conn; + } +- conn->x.in.n_left -= nread; +- conn->x.in.pos += nread; +- if (conn->x.in.n_left <= 0) ++ in->n_left -= nread; ++ in->pos += nread; ++ if (in->n_left <= 0) + return 1; + } else { + /* Reading length. */ + nread = SOCKET_READ(conn->fd, +- conn->x.in.bufsizebytes + conn->x.in.bufsizebytes_read, +- 4 - conn->x.in.bufsizebytes_read); ++ in->bufsizebytes + in->bufsizebytes_read, ++ 4 - in->bufsizebytes_read); + if (nread <= 0) { + e = nread ? SOCKET_ERRNO : ECONNRESET; + TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(context, &conn->addr, e); + goto kill_conn; + } +- conn->x.in.bufsizebytes_read += nread; +- if (conn->x.in.bufsizebytes_read == 4) { +- unsigned long len = load_32_be (conn->x.in.bufsizebytes); ++ in->bufsizebytes_read += nread; ++ if (in->bufsizebytes_read == 4) { ++ unsigned long len = load_32_be(in->bufsizebytes); + /* Arbitrary 1M cap. */ + if (len > 1 * 1024 * 1024) + goto kill_conn; +- conn->x.in.bufsize = conn->x.in.n_left = len; +- conn->x.in.buf = conn->x.in.pos = malloc(len); +- if (conn->x.in.buf == 0) ++ in->bufsize = in->n_left = len; ++ in->pos = 0; ++ in->buf = malloc(len); ++ if (in->buf == NULL) + goto kill_conn; + } + } +@@ -915,13 +919,13 @@ service_udp_fd(krb5_context context, struct conn_state *conn, + if (conn->state != READING) + abort(); + +- nread = recv(conn->fd, conn->x.in.buf, conn->x.in.bufsize, 0); ++ nread = recv(conn->fd, conn->in.buf, conn->in.bufsize, 0); + if (nread < 0) { + TRACE_SENDTO_KDC_UDP_ERROR_RECV(context, &conn->addr, SOCKET_ERRNO); + kill_conn(conn, selstate); + return 0; + } +- conn->x.in.pos = conn->x.in.buf + nread; ++ conn->in.pos = nread; + return 1; + } + +@@ -986,10 +990,7 @@ service_fds(krb5_context context, struct select_state *selstate, + int stop = 1; + + if (msg_handler != NULL) { +- krb5_data reply; +- +- reply.data = state->x.in.buf; +- reply.length = state->x.in.pos - state->x.in.buf; ++ krb5_data reply = make_data(state->in.buf, state->in.pos); + + stop = (msg_handler(context, &reply, msg_handler_data) != 0); + } +@@ -1051,8 +1052,7 @@ k5_sendto(krb5_context context, const krb5_data *message, + char *udpbuf = NULL; + krb5_boolean done = FALSE; + +- reply->data = 0; +- reply->length = 0; ++ *reply = empty_data(); + + /* One for use here, listing all our fds in use, and one for + * temporary use in service_fds, for the fds of interest. */ +@@ -1077,7 +1077,7 @@ k5_sendto(krb5_context context, const krb5_data *message, + /* Contact each new connection whose socktype matches socktype1. */ + if (state->addr.type != socktype1) + continue; +- if (maybe_send(context, state, sel_state, callback_info)) ++ if (maybe_send(context, state, message, sel_state, callback_info)) + continue; + done = service_fds(context, sel_state, 1000, conns, seltemp, + msg_handler, msg_handler_data, &winner); +@@ -1089,7 +1089,7 @@ k5_sendto(krb5_context context, const krb5_data *message, + for (state = conns; state != NULL && !done; state = state->next) { + if (state->addr.type != socktype2) + continue; +- if (maybe_send(context, state, sel_state, callback_info)) ++ if (maybe_send(context, state, message, sel_state, callback_info)) + continue; + done = service_fds(context, sel_state, 1000, conns, seltemp, + msg_handler, msg_handler_data, &winner); +@@ -1105,7 +1105,7 @@ k5_sendto(krb5_context context, const krb5_data *message, + delay = 4000; + for (pass = 1; pass < MAX_PASS && !done; pass++) { + for (state = conns; state != NULL && !done; state = state->next) { +- if (maybe_send(context, state, sel_state, callback_info)) ++ if (maybe_send(context, state, message, sel_state, callback_info)) + continue; + done = service_fds(context, sel_state, 1000, conns, seltemp, + msg_handler, msg_handler_data, &winner); +@@ -1127,10 +1127,9 @@ k5_sendto(krb5_context context, const krb5_data *message, + goto cleanup; + } + /* Success! */ +- reply->data = winner->x.in.buf; +- reply->length = winner->x.in.pos - winner->x.in.buf; ++ *reply = make_data(winner->in.buf, winner->in.pos); + retval = 0; +- winner->x.in.buf = NULL; ++ winner->in.buf = NULL; + if (server_used != NULL) + *server_used = winner->server_index; + if (remoteaddr != NULL && remoteaddrlen != 0 && *remoteaddrlen > 0) +@@ -1142,8 +1141,8 @@ cleanup: + next = state->next; + if (state->fd != INVALID_SOCKET) + closesocket(state->fd); +- if (state->state == READING && state->x.in.buf != udpbuf) +- free(state->x.in.buf); ++ if (state->state == READING && state->in.buf != udpbuf) ++ free(state->in.buf); + if (callback_info) { + callback_info->pfn_cleanup(callback_info->data, + &state->callback_buffer); +-- +2.1.0 + diff --git a/SOURCES/0002-Add-helper-to-determine-if-a-KDC-is-the-master.patch b/SOURCES/0002-Add-helper-to-determine-if-a-KDC-is-the-master.patch new file mode 100644 index 0000000..50ae55b --- /dev/null +++ b/SOURCES/0002-Add-helper-to-determine-if-a-KDC-is-the-master.patch @@ -0,0 +1,233 @@ +From f4b1a7e7b80ce68e57912edcd48c39ea62c73e43 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Sun, 6 Apr 2014 18:06:14 -0400 +Subject: [PATCH 02/13] Add helper to determine if a KDC is the master + +Add a new function k5_kdc_is_master in locate_kdc.c to determine +whether a KDC matches one of the masters, and use it in +krb5_sendto_kdc. +--- + src/lib/krb5/os/locate_kdc.c | 110 +++++++++++++++++++++++++++++-------------- + src/lib/krb5/os/os-proto.h | 3 ++ + src/lib/krb5/os/sendto_kdc.c | 31 +----------- + 3 files changed, 80 insertions(+), 64 deletions(-) + +diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c +index 88d55a8..4479465 100644 +--- a/src/lib/krb5/os/locate_kdc.c ++++ b/src/lib/krb5/os/locate_kdc.c +@@ -166,6 +166,24 @@ add_host_to_list(struct serverlist *list, const char *hostname, int port, + return 0; + } + ++/* Return true if server is identical to an entry in list. */ ++static krb5_boolean ++server_list_contains(struct serverlist *list, struct server_entry *server) ++{ ++ struct server_entry *ent; ++ ++ for (ent = list->servers; ent < list->servers + list->nservers; ent++) { ++ if (server->hostname != NULL && ent->hostname != NULL && ++ strcmp(server->hostname, ent->hostname) == 0) ++ return TRUE; ++ if (server->hostname == NULL && ent->hostname == NULL && ++ server->addrlen == ent->addrlen && ++ memcmp(&server->addr, &ent->addr, server->addrlen) == 0) ++ return TRUE; ++ } ++ return FALSE; ++} ++ + static krb5_error_code + locate_srv_conf_1(krb5_context context, const krb5_data *realm, + const char * name, struct serverlist *serverlist, +@@ -529,6 +547,41 @@ dns_locate_server(krb5_context context, const krb5_data *realm, + } + #endif /* KRB5_DNS_LOOKUP */ + ++static krb5_error_code ++locate_server(krb5_context context, const krb5_data *realm, ++ struct serverlist *serverlist, enum locate_service_type svc, ++ int socktype) ++{ ++ krb5_error_code ret; ++ struct serverlist list = SERVERLIST_INIT; ++ ++ *serverlist = list; ++ ++ /* Try modules. If a module returns 0 but leaves the list empty, return an ++ * empty list. */ ++ ret = module_locate_server(context, realm, &list, svc, socktype); ++ if (ret != KRB5_PLUGIN_NO_HANDLE) ++ goto done; ++ ++ /* Try the profile. Fall back to DNS if it returns an empty list. */ ++ ret = prof_locate_server(context, realm, &list, svc, socktype); ++ if (ret) ++ goto done; ++ ++#ifdef KRB5_DNS_LOOKUP ++ if (list.nservers == 0) ++ ret = dns_locate_server(context, realm, &list, svc, socktype); ++#endif ++ ++done: ++ if (ret) { ++ k5_free_serverlist(&list); ++ return ret; ++ } ++ *serverlist = list; ++ return 0; ++} ++ + /* + * Wrapper function for the various backends + */ +@@ -538,54 +591,26 @@ k5_locate_server(krb5_context context, const krb5_data *realm, + struct serverlist *serverlist, enum locate_service_type svc, + int socktype) + { +- krb5_error_code code; +- struct serverlist al = SERVERLIST_INIT; +- +- *serverlist = al; ++ krb5_error_code ret; + ++ memset(serverlist, 0, sizeof(*serverlist)); + if (realm == NULL || realm->data == NULL || realm->data[0] == 0) { + krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, + "Cannot find KDC for invalid realm name \"\""); + return KRB5_REALM_CANT_RESOLVE; + } + +- code = module_locate_server(context, realm, &al, svc, socktype); +- Tprintf("module_locate_server returns %d\n", code); +- if (code == KRB5_PLUGIN_NO_HANDLE) { +- /* +- * We always try the local file before DNS. Note that there +- * is no way to indicate "service not available" via the +- * config file. +- */ +- +- code = prof_locate_server(context, realm, &al, svc, socktype); +- +-#ifdef KRB5_DNS_LOOKUP +- if (code == 0 && al.nservers == 0) +- code = dns_locate_server(context, realm, &al, svc, socktype); +-#endif /* KRB5_DNS_LOOKUP */ ++ ret = locate_server(context, realm, serverlist, svc, socktype); ++ if (ret) ++ return ret; + +- /* We could put more heuristics here, like looking up a hostname +- of "kerberos."+REALM, etc. */ +- } +- if (code == 0) +- Tprintf ("krb5int_locate_server found %d addresses\n", +- al.nservers); +- else +- Tprintf ("krb5int_locate_server returning error code %d/%s\n", +- code, error_message(code)); +- if (code != 0) { +- k5_free_serverlist(&al); +- return code; +- } +- if (al.nservers == 0) { /* No good servers */ +- k5_free_serverlist(&al); ++ if (serverlist->nservers == 0) { ++ k5_free_serverlist(serverlist); + krb5_set_error_message(context, KRB5_REALM_UNKNOWN, + _("Cannot find KDC for realm \"%.*s\""), + realm->length, realm->data); + return KRB5_REALM_UNKNOWN; + } +- *serverlist = al; + return 0; + } + +@@ -598,3 +623,18 @@ k5_locate_kdc(krb5_context context, const krb5_data *realm, + stype = get_masters ? locate_service_master_kdc : locate_service_kdc; + return k5_locate_server(context, realm, serverlist, stype, socktype); + } ++ ++krb5_boolean ++k5_kdc_is_master(krb5_context context, const krb5_data *realm, ++ struct server_entry *server) ++{ ++ struct serverlist list; ++ krb5_boolean found; ++ ++ if (locate_server(context, realm, &list, locate_service_master_kdc, ++ server->socktype) != 0) ++ return FALSE; ++ found = server_list_contains(&list, server); ++ k5_free_serverlist(&list); ++ return found; ++} +diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h +index c6b730f..9125ba0 100644 +--- a/src/lib/krb5/os/os-proto.h ++++ b/src/lib/krb5/os/os-proto.h +@@ -76,6 +76,9 @@ krb5_error_code k5_locate_kdc(krb5_context context, const krb5_data *realm, + struct serverlist *serverlist, int get_masters, + int socktype); + ++krb5_boolean k5_kdc_is_master(krb5_context context, const krb5_data *realm, ++ struct server_entry *server); ++ + void k5_free_serverlist(struct serverlist *); + + #ifdef HAVE_NETINET_IN_H +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index 5f781d3..e3855a3 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -293,25 +293,6 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime, + } + + static int +-in_addrlist(struct server_entry *entry, struct serverlist *list) +-{ +- size_t i; +- struct server_entry *le; +- +- for (i = 0; i < list->nservers; i++) { +- le = &list->servers[i]; +- if (entry->hostname != NULL && le->hostname != NULL && +- strcmp(entry->hostname, le->hostname) == 0) +- return 1; +- if (entry->hostname == NULL && le->hostname == NULL && +- entry->addrlen == le->addrlen && +- memcmp(&entry->addr, &le->addr, entry->addrlen) == 0) +- return 1; +- } +- return 0; +-} +- +-static int + check_for_svc_unavailable (krb5_context context, + const krb5_data *reply, + void *msg_handler_data) +@@ -418,17 +399,9 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message, + /* Set use_master to 1 if we ended up talking to a master when we didn't + * explicitly request to. */ + if (*use_master == 0) { +- struct serverlist mservers; +- struct server_entry *entry = &servers.servers[server_used]; +- retval = k5_locate_kdc(context, realm, &mservers, TRUE, +- entry->socktype); +- if (retval == 0) { +- if (in_addrlist(entry, &mservers)) +- *use_master = 1; +- k5_free_serverlist(&mservers); +- } ++ *use_master = k5_kdc_is_master(context, realm, ++ &servers.servers[server_used]); + TRACE_SENDTO_KDC_MASTER(context, *use_master); +- retval = 0; + } + + cleanup: +-- +2.1.0 + diff --git a/SOURCES/0002-In-ksu-don-t-stat-not-on-disk-ccache-residuals.patch b/SOURCES/0002-In-ksu-don-t-stat-not-on-disk-ccache-residuals.patch new file mode 100644 index 0000000..262e7c7 --- /dev/null +++ b/SOURCES/0002-In-ksu-don-t-stat-not-on-disk-ccache-residuals.patch @@ -0,0 +1,369 @@ +From 9ebae7cb434b9b177c0af85c67a6d6267f46bc68 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Fri, 1 Nov 2013 09:48:13 -0400 +Subject: [PATCH 2/7] In ksu, don't 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, and +use whether or not that succeeds as an indication of whether or not +there's a ccache in a given location. + +ticket: 7728 +--- + src/clients/ksu/ccache.c | 60 ++++++++++++++++++++-------------- + src/clients/ksu/heuristic.c | 13 ++------ + src/clients/ksu/ksu.h | 8 +++-- + src/clients/ksu/main.c | 79 +++++++++------------------------------------ + 4 files changed, 60 insertions(+), 100 deletions(-) + +diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c +index 118fc53..5f57279 100644 +--- a/src/clients/ksu/ccache.c ++++ b/src/clients/ksu/ccache.c +@@ -62,12 +62,9 @@ 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; + 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)); + +@@ -76,16 +73,13 @@ 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); +- +- if ( ! stat(cc_def_name, &st_temp)){ ++ if (ks_ccache_is_initialized(context, cc_def)) { + if((retval = krb5_get_nonexp_tkts(context,cc_def,&cc_def_creds_arr))){ + return retval; + } + } + +- if (!lstat( cc_other_name, &st_temp)) ++ if (ks_ccache_name_is_initialized(context, cc_other_tag)) + return EINVAL; + + if (krb5_seteuid(0)||krb5_seteuid(target_uid)) { +@@ -540,24 +534,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 (ks_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 (ks_ccache_is_initialized(context, cct)) { + if ((retval = krb5_cc_get_principal(context, cct, &temp_principal))){ + return retval; + } +@@ -643,12 +631,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 (ks_ccache_is_initialized(context, cc)) { + if (auth_debug) { + fprintf(stderr,"putting cache %s through a filter for -z option\n", cc_name); + } +@@ -713,12 +699,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 (ks_ccache_is_initialized(context, cc)) { + if ((retval = krb5_get_nonexp_tkts(context, cc, &creds_list))){ + return retval; + } +@@ -727,3 +709,33 @@ 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; + } ++ ++krb5_boolean ++ks_ccache_name_is_initialized(krb5_context context, const char *cctag) ++{ ++ krb5_boolean result; ++ krb5_ccache cc; ++ ++ if (krb5_cc_resolve(context, cctag, &cc) != 0) ++ return FALSE; ++ result = ks_ccache_is_initialized(context, cc); ++ krb5_cc_close(context, cc); ++ ++ return result; ++} ++ ++krb5_boolean ++ks_ccache_is_initialized(krb5_context context, krb5_ccache cc) ++{ ++ krb5_principal princ; ++ krb5_error_code retval; ++ ++ if (cc == NULL) ++ return FALSE; ++ ++ retval = krb5_cc_get_principal(context, cc, &princ); ++ if (retval == 0) ++ krb5_free_principal(context, princ); ++ ++ return retval == 0; ++} +diff --git a/src/clients/ksu/heuristic.c b/src/clients/ksu/heuristic.c +index 99b54e5..f73b8eb 100644 +--- a/src/clients/ksu/heuristic.c ++++ b/src/clients/ksu/heuristic.c +@@ -397,12 +397,8 @@ krb5_error_code find_either_ticket (context, cc, client, end_server, found) + krb5_principal kdc_server; + krb5_error_code retval; + krb5_boolean temp_found = FALSE; +- const char * cc_source_name; +- struct stat st_temp; + +- cc_source_name = krb5_cc_get_name(context, cc); +- +- if ( ! stat(cc_source_name, &st_temp)){ ++ if (ks_ccache_is_initialized(context, cc)) { + + retval = find_ticket(context, cc, client, end_server, &temp_found); + if (retval) +@@ -539,7 +535,6 @@ krb5_error_code get_best_princ_for_target(context, source_uid, target_uid, + { + + princ_info princ_trials[10]; +- const char * cc_source_name; + krb5_principal cc_def_princ = NULL; + krb5_principal temp_client; + krb5_principal target_client; +@@ -551,7 +546,6 @@ krb5_error_code get_best_princ_for_target(context, source_uid, target_uid, + struct stat tb; + int count =0; + int i; +- struct stat st_temp; + + *path_out = 0; + +@@ -559,10 +553,7 @@ krb5_error_code get_best_princ_for_target(context, source_uid, target_uid, + if (options->princ) + return 0; + +- cc_source_name = krb5_cc_get_name(context, cc_source); +- +- +- if (! stat(cc_source_name, &st_temp)) { ++ if (ks_ccache_is_initialized(context, cc_source)) { + retval = krb5_cc_get_principal(context, cc_source, &cc_def_princ); + if (retval) + return retval; +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index 9e0c613..e1e34f1 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 ks_ccache_name_is_initialized ++(krb5_context, const char *); ++ ++extern krb5_boolean ks_ccache_is_initialized ++(krb5_context, krb5_ccache); ++ + extern krb5_error_code krb5_ccache_refresh + (krb5_context, krb5_ccache); + +@@ -198,8 +204,6 @@ extern int standard_shell (char *); + + extern krb5_error_code get_params (int *, int, char **, char ***); + +-extern char *get_dir_of_file (const char *); +- + /* heuristic.c */ + extern krb5_error_code get_all_princ_from_file (FILE *, char ***); + +diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c +index 62f3bc0..8c49f94 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -51,7 +51,6 @@ static void print_status( const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 1, 2))) + #endif + ; +-char * get_dir_of_file(); + + /* Note -e and -a options are mutually exclusive */ + /* insure the proper specification of target user as well as catching +@@ -96,7 +95,6 @@ main (argc, argv) + const char * cc_source_tag = NULL; + uid_t source_gid; + const char * cc_source_tag_tmp = NULL; +- char * cc_target_tag_tmp=NULL; + char * cmd = NULL, * exec_cmd = NULL; + int errflg = 0; + krb5_boolean auth_val; +@@ -112,11 +110,9 @@ 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; +- char * dir_of_cc_target; + krb5_boolean restrict_creds; + + options.opt = KRB5_DEFAULT_OPTIONS; +@@ -266,9 +262,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 (!ks_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); + } +@@ -419,32 +416,18 @@ main (argc, argv) + exit(1); + } + +- 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 ( !stat ( cc_target_tag_tmp, &st_temp)); +- } +- +- +- 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); +- } ++ /* ++ * 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. ++ */ ++ cc_target_tag = (char *)xcalloc(KRB5_SEC_BUFFSIZE, sizeof(char)); ++ do { ++ snprintf(cc_target_tag, KRB5_SEC_BUFFSIZE, "%s%ld.%d", ++ KRB5_SECONDARY_CACHE, ++ (long)target_uid, gen_sym()); ++ } while (ks_ccache_name_is_initialized(ksu_context, cc_target_tag)); + + if (auth_debug){ + fprintf(stderr, " source cache = %s\n", cc_source_tag); +@@ -747,13 +730,6 @@ main (argc, argv) + 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); +- } +- + if ( cc_source) + krb5_cc_close(ksu_context, cc_source); + +@@ -873,8 +849,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) { +@@ -883,8 +857,7 @@ static void sweep_up(context, cc) + exit(1); + } + +- cc_name = krb5_cc_get_name(context, cc); +- if ( ! stat(cc_name, &st_temp)){ ++ if (ks_ccache_is_initialized(context, cc)) { + if ((retval = krb5_cc_destroy(context, cc))) + com_err(prog_name, retval, _("while destroying cache")); + } +@@ -937,26 +910,6 @@ void print_status(const char *fmt, ...) + } + } + +- +-char *get_dir_of_file(path) +- const char *path; +-{ +- char * temp_path; +- char * ptr; +- +- temp_path = xstrdup(path); +- +- if ((ptr = strrchr( temp_path, '/'))) { +- *ptr = '\0'; +- } else { +- free (temp_path); +- temp_path = xmalloc(MAXPATHLEN); +- if (temp_path) +- getcwd(temp_path, MAXPATHLEN); +- } +- return temp_path; +-} +- + krb5_error_code + ksu_tgtname(context, server, client, tgtprinc) + krb5_context context; +-- +2.0.4 + 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 deleted file mode 100644 index 6fed2d8..0000000 --- a/SOURCES/0002-Use-an-in-memory-cache-until-we-need-the-target-s.patch +++ /dev/null @@ -1,321 +0,0 @@ -From ef82ee237510535238fb2b1e2fbf60112aaf70d1 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-Handlers-won-t-take-care-of-initializing-err.patch b/SOURCES/0003-Handlers-won-t-take-care-of-initializing-err.patch deleted file mode 100644 index db73965..0000000 --- a/SOURCES/0003-Handlers-won-t-take-care-of-initializing-err.patch +++ /dev/null @@ -1,27 +0,0 @@ -From f93d963198c2b98e02fa279b39b01772e88b2259 Mon Sep 17 00:00:00 2001 -From: Nalin Dahyabhai -Date: Tue, 11 Mar 2014 13:26:32 -0400 -Subject: [PATCH 3/4] Handlers won't take care of initializing 'err' - -We can get an KRB5_KDC_UNREACH error back without processing a server -reply first, so we should go ahead and initialize err for that case. ---- - src/lib/krb5/os/sendto_kdc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c -index 828bfff..23b2162 100644 ---- a/src/lib/krb5/os/sendto_kdc.c -+++ b/src/lib/krb5/os/sendto_kdc.c -@@ -166,7 +166,7 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message, - const krb5_data *realm, krb5_data *reply, int *use_master, - int tcp_only) - { -- krb5_error_code retval, err; -+ krb5_error_code retval, err = 0; - struct serverlist servers; - int socktype1 = 0, socktype2 = 0, server_used; - --- -1.9.0 - 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 deleted file mode 100644 index c78bcba..0000000 --- a/SOURCES/0003-Learn-to-destroy-the-ccache-we-re-copying-from.patch +++ /dev/null @@ -1,95 +0,0 @@ -From bb1793f369fc486362d3d540eaa19799164d717f 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/0003-Use-an-intermediate-memory-cache-in-ksu.patch b/SOURCES/0003-Use-an-intermediate-memory-cache-in-ksu.patch new file mode 100644 index 0000000..4bef600 --- /dev/null +++ b/SOURCES/0003-Use-an-intermediate-memory-cache-in-ksu.patch @@ -0,0 +1,417 @@ +From dccc80a469b1925fcfe7697406a69912efe4baa1 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Wed, 30 Oct 2013 21:45:35 -0400 +Subject: [PATCH 3/7] Use an intermediate memory cache in ksu + +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. + +We no longer need to clean up the temporary ccache when exiting in +most error cases. + +Use a fake principal name ("_ksu/_ksu@_ksu") as the primary holder of +the temporary cache so that we won't accidentally select it when we +make a subsequent call to krb5_cc_cache_match() (to be added in a +later patch) to find the target location where the creds should be +stored for use while running as the target user. +--- + src/clients/ksu/ccache.c | 10 +-- + src/clients/ksu/ksu.h | 4 +- + src/clients/ksu/main.c | 156 ++++++++++++++++++++++++----------------------- + 3 files changed, 87 insertions(+), 83 deletions(-) + +diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c +index 5f57279..d0fc389 100644 +--- a/src/clients/ksu/ccache.c ++++ b/src/clients/ksu/ccache.c +@@ -47,14 +47,15 @@ void show_credential(); + */ + + krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, +- primary_principal, restrict_creds, cc_out, +- stored, target_uid) ++ primary_principal, restrict_creds, ++ target_principal, cc_out, stored, target_uid) + /* IN */ + krb5_context context; + krb5_ccache cc_def; + char *cc_other_tag; + krb5_principal primary_principal; + krb5_boolean restrict_creds; ++ krb5_principal target_principal; + uid_t target_uid; + /* OUT */ + krb5_ccache *cc_out; +@@ -86,10 +87,9 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, + return errno; + } + +- +- if ((retval = krb5_cc_initialize(context, *cc_other, primary_principal))){ ++ retval = krb5_cc_initialize(context, *cc_other, target_principal); ++ if (retval) + return retval; +- } + + if (restrict_creds) { + retval = krb5_store_some_creds(context, *cc_other, cc_def_creds_arr, +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index e1e34f1..08bf01b 100644 +--- a/src/clients/ksu/ksu.h ++++ b/src/clients/ksu/ksu.h +@@ -106,8 +106,8 @@ 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_context, krb5_ccache, char *, krb5_principal, krb5_boolean, ++ krb5_principal, 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 8c49f94..d1bb8ca 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -42,10 +42,13 @@ char * gb_err = NULL; + int quiet = 0; + /***********/ + ++#define KS_TEMPORARY_CACHE "MEMORY:_ksu" ++#define KS_TEMPORARY_PRINC "_ksu/_ksu@_ksu" + #define _DEF_CSH "/bin/csh" + static int set_env_var (char *, char *); + static void sweep_up (krb5_context, krb5_ccache); + static char * ontty (void); ++static krb5_error_code set_ccname_env(krb5_context, krb5_ccache); + static void print_status( const char *fmt, ...) + #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) + __attribute__ ((__format__ (__printf__, 1, 2))) +@@ -84,8 +87,8 @@ main (argc, argv) + int option=0; + int statusp=0; + krb5_error_code retval = 0; +- krb5_principal client = NULL; +- krb5_ccache cc_target = NULL; ++ krb5_principal client = NULL, tmp_princ = NULL; ++ krb5_ccache cc_tmp = NULL, cc_target = NULL; + krb5_context ksu_context; + char * cc_target_tag = NULL; + char * target_user = NULL; +@@ -93,7 +96,6 @@ main (argc, argv) + + krb5_ccache cc_source = NULL; + const char * cc_source_tag = NULL; +- uid_t source_gid; + const char * cc_source_tag_tmp = NULL; + char * cmd = NULL, * exec_cmd = NULL; + int errflg = 0; +@@ -342,8 +344,6 @@ main (argc, argv) + /* allocate space and copy the usernamane there */ + source_user = xstrdup(pwd->pw_name); + source_uid = pwd->pw_uid; +- source_gid = pwd->pw_gid; +- + + if (!strcmp(SOURCE_USER_LOGIN, target_user)){ + target_user = xstrdup (source_user); +@@ -435,25 +435,32 @@ 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.*/ ++ * After proper authentication and authorization, 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 + should be copied */ + + restrict_creds = (source_uid == 0) && (target_uid != 0); +- retval = krb5_ccache_copy(ksu_context, cc_source, cc_target_tag, client, +- restrict_creds, &cc_target, &stored, target_uid); ++ retval = krb5_parse_name(ksu_context, KS_TEMPORARY_PRINC, &tmp_princ); ++ if (retval) { ++ com_err(prog_name, retval, _("while parsing temporary name")); ++ exit(1); ++ } ++ retval = krb5_ccache_copy(ksu_context, cc_source, KS_TEMPORARY_CACHE, ++ client, restrict_creds, tmp_princ, &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), KS_TEMPORARY_CACHE); + exit(1); + } + +@@ -473,7 +480,6 @@ main (argc, argv) + &kdc_server))){ + com_err(prog_name, retval, + _("while creating tgt for local realm")); +- sweep_up(ksu_context, cc_target); + exit(1); + } + +@@ -481,13 +487,12 @@ 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); + exit(1); + } + +@@ -506,48 +511,20 @@ 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); + exit(1); + } + +-#if 0 +- /* At best, this avoids a single kdc request +- It is hard to implement dealing with file permissions and +- is unnecessary. It is important +- to properly handle races in chown if this code is ever re-enabled. +- */ +- /* cache the tickets if possible in the source cache */ +- if (!path_passwd){ +- +- if ((retval = krb5_ccache_overwrite(ksu_context, cc_target, cc_source, +- client))){ +- com_err (prog_name, retval, +- "while copying cache %s to %s", +- krb5_cc_get_name(ksu_context, cc_target), +- krb5_cc_get_name(ksu_context, cc_source)); +- sweep_up(ksu_context, cc_target); +- exit(1); +- } +- if (chown(cc_source_tag_tmp, source_uid, source_gid)){ +- com_err(prog_name, errno, +- "while changing owner for %s", +- cc_source_tag_tmp); +- exit(1); +- } +- } +-#endif /*0*/ +- + if ((retval = krb5_unparse_name(ksu_context, client, &client_name))) { + com_err(prog_name, retval, _("When unparsing name")); +- sweep_up(ksu_context, cc_target); + exit(1); + } + +@@ -560,7 +537,6 @@ 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); + exit(1); + } + +@@ -568,14 +544,12 @@ 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); + 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); + exit(1); + } + if (authorization_val == TRUE){ +@@ -617,25 +591,25 @@ main (argc, argv) + + } + +- sweep_up(ksu_context, cc_target); + 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); + exit(1); + } + } + + if (all_rest_copy){ +- if ((retval = krb5_cc_initialize(ksu_context, cc_target, client))){ ++ retval = krb5_cc_initialize(ksu_context, cc_tmp, tmp_princ); ++ if (retval) { + com_err(prog_name, retval, _("while erasing target cache")); + exit(1); + } +- ++ stored = FALSE; + } + + /* get the shell of the user, this will be the shell used by su */ +@@ -653,7 +627,6 @@ 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); + exit(1); + } + #endif /* HAVE_GETUSERSHELL */ +@@ -663,43 +636,28 @@ 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); + 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); + 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); + exit(1); + } + + /* set permissions */ + if (setgid(target_pwd->pw_gid) < 0) { + perror("ksu: setgid"); +- sweep_up(ksu_context, cc_target); + exit(1); + } + +- + if (initgroups(target_user, target_pwd->pw_gid)) { + fprintf(stderr, _("ksu: initgroups failed.\n")); +- sweep_up(ksu_context, cc_target); + exit(1); + } + +@@ -719,13 +677,36 @@ main (argc, argv) + */ + if (setluid((uid_t) pwd->pw_uid) < 0) { + perror("setluid"); +- sweep_up(ksu_context, cc_target); + exit(1); + } + #endif /* HAVE_SETLUID */ + + if (setuid(target_pwd->pw_uid) < 0) { + perror("ksu: setuid"); ++ exit(1); ++ } ++ ++ retval = krb5_ccache_copy(ksu_context, cc_tmp, cc_target_tag, ++ client, FALSE, client, &cc_target, &stored, ++ target_pwd->pw_uid); ++ if (retval) { ++ com_err(prog_name, retval, _("while copying cache %s to %s"), ++ KS_TEMPORARY_CACHE, cc_target_tag); ++ exit(1); ++ } ++ ++ if (stored && !ks_ccache_is_initialized(ksu_context, cc_target)) { ++ com_err(prog_name, errno, ++ _("%s does not have correct permissions for %s, %s aborted"), ++ target_user, cc_target_tag, prog_name); ++ exit(1); ++ } ++ ++ free(cc_target_tag); ++ ++ /* Set the cc env name to target. */ ++ retval = set_ccname_env(ksu_context, cc_target); ++ if (retval != 0) { + sweep_up(ksu_context, cc_target); + exit(1); + } +@@ -799,6 +780,29 @@ main (argc, argv) + } + } + ++/* Set KRB5CCNAME in the environment to point to ccache. Print an error ++ * message on failure. */ ++static krb5_error_code ++set_ccname_env(krb5_context ksu_context, krb5_ccache ccache) ++{ ++ krb5_error_code retval; ++ char *ccname; ++ ++ retval = krb5_cc_get_full_name(ksu_context, ccache, &ccname); ++ if (retval) { ++ com_err(prog_name, retval, _("while reading cache name from ccache")); ++ return retval; ++ } ++ if (set_env_var(KRB5_ENV_CCNAME, ccname)) { ++ retval = errno; ++ fprintf(stderr, ++ _("ksu: couldn't set environment variable %s\n"), ++ KRB5_ENV_CCNAME); ++ } ++ krb5_free_string(ksu_context, ccname); ++ return retval; ++} ++ + #ifdef HAVE_GETUSERSHELL + + int standard_shell(sh) +-- +2.0.4 + diff --git a/SOURCES/0003-Use-k5_transport-_strategy-enums-for-k5_sendto.patch b/SOURCES/0003-Use-k5_transport-_strategy-enums-for-k5_sendto.patch new file mode 100644 index 0000000..ba3f91c --- /dev/null +++ b/SOURCES/0003-Use-k5_transport-_strategy-enums-for-k5_sendto.patch @@ -0,0 +1,913 @@ +From 9c6be00daca0b80aed94ec9680724f95e6be92e1 Mon Sep 17 00:00:00 2001 +From: "Robbie Harwood (frozencemetery)" +Date: Thu, 15 Aug 2013 15:55:52 -0400 +Subject: [PATCH 03/13] Use k5_transport(_strategy) enums for k5_sendto + +In k5_sendto and k5_locate_server, replace "socktype" parameters with +a new enumerator k5_transport, so that we can add new transports which +are not in the socket type namespace. Control the order in which we +make connections of different types using a new k5_transport_strategy +enumerator, to simplify the logic for adding new transports later. +Control the result of k5_locate_server with a no_udp boolean rather +than a socket type. + +[ghudson@mit.edu: renamed type to k5_transport; k5_locate_server + no_udp change; clarified commit message; fix for Solaris getaddrinfo] +[kaduk@mit.edu: name variables of type k5_transport 'transport'] +[nalin@redhat.com: use transport rather than sock_type in more places, + add and use k5_transport_strategy, update the test program] + +ticket: 7929 +--- + src/lib/krb5/os/changepw.c | 31 +++++----- + src/lib/krb5/os/hostrealm_domain.c | 2 +- + src/lib/krb5/os/locate_kdc.c | 75 ++++++++++++---------- + src/lib/krb5/os/os-proto.h | 27 +++++--- + src/lib/krb5/os/sendto_kdc.c | 123 +++++++++++++++++++++++-------------- + src/lib/krb5/os/t_locate_kdc.c | 24 ++++---- + src/lib/krb5/os/t_std_conf.c | 2 +- + src/lib/krb5/os/t_trace.c | 6 +- + src/lib/krb5/os/t_trace.ref | 4 +- + src/lib/krb5/os/trace.c | 6 +- + 10 files changed, 178 insertions(+), 122 deletions(-) + +diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c +index 4d8abd9..a1c9885 100644 +--- a/src/lib/krb5/os/changepw.c ++++ b/src/lib/krb5/os/changepw.c +@@ -59,25 +59,25 @@ struct sendto_callback_context { + + static krb5_error_code + locate_kpasswd(krb5_context context, const krb5_data *realm, +- struct serverlist *serverlist, int socktype) ++ struct serverlist *serverlist, krb5_boolean no_udp) + { + krb5_error_code code; + + code = k5_locate_server(context, realm, serverlist, locate_service_kpasswd, +- socktype); ++ no_udp); + + if (code == KRB5_REALM_CANT_RESOLVE || code == KRB5_REALM_UNKNOWN) { + code = k5_locate_server(context, realm, serverlist, +- locate_service_kadmin, SOCK_STREAM); ++ locate_service_kadmin, TRUE); + if (!code) { +- /* Success with admin_server but now we need to change the +- port number to use DEFAULT_KPASSWD_PORT and the socktype. */ ++ /* Success with admin_server but now we need to change the port ++ * number to use DEFAULT_KPASSWD_PORT and the transport. */ + size_t i; + for (i = 0; i < serverlist->nservers; i++) { + struct server_entry *s = &serverlist->servers[i]; + krb5_ui_2 kpasswd_port = htons(DEFAULT_KPASSWD_PORT); +- if (socktype != SOCK_STREAM) +- s->socktype = socktype; ++ if (!no_udp && s->transport == TCP) ++ s->transport = TCP_OR_UDP; + if (s->hostname != NULL) + s->port = kpasswd_port; + else if (s->family == AF_INET) +@@ -214,7 +214,7 @@ change_set_password(krb5_context context, + krb5_data *result_string) + { + krb5_data chpw_rep; +- krb5_boolean use_tcp = 0; ++ krb5_boolean no_udp = FALSE; + GETSOCKNAME_ARG3_TYPE addrlen; + krb5_error_code code = 0; + char *code_string; +@@ -247,9 +247,10 @@ change_set_password(krb5_context context, + callback_ctx.local_seq_num = callback_ctx.auth_context->local_seq_number; + + do { +- int socktype = (use_tcp ? SOCK_STREAM : SOCK_DGRAM); ++ k5_transport_strategy strategy = no_udp ? NO_UDP : UDP_FIRST; ++ + code = locate_kpasswd(callback_ctx.context, &creds->server->realm, &sl, +- socktype); ++ no_udp); + if (code) + break; + +@@ -260,7 +261,7 @@ change_set_password(krb5_context context, + callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup; + krb5_free_data_contents(callback_ctx.context, &chpw_rep); + +- code = k5_sendto(callback_ctx.context, NULL, &sl, socktype, 0, ++ code = k5_sendto(callback_ctx.context, NULL, &sl, strategy, + &callback_info, &chpw_rep, ss2sa(&remote_addr), + &addrlen, NULL, NULL, NULL); + if (code) { +@@ -277,9 +278,9 @@ change_set_password(krb5_context context, + result_string); + + if (code) { +- if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) { ++ if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !no_udp) { + k5_free_serverlist(&sl); +- use_tcp = 1; ++ no_udp = 1; + continue; + } + +@@ -305,9 +306,9 @@ change_set_password(krb5_context context, + strncpy(result_code_string->data, code_string, result_code_string->length); + } + +- if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) { ++ if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !no_udp) { + k5_free_serverlist(&sl); +- use_tcp = 1; ++ no_udp = 1; + } else { + break; + } +diff --git a/src/lib/krb5/os/hostrealm_domain.c b/src/lib/krb5/os/hostrealm_domain.c +index dc9cc59..2228df0 100644 +--- a/src/lib/krb5/os/hostrealm_domain.c ++++ b/src/lib/krb5/os/hostrealm_domain.c +@@ -85,7 +85,7 @@ domain_fallback_realm(krb5_context context, krb5_hostrealm_moddata data, + suffix = uhost; + while (limit-- >= 0 && (dot = strchr(suffix, '.')) != NULL) { + drealm = string2data((char *)suffix); +- if (k5_locate_kdc(context, &drealm, &slist, FALSE, SOCK_DGRAM) == 0) { ++ if (k5_locate_kdc(context, &drealm, &slist, FALSE, FALSE) == 0) { + k5_free_serverlist(&slist); + ret = k5_make_realmlist(suffix, realms_out); + goto cleanup; +diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c +index 4479465..4c8aead 100644 +--- a/src/lib/krb5/os/locate_kdc.c ++++ b/src/lib/krb5/os/locate_kdc.c +@@ -129,7 +129,7 @@ new_server_entry(struct serverlist *list) + + /* Add an address entry to list. */ + static int +-add_addr_to_list(struct serverlist *list, int socktype, int family, ++add_addr_to_list(struct serverlist *list, k5_transport transport, int family, + size_t addrlen, struct sockaddr *addr) + { + struct server_entry *entry; +@@ -137,7 +137,7 @@ add_addr_to_list(struct serverlist *list, int socktype, int family, + entry = new_server_entry(list); + if (entry == NULL) + return ENOMEM; +- entry->socktype = socktype; ++ entry->transport = transport; + entry->family = family; + entry->hostname = NULL; + entry->addrlen = addrlen; +@@ -149,14 +149,14 @@ add_addr_to_list(struct serverlist *list, int socktype, int family, + /* Add a hostname entry to list. */ + static int + add_host_to_list(struct serverlist *list, const char *hostname, int port, +- int socktype, int family) ++ k5_transport transport, int family) + { + struct server_entry *entry; + + entry = new_server_entry(list); + if (entry == NULL) + return ENOMEM; +- entry->socktype = socktype; ++ entry->transport = transport; + entry->family = family; + entry->hostname = strdup(hostname); + if (entry->hostname == NULL) +@@ -187,7 +187,7 @@ server_list_contains(struct serverlist *list, struct server_entry *server) + static krb5_error_code + locate_srv_conf_1(krb5_context context, const krb5_data *realm, + const char * name, struct serverlist *serverlist, +- int socktype, int udpport, int sec_udpport) ++ k5_transport transport, int udpport, int sec_udpport) + { + const char *realm_srv_names[4]; + char **hostlist, *host, *port, *cp; +@@ -255,12 +255,12 @@ locate_srv_conf_1(krb5_context context, const krb5_data *realm, + *cp = '\0'; + } + +- code = add_host_to_list(serverlist, host, p1, socktype, AF_UNSPEC); ++ code = add_host_to_list(serverlist, host, p1, transport, AF_UNSPEC); + /* Second port is for IPv4 UDP only, and should possibly go away as + * it was originally a krb4 compatibility measure. */ + if (code == 0 && p2 != 0 && +- (socktype == 0 || socktype == SOCK_DGRAM)) +- code = add_host_to_list(serverlist, host, p2, SOCK_DGRAM, AF_INET); ++ (transport == TCP_OR_UDP || transport == UDP)) ++ code = add_host_to_list(serverlist, host, p2, UDP, AF_INET); + if (code) + goto cleanup; + } +@@ -278,7 +278,8 @@ krb5_locate_srv_conf(krb5_context context, const krb5_data *realm, + { + krb5_error_code ret; + +- ret = locate_srv_conf_1(context, realm, name, al, 0, udpport, sec_udpport); ++ ret = locate_srv_conf_1(context, realm, name, al, TCP_OR_UDP, udpport, ++ sec_udpport); + if (ret) + return ret; + if (al->nservers == 0) /* Couldn't resolve any KDC names */ +@@ -294,7 +295,7 @@ locate_srv_dns_1(const krb5_data *realm, const char *service, + { + struct srv_dns_entry *head = NULL, *entry = NULL; + krb5_error_code code = 0; +- int socktype; ++ k5_transport transport; + + code = krb5int_make_srv_query_realm(realm, service, protocol, &head); + if (code) +@@ -310,9 +311,9 @@ locate_srv_dns_1(const krb5_data *realm, const char *service, + } + + for (entry = head; entry != NULL; entry = entry->next) { +- socktype = (strcmp(protocol, "_tcp") == 0) ? SOCK_STREAM : SOCK_DGRAM; ++ transport = (strcmp(protocol, "_tcp") == 0) ? TCP : UDP; + code = add_host_to_list(serverlist, entry->host, htons(entry->port), +- socktype, AF_UNSPEC); ++ transport, AF_UNSPEC); + if (code) + goto cleanup; + } +@@ -341,6 +342,7 @@ module_callback(void *cbdata, int socktype, struct sockaddr *sa) + { + struct module_callback_data *d = cbdata; + size_t addrlen; ++ k5_transport transport; + + if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM) + return 0; +@@ -350,7 +352,8 @@ module_callback(void *cbdata, int socktype, struct sockaddr *sa) + addrlen = sizeof(struct sockaddr_in6); + else + return 0; +- if (add_addr_to_list(d->list, socktype, sa->sa_family, addrlen, ++ transport = (socktype == SOCK_STREAM) ? TCP : UDP; ++ if (add_addr_to_list(d->list, transport, sa->sa_family, addrlen, + sa) != 0) { + /* Assumes only error is ENOMEM. */ + d->out_of_mem = 1; +@@ -362,14 +365,14 @@ module_callback(void *cbdata, int socktype, struct sockaddr *sa) + static krb5_error_code + module_locate_server(krb5_context ctx, const krb5_data *realm, + struct serverlist *serverlist, +- enum locate_service_type svc, int socktype) ++ enum locate_service_type svc, k5_transport transport) + { + struct krb5plugin_service_locate_result *res = NULL; + krb5_error_code code; + struct krb5plugin_service_locate_ftable *vtbl = NULL; + void **ptrs; + char *realmz; /* NUL-terminated realm */ +- int i; ++ int socktype, i; + struct module_callback_data cbdata = { 0, }; + const char *msg; + +@@ -413,11 +416,11 @@ module_locate_server(krb5_context ctx, const krb5_data *realm, + if (code) + continue; + +- code = vtbl->lookup(blob, svc, realmz, +- (socktype != 0) ? socktype : SOCK_DGRAM, AF_UNSPEC, ++ socktype = (transport == TCP) ? SOCK_STREAM : SOCK_DGRAM; ++ code = vtbl->lookup(blob, svc, realmz, socktype, AF_UNSPEC, + module_callback, &cbdata); + /* Also ask for TCP addresses if we got UDP addresses and want both. */ +- if (code == 0 && socktype == 0) { ++ if (code == 0 && transport == TCP_OR_UDP) { + code = vtbl->lookup(blob, svc, realmz, SOCK_STREAM, AF_UNSPEC, + module_callback, &cbdata); + if (code == KRB5_PLUGIN_NO_HANDLE) +@@ -459,7 +462,7 @@ module_locate_server(krb5_context ctx, const krb5_data *realm, + static krb5_error_code + prof_locate_server(krb5_context context, const krb5_data *realm, + struct serverlist *serverlist, enum locate_service_type svc, +- int socktype) ++ k5_transport transport) + { + const char *profname; + int dflport1, dflport2 = 0; +@@ -495,7 +498,7 @@ prof_locate_server(krb5_context context, const krb5_data *realm, + return EBUSY; /* XXX */ + } + +- return locate_srv_conf_1(context, realm, profname, serverlist, socktype, ++ return locate_srv_conf_1(context, realm, profname, serverlist, transport, + dflport1, dflport2); + } + +@@ -503,7 +506,7 @@ prof_locate_server(krb5_context context, const krb5_data *realm, + static krb5_error_code + dns_locate_server(krb5_context context, const krb5_data *realm, + struct serverlist *serverlist, enum locate_service_type svc, +- int socktype) ++ k5_transport transport) + { + const char *dnsname; + int use_dns = _krb5_use_dns_kdc(context); +@@ -533,12 +536,12 @@ dns_locate_server(krb5_context context, const krb5_data *realm, + } + + code = 0; +- if (socktype == SOCK_DGRAM || socktype == 0) { ++ if (transport == UDP || transport == TCP_OR_UDP) { + code = locate_srv_dns_1(realm, dnsname, "_udp", serverlist); + if (code) + Tprintf("dns udp lookup returned error %d\n", code); + } +- if ((socktype == SOCK_STREAM || socktype == 0) && code == 0) { ++ if ((transport == TCP || transport == TCP_OR_UDP) && code == 0) { + code = locate_srv_dns_1(realm, dnsname, "_tcp", serverlist); + if (code) + Tprintf("dns tcp lookup returned error %d\n", code); +@@ -547,10 +550,16 @@ dns_locate_server(krb5_context context, const krb5_data *realm, + } + #endif /* KRB5_DNS_LOOKUP */ + ++/* ++ * Try all of the server location methods in sequence. transport must be ++ * TCP_OR_UDP, TCP, or UDP. It is applied to hostname entries in the profile ++ * and affects whether we query modules or DNS for UDP or TCP or both, but does ++ * not restrict a method from returning entries of other transports. ++ */ + static krb5_error_code + locate_server(krb5_context context, const krb5_data *realm, + struct serverlist *serverlist, enum locate_service_type svc, +- int socktype) ++ k5_transport transport) + { + krb5_error_code ret; + struct serverlist list = SERVERLIST_INIT; +@@ -559,18 +568,18 @@ locate_server(krb5_context context, const krb5_data *realm, + + /* Try modules. If a module returns 0 but leaves the list empty, return an + * empty list. */ +- ret = module_locate_server(context, realm, &list, svc, socktype); ++ ret = module_locate_server(context, realm, &list, svc, transport); + if (ret != KRB5_PLUGIN_NO_HANDLE) + goto done; + + /* Try the profile. Fall back to DNS if it returns an empty list. */ +- ret = prof_locate_server(context, realm, &list, svc, socktype); ++ ret = prof_locate_server(context, realm, &list, svc, transport); + if (ret) + goto done; + + #ifdef KRB5_DNS_LOOKUP + if (list.nservers == 0) +- ret = dns_locate_server(context, realm, &list, svc, socktype); ++ ret = dns_locate_server(context, realm, &list, svc, transport); + #endif + + done: +@@ -589,9 +598,10 @@ done: + krb5_error_code + k5_locate_server(krb5_context context, const krb5_data *realm, + struct serverlist *serverlist, enum locate_service_type svc, +- int socktype) ++ krb5_boolean no_udp) + { + krb5_error_code ret; ++ k5_transport transport = no_udp ? TCP : TCP_OR_UDP; + + memset(serverlist, 0, sizeof(*serverlist)); + if (realm == NULL || realm->data == NULL || realm->data[0] == 0) { +@@ -600,7 +610,7 @@ k5_locate_server(krb5_context context, const krb5_data *realm, + return KRB5_REALM_CANT_RESOLVE; + } + +- ret = locate_server(context, realm, serverlist, svc, socktype); ++ ret = locate_server(context, realm, serverlist, svc, transport); + if (ret) + return ret; + +@@ -616,12 +626,13 @@ k5_locate_server(krb5_context context, const krb5_data *realm, + + krb5_error_code + k5_locate_kdc(krb5_context context, const krb5_data *realm, +- struct serverlist *serverlist, int get_masters, int socktype) ++ struct serverlist *serverlist, krb5_boolean get_masters, ++ krb5_boolean no_udp) + { + enum locate_service_type stype; + + stype = get_masters ? locate_service_master_kdc : locate_service_kdc; +- return k5_locate_server(context, realm, serverlist, stype, socktype); ++ return k5_locate_server(context, realm, serverlist, stype, no_udp); + } + + krb5_boolean +@@ -632,7 +643,7 @@ k5_kdc_is_master(krb5_context context, const krb5_data *realm, + krb5_boolean found; + + if (locate_server(context, realm, &list, locate_service_master_kdc, +- server->socktype) != 0) ++ server->transport) != 0) + return FALSE; + found = server_list_contains(&list, server); + k5_free_serverlist(&list); +diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h +index 9125ba0..3196bca 100644 +--- a/src/lib/krb5/os/os-proto.h ++++ b/src/lib/krb5/os/os-proto.h +@@ -38,11 +38,23 @@ + + #include + ++typedef enum { ++ TCP_OR_UDP = 0, ++ TCP, ++ UDP, ++} k5_transport; ++ ++typedef enum { ++ UDP_FIRST = 0, ++ UDP_LAST, ++ NO_UDP, ++} k5_transport_strategy; ++ + /* A single server hostname or address. */ + struct server_entry { + char *hostname; /* NULL -> use addrlen/addr instead */ + int port; /* Used only if hostname set */ +- int socktype; /* May be 0 for UDP/TCP if hostname set */ ++ k5_transport transport; /* May be 0 for UDP/TCP if hostname set */ + int family; /* May be 0 (aka AF_UNSPEC) if hostname set */ + size_t addrlen; + struct sockaddr_storage addr; +@@ -56,8 +68,8 @@ struct serverlist { + #define SERVERLIST_INIT { NULL, 0 } + + struct remote_address { ++ k5_transport transport; + int family; +- int type; + socklen_t len; + struct sockaddr_storage saddr; + }; +@@ -69,12 +81,13 @@ struct sendto_callback_info { + }; + + krb5_error_code k5_locate_server(krb5_context, const krb5_data *realm, +- struct serverlist *, +- enum locate_service_type svc, int socktype); ++ struct serverlist *serverlist, ++ enum locate_service_type svc, ++ krb5_boolean no_udp); + + krb5_error_code k5_locate_kdc(krb5_context context, const krb5_data *realm, +- struct serverlist *serverlist, int get_masters, +- int socktype); ++ struct serverlist *serverlist, ++ krb5_boolean get_masters, krb5_boolean no_udp); + + krb5_boolean k5_kdc_is_master(krb5_context context, const krb5_data *realm, + struct server_entry *server); +@@ -103,7 +116,7 @@ int _krb5_conf_boolean (const char *); + + krb5_error_code k5_sendto(krb5_context context, const krb5_data *message, + const struct serverlist *addrs, +- int socktype1, int socktype2, ++ k5_transport_strategy strategy, + struct sendto_callback_info *callback_info, + krb5_data *reply, struct sockaddr *remoteaddr, + socklen_t *remoteaddrlen, int *server_used, +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index e3855a3..3f99ce8 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -104,6 +104,7 @@ struct conn_state { + size_t server_index; + struct conn_state *next; + time_ms endtime; ++ krb5_boolean defer; + }; + + /* Get current time in milliseconds. */ +@@ -293,6 +294,19 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime, + } + + static int ++socktype_for_transport(k5_transport transport) ++{ ++ switch (transport) { ++ case UDP: ++ return SOCK_DGRAM; ++ case TCP: ++ return SOCK_STREAM; ++ default: ++ return 0; ++ } ++} ++ ++static int + check_for_svc_unavailable (krb5_context context, + const krb5_data *reply, + void *msg_handler_data) +@@ -330,11 +344,12 @@ check_for_svc_unavailable (krb5_context context, + krb5_error_code + krb5_sendto_kdc(krb5_context context, const krb5_data *message, + const krb5_data *realm, krb5_data *reply, int *use_master, +- int tcp_only) ++ int no_udp) + { + krb5_error_code retval, err; + struct serverlist servers; +- int socktype1 = 0, socktype2 = 0, server_used; ++ int server_used; ++ k5_transport_strategy strategy; + + /* + * find KDC location(s) for realm +@@ -349,9 +364,9 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message, + * should probably be returned as well. + */ + +- TRACE_SENDTO_KDC(context, message->length, realm, *use_master, tcp_only); ++ TRACE_SENDTO_KDC(context, message->length, realm, *use_master, no_udp); + +- if (!tcp_only && context->udp_pref_limit < 0) { ++ if (!no_udp && context->udp_pref_limit < 0) { + int tmp; + retval = profile_get_integer(context->profile, + KRB5_CONF_LIBDEFAULTS, KRB5_CONF_UDP_PREFERENCE_LIMIT, 0, +@@ -368,22 +383,21 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message, + context->udp_pref_limit = tmp; + } + +- if (tcp_only) +- socktype1 = SOCK_STREAM, socktype2 = 0; ++ if (no_udp) ++ strategy = NO_UDP; + else if (message->length <= (unsigned int) context->udp_pref_limit) +- socktype1 = SOCK_DGRAM, socktype2 = SOCK_STREAM; ++ strategy = UDP_FIRST; + else +- socktype1 = SOCK_STREAM, socktype2 = SOCK_DGRAM; ++ strategy = UDP_LAST; + +- retval = k5_locate_kdc(context, realm, &servers, *use_master, +- tcp_only ? SOCK_STREAM : 0); ++ retval = k5_locate_kdc(context, realm, &servers, *use_master, no_udp); + if (retval) + return retval; + + err = 0; +- retval = k5_sendto(context, message, &servers, socktype1, socktype2, +- NULL, reply, NULL, NULL, &server_used, +- check_for_svc_unavailable, &err); ++ retval = k5_sendto(context, message, &servers, strategy, NULL, reply, ++ NULL, NULL, &server_used, check_for_svc_unavailable, ++ &err); + if (retval == KRB5_KDC_UNREACH) { + if (err == KDC_ERR_SVC_UNAVAILABLE) { + retval = KRB5KDC_ERR_SVC_UNAVAILABLE; +@@ -444,7 +458,7 @@ set_transport_message(struct conn_state *state, const krb5_data *message) + if (message == NULL || message->length == 0) + return; + +- if (state->addr.type == SOCK_STREAM) { ++ if (state->addr.transport == TCP) { + store_32_be(message->length, out->msg_len_buf); + SG_SET(&out->sgbuf[0], out->msg_len_buf, 4); + SG_SET(&out->sgbuf[1], message->data, message->length); +@@ -457,8 +471,9 @@ set_transport_message(struct conn_state *state, const krb5_data *message) + } + + static krb5_error_code +-add_connection(struct conn_state **conns, struct addrinfo *ai, +- size_t server_index, char **udpbufp) ++add_connection(struct conn_state **conns, k5_transport transport, ++ krb5_boolean defer, struct addrinfo *ai, size_t server_index, ++ char **udpbufp) + { + struct conn_state *state, **tailptr; + +@@ -467,14 +482,15 @@ add_connection(struct conn_state **conns, struct addrinfo *ai, + return ENOMEM; + state->state = INITIALIZING; + state->out.sgp = state->out.sgbuf; +- state->addr.type = ai->ai_socktype; ++ state->addr.transport = transport; + state->addr.family = ai->ai_family; + state->addr.len = ai->ai_addrlen; + memcpy(&state->addr.saddr, ai->ai_addr, ai->ai_addrlen); ++ state->defer = defer; + state->fd = INVALID_SOCKET; + state->server_index = server_index; + SG_SET(&state->out.sgbuf[1], NULL, 0); +- if (ai->ai_socktype == SOCK_STREAM) { ++ if (transport == TCP) { + state->service = service_tcp_fd; + } else { + state->service = service_udp_fd; +@@ -549,32 +565,41 @@ translate_ai_error (int err) + */ + static krb5_error_code + resolve_server(krb5_context context, const struct serverlist *servers, +- size_t ind, int socktype1, int socktype2, ++ size_t ind, k5_transport_strategy strategy, + const krb5_data *message, char **udpbufp, + struct conn_state **conns) + { + krb5_error_code retval; + struct server_entry *entry = &servers->servers[ind]; ++ k5_transport transport; + struct addrinfo *addrs, *a, hint, ai; ++ krb5_boolean defer; + int err, result; + char portbuf[64]; + +- /* Skip any stray entries of socktypes we don't want. */ +- if (entry->socktype != 0 && entry->socktype != socktype1 && +- entry->socktype != socktype2) ++ /* Skip UDP entries if we don't want UDP. */ ++ if (strategy == NO_UDP && entry->transport == UDP) + return 0; + ++ transport = (strategy == UDP_FIRST) ? UDP : TCP; + if (entry->hostname == NULL) { +- ai.ai_socktype = entry->socktype; ++ /* Added by a module, so transport is either TCP or UDP. */ ++ ai.ai_socktype = socktype_for_transport(entry->transport); + ai.ai_family = entry->family; + ai.ai_addrlen = entry->addrlen; + ai.ai_addr = (struct sockaddr *)&entry->addr; +- return add_connection(conns, &ai, ind, udpbufp); ++ defer = (entry->transport != transport); ++ return add_connection(conns, entry->transport, defer, &ai, ind, ++ udpbufp); + } + ++ /* If the entry has a specified transport, use it. */ ++ if (entry->transport != TCP_OR_UDP) ++ transport = entry->transport; ++ + memset(&hint, 0, sizeof(hint)); + hint.ai_family = entry->family; +- hint.ai_socktype = (entry->socktype != 0) ? entry->socktype : socktype1; ++ hint.ai_socktype = socktype_for_transport(transport); + hint.ai_flags = AI_ADDRCONFIG; + #ifdef AI_NUMERICSERV + hint.ai_flags |= AI_NUMERICSERV; +@@ -586,15 +611,19 @@ resolve_server(krb5_context context, const struct serverlist *servers, + err = getaddrinfo(entry->hostname, portbuf, &hint, &addrs); + if (err) + return translate_ai_error(err); +- /* Add each address with the preferred socktype. */ ++ ++ /* Add each address with the specified or preferred transport. */ + retval = 0; + for (a = addrs; a != 0 && retval == 0; a = a->ai_next) +- retval = add_connection(conns, a, ind, udpbufp); +- if (retval == 0 && entry->socktype == 0 && socktype2 != 0) { +- /* Add each address again with the non-preferred socktype. */ ++ retval = add_connection(conns, transport, FALSE, a, ind, udpbufp); ++ ++ /* For TCP_OR_UDP entries, add each address again with the non-preferred ++ * transport, unless we are avoiding UDP. Flag these as deferred. */ ++ if (retval == 0 && entry->transport == TCP_OR_UDP && strategy != NO_UDP) { ++ transport = (strategy == UDP_FIRST) ? TCP : UDP; + for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { +- a->ai_socktype = socktype2; +- retval = add_connection(conns, a, ind, udpbufp); ++ a->ai_socktype = socktype_for_transport(transport); ++ retval = add_connection(conns, transport, TRUE, a, ind, udpbufp); + } + } + freeaddrinfo(addrs); +@@ -606,17 +635,18 @@ start_connection(krb5_context context, struct conn_state *state, + const krb5_data *message, struct select_state *selstate, + struct sendto_callback_info *callback_info) + { +- int fd, e; ++ int fd, e, type; + static const int one = 1; + static const struct linger lopt = { 0, 0 }; + +- fd = socket(state->addr.family, state->addr.type, 0); ++ type = socktype_for_transport(state->addr.transport); ++ fd = socket(state->addr.family, type, 0); + if (fd == INVALID_SOCKET) + return -1; /* try other hosts */ + set_cloexec_fd(fd); + /* Make it non-blocking. */ + ioctlsocket(fd, FIONBIO, (const void *) &one); +- if (state->addr.type == SOCK_STREAM) { ++ if (state->addr.transport == TCP) { + setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt)); + TRACE_SENDTO_KDC_TCP_CONNECT(context, &state->addr); + } +@@ -665,7 +695,7 @@ start_connection(krb5_context context, struct conn_state *state, + } + set_transport_message(state, message); + +- if (state->addr.type == SOCK_DGRAM) { ++ if (state->addr.transport == UDP) { + /* Send it now. */ + ssize_t ret; + sg_buf *sg = &state->out.sgbuf[0]; +@@ -720,7 +750,7 @@ maybe_send(krb5_context context, struct conn_state *conn, + return -1; + } + +- if (conn->addr.type == SOCK_STREAM) { ++ if (conn->addr.transport != UDP) { + /* The select callback will handle flushing any data we + haven't written yet, and we only write it once. */ + return -1; +@@ -910,7 +940,7 @@ get_endtime(time_ms endtime, struct conn_state *conns) + struct conn_state *state; + + for (state = conns; state != NULL; state = state->next) { +- if (state->addr.type == SOCK_STREAM && ++ if (state->addr.transport == TCP && + (state->state == READING || state->state == WRITING) && + state->endtime > endtime) + endtime = state->endtime; +@@ -1008,7 +1038,7 @@ service_fds(krb5_context context, struct select_state *selstate, + + krb5_error_code + k5_sendto(krb5_context context, const krb5_data *message, +- const struct serverlist *servers, int socktype1, int socktype2, ++ const struct serverlist *servers, k5_transport_strategy strategy, + struct sendto_callback_info* callback_info, krb5_data *reply, + struct sockaddr *remoteaddr, socklen_t *remoteaddrlen, + int *server_used, +@@ -1038,17 +1068,18 @@ k5_sendto(krb5_context context, const krb5_data *message, + cm_init_selstate(sel_state); + + /* First pass: resolve server hosts, communicate with resulting addresses +- * of the preferred socktype, and wait 1s for an answer from each. */ ++ * of the preferred transport, and wait 1s for an answer from each. */ + for (s = 0; s < servers->nservers && !done; s++) { + /* Find the current tail pointer. */ + for (tailptr = &conns; *tailptr != NULL; tailptr = &(*tailptr)->next); +- retval = resolve_server(context, servers, s, socktype1, socktype2, +- message, &udpbuf, &conns); ++ retval = resolve_server(context, servers, s, strategy, message, ++ &udpbuf, &conns); + if (retval) + goto cleanup; + for (state = *tailptr; state != NULL && !done; state = state->next) { +- /* Contact each new connection whose socktype matches socktype1. */ +- if (state->addr.type != socktype1) ++ /* Contact each new connection, deferring those which use the ++ * non-preferred RFC 4120 transport. */ ++ if (state->defer) + continue; + if (maybe_send(context, state, message, sel_state, callback_info)) + continue; +@@ -1057,10 +1088,10 @@ k5_sendto(krb5_context context, const krb5_data *message, + } + } + +- /* Complete the first pass by contacting servers of the non-preferred +- * socktype (if given), waiting 1s for an answer from each. */ ++ /* Complete the first pass by contacting servers of the non-preferred RFC ++ * 4120 transport (if given), waiting 1s for an answer from each. */ + for (state = conns; state != NULL && !done; state = state->next) { +- if (state->addr.type != socktype2) ++ if (!state->defer) + continue; + if (maybe_send(context, state, message, sel_state, callback_info)) + continue; +diff --git a/src/lib/krb5/os/t_locate_kdc.c b/src/lib/krb5/os/t_locate_kdc.c +index 5453a4c..300aa71 100644 +--- a/src/lib/krb5/os/t_locate_kdc.c ++++ b/src/lib/krb5/os/t_locate_kdc.c +@@ -29,18 +29,18 @@ kfatal (krb5_error_code err) + } + + static const char * +-stypename (int stype) ++ttypename (k5_transport ttype) + { + static char buf[20]; +- switch (stype) { +- case SOCK_STREAM: +- return "stream"; +- case SOCK_DGRAM: +- return "dgram"; +- case SOCK_RAW: +- return "raw"; ++ switch (ttype) { ++ case TCP_OR_UDP: ++ return "tcp or udp"; ++ case TCP: ++ return "tcp"; ++ case UDP: ++ return "udp"; + default: +- snprintf(buf, sizeof(buf), "?%d", stype); ++ snprintf(buf, sizeof(buf), "?%d", ttype); + return buf; + } + } +@@ -58,7 +58,7 @@ print_addrs (void) + + if (entry->hostname != NULL) { + printf("%2d: host %s\t%s\tport %d\n", (int)i, entry->hostname, +- stypename(entry->socktype), ntohs(entry->port)); ++ ttypename(entry->transport), ntohs(entry->port)); + continue; + } + err = getnameinfo((struct sockaddr *)&entry->addr, entry->addrlen, +@@ -69,7 +69,7 @@ print_addrs (void) + gai_strerror(err)); + } else { + printf("%2d: address %s\t%s\tport %s\n", (int)i, hostbuf, +- stypename(entry->socktype), srvbuf); ++ ttypename(entry->transport), srvbuf); + } + } + } +@@ -129,7 +129,7 @@ main (int argc, char *argv[]) + break; + + case LOOKUP_WHATEVER: +- err = k5_locate_kdc(ctx, &realm, &sl, master, 0); ++ err = k5_locate_kdc(ctx, &realm, &sl, master, FALSE); + break; + } + if (err) kfatal (err); +diff --git a/src/lib/krb5/os/t_std_conf.c b/src/lib/krb5/os/t_std_conf.c +index e2ff572..6ee54d5 100644 +--- a/src/lib/krb5/os/t_std_conf.c ++++ b/src/lib/krb5/os/t_std_conf.c +@@ -82,7 +82,7 @@ test_locate_kdc(krb5_context ctx, char *realm) + + rlm.data = realm; + rlm.length = strlen(realm); +- retval = k5_locate_kdc(ctx, &rlm, &servers, get_masters, 0); ++ retval = k5_locate_kdc(ctx, &rlm, &servers, get_masters, FALSE); + if (retval) { + com_err("krb5_locate_kdc", retval, 0); + return; +diff --git a/src/lib/krb5/os/t_trace.c b/src/lib/krb5/os/t_trace.c +index 36044f5..4cb2bd0 100644 +--- a/src/lib/krb5/os/t_trace.c ++++ b/src/lib/krb5/os/t_trace.c +@@ -112,7 +112,7 @@ main (int argc, char *argv[]) + TRACE(ctx, "size_t and const char *, as four-character hex hash: " + "{hashlenstr}", 1, NULL); + +- ra.type = SOCK_STREAM; ++ ra.transport = TCP; + addr_in = (struct sockaddr_in *)&ra.saddr; + addr_in->sin_family = AF_INET; + addr_in->sin_addr.s_addr = INADDR_ANY; +@@ -121,10 +121,10 @@ main (int argc, char *argv[]) + ra.family = AF_INET; + TRACE(ctx, "struct remote_address *, show socket type, address, port: " + "{raddr}", &ra); +- ra.type = SOCK_DGRAM; ++ ra.transport = UDP; + TRACE(ctx, "struct remote_address *, show socket type, address, port: " + "{raddr}", &ra); +- ra.type = 1234; ++ ra.transport = 1234; + addr_in->sin_family = AF_UNSPEC; + ra.family = AF_UNSPEC; + TRACE(ctx, "struct remote_address *, show socket type, address, port: " +diff --git a/src/lib/krb5/os/t_trace.ref b/src/lib/krb5/os/t_trace.ref +index 749d9c9..ca5818a 100644 +--- a/src/lib/krb5/os/t_trace.ref ++++ b/src/lib/krb5/os/t_trace.ref +@@ -10,8 +10,8 @@ size_t and const char *, as four-character hex hash: 7B9A + size_t and const char *, as four-character hex hash: (null) + struct remote_address *, show socket type, address, port: stream 0.0.0.0:88 + struct remote_address *, show socket type, address, port: dgram 0.0.0.0:88 +-struct remote_address *, show socket type, address, port: socktype1234 AF_UNSPEC +-struct remote_address *, show socket type, address, port: socktype1234 af5678 ++struct remote_address *, show socket type, address, port: transport1234 AF_UNSPEC ++struct remote_address *, show socket type, address, port: transport1234 af5678 + krb5_data *, display as counted string: example.data + krb5_data *, display as counted string: (null) + krb5_data *, display as hex bytes: 6578616D706C652E64617461 +diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c +index 525742c..8319a86 100644 +--- a/src/lib/krb5/os/trace.c ++++ b/src/lib/krb5/os/trace.c +@@ -197,12 +197,12 @@ trace_format(krb5_context context, const char *fmt, va_list ap) + } + } else if (strcmp(tmpbuf, "raddr") == 0) { + ra = va_arg(ap, struct remote_address *); +- if (ra->type == SOCK_DGRAM) ++ if (ra->transport == UDP) + k5_buf_add(&buf, "dgram"); +- else if (ra->type == SOCK_STREAM) ++ else if (ra->transport == TCP) + k5_buf_add(&buf, "stream"); + else +- k5_buf_add_fmt(&buf, "socktype%d", ra->type); ++ k5_buf_add_fmt(&buf, "transport%d", ra->transport); + + if (getnameinfo((struct sockaddr *)&ra->saddr, ra->len, + addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), +-- +2.1.0 + diff --git a/SOURCES/0004-Build-support-for-TLS-used-by-HTTPS-proxy-support.patch b/SOURCES/0004-Build-support-for-TLS-used-by-HTTPS-proxy-support.patch new file mode 100644 index 0000000..df4707d --- /dev/null +++ b/SOURCES/0004-Build-support-for-TLS-used-by-HTTPS-proxy-support.patch @@ -0,0 +1,187 @@ +From d0be57ac45ea639baa3cff0dd2108c34e834bfa7 Mon Sep 17 00:00:00 2001 +From: "Robbie Harwood (frozencemetery)" +Date: Fri, 16 Aug 2013 12:45:03 -0400 +Subject: [PATCH 04/13] Build support for TLS used by HTTPS proxy support + +Add a --with-proxy-tls-impl option to configure, taking 'openssl', +'auto', or invocation as --without-proxy-tls-impl. Use related CFLAGS +when building lib/krb5/os, and LIBS when linking libkrb5. Call the +OpenSSL library startup functions during library initialization. + +ticket: 7929 +--- + src/Makefile.in | 1 + + src/config/pre.in | 5 +++++ + src/configure.in | 40 ++++++++++++++++++++++++++++++++++++++++ + src/lib/krb5/Makefile.in | 3 ++- + src/lib/krb5/krb5_libinit.c | 2 ++ + src/lib/krb5/os/Makefile.in | 2 +- + src/lib/krb5/os/os-proto.h | 1 + + src/lib/krb5/os/sendto_kdc.c | 14 ++++++++++++++ + 8 files changed, 66 insertions(+), 2 deletions(-) + +diff --git a/src/Makefile.in b/src/Makefile.in +index 1725093..5e2cf4e 100644 +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -553,6 +553,7 @@ pyrunenv.vals: Makefile + for i in $(RUN_VARS); do \ + eval echo 'env['\\\'$$i\\\''] = '\\\'\$$$$i\\\'; \ + done > $@ ++ echo "proxy_tls_impl = '$(PROXY_TLS_IMPL)'" >> $@ + + runenv.py: pyrunenv.vals + echo 'env = {}' > $@ +diff --git a/src/config/pre.in b/src/config/pre.in +index fbc5c11..e1d7e4b 100644 +--- a/src/config/pre.in ++++ b/src/config/pre.in +@@ -428,6 +428,11 @@ PKINIT_CRYPTO_IMPL = @PKINIT_CRYPTO_IMPL@ + PKINIT_CRYPTO_IMPL_CFLAGS = @PKINIT_CRYPTO_IMPL_CFLAGS@ + PKINIT_CRYPTO_IMPL_LIBS = @PKINIT_CRYPTO_IMPL_LIBS@ + ++# TLS implementation selection for HTTPS proxy support ++PROXY_TLS_IMPL = @PROXY_TLS_IMPL@ ++PROXY_TLS_IMPL_CFLAGS = @PROXY_TLS_IMPL_CFLAGS@ ++PROXY_TLS_IMPL_LIBS = @PROXY_TLS_IMPL_LIBS@ ++ + # error table rules + # + ### /* these are invoked as $(...) foo.et, which works, but could be better */ +diff --git a/src/configure.in b/src/configure.in +index 9bc4663..39e3738 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -272,6 +272,46 @@ AC_SUBST(PKINIT_CRYPTO_IMPL) + AC_SUBST(PKINIT_CRYPTO_IMPL_CFLAGS) + AC_SUBST(PKINIT_CRYPTO_IMPL_LIBS) + ++# WITH_PROXY_TLS_IMPL ++ ++AC_ARG_WITH([proxy-tls-impl], ++AC_HELP_STRING([--with-proxy-tls-impl=IMPL], ++ [use specified TLS implementation for HTTPS @<:@auto@:>@]), ++[PROXY_TLS_IMPL=$withval],[PROXY_TLS_IMPL=auto]) ++case "$PROXY_TLS_IMPL" in ++openssl|auto) ++ AC_CHECK_LIB(ssl,SSL_CTX_new,[have_lib_ssl=true],[have_lib_ssl=false], ++ -lcrypto) ++ AC_MSG_CHECKING([for OpenSSL]) ++ if test x$have_lib_ssl = xtrue ; then ++ AC_DEFINE(PROXY_TLS_IMPL_OPENSSL,1, ++ [Define if HTTPS TLS implementation is OpenSSL]) ++ AC_MSG_RESULT([yes]) ++ PROXY_TLS_IMPL_LIBS="-lssl -lcrypto" ++ PROXY_TLS_IMPL=openssl ++ AC_MSG_NOTICE(HTTPS support will use TLS from '$PROXY_TLS_IMPL') ++ else ++ if test "$PROXY_TLS_IMPL" = openssl ; then ++ AC_MSG_ERROR([OpenSSL not found!]) ++ else ++ AC_MSG_WARN([OpenSSL not found!]) ++ fi ++ PROXY_TLS_IMPL=no ++ AC_MSG_NOTICE(building without HTTPS support) ++ fi ++ ;; ++no) ++ AC_MSG_NOTICE(building without HTTPS support) ++ ;; ++*) ++ AC_MSG_ERROR([Unsupported HTTPS proxy TLS implementation $withval]) ++ ;; ++esac ++ ++AC_SUBST(PROXY_TLS_IMPL) ++AC_SUBST(PROXY_TLS_IMPL_CFLAGS) ++AC_SUBST(PROXY_TLS_IMPL_LIBS) ++ + AC_ARG_ENABLE([aesni], + AC_HELP_STRING([--disable-aesni],[Do not build with AES-NI support]), , + enable_aesni=check) +diff --git a/src/lib/krb5/Makefile.in b/src/lib/krb5/Makefile.in +index d9cddc1..472c008 100644 +--- a/src/lib/krb5/Makefile.in ++++ b/src/lib/krb5/Makefile.in +@@ -56,7 +56,8 @@ RELDIR=krb5 + SHLIB_EXPDEPS = \ + $(TOPLIBD)/libk5crypto$(SHLIBEXT) \ + $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB) +-SHLIB_EXPLIBS=-lk5crypto -lcom_err $(SUPPORT_LIB) @GEN_LIB@ $(LIBS) ++SHLIB_EXPLIBS=-lk5crypto -lcom_err $(PROXY_TLS_IMPL_LIBS) $(SUPPORT_LIB) \ ++ @GEN_LIB@ $(LIBS) + + all-unix:: all-liblinks + +diff --git a/src/lib/krb5/krb5_libinit.c b/src/lib/krb5/krb5_libinit.c +index f83d25b..f2382d1 100644 +--- a/src/lib/krb5/krb5_libinit.c ++++ b/src/lib/krb5/krb5_libinit.c +@@ -58,6 +58,8 @@ int krb5int_lib_init(void) + if (err) + return err; + ++ k5_sendto_kdc_initialize(); ++ + return 0; + } + +diff --git a/src/lib/krb5/os/Makefile.in b/src/lib/krb5/os/Makefile.in +index 5add9f9..fb4001a 100644 +--- a/src/lib/krb5/os/Makefile.in ++++ b/src/lib/krb5/os/Makefile.in +@@ -2,7 +2,7 @@ mydir=lib$(S)krb5$(S)os + BUILDTOP=$(REL)..$(S)..$(S).. + DEFINES=-DLIBDIR=\"$(KRB5_LIBDIR)\" -DBINDIR=\"$(CLIENT_BINDIR)\" \ + -DSBINDIR=\"$(ADMIN_BINDIR)\" +-LOCALINCLUDES=-I$(top_srcdir)/util/profile ++LOCALINCLUDES= $(PROXY_TLS_IMPL_CFLAGS) -I$(top_srcdir)/util/profile + + ##DOS##BUILDTOP = ..\..\.. + ##DOS##PREFIXDIR=os +diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h +index 3196bca..f23dda5 100644 +--- a/src/lib/krb5/os/os-proto.h ++++ b/src/lib/krb5/os/os-proto.h +@@ -184,5 +184,6 @@ krb5_error_code localauth_k5login_initvt(krb5_context context, int maj_ver, + krb5_plugin_vtable vtable); + krb5_error_code localauth_an2ln_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable); ++void k5_sendto_kdc_initialize(void); + + #endif /* KRB5_LIBOS_INT_PROTO__ */ +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index 3f99ce8..c6aae8e 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -48,6 +48,10 @@ + #endif + #endif + ++#ifdef PROXY_TLS_IMPL_OPENSSL ++#include ++#endif ++ + #define MAX_PASS 3 + #define DEFAULT_UDP_PREF_LIMIT 1465 + #define HARD_UDP_LIMIT 32700 /* could probably do 64K-epsilon ? */ +@@ -107,6 +111,16 @@ struct conn_state { + krb5_boolean defer; + }; + ++void ++k5_sendto_kdc_initialize(void) ++{ ++#ifdef PROXY_TLS_IMPL_OPENSSL ++ SSL_library_init(); ++ SSL_load_error_strings(); ++ OpenSSL_add_all_algorithms(); ++#endif ++} ++ + /* Get current time in milliseconds. */ + static krb5_error_code + get_curtime_ms(time_ms *time_out) +-- +2.1.0 + diff --git a/SOURCES/0004-Don-t-leak-the-per-request-preauth-context.patch b/SOURCES/0004-Don-t-leak-the-per-request-preauth-context.patch deleted file mode 100644 index f6d3258..0000000 --- a/SOURCES/0004-Don-t-leak-the-per-request-preauth-context.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 37fd72ac18648155bb4715ac6afd40f471ba01fa Mon Sep 17 00:00:00 2001 -From: Nalin Dahyabhai -Date: Tue, 11 Mar 2014 13:33:23 -0400 -Subject: [PATCH 4/4] Don't leak the per-request preauth context - ---- - src/lib/krb5/krb/get_in_tkt.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c -index ebd2844..ebcb362 100644 ---- a/src/lib/krb5/krb/get_in_tkt.c -+++ b/src/lib/krb5/krb/get_in_tkt.c -@@ -488,6 +488,7 @@ krb5_init_creds_free(krb5_context context, - k5_response_items_free(ctx->rctx.items); - free(ctx->in_tkt_service); - zapfree(ctx->gakpw.storage.data, ctx->gakpw.storage.length); -+ krb5_preauth_request_context_fini(context); - krb5_free_error(context, ctx->err_reply); - krb5_free_pa_data(context, ctx->err_padata); - krb5_free_cred_contents(context, &ctx->cred); --- -1.9.0 - diff --git a/SOURCES/0004-Make-ksu-respect-the-default_ccache_name-setting.patch b/SOURCES/0004-Make-ksu-respect-the-default_ccache_name-setting.patch new file mode 100644 index 0000000..cb45f1b --- /dev/null +++ b/SOURCES/0004-Make-ksu-respect-the-default_ccache_name-setting.patch @@ -0,0 +1,378 @@ +From 3a456898af626dcab4e1ab0749ca2ccb9ad6162b Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Wed, 30 Oct 2013 21:47:14 -0400 +Subject: [PATCH 4/7] Make ksu respect the default_ccache_name setting + +Move the logic for resolving and initializing a cache that we're +copying creds into out of krb5_ccache_copy(), and let the caller deal +with it. Add a helper functions to select/resolve an output ccache in +the default location for the target user after we've switched to the +target user's privileges. If the destination is a collection, take +care not to change which subsidiary is its primary, and reuse a +subsidiary cache if we can. If the destination is not a collection, +append a unique value to its name to make a new ccache. + +[ghudson@mit.edu: some changes to variable names and comments; move +responsibility for getting target ccache name from +resolve_target_ccache to main] + +ticket: 7984 (new) +--- + src/clients/ksu/ccache.c | 35 +++------ + src/clients/ksu/ksu.h | 6 +- + src/clients/ksu/main.c | 181 ++++++++++++++++++++++++++++++++++++++--------- + 3 files changed, 157 insertions(+), 65 deletions(-) + +diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c +index d0fc389..4693bd4 100644 +--- a/src/clients/ksu/ccache.c ++++ b/src/clients/ksu/ccache.c +@@ -46,59 +46,41 @@ void show_credential(); + with k5 beta 3 release. + */ + +-krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, +- primary_principal, restrict_creds, +- target_principal, cc_out, stored, target_uid) ++krb5_error_code krb5_ccache_copy(context, cc_def, target_principal, cc_target, ++ restrict_creds, primary_principal, stored) + /* IN */ + krb5_context context; + krb5_ccache cc_def; +- char *cc_other_tag; +- krb5_principal primary_principal; +- krb5_boolean restrict_creds; + krb5_principal target_principal; +- uid_t target_uid; ++ krb5_ccache cc_target; ++ krb5_boolean restrict_creds; ++ krb5_principal primary_principal; + /* OUT */ +- krb5_ccache *cc_out; + krb5_boolean *stored; + { + int i=0; +- krb5_ccache * cc_other; + krb5_error_code retval=0; + krb5_creds ** cc_def_creds_arr = NULL; + krb5_creds ** cc_other_creds_arr = NULL; + +- cc_other = (krb5_ccache *) xcalloc(1, sizeof (krb5_ccache)); +- +- if ((retval = krb5_cc_resolve(context, cc_other_tag, cc_other))){ +- com_err(prog_name, retval, _("resolving ccache %s"), cc_other_tag); +- return retval; +- } +- + if (ks_ccache_is_initialized(context, cc_def)) { + if((retval = krb5_get_nonexp_tkts(context,cc_def,&cc_def_creds_arr))){ + return retval; + } + } + +- if (ks_ccache_name_is_initialized(context, cc_other_tag)) +- return EINVAL; +- +- if (krb5_seteuid(0)||krb5_seteuid(target_uid)) { +- return errno; +- } +- +- retval = krb5_cc_initialize(context, *cc_other, target_principal); ++ retval = krb5_cc_initialize(context, cc_target, target_principal); + if (retval) + return retval; + + if (restrict_creds) { +- retval = krb5_store_some_creds(context, *cc_other, cc_def_creds_arr, ++ retval = krb5_store_some_creds(context, cc_target, cc_def_creds_arr, + cc_other_creds_arr, primary_principal, + stored); + } else { + *stored = krb5_find_princ_in_cred_list(context, cc_def_creds_arr, + primary_principal); +- retval = krb5_store_all_creds(context, *cc_other, cc_def_creds_arr, ++ retval = krb5_store_all_creds(context, cc_target, cc_def_creds_arr, + cc_other_creds_arr); + } + +@@ -118,7 +100,6 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, + } + } + +- *cc_out = *cc_other; + return retval; + } + +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index 08bf01b..fbbf217 100644 +--- a/src/clients/ksu/ksu.h ++++ b/src/clients/ksu/ksu.h +@@ -44,8 +44,6 @@ + #define KRB5_DEFAULT_OPTIONS 0 + #define KRB5_DEFAULT_TKT_LIFE 60*60*12 /* 12 hours */ + +-#define KRB5_SECONDARY_CACHE "FILE:/tmp/krb5cc_" +- + #define KRB5_LOGIN_NAME ".k5login" + #define KRB5_USERS_NAME ".k5users" + #define USE_DEFAULT_REALM_NAME "." +@@ -106,8 +104,8 @@ 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_principal, krb5_ccache *, krb5_boolean *, uid_t); ++(krb5_context, krb5_ccache, krb5_principal, krb5_ccache, ++ krb5_boolean, krb5_principal, krb5_boolean *); + + 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 d1bb8ca..41a3bf8 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -54,6 +54,10 @@ static void print_status( const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 1, 2))) + #endif + ; ++static krb5_error_code resolve_target_cache(krb5_context ksu_context, ++ krb5_principal princ, ++ krb5_ccache *ccache_out, ++ krb5_boolean *ccache_reused); + + /* Note -e and -a options are mutually exclusive */ + /* insure the proper specification of target user as well as catching +@@ -112,7 +116,7 @@ main (argc, argv) + extern char * getpass(), *crypt(); + int pargc; + char ** pargv; +- krb5_boolean stored = FALSE; ++ krb5_boolean stored = FALSE, cc_reused = FALSE; + krb5_principal kdc_server; + krb5_boolean zero_password; + krb5_boolean restrict_creds; +@@ -416,23 +420,8 @@ main (argc, argv) + exit(1); + } + +- /* +- * 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. +- */ +- cc_target_tag = (char *)xcalloc(KRB5_SEC_BUFFSIZE, sizeof(char)); +- do { +- snprintf(cc_target_tag, KRB5_SEC_BUFFSIZE, "%s%ld.%d", +- KRB5_SECONDARY_CACHE, +- (long)target_uid, gen_sym()); +- } while (ks_ccache_name_is_initialized(ksu_context, cc_target_tag)); +- +- if (auth_debug){ ++ if (auth_debug) + fprintf(stderr, " source cache = %s\n", cc_source_tag); +- fprintf(stderr, " target cache = %s\n", cc_target_tag); +- } + + /* + * After proper authentication and authorization, populate a cache for the +@@ -455,14 +444,19 @@ main (argc, argv) + com_err(prog_name, retval, _("while parsing temporary name")); + exit(1); + } +- retval = krb5_ccache_copy(ksu_context, cc_source, KS_TEMPORARY_CACHE, +- client, restrict_creds, tmp_princ, &cc_tmp, +- &stored, 0); ++ retval = krb5_cc_resolve(ksu_context, KS_TEMPORARY_CACHE, &cc_tmp); ++ if (retval) { ++ com_err(prog_name, retval, _("while creating temporary cache")); ++ exit(1); ++ } ++ retval = krb5_ccache_copy(ksu_context, cc_source, tmp_princ, cc_tmp, ++ restrict_creds, client, &stored); + if (retval) { + com_err(prog_name, retval, _("while copying cache %s to %s"), + krb5_cc_get_name(ksu_context, cc_source), KS_TEMPORARY_CACHE); + exit(1); + } ++ krb5_cc_close(ksu_context, cc_source); + + /* Become root for authentication*/ + +@@ -686,23 +680,38 @@ main (argc, argv) + exit(1); + } + +- retval = krb5_ccache_copy(ksu_context, cc_tmp, cc_target_tag, +- client, FALSE, client, &cc_target, &stored, +- target_pwd->pw_uid); ++ retval = resolve_target_cache(ksu_context, client, &cc_target, &cc_reused); ++ if (retval) ++ exit(1); ++ retval = krb5_cc_get_full_name(ksu_context, cc_target, &cc_target_tag); + if (retval) { +- com_err(prog_name, retval, _("while copying cache %s to %s"), +- KS_TEMPORARY_CACHE, cc_target_tag); ++ com_err(prog_name, retval, _("while getting name of target ccache")); ++ sweep_up(ksu_context, cc_target); + exit(1); + } ++ if (auth_debug) ++ fprintf(stderr, " target cache = %s\n", cc_target_tag); ++ if (cc_reused) ++ keep_target_cache = TRUE; + +- if (stored && !ks_ccache_is_initialized(ksu_context, cc_target)) { +- com_err(prog_name, errno, +- _("%s does not have correct permissions for %s, %s aborted"), +- target_user, cc_target_tag, prog_name); +- exit(1); ++ if (stored) { ++ retval = krb5_ccache_copy(ksu_context, cc_tmp, client, cc_target, ++ FALSE, client, &stored); ++ if (retval) { ++ com_err(prog_name, retval, _("while copying cache %s to %s"), ++ KS_TEMPORARY_CACHE, cc_target_tag); ++ exit(1); ++ } ++ ++ if (!ks_ccache_is_initialized(ksu_context, cc_target)) { ++ com_err(prog_name, errno, ++ _("%s does not have correct permissions for %s, " ++ "%s aborted"), target_user, cc_target_tag, prog_name); ++ exit(1); ++ } + } + +- free(cc_target_tag); ++ krb5_free_string(ksu_context, cc_target_tag); + + /* Set the cc env name to target. */ + retval = set_ccname_env(ksu_context, cc_target); +@@ -711,9 +720,6 @@ main (argc, argv) + exit(1); + } + +- if ( cc_source) +- krb5_cc_close(ksu_context, cc_source); +- + if (cmd){ + if ((source_uid == 0) || (source_uid == target_uid )){ + exec_cmd = cmd; +@@ -803,6 +809,113 @@ set_ccname_env(krb5_context ksu_context, krb5_ccache ccache) + return retval; + } + ++/* ++ * Get the configured default ccache name. Unset KRB5CCNAME and force a ++ * recomputation so we don't use values for the source user. Print an error ++ * message on failure. ++ */ ++static krb5_error_code ++get_configured_defccname(krb5_context context, char **target_out) ++{ ++ krb5_error_code retval; ++ const char *defname; ++ char *target; ++ ++ *target_out = NULL; ++ ++ if (unsetenv(KRB5_ENV_CCNAME) != 0) { ++ retval = errno; ++ com_err(prog_name, retval, _("while clearing the value of %s"), ++ KRB5_ENV_CCNAME); ++ return retval; ++ } ++ ++ /* Make sure we don't have a cached value for a different uid. */ ++ retval = krb5_cc_set_default_name(context, NULL); ++ if (retval != 0) { ++ com_err(prog_name, retval, _("while resetting target ccache name")); ++ return retval; ++ } ++ ++ defname = krb5_cc_default_name(context); ++ target = (defname == NULL) ? NULL : strdup(defname); ++ if (target == NULL) { ++ com_err(prog_name, ENOMEM, _("while determining target ccache name")); ++ return ENOMEM; ++ } ++ *target_out = target; ++ return 0; ++} ++ ++/* Determine where the target user's creds should be stored. Print an error ++ * message on failure. */ ++static krb5_error_code ++resolve_target_cache(krb5_context context, krb5_principal princ, ++ krb5_ccache *ccache_out, krb5_boolean *ccache_reused) ++{ ++ krb5_error_code retval; ++ krb5_boolean switchable, reused = FALSE; ++ krb5_ccache ccache = NULL; ++ char *sep, *ccname = NULL, *target; ++ ++ *ccache_out = NULL; ++ *ccache_reused = FALSE; ++ ++ retval = get_configured_defccname(context, &target); ++ if (retval != 0) ++ return retval; ++ ++ /* Check if the configured default name uses a switchable type. */ ++ sep = strchr(target, ':'); ++ *sep = '\0'; ++ switchable = krb5_cc_support_switch(context, target); ++ *sep = ':'; ++ ++ if (!switchable) { ++ /* Try to avoid destroying an in-use target ccache by coming up with ++ * the name of a cache that doesn't exist yet. */ ++ do { ++ free(ccname); ++ if (asprintf(&ccname, "%s.%d", target, gen_sym()) < 0) { ++ retval = ENOMEM; ++ com_err(prog_name, ENOMEM, ++ _("while allocating memory for target ccache name")); ++ goto cleanup; ++ } ++ } while (ks_ccache_name_is_initialized(context, ccname)); ++ retval = krb5_cc_resolve(context, ccname, &ccache); ++ } else { ++ /* Look for a cache in the collection that we can reuse. */ ++ retval = krb5_cc_cache_match(context, princ, &ccache); ++ if (retval == 0) { ++ reused = TRUE; ++ } else { ++ /* There isn't one, so create a new one. */ ++ *sep = '\0'; ++ retval = krb5_cc_new_unique(context, target, NULL, &ccache); ++ *sep = ':'; ++ if (retval) { ++ com_err(prog_name, retval, ++ _("while creating new target ccache")); ++ goto cleanup; ++ } ++ retval = krb5_cc_initialize(context, ccache, princ); ++ if (retval) { ++ com_err(prog_name, retval, ++ _("while initializing target cache")); ++ goto cleanup; ++ } ++ } ++ } ++ ++ *ccache_out = ccache; ++ *ccache_reused = reused; ++ ++cleanup: ++ free(target); ++ return retval; ++} ++ + #ifdef HAVE_GETUSERSHELL + + int standard_shell(sh) +-- +2.0.4 + 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 deleted file mode 100644 index b822a09..0000000 --- a/SOURCES/0004-Try-to-use-the-default_ccache_name-d-as-the-target.patch +++ /dev/null @@ -1,149 +0,0 @@ -From d0a3250bd384b5dd524f102f97c9c1edc1fe00fb 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-Add-ASN.1-codec-for-KKDCP-s-KDC-PROXY-MESSAGE.patch b/SOURCES/0005-Add-ASN.1-codec-for-KKDCP-s-KDC-PROXY-MESSAGE.patch new file mode 100644 index 0000000..f650d69 --- /dev/null +++ b/SOURCES/0005-Add-ASN.1-codec-for-KKDCP-s-KDC-PROXY-MESSAGE.patch @@ -0,0 +1,352 @@ +From bb89afd7c59deea855d2818fe36ef7472b4abf2e Mon Sep 17 00:00:00 2001 +From: Nathaniel McCallum +Date: Mon, 9 Sep 2013 14:23:56 -0400 +Subject: [PATCH 05/13] Add ASN.1 codec for KKDCP's KDC-PROXY-MESSAGE + +Handle encoding and decoding [MS-KKDCP] proxy messages, including +handling of the additional length bytes. Early versions of [MS-KKDCP] +incorrectly omit that the size of the proxied message is prepended to +the proxied message, as it is when we're using plain TCP, before +encoding the proxy-message structure. This is fixed at least as of +version 2.1 of the spec. + +[nalin@redhat.com: add tests] + +ticket: 7929 +--- + src/include/k5-int.h | 13 +++++++++++++ + src/lib/krb5/asn.1/asn1_k_encode.c | 14 ++++++++++++++ + src/lib/krb5/krb/kfree.c | 10 ++++++++++ + src/lib/krb5/libkrb5.exports | 3 +++ + src/tests/asn.1/krb5_decode_test.c | 18 ++++++++++++++++++ + src/tests/asn.1/krb5_encode_test.c | 8 ++++++++ + src/tests/asn.1/ktest.c | 23 ++++++++++++++++++++++ + src/tests/asn.1/ktest.h | 5 +++++ + src/tests/asn.1/ktest_equal.c | 12 ++++++++++++ + src/tests/asn.1/ktest_equal.h | 3 +++ + src/tests/asn.1/reference_encode.out | 1 + + src/tests/asn.1/trval_reference.out | 37 ++++++++++++++++++++++++++++++++++++ + 12 files changed, 147 insertions(+) + +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index 096cd14..8f039ee 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -518,6 +518,12 @@ typedef struct _krb5_pa_otp_req { + krb5_data vendor; + } krb5_pa_otp_req; + ++typedef struct _krb5_kkdcp_message { ++ krb5_data kerb_message; ++ krb5_data target_domain; ++ krb5_int32 dclocator_hint; ++} krb5_kkdcp_message; ++ + #include + #include + +@@ -898,6 +904,7 @@ void k5_free_otp_tokeninfo(krb5_context context, krb5_otp_tokeninfo *val); + void k5_free_pa_otp_challenge(krb5_context context, + krb5_pa_otp_challenge *val); + void k5_free_pa_otp_req(krb5_context context, krb5_pa_otp_req *val); ++void k5_free_kkdcp_message(krb5_context context, krb5_kkdcp_message *val); + + /* #include "krb5/wordsize.h" -- comes in through base-defs.h. */ + #include "com_err.h" +@@ -1438,6 +1445,9 @@ encode_krb5_pa_otp_req(const krb5_pa_otp_req *, krb5_data **); + krb5_error_code + encode_krb5_pa_otp_enc_req(const krb5_data *, krb5_data **); + ++krb5_error_code ++encode_krb5_kkdcp_message(const krb5_kkdcp_message *, krb5_data **); ++ + /************************************************************************* + * End of prototypes for krb5_encode.c + *************************************************************************/ +@@ -1608,6 +1618,9 @@ decode_krb5_pa_otp_req(const krb5_data *, krb5_pa_otp_req **); + krb5_error_code + decode_krb5_pa_otp_enc_req(const krb5_data *, krb5_data **); + ++krb5_error_code ++decode_krb5_kkdcp_message(const krb5_data *, krb5_kkdcp_message **); ++ + struct _krb5_key_data; /* kdb.h */ + + struct ldap_seqof_key_data { +diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c +index 7b9179d..4dc49c2 100644 +--- a/src/lib/krb5/asn.1/asn1_k_encode.c ++++ b/src/lib/krb5/asn.1/asn1_k_encode.c +@@ -1711,3 +1711,17 @@ static const struct atype_info *pa_otp_enc_req_fields[] = { + }; + DEFSEQTYPE(pa_otp_enc_req, krb5_data, pa_otp_enc_req_fields); + MAKE_CODEC(krb5_pa_otp_enc_req, pa_otp_enc_req); ++ ++DEFFIELD(kkdcp_message_0, krb5_kkdcp_message, ++ kerb_message, 0, ostring_data); ++DEFFIELD(kkdcp_message_1, krb5_kkdcp_message, ++ target_domain, 1, opt_gstring_data); ++DEFFIELD(kkdcp_message_2, krb5_kkdcp_message, ++ dclocator_hint, 2, opt_int32); ++static const struct atype_info *kkdcp_message_fields[] = { ++ &k5_atype_kkdcp_message_0, &k5_atype_kkdcp_message_1, ++ &k5_atype_kkdcp_message_2 ++}; ++DEFSEQTYPE(kkdcp_message, krb5_kkdcp_message, ++ kkdcp_message_fields); ++MAKE_CODEC(krb5_kkdcp_message, kkdcp_message); +diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c +index 32b2151..f86c619 100644 +--- a/src/lib/krb5/krb/kfree.c ++++ b/src/lib/krb5/krb/kfree.c +@@ -821,3 +821,13 @@ k5_free_pa_otp_req(krb5_context context, krb5_pa_otp_req *val) + free(val->vendor.data); + free(val); + } ++ ++void ++k5_free_kkdcp_message(krb5_context context, krb5_kkdcp_message *val) ++{ ++ if (val == NULL) ++ return; ++ free(val->target_domain.data); ++ free(val->kerb_message.data); ++ free(val); ++} +diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports +index 863ec02..2d0852d 100644 +--- a/src/lib/krb5/libkrb5.exports ++++ b/src/lib/krb5/libkrb5.exports +@@ -25,6 +25,7 @@ decode_krb5_iakerb_finished + decode_krb5_iakerb_header + decode_krb5_kdc_req_body + decode_krb5_otp_tokeninfo ++decode_krb5_kkdcp_message + decode_krb5_pa_enc_ts + decode_krb5_pa_for_user + decode_krb5_pa_fx_fast_reply +@@ -72,6 +73,7 @@ encode_krb5_iakerb_finished + encode_krb5_iakerb_header + encode_krb5_kdc_req_body + encode_krb5_otp_tokeninfo ++encode_krb5_kkdcp_message + encode_krb5_pa_enc_ts + encode_krb5_pa_for_user + encode_krb5_pa_fx_fast_reply +@@ -113,6 +115,7 @@ k5_expand_path_tokens + k5_expand_path_tokens_extra + k5_free_algorithm_identifier + k5_free_otp_tokeninfo ++k5_free_kkdcp_message + k5_free_pa_otp_challenge + k5_free_pa_otp_req + k5_free_serverlist +diff --git a/src/tests/asn.1/krb5_decode_test.c b/src/tests/asn.1/krb5_decode_test.c +index 8719978..f12bb16 100644 +--- a/src/tests/asn.1/krb5_decode_test.c ++++ b/src/tests/asn.1/krb5_decode_test.c +@@ -54,6 +54,8 @@ static void ktest_free_reply_key_pack(krb5_context context, + static void ktest_free_reply_key_pack_draft9(krb5_context context, + krb5_reply_key_pack_draft9 *val); + #endif ++static void ktest_free_kkdcp_message(krb5_context context, ++ krb5_kkdcp_message *val); + + int main(argc, argv) + int argc; +@@ -1077,6 +1079,13 @@ int main(argc, argv) + ktest_empty_data(&ref); + } + ++ /****************************************************************/ ++ /* decode_krb5_kkdcp_message */ ++ { ++ setup(krb5_kkdcp_message,ktest_make_sample_kkdcp_message); ++ decode_run("kkdcp_message","","30 82 01 FC A0 82 01 EC 04 82 01 E8 6A 82 01 E4 30 82 01 E0 A1 03 02 01 05 A2 03 02 01 0A A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A4 82 01 AA 30 82 01 A6 A0 07 03 05 00 FE DC BA 98 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 A9 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 AA 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A1 0A 1B 08 6B 72 62 35 64 61 74 61",decode_krb5_kkdcp_message,ktest_equal_kkdcp_message,ktest_free_kkdcp_message); ++ } ++ + #ifndef DISABLE_PKINIT + + /****************************************************************/ +@@ -1262,3 +1271,12 @@ ktest_free_reply_key_pack_draft9(krb5_context context, + } + + #endif /* not DISABLE_PKINIT */ ++ ++static void ++ktest_free_kkdcp_message(krb5_context context, ++ krb5_kkdcp_message *val) ++{ ++ if (val) ++ ktest_empty_kkdcp_message(val); ++ free(val); ++} +diff --git a/src/tests/asn.1/krb5_encode_test.c b/src/tests/asn.1/krb5_encode_test.c +index 638f6fe..3ba8684 100644 +--- a/src/tests/asn.1/krb5_encode_test.c ++++ b/src/tests/asn.1/krb5_encode_test.c +@@ -734,6 +734,14 @@ main(argc, argv) + encode_run(d, "pa_otp_enc_req", "", encode_krb5_pa_otp_enc_req); + ktest_empty_data(&d); + } ++ /****************************************************************/ ++ /* encode_krb5_kkdcp_message */ ++ { ++ krb5_kkdcp_message info; ++ ktest_make_sample_kkdcp_message(&info); ++ encode_run(info, "kkdcp_message", "", encode_krb5_kkdcp_message); ++ ktest_empty_kkdcp_message(&info); ++ } + #ifndef DISABLE_PKINIT + /****************************************************************/ + /* encode_krb5_pa_pk_as_req */ +diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c +index aa41fd8..4ce9f70 100644 +--- a/src/tests/asn.1/ktest.c ++++ b/src/tests/asn.1/ktest.c +@@ -933,6 +933,21 @@ ktest_make_sample_ldap_seqof_key_data(ldap_seqof_key_data *p) + } + #endif + ++void ++ktest_make_sample_kkdcp_message(krb5_kkdcp_message *p) ++{ ++ krb5_kdc_req req; ++ krb5_data *message; ++ ++ ktest_make_sample_kdc_req(&req); ++ req.msg_type = KRB5_AS_REQ; ++ encode_krb5_as_req(&req, &message); ++ p->kerb_message = *message; ++ free(message); ++ ktest_empty_kdc_req(&req); ++ ktest_make_sample_data(&(p->target_domain)); ++ p->dclocator_hint = 0; ++} + + /****************************************************************/ + /* destructors */ +@@ -1731,3 +1746,11 @@ ktest_empty_ldap_seqof_key_data(krb5_context ctx, ldap_seqof_key_data *p) + free(p->key_data); + } + #endif ++ ++void ++ktest_empty_kkdcp_message(krb5_kkdcp_message *p) ++{ ++ ktest_empty_data(&p->kerb_message); ++ ktest_empty_data(&p->target_domain); ++ p->dclocator_hint = -1; ++} +diff --git a/src/tests/asn.1/ktest.h b/src/tests/asn.1/ktest.h +index 67a6c69..a9ebb77 100644 +--- a/src/tests/asn.1/ktest.h ++++ b/src/tests/asn.1/ktest.h +@@ -119,6 +119,9 @@ void ktest_make_sample_pkinit_supp_pub_info(krb5_pkinit_supp_pub_info *p); + #ifdef ENABLE_LDAP + void ktest_make_sample_ldap_seqof_key_data(ldap_seqof_key_data *p); + #endif ++ ++void ktest_make_sample_kkdcp_message(krb5_kkdcp_message *p); ++ + /*----------------------------------------------------------------------*/ + + void ktest_empty_authorization_data(krb5_authdata **ad); +@@ -200,6 +203,8 @@ void ktest_empty_pkinit_supp_pub_info(krb5_pkinit_supp_pub_info *p); + void ktest_empty_ldap_seqof_key_data(krb5_context, ldap_seqof_key_data *p); + #endif + ++void ktest_empty_kkdcp_message(krb5_kkdcp_message *p); ++ + extern krb5_context test_context; + extern char *sample_principal_name; + +diff --git a/src/tests/asn.1/ktest_equal.c b/src/tests/asn.1/ktest_equal.c +index 4e71242..39c35b5 100644 +--- a/src/tests/asn.1/ktest_equal.c ++++ b/src/tests/asn.1/ktest_equal.c +@@ -1039,3 +1039,15 @@ ktest_equal_reply_key_pack_draft9(krb5_reply_key_pack_draft9 *ref, + } + + #endif /* not DISABLE_PKINIT */ ++ ++int ++ktest_equal_kkdcp_message(krb5_kkdcp_message *ref, krb5_kkdcp_message *var) ++{ ++ int p = TRUE; ++ if (ref == var) return TRUE; ++ else if (ref == NULL || var == NULL) return FALSE; ++ p = p && data_eq(ref->kerb_message, var->kerb_message); ++ p = p && data_eq(ref->target_domain, var->target_domain); ++ p = p && (ref->dclocator_hint == var->dclocator_hint); ++ return p; ++} +diff --git a/src/tests/asn.1/ktest_equal.h b/src/tests/asn.1/ktest_equal.h +index e75f86a..491653f 100644 +--- a/src/tests/asn.1/ktest_equal.h ++++ b/src/tests/asn.1/ktest_equal.h +@@ -145,4 +145,7 @@ generic(ktest_equal_reply_key_pack, krb5_reply_key_pack); + generic(ktest_equal_reply_key_pack_draft9, krb5_reply_key_pack_draft9); + #endif /* not DISABLE_PKINIT */ + ++int ktest_equal_kkdcp_message(krb5_kkdcp_message *ref, ++ krb5_kkdcp_message *var); ++ + #endif +diff --git a/src/tests/asn.1/reference_encode.out b/src/tests/asn.1/reference_encode.out +index 315e25b..b737da3 100644 +--- a/src/tests/asn.1/reference_encode.out ++++ b/src/tests/asn.1/reference_encode.out +@@ -68,3 +68,4 @@ encode_krb5_pa_otp_challenge: 30 81 A5 80 08 6D 61 78 6E 6F 6E 63 65 81 0B 74 65 + encode_krb5_pa_otp_req(optionals NULL): 30 2C 80 05 00 00 00 00 00 A2 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 + encode_krb5_pa_otp_req: 30 81 B9 80 05 00 60 00 00 00 81 05 6E 6F 6E 63 65 A2 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A3 0B 06 09 60 86 48 01 65 03 04 02 01 84 02 03 E8 85 05 66 72 6F 67 73 86 0A 6D 79 66 69 72 73 74 70 69 6E 87 05 68 61 72 6B 21 88 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A 89 03 33 34 36 8A 01 02 8B 09 79 6F 75 72 74 6F 6B 65 6E 8C 28 75 72 6E 3A 69 65 74 66 3A 70 61 72 61 6D 73 3A 78 6D 6C 3A 6E 73 3A 6B 65 79 70 72 6F 76 3A 70 73 6B 63 3A 68 6F 74 70 8D 0B 45 78 61 6D 70 6C 65 63 6F 72 70 + encode_krb5_pa_otp_enc_req: 30 0A 80 08 6B 72 62 35 64 61 74 61 ++encode_krb5_kkdcp_message: 30 82 01 FC A0 82 01 EC 04 82 01 E8 6A 82 01 E4 30 82 01 E0 A1 03 02 01 05 A2 03 02 01 0A A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A4 82 01 AA 30 82 01 A6 A0 07 03 05 00 FE DC BA 98 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 A9 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 AA 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A1 0A 1B 08 6B 72 62 35 64 61 74 61 +diff --git a/src/tests/asn.1/trval_reference.out b/src/tests/asn.1/trval_reference.out +index 461021e..599580c 100644 +--- a/src/tests/asn.1/trval_reference.out ++++ b/src/tests/asn.1/trval_reference.out +@@ -1478,3 +1478,40 @@ encode_krb5_pa_otp_enc_req: + [Sequence/Sequence Of] + . [0] <8> + 6b 72 62 35 64 61 74 61 krb5data ++ ++encode_krb5_kkdcp_message: ++ ++[Sequence/Sequence Of] ++. [0] [Octet String] <488> ++ 6a 82 01 e4 30 82 01 e0 a1 03 02 01 05 a2 03 02 j...0........... ++ 01 0a a3 26 30 24 30 10 a1 03 02 01 0d a2 09 04 ...&0$0......... ++ 07 70 61 2d 64 61 74 61 30 10 a1 03 02 01 0d a2 .pa-data0....... ++ 09 04 07 70 61 2d 64 61 74 61 a4 82 01 aa 30 82 ...pa-data....0. ++ 01 a6 a0 07 03 05 00 fe dc ba 98 a1 1a 30 18 a0 .............0.. ++ 03 02 01 01 a1 11 30 0f 1b 06 68 66 74 73 61 69 ......0...hftsai ++ 1b 05 65 78 74 72 61 a2 10 1b 0e 41 54 48 45 4e ..extra....ATHEN ++ 41 2e 4d 49 54 2e 45 44 55 a3 1a 30 18 a0 03 02 A.MIT.EDU..0.... ++ 01 01 a1 11 30 0f 1b 06 68 66 74 73 61 69 1b 05 ....0...hftsai.. ++ 65 78 74 72 61 a4 11 18 0f 31 39 39 34 30 36 31 extra....1994061 ++ 30 30 36 30 33 31 37 5a a5 11 18 0f 31 39 39 34 0060317Z....1994 ++ 30 36 31 30 30 36 30 33 31 37 5a a6 11 18 0f 31 0610060317Z....1 ++ 39 39 34 30 36 31 30 30 36 30 33 31 37 5a a7 03 9940610060317Z.. ++ 02 01 2a a8 08 30 06 02 01 00 02 01 01 a9 20 30 ..*..0........ 0 ++ 1e 30 0d a0 03 02 01 02 a1 06 04 04 12 d0 00 23 .0.............# ++ 30 0d a0 03 02 01 02 a1 06 04 04 12 d0 00 23 aa 0.............#. ++ 25 30 23 a0 03 02 01 00 a1 03 02 01 05 a2 17 04 %0#............. ++ 15 6b 72 62 41 53 4e 2e 31 20 74 65 73 74 20 6d .krbASN.1 test m ++ 65 73 73 61 67 65 ab 81 bf 30 81 bc 61 5c 30 5a essage...0..a\0Z ++ a0 03 02 01 05 a1 10 1b 0e 41 54 48 45 4e 41 2e .........ATHENA. ++ 4d 49 54 2e 45 44 55 a2 1a 30 18 a0 03 02 01 01 MIT.EDU..0...... ++ a1 11 30 0f 1b 06 68 66 74 73 61 69 1b 05 65 78 ..0...hftsai..ex ++ 74 72 61 a3 25 30 23 a0 03 02 01 00 a1 03 02 01 tra.%0#......... ++ 05 a2 17 04 15 6b 72 62 41 53 4e 2e 31 20 74 65 .....krbASN.1 te ++ 73 74 20 6d 65 73 73 61 67 65 61 5c 30 5a a0 03 st messagea\0Z.. ++ 02 01 05 a1 10 1b 0e 41 54 48 45 4e 41 2e 4d 49 .......ATHENA.MI ++ 54 2e 45 44 55 a2 1a 30 18 a0 03 02 01 01 a1 11 T.EDU..0........ ++ 30 0f 1b 06 68 66 74 73 61 69 1b 05 65 78 74 72 0...hftsai..extr ++ 61 a3 25 30 23 a0 03 02 01 00 a1 03 02 01 05 a2 a.%0#........... ++ 17 04 15 6b 72 62 41 53 4e 2e 31 20 74 65 73 74 ...krbASN.1 test ++ 20 6d 65 73 73 61 67 65 message ++. [1] [General string] "krb5data" +-- +2.1.0 + diff --git a/SOURCES/0005-Be-more-careful-of-target-ccache-collections.patch b/SOURCES/0005-Be-more-careful-of-target-ccache-collections.patch deleted file mode 100644 index 367efef..0000000 --- a/SOURCES/0005-Be-more-careful-of-target-ccache-collections.patch +++ /dev/null @@ -1,179 +0,0 @@ -From b39abd936b6422716d0d6edf5b37326bbe095da7 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/0005-Copy-config-entries-to-the-ksu-target-ccache.patch b/SOURCES/0005-Copy-config-entries-to-the-ksu-target-ccache.patch new file mode 100644 index 0000000..e004136 --- /dev/null +++ b/SOURCES/0005-Copy-config-entries-to-the-ksu-target-ccache.patch @@ -0,0 +1,30 @@ +From 297496f0938955ba4aaf0ebecf4e393e527b8cbf Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Tue, 29 Oct 2013 16:27:20 -0400 +Subject: [PATCH 5/7] Copy config entries to the ksu 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. + +ticket: 7986 (new) +--- + 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 4693bd4..0f9e042 100644 +--- a/src/clients/ksu/ccache.c ++++ b/src/clients/ksu/ccache.c +@@ -219,7 +219,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; + } +-- +2.0.4 + diff --git a/SOURCES/0006-Copy-config-entries-to-the-target-ccache.patch b/SOURCES/0006-Copy-config-entries-to-the-target-ccache.patch deleted file mode 100644 index 10608ca..0000000 --- a/SOURCES/0006-Copy-config-entries-to-the-target-ccache.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0e6e95235499818800d6ca15124a5860f0d92a2b 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/0006-Dispatch-style-protocol-switching-for-transport.patch b/SOURCES/0006-Dispatch-style-protocol-switching-for-transport.patch new file mode 100644 index 0000000..e36544e --- /dev/null +++ b/SOURCES/0006-Dispatch-style-protocol-switching-for-transport.patch @@ -0,0 +1,506 @@ +From 606e2ccc0a2546a23761f910482a55c5bf0f98ac Mon Sep 17 00:00:00 2001 +From: "Robbie Harwood (frozencemetery)" +Date: Fri, 16 Aug 2013 14:48:55 -0400 +Subject: [PATCH 06/13] Dispatch-style protocol switching for transport + +Switch to using per-transport-type functions when a socket that we're +using to communicate with a server becomes readable or writable, and add +them as pointers to the connection state. The functions are passed the +name of the realm of the server being contacted, as we expect to need +this in the near future. + +[nalin@redhat.com: replace macros with typedefs] +[nalin@redhat.com: compare transports with TCP_OR_UDP rather than with 0] + +ticket: 7929 +--- + src/lib/krb5/os/changepw.c | 6 +- + src/lib/krb5/os/os-proto.h | 1 + + src/lib/krb5/os/sendto_kdc.c | 297 ++++++++++++++++++++++++------------------- + 3 files changed, 171 insertions(+), 133 deletions(-) + +diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c +index a1c9885..0ee427d 100644 +--- a/src/lib/krb5/os/changepw.c ++++ b/src/lib/krb5/os/changepw.c +@@ -261,9 +261,9 @@ change_set_password(krb5_context context, + callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup; + krb5_free_data_contents(callback_ctx.context, &chpw_rep); + +- code = k5_sendto(callback_ctx.context, NULL, &sl, strategy, +- &callback_info, &chpw_rep, ss2sa(&remote_addr), +- &addrlen, NULL, NULL, NULL); ++ code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm, ++ &sl, strategy, &callback_info, &chpw_rep, ++ ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL); + if (code) { + /* + * Here we may want to switch to TCP on some errors. +diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h +index f23dda5..e60ccd0 100644 +--- a/src/lib/krb5/os/os-proto.h ++++ b/src/lib/krb5/os/os-proto.h +@@ -115,6 +115,7 @@ int _krb5_use_dns_kdc (krb5_context); + int _krb5_conf_boolean (const char *); + + krb5_error_code k5_sendto(krb5_context context, const krb5_data *message, ++ const krb5_data *realm, + const struct serverlist *addrs, + k5_transport_strategy strategy, + struct sendto_callback_info *callback_info, +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index c6aae8e..28f1c4d 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -96,11 +96,18 @@ struct outgoing_message { + unsigned char msg_len_buf[4]; + }; + ++struct conn_state; ++typedef krb5_boolean fd_handler_fn(krb5_context context, ++ const krb5_data *realm, ++ struct conn_state *conn, ++ struct select_state *selstate); ++ + struct conn_state { + SOCKET fd; + enum conn_states state; +- int (*service)(krb5_context context, struct conn_state *, +- struct select_state *, int); ++ fd_handler_fn *service_connect; ++ fd_handler_fn *service_write; ++ fd_handler_fn *service_read; + struct remote_address addr; + struct incoming_message in; + struct outgoing_message out; +@@ -409,9 +416,9 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message, + return retval; + + err = 0; +- retval = k5_sendto(context, message, &servers, strategy, NULL, reply, +- NULL, NULL, &server_used, check_for_svc_unavailable, +- &err); ++ retval = k5_sendto(context, message, realm, &servers, strategy, NULL, ++ reply, NULL, NULL, &server_used, ++ check_for_svc_unavailable, &err); + if (retval == KRB5_KDC_UNREACH) { + if (err == KDC_ERR_SVC_UNAVAILABLE) { + retval = KRB5KDC_ERR_SVC_UNAVAILABLE; +@@ -457,10 +464,10 @@ cleanup: + * connections already in progress + */ + +-static int service_tcp_fd(krb5_context context, struct conn_state *conn, +- struct select_state *selstate, int ssflags); +-static int service_udp_fd(krb5_context context, struct conn_state *conn, +- struct select_state *selstate, int ssflags); ++static fd_handler_fn service_tcp_connect; ++static fd_handler_fn service_tcp_write; ++static fd_handler_fn service_tcp_read; ++static fd_handler_fn service_udp_read; + + /* Set up the actual message we will send across the underlying transport to + * communicate the payload message, using one or both of state->out.sgbuf. */ +@@ -505,9 +512,13 @@ add_connection(struct conn_state **conns, k5_transport transport, + state->server_index = server_index; + SG_SET(&state->out.sgbuf[1], NULL, 0); + if (transport == TCP) { +- state->service = service_tcp_fd; ++ state->service_connect = service_tcp_connect; ++ state->service_write = service_tcp_write; ++ state->service_read = service_tcp_read; + } else { +- state->service = service_udp_fd; ++ state->service_connect = NULL; ++ state->service_write = NULL; ++ state->service_read = service_udp_read; + + if (*udpbufp == NULL) { + *udpbufp = malloc(MAX_DGRAM_SIZE); +@@ -788,9 +799,13 @@ maybe_send(krb5_context context, struct conn_state *conn, + } + + static void +-kill_conn(struct conn_state *conn, struct select_state *selstate) ++kill_conn(krb5_context context, struct conn_state *conn, ++ struct select_state *selstate) + { ++ if (socktype_for_transport(conn->addr.transport) == SOCK_STREAM) ++ TRACE_SENDTO_KDC_TCP_DISCONNECT(context, &conn->addr); + cm_remove_fd(selstate, conn->fd); ++ + closesocket(conn->fd); + conn->fd = INVALID_SOCKET; + conn->state = FAILED; +@@ -814,136 +829,157 @@ get_so_error(int fd) + return sockerr; + } + +-/* Process events on a TCP socket. Return 1 if we get a complete reply. */ +-static int +-service_tcp_fd(krb5_context context, struct conn_state *conn, +- struct select_state *selstate, int ssflags) ++/* Perform next step in sending. Return true on usable data. */ ++static krb5_boolean ++service_dispatch(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate, ++ int ssflags) + { +- int e = 0; +- ssize_t nwritten, nread; +- SOCKET_WRITEV_TEMP tmp; +- struct incoming_message *in = &conn->in; +- struct outgoing_message *out = &conn->out; +- + /* Check for a socket exception. */ +- if (ssflags & SSF_EXCEPTION) +- goto kill_conn; ++ if (ssflags & SSF_EXCEPTION) { ++ kill_conn(context, conn, selstate); ++ return FALSE; ++ } + + switch (conn->state) { + case CONNECTING: +- /* Check whether the connection succeeded. */ +- e = get_so_error(conn->fd); +- if (e) { +- TRACE_SENDTO_KDC_TCP_ERROR_CONNECT(context, &conn->addr, e); +- goto kill_conn; +- } +- conn->state = WRITING; ++ assert(conn->service_connect != NULL); ++ return conn->service_connect(context, realm, conn, selstate); ++ case WRITING: ++ assert(conn->service_write != NULL); ++ return conn->service_write(context, realm, conn, selstate); ++ case READING: ++ assert(conn->service_read != NULL); ++ return conn->service_read(context, realm, conn, selstate); ++ default: ++ abort(); ++ } ++} + +- /* Record this connection's timeout for service_fds. */ +- if (get_curtime_ms(&conn->endtime) == 0) +- conn->endtime += 10000; ++/* Initialize TCP transport. */ ++static krb5_boolean ++service_tcp_connect(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate) ++{ ++ /* Check whether the connection succeeded. */ ++ int e = get_so_error(conn->fd); + +- /* Fall through. */ +- case WRITING: +- TRACE_SENDTO_KDC_TCP_SEND(context, &conn->addr); +- nwritten = SOCKET_WRITEV(conn->fd, out->sgp, out->sg_count, tmp); +- if (nwritten < 0) { +- TRACE_SENDTO_KDC_TCP_ERROR_SEND(context, &conn->addr, +- SOCKET_ERRNO); +- goto kill_conn; ++ if (e) { ++ TRACE_SENDTO_KDC_TCP_ERROR_CONNECT(context, &conn->addr, e); ++ kill_conn(context, conn, selstate); ++ return FALSE; ++ } ++ ++ conn->state = WRITING; ++ ++ /* Record this connection's timeout for service_fds. */ ++ if (get_curtime_ms(&conn->endtime) == 0) ++ conn->endtime += 10000; ++ ++ return service_tcp_write(context, realm, conn, selstate); ++} ++ ++/* Sets conn->state to READING when done. */ ++static krb5_boolean ++service_tcp_write(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate) ++{ ++ ssize_t nwritten; ++ SOCKET_WRITEV_TEMP tmp; ++ ++ TRACE_SENDTO_KDC_TCP_SEND(context, &conn->addr); ++ nwritten = SOCKET_WRITEV(conn->fd, conn->out.sgp, conn->out.sg_count, tmp); ++ if (nwritten < 0) { ++ TRACE_SENDTO_KDC_TCP_ERROR_SEND(context, &conn->addr, SOCKET_ERRNO); ++ kill_conn(context, conn, selstate); ++ return FALSE; ++ } ++ while (nwritten) { ++ sg_buf *sgp = conn->out.sgp; ++ if ((size_t)nwritten < SG_LEN(sgp)) { ++ SG_ADVANCE(sgp, (size_t)nwritten); ++ nwritten = 0; ++ } else { ++ nwritten -= SG_LEN(sgp); ++ conn->out.sgp++; ++ conn->out.sg_count--; + } +- while (nwritten) { +- sg_buf *sgp = out->sgp; +- if ((size_t) nwritten < SG_LEN(sgp)) { +- SG_ADVANCE(sgp, (size_t) nwritten); +- nwritten = 0; +- } else { +- nwritten -= SG_LEN(sgp); +- out->sgp++; +- out->sg_count--; +- } ++ } ++ if (conn->out.sg_count == 0) { ++ /* Done writing, switch to reading. */ ++ cm_read(selstate, conn->fd); ++ conn->state = READING; ++ } ++ return FALSE; ++} ++ ++/* Return true on usable data. */ ++static krb5_boolean ++service_tcp_read(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate) ++{ ++ ssize_t nread; ++ int e = 0; ++ struct incoming_message *in = &conn->in; ++ ++ if (in->bufsizebytes_read == 4) { ++ /* Reading data. */ ++ nread = SOCKET_READ(conn->fd, &in->buf[in->pos], in->n_left); ++ if (nread <= 0) { ++ e = nread ? SOCKET_ERRNO : ECONNRESET; ++ TRACE_SENDTO_KDC_TCP_ERROR_RECV(context, &conn->addr, e); ++ kill_conn(context, conn, selstate); ++ return FALSE; + } +- if (out->sg_count == 0) { +- /* Done writing, switch to reading. */ +- cm_read(selstate, conn->fd); +- conn->state = READING; +- in->bufsizebytes_read = 0; +- in->bufsize = 0; +- in->pos = 0; +- in->buf = NULL; +- in->n_left = 0; ++ in->n_left -= nread; ++ in->pos += nread; ++ if (in->n_left <= 0) ++ return TRUE; ++ } else { ++ /* Reading length. */ ++ nread = SOCKET_READ(conn->fd, in->bufsizebytes + in->bufsizebytes_read, ++ 4 - in->bufsizebytes_read); ++ if (nread <= 0) { ++ e = nread ? SOCKET_ERRNO : ECONNRESET; ++ TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(context, &conn->addr, e); ++ kill_conn(context, conn, selstate); ++ return FALSE; + } +- return 0; +- +- case READING: ++ in->bufsizebytes_read += nread; + if (in->bufsizebytes_read == 4) { +- /* Reading data. */ +- nread = SOCKET_READ(conn->fd, &in->buf[in->pos], in->n_left); +- if (nread <= 0) { +- e = nread ? SOCKET_ERRNO : ECONNRESET; +- TRACE_SENDTO_KDC_TCP_ERROR_RECV(context, &conn->addr, e); +- goto kill_conn; +- } +- in->n_left -= nread; +- in->pos += nread; +- if (in->n_left <= 0) +- return 1; +- } else { +- /* Reading length. */ +- nread = SOCKET_READ(conn->fd, +- in->bufsizebytes + in->bufsizebytes_read, +- 4 - in->bufsizebytes_read); +- if (nread <= 0) { +- e = nread ? SOCKET_ERRNO : ECONNRESET; +- TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(context, &conn->addr, e); +- goto kill_conn; ++ unsigned long len = load_32_be(in->bufsizebytes); ++ /* Arbitrary 1M cap. */ ++ if (len > 1 * 1024 * 1024) { ++ kill_conn(context, conn, selstate); ++ return FALSE; + } +- in->bufsizebytes_read += nread; +- if (in->bufsizebytes_read == 4) { +- unsigned long len = load_32_be(in->bufsizebytes); +- /* Arbitrary 1M cap. */ +- if (len > 1 * 1024 * 1024) +- goto kill_conn; +- in->bufsize = in->n_left = len; +- in->pos = 0; +- in->buf = malloc(len); +- if (in->buf == NULL) +- goto kill_conn; ++ in->bufsize = in->n_left = len; ++ in->pos = 0; ++ in->buf = malloc(len); ++ if (in->buf == NULL) { ++ kill_conn(context, conn, selstate); ++ return FALSE; + } + } +- break; +- +- default: +- abort(); + } +- return 0; +- +-kill_conn: +- TRACE_SENDTO_KDC_TCP_DISCONNECT(context, &conn->addr); +- kill_conn(conn, selstate); +- return 0; ++ return FALSE; + } + +-/* Process events on a UDP socket. Return 1 if we get a reply. */ +-static int +-service_udp_fd(krb5_context context, struct conn_state *conn, +- struct select_state *selstate, int ssflags) ++/* Process events on a UDP socket. Return true if we get a reply. */ ++static krb5_boolean ++service_udp_read(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate) + { + int nread; + +- if (!(ssflags & (SSF_READ|SSF_EXCEPTION))) +- abort(); +- if (conn->state != READING) +- abort(); +- + nread = recv(conn->fd, conn->in.buf, conn->in.bufsize, 0); + if (nread < 0) { + TRACE_SENDTO_KDC_UDP_ERROR_RECV(context, &conn->addr, SOCKET_ERRNO); +- kill_conn(conn, selstate); +- return 0; ++ kill_conn(context, conn, selstate); ++ return FALSE; + } + conn->in.pos = nread; +- return 1; ++ return TRUE; + } + + /* Return the maximum of endtime and the endtime fields of all currently active +@@ -965,7 +1001,7 @@ get_endtime(time_ms endtime, struct conn_state *conns) + static krb5_boolean + service_fds(krb5_context context, struct select_state *selstate, + time_ms interval, struct conn_state *conns, +- struct select_state *seltemp, ++ struct select_state *seltemp, const krb5_data *realm, + int (*msg_handler)(krb5_context, const krb5_data *, void *), + void *msg_handler_data, struct conn_state **winner_out) + { +@@ -977,7 +1013,7 @@ service_fds(krb5_context context, struct select_state *selstate, + + e = get_curtime_ms(&endtime); + if (e) +- return 1; ++ return TRUE; + endtime += interval; + + e = 0; +@@ -991,7 +1027,7 @@ service_fds(krb5_context context, struct select_state *selstate, + + if (selret == 0) + /* Timeout, return to caller. */ +- return 0; ++ return FALSE; + + /* Got something on a socket, process it. */ + for (state = conns; state != NULL; state = state->next) { +@@ -1003,7 +1039,7 @@ service_fds(krb5_context context, struct select_state *selstate, + if (!ssflags) + continue; + +- if (state->service(context, state, selstate, ssflags)) { ++ if (service_dispatch(context, realm, state, selstate, ssflags)) { + int stop = 1; + + if (msg_handler != NULL) { +@@ -1014,14 +1050,14 @@ service_fds(krb5_context context, struct select_state *selstate, + + if (stop) { + *winner_out = state; +- return 1; ++ return TRUE; + } + } + } + } + if (e != 0) +- return 1; +- return 0; ++ return TRUE; ++ return FALSE; + } + + /* +@@ -1052,7 +1088,8 @@ service_fds(krb5_context context, struct select_state *selstate, + + krb5_error_code + k5_sendto(krb5_context context, const krb5_data *message, +- const struct serverlist *servers, k5_transport_strategy strategy, ++ const krb5_data *realm, const struct serverlist *servers, ++ k5_transport_strategy strategy, + struct sendto_callback_info* callback_info, krb5_data *reply, + struct sockaddr *remoteaddr, socklen_t *remoteaddrlen, + int *server_used, +@@ -1098,7 +1135,7 @@ k5_sendto(krb5_context context, const krb5_data *message, + if (maybe_send(context, state, message, sel_state, callback_info)) + continue; + done = service_fds(context, sel_state, 1000, conns, seltemp, +- msg_handler, msg_handler_data, &winner); ++ realm, msg_handler, msg_handler_data, &winner); + } + } + +@@ -1110,13 +1147,13 @@ k5_sendto(krb5_context context, const krb5_data *message, + if (maybe_send(context, state, message, sel_state, callback_info)) + continue; + done = service_fds(context, sel_state, 1000, conns, seltemp, +- msg_handler, msg_handler_data, &winner); ++ realm, msg_handler, msg_handler_data, &winner); + } + + /* Wait for two seconds at the end of the first pass. */ + if (!done) { + done = service_fds(context, sel_state, 2000, conns, seltemp, +- msg_handler, msg_handler_data, &winner); ++ realm, msg_handler, msg_handler_data, &winner); + } + + /* Make remaining passes over all of the connections. */ +@@ -1126,14 +1163,14 @@ k5_sendto(krb5_context context, const krb5_data *message, + if (maybe_send(context, state, message, sel_state, callback_info)) + continue; + done = service_fds(context, sel_state, 1000, conns, seltemp, +- msg_handler, msg_handler_data, &winner); ++ realm, msg_handler, msg_handler_data, &winner); + if (sel_state->nfds == 0) + break; + } + /* Wait for the delay backoff at the end of this pass. */ + if (!done) { + done = service_fds(context, sel_state, delay, conns, seltemp, +- msg_handler, msg_handler_data, &winner); ++ realm, msg_handler, msg_handler_data, &winner); + } + if (sel_state->nfds == 0) + break; +-- +2.1.0 + diff --git a/SOURCES/0006-Use-more-randomness-for-ksu-secondary-cache-names.patch b/SOURCES/0006-Use-more-randomness-for-ksu-secondary-cache-names.patch new file mode 100644 index 0000000..da8a32a --- /dev/null +++ b/SOURCES/0006-Use-more-randomness-for-ksu-secondary-cache-names.patch @@ -0,0 +1,115 @@ +From 69c8e20b18577781e17c5959e23514134dfb5755 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Thu, 24 Jul 2014 16:43:21 -0400 +Subject: [PATCH 6/7] Use more randomness for ksu secondary cache names + +When generating a suffix to append to a ccache name that will hold the +credentials for a ksu-invoked process, instead of using integers +counting up from 1, use the result of base64-encoding six randomly- +generated octets. Tweak the output alphabet just a bit to avoid using +'+' or '/' in the generated names, the latter of which could really +confuse things. +--- + src/clients/ksu/ccache.c | 27 +++++++++++++++++++++++---- + src/clients/ksu/ksu.h | 2 +- + src/clients/ksu/main.c | 16 ++++++++++++---- + 3 files changed, 36 insertions(+), 9 deletions(-) + +diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c +index 0f9e042..a0736f2 100644 +--- a/src/clients/ksu/ccache.c ++++ b/src/clients/ksu/ccache.c +@@ -27,6 +27,7 @@ + */ + + #include "ksu.h" ++#include "k5-base64.h" + #include "adm_proto.h" + #include + #include +@@ -504,10 +505,28 @@ show_credential(context, cred, cc) + free(sname); + } + +-int gen_sym(){ +- static int i = 0; +- i ++; +- return i; ++/* Create a random string suitable for a filename extension. */ ++krb5_error_code ++gen_sym(krb5_context context, char **sym_out) ++{ ++ krb5_error_code retval; ++ char bytes[6], *p, *sym; ++ krb5_data data = make_data(bytes, sizeof(bytes)); ++ ++ *sym_out = NULL; ++ retval = krb5_c_random_make_octets(context, &data); ++ if (retval) ++ return retval; ++ sym = k5_base64_encode(data.data, data.length); ++ if (sym == NULL) ++ return ENOMEM; ++ /* Tweak the output alphabet just a bit. */ ++ while ((p = strchr(sym, '/')) != NULL) ++ *p = '_'; ++ while ((p = strchr(sym, '+')) != NULL) ++ *p = '-'; ++ *sym_out = sym; ++ return 0; + } + + krb5_error_code krb5_ccache_overwrite(context, ccs, cct, primary_principal) +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index fbbf217..5ba5ceb 100644 +--- a/src/clients/ksu/ksu.h ++++ b/src/clients/ksu/ksu.h +@@ -130,7 +130,7 @@ extern krb5_error_code krb5_get_login_princ + extern void show_credential + (krb5_context, krb5_creds *, krb5_ccache); + +-extern int gen_sym (void); ++krb5_error_code gen_sym(krb5_context context, char **sym); + + extern krb5_error_code krb5_ccache_overwrite + (krb5_context, krb5_ccache, krb5_ccache, krb5_principal); +diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c +index 41a3bf8..47fa820 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -856,7 +856,7 @@ resolve_target_cache(krb5_context context, krb5_principal princ, + krb5_error_code retval; + krb5_boolean switchable, reused = FALSE; + krb5_ccache ccache = NULL; +- char *sep, *ccname = NULL, *target; ++ char *sep, *ccname = NULL, *sym = NULL, *target; + + *ccache_out = NULL; + *ccache_reused = FALSE; +@@ -876,12 +876,20 @@ resolve_target_cache(krb5_context context, krb5_principal princ, + * the name of a cache that doesn't exist yet. */ + do { + free(ccname); +- if (asprintf(&ccname, "%s.%d", target, gen_sym()) < 0) { ++ retval = gen_sym(context, &sym); ++ if (retval) { ++ com_err(prog_name, retval, ++ _("while generating part of the target ccache name")); ++ return retval; ++ } ++ if (asprintf(&ccname, "%s.%s", target, sym) < 0) { + retval = ENOMEM; +- com_err(prog_name, ENOMEM, +- _("while allocating memory for target ccache name")); ++ free(sym); ++ com_err(prog_name, retval, _("while allocating memory for the " ++ "target ccache name")); + goto cleanup; + } ++ free(sym); + } while (ks_ccache_name_is_initialized(context, ccname)); + retval = krb5_cc_resolve(context, ccname, &ccache); + } else { +-- +2.0.4 + diff --git a/SOURCES/0007-HTTPS-transport-Microsoft-KKDCPP-implementation.patch b/SOURCES/0007-HTTPS-transport-Microsoft-KKDCPP-implementation.patch new file mode 100644 index 0000000..cd21dac --- /dev/null +++ b/SOURCES/0007-HTTPS-transport-Microsoft-KKDCPP-implementation.patch @@ -0,0 +1,858 @@ +From d950809ff49e3e7603594186d77135a09ab6b1b2 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Thu, 24 Apr 2014 16:30:56 -0400 +Subject: [PATCH 07/13] HTTPS transport (Microsoft KKDCPP implementation) + +Add an 'HTTPS' transport type which connects to an [MS-KKDCP] proxy +server using HTTPS to communicate with a KDC. The KDC's name should +take the form of an HTTPS URL (e.g. "https://proxybox/KdcProxy"). + +An HTTPS connection's encryption layer can be reading and writing when +the application layer is expecting to write and read, so the HTTPS +callbacks have to handle being called multiple times. + +[nalin@redhat.com: use cleanup labels, make sure we always send the + realm name, keep a copy of the URI on-hand, move most of the + conditionally-compiled sections into their own conditionally-built + functions, break out HTTPS request formatting into a helper function, + handle the MS-KKDCP length bytes, update comments to mention specific + versions of the MS-KKDCP spec, differentiate TCP and HTTP trace + messages, trace unparseable responses] + +ticket: 7929 +--- + src/include/k5-trace.h | 13 ++ + src/lib/krb5/os/locate_kdc.c | 63 ++++++- + src/lib/krb5/os/os-proto.h | 2 + + src/lib/krb5/os/sendto_kdc.c | 417 ++++++++++++++++++++++++++++++++++++++--- + src/lib/krb5/os/t_locate_kdc.c | 2 + + src/lib/krb5/os/trace.c | 2 + + 6 files changed, 471 insertions(+), 28 deletions(-) + +diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h +index dfd34f6..f0d79f1 100644 +--- a/src/include/k5-trace.h ++++ b/src/include/k5-trace.h +@@ -312,6 +312,9 @@ void krb5int_trace(krb5_context context, const char *fmt, ...); + TRACE(c, "AP-REQ ticket: {princ} -> {princ}, session key {keyblock}", \ + client, server, keyblock) + ++#define TRACE_SENDTO_KDC_ERROR_SET_MESSAGE(c, raddr, err) \ ++ TRACE(c, "Error preparing message to send to {raddr}: {errno}", \ ++ raddr, err) + #define TRACE_SENDTO_KDC(c, len, rlm, master, tcp) \ + TRACE(c, "Sending request ({int} bytes) to {data}{str}{str}", len, \ + rlm, (master) ? " (master)" : "", (tcp) ? " (tcp only)" : "") +@@ -321,6 +324,16 @@ void krb5int_trace(krb5_context context, const char *fmt, ...); + TRACE(c, "Resolving hostname {str}", hostname) + #define TRACE_SENDTO_KDC_RESPONSE(c, len, raddr) \ + TRACE(c, "Received answer ({int} bytes) from {raddr}", len, raddr) ++#define TRACE_SENDTO_KDC_HTTPS_ERROR_CONNECT(c, raddr) \ ++ TRACE(c, "HTTPS error connecting to {raddr}", raddr) ++#define TRACE_SENDTO_KDC_HTTPS_ERROR_RECV(c, raddr, err) \ ++ TRACE(c, "HTTPS error receiving from {raddr}: {errno}", raddr, err) ++#define TRACE_SENDTO_KDC_HTTPS_ERROR_SEND(c, raddr) \ ++ TRACE(c, "HTTPS error sending to {raddr}", raddr) ++#define TRACE_SENDTO_KDC_HTTPS_SEND(c, raddr) \ ++ TRACE(c, "Sending HTTPS request to {raddr}", raddr) ++#define TRACE_SENDTO_KDC_HTTPS_ERROR(c, errs) \ ++ TRACE(c, "HTTPS error: {str}", errs) + #define TRACE_SENDTO_KDC_TCP_CONNECT(c, raddr) \ + TRACE(c, "Initiating TCP connection to {raddr}", raddr) + #define TRACE_SENDTO_KDC_TCP_DISCONNECT(c, raddr) \ +diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c +index 4c8aead..1136809 100644 +--- a/src/lib/krb5/os/locate_kdc.c ++++ b/src/lib/krb5/os/locate_kdc.c +@@ -91,8 +91,10 @@ k5_free_serverlist (struct serverlist *list) + { + size_t i; + +- for (i = 0; i < list->nservers; i++) ++ for (i = 0; i < list->nservers; i++) { + free(list->servers[i].hostname); ++ free(list->servers[i].uri_path); ++ } + free(list->servers); + list->servers = NULL; + list->nservers = 0; +@@ -140,6 +142,7 @@ add_addr_to_list(struct serverlist *list, k5_transport transport, int family, + entry->transport = transport; + entry->family = family; + entry->hostname = NULL; ++ entry->uri_path = NULL; + entry->addrlen = addrlen; + memcpy(&entry->addr, addr, addrlen); + list->nservers++; +@@ -149,7 +152,7 @@ add_addr_to_list(struct serverlist *list, k5_transport transport, int family, + /* Add a hostname entry to list. */ + static int + add_host_to_list(struct serverlist *list, const char *hostname, int port, +- k5_transport transport, int family) ++ k5_transport transport, int family, char *uri_path) + { + struct server_entry *entry; + +@@ -160,11 +163,46 @@ add_host_to_list(struct serverlist *list, const char *hostname, int port, + entry->family = family; + entry->hostname = strdup(hostname); + if (entry->hostname == NULL) +- return ENOMEM; ++ goto oom; ++ if (uri_path != NULL) { ++ entry->uri_path = strdup(uri_path); ++ if (entry->uri_path == NULL) ++ goto oom; ++ } + entry->port = port; + list->nservers++; + return 0; ++oom: ++ free(entry->hostname); ++ entry->hostname = NULL; ++ return ENOMEM; ++} ++ ++#ifdef PROXY_TLS_IMPL_OPENSSL ++static void ++parse_uri_if_https(char *host_or_uri, k5_transport *transport, char **host, ++ char **uri_path) ++{ ++ char *cp; ++ ++ if (strncmp(host_or_uri, "https://", 8) == 0) { ++ *transport = HTTPS; ++ *host = host_or_uri + 8; ++ ++ cp = strchr(*host, '/'); ++ if (cp != NULL) { ++ *cp = '\0'; ++ *uri_path = cp + 1; ++ } ++ } ++} ++#else ++static void ++parse_uri_if_https(char *host_or_uri, k5_transport *transport, char **host, ++ char **uri) ++{ + } ++#endif + + /* Return true if server is identical to an entry in list. */ + static krb5_boolean +@@ -222,9 +260,14 @@ locate_srv_conf_1(krb5_context context, const krb5_data *realm, + + for (i=0; hostlist[i]; i++) { + int p1, p2; ++ k5_transport this_transport = transport; ++ char *uri_path = NULL; + + host = hostlist[i]; + Tprintf ("entry %d is '%s'\n", i, host); ++ ++ parse_uri_if_https(host, &this_transport, &host, &uri_path); ++ + /* Find port number, and strip off any excess characters. */ + if (*host == '[' && (cp = strchr(host, ']'))) + cp = cp + 1; +@@ -244,6 +287,9 @@ locate_srv_conf_1(krb5_context context, const krb5_data *realm, + return EINVAL; + p1 = htons (l); + p2 = 0; ++ } else if (this_transport == HTTPS) { ++ p1 = htons(443); ++ p2 = 0; + } else { + p1 = udpport; + p2 = sec_udpport; +@@ -255,12 +301,15 @@ locate_srv_conf_1(krb5_context context, const krb5_data *realm, + *cp = '\0'; + } + +- code = add_host_to_list(serverlist, host, p1, transport, AF_UNSPEC); ++ code = add_host_to_list(serverlist, host, p1, this_transport, ++ AF_UNSPEC, uri_path); + /* Second port is for IPv4 UDP only, and should possibly go away as + * it was originally a krb4 compatibility measure. */ + if (code == 0 && p2 != 0 && +- (transport == TCP_OR_UDP || transport == UDP)) +- code = add_host_to_list(serverlist, host, p2, UDP, AF_INET); ++ (this_transport == TCP_OR_UDP || this_transport == UDP)) { ++ code = add_host_to_list(serverlist, host, p2, UDP, AF_INET, ++ uri_path); ++ } + if (code) + goto cleanup; + } +@@ -313,7 +362,7 @@ locate_srv_dns_1(const krb5_data *realm, const char *service, + for (entry = head; entry != NULL; entry = entry->next) { + transport = (strcmp(protocol, "_tcp") == 0) ? TCP : UDP; + code = add_host_to_list(serverlist, entry->host, htons(entry->port), +- transport, AF_UNSPEC); ++ transport, AF_UNSPEC, NULL); + if (code) + goto cleanup; + } +diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h +index e60ccd0..34bf028 100644 +--- a/src/lib/krb5/os/os-proto.h ++++ b/src/lib/krb5/os/os-proto.h +@@ -42,6 +42,7 @@ typedef enum { + TCP_OR_UDP = 0, + TCP, + UDP, ++ HTTPS, + } k5_transport; + + typedef enum { +@@ -55,6 +56,7 @@ struct server_entry { + char *hostname; /* NULL -> use addrlen/addr instead */ + int port; /* Used only if hostname set */ + k5_transport transport; /* May be 0 for UDP/TCP if hostname set */ ++ char *uri_path; /* Used only if transport is HTTPS */ + int family; /* May be 0 (aka AF_UNSPEC) if hostname set */ + size_t addrlen; + struct sockaddr_storage addr; +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index 28f1c4d..a4727c4 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -23,6 +23,32 @@ + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ ++/* ++ * MS-KKDCP implementation Copyright 2013,2014 Red Hat, Inc. ++ * ++ * 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. ++ */ + + /* Send packet to KDC for realm; wait for response, retransmitting + * as necessary. */ +@@ -49,6 +75,7 @@ + #endif + + #ifdef PROXY_TLS_IMPL_OPENSSL ++#include + #include + #endif + +@@ -116,6 +143,13 @@ struct conn_state { + struct conn_state *next; + time_ms endtime; + krb5_boolean defer; ++ struct { ++ const char *uri_path; ++ char *https_request; ++#ifdef PROXY_TLS_IMPL_OPENSSL ++ SSL *ssl; ++#endif ++ } http; + }; + + void +@@ -140,6 +174,22 @@ get_curtime_ms(time_ms *time_out) + return 0; + } + ++#ifdef PROXY_TLS_IMPL_OPENSSL ++static void ++free_http_ssl_data(struct conn_state *state) ++{ ++ SSL_free(state->http.ssl); ++ state->http.ssl = NULL; ++ free(state->http.https_request); ++ state->http.https_request = NULL; ++} ++#else ++static void ++free_http_ssl_data(struct conn_state *state) ++{ ++} ++#endif ++ + #ifdef USE_POLL + + /* Find a pollfd in selstate by fd, or abort if we can't find it. */ +@@ -321,6 +371,7 @@ socktype_for_transport(k5_transport transport) + case UDP: + return SOCK_DGRAM; + case TCP: ++ case HTTPS: + return SOCK_STREAM; + default: + return 0; +@@ -468,33 +519,113 @@ static fd_handler_fn service_tcp_connect; + static fd_handler_fn service_tcp_write; + static fd_handler_fn service_tcp_read; + static fd_handler_fn service_udp_read; ++static fd_handler_fn service_https_write; ++static fd_handler_fn service_https_read; ++ ++#ifdef PROXY_TLS_IMPL_OPENSSL ++static krb5_error_code ++make_proxy_request(struct conn_state *state, const krb5_data *realm, ++ const krb5_data *message, char **req_out, size_t *len_out) ++{ ++ krb5_kkdcp_message pm; ++ krb5_data *encoded_pm = NULL; ++ struct k5buf buf; ++ const char *uri_path; ++ krb5_error_code ret; ++ ++ *req_out = NULL; ++ *len_out = 0; ++ ++ /* ++ * Stuff the message length in at the front of the kerb_message field ++ * before encoding. The proxied messages are actually the payload we'd ++ * be sending and receiving if we were using plain TCP. ++ */ ++ memset(&pm, 0, sizeof(pm)); ++ ret = alloc_data(&pm.kerb_message, message->length + 4); ++ if (ret != 0) ++ goto cleanup; ++ store_32_be(message->length, pm.kerb_message.data); ++ memcpy(pm.kerb_message.data + 4, message->data, message->length); ++ pm.target_domain = *realm; ++ ret = encode_krb5_kkdcp_message(&pm, &encoded_pm); ++ if (ret != 0) ++ goto cleanup; ++ ++ /* Build the request to transmit: the headers + the proxy message. */ ++ k5_buf_init_dynamic(&buf); ++ uri_path = (state->http.uri_path != NULL) ? state->http.uri_path : ""; ++ k5_buf_add_fmt(&buf, "POST /%s HTTP/1.0\r\n", uri_path); ++ k5_buf_add(&buf, "Cache-Control: no-cache\r\n"); ++ k5_buf_add(&buf, "Pragma: no-cache\r\n"); ++ k5_buf_add(&buf, "User-Agent: kerberos/1.0\r\n"); ++ k5_buf_add(&buf, "Content-type: application/kerberos\r\n"); ++ k5_buf_add_fmt(&buf, "Content-Length: %d\r\n\r\n", encoded_pm->length); ++ k5_buf_add_len(&buf, encoded_pm->data, encoded_pm->length); ++ if (k5_buf_data(&buf) == NULL) { ++ ret = ENOMEM; ++ goto cleanup; ++ } ++ ++ *req_out = k5_buf_data(&buf); ++ *len_out = k5_buf_len(&buf); ++ ++cleanup: ++ krb5_free_data_contents(NULL, &pm.kerb_message); ++ krb5_free_data(NULL, encoded_pm); ++ return ret; ++} ++#else ++static krb5_error_code ++make_proxy_request(struct conn_state *state, const krb5_data *realm, ++ const krb5_data *message, char **req_out, size_t *len_out) ++{ ++ abort(); ++} ++#endif + + /* Set up the actual message we will send across the underlying transport to + * communicate the payload message, using one or both of state->out.sgbuf. */ +-static void +-set_transport_message(struct conn_state *state, const krb5_data *message) ++static krb5_error_code ++set_transport_message(struct conn_state *state, const krb5_data *realm, ++ const krb5_data *message) + { + struct outgoing_message *out = &state->out; ++ char *req = NULL; ++ size_t reqlen; ++ krb5_error_code ret; + + if (message == NULL || message->length == 0) +- return; ++ return 0; + + if (state->addr.transport == TCP) { + store_32_be(message->length, out->msg_len_buf); + SG_SET(&out->sgbuf[0], out->msg_len_buf, 4); + SG_SET(&out->sgbuf[1], message->data, message->length); + out->sg_count = 2; ++ return 0; ++ } else if (state->addr.transport == HTTPS) { ++ ret = make_proxy_request(state, realm, message, &req, &reqlen); ++ if (ret != 0) ++ return ret; ++ SG_SET(&state->out.sgbuf[0], req, reqlen); ++ SG_SET(&state->out.sgbuf[1], 0, 0); ++ state->out.sg_count = 1; ++ free(state->http.https_request); ++ state->http.https_request = req; ++ return 0; + } else { + SG_SET(&out->sgbuf[0], message->data, message->length); + SG_SET(&out->sgbuf[1], NULL, 0); + out->sg_count = 1; ++ return 0; + } + } + + static krb5_error_code + add_connection(struct conn_state **conns, k5_transport transport, + krb5_boolean defer, struct addrinfo *ai, size_t server_index, +- char **udpbufp) ++ const krb5_data *realm, const char *uri_path, char **udpbufp) + { + struct conn_state *state, **tailptr; + +@@ -515,6 +646,11 @@ add_connection(struct conn_state **conns, k5_transport transport, + state->service_connect = service_tcp_connect; + state->service_write = service_tcp_write; + state->service_read = service_tcp_read; ++ } else if (transport == HTTPS) { ++ state->service_connect = service_tcp_connect; ++ state->service_write = service_https_write; ++ state->service_read = service_https_read; ++ state->http.uri_path = uri_path; + } else { + state->service_connect = NULL; + state->service_write = NULL; +@@ -589,10 +725,10 @@ translate_ai_error (int err) + * connections. + */ + static krb5_error_code +-resolve_server(krb5_context context, const struct serverlist *servers, +- size_t ind, k5_transport_strategy strategy, +- const krb5_data *message, char **udpbufp, +- struct conn_state **conns) ++resolve_server(krb5_context context, const krb5_data *realm, ++ const struct serverlist *servers, size_t ind, ++ k5_transport_strategy strategy, const krb5_data *message, ++ char **udpbufp, struct conn_state **conns) + { + krb5_error_code retval; + struct server_entry *entry = &servers->servers[ind]; +@@ -615,7 +751,7 @@ resolve_server(krb5_context context, const struct serverlist *servers, + ai.ai_addr = (struct sockaddr *)&entry->addr; + defer = (entry->transport != transport); + return add_connection(conns, entry->transport, defer, &ai, ind, +- udpbufp); ++ realm, entry->uri_path, udpbufp); + } + + /* If the entry has a specified transport, use it. */ +@@ -639,8 +775,10 @@ resolve_server(krb5_context context, const struct serverlist *servers, + + /* Add each address with the specified or preferred transport. */ + retval = 0; +- for (a = addrs; a != 0 && retval == 0; a = a->ai_next) +- retval = add_connection(conns, transport, FALSE, a, ind, udpbufp); ++ for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { ++ retval = add_connection(conns, transport, FALSE, a, ind, realm, ++ entry->uri_path, udpbufp); ++ } + + /* For TCP_OR_UDP entries, add each address again with the non-preferred + * transport, unless we are avoiding UDP. Flag these as deferred. */ +@@ -648,7 +786,8 @@ resolve_server(krb5_context context, const struct serverlist *servers, + transport = (strategy == UDP_FIRST) ? TCP : UDP; + for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { + a->ai_socktype = socktype_for_transport(transport); +- retval = add_connection(conns, transport, TRUE, a, ind, udpbufp); ++ retval = add_connection(conns, transport, TRUE, a, ind, realm, ++ entry->uri_path, udpbufp); + } + } + freeaddrinfo(addrs); +@@ -658,6 +797,7 @@ resolve_server(krb5_context context, const struct serverlist *servers, + static int + start_connection(krb5_context context, struct conn_state *state, + const krb5_data *message, struct select_state *selstate, ++ const krb5_data *realm, + struct sendto_callback_info *callback_info) + { + int fd, e, type; +@@ -718,7 +858,15 @@ start_connection(krb5_context context, struct conn_state *state, + + message = &state->callback_buffer; + } +- set_transport_message(state, message); ++ ++ e = set_transport_message(state, realm, message); ++ if (e != 0) { ++ TRACE_SENDTO_KDC_ERROR_SET_MESSAGE(context, &state->addr, e); ++ (void) closesocket(state->fd); ++ state->fd = INVALID_SOCKET; ++ state->state = FAILED; ++ return -4; ++ } + + if (state->addr.transport == UDP) { + /* Send it now. */ +@@ -733,7 +881,7 @@ start_connection(krb5_context context, struct conn_state *state, + (void) closesocket(state->fd); + state->fd = INVALID_SOCKET; + state->state = FAILED; +- return -4; ++ return -5; + } else { + state->state = READING; + } +@@ -760,6 +908,7 @@ start_connection(krb5_context context, struct conn_state *state, + static int + maybe_send(krb5_context context, struct conn_state *conn, + const krb5_data *message, struct select_state *selstate, ++ const krb5_data *realm, + struct sendto_callback_info *callback_info) + { + sg_buf *sg; +@@ -767,7 +916,7 @@ maybe_send(krb5_context context, struct conn_state *conn, + + if (conn->state == INITIALIZING) { + return start_connection(context, conn, message, selstate, +- callback_info); ++ realm, callback_info); + } + + /* Did we already shut down this channel? */ +@@ -802,6 +951,8 @@ static void + kill_conn(krb5_context context, struct conn_state *conn, + struct select_state *selstate) + { ++ free_http_ssl_data(conn); ++ + if (socktype_for_transport(conn->addr.transport) == SOCK_STREAM) + TRACE_SENDTO_KDC_TCP_DISCONNECT(context, &conn->addr); + cm_remove_fd(selstate, conn->fd); +@@ -876,7 +1027,7 @@ service_tcp_connect(krb5_context context, const krb5_data *realm, + if (get_curtime_ms(&conn->endtime) == 0) + conn->endtime += 10000; + +- return service_tcp_write(context, realm, conn, selstate); ++ return conn->service_write(context, realm, conn, selstate); + } + + /* Sets conn->state to READING when done. */ +@@ -982,6 +1133,223 @@ service_udp_read(krb5_context context, const krb5_data *realm, + return TRUE; + } + ++#ifdef PROXY_TLS_IMPL_OPENSSL ++/* Output any error strings that OpenSSL's accumulated as tracing messages. */ ++static void ++flush_ssl_errors(krb5_context context) ++{ ++ unsigned long err; ++ char buf[128]; ++ ++ while ((err = ERR_get_error()) != 0) { ++ ERR_error_string_n(err, buf, sizeof(buf)); ++ TRACE_SENDTO_KDC_HTTPS_ERROR(context, buf); ++ } ++} ++ ++/* ++ * Set up structures that we use to manage the SSL handling for this connection ++ * and apply any non-default settings. Kill the connection and return false if ++ * anything goes wrong while we're doing that; return true otherwise. ++ */ ++static krb5_boolean ++setup_ssl(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate) ++{ ++ long options; ++ SSL_CTX *ctx = NULL; ++ SSL *ssl = NULL; ++ ++ /* Do general SSL library setup. */ ++ ctx = SSL_CTX_new(SSLv23_client_method()); ++ if (ctx == NULL) ++ goto kill_conn; ++ options = SSL_CTX_get_options(ctx); ++ SSL_CTX_set_options(ctx, options | SSL_OP_NO_SSLv2); ++ ++ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); ++ if (!SSL_CTX_set_default_verify_paths(ctx)) ++ goto kill_conn; ++ ++ ssl = SSL_new(ctx); ++ if (ssl == NULL) ++ goto kill_conn; ++ ++ /* Tell the SSL library about the socket. */ ++ if (!SSL_set_fd(ssl, conn->fd)) ++ goto kill_conn; ++ SSL_set_connect_state(ssl); ++ ++ SSL_CTX_free(ctx); ++ conn->http.ssl = ssl; ++ ++ return TRUE; ++ ++kill_conn: ++ TRACE_SENDTO_KDC_HTTPS_ERROR_CONNECT(context, &conn->addr); ++ flush_ssl_errors(context); ++ SSL_free(ssl); ++ SSL_CTX_free(ctx); ++ kill_conn(context, conn, selstate); ++ return FALSE; ++} ++ ++/* Set conn->state to READING when done; otherwise, call a cm_set_. */ ++static krb5_boolean ++service_https_write(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate) ++{ ++ ssize_t nwritten; ++ int e; ++ ++ /* If this is our first time in here, set up the SSL context. */ ++ if (conn->http.ssl == NULL && !setup_ssl(context, realm, conn, selstate)) ++ return FALSE; ++ ++ /* Try to transmit our request to the server. */ ++ nwritten = SSL_write(conn->http.ssl, SG_BUF(conn->out.sgp), ++ SG_LEN(conn->out.sgbuf)); ++ if (nwritten <= 0) { ++ e = SSL_get_error(conn->http.ssl, nwritten); ++ if (e == SSL_ERROR_WANT_READ) { ++ cm_read(selstate, conn->fd); ++ return FALSE; ++ } else if (e == SSL_ERROR_WANT_WRITE) { ++ cm_write(selstate, conn->fd); ++ return FALSE; ++ } ++ TRACE_SENDTO_KDC_HTTPS_ERROR_SEND(context, &conn->addr); ++ flush_ssl_errors(context); ++ kill_conn(context, conn, selstate); ++ return FALSE; ++ } ++ ++ /* Done writing, switch to reading. */ ++ TRACE_SENDTO_KDC_HTTPS_SEND(context, &conn->addr); ++ cm_read(selstate, conn->fd); ++ conn->state = READING; ++ return FALSE; ++} ++ ++/* ++ * Return true on readable data, call a cm_read/write function and return ++ * false if the SSL layer needs it, kill the connection otherwise. ++ */ ++static krb5_boolean ++https_read_bytes(krb5_context context, struct conn_state *conn, ++ struct select_state *selstate) ++{ ++ size_t bufsize; ++ ssize_t nread; ++ krb5_boolean readbytes = FALSE; ++ int e = 0; ++ char *tmp; ++ struct incoming_message *in = &conn->in; ++ ++ for (;;) { ++ if (in->buf == NULL || in->bufsize - in->pos < 1024) { ++ bufsize = in->bufsize ? in->bufsize * 2 : 8192; ++ if (bufsize > 1024 * 1024) { ++ kill_conn(context, conn, selstate); ++ return FALSE; ++ } ++ tmp = realloc(in->buf, bufsize); ++ if (tmp == NULL) { ++ kill_conn(context, conn, selstate); ++ return FALSE; ++ } ++ in->buf = tmp; ++ in->bufsize = bufsize; ++ } ++ ++ nread = SSL_read(conn->http.ssl, &in->buf[in->pos], ++ in->bufsize - in->pos - 1); ++ if (nread <= 0) ++ break; ++ in->pos += nread; ++ in->buf[in->pos] = '\0'; ++ readbytes = TRUE; ++ } ++ ++ e = SSL_get_error(conn->http.ssl, nread); ++ if (e == SSL_ERROR_WANT_READ) { ++ cm_read(selstate, conn->fd); ++ return FALSE; ++ } else if (e == SSL_ERROR_WANT_WRITE) { ++ cm_write(selstate, conn->fd); ++ return FALSE; ++ } else if ((e == SSL_ERROR_ZERO_RETURN) || ++ (e == SSL_ERROR_SYSCALL && nread == 0 && readbytes)) { ++ return TRUE; ++ } ++ ++ e = readbytes ? SOCKET_ERRNO : ECONNRESET; ++ TRACE_SENDTO_KDC_HTTPS_ERROR_RECV(context, &conn->addr, e); ++ flush_ssl_errors(context); ++ kill_conn(context, conn, selstate); ++ return FALSE; ++} ++ ++/* Return true on readable, valid KKDCPP data. */ ++static krb5_boolean ++service_https_read(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate) ++{ ++ krb5_kkdcp_message *pm = NULL; ++ krb5_data buf; ++ const char *rep; ++ struct incoming_message *in = &conn->in; ++ ++ /* Read data through the encryption layer. */ ++ if (!https_read_bytes(context, conn, selstate)) ++ return FALSE; ++ ++ /* Find the beginning of the response body. */ ++ rep = strstr(in->buf, "\r\n\r\n"); ++ if (rep == NULL) ++ goto kill_conn; ++ rep += 4; ++ ++ /* Decode the response. */ ++ buf = make_data((char *)rep, in->pos - (rep - in->buf)); ++ if (decode_krb5_kkdcp_message(&buf, &pm) != 0) ++ goto kill_conn; ++ ++ /* Check and discard the message length at the front of the kerb_message ++ * field after decoding. If it's wrong or missing, something broke. */ ++ if (pm->kerb_message.length < 4 || ++ load_32_be(pm->kerb_message.data) != pm->kerb_message.length - 4) { ++ goto kill_conn; ++ } ++ ++ /* Replace all of the content that we read back with just the message. */ ++ memcpy(in->buf, pm->kerb_message.data + 4, pm->kerb_message.length - 4); ++ in->pos = pm->kerb_message.length - 4; ++ k5_free_kkdcp_message(context, pm); ++ ++ return TRUE; ++ ++kill_conn: ++ TRACE_SENDTO_KDC_HTTPS_ERROR(context, in->buf); ++ k5_free_kkdcp_message(context, pm); ++ kill_conn(context, conn, selstate); ++ return FALSE; ++} ++#else ++static krb5_boolean ++service_https_write(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate) ++{ ++ abort(); ++} ++static krb5_boolean ++service_https_read(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate) ++{ ++ abort(); ++} ++#endif ++ + /* Return the maximum of endtime and the endtime fields of all currently active + * TCP connections. */ + static time_ms +@@ -1123,7 +1491,7 @@ k5_sendto(krb5_context context, const krb5_data *message, + for (s = 0; s < servers->nservers && !done; s++) { + /* Find the current tail pointer. */ + for (tailptr = &conns; *tailptr != NULL; tailptr = &(*tailptr)->next); +- retval = resolve_server(context, servers, s, strategy, message, ++ retval = resolve_server(context, realm, servers, s, strategy, message, + &udpbuf, &conns); + if (retval) + goto cleanup; +@@ -1132,7 +1500,8 @@ k5_sendto(krb5_context context, const krb5_data *message, + * non-preferred RFC 4120 transport. */ + if (state->defer) + continue; +- if (maybe_send(context, state, message, sel_state, callback_info)) ++ if (maybe_send(context, state, message, sel_state, realm, ++ callback_info)) + continue; + done = service_fds(context, sel_state, 1000, conns, seltemp, + realm, msg_handler, msg_handler_data, &winner); +@@ -1144,7 +1513,8 @@ k5_sendto(krb5_context context, const krb5_data *message, + for (state = conns; state != NULL && !done; state = state->next) { + if (!state->defer) + continue; +- if (maybe_send(context, state, message, sel_state, callback_info)) ++ if (maybe_send(context, state, message, sel_state, realm, ++ callback_info)) + continue; + done = service_fds(context, sel_state, 1000, conns, seltemp, + realm, msg_handler, msg_handler_data, &winner); +@@ -1160,7 +1530,8 @@ k5_sendto(krb5_context context, const krb5_data *message, + delay = 4000; + for (pass = 1; pass < MAX_PASS && !done; pass++) { + for (state = conns; state != NULL && !done; state = state->next) { +- if (maybe_send(context, state, message, sel_state, callback_info)) ++ if (maybe_send(context, state, message, sel_state, realm, ++ callback_info)) + continue; + done = service_fds(context, sel_state, 1000, conns, seltemp, + realm, msg_handler, msg_handler_data, &winner); +@@ -1194,8 +1565,12 @@ k5_sendto(krb5_context context, const krb5_data *message, + cleanup: + for (state = conns; state != NULL; state = next) { + next = state->next; +- if (state->fd != INVALID_SOCKET) ++ if (state->fd != INVALID_SOCKET) { ++ if (socktype_for_transport(state->addr.transport) == SOCK_STREAM) ++ TRACE_SENDTO_KDC_TCP_DISCONNECT(context, &state->addr); + closesocket(state->fd); ++ free_http_ssl_data(state); ++ } + if (state->state == READING && state->in.buf != udpbuf) + free(state->in.buf); + if (callback_info) { +diff --git a/src/lib/krb5/os/t_locate_kdc.c b/src/lib/krb5/os/t_locate_kdc.c +index 300aa71..dd609fd 100644 +--- a/src/lib/krb5/os/t_locate_kdc.c ++++ b/src/lib/krb5/os/t_locate_kdc.c +@@ -39,6 +39,8 @@ ttypename (k5_transport ttype) + return "tcp"; + case UDP: + return "udp"; ++ case HTTPS: ++ return "https"; + default: + snprintf(buf, sizeof(buf), "?%d", ttype); + return buf; +diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c +index 8319a86..105a2cd 100644 +--- a/src/lib/krb5/os/trace.c ++++ b/src/lib/krb5/os/trace.c +@@ -201,6 +201,8 @@ trace_format(krb5_context context, const char *fmt, va_list ap) + k5_buf_add(&buf, "dgram"); + else if (ra->transport == TCP) + k5_buf_add(&buf, "stream"); ++ else if (ra->transport == HTTPS) ++ k5_buf_add(&buf, "https"); + else + k5_buf_add_fmt(&buf, "transport%d", ra->transport); + +-- +2.1.0 + diff --git a/SOURCES/0007-Make-krb5_cc_new_unique-create-DIR-directories.patch b/SOURCES/0007-Make-krb5_cc_new_unique-create-DIR-directories.patch new file mode 100644 index 0000000..c0b8778 --- /dev/null +++ b/SOURCES/0007-Make-krb5_cc_new_unique-create-DIR-directories.patch @@ -0,0 +1,37 @@ +Context tweaked to apply to 1.12.1. + +From bca1191210eb582fe09e94486e2631d72b8a5ca5 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Fri, 8 Aug 2014 16:58:03 -0400 +Subject: [PATCH 7/7] Make krb5_cc_new_unique create DIR: directories + +When we use krb5_cc_new_unique to create a new cache in a directory +cache collection, we will fail if the directory doesn't exist yet. + +Go ahead and preemptively create it, as we do during krb5_cc_resolve, +before attempting to create a new file under it. + +ticket: 7988 (new) +target_version: 1.13 +tags: pullup +--- + src/lib/krb5/ccache/cc_dir.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/lib/krb5/ccache/cc_dir.c b/src/lib/krb5/ccache/cc_dir.c +index d82f335..b00a6bb 100644 +--- a/src/lib/krb5/ccache/cc_dir.c ++++ b/src/lib/krb5/ccache/cc_dir.c +@@ -401,6 +401,9 @@ dcc_gen_new(krb5_context context, krb5_ccache *cache_out) + "collection")); + return KRB5_DCC_CANNOT_CREATE; + } ++ ret = verify_dir(context, dirname); ++ if (ret) ++ goto cleanup; + ret = k5_path_join(dirname, "tktXXXXXX", &template); + if (ret) + goto cleanup; +-- +2.0.4 + diff --git a/SOURCES/0008-Load-custom-anchors-when-using-KKDCP.patch b/SOURCES/0008-Load-custom-anchors-when-using-KKDCP.patch new file mode 100644 index 0000000..19fe964 --- /dev/null +++ b/SOURCES/0008-Load-custom-anchors-when-using-KKDCP.patch @@ -0,0 +1,312 @@ +From f220067c2969aab107bd1300ad1cb8d4855389a7 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Thu, 17 Apr 2014 17:17:13 -0400 +Subject: [PATCH 08/13] Load custom anchors when using KKDCP + +Add an http_anchors per-realm setting which we'll apply when using an +HTTPS proxy, more or less mimicking the syntax of its similarly-named +PKINIT counterpart. We only check the [realms] section, though. + +ticket: 7929 +--- + doc/admin/conf_files/krb5_conf.rst | 26 ++++++ + src/include/k5-int.h | 1 + + src/include/k5-trace.h | 7 ++ + src/lib/krb5/os/sendto_kdc.c | 169 ++++++++++++++++++++++++++++++++++++- + 4 files changed, 201 insertions(+), 2 deletions(-) + +diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst +index 19ea9c9..c069327 100644 +--- a/doc/admin/conf_files/krb5_conf.rst ++++ b/doc/admin/conf_files/krb5_conf.rst +@@ -428,6 +428,32 @@ following tags may be specified in the realm's subsection: + (for example, when converting ``rcmd.hostname`` to + ``host/hostname.domain``). + ++**http_anchors** ++ When KDCs and kpasswd servers are accessed through HTTPS proxies, this tag ++ can be used to specify the location of the CA certificate which should be ++ trusted to issue the certificate for a proxy server. If left unspecified, ++ the system-wide default set of CA certificates is used. ++ ++ The syntax for values is similar to that of values for the ++ **pkinit_anchors** tag: ++ ++ **FILE:** *filename* ++ ++ *filename* is assumed to be the name of an OpenSSL-style ca-bundle file. ++ ++ **DIR:** *dirname* ++ ++ *dirname* is assumed to be an directory which contains CA certificates. ++ All files in the directory will be examined; if they contain certificates ++ (in PEM format), they will be used. ++ ++ **ENV:** *envvar* ++ ++ *envvar* specifies the name of an environment variable which has been set ++ to a value conforming to one of the previous values. For example, ++ ``ENV:X509_PROXY_CA``, where environment variable ``X509_PROXY_CA`` has ++ been set to ``FILE:/tmp/my_proxy.pem``. ++ + **kdc** + The name or address of a host running a KDC for that realm. An + optional port number, separated from the hostname by a colon, may +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index 8f039ee..187d16d 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -212,6 +212,7 @@ typedef unsigned char u_char; + #define KRB5_CONF_EXTRA_ADDRESSES "extra_addresses" + #define KRB5_CONF_FORWARDABLE "forwardable" + #define KRB5_CONF_HOST_BASED_SERVICES "host_based_services" ++#define KRB5_CONF_HTTP_ANCHORS "http_anchors" + #define KRB5_CONF_IGNORE_ACCEPTOR_HOSTNAME "ignore_acceptor_hostname" + #define KRB5_CONF_IPROP_ENABLE "iprop_enable" + #define KRB5_CONF_IPROP_MASTER_ULOGSIZE "iprop_master_ulogsize" +diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h +index f0d79f1..046bc95 100644 +--- a/src/include/k5-trace.h ++++ b/src/include/k5-trace.h +@@ -324,6 +324,13 @@ void krb5int_trace(krb5_context context, const char *fmt, ...); + TRACE(c, "Resolving hostname {str}", hostname) + #define TRACE_SENDTO_KDC_RESPONSE(c, len, raddr) \ + TRACE(c, "Received answer ({int} bytes) from {raddr}", len, raddr) ++#define TRACE_SENDTO_KDC_HTTPS_NO_REMOTE_CERTIFICATE(c) \ ++ TRACE(c, "HTTPS server certificate not received") ++#define TRACE_SENDTO_KDC_HTTPS_PROXY_CERTIFICATE_ERROR(c, depth, \ ++ namelen, name, \ ++ err, errs) \ ++ TRACE(c, "HTTPS certificate error at {int} ({lenstr}): " \ ++ "{int} ({str})", depth, namelen, name, err, errs) + #define TRACE_SENDTO_KDC_HTTPS_ERROR_CONNECT(c, raddr) \ + TRACE(c, "HTTPS error connecting to {raddr}", raddr) + #define TRACE_SENDTO_KDC_HTTPS_ERROR_RECV(c, raddr, err) \ +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index a4727c4..4bd8698 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -77,6 +77,9 @@ + #ifdef PROXY_TLS_IMPL_OPENSSL + #include + #include ++#include ++#include ++#include + #endif + + #define MAX_PASS 3 +@@ -152,6 +155,11 @@ struct conn_state { + } http; + }; + ++#ifdef PROXY_TLS_IMPL_OPENSSL ++/* Extra-data identifier, used to pass context into the verify callback. */ ++static int ssl_ex_context_id = -1; ++#endif ++ + void + k5_sendto_kdc_initialize(void) + { +@@ -159,6 +167,8 @@ k5_sendto_kdc_initialize(void) + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); ++ ++ ssl_ex_context_id = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); + #endif + } + +@@ -1147,6 +1157,152 @@ flush_ssl_errors(krb5_context context) + } + } + ++static krb5_error_code ++load_http_anchor_file(X509_STORE *store, const char *path) ++{ ++ FILE *fp; ++ STACK_OF(X509_INFO) *sk = NULL; ++ X509_INFO *xi; ++ int i; ++ ++ fp = fopen(path, "r"); ++ if (fp == NULL) ++ return errno; ++ sk = PEM_X509_INFO_read(fp, NULL, NULL, NULL); ++ fclose(fp); ++ if (sk == NULL) ++ return ENOENT; ++ for (i = 0; i < sk_X509_INFO_num(sk); i++) { ++ xi = sk_X509_INFO_value(sk, i); ++ if (xi->x509 != NULL) ++ X509_STORE_add_cert(store, xi->x509); ++ } ++ sk_X509_INFO_pop_free(sk, X509_INFO_free); ++ return 0; ++} ++ ++static krb5_error_code ++load_http_anchor_dir(X509_STORE *store, const char *path) ++{ ++ DIR *d = NULL; ++ struct dirent *dentry = NULL; ++ char filename[1024]; ++ krb5_boolean found_any = FALSE; ++ ++ d = opendir(path); ++ if (d == NULL) ++ return ENOENT; ++ while ((dentry = readdir(d)) != NULL) { ++ if (dentry->d_name[0] != '.') { ++ snprintf(filename, sizeof(filename), "%s/%s", ++ path, dentry->d_name); ++ if (load_http_anchor_file(store, filename) == 0) ++ found_any = TRUE; ++ } ++ } ++ closedir(d); ++ return found_any ? 0 : ENOENT; ++} ++ ++static krb5_error_code ++load_http_anchor(SSL_CTX *ctx, const char *location) ++{ ++ X509_STORE *store; ++ const char *envloc; ++ ++ store = SSL_CTX_get_cert_store(ctx); ++ if (strncmp(location, "FILE:", 5) == 0) { ++ return load_http_anchor_file(store, location + 5); ++ } else if (strncmp(location, "DIR:", 4) == 0) { ++ return load_http_anchor_dir(store, location + 4); ++ } else if (strncmp(location, "ENV:", 4) == 0) { ++ envloc = getenv(location + 4); ++ if (envloc == NULL) ++ return ENOENT; ++ return load_http_anchor(ctx, envloc); ++ } ++ return EINVAL; ++} ++ ++static krb5_error_code ++load_http_verify_anchors(krb5_context context, const krb5_data *realm, ++ SSL_CTX *sctx) ++{ ++ const char *anchors[4]; ++ char **values = NULL, *realmz; ++ unsigned int i; ++ krb5_error_code err; ++ ++ realmz = k5memdup0(realm->data, realm->length, &err); ++ if (realmz == NULL) ++ goto cleanup; ++ ++ /* Load the configured anchors. */ ++ anchors[0] = KRB5_CONF_REALMS; ++ anchors[1] = realmz; ++ anchors[2] = KRB5_CONF_HTTP_ANCHORS; ++ anchors[3] = NULL; ++ if (profile_get_values(context->profile, anchors, &values) == 0) { ++ for (i = 0; values[i] != NULL; i++) { ++ err = load_http_anchor(sctx, values[i]); ++ if (err != 0) ++ break; ++ } ++ profile_free_list(values); ++ } else { ++ /* Use the library defaults. */ ++ if (SSL_CTX_set_default_verify_paths(sctx) != 1) ++ err = ENOENT; ++ } ++ ++cleanup: ++ free(realmz); ++ return err; ++} ++ ++static int ++ssl_verify_callback(int preverify_ok, X509_STORE_CTX *store_ctx) ++{ ++ X509 *x; ++ SSL *ssl; ++ BIO *bio; ++ krb5_context context; ++ int err, depth; ++ const char *cert = NULL, *errstr; ++ size_t count; ++ ++ ssl = X509_STORE_CTX_get_ex_data(store_ctx, ++ SSL_get_ex_data_X509_STORE_CTX_idx()); ++ context = SSL_get_ex_data(ssl, ssl_ex_context_id); ++ /* We do have the peer's cert, right? */ ++ x = X509_STORE_CTX_get_current_cert(store_ctx); ++ if (x == NULL) { ++ TRACE_SENDTO_KDC_HTTPS_NO_REMOTE_CERTIFICATE(context); ++ return 0; ++ } ++ /* Figure out where we are. */ ++ depth = X509_STORE_CTX_get_error_depth(store_ctx); ++ if (depth < 0) ++ return 0; ++ /* If there's an error at this level that we're not ignoring, fail. */ ++ err = X509_STORE_CTX_get_error(store_ctx); ++ if (err != X509_V_OK) { ++ bio = BIO_new(BIO_s_mem()); ++ if (bio != NULL) { ++ X509_NAME_print_ex(bio, x->cert_info->subject, 0, 0); ++ count = BIO_get_mem_data(bio, &cert); ++ errstr = X509_verify_cert_error_string(err); ++ TRACE_SENDTO_KDC_HTTPS_PROXY_CERTIFICATE_ERROR(context, depth, ++ count, cert, err, ++ errstr); ++ BIO_free(bio); ++ } ++ return 0; ++ } ++ /* All done. */ ++ return 1; ++} ++ + /* + * Set up structures that we use to manage the SSL handling for this connection + * and apply any non-default settings. Kill the connection and return false if +@@ -1156,10 +1312,14 @@ static krb5_boolean + setup_ssl(krb5_context context, const krb5_data *realm, + struct conn_state *conn, struct select_state *selstate) + { ++ int e; + long options; + SSL_CTX *ctx = NULL; + SSL *ssl = NULL; + ++ if (ssl_ex_context_id == -1) ++ goto kill_conn; ++ + /* Do general SSL library setup. */ + ctx = SSL_CTX_new(SSLv23_client_method()); + if (ctx == NULL) +@@ -1167,14 +1327,19 @@ setup_ssl(krb5_context context, const krb5_data *realm, + options = SSL_CTX_get_options(ctx); + SSL_CTX_set_options(ctx, options | SSL_OP_NO_SSLv2); + +- SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); +- if (!SSL_CTX_set_default_verify_paths(ctx)) ++ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, ssl_verify_callback); ++ X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), 0); ++ e = load_http_verify_anchors(context, realm, ctx); ++ if (e != 0) + goto kill_conn; + + ssl = SSL_new(ctx); + if (ssl == NULL) + goto kill_conn; + ++ if (!SSL_set_ex_data(ssl, ssl_ex_context_id, context)) ++ goto kill_conn; ++ + /* Tell the SSL library about the socket. */ + if (!SSL_set_fd(ssl, conn->fd)) + goto kill_conn; +-- +2.1.0 + diff --git a/SOURCES/0009-Check-names-in-the-server-s-cert-when-using-KKDCP.patch b/SOURCES/0009-Check-names-in-the-server-s-cert-when-using-KKDCP.patch new file mode 100644 index 0000000..14e3354 --- /dev/null +++ b/SOURCES/0009-Check-names-in-the-server-s-cert-when-using-KKDCP.patch @@ -0,0 +1,562 @@ +From f7825e81b1ebf533c1dba9f84ae9ad36073a89cf Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Thu, 17 Apr 2014 17:19:03 -0400 +Subject: [PATCH 09/13] Check names in the server's cert when using KKDCP + +When we connect to a KDC using an HTTPS proxy, check that the naming +information in the certificate matches the name or address which we +extracted from the server URL in the configuration. + +ticket: 7929 +--- + src/include/k5-trace.h | 5 + + src/lib/krb5/os/Makefile.in | 3 + + src/lib/krb5/os/checkhost.c | 251 +++++++++++++++++++++++++++++++++++++++++++ + src/lib/krb5/os/checkhost.h | 39 +++++++ + src/lib/krb5/os/deps | 14 ++- + src/lib/krb5/os/sendto_kdc.c | 53 +++++++-- + 6 files changed, 355 insertions(+), 10 deletions(-) + create mode 100644 src/lib/krb5/os/checkhost.c + create mode 100644 src/lib/krb5/os/checkhost.h + +diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h +index 046bc95..9e75b29 100644 +--- a/src/include/k5-trace.h ++++ b/src/include/k5-trace.h +@@ -324,6 +324,11 @@ void krb5int_trace(krb5_context context, const char *fmt, ...); + TRACE(c, "Resolving hostname {str}", hostname) + #define TRACE_SENDTO_KDC_RESPONSE(c, len, raddr) \ + TRACE(c, "Received answer ({int} bytes) from {raddr}", len, raddr) ++#define TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MISMATCH(c, hostname) \ ++ TRACE(c, "HTTPS certificate name mismatch: server certificate is " \ ++ "not for \"{str}\"", hostname) ++#define TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MATCH(c, hostname) \ ++ TRACE(c, "HTTPS certificate name matched \"{str}\"", hostname) + #define TRACE_SENDTO_KDC_HTTPS_NO_REMOTE_CERTIFICATE(c) \ + TRACE(c, "HTTPS server certificate not received") + #define TRACE_SENDTO_KDC_HTTPS_PROXY_CERTIFICATE_ERROR(c, depth, \ +diff --git a/src/lib/krb5/os/Makefile.in b/src/lib/krb5/os/Makefile.in +index fb4001a..fa8a093 100644 +--- a/src/lib/krb5/os/Makefile.in ++++ b/src/lib/krb5/os/Makefile.in +@@ -13,6 +13,7 @@ STLIBOBJS= \ + c_ustime.o \ + ccdefname.o \ + changepw.o \ ++ checkhost.o \ + dnsglue.o \ + dnssrv.o \ + expand_path.o \ +@@ -59,6 +60,7 @@ OBJS= \ + $(OUTPRE)c_ustime.$(OBJEXT) \ + $(OUTPRE)ccdefname.$(OBJEXT) \ + $(OUTPRE)changepw.$(OBJEXT) \ ++ $(OUTPRE)checkhost.$(OBJEXT) \ + $(OUTPRE)dnsglue.$(OBJEXT) \ + $(OUTPRE)dnssrv.$(OBJEXT) \ + $(OUTPRE)expand_path.$(OBJEXT) \ +@@ -105,6 +107,7 @@ SRCS= \ + $(srcdir)/c_ustime.c \ + $(srcdir)/ccdefname.c \ + $(srcdir)/changepw.c \ ++ $(srcdir)/checkhost.c \ + $(srcdir)/dnsglue.c \ + $(srcdir)/dnssrv.c \ + $(srcdir)/expand_path.c \ +diff --git a/src/lib/krb5/os/checkhost.c b/src/lib/krb5/os/checkhost.c +new file mode 100644 +index 0000000..a91615d +--- /dev/null ++++ b/src/lib/krb5/os/checkhost.c +@@ -0,0 +1,251 @@ ++/* ++ * Copyright 2014 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-utf8.h" ++ ++#ifdef PROXY_TLS_IMPL_OPENSSL ++#include ++#include ++#include ++#include "checkhost.h" ++ ++/* Return the passed-in character, lower-cased if it's an ASCII character. */ ++static inline char ++ascii_tolower(char p) ++{ ++ if (KRB5_UPPER(p)) ++ return p + ('a' - 'A'); ++ return p; ++} ++ ++/* ++ * Check a single label. If allow_wildcard is true, and the presented name ++ * includes a wildcard, return true and note that we matched a wildcard. ++ * Otherwise, for both the presented and expected values, do a case-insensitive ++ * comparison of ASCII characters, and a case-sensitive comparison of ++ * everything else. ++ */ ++static krb5_boolean ++label_match(const char *presented, size_t plen, const char *expected, ++ size_t elen, krb5_boolean allow_wildcard, krb5_boolean *wildcard) ++{ ++ unsigned int i; ++ ++ if (allow_wildcard && plen == 1 && presented[0] == '*') { ++ *wildcard = TRUE; ++ return TRUE; ++ } ++ ++ if (plen != elen) ++ return FALSE; ++ ++ for (i = 0; i < elen; i++) { ++ if (ascii_tolower(presented[i]) != ascii_tolower(expected[i])) ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++/* Break up the two names and check them, label by label. */ ++static krb5_boolean ++domain_match(const char *presented, size_t plen, const char *expected) ++{ ++ const char *p, *q, *r, *s; ++ int n_label; ++ krb5_boolean used_wildcard = FALSE; ++ ++ n_label = 0; ++ p = presented; ++ r = expected; ++ while (p < presented + plen && *r != '\0') { ++ q = memchr(p, '.', plen - (p - presented)); ++ if (q == NULL) ++ q = presented + plen; ++ s = r + strcspn(r, "."); ++ if (!label_match(p, q - p, r, s - r, n_label == 0, &used_wildcard)) ++ return FALSE; ++ p = q < presented + plen ? q + 1 : q; ++ r = *s ? s + 1 : s; ++ n_label++; ++ } ++ if (used_wildcard && n_label <= 2) ++ return FALSE; ++ if (p == presented + plen && *r == '\0') ++ return TRUE; ++ return FALSE; ++} ++ ++/* Fetch the list of subjectAltNames from a certificate. */ ++static GENERAL_NAMES * ++get_cert_sans(X509 *x) ++{ ++ int ext; ++ X509_EXTENSION *san_ext; ++ ++ ext = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); ++ if (ext < 0) ++ return NULL; ++ san_ext = X509_get_ext(x, ext); ++ if (san_ext == NULL) ++ return NULL; ++ return X509V3_EXT_d2i(san_ext); ++} ++ ++/* Fetch a CN value from the subjct name field, returning its length, or -1 if ++ * there is no subject name or it contains no CN value. */ ++static ssize_t ++get_cert_cn(X509 *x, char *buf, size_t bufsize) ++{ ++ X509_NAME *name; ++ ++ name = X509_get_subject_name(x); ++ if (name == NULL) ++ return -1; ++ return X509_NAME_get_text_by_NID(name, NID_commonName, buf, bufsize); ++} ++ ++/* ++ * Return true if the passed-in expected IP address matches any of the names we ++ * can recover from the server certificate, false otherwise. ++ */ ++krb5_boolean ++k5_check_cert_address(X509 *x, const char *text) ++{ ++ char buf[1024]; ++ GENERAL_NAMES *sans; ++ GENERAL_NAME *san = NULL; ++ ASN1_OCTET_STRING *ip; ++ krb5_boolean found_ip_san = FALSE, matched = FALSE; ++ int n_sans, i; ++ size_t name_length; ++ union { ++ struct in_addr in; ++ struct in6_addr in6; ++ } name; ++ ++ /* Parse the IP address into an octet string. */ ++ ip = M_ASN1_OCTET_STRING_new(); ++ if (ip == NULL) ++ return FALSE; ++ ++ if (inet_aton(text, &name.in) == 1) ++ name_length = sizeof(name.in); ++ else if (inet_pton(AF_INET6, text, &name.in6) == 1) ++ name_length = sizeof(name.in6); ++ else ++ name_length = 0; ++ ++ if (name_length == 0) { ++ ASN1_OCTET_STRING_free(ip); ++ return FALSE; ++ } ++ M_ASN1_OCTET_STRING_set(ip, &name, name_length); ++ ++ /* Check for matches in ipaddress subjectAltName values. */ ++ sans = get_cert_sans(x); ++ if (sans != NULL) { ++ n_sans = sk_GENERAL_NAME_num(sans); ++ for (i = 0; i < n_sans; i++) { ++ san = sk_GENERAL_NAME_value(sans, i); ++ if (san->type != GEN_IPADD) ++ continue; ++ found_ip_san = TRUE; ++ matched = ASN1_OCTET_STRING_cmp(ip, san->d.iPAddress) == 0; ++ if (matched) ++ break; ++ } ++ sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free); ++ } ++ ASN1_OCTET_STRING_free(ip); ++ ++ if (matched) ++ return TRUE; ++ if (found_ip_san) ++ return matched; ++ ++ /* Check for a match against the CN value in the peer's subject name. */ ++ name_length = get_cert_cn(x, buf, sizeof(buf)); ++ if (name_length >= 0) { ++ /* Do a string compare to check if it's an acceptable value. */ ++ return strlen(text) == name_length && ++ strncmp(text, buf, name_length) == 0; ++ } ++ ++ /* We didn't find a match. */ ++ return FALSE; ++} ++ ++/* ++ * Return true if the passed-in expected name matches any of the names we can ++ * recover from a server certificate, false otherwise. ++ */ ++krb5_boolean ++k5_check_cert_servername(X509 *x, const char *expected) ++{ ++ char buf[1024]; ++ GENERAL_NAMES *sans; ++ GENERAL_NAME *san = NULL; ++ unsigned char *dnsname; ++ krb5_boolean found_dns_san = FALSE, matched = FALSE; ++ int name_length, n_sans, i; ++ ++ /* Check for matches in dnsname subjectAltName values. */ ++ sans = get_cert_sans(x); ++ if (sans != NULL) { ++ n_sans = sk_GENERAL_NAME_num(sans); ++ for (i = 0; i < n_sans; i++) { ++ san = sk_GENERAL_NAME_value(sans, i); ++ if (san->type != GEN_DNS) ++ continue; ++ found_dns_san = TRUE; ++ dnsname = NULL; ++ name_length = ASN1_STRING_to_UTF8(&dnsname, san->d.dNSName); ++ if (dnsname == NULL) ++ continue; ++ matched = domain_match((char *)dnsname, name_length, expected); ++ OPENSSL_free(dnsname); ++ if (matched) ++ break; ++ } ++ sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free); ++ } ++ ++ if (matched) ++ return TRUE; ++ if (found_dns_san) ++ return matched; ++ ++ /* Check for a match against the CN value in the peer's subject name. */ ++ name_length = get_cert_cn(x, buf, sizeof(buf)); ++ if (name_length >= 0) ++ return domain_match(buf, name_length, expected); ++ ++ /* We didn't find a match. */ ++ return FALSE; ++} ++#endif +diff --git a/src/lib/krb5/os/checkhost.h b/src/lib/krb5/os/checkhost.h +new file mode 100644 +index 0000000..b9d751e +--- /dev/null ++++ b/src/lib/krb5/os/checkhost.h +@@ -0,0 +1,39 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* ++ * Copyright 2014 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. ++ */ ++ ++/* ++ * Certificate subjectAltName check prototypes. ++ */ ++ ++#ifndef KRB5_LIBOS_CHECKHOST_PROTO__ ++#define KRB5_LIBOS_CHECKHOST_PROTO__ ++ ++krb5_boolean k5_check_cert_servername(X509 *x, const char *expected); ++krb5_boolean k5_check_cert_address(X509 *x, const char *expected); ++ ++#endif /* KRB5_LIBOS_CHECKHOST_PROTO__ */ +diff --git a/src/lib/krb5/os/deps b/src/lib/krb5/os/deps +index 3dd6d46..d56ff30 100644 +--- a/src/lib/krb5/os/deps ++++ b/src/lib/krb5/os/deps +@@ -49,6 +49,17 @@ changepw.so changepw.po $(OUTPRE)changepw.$(OBJEXT): \ + $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + changepw.c os-proto.h ++checkhost.so checkhost.po $(OUTPRE)checkhost.$(OBJEXT): \ ++ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ ++ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ ++ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ ++ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ ++ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ ++ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ ++ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/k5-utf8.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 checkhost.c checkhost.h + dnsglue.so dnsglue.po $(OUTPRE)dnsglue.$(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 \ +@@ -418,7 +429,8 @@ sendto_kdc.so sendto_kdc.po $(OUTPRE)sendto_kdc.$(OBJEXT): \ + $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ +- $(top_srcdir)/include/socket-utils.h os-proto.h sendto_kdc.c ++ $(top_srcdir)/include/socket-utils.h checkhost.h os-proto.h \ ++ sendto_kdc.c + sn2princ.so sn2princ.po $(OUTPRE)sn2princ.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index 4bd8698..f083c0f 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -80,6 +80,7 @@ + #include + #include + #include ++#include "checkhost.h" + #endif + + #define MAX_PASS 3 +@@ -148,6 +149,7 @@ struct conn_state { + krb5_boolean defer; + struct { + const char *uri_path; ++ const char *servername; + char *https_request; + #ifdef PROXY_TLS_IMPL_OPENSSL + SSL *ssl; +@@ -158,6 +160,7 @@ struct conn_state { + #ifdef PROXY_TLS_IMPL_OPENSSL + /* Extra-data identifier, used to pass context into the verify callback. */ + static int ssl_ex_context_id = -1; ++static int ssl_ex_conn_id = -1; + #endif + + void +@@ -169,6 +172,7 @@ k5_sendto_kdc_initialize(void) + OpenSSL_add_all_algorithms(); + + ssl_ex_context_id = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); ++ ssl_ex_conn_id = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); + #endif + } + +@@ -635,7 +639,8 @@ set_transport_message(struct conn_state *state, const krb5_data *realm, + static krb5_error_code + add_connection(struct conn_state **conns, k5_transport transport, + krb5_boolean defer, struct addrinfo *ai, size_t server_index, +- const krb5_data *realm, const char *uri_path, char **udpbufp) ++ const krb5_data *realm, const char *hostname, ++ const char *uri_path, char **udpbufp) + { + struct conn_state *state, **tailptr; + +@@ -661,6 +666,7 @@ add_connection(struct conn_state **conns, k5_transport transport, + state->service_write = service_https_write; + state->service_read = service_https_read; + state->http.uri_path = uri_path; ++ state->http.servername = hostname; + } else { + state->service_connect = NULL; + state->service_write = NULL; +@@ -760,8 +766,8 @@ resolve_server(krb5_context context, const krb5_data *realm, + ai.ai_addrlen = entry->addrlen; + ai.ai_addr = (struct sockaddr *)&entry->addr; + defer = (entry->transport != transport); +- return add_connection(conns, entry->transport, defer, &ai, ind, +- realm, entry->uri_path, udpbufp); ++ return add_connection(conns, entry->transport, defer, &ai, ind, realm, ++ NULL, entry->uri_path, udpbufp); + } + + /* If the entry has a specified transport, use it. */ +@@ -787,7 +793,7 @@ resolve_server(krb5_context context, const krb5_data *realm, + retval = 0; + for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { + retval = add_connection(conns, transport, FALSE, a, ind, realm, +- entry->uri_path, udpbufp); ++ entry->hostname, entry->uri_path, udpbufp); + } + + /* For TCP_OR_UDP entries, add each address again with the non-preferred +@@ -797,7 +803,7 @@ resolve_server(krb5_context context, const krb5_data *realm, + for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { + a->ai_socktype = socktype_for_transport(transport); + retval = add_connection(conns, transport, TRUE, a, ind, realm, +- entry->uri_path, udpbufp); ++ entry->hostname, entry->uri_path, udpbufp); + } + } + freeaddrinfo(addrs); +@@ -1260,6 +1266,20 @@ cleanup: + return err; + } + ++static krb5_boolean ++ssl_check_name_or_ip(X509 *x, const char *expected_name) ++{ ++ struct in_addr in; ++ struct in6_addr in6; ++ ++ if (inet_aton(expected_name, &in) != 0 || ++ inet_pton(AF_INET6, expected_name, &in6) != 0) { ++ return k5_check_cert_address(x, expected_name); ++ } else { ++ return k5_check_cert_servername(x, expected_name); ++ } ++} ++ + static int + ssl_verify_callback(int preverify_ok, X509_STORE_CTX *store_ctx) + { +@@ -1268,12 +1288,14 @@ ssl_verify_callback(int preverify_ok, X509_STORE_CTX *store_ctx) + BIO *bio; + krb5_context context; + int err, depth; +- const char *cert = NULL, *errstr; ++ struct conn_state *conn = NULL; ++ const char *cert = NULL, *errstr, *expected_name; + size_t count; + + ssl = X509_STORE_CTX_get_ex_data(store_ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + context = SSL_get_ex_data(ssl, ssl_ex_context_id); ++ conn = SSL_get_ex_data(ssl, ssl_ex_conn_id); + /* We do have the peer's cert, right? */ + x = X509_STORE_CTX_get_current_cert(store_ctx); + if (x == NULL) { +@@ -1299,8 +1321,19 @@ ssl_verify_callback(int preverify_ok, X509_STORE_CTX *store_ctx) + } + return 0; + } +- /* All done. */ +- return 1; ++ /* If we're not looking at the peer, we're done and everything's ok. */ ++ if (depth != 0) ++ return 1; ++ /* Check if the name we expect to find is in the certificate. */ ++ expected_name = conn->http.servername; ++ if (ssl_check_name_or_ip(x, expected_name)) { ++ TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MATCH(context, expected_name); ++ return 1; ++ } else { ++ TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MISMATCH(context, expected_name); ++ } ++ /* The name didn't match. */ ++ return 0; + } + + /* +@@ -1317,7 +1350,7 @@ setup_ssl(krb5_context context, const krb5_data *realm, + SSL_CTX *ctx = NULL; + SSL *ssl = NULL; + +- if (ssl_ex_context_id == -1) ++ if (ssl_ex_context_id == -1 || ssl_ex_conn_id == -1) + goto kill_conn; + + /* Do general SSL library setup. */ +@@ -1339,6 +1372,8 @@ setup_ssl(krb5_context context, const krb5_data *realm, + + if (!SSL_set_ex_data(ssl, ssl_ex_context_id, context)) + goto kill_conn; ++ if (!SSL_set_ex_data(ssl, ssl_ex_conn_id, conn)) ++ goto kill_conn; + + /* Tell the SSL library about the socket. */ + if (!SSL_set_fd(ssl, conn->fd)) +-- +2.1.0 + diff --git a/SOURCES/0010-Add-some-longer-form-docs-for-HTTPS.patch b/SOURCES/0010-Add-some-longer-form-docs-for-HTTPS.patch new file mode 100644 index 0000000..88f1327 --- /dev/null +++ b/SOURCES/0010-Add-some-longer-form-docs-for-HTTPS.patch @@ -0,0 +1,86 @@ +From b52acabf478e8d1aa19f7823aade81eed1553143 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Tue, 22 Apr 2014 16:31:14 -0400 +Subject: [PATCH 10/13] Add some longer-form docs for HTTPS + +Add some longer-form documentation for the new HTTPS support, walking a +prospective administrator through generating a bare minimal signing +setup, deploying a WSGI-based proxy server onto an Apache httpd server +using mod_ssl and mod_wsgi, and configuring clients to use it. + +ticket: 7929 +--- + doc/admin/https.rst | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ + doc/admin/index.rst | 1 + + 2 files changed, 49 insertions(+) + create mode 100644 doc/admin/https.rst + +diff --git a/doc/admin/https.rst b/doc/admin/https.rst +new file mode 100644 +index 0000000..b4e68b2 +--- /dev/null ++++ b/doc/admin/https.rst +@@ -0,0 +1,48 @@ ++.. _https: ++ ++HTTPS proxy configuration ++========================= ++ ++In addition to being able to use UDP or TCP to communicate directly ++with a KDC as is outlined in RFC4120, and with kpasswd services in a ++similar fashion, the client libraries can attempt to use an HTTPS ++proxy server to communicate with a KDC or kpasswd service, using the ++protocol outlined in [MS-KKDCP]. ++ ++Communicating with a KDC through an HTTPS proxy allows clients to ++contact servers when network firewalls might otherwise prevent them ++from doing so. The use of TLS also encrypts all traffic between the ++clients and the KDC, preventing observers from conducting password ++dictionary attacks or from observing the client and server principals ++being authenticated, at additional computational cost to both clients ++and servers. ++ ++An HTTPS proxy server is provided as a feature in some versions of ++Microsoft Windows Server, and a WSGI implementation named `kdcproxy` ++is available in the python package index. ++ ++ ++Configuring the clients ++----------------------- ++ ++To use an HTTPS proxy, a client host must trust the CA which issued ++that proxy's SSL certificate. If that CA's certificate is not in the ++system-wide default set of trusted certificates, configure the ++following relation in the client host's :ref:`krb5.conf(5)` file in ++the appropriate :ref:`realms` subsection:: ++ ++ http_anchors = FILE:/etc/krb5/cacert.pem ++ ++Adjust the pathname to match the path of the file which contains a ++copy of the CA's certificate. The `http_anchors` option is documented ++more fully in :ref:`krb5.conf(5)`. ++ ++Configure the client to access the KDC and kpasswd service by ++specifying their locations in its :ref:`krb5.conf(5)` file in the form ++of HTTPS URLs for the proxy server:: ++ ++ kdc = https://server.fqdn/KdcProxy ++ kpasswd_server = https://server.fqdn/KdcProxy ++ ++If the proxy and client are properly configured, client commands such ++as ``kinit``, ``kvno``, and ``kpasswd`` should all function normally. +diff --git a/doc/admin/index.rst b/doc/admin/index.rst +index 3406843..3cd57f5 100644 +--- a/doc/admin/index.rst ++++ b/doc/admin/index.rst +@@ -17,6 +17,7 @@ For administrators + otp.rst + princ_dns.rst + enctypes.rst ++ https.rst + + .. toctree:: + :maxdepth: 1 +-- +2.1.0 + diff --git a/SOURCES/0011-Have-k5test.py-provide-runenv-to-python-tests.patch b/SOURCES/0011-Have-k5test.py-provide-runenv-to-python-tests.patch new file mode 100644 index 0000000..218e629 --- /dev/null +++ b/SOURCES/0011-Have-k5test.py-provide-runenv-to-python-tests.patch @@ -0,0 +1,64 @@ +From f78f8b1a46534db3a4547323ba952c1fa1b41fe9 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Fri, 30 May 2014 17:13:31 -0400 +Subject: [PATCH 11/13] Have k5test.py provide 'runenv' to python tests + +Expose the formerly-internal _runenv module as k5test.runenv, so that +settings we store in the top-level runenv.py will be available to them. + +ticket: 7929 +--- + src/util/k5test.py | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/src/util/k5test.py b/src/util/k5test.py +index a2bfbee..8cb477d 100644 +--- a/src/util/k5test.py ++++ b/src/util/k5test.py +@@ -177,6 +177,12 @@ Scripts may use the following functions and variables: + + * args: Positional arguments left over after flags are processed. + ++* runenv: The contents of $srctop/runenv.py, containing a dictionary ++ 'env' which specifies additional variables to be added to the realm ++ environment, and a variable 'proxy_tls_impl', which indicates which ++ SSL implementation (if any) is being used by libkrb5's support for ++ contacting KDCs and kpasswd servers over HTTPS. ++ + * verbose: Whether the script is running verbosely. + + * testpass: The command-line test pass argument. The script does not +@@ -526,9 +532,9 @@ def _match_cmdnum(cmdnum, ind): + # Return an environment suitable for running programs in the build + # tree. It is safe to modify the result. + def _build_env(): +- global buildtop, _runenv ++ global buildtop, runenv + env = os.environ.copy() +- for (k, v) in _runenv.iteritems(): ++ for (k, v) in runenv.env.iteritems(): + if v.find('./') == 0: + env[k] = os.path.join(buildtop, v) + else: +@@ -544,8 +550,7 @@ def _import_runenv(): + runenv_py = os.path.join(buildtop, 'runenv.py') + if not os.path.exists(runenv_py): + fail('You must run "make runenv.py" in %s first.' % buildtop) +- module = imp.load_source('runenv', runenv_py) +- return module.env ++ return imp.load_source('runenv', runenv_py) + + + # Merge the nested dictionaries cfg1 and cfg2 into a new dictionary. +@@ -1174,7 +1179,7 @@ _cmd_index = 1 + buildtop = _find_buildtop() + srctop = _find_srctop() + plugins = os.path.join(buildtop, 'plugins') +-_runenv = _import_runenv() ++runenv = _import_runenv() + hostname = _get_hostname() + null_input = open(os.devnull, 'r') + +-- +2.1.0 + diff --git a/SOURCES/0012-Add-a-simple-KDC-proxy-test-server.patch b/SOURCES/0012-Add-a-simple-KDC-proxy-test-server.patch new file mode 100644 index 0000000..48aa032 --- /dev/null +++ b/SOURCES/0012-Add-a-simple-KDC-proxy-test-server.patch @@ -0,0 +1,526 @@ +From 142255ba9af4ce1016a8eadf147e599ee490f1f7 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Fri, 7 Feb 2014 18:03:29 -0500 +Subject: [PATCH 12/13] Add a simple KDC proxy test server + +This proxy server uses python-paste to run the kdcproxy from +https://pypi.python.org/pypi/kdcproxy. It should be used along +with the proxy.pem certificate in ../tests/dejagnu/proxy-certs. + +ticket: 7929 +--- + src/tests/dejagnu/proxy-certs/ca.pem | 28 +++++ + src/tests/dejagnu/proxy-certs/make-certs.sh | 124 +++++++++++++++++++++++ + src/tests/dejagnu/proxy-certs/proxy-badsig.pem | 56 ++++++++++ + src/tests/dejagnu/proxy-certs/proxy-ideal.pem | 56 ++++++++++ + src/tests/dejagnu/proxy-certs/proxy-no-match.pem | 54 ++++++++++ + src/tests/dejagnu/proxy-certs/proxy-san.pem | 56 ++++++++++ + src/tests/dejagnu/proxy-certs/proxy-subject.pem | 54 ++++++++++ + src/util/paste-kdcproxy.py | 18 ++++ + 8 files changed, 446 insertions(+) + create mode 100644 src/tests/dejagnu/proxy-certs/ca.pem + create mode 100755 src/tests/dejagnu/proxy-certs/make-certs.sh + create mode 100644 src/tests/dejagnu/proxy-certs/proxy-badsig.pem + create mode 100644 src/tests/dejagnu/proxy-certs/proxy-ideal.pem + create mode 100644 src/tests/dejagnu/proxy-certs/proxy-no-match.pem + create mode 100644 src/tests/dejagnu/proxy-certs/proxy-san.pem + create mode 100644 src/tests/dejagnu/proxy-certs/proxy-subject.pem + create mode 100755 src/util/paste-kdcproxy.py + +diff --git a/src/tests/dejagnu/proxy-certs/ca.pem b/src/tests/dejagnu/proxy-certs/ca.pem +new file mode 100644 +index 0000000..e0f8dc7 +--- /dev/null ++++ b/src/tests/dejagnu/proxy-certs/ca.pem +@@ -0,0 +1,28 @@ ++-----BEGIN CERTIFICATE----- ++MIIEuzCCA6OgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBmTELMAkGA1UEBhMCVVMx ++FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcTCUNhbWJyaWRnZTEMMAoG ++A1UEChMDTUlUMSIwIAYDVQQLExlJbnNlY3VyZSBLZXJiZXJvcyB0ZXN0IENBMSww ++KgYDVQQDFCN0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVyd2lzZTAeFw0x ++NDA1MDIxOTA2MDhaFw0yNTA0MTQxOTA2MDhaMIGZMQswCQYDVQQGEwJVUzEWMBQG ++A1UECBMNTWFzc2FjaHVzZXR0czESMBAGA1UEBxMJQ2FtYnJpZGdlMQwwCgYDVQQK ++EwNNSVQxIjAgBgNVBAsTGUluc2VjdXJlIEtlcmJlcm9zIHRlc3QgQ0ExLDAqBgNV ++BAMUI3Rlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ugb3RoZXJ3aXNlMIIBIjANBgkq ++hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1zudnpN8FP7iLn1vgkyTSn/RQxXx1yt6 ++zikHaMrVPjkjXPPUoCFpWS3eeI4aQFoj93L5MwZDmSxOflBAqLwV2AMAacrYnNPJ ++IkHtbYKdVsvw9b4INTWqV9/DOODO7UowyMppmO35/pUXaLL+AjHjLw1/EhQ3ZYtq ++fpAMOkf5TnS5GtqZFlrYgZKE8vTC8BxDKM7FYhWYz7kp/tG3S8O/RTnP7Nd+h1Yd ++pmlHBGfuwIRIJz5xNw6KIcCy3Q0NNoKnh00WVwLmR+x11BGSkMjiZZkwJ5D0RObS ++g13QD/itrGoV2gtPzjQgNPfTrjsMvyOWAAFrWVR3QLTxnnmXsqnXvwIDAQABo4IB ++CjCCAQYwHQYDVR0OBBYEFHO5+DSYzq8rvQhUldyvn0y4AqlHMIHGBgNVHSMEgb4w ++gbuAFHO5+DSYzq8rvQhUldyvn0y4AqlHoYGfpIGcMIGZMQswCQYDVQQGEwJVUzEW ++MBQGA1UECBMNTWFzc2FjaHVzZXR0czESMBAGA1UEBxMJQ2FtYnJpZGdlMQwwCgYD ++VQQKEwNNSVQxIjAgBgNVBAsTGUluc2VjdXJlIEtlcmJlcm9zIHRlc3QgQ0ExLDAq ++BgNVBAMUI3Rlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ugb3RoZXJ3aXNlggEBMAsG ++A1UdDwQEAwIB/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAM ++Mf4ptC6WoQBH3GoTfgBL0WlIeYeSFmLO7IaSjpK0FV6F/yF7iPFSXcpmu23m6USY ++LRSxnAvxFTi+h1S5Za9O2Pjq88R9nHmesg4v8HJqOw4HpkDowYo2lumjIMfAutyR ++MQUOujYJW1WyZ2PidN5M1exDeMgQN9nVjUCx/WKD9fnzOjOOR1Sc8Us2KpoyccIi ++A+ABHubCvSO3cln0Sp7qjkssJScZtouzPu8FYiroTIR+1oSIKTpJiik1EptlsTea ++L6fHTMHspFhZaiUJFHWTBAgn/dT+UkFntHdHGI6HWBThFVW05hKoarBA7N25W7FN ++AHyfC0lKds4qFiBQkpdi ++-----END CERTIFICATE----- +diff --git a/src/tests/dejagnu/proxy-certs/make-certs.sh b/src/tests/dejagnu/proxy-certs/make-certs.sh +new file mode 100755 +index 0000000..1191bf0 +--- /dev/null ++++ b/src/tests/dejagnu/proxy-certs/make-certs.sh +@@ -0,0 +1,124 @@ ++#!/bin/sh -e ++ ++PWD=`pwd` ++NAMETYPE=1 ++KEYSIZE=2048 ++DAYS=4000 ++REALM=KRBTEST.COM ++TLS_SERVER_EKU=1.3.6.1.5.5.7.3.1 ++PROXY_EKU_LIST=$TLS_SERVER_EKU ++ ++cat > openssl.cnf << EOF ++[req] ++prompt = no ++distinguished_name = \$ENV::SUBJECT ++ ++[ca] ++default_ca = test_ca ++ ++[test_ca] ++new_certs_dir = $PWD ++serial = $PWD/ca.srl ++database = $PWD/ca.db ++certificate = $PWD/ca.pem ++private_key = $PWD/privkey.pem ++default_days = $DAYS ++x509_extensions = exts_proxy ++policy = proxyname ++default_md = sha1 ++unique_subject = no ++email_in_dn = no ++ ++[signer] ++CN = test CA certificate ++C = US ++ST = Massachusetts ++L = Cambridge ++O = MIT ++OU = Insecure Kerberos test CA ++CN = test suite CA; do not use otherwise ++ ++[proxy] ++C = US ++ST = Massachusetts ++O = KRBTEST.COM ++CN = PROXYinSubject ++ ++[localhost] ++C = US ++ST = Massachusetts ++O = KRBTEST.COM ++CN = localhost ++ ++[proxyname] ++C = supplied ++ST = supplied ++O = supplied ++CN = supplied ++ ++[exts_ca] ++subjectKeyIdentifier = hash ++authorityKeyIdentifier = keyid:always,issuer:always ++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign ++basicConstraints = critical,CA:TRUE ++ ++[exts_proxy] ++subjectKeyIdentifier = hash ++authorityKeyIdentifier = keyid:always,issuer:always ++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement ++basicConstraints = critical,CA:FALSE ++subjectAltName = DNS:proxyÅ ubjectÄltÑame,DNS:proxySubjectAltName,IP:127.0.0.1,IP:::1,DNS:localhost ++extendedKeyUsage = $PROXY_EKU_LIST ++ ++[exts_proxy_no_san] ++subjectKeyIdentifier = hash ++authorityKeyIdentifier = keyid:always,issuer:always ++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement ++basicConstraints = critical,CA:FALSE ++extendedKeyUsage = $PROXY_EKU_LIST ++EOF ++ ++# Generate a private key. ++openssl genrsa $KEYSIZE -nodes > privkey.pem ++ ++# Generate a "CA" certificate. ++SUBJECT=signer openssl req -config openssl.cnf -new -x509 -extensions exts_ca \ ++ -set_serial 1 -days $DAYS -key privkey.pem -out ca.pem ++ ++# Generate proxy certificate signing requests. ++SUBJECT=proxy openssl req -config openssl.cnf -new -key privkey.pem \ ++ -out proxy.csr ++SUBJECT=localhost openssl req -config openssl.cnf -new -key privkey.pem \ ++ -out localhost.csr ++ ++# Issue the certificate with the right name in a subjectAltName. ++echo 02 > ca.srl ++cat /dev/null > ca.db ++SUBJECT=proxy openssl ca -config openssl.cnf -extensions exts_proxy \ ++ -batch -days $DAYS -notext -out tmp.pem -in proxy.csr ++cat privkey.pem tmp.pem > proxy-san.pem ++ ++# Issue a certificate that only has the name in the subject field ++SUBJECT=proxy openssl ca -config openssl.cnf -extensions exts_proxy_no_san \ ++ -batch -days $DAYS -notext -out tmp.pem -in localhost.csr ++cat privkey.pem tmp.pem > proxy-subject.pem ++ ++# Issue a certificate that doesn't include any matching name values. ++SUBJECT=proxy openssl ca -config openssl.cnf -extensions exts_proxy_no_san \ ++ -batch -days $DAYS -notext -out tmp.pem -in proxy.csr ++cat privkey.pem tmp.pem > proxy-no-match.pem ++ ++# Issue a certificate that contains all matching name values. ++SUBJECT=proxy openssl ca -config openssl.cnf -extensions exts_proxy \ ++ -batch -days $DAYS -notext -out tmp.pem -in localhost.csr ++cat privkey.pem tmp.pem > proxy-ideal.pem ++ ++# Corrupt the signature on the certificate. ++SUBJECT=proxy openssl x509 -outform der -in proxy-ideal.pem -out bad.der ++length=`od -Ad bad.der | tail -n 1 | awk '{print $1}'` ++dd if=/dev/zero bs=1 of=bad.der count=16 seek=`expr $length - 16` ++SUBJECT=proxy openssl x509 -inform der -in bad.der -out tmp.pem ++cat privkey.pem tmp.pem > proxy-badsig.pem ++ ++# Clean up. ++rm -f openssl.cnf proxy.csr localhost.csr privkey.pem ca.db ca.db.old ca.srl ca.srl.old ca.db.attr ca.db.attr.old 02.pem 03.pem 04.pem 05.pem tmp.pem bad.der +diff --git a/src/tests/dejagnu/proxy-certs/proxy-badsig.pem b/src/tests/dejagnu/proxy-certs/proxy-badsig.pem +new file mode 100644 +index 0000000..2b31f7d +--- /dev/null ++++ b/src/tests/dejagnu/proxy-certs/proxy-badsig.pem +@@ -0,0 +1,56 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpQIBAAKCAQEA1zudnpN8FP7iLn1vgkyTSn/RQxXx1yt6zikHaMrVPjkjXPPU ++oCFpWS3eeI4aQFoj93L5MwZDmSxOflBAqLwV2AMAacrYnNPJIkHtbYKdVsvw9b4I ++NTWqV9/DOODO7UowyMppmO35/pUXaLL+AjHjLw1/EhQ3ZYtqfpAMOkf5TnS5GtqZ ++FlrYgZKE8vTC8BxDKM7FYhWYz7kp/tG3S8O/RTnP7Nd+h1YdpmlHBGfuwIRIJz5x ++Nw6KIcCy3Q0NNoKnh00WVwLmR+x11BGSkMjiZZkwJ5D0RObSg13QD/itrGoV2gtP ++zjQgNPfTrjsMvyOWAAFrWVR3QLTxnnmXsqnXvwIDAQABAoIBAQCqvhpeMDXhGgoo ++Q03wmfrGwPsrMv91aIK1hYrhMPdVs1JAbRYiKh8+pcq07FYa8udRaB4UwkVh/+oM ++/nEs6niRsl/jjQ2l68TFrnNByroynvr6l9Q/EeGecF6Ygo7lY1OsFhcLQM5vjarS ++XhxvdU/6hcRmfS8tGRpUaMWqfmpiN3YgJcgt8SoYhiwAYDTMJjNyWC61lO7IqNVR ++4kntiM24sfAu1sdZynX8Gp2GrpNChapEuhilQ8RayjuStEYr2abcSIjfZFHQXN7o ++TnjL+AQUzc/ZTXDGnIe9ZzZeFz8UCueeoN6KPxfrq9UUWRL6qt7gOIMdhYR6lFxt ++6pj6kLhxAoGBAO5DTnTKDfCMY2/AsTzCJvMGSY0bT1rsdDxrpqjrbUSeMHV3s5Lm ++vEPnnm+05FD/vi99+HZjHXAZFkhA3ubij2qWFPBnQ5YUoh17IW/Ae4bzY2uXikgL ++tLZ+R+OrcGYQQlvPn//PLsxbfdk5vraqzm08kIX0T4o4Iz8ST5NFJ8hVAoGBAOdB ++ahXr14563Cjeu0pSQ1nXoz3IXdnDwePXasYhxQHl8Ayk8qZS5pt7r07H3dqq6pvn ++e09gZINJe47B9UhkR3H5bPyz/kujKS4zqo3Zlbryzm3V0BWqjNj+j8E2YuQKNQr+ ++c480jn2FzwW66w0i3n4U4KUn1w2/iq5AnVzyNkPDAoGAWLYEsyU79XE/4K79DqM3 ++P0r6/afKbw8U5B4syj4FzAOeBU6RNMPmGt5VNkBCtgnSdPpRFTsoDcG5cyN8GrkG ++Lug8WZoJJwr9pT5gH6yqEX/zZ27f1J1PJpd0CsedLNMm8eonJ2arhPkXrVZ7tKV6 ++AGAJa2agatUmAmi96hZYjpUCgYEA32abJEgsedEIhFb/GYI03ELryRCaUXfCA+gj ++lvoihn3qE1z5qGGns4adyX5dPRQmBqxtvDXDg+zl9vg6i0+MkXdCqTD8tXcOnjp9 ++RgFvmyVa9FI8beHPpQTuPNncWK3fpho/6pT8Hhi48LEsxwjrZWOnzQSaxQZH46Q6 ++IQNAFt8CgYEAkflxXvA2/2naix+riaBzv5EVJB7ilbfWiWtq2LEAtwrQ5XNFjrtK ++g45jKrZ/ezAzTfPa5Dwn4xcImd0MIavnJhDu2ATxMGB0GATLlDH2HZvU7UwKLpTW ++6Hlol4yRcX4GSEOxJ2ZpWYNIOYH0yDf1qLJXs1j8Fi3zWRe+V1kff4w= ++-----END RSA PRIVATE KEY----- ++-----BEGIN CERTIFICATE----- ++MIIE3TCCA8WgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBmTELMAkGA1UEBhMCVVMx ++FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcTCUNhbWJyaWRnZTEMMAoG ++A1UEChMDTUlUMSIwIAYDVQQLExlJbnNlY3VyZSBLZXJiZXJvcyB0ZXN0IENBMSww ++KgYDVQQDFCN0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVyd2lzZTAeFw0x ++NDA1MDIxOTA2MDlaFw0yNTA0MTQxOTA2MDlaME8xCzAJBgNVBAYTAlVTMRYwFAYD ++VQQIEw1NYXNzYWNodXNldHRzMRQwEgYDVQQKEwtLUkJURVNULkNPTTESMBAGA1UE ++AxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1zud ++npN8FP7iLn1vgkyTSn/RQxXx1yt6zikHaMrVPjkjXPPUoCFpWS3eeI4aQFoj93L5 ++MwZDmSxOflBAqLwV2AMAacrYnNPJIkHtbYKdVsvw9b4INTWqV9/DOODO7UowyMpp ++mO35/pUXaLL+AjHjLw1/EhQ3ZYtqfpAMOkf5TnS5GtqZFlrYgZKE8vTC8BxDKM7F ++YhWYz7kp/tG3S8O/RTnP7Nd+h1YdpmlHBGfuwIRIJz5xNw6KIcCy3Q0NNoKnh00W ++VwLmR+x11BGSkMjiZZkwJ5D0RObSg13QD/itrGoV2gtPzjQgNPfTrjsMvyOWAAFr ++WVR3QLTxnnmXsqnXvwIDAQABo4IBdzCCAXMwHQYDVR0OBBYEFHO5+DSYzq8rvQhU ++ldyvn0y4AqlHMIHGBgNVHSMEgb4wgbuAFHO5+DSYzq8rvQhUldyvn0y4AqlHoYGf ++pIGcMIGZMQswCQYDVQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czESMBAG ++A1UEBxMJQ2FtYnJpZGdlMQwwCgYDVQQKEwNNSVQxIjAgBgNVBAsTGUluc2VjdXJl ++IEtlcmJlcm9zIHRlc3QgQ0ExLDAqBgNVBAMUI3Rlc3Qgc3VpdGUgQ0E7IGRvIG5v ++dCB1c2Ugb3RoZXJ3aXNlggEBMAsGA1UdDwQEAwID6DAMBgNVHRMBAf8EAjAAMFkG ++A1UdEQRSMFCCFnByb3h5xaB1YmplY3TDhGx0w5FhbWWCE3Byb3h5U3ViamVjdEFs ++dE5hbWWHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAGCCWxvY2FsaG9zdDATBgNVHSUE ++DDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOCAQEAfTctgFjQSaevBi64q7yh ++GNsK3PqeNEALZz4pSXRbOwm0E4RpYIS7uqg1C4zJ5Zbd4V/dOX7q+T/iBS7gErzS ++rj21jH3Ggc92TmXzcFxMDCxLV0hO8xFkqg3P4sslJESOHxvEMTTf5s893yUb8vJ/ ++DCvZXXRoRwPot9MFozkmcQcaTNunREWFvn4i4JXcMCSAfWTd+/VkpVsy69u3tj68 ++7G2/K5nalvZikutEC+DyfyBuvDAoxIYzCi3VtQxCalW28Q5hzWV21QsvKTP5QBsh ++RaU2r0O58lZPPvrOrtWQBCudUgsnoraVLrjJshEQ4z/ZAAAAAAAAAAAAAAAAAAAA ++AA== ++-----END CERTIFICATE----- +diff --git a/src/tests/dejagnu/proxy-certs/proxy-ideal.pem b/src/tests/dejagnu/proxy-certs/proxy-ideal.pem +new file mode 100644 +index 0000000..4588f7d +--- /dev/null ++++ b/src/tests/dejagnu/proxy-certs/proxy-ideal.pem +@@ -0,0 +1,56 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpQIBAAKCAQEA1zudnpN8FP7iLn1vgkyTSn/RQxXx1yt6zikHaMrVPjkjXPPU ++oCFpWS3eeI4aQFoj93L5MwZDmSxOflBAqLwV2AMAacrYnNPJIkHtbYKdVsvw9b4I ++NTWqV9/DOODO7UowyMppmO35/pUXaLL+AjHjLw1/EhQ3ZYtqfpAMOkf5TnS5GtqZ ++FlrYgZKE8vTC8BxDKM7FYhWYz7kp/tG3S8O/RTnP7Nd+h1YdpmlHBGfuwIRIJz5x ++Nw6KIcCy3Q0NNoKnh00WVwLmR+x11BGSkMjiZZkwJ5D0RObSg13QD/itrGoV2gtP ++zjQgNPfTrjsMvyOWAAFrWVR3QLTxnnmXsqnXvwIDAQABAoIBAQCqvhpeMDXhGgoo ++Q03wmfrGwPsrMv91aIK1hYrhMPdVs1JAbRYiKh8+pcq07FYa8udRaB4UwkVh/+oM ++/nEs6niRsl/jjQ2l68TFrnNByroynvr6l9Q/EeGecF6Ygo7lY1OsFhcLQM5vjarS ++XhxvdU/6hcRmfS8tGRpUaMWqfmpiN3YgJcgt8SoYhiwAYDTMJjNyWC61lO7IqNVR ++4kntiM24sfAu1sdZynX8Gp2GrpNChapEuhilQ8RayjuStEYr2abcSIjfZFHQXN7o ++TnjL+AQUzc/ZTXDGnIe9ZzZeFz8UCueeoN6KPxfrq9UUWRL6qt7gOIMdhYR6lFxt ++6pj6kLhxAoGBAO5DTnTKDfCMY2/AsTzCJvMGSY0bT1rsdDxrpqjrbUSeMHV3s5Lm ++vEPnnm+05FD/vi99+HZjHXAZFkhA3ubij2qWFPBnQ5YUoh17IW/Ae4bzY2uXikgL ++tLZ+R+OrcGYQQlvPn//PLsxbfdk5vraqzm08kIX0T4o4Iz8ST5NFJ8hVAoGBAOdB ++ahXr14563Cjeu0pSQ1nXoz3IXdnDwePXasYhxQHl8Ayk8qZS5pt7r07H3dqq6pvn ++e09gZINJe47B9UhkR3H5bPyz/kujKS4zqo3Zlbryzm3V0BWqjNj+j8E2YuQKNQr+ ++c480jn2FzwW66w0i3n4U4KUn1w2/iq5AnVzyNkPDAoGAWLYEsyU79XE/4K79DqM3 ++P0r6/afKbw8U5B4syj4FzAOeBU6RNMPmGt5VNkBCtgnSdPpRFTsoDcG5cyN8GrkG ++Lug8WZoJJwr9pT5gH6yqEX/zZ27f1J1PJpd0CsedLNMm8eonJ2arhPkXrVZ7tKV6 ++AGAJa2agatUmAmi96hZYjpUCgYEA32abJEgsedEIhFb/GYI03ELryRCaUXfCA+gj ++lvoihn3qE1z5qGGns4adyX5dPRQmBqxtvDXDg+zl9vg6i0+MkXdCqTD8tXcOnjp9 ++RgFvmyVa9FI8beHPpQTuPNncWK3fpho/6pT8Hhi48LEsxwjrZWOnzQSaxQZH46Q6 ++IQNAFt8CgYEAkflxXvA2/2naix+riaBzv5EVJB7ilbfWiWtq2LEAtwrQ5XNFjrtK ++g45jKrZ/ezAzTfPa5Dwn4xcImd0MIavnJhDu2ATxMGB0GATLlDH2HZvU7UwKLpTW ++6Hlol4yRcX4GSEOxJ2ZpWYNIOYH0yDf1qLJXs1j8Fi3zWRe+V1kff4w= ++-----END RSA PRIVATE KEY----- ++-----BEGIN CERTIFICATE----- ++MIIE3TCCA8WgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBmTELMAkGA1UEBhMCVVMx ++FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcTCUNhbWJyaWRnZTEMMAoG ++A1UEChMDTUlUMSIwIAYDVQQLExlJbnNlY3VyZSBLZXJiZXJvcyB0ZXN0IENBMSww ++KgYDVQQDFCN0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVyd2lzZTAeFw0x ++NDA1MDIxOTA2MDlaFw0yNTA0MTQxOTA2MDlaME8xCzAJBgNVBAYTAlVTMRYwFAYD ++VQQIEw1NYXNzYWNodXNldHRzMRQwEgYDVQQKEwtLUkJURVNULkNPTTESMBAGA1UE ++AxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1zud ++npN8FP7iLn1vgkyTSn/RQxXx1yt6zikHaMrVPjkjXPPUoCFpWS3eeI4aQFoj93L5 ++MwZDmSxOflBAqLwV2AMAacrYnNPJIkHtbYKdVsvw9b4INTWqV9/DOODO7UowyMpp ++mO35/pUXaLL+AjHjLw1/EhQ3ZYtqfpAMOkf5TnS5GtqZFlrYgZKE8vTC8BxDKM7F ++YhWYz7kp/tG3S8O/RTnP7Nd+h1YdpmlHBGfuwIRIJz5xNw6KIcCy3Q0NNoKnh00W ++VwLmR+x11BGSkMjiZZkwJ5D0RObSg13QD/itrGoV2gtPzjQgNPfTrjsMvyOWAAFr ++WVR3QLTxnnmXsqnXvwIDAQABo4IBdzCCAXMwHQYDVR0OBBYEFHO5+DSYzq8rvQhU ++ldyvn0y4AqlHMIHGBgNVHSMEgb4wgbuAFHO5+DSYzq8rvQhUldyvn0y4AqlHoYGf ++pIGcMIGZMQswCQYDVQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czESMBAG ++A1UEBxMJQ2FtYnJpZGdlMQwwCgYDVQQKEwNNSVQxIjAgBgNVBAsTGUluc2VjdXJl ++IEtlcmJlcm9zIHRlc3QgQ0ExLDAqBgNVBAMUI3Rlc3Qgc3VpdGUgQ0E7IGRvIG5v ++dCB1c2Ugb3RoZXJ3aXNlggEBMAsGA1UdDwQEAwID6DAMBgNVHRMBAf8EAjAAMFkG ++A1UdEQRSMFCCFnByb3h5xaB1YmplY3TDhGx0w5FhbWWCE3Byb3h5U3ViamVjdEFs ++dE5hbWWHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAGCCWxvY2FsaG9zdDATBgNVHSUE ++DDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOCAQEAfTctgFjQSaevBi64q7yh ++GNsK3PqeNEALZz4pSXRbOwm0E4RpYIS7uqg1C4zJ5Zbd4V/dOX7q+T/iBS7gErzS ++rj21jH3Ggc92TmXzcFxMDCxLV0hO8xFkqg3P4sslJESOHxvEMTTf5s893yUb8vJ/ ++DCvZXXRoRwPot9MFozkmcQcaTNunREWFvn4i4JXcMCSAfWTd+/VkpVsy69u3tj68 ++7G2/K5nalvZikutEC+DyfyBuvDAoxIYzCi3VtQxCalW28Q5hzWV21QsvKTP5QBsh ++RaU2r0O58lZPPvrOrtWQBCudUgsnoraVLrjJshEQ4z/ZA9fVtX2ndCSIoyWpWk01 ++gQ== ++-----END CERTIFICATE----- +diff --git a/src/tests/dejagnu/proxy-certs/proxy-no-match.pem b/src/tests/dejagnu/proxy-certs/proxy-no-match.pem +new file mode 100644 +index 0000000..a97c1c7 +--- /dev/null ++++ b/src/tests/dejagnu/proxy-certs/proxy-no-match.pem +@@ -0,0 +1,54 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpQIBAAKCAQEA1zudnpN8FP7iLn1vgkyTSn/RQxXx1yt6zikHaMrVPjkjXPPU ++oCFpWS3eeI4aQFoj93L5MwZDmSxOflBAqLwV2AMAacrYnNPJIkHtbYKdVsvw9b4I ++NTWqV9/DOODO7UowyMppmO35/pUXaLL+AjHjLw1/EhQ3ZYtqfpAMOkf5TnS5GtqZ ++FlrYgZKE8vTC8BxDKM7FYhWYz7kp/tG3S8O/RTnP7Nd+h1YdpmlHBGfuwIRIJz5x ++Nw6KIcCy3Q0NNoKnh00WVwLmR+x11BGSkMjiZZkwJ5D0RObSg13QD/itrGoV2gtP ++zjQgNPfTrjsMvyOWAAFrWVR3QLTxnnmXsqnXvwIDAQABAoIBAQCqvhpeMDXhGgoo ++Q03wmfrGwPsrMv91aIK1hYrhMPdVs1JAbRYiKh8+pcq07FYa8udRaB4UwkVh/+oM ++/nEs6niRsl/jjQ2l68TFrnNByroynvr6l9Q/EeGecF6Ygo7lY1OsFhcLQM5vjarS ++XhxvdU/6hcRmfS8tGRpUaMWqfmpiN3YgJcgt8SoYhiwAYDTMJjNyWC61lO7IqNVR ++4kntiM24sfAu1sdZynX8Gp2GrpNChapEuhilQ8RayjuStEYr2abcSIjfZFHQXN7o ++TnjL+AQUzc/ZTXDGnIe9ZzZeFz8UCueeoN6KPxfrq9UUWRL6qt7gOIMdhYR6lFxt ++6pj6kLhxAoGBAO5DTnTKDfCMY2/AsTzCJvMGSY0bT1rsdDxrpqjrbUSeMHV3s5Lm ++vEPnnm+05FD/vi99+HZjHXAZFkhA3ubij2qWFPBnQ5YUoh17IW/Ae4bzY2uXikgL ++tLZ+R+OrcGYQQlvPn//PLsxbfdk5vraqzm08kIX0T4o4Iz8ST5NFJ8hVAoGBAOdB ++ahXr14563Cjeu0pSQ1nXoz3IXdnDwePXasYhxQHl8Ayk8qZS5pt7r07H3dqq6pvn ++e09gZINJe47B9UhkR3H5bPyz/kujKS4zqo3Zlbryzm3V0BWqjNj+j8E2YuQKNQr+ ++c480jn2FzwW66w0i3n4U4KUn1w2/iq5AnVzyNkPDAoGAWLYEsyU79XE/4K79DqM3 ++P0r6/afKbw8U5B4syj4FzAOeBU6RNMPmGt5VNkBCtgnSdPpRFTsoDcG5cyN8GrkG ++Lug8WZoJJwr9pT5gH6yqEX/zZ27f1J1PJpd0CsedLNMm8eonJ2arhPkXrVZ7tKV6 ++AGAJa2agatUmAmi96hZYjpUCgYEA32abJEgsedEIhFb/GYI03ELryRCaUXfCA+gj ++lvoihn3qE1z5qGGns4adyX5dPRQmBqxtvDXDg+zl9vg6i0+MkXdCqTD8tXcOnjp9 ++RgFvmyVa9FI8beHPpQTuPNncWK3fpho/6pT8Hhi48LEsxwjrZWOnzQSaxQZH46Q6 ++IQNAFt8CgYEAkflxXvA2/2naix+riaBzv5EVJB7ilbfWiWtq2LEAtwrQ5XNFjrtK ++g45jKrZ/ezAzTfPa5Dwn4xcImd0MIavnJhDu2ATxMGB0GATLlDH2HZvU7UwKLpTW ++6Hlol4yRcX4GSEOxJ2ZpWYNIOYH0yDf1qLJXs1j8Fi3zWRe+V1kff4w= ++-----END RSA PRIVATE KEY----- ++-----BEGIN CERTIFICATE----- ++MIIEhzCCA2+gAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBmTELMAkGA1UEBhMCVVMx ++FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcTCUNhbWJyaWRnZTEMMAoG ++A1UEChMDTUlUMSIwIAYDVQQLExlJbnNlY3VyZSBLZXJiZXJvcyB0ZXN0IENBMSww ++KgYDVQQDFCN0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVyd2lzZTAeFw0x ++NDA1MDIxOTA2MDhaFw0yNTA0MTQxOTA2MDhaMFQxCzAJBgNVBAYTAlVTMRYwFAYD ++VQQIEw1NYXNzYWNodXNldHRzMRQwEgYDVQQKEwtLUkJURVNULkNPTTEXMBUGA1UE ++AxMOUFJPWFlpblN1YmplY3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB ++AQDXO52ek3wU/uIufW+CTJNKf9FDFfHXK3rOKQdoytU+OSNc89SgIWlZLd54jhpA ++WiP3cvkzBkOZLE5+UECovBXYAwBpytic08kiQe1tgp1Wy/D1vgg1NapX38M44M7t ++SjDIymmY7fn+lRdosv4CMeMvDX8SFDdli2p+kAw6R/lOdLka2pkWWtiBkoTy9MLw ++HEMozsViFZjPuSn+0bdLw79FOc/s136HVh2maUcEZ+7AhEgnPnE3DoohwLLdDQ02 ++gqeHTRZXAuZH7HXUEZKQyOJlmTAnkPRE5tKDXdAP+K2sahXaC0/ONCA099OuOwy/ ++I5YAAWtZVHdAtPGeeZeyqde/AgMBAAGjggEcMIIBGDAdBgNVHQ4EFgQUc7n4NJjO ++ryu9CFSV3K+fTLgCqUcwgcYGA1UdIwSBvjCBu4AUc7n4NJjOryu9CFSV3K+fTLgC ++qUehgZ+kgZwwgZkxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRz ++MRIwEAYDVQQHEwlDYW1icmlkZ2UxDDAKBgNVBAoTA01JVDEiMCAGA1UECxMZSW5z ++ZWN1cmUgS2VyYmVyb3MgdGVzdCBDQTEsMCoGA1UEAxQjdGVzdCBzdWl0ZSBDQTsg ++ZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0PBAQDAgPoMAwGA1UdEwEB/wQC ++MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADggEBAMsP++r4 ++vki0mBJg3POpp0i+H6zNMimoYLLtM5NvwXinfFuFQKbwLm8QWuHVifjfCYxMUm+l ++iL5cS/bq+SUWGDmrlOhsuu4+aYaxgNiEyki5Rol6miSOHbfOhzX8yp0EBPpq08dg ++SEdrTd/FIl4qgkkb1A4RJYZRErn/fbsyjJN66KIfSOXJuC8XMBf03Vw9f2rdrHJa ++r5lVGvqa4wjO2MPq9vVK52VFrbU/zuyyCUtggyIOwGLGSY0Axtbci+IHToDBQes+ ++6W4WwSUCssWfIZXQDLjFw1oRHnN43fXmX5vsVLi7YvOFHOAa1BDnDtCTZit26xVA ++Mdic66hR2jHP0TE= ++-----END CERTIFICATE----- +diff --git a/src/tests/dejagnu/proxy-certs/proxy-san.pem b/src/tests/dejagnu/proxy-certs/proxy-san.pem +new file mode 100644 +index 0000000..ac8bbaa +--- /dev/null ++++ b/src/tests/dejagnu/proxy-certs/proxy-san.pem +@@ -0,0 +1,56 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpQIBAAKCAQEA1zudnpN8FP7iLn1vgkyTSn/RQxXx1yt6zikHaMrVPjkjXPPU ++oCFpWS3eeI4aQFoj93L5MwZDmSxOflBAqLwV2AMAacrYnNPJIkHtbYKdVsvw9b4I ++NTWqV9/DOODO7UowyMppmO35/pUXaLL+AjHjLw1/EhQ3ZYtqfpAMOkf5TnS5GtqZ ++FlrYgZKE8vTC8BxDKM7FYhWYz7kp/tG3S8O/RTnP7Nd+h1YdpmlHBGfuwIRIJz5x ++Nw6KIcCy3Q0NNoKnh00WVwLmR+x11BGSkMjiZZkwJ5D0RObSg13QD/itrGoV2gtP ++zjQgNPfTrjsMvyOWAAFrWVR3QLTxnnmXsqnXvwIDAQABAoIBAQCqvhpeMDXhGgoo ++Q03wmfrGwPsrMv91aIK1hYrhMPdVs1JAbRYiKh8+pcq07FYa8udRaB4UwkVh/+oM ++/nEs6niRsl/jjQ2l68TFrnNByroynvr6l9Q/EeGecF6Ygo7lY1OsFhcLQM5vjarS ++XhxvdU/6hcRmfS8tGRpUaMWqfmpiN3YgJcgt8SoYhiwAYDTMJjNyWC61lO7IqNVR ++4kntiM24sfAu1sdZynX8Gp2GrpNChapEuhilQ8RayjuStEYr2abcSIjfZFHQXN7o ++TnjL+AQUzc/ZTXDGnIe9ZzZeFz8UCueeoN6KPxfrq9UUWRL6qt7gOIMdhYR6lFxt ++6pj6kLhxAoGBAO5DTnTKDfCMY2/AsTzCJvMGSY0bT1rsdDxrpqjrbUSeMHV3s5Lm ++vEPnnm+05FD/vi99+HZjHXAZFkhA3ubij2qWFPBnQ5YUoh17IW/Ae4bzY2uXikgL ++tLZ+R+OrcGYQQlvPn//PLsxbfdk5vraqzm08kIX0T4o4Iz8ST5NFJ8hVAoGBAOdB ++ahXr14563Cjeu0pSQ1nXoz3IXdnDwePXasYhxQHl8Ayk8qZS5pt7r07H3dqq6pvn ++e09gZINJe47B9UhkR3H5bPyz/kujKS4zqo3Zlbryzm3V0BWqjNj+j8E2YuQKNQr+ ++c480jn2FzwW66w0i3n4U4KUn1w2/iq5AnVzyNkPDAoGAWLYEsyU79XE/4K79DqM3 ++P0r6/afKbw8U5B4syj4FzAOeBU6RNMPmGt5VNkBCtgnSdPpRFTsoDcG5cyN8GrkG ++Lug8WZoJJwr9pT5gH6yqEX/zZ27f1J1PJpd0CsedLNMm8eonJ2arhPkXrVZ7tKV6 ++AGAJa2agatUmAmi96hZYjpUCgYEA32abJEgsedEIhFb/GYI03ELryRCaUXfCA+gj ++lvoihn3qE1z5qGGns4adyX5dPRQmBqxtvDXDg+zl9vg6i0+MkXdCqTD8tXcOnjp9 ++RgFvmyVa9FI8beHPpQTuPNncWK3fpho/6pT8Hhi48LEsxwjrZWOnzQSaxQZH46Q6 ++IQNAFt8CgYEAkflxXvA2/2naix+riaBzv5EVJB7ilbfWiWtq2LEAtwrQ5XNFjrtK ++g45jKrZ/ezAzTfPa5Dwn4xcImd0MIavnJhDu2ATxMGB0GATLlDH2HZvU7UwKLpTW ++6Hlol4yRcX4GSEOxJ2ZpWYNIOYH0yDf1qLJXs1j8Fi3zWRe+V1kff4w= ++-----END RSA PRIVATE KEY----- ++-----BEGIN CERTIFICATE----- ++MIIE4jCCA8qgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBmTELMAkGA1UEBhMCVVMx ++FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcTCUNhbWJyaWRnZTEMMAoG ++A1UEChMDTUlUMSIwIAYDVQQLExlJbnNlY3VyZSBLZXJiZXJvcyB0ZXN0IENBMSww ++KgYDVQQDFCN0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVyd2lzZTAeFw0x ++NDA1MDIxOTA2MDhaFw0yNTA0MTQxOTA2MDhaMFQxCzAJBgNVBAYTAlVTMRYwFAYD ++VQQIEw1NYXNzYWNodXNldHRzMRQwEgYDVQQKEwtLUkJURVNULkNPTTEXMBUGA1UE ++AxMOUFJPWFlpblN1YmplY3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB ++AQDXO52ek3wU/uIufW+CTJNKf9FDFfHXK3rOKQdoytU+OSNc89SgIWlZLd54jhpA ++WiP3cvkzBkOZLE5+UECovBXYAwBpytic08kiQe1tgp1Wy/D1vgg1NapX38M44M7t ++SjDIymmY7fn+lRdosv4CMeMvDX8SFDdli2p+kAw6R/lOdLka2pkWWtiBkoTy9MLw ++HEMozsViFZjPuSn+0bdLw79FOc/s136HVh2maUcEZ+7AhEgnPnE3DoohwLLdDQ02 ++gqeHTRZXAuZH7HXUEZKQyOJlmTAnkPRE5tKDXdAP+K2sahXaC0/ONCA099OuOwy/ ++I5YAAWtZVHdAtPGeeZeyqde/AgMBAAGjggF3MIIBczAdBgNVHQ4EFgQUc7n4NJjO ++ryu9CFSV3K+fTLgCqUcwgcYGA1UdIwSBvjCBu4AUc7n4NJjOryu9CFSV3K+fTLgC ++qUehgZ+kgZwwgZkxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRz ++MRIwEAYDVQQHEwlDYW1icmlkZ2UxDDAKBgNVBAoTA01JVDEiMCAGA1UECxMZSW5z ++ZWN1cmUgS2VyYmVyb3MgdGVzdCBDQTEsMCoGA1UEAxQjdGVzdCBzdWl0ZSBDQTsg ++ZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0PBAQDAgPoMAwGA1UdEwEB/wQC ++MAAwWQYDVR0RBFIwUIIWcHJveHnFoHViamVjdMOEbHTDkWFtZYITcHJveHlTdWJq ++ZWN0QWx0TmFtZYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAAYIJbG9jYWxob3N0MBMG ++A1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4IBAQAH6AWuyRLzMbKq ++MUlyg9ZIar8p0Ms0/UEaa6Xm3/cfm6HSujtgcYlDN3M86Z3zWzWdTrOHsRr/YSG3 ++H3YDhJToKqxcjgho+1xdBPm0xuFsJcypRqGj/mIaJSoa+wC2AdY1EdE+URsh87XC ++SHYNbxAVo8qBHMjtROm6AKb2YusYqHnkT+U6nc4Pn9UnIzmu4wfoSB+X1vtY24TP ++AtXNYQEG4BkgSrcsgoL+z/+wtZLU8QFk6JRO7Bedq711Oh/taEasZHjRAmnqC5TB ++Ab2fnwWuoVZHqz2qydeywXUKrZlctuRVdjE++wOt9xuMPKFGo0PKDw/SymCe61Q8 ++Nc/d2mhz ++-----END CERTIFICATE----- +diff --git a/src/tests/dejagnu/proxy-certs/proxy-subject.pem b/src/tests/dejagnu/proxy-certs/proxy-subject.pem +new file mode 100644 +index 0000000..e17918f +--- /dev/null ++++ b/src/tests/dejagnu/proxy-certs/proxy-subject.pem +@@ -0,0 +1,54 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpQIBAAKCAQEA1zudnpN8FP7iLn1vgkyTSn/RQxXx1yt6zikHaMrVPjkjXPPU ++oCFpWS3eeI4aQFoj93L5MwZDmSxOflBAqLwV2AMAacrYnNPJIkHtbYKdVsvw9b4I ++NTWqV9/DOODO7UowyMppmO35/pUXaLL+AjHjLw1/EhQ3ZYtqfpAMOkf5TnS5GtqZ ++FlrYgZKE8vTC8BxDKM7FYhWYz7kp/tG3S8O/RTnP7Nd+h1YdpmlHBGfuwIRIJz5x ++Nw6KIcCy3Q0NNoKnh00WVwLmR+x11BGSkMjiZZkwJ5D0RObSg13QD/itrGoV2gtP ++zjQgNPfTrjsMvyOWAAFrWVR3QLTxnnmXsqnXvwIDAQABAoIBAQCqvhpeMDXhGgoo ++Q03wmfrGwPsrMv91aIK1hYrhMPdVs1JAbRYiKh8+pcq07FYa8udRaB4UwkVh/+oM ++/nEs6niRsl/jjQ2l68TFrnNByroynvr6l9Q/EeGecF6Ygo7lY1OsFhcLQM5vjarS ++XhxvdU/6hcRmfS8tGRpUaMWqfmpiN3YgJcgt8SoYhiwAYDTMJjNyWC61lO7IqNVR ++4kntiM24sfAu1sdZynX8Gp2GrpNChapEuhilQ8RayjuStEYr2abcSIjfZFHQXN7o ++TnjL+AQUzc/ZTXDGnIe9ZzZeFz8UCueeoN6KPxfrq9UUWRL6qt7gOIMdhYR6lFxt ++6pj6kLhxAoGBAO5DTnTKDfCMY2/AsTzCJvMGSY0bT1rsdDxrpqjrbUSeMHV3s5Lm ++vEPnnm+05FD/vi99+HZjHXAZFkhA3ubij2qWFPBnQ5YUoh17IW/Ae4bzY2uXikgL ++tLZ+R+OrcGYQQlvPn//PLsxbfdk5vraqzm08kIX0T4o4Iz8ST5NFJ8hVAoGBAOdB ++ahXr14563Cjeu0pSQ1nXoz3IXdnDwePXasYhxQHl8Ayk8qZS5pt7r07H3dqq6pvn ++e09gZINJe47B9UhkR3H5bPyz/kujKS4zqo3Zlbryzm3V0BWqjNj+j8E2YuQKNQr+ ++c480jn2FzwW66w0i3n4U4KUn1w2/iq5AnVzyNkPDAoGAWLYEsyU79XE/4K79DqM3 ++P0r6/afKbw8U5B4syj4FzAOeBU6RNMPmGt5VNkBCtgnSdPpRFTsoDcG5cyN8GrkG ++Lug8WZoJJwr9pT5gH6yqEX/zZ27f1J1PJpd0CsedLNMm8eonJ2arhPkXrVZ7tKV6 ++AGAJa2agatUmAmi96hZYjpUCgYEA32abJEgsedEIhFb/GYI03ELryRCaUXfCA+gj ++lvoihn3qE1z5qGGns4adyX5dPRQmBqxtvDXDg+zl9vg6i0+MkXdCqTD8tXcOnjp9 ++RgFvmyVa9FI8beHPpQTuPNncWK3fpho/6pT8Hhi48LEsxwjrZWOnzQSaxQZH46Q6 ++IQNAFt8CgYEAkflxXvA2/2naix+riaBzv5EVJB7ilbfWiWtq2LEAtwrQ5XNFjrtK ++g45jKrZ/ezAzTfPa5Dwn4xcImd0MIavnJhDu2ATxMGB0GATLlDH2HZvU7UwKLpTW ++6Hlol4yRcX4GSEOxJ2ZpWYNIOYH0yDf1qLJXs1j8Fi3zWRe+V1kff4w= ++-----END RSA PRIVATE KEY----- ++-----BEGIN CERTIFICATE----- ++MIIEgjCCA2qgAwIBAgIBAzANBgkqhkiG9w0BAQUFADCBmTELMAkGA1UEBhMCVVMx ++FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcTCUNhbWJyaWRnZTEMMAoG ++A1UEChMDTUlUMSIwIAYDVQQLExlJbnNlY3VyZSBLZXJiZXJvcyB0ZXN0IENBMSww ++KgYDVQQDFCN0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVyd2lzZTAeFw0x ++NDA1MDIxOTA2MDhaFw0yNTA0MTQxOTA2MDhaME8xCzAJBgNVBAYTAlVTMRYwFAYD ++VQQIEw1NYXNzYWNodXNldHRzMRQwEgYDVQQKEwtLUkJURVNULkNPTTESMBAGA1UE ++AxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1zud ++npN8FP7iLn1vgkyTSn/RQxXx1yt6zikHaMrVPjkjXPPUoCFpWS3eeI4aQFoj93L5 ++MwZDmSxOflBAqLwV2AMAacrYnNPJIkHtbYKdVsvw9b4INTWqV9/DOODO7UowyMpp ++mO35/pUXaLL+AjHjLw1/EhQ3ZYtqfpAMOkf5TnS5GtqZFlrYgZKE8vTC8BxDKM7F ++YhWYz7kp/tG3S8O/RTnP7Nd+h1YdpmlHBGfuwIRIJz5xNw6KIcCy3Q0NNoKnh00W ++VwLmR+x11BGSkMjiZZkwJ5D0RObSg13QD/itrGoV2gtPzjQgNPfTrjsMvyOWAAFr ++WVR3QLTxnnmXsqnXvwIDAQABo4IBHDCCARgwHQYDVR0OBBYEFHO5+DSYzq8rvQhU ++ldyvn0y4AqlHMIHGBgNVHSMEgb4wgbuAFHO5+DSYzq8rvQhUldyvn0y4AqlHoYGf ++pIGcMIGZMQswCQYDVQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czESMBAG ++A1UEBxMJQ2FtYnJpZGdlMQwwCgYDVQQKEwNNSVQxIjAgBgNVBAsTGUluc2VjdXJl ++IEtlcmJlcm9zIHRlc3QgQ0ExLDAqBgNVBAMUI3Rlc3Qgc3VpdGUgQ0E7IGRvIG5v ++dCB1c2Ugb3RoZXJ3aXNlggEBMAsGA1UdDwQEAwID6DAMBgNVHRMBAf8EAjAAMBMG ++A1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4IBAQCzGPT+QOrl9mbJ ++nsGlPlLUOF+PYz0a/9V/iznlofxwCXiRi2ryMpLFbjLeOvjLJ3UzyNKtmEeudTBM ++yfR4i8tb9WA7Oh0BjK1+kD4688bAUXiIDhueKBjonmPvMd9kq3MDd4vDLkcZk6R4 ++4IcbdwhzSBmnJH8ha2J82XShPpRq5CZNR9+vTyFwGdGWdPDjTMiXoXAmpRemcEgO ++iO4Gxvcrg/Z06Ys3eLze7QHNMAEwXhC4rUR34j5I2zgU7CEhff3AktLmnKVa8go8 ++4BJT/n3XGB+3gdAEihQmgCEZetHH+YxAR0Ppn3ty7fpAlOnbRJqpeu6TMN8x/lL8 ++c6JtDWRG ++-----END CERTIFICATE----- +diff --git a/src/util/paste-kdcproxy.py b/src/util/paste-kdcproxy.py +new file mode 100755 +index 0000000..1e56b89 +--- /dev/null ++++ b/src/util/paste-kdcproxy.py +@@ -0,0 +1,18 @@ ++#!/usr/bin/python ++import kdcproxy ++from paste import httpserver ++import os ++import sys ++ ++if len(sys.argv) > 1: ++ port = sys.argv[1] ++else: ++ port = 8443 ++if len(sys.argv) > 2: ++ pem = sys.argv[2] ++else: ++ pem = '*' ++server = httpserver.serve(kdcproxy.Application(), port=port, ssl_pem=pem, ++ start_loop=False) ++os.write(sys.stdout.fileno(), 'proxy server ready\n') ++server.serve_forever() +-- +2.1.0 + diff --git a/SOURCES/0013-Add-tests-for-MS-KKDCP-client-support.patch b/SOURCES/0013-Add-tests-for-MS-KKDCP-client-support.patch new file mode 100644 index 0000000..fdb6eca --- /dev/null +++ b/SOURCES/0013-Add-tests-for-MS-KKDCP-client-support.patch @@ -0,0 +1,259 @@ +Tweaked context for src/tests/Makefile.in because t_salt.py hadn't yet been +added as a test in 1.12, and the rdreq and s2p helpers weren't there yet. + +From 3e2c7cc557048faac3400ae41b0228bd37a82a4c Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Fri, 7 Feb 2014 18:56:10 -0500 +Subject: [PATCH 13/13] Add tests for MS-KKDCP client support + +Exercise the MS-KKDCP client support using the test proxy server, for +AS, TGS, and kpasswd requests while also checking the certificate +verification and name checks. + +ticket: 7929 +--- + src/tests/Makefile.in | 1 + + src/tests/t_proxy.py | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 220 insertions(+) + create mode 100644 src/tests/t_proxy.py + +diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in +index 7347ed6..536f5cb 100644 +--- a/src/tests/Makefile.in ++++ b/src/tests/Makefile.in +@@ -134,6 +134,7 @@ check-pytests:: t_init_creds t_localauth + $(RUNPYTEST) $(srcdir)/jsonwalker.py -d $(srcdir)/au_dict.json \ + -i au.log + $(RUNPYTEST) $(srcdir)/t_bogus_kdc_req.py $(PYTESTFLAGS) ++ $(RUNPYTEST) $(srcdir)/t_proxy.py $(PYTESTFLAGS) + + clean:: + $(RM) gcred hist hrealm kdbtest plugorder responder +diff --git a/src/tests/t_proxy.py b/src/tests/t_proxy.py +new file mode 100644 +index 0000000..e4e3d48 +--- /dev/null ++++ b/src/tests/t_proxy.py +@@ -0,0 +1,219 @@ ++#!/usr/bin/python ++from k5test import * ++ ++# Skip this test if we're missing proxy functionality or parts of the proxy. ++if runenv.proxy_tls_impl == 'no': ++ success('Warning: not testing proxy support because feature ' + ++ 'was not enabled') ++ exit(0) ++try: ++ from paste import httpserver ++except: ++ success('Warning: not testing proxy support because python ' + ++ 'paste.httpserver module not found') ++ exit(0) ++try: ++ import kdcproxy ++except: ++ success('Warning: not testing proxy support because python ' + ++ 'kdcproxy module not found') ++ exit(0) ++ ++# Construct a krb5.conf fragment configuring the client to use a local proxy ++# server. ++proxysubjectpem = os.path.join(srctop, 'tests', 'dejagnu', 'proxy-certs', ++ 'proxy-subject.pem') ++proxysanpem = os.path.join(srctop, 'tests', 'dejagnu', 'proxy-certs', ++ 'proxy-san.pem') ++proxyidealpem = os.path.join(srctop, 'tests', 'dejagnu', 'proxy-certs', ++ 'proxy-ideal.pem') ++proxywrongpem = os.path.join(srctop, 'tests', 'dejagnu', 'proxy-certs', ++ 'proxy-no-match.pem') ++proxybadpem = os.path.join(srctop, 'tests', 'dejagnu', 'proxy-certs', ++ 'proxy-badsig.pem') ++proxyca = os.path.join(srctop, 'tests', 'dejagnu', 'proxy-certs', 'ca.pem') ++proxyurl = 'https://localhost:$port5/KdcProxy' ++proxyurlupcase = 'https://LocalHost:$port5/KdcProxy' ++proxyurl4 = 'https://127.0.0.1:$port5/KdcProxy' ++proxyurl6 = 'https://[::1]:$port5/KdcProxy' ++ ++unanchored_krb5_conf = {'realms': {'$realm': { ++ 'kdc': proxyurl, ++ 'kpasswd_server': proxyurl}}} ++anchored_name_krb5_conf = {'realms': {'$realm': { ++ 'kdc': proxyurl, ++ 'kpasswd_server': proxyurl, ++ 'http_anchors': 'FILE:%s' % proxyca}}} ++anchored_upcasename_krb5_conf = {'realms': {'$realm': { ++ 'kdc': proxyurlupcase, ++ 'kpasswd_server': proxyurlupcase, ++ 'http_anchors': 'FILE:%s' % proxyca}}} ++anchored_kadmin_krb5_conf = {'realms': {'$realm': { ++ 'kdc': proxyurl, ++ 'admin_server': proxyurl, ++ 'http_anchors': 'FILE:%s' % proxyca}}} ++anchored_ipv4_krb5_conf = {'realms': {'$realm': { ++ 'kdc': proxyurl4, ++ 'kpasswd_server': proxyurl4, ++ 'http_anchors': 'FILE:%s' % proxyca}}} ++kpasswd_input = (password('user') + '\n' + password('user') + '\n' + ++ password('user') + '\n') ++ ++def start_proxy(realm, keycertpem): ++ proxy_conf_path = os.path.join(realm.testdir, 'kdcproxy.conf') ++ proxy_exec_path = os.path.join(srctop, 'util', 'paste-kdcproxy.py') ++ conf = open(proxy_conf_path, 'w') ++ conf.write('[%s]\n' % realm.realm) ++ conf.write('kerberos = kerberos://localhost:%d\n' % realm.portbase) ++ conf.write('kpasswd = kpasswd://localhost:%d\n' % (realm.portbase + 2)) ++ conf.close() ++ realm.env['KDCPROXY_CONFIG'] = proxy_conf_path ++ cmd = [proxy_exec_path, str(realm.server_port()), keycertpem] ++ return realm.start_server(cmd, sentinel='proxy server ready') ++ ++# Fail: untrusted issuer and hostname doesn't match. ++output("running pass 1: issuer not trusted and hostname doesn't match\n") ++realm = K5Realm(krb5_conf=unanchored_krb5_conf, get_creds=False, ++ create_host=False) ++proxy = start_proxy(realm, proxywrongpem) ++realm.kinit(realm.user_princ, password=password('user'), expected_code=1) ++stop_daemon(proxy) ++realm.stop() ++ ++# Fail: untrusted issuer, host name matches subject. ++output("running pass 2: subject matches, issuer not trusted\n") ++realm = K5Realm(krb5_conf=unanchored_krb5_conf, get_creds=False, ++ create_host=False) ++proxy = start_proxy(realm, proxysubjectpem) ++realm.kinit(realm.user_princ, password=password('user'), expected_code=1) ++stop_daemon(proxy) ++realm.stop() ++ ++# Fail: untrusted issuer, host name matches subjectAltName. ++output("running pass 3: subjectAltName matches, issuer not trusted\n") ++realm = K5Realm(krb5_conf=unanchored_krb5_conf, get_creds=False, ++ create_host=False) ++proxy = start_proxy(realm, proxysanpem) ++realm.kinit(realm.user_princ, password=password('user'), expected_code=1) ++stop_daemon(proxy) ++realm.stop() ++ ++# Fail: untrusted issuer, certificate signature is bad. ++output("running pass 4: subject matches, issuer not trusted\n") ++realm = K5Realm(krb5_conf=unanchored_krb5_conf, get_creds=False, ++ create_host=False) ++proxy = start_proxy(realm, proxybadpem) ++realm.kinit(realm.user_princ, password=password('user'), expected_code=1) ++stop_daemon(proxy) ++realm.stop() ++ ++# Fail: trusted issuer but hostname doesn't match. ++output("running pass 5: issuer trusted but hostname doesn't match\n") ++realm = K5Realm(krb5_conf=anchored_name_krb5_conf, get_creds=False, ++ create_host=False) ++proxy = start_proxy(realm, proxywrongpem) ++realm.kinit(realm.user_princ, password=password('user'), expected_code=1) ++stop_daemon(proxy) ++realm.stop() ++ ++# Succeed: trusted issuer and host name matches subject. ++output("running pass 6: issuer trusted, subject matches\n") ++realm = K5Realm(krb5_conf=anchored_name_krb5_conf, start_kadmind=True, ++ get_creds=False) ++proxy = start_proxy(realm, proxysubjectpem) ++realm.kinit(realm.user_princ, password=password('user')) ++realm.run([kvno, realm.host_princ]) ++realm.run([kpasswd, realm.user_princ], input=kpasswd_input) ++stop_daemon(proxy) ++realm.stop() ++ ++# Succeed: trusted issuer and host name matches subjectAltName. ++output("running pass 7: issuer trusted, subjectAltName matches\n") ++realm = K5Realm(krb5_conf=anchored_name_krb5_conf, start_kadmind=True, ++ get_creds=False) ++proxy = start_proxy(realm, proxysanpem) ++realm.kinit(realm.user_princ, password=password('user')) ++realm.run([kvno, realm.host_princ]) ++realm.run([kpasswd, realm.user_princ], input=kpasswd_input) ++stop_daemon(proxy) ++realm.stop() ++ ++# Fail: certificate signature is bad. ++output("running pass 8: issuer trusted and subjectAltName matches, sig bad\n") ++realm = K5Realm(krb5_conf=anchored_name_krb5_conf, ++ get_creds=False, ++ create_host=False) ++proxy = start_proxy(realm, proxybadpem) ++realm.kinit(realm.user_princ, password=password('user'), expected_code=1) ++stop_daemon(proxy) ++realm.stop() ++ ++# Fail: trusted issuer but IP doesn't match. ++output("running pass 9: issuer trusted but no name matches IP\n") ++realm = K5Realm(krb5_conf=anchored_ipv4_krb5_conf, get_creds=False, ++ create_host=False) ++proxy = start_proxy(realm, proxywrongpem) ++realm.kinit(realm.user_princ, password=password('user'), expected_code=1) ++stop_daemon(proxy) ++realm.stop() ++ ++# Fail: trusted issuer, but subject does not match. ++output("running pass 10: issuer trusted, but subject does not match IP\n") ++realm = K5Realm(krb5_conf=anchored_ipv4_krb5_conf, get_creds=False, ++ create_host=False) ++proxy = start_proxy(realm, proxysubjectpem) ++realm.kinit(realm.user_princ, password=password('user'), expected_code=1) ++stop_daemon(proxy) ++realm.stop() ++ ++# Succeed: trusted issuer and host name matches subjectAltName. ++output("running pass 11: issuer trusted, subjectAltName matches IP\n") ++realm = K5Realm(krb5_conf=anchored_ipv4_krb5_conf, start_kadmind=True, ++ get_creds=False) ++proxy = start_proxy(realm, proxysanpem) ++realm.kinit(realm.user_princ, password=password('user')) ++realm.run([kvno, realm.host_princ]) ++realm.run([kpasswd, realm.user_princ], input=kpasswd_input) ++stop_daemon(proxy) ++realm.stop() ++ ++# Fail: certificate signature is bad. ++output("running pass 12: issuer trusted, names don't match, signature bad\n") ++realm = K5Realm(krb5_conf=anchored_ipv4_krb5_conf, get_creds=False, ++ create_host=False) ++proxy = start_proxy(realm, proxybadpem) ++realm.kinit(realm.user_princ, password=password('user'), expected_code=1) ++stop_daemon(proxy) ++realm.stop() ++ ++# Succeed: trusted issuer and host name matches subject, using kadmin ++# configuration to find kpasswdd. ++output("running pass 13: issuer trusted, subject matches\n") ++realm = K5Realm(krb5_conf=anchored_kadmin_krb5_conf, start_kadmind=True, ++ get_creds=False, create_host=False) ++proxy = start_proxy(realm, proxysubjectpem) ++realm.run([kpasswd, realm.user_princ], input=kpasswd_input) ++stop_daemon(proxy) ++realm.stop() ++ ++# Succeed: trusted issuer and host name matches subjectAltName, using ++# kadmin configuration to find kpasswdd. ++output("running pass 14: issuer trusted, subjectAltName matches\n") ++realm = K5Realm(krb5_conf=anchored_kadmin_krb5_conf, start_kadmind=True, ++ get_creds=False, create_host=False) ++proxy = start_proxy(realm, proxysanpem) ++realm.run([kpasswd, realm.user_princ], input=kpasswd_input) ++stop_daemon(proxy) ++realm.stop() ++ ++# Succeed: trusted issuer and host name matches subjectAltName (give or take ++# case). ++output("running pass 15: issuer trusted, subjectAltName case-insensitive\n") ++realm = K5Realm(krb5_conf=anchored_upcasename_krb5_conf, start_kadmind=True, ++ get_creds=False, create_host=False) ++proxy = start_proxy(realm, proxysanpem) ++realm.run([kpasswd, realm.user_princ], input=kpasswd_input) ++stop_daemon(proxy) ++realm.stop() ++ ++success('MS-KKDCP proxy') +-- +2.1.0 + diff --git a/SOURCES/kprop.service b/SOURCES/kprop.service index 959a300..4ed2247 100644 --- a/SOURCES/kprop.service +++ b/SOURCES/kprop.service @@ -4,7 +4,7 @@ After=syslog.target network.target [Service] Type=forking -ExecStart=/usr/sbin/_kpropd -S +ExecStart=/usr/sbin/_kpropd [Install] WantedBy=multi-user.target diff --git a/SOURCES/krb5-1.10-CVE-2013-1418.patch b/SOURCES/krb5-1.10-CVE-2013-1418.patch deleted file mode 100644 index 0adb104..0000000 --- a/SOURCES/krb5-1.10-CVE-2013-1418.patch +++ /dev/null @@ -1,37 +0,0 @@ -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 deleted file mode 100644 index 25b05ac..0000000 --- a/SOURCES/krb5-1.10-buildconf.patch +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index c20075c..0000000 --- a/SOURCES/krb5-1.10-doublelog.patch +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index fd8da8e..0000000 --- a/SOURCES/krb5-1.10-kpasswd_tcp.patch +++ /dev/null @@ -1,32 +0,0 @@ -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-ksu-path.patch b/SOURCES/krb5-1.10-ksu-path.patch deleted file mode 100644 index 48443ef..0000000 --- a/SOURCES/krb5-1.10-ksu-path.patch +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 67875e6..0000000 --- a/SOURCES/krb5-1.11-alpha1-init.patch +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index f3ce693..0000000 --- a/SOURCES/krb5-1.11-check_transited.patch +++ /dev/null @@ -1,56 +0,0 @@ -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-gss-client-keytab.patch b/SOURCES/krb5-1.11-gss-client-keytab.patch deleted file mode 100644 index 3c1e964..0000000 --- a/SOURCES/krb5-1.11-gss-client-keytab.patch +++ /dev/null @@ -1,131 +0,0 @@ -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 deleted file mode 100644 index ad7b07f..0000000 --- a/SOURCES/krb5-1.11-gss-methods1.patch +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index 6d6e620..0000000 --- a/SOURCES/krb5-1.11-gss-methods2.patch +++ /dev/null @@ -1,38 +0,0 @@ -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-pam.patch b/SOURCES/krb5-1.11-pam.patch deleted file mode 100644 index 9e1d516..0000000 --- a/SOURCES/krb5-1.11-pam.patch +++ /dev/null @@ -1,753 +0,0 @@ -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-preauthcore.patch b/SOURCES/krb5-1.11-preauthcore.patch deleted file mode 100644 index 27c6692..0000000 --- a/SOURCES/krb5-1.11-preauthcore.patch +++ /dev/null @@ -1,12 +0,0 @@ -Backport a small fix from 1.12 (#1035203). - ---- src/lib/krb5/krb/preauth2.c -+++ src/lib/krb5/krb/preauth2.c -@@ -1002,6 +1002,7 @@ krb5_do_preauth(krb5_context context, kr - krb5_init_preauth_context(context); - if (context->preauth_context == NULL) { - *out_padata = out_pa_list; -+ out_pa_list = NULL; - goto error; - } - diff --git a/SOURCES/krb5-1.11-rcache-acquirecred-source.patch b/SOURCES/krb5-1.11-rcache-acquirecred-source.patch deleted file mode 100644 index d67d5c7..0000000 --- a/SOURCES/krb5-1.11-rcache-acquirecred-source.patch +++ /dev/null @@ -1,138 +0,0 @@ -Adapted. - -commit 7dad0bee30fbbde8cfc0eacd2d1487c198a004a1 -Author: Simo Sorce -Date: Thu Dec 26 19:05:34 2013 -0500 - - Add rcache feature to gss_acquire_cred_from - - The "rcache" cred store entry can specify a replay cache type and name - to be used with the credentials being acquired. - - [ghudson@mit.edu: split up, simplified, and altered to fit preparatory - commits] - - ticket: 7819 (new) - -diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c -index f625c0c..5d680f9 100644 ---- a/src/lib/gssapi/krb5/acquire_cred.c -+++ b/src/lib/gssapi/krb5/acquire_cred.c -@@ -180,7 +180,8 @@ cleanup: - - static OM_uint32 - acquire_accept_cred(krb5_context context, OM_uint32 *minor_status, -- krb5_keytab req_keytab, krb5_gss_cred_id_rec *cred) -+ krb5_keytab req_keytab, const char *rcname, -+ krb5_gss_cred_id_rec *cred) - { - OM_uint32 major; - krb5_error_code code; -@@ -189,6 +190,20 @@ acquire_accept_cred(krb5_context context, OM_uint32 *minor_status, - - assert(cred->keytab == NULL); - -+ /* If we have an explicit rcache name, open it. */ -+ if (rcname != NULL) { -+ code = krb5_rc_resolve_full(context, &rc, rcname); -+ if (code) { -+ major = GSS_S_FAILURE; -+ goto cleanup; -+ } -+ code = krb5_rc_recover_or_initialize(context, rc, context->clockskew); -+ if (code) { -+ major = GSS_S_FAILURE; -+ goto cleanup; -+ } -+ } -+ - if (req_keytab != NULL) { - char ktname[BUFSIZ]; - -@@ -221,12 +236,14 @@ acquire_accept_cred(krb5_context context, OM_uint32 *minor_status, - goto cleanup; - } - -- /* Open the replay cache for this principal. */ -- code = krb5_get_server_rcache(context, &cred->name->princ->data[0], -- &rc); -- if (code) { -- major = GSS_S_FAILURE; -- goto cleanup; -+ if (rc == NULL) { -+ /* Open the replay cache for this principal. */ -+ code = krb5_get_server_rcache(context, &cred->name->princ->data[0], -+ &rc); -+ if (code) { -+ major = GSS_S_FAILURE; -+ goto cleanup; -+ } - } - } else { - /* Make sure we have a keytab with keys in it. */ -@@ -718,8 +735,8 @@ 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 client_keytab, -- krb5_keytab keytab, krb5_boolean iakerb, -- gss_cred_id_t *output_cred_handle, -+ krb5_keytab keytab, const char *rcname, -+ krb5_boolean iakerb, gss_cred_id_t *output_cred_handle, - OM_uint32 *time_rec) - { - krb5_gss_cred_id_t cred = NULL; -@@ -775,7 +792,7 @@ acquire_cred_context(krb5_context context, OM_uint32 *minor_status, - * in cred->name if desired_princ is specified. - */ - if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { -- ret = acquire_accept_cred(context, minor_status, keytab, cred); -+ ret = acquire_accept_cred(context, minor_status, keytab, rcname, cred); - if (ret != GSS_S_COMPLETE) - goto error_out; - } -@@ -867,7 +884,7 @@ 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, NULL, keytab, -- iakerb, output_cred_handle, time_rec); -+ NULL, iakerb, output_cred_handle, time_rec); - - out: - krb5_free_context(context); -@@ -1135,7 +1152,7 @@ krb5_gss_acquire_cred_from(OM_uint32 *minor_status, - krb5_keytab client_keytab = NULL; - krb5_keytab keytab = NULL; - krb5_ccache ccache = NULL; -- const char *value; -+ const char *rcname, *value; - OM_uint32 ret; - - code = gss_krb5int_initialize_library(); -@@ -1191,9 +1208,14 @@ krb5_gss_acquire_cred_from(OM_uint32 *minor_status, - } - } - -+ ret = kg_value_from_cred_store(cred_store, KRB5_CS_RCACHE_URN, &rcname); -+ if (GSS_ERROR(ret)) -+ goto out; -+ - ret = acquire_cred_context(context, minor_status, desired_name, NULL, - time_req, cred_usage, ccache, client_keytab, -- keytab, 0, output_cred_handle, time_rec); -+ keytab, rcname, 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 0167816..8e4f6d9 100644 ---- a/src/lib/gssapi/krb5/gssapiP_krb5.h -+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h -@@ -1260,6 +1260,7 @@ data_to_gss(krb5_data *input_k5data, gss_buffer_t output_buffer) - #define KRB5_CS_CLI_KEYTAB_URN "client_keytab" - #define KRB5_CS_KEYTAB_URN "keytab" - #define KRB5_CS_CCACHE_URN "ccache" -+#define KRB5_CS_RCACHE_URN "rcache" - - OM_uint32 - kg_value_from_cred_store(gss_const_key_value_set_t cred_store, diff --git a/SOURCES/krb5-1.11-rcache-acquirecred-test.patch b/SOURCES/krb5-1.11-rcache-acquirecred-test.patch deleted file mode 100644 index ec1709b..0000000 --- a/SOURCES/krb5-1.11-rcache-acquirecred-test.patch +++ /dev/null @@ -1,90 +0,0 @@ -Adapted, with some more intermediate context applied in between. - -commit 6f8d5135334c9ddb674f9824e750872b3b0642ea -Author: Greg Hudson -Date: Thu Jan 16 11:49:55 2014 -0500 - - Add test for gss_acquire_cred_from rcache feature - -diff --git a/src/tests/gssapi/t_credstore.c b/src/tests/gssapi/t_credstore.c -index 575f96d..e28f5d0 100644 ---- a/src/tests/gssapi/t_credstore.c -+++ b/src/tests/gssapi/t_credstore.c -@@ -46,7 +46,9 @@ main(int argc, char *argv[]) - gss_cred_usage_t cred_usage = GSS_C_BOTH; - gss_OID_set mechs = GSS_C_NO_OID_SET; - gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; -- krb5_boolean store_creds = FALSE; -+ gss_ctx_id_t ictx = GSS_C_NO_CONTEXT, actx = GSS_C_NO_CONTEXT; -+ gss_buffer_desc itok, atok; -+ krb5_boolean store_creds = FALSE, replay = FALSE; - char opt; - - /* Parse options. */ -@@ -54,6 +56,8 @@ main(int argc, char *argv[]) - opt = (*argv)[1]; - if (opt == 's') - store_creds = TRUE; -+ else if (opt == 'r') -+ replay = TRUE; - else if (opt == 'a') - cred_usage = GSS_C_ACCEPT; - else if (opt == 'b') -@@ -101,6 +105,31 @@ main(int argc, char *argv[]) - &store, &cred, NULL, NULL); - check_gsserr("gss_acquire_cred_from", major, minor); - -+ if (replay) { -+ /* Induce a replay using cred as the acceptor cred, to test the replay -+ * cache indicated by the store. */ -+ major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &ictx, name, -+ &mech_krb5, 0, GSS_C_INDEFINITE, -+ GSS_C_NO_CHANNEL_BINDINGS, -+ GSS_C_NO_BUFFER, NULL, &itok, NULL, NULL); -+ check_gsserr("gss_init_sec_context", major, minor); -+ (void)gss_delete_sec_context(&minor, &ictx, NULL); -+ -+ major = gss_accept_sec_context(&minor, &actx, cred, &itok, -+ GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL, -+ &atok, NULL, NULL, NULL); -+ check_gsserr("gss_accept_sec_context(1)", major, minor); -+ (void)gss_release_buffer(&minor, &atok); -+ (void)gss_delete_sec_context(&minor, &actx, NULL); -+ -+ major = gss_accept_sec_context(&minor, &actx, cred, &itok, -+ GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL, -+ &atok, NULL, NULL, NULL); -+ check_gsserr("gss_accept_sec_context(2)", major, minor); -+ (void)gss_release_buffer(&minor, &atok); -+ (void)gss_delete_sec_context(&minor, &actx, NULL); -+ } -+ - gss_release_name(&minor, &name); - gss_release_cred(&minor, &cred); - free(store.elements); -diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py -index 74139e4..106910d 100755 ---- a/src/tests/gssapi/t_gssapi.py -+++ b/src/tests/gssapi/t_gssapi.py -@@ -89,11 +89,18 @@ - realm.addprinc(service_cs) - realm.extract_keytab(service_cs, servicekeytab) - realm.kinit(service_cs, None, ['-k', '-t', servicekeytab]) --output = realm.run_as_client(['./t_credstore', service_cs, '--cred_store', -+output = realm.run_as_client(['./t_credstore', '-s', 'p:' + service_cs, - 'ccache', storagecache, 'keytab', servicekeytab]) --if 'Cred Store Success' not in output: -- fail('Expected test to succeed') - -+# Test rcache feature of cred stores. t_credstore -r should produce a -+# replay error normally, but not with rcache set to "none:". -+output = realm.run_as_client(['./t_credstore', '-r', '-a', -+ 'p:' + realm.host_princ], expected_code=1) -+if 'gss_accept_sec_context(2): Request is a replay' not in output: -+ fail('Expected replay error not seen in t_credstore output') -+realm.run_as_client(['./t_credstore', '-r', '-a', 'p:' + realm.host_princ, -+ 'rcache', 'none:']) -+ - # Verify that we can't acquire acceptor creds without a keytab. - os.remove(realm.keytab) - output = realm.run_as_client(['./t_accname', 'p:abc'], expected_code=1) diff --git a/SOURCES/krb5-1.11-selinux-label.patch b/SOURCES/krb5-1.11-selinux-label.patch deleted file mode 100644 index f832728..0000000 --- a/SOURCES/krb5-1.11-selinux-label.patch +++ /dev/null @@ -1,1015 +0,0 @@ -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-spnego-preserve-oid.patch b/SOURCES/krb5-1.11-spnego-preserve-oid.patch deleted file mode 100644 index 619a64c..0000000 --- a/SOURCES/krb5-1.11-spnego-preserve-oid.patch +++ /dev/null @@ -1,171 +0,0 @@ -Adjusted to apply to 1.11.5. - -commit 8255613476d4c1583a5e810b50444f188fde871f -Author: Greg Hudson -Date: Mon Feb 3 21:11:34 2014 -0500 - - Properly reflect MS krb5 mech in SPNEGO acceptor - - r25590 changed negotiate_mech() to return an alias into the acceptor's - mech set, with the unfortunate side effect of transforming the - erroneous Microsoft krb5 mech OID into the correct krb5 mech OID, - meaning that we answer with a different OID than the requested one. - Return an alias into the initiator's mech set instead, and store that - in mech_set field the SPNEGO context. The acceptor code only uses - mech_set to hold the allocated storage pointed into by internal_mech, - so this change is safe. - - ticket: 7858 - target_version: 1.12.2 - tags: pullup - -diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c -index 7e4bf90..7529c74 100644 ---- a/src/lib/gssapi/spnego/spnego_mech.c -+++ b/src/lib/gssapi/spnego/spnego_mech.c -@@ -1388,8 +1388,8 @@ acc_ctx_new(OM_uint32 *minor_status, - *return_token = NO_TOKEN_SEND; - goto cleanup; - } -- sc->mech_set = supported_mechSet; -- supported_mechSet = GSS_C_NO_OID_SET; -+ sc->mech_set = mechTypes; -+ mechTypes = GSS_C_NO_OID_SET; - sc->internal_mech = mech_wanted; - sc->DER_mechTypes = der_mechTypes; - der_mechTypes.length = 0; -@@ -3538,7 +3538,7 @@ put_negResult(unsigned char **buf_out, OM_uint32 negResult, - * is set to ACCEPT_INCOMPLETE if it's the first mech, REQUEST_MIC if - * it's not the first mech, otherwise we return NULL and negResult - * is set to REJECT. The returned pointer is an alias into -- * supported->elements and should not be freed. -+ * received->elements and should not be freed. - * - * NOTE: There is currently no way to specify a preference order of - * mechanisms supported by the acceptor. -@@ -3560,7 +3560,7 @@ negotiate_mech(gss_OID_set supported, gss_OID_set received, - if (g_OID_equal(mech_oid, &supported->elements[j])) { - *negResult = (i == 0) ? ACCEPT_INCOMPLETE : - REQUEST_MIC; -- return &supported->elements[j]; -+ return &received->elements[i]; - } - } - } - -commit 53cfb8327c452bd72a8e915338fb5ec838079cd3 -Author: Greg Hudson -Date: Mon Feb 3 20:59:54 2014 -0500 - - Test SPNEGO acceptor response to MS krb5 mech OID - - In t_spnego.c, add code to make a SPNEGO request with the erroneous - Microsoft OID value and examine the response to make sure that it uses - the same OID value as the request did. The token and tmp variables - were unused, so rename them to itok and atok for the purpose of the - new test code. - - ticket: 7858 - target_version: 1.12.2 - tags: pullup - -diff --git a/src/tests/gssapi/t_spnego.c b/src/tests/gssapi/t_spnego.c -index cbf720b..ca05848 100644 ---- a/src/tests/gssapi/t_spnego.c -+++ b/src/tests/gssapi/t_spnego.c -@@ -27,9 +27,15 @@ - #include - #include - #include -+#include - - #include "common.h" - -+static gss_OID_desc mech_krb5_wrong = { -+ 9, "\052\206\110\202\367\022\001\002\002" -+}; -+gss_OID_set_desc mechset_krb5_wrong = { 1, &mech_krb5_wrong }; -+ - /* - * Test program for SPNEGO and gss_set_neg_mechs - * -@@ -44,13 +50,16 @@ main(int argc, char *argv[]) - { - OM_uint32 minor, major; - gss_cred_id_t verifier_cred_handle = GSS_C_NO_CREDENTIAL; -+ gss_cred_id_t initiator_cred_handle = GSS_C_NO_CREDENTIAL; - gss_OID_set actual_mechs = GSS_C_NO_OID_SET; - gss_buffer_desc token = GSS_C_EMPTY_BUFFER, tmp = GSS_C_EMPTY_BUFFER; -+ gss_buffer_desc itok = GSS_C_EMPTY_BUFFER, atok = GSS_C_EMPTY_BUFFER; - gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT; - gss_ctx_id_t acceptor_context = GSS_C_NO_CONTEXT; - gss_name_t target_name, source_name = GSS_C_NO_NAME; - OM_uint32 time_rec; - gss_OID mech = GSS_C_NO_OID; -+ const unsigned char *atok_oid; - - if (argc < 2 || argc > 3) { - fprintf(stderr, "Usage: %s target_name [keytab]\n", argv[0]); -@@ -83,10 +91,59 @@ main(int argc, char *argv[]) - - (void)gss_delete_sec_context(&minor, &acceptor_context, NULL); - (void)gss_release_name(&minor, &source_name); -- (void)gss_release_name(&minor, &target_name); -- (void)gss_release_buffer(&minor, &token); -- (void)gss_release_buffer(&minor, &tmp); - (void)gss_release_cred(&minor, &verifier_cred_handle); - (void)gss_release_oid_set(&minor, &actual_mechs); -+ -+ /* -+ * Test that the SPNEGO acceptor code properly reflects back the erroneous -+ * Microsoft mech OID in the supportedMech field of the NegTokenResp -+ * message. Our initiator code doesn't care (it treats all variants of the -+ * krb5 mech as equivalent when comparing the supportedMech response to its -+ * first-choice mech), so we have to look directly at the DER encoding of -+ * the response token. If we don't request mutual authentication, the -+ * SPNEGO reply will contain no underlying mech token, so the encoding of -+ * the correct NegotiationToken response is completely predictable: -+ * -+ * A1 14 (choice 1, length 20, meaning negTokenResp) -+ * 30 12 (sequence, length 18) -+ * A0 03 (context tag 0, length 3) -+ * 0A 01 00 (enumerated value 0, meaning accept-completed) -+ * A1 0B (context tag 1, length 11) -+ * 06 09 (object identifier, length 9) -+ * 2A 86 48 82 F7 12 01 02 02 (the erroneous krb5 OID) -+ * -+ * So we can just compare the length to 22 and the nine bytes at offset 13 -+ * to the expected OID. -+ */ -+ major = gss_acquire_cred(&minor, GSS_C_NO_NAME, GSS_C_INDEFINITE, -+ &mechset_spnego, GSS_C_INITIATE, -+ &initiator_cred_handle, NULL, NULL); -+ check_gsserr("gss_acquire_cred(2)", major, minor); -+ major = gss_set_neg_mechs(&minor, initiator_cred_handle, -+ &mechset_krb5_wrong); -+ check_gsserr("gss_set_neg_mechs(2)", major, minor); -+ major = gss_init_sec_context(&minor, initiator_cred_handle, -+ &initiator_context, target_name, &mech_spnego, -+ GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG, -+ GSS_C_INDEFINITE, -+ GSS_C_NO_CHANNEL_BINDINGS, &atok, NULL, &itok, -+ NULL, NULL); -+ check_gsserr("gss_init_sec_context", major, minor); -+ assert(major == GSS_S_CONTINUE_NEEDED); -+ major = gss_accept_sec_context(&minor, &acceptor_context, -+ GSS_C_NO_CREDENTIAL, &itok, -+ GSS_C_NO_CHANNEL_BINDINGS, NULL, -+ NULL, &atok, NULL, NULL, NULL); -+ assert(atok.length == 22); -+ atok_oid = (unsigned char *)atok.value + 13; -+ assert(memcmp(atok_oid, mech_krb5_wrong.elements, 9) == 0); -+ check_gsserr("gss_accept_sec_context", major, minor); -+ -+ (void)gss_delete_sec_context(&minor, &initiator_context, NULL); -+ (void)gss_delete_sec_context(&minor, &acceptor_context, NULL); -+ (void)gss_release_cred(&minor, &initiator_cred_handle); -+ (void)gss_release_name(&minor, &target_name); -+ (void)gss_release_buffer(&minor, &itok); -+ (void)gss_release_buffer(&minor, &atok); - return 0; - } diff --git a/SOURCES/krb5-1.11.2-arcfour_short.patch b/SOURCES/krb5-1.11.2-arcfour_short.patch deleted file mode 100644 index 2f67ae3..0000000 --- a/SOURCES/krb5-1.11.2-arcfour_short.patch +++ /dev/null @@ -1,122 +0,0 @@ -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 deleted file mode 100644 index 3941084..0000000 --- a/SOURCES/krb5-1.11.2-empty_passwords.patch +++ /dev/null @@ -1,492 +0,0 @@ -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 deleted file mode 100644 index 4b4bd08..0000000 --- a/SOURCES/krb5-1.11.2-keycheck.patch +++ /dev/null @@ -1,230 +0,0 @@ -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 deleted file mode 100644 index eab913e..0000000 --- a/SOURCES/krb5-1.11.2-otp.patch +++ /dev/null @@ -1,5163 +0,0 @@ -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 deleted file mode 100644 index c7dc919..0000000 --- a/SOURCES/krb5-1.11.2-skew1.patch +++ /dev/null @@ -1,115 +0,0 @@ ->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 deleted file mode 100644 index d5063bd..0000000 --- a/SOURCES/krb5-1.11.2-skew2.patch +++ /dev/null @@ -1,144 +0,0 @@ ->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-1.12.1-credstoretest.patch b/SOURCES/krb5-1.11.3-1.12.1-credstoretest.patch deleted file mode 100644 index dbfd7fe..0000000 --- a/SOURCES/krb5-1.11.3-1.12.1-credstoretest.patch +++ /dev/null @@ -1,125 +0,0 @@ -diff --git a/src/tests/gssapi/t_credstore.c b/src/tests/gssapi/t_credstore.c -index 085bc79..575f96d 100644 ---- a/src/tests/gssapi/t_credstore.c -+++ b/src/tests/gssapi/t_credstore.c -@@ -33,7 +33,7 @@ static void - usage(void) - { - fprintf(stderr, -- "Usage: t_credstore principal [--cred_store {key value} ...]\n"); -+ "Usage: t_credstore [-sabi] principal [{key value} ...]\n"); - exit(1); - } - -@@ -42,63 +42,66 @@ main(int argc, char *argv[]) - { - OM_uint32 minor, major; - gss_key_value_set_desc store; -- gss_buffer_desc buf; -- gss_name_t service = GSS_C_NO_NAME; -+ gss_name_t name; -+ gss_cred_usage_t cred_usage = GSS_C_BOTH; -+ gss_OID_set mechs = GSS_C_NO_OID_SET; - gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; -- int i, e; -- -- if (argc < 2 || ((argc - 3) % 2)) -- usage(); -- -- store.count = (argc - 3) / 2; -- store.elements = calloc(store.count, -- sizeof(struct gss_key_value_element_struct)); -- if (!store.elements) { -- fprintf(stderr, "OOM\n"); -- exit(1); -+ krb5_boolean store_creds = FALSE; -+ char opt; -+ -+ /* Parse options. */ -+ for (argv++; *argv != NULL && **argv == '-'; argv++) { -+ opt = (*argv)[1]; -+ if (opt == 's') -+ store_creds = TRUE; -+ else if (opt == 'a') -+ cred_usage = GSS_C_ACCEPT; -+ else if (opt == 'b') -+ cred_usage = GSS_C_BOTH; -+ else if (opt == 'i') -+ cred_usage = GSS_C_INITIATE; -+ else -+ usage(); - } - -- if (argc > 2) { -- if (strcmp(argv[2], "--cred_store") != 0) -+ /* Get the principal name. */ -+ if (*argv == NULL) -+ usage(); -+ name = import_name(*argv++); -+ -+ /* Put any remaining arguments into the store. */ -+ store.elements = calloc(argc, sizeof(struct gss_key_value_element_struct)); -+ if (!store.elements) -+ errout("OOM"); -+ store.count = 0; -+ while (*argv != NULL) { -+ if (*(argv + 1) == NULL) - usage(); -- -- for (i = 3, e = 0; i < argc; i += 2, e++) { -- store.elements[e].key = argv[i]; -- store.elements[e].value = argv[i + 1]; -- continue; -- } -+ store.elements[store.count].key = *argv; -+ store.elements[store.count].value = *(argv + 1); -+ store.count++; -+ argv += 2; - } - -- /* First acquire default creds and try to store them in the cred store. */ -- -- major = gss_acquire_cred(&minor, GSS_C_NO_NAME, 0, GSS_C_NO_OID_SET, -- GSS_C_INITIATE, &cred, NULL, NULL); -- check_gsserr("gss_acquire_cred", major, minor); -+ if (store_creds) { -+ /* Acquire default creds and try to store them in the cred store. */ -+ major = gss_acquire_cred(&minor, GSS_C_NO_NAME, 0, GSS_C_NO_OID_SET, -+ GSS_C_INITIATE, &cred, NULL, NULL); -+ check_gsserr("gss_acquire_cred", major, minor); - -- major = gss_store_cred_into(&minor, cred, GSS_C_INITIATE, -- GSS_C_NO_OID, 1, 0, &store, NULL, NULL); -- check_gsserr("gss_store_cred_into", major, minor); -+ major = gss_store_cred_into(&minor, cred, GSS_C_INITIATE, -+ GSS_C_NO_OID, 1, 0, &store, NULL, NULL); -+ check_gsserr("gss_store_cred_into", major, minor); - -- gss_release_cred(&minor, &cred); -- -- /* Then try to acquire creds from store. */ -- -- buf.value = argv[1]; -- buf.length = strlen(argv[1]); -- -- major = gss_import_name(&minor, &buf, -- (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, -- &service); -- check_gsserr("gss_import_name", major, minor); -+ gss_release_cred(&minor, &cred); -+ } - -- major = gss_acquire_cred_from(&minor, service, -- 0, GSS_C_NO_OID_SET, GSS_C_BOTH, -+ /* Try to acquire creds from store. */ -+ major = gss_acquire_cred_from(&minor, name, 0, mechs, cred_usage, - &store, &cred, NULL, NULL); - check_gsserr("gss_acquire_cred_from", major, minor); - -- fprintf(stdout, "Cred Store Success\n"); -- -- gss_release_name(&minor, &service); -+ gss_release_name(&minor, &name); - gss_release_cred(&minor, &cred); - free(store.elements); - return 0; diff --git a/SOURCES/krb5-1.11.3-client-loop.patch b/SOURCES/krb5-1.11.3-client-loop.patch deleted file mode 100644 index f9b7c13..0000000 --- a/SOURCES/krb5-1.11.3-client-loop.patch +++ /dev/null @@ -1,34 +0,0 @@ -Tweaked for 1.11.3. - -commit 53e5c850e05f011e9e7f25c2032aec51d8b352a9 -Author: Viktor Dukhovni -Date: Tue Jun 25 12:27:42 2013 -0400 - - Fix spin loop reading from KDC TCP socket - - In the k5_sendto code for reading from a TCP socket, detect - end-of-stream when reading the length. Otherwise we can get stuck in - an infinite loop of poll() and read(). - - [ghudson@mit.edu: commit message] - - ticket: 7508 - target_version: 1.11.4 - tags: pullup - -diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c -index 3e4ec7e..3c31d9f 100644 ---- a/src/lib/krb5/os/sendto_kdc.c -+++ b/src/lib/krb5/os/sendto_kdc.c -@@ -853,9 +853,9 @@ service_tcp_fd(krb5_context context, struct conn_state *conn, - nread = SOCKET_READ(conn->fd, - conn->x.in.bufsizebytes + conn->x.in.bufsizebytes_read, - 4 - conn->x.in.bufsizebytes_read); -- if (nread < 0) { -+ if (nread <= 0) { -+ e = nread ? SOCKET_ERRNO : ECONNRESET; - TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(context, conn, e); -- e = SOCKET_ERRNO; - goto kill_conn; - } - conn->x.in.bufsizebytes_read += nread; diff --git a/SOURCES/krb5-1.11.3-copy_context.patch b/SOURCES/krb5-1.11.3-copy_context.patch deleted file mode 100644 index fbd35c4..0000000 --- a/SOURCES/krb5-1.11.3-copy_context.patch +++ /dev/null @@ -1,302 +0,0 @@ -Adjusted for 1.11.3, which still had vtbl, locate_fptrs, and (vestigial) -profile_in_memory fields, but didn't have localauth_handles, -hostrealm_handles, or dns_canonicalize_hostname, and drop the hunk that -touched .gitignore. - -commit c452644d91d57d8b05ef396a029e34d0c7a48920 -Author: Greg Hudson -Date: Wed Dec 18 15:03:03 2013 -0500 - - Fix krb5_copy_context - - krb5_copy_context has been broken since 1.8 (it broke in r22456) - because k5_copy_etypes crashes on null enctype lists. Subsequent - additions to the context structure were not reflected in - krb5_copy_context, creating double-free bugs. Make k5_copy_etypes - handle null input and account for all new fields in krb5_copy_context. - Reported by Arran Cudbard-Bell. - - ticket: 7807 (new) - target_version: 1.12.1 - tags: pullup - -diff --git a/src/lib/krb5/krb/copy_ctx.c b/src/lib/krb5/krb/copy_ctx.c -index 0bc92f8..4237023 100644 ---- a/src/lib/krb5/krb/copy_ctx.c -+++ b/src/lib/krb5/krb/copy_ctx.c -@@ -77,13 +77,24 @@ krb5_copy_context(krb5_context ctx, krb5_context *nctx_out) - nctx->ser_ctx_count = 0; - nctx->ser_ctx = NULL; - nctx->prompt_types = NULL; -+ nctx->preauth_context = NULL; -+ nctx->ccselect_handles = NULL; -+ nctx->kdblog_context = NULL; -+ nctx->trace_callback = NULL; -+ nctx->trace_callback_data = NULL; -+ nctx->plugin_base_dir = NULL; - nctx->os_context.default_ccname = NULL; - -+#ifdef KRB5_DNS_LOOKUP -+ nctx->profile_in_memory = 0; -+#endif /* KRB5_DNS_LOOKUP */ -+ - memset(&nctx->libkrb5_plugins, 0, sizeof(nctx->libkrb5_plugins)); - nctx->vtbl = NULL; - nctx->locate_fptrs = NULL; - - memset(&nctx->err, 0, sizeof(nctx->err)); -+ memset(&nctx->plugins, 0, sizeof(nctx->plugins)); - - ret = k5_copy_etypes(ctx->in_tkt_etypes, &nctx->in_tkt_etypes); - if (ret) -@@ -101,6 +109,11 @@ krb5_copy_context(krb5_context ctx, krb5_context *nctx_out) - ret = krb5_get_profile(ctx, &nctx->profile); - if (ret) - goto errout; -+ nctx->plugin_base_dir = strdup(ctx->plugin_base_dir); -+ if (nctx->plugin_base_dir == NULL) { -+ ret = ENOMEM; -+ goto errout; -+ } - - errout: - if (ret) { -diff --git a/src/lib/krb5/krb/etype_list.c b/src/lib/krb5/krb/etype_list.c -index 9efe2e0..71f664f 100644 ---- a/src/lib/krb5/krb/etype_list.c -+++ b/src/lib/krb5/krb/etype_list.c -@@ -49,6 +49,8 @@ k5_copy_etypes(const krb5_enctype *old_list, krb5_enctype **new_list) - krb5_enctype *list; - - *new_list = NULL; -+ if (old_list == NULL) -+ return 0; - count = k5_count_etypes(old_list); - list = malloc(sizeof(krb5_enctype) * (count + 1)); - if (list == NULL) - -commit b78c3c8c5025aec870d20472f80d4a652062f921 -Author: Greg Hudson -Date: Wed Dec 18 13:08:25 2013 -0500 - - Add a test program for krb5_copy_context - - This test program isn't completely proof against the kind of mistakes - we've made with krb5_copy_context in the past, but it at least - exercises krb5_copy_context and can detect some kinds of bugs. - - ticket: 7807 - -diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in -index 7d1682d..3b58219 100644 ---- a/src/lib/krb5/krb/Makefile.in -+++ b/src/lib/krb5/krb/Makefile.in -@@ -349,6 +349,7 @@ SRCS= $(srcdir)/addr_comp.c \ - $(srcdir)/t_expire_warn.c \ - $(srcdir)/t_authdata.c \ - $(srcdir)/t_cc_config.c \ -+ $(srcdir)/t_copy_context.c \ - $(srcdir)/t_in_ccache.c \ - $(srcdir)/t_response_items.c \ - $(srcdir)/t_vfy_increds.c -@@ -429,11 +430,14 @@ t_in_ccache: t_in_ccache.o $(KRB5_BASE_DEPLIBS) - t_cc_config: t_cc_config.o $(KRB5_BASE_DEPLIBS) - $(CC_LINK) -o $@ t_cc_config.o $(KRB5_BASE_LIBS) - -+t_copy_context: t_copy_context.o $(KRB5_BASE_DEPLIBS) -+ $(CC_LINK) -o $@ t_copy_context.o $(KRB5_BASE_LIBS) -+ - t_response_items: t_response_items.o response_items.o $(KRB5_BASE_DEPLIBS) - $(CC_LINK) -o $@ t_response_items.o response_items.o $(KRB5_BASE_LIBS) - - TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand t_authdata t_pac \ -- t_in_ccache t_cc_config \ -+ t_in_ccache t_cc_config t_copy_context \ - t_princ t_etypes t_vfy_increds t_response_items - - check-unix:: $(TEST_PROGS) -@@ -473,6 +477,8 @@ check-unix:: $(TEST_PROGS) - $(RUN_SETUP) $(VALGRIND) ./t_princ - $(RUN_SETUP) $(VALGRIND) ./t_etypes - $(RUN_SETUP) $(VALGRIND) ./t_response_items -+ KRB5_CONFIG=$(srcdir)/t_krb5.conf ; export KRB5_CONFIG ;\ -+ $(RUN_SETUP) $(VALGRIND) ./t_copy_context - - check-pytests:: t_expire_warn t_vfy_increds - $(RUNPYTEST) $(srcdir)/t_expire_warn.py $(PYTESTFLAGS) -@@ -491,6 +497,7 @@ clean:: - $(OUTPRE)t_pac$(EXEEXT) $(OUTPRE)t_pac.$(OBJEXT) \ - $(OUTPRE)t_princ$(EXEEXT) $(OUTPRE)t_princ.$(OBJEXT) \ - $(OUTPRE)t_authdata$(EXEEXT) $(OUTPRE)t_authdata.$(OBJEXT) \ -+ $(OUTPRE)t_copy_context(EXEEXT) $(OUTPRE)t_copy_context.$(OBJEXT) \ - $(OUTPRE)t_vfy_increds$(EXEEXT) $(OUTPRE)t_vfy_increds.$(OBJEXT) \ - $(OUTPRE)t_response_items$(EXEEXT) $(OUTPRE)t_response_items.$(OBJEXT) - -diff --git a/src/lib/krb5/krb/t_copy_context.c b/src/lib/krb5/krb/t_copy_context.c -new file mode 100644 -index 0000000..522fa0c ---- /dev/null -+++ b/src/lib/krb5/krb/t_copy_context.c -@@ -0,0 +1,162 @@ -+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -+/* lib/krb5/krb/t_copy_context.C - Test program for krb5_copy_context */ -+/* -+ * 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 -+ -+static void -+trace(krb5_context ctx, const krb5_trace_info *info, void *data) -+{ -+} -+ -+static void -+check(int cond) -+{ -+ if (!cond) -+ abort(); -+} -+ -+static void -+compare_string(const char *str1, const char *str2) -+{ -+ check((str1 == NULL) == (str2 == NULL)); -+ if (str1 != NULL) -+ check(strcmp(str1, str2) == 0); -+} -+ -+static void -+compare_etypes(krb5_enctype *list1, krb5_enctype *list2) -+{ -+ check((list1 == NULL) == (list2 == NULL)); -+ if (list1 == NULL) -+ return; -+ while (*list1 != ENCTYPE_NULL && *list1 == *list2) -+ list1++, list2++; -+ check(*list1 == *list2); -+} -+ -+/* Check that the context c is a valid copy of the reference context r. */ -+static void -+check_context(krb5_context c, krb5_context r) -+{ -+ int i; -+ -+ /* Check fields which should have been propagated from r. */ -+ compare_etypes(c->in_tkt_etypes, r->in_tkt_etypes); -+ compare_etypes(c->tgs_etypes, r->tgs_etypes); -+ check(c->os_context.time_offset == r->os_context.time_offset); -+ check(c->os_context.usec_offset == r->os_context.usec_offset); -+ check(c->os_context.os_flags == r->os_context.os_flags); -+ compare_string(c->os_context.default_ccname, r->os_context.default_ccname); -+ check(c->clockskew == r->clockskew); -+ check(c->kdc_req_sumtype == r->kdc_req_sumtype); -+ check(c->default_ap_req_sumtype == r->default_ap_req_sumtype); -+ check(c->default_safe_sumtype == r->default_safe_sumtype); -+ check(c->kdc_default_options == r->kdc_default_options); -+ check(c->library_options == r->library_options); -+ check(c->profile_secure == r->profile_secure); -+ check(c->fcc_default_format == r->fcc_default_format); -+ check(c->udp_pref_limit == r->udp_pref_limit); -+ check(c->use_conf_ktypes == r->use_conf_ktypes); -+ check(c->allow_weak_crypto == r->allow_weak_crypto); -+ check(c->ignore_acceptor_hostname == r->ignore_acceptor_hostname); -+ compare_string(c->plugin_base_dir, r->plugin_base_dir); -+ -+ /* Check fields which don't propagate. */ -+ check(c->dal_handle == NULL); -+ check(c->ser_ctx_count == 0); -+ check(c->ser_ctx == NULL); -+ check(c->prompt_types == NULL); -+ check(c->libkrb5_plugins.files == NULL); -+ check(c->preauth_context == NULL); -+ check(c->ccselect_handles == NULL); -+ check(c->err.code == 0); -+ check(c->err.msg == NULL); -+ check(c->kdblog_context == NULL); -+ check(c->trace_callback == NULL); -+ check(c->trace_callback_data == NULL); -+ for (i = 0; i < PLUGIN_NUM_INTERFACES; i++) { -+ check(c->plugins[i].modules == NULL); -+ check(!c->plugins[i].configured); -+ } -+} -+ -+int -+main(int argc, char **argv) -+{ -+ krb5_context ctx, ctx2; -+ krb5_plugin_initvt_fn *mods; -+ const krb5_enctype etypes1[] = { ENCTYPE_DES3_CBC_SHA1, 0 }; -+ const krb5_enctype etypes2[] = { ENCTYPE_AES128_CTS_HMAC_SHA1_96, -+ ENCTYPE_AES256_CTS_HMAC_SHA1_96, 0 }; -+ krb5_prompt_type ptypes[] = { KRB5_PROMPT_TYPE_PASSWORD }; -+ -+ /* Copy a default context and verify the result. */ -+ check(krb5_init_context(&ctx) == 0); -+ check(krb5_copy_context(ctx, &ctx2) == 0); -+ check_context(ctx2, ctx); -+ krb5_free_context(ctx2); -+ -+ /* Set non-default values for all of the propagated fields in ctx. */ -+ ctx->allow_weak_crypto = TRUE; -+ check(krb5_set_default_in_tkt_ktypes(ctx, etypes1) == 0); -+ check(krb5_set_default_tgs_enctypes(ctx, etypes2) == 0); -+ check(krb5_set_debugging_time(ctx, 1234, 5678) == 0); -+ check(krb5_cc_set_default_name(ctx, "defccname") == 0); -+ check(krb5_set_default_realm(ctx, "defrealm") == 0); -+ ctx->clockskew = 18; -+ ctx->kdc_req_sumtype = CKSUMTYPE_NIST_SHA; -+ ctx->default_ap_req_sumtype = CKSUMTYPE_HMAC_SHA1_96_AES128; -+ ctx->default_safe_sumtype = CKSUMTYPE_HMAC_SHA1_96_AES256; -+ ctx->kdc_default_options = KDC_OPT_FORWARDABLE; -+ ctx->library_options = 0; -+ ctx->profile_secure = TRUE; -+ ctx->udp_pref_limit = 2345; -+ ctx->use_conf_ktypes = TRUE; -+ ctx->ignore_acceptor_hostname = TRUE; -+ free(ctx->plugin_base_dir); -+ check((ctx->plugin_base_dir = strdup("/a/b/c/d")) != NULL); -+ -+ /* Also set some of the non-propagated fields. */ -+ ctx->prompt_types = ptypes; -+ check(k5_plugin_load_all(ctx, PLUGIN_INTERFACE_PWQUAL, &mods) == 0); -+ k5_plugin_free_modules(ctx, mods); -+ krb5_set_error_message(ctx, ENOMEM, "nooooooooo"); -+ krb5_set_trace_callback(ctx, trace, ctx); -+ -+ /* Copy the intentionally messy context and verify the result. */ -+ check(krb5_copy_context(ctx, &ctx2) == 0); -+ check_context(ctx2, ctx); -+ krb5_free_context(ctx2); -+ -+ krb5_free_context(ctx); -+ return 0; -+} diff --git a/SOURCES/krb5-1.11.3-gss-ccache-import.patch b/SOURCES/krb5-1.11.3-gss-ccache-import.patch deleted file mode 100644 index 2bfd927..0000000 --- a/SOURCES/krb5-1.11.3-gss-ccache-import.patch +++ /dev/null @@ -1,131 +0,0 @@ -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-nodelete-pkinit.patch b/SOURCES/krb5-1.11.3-nodelete-pkinit.patch deleted file mode 100644 index a5892d6..0000000 --- a/SOURCES/krb5-1.11.3-nodelete-pkinit.patch +++ /dev/null @@ -1,14 +0,0 @@ -Cause the pkinit plugin to be kept in memory, so that it doesn't -reinitialize libcrypto every time it's loaded and subsequently lose -track of the memory that doing so allocates, every time the plugin is -unloaded. ---- krb5-1.11.3/src/plugins/preauth/pkinit/Makefile.in -+++ krb5-1.11.3/src/plugins/preauth/pkinit/Makefile.in -@@ -6,6 +6,7 @@ PROG_LIBPATH=-L$(TOPLIBD) - PROG_RPATH=$(KRB5_LIBDIR) - MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR) - DEFS=@DEFS@ -+LDFLAGS += -Wl,-z,nodelete - - LOCALINCLUDES = -I../../../include/krb5 -I. $(PKINIT_CRYPTO_IMPL_CFLAGS) - RUN_SETUP = @KRB5_RUN_ENV@ diff --git a/SOURCES/krb5-1.11.3-otp2.patch b/SOURCES/krb5-1.11.3-otp2.patch deleted file mode 100644 index da8d79a..0000000 --- a/SOURCES/krb5-1.11.3-otp2.patch +++ /dev/null @@ -1,699 +0,0 @@ -A couple of other changes that were made for OTP support when it was merged, -extracted and applied after the OTP backport: -* Read the secret that we share with the RADIUS server from the file named by - the "secret" configuration setting. -* Log an error if we can't parse the OTP configuration string for a given - principal entry. -* Pass back the error code if attempting to read the OTP configuration string - for an entry produces one. -* When setting the remote address on the socket we're using to talk to the - RADIUS server, wait for the non-blocking connect() to complete by waiting - for it to become writable instead of readable. ---- krb5-1.11.3/src/include/k5-int.h -+++ krb5-1.11.3/src/include/k5-int.h -@@ -2612,6 +2612,17 @@ k5memdup(const void *in, size_t len, krb - return ptr; - } - -+/* 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) -+ 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, ---- krb5-1.11.3/src/plugins/preauth/otp/otp_state.c -+++ krb5-1.11.3/src/plugins/preauth/otp/otp_state.c -@@ -43,6 +43,7 @@ - #define DEFAULT_SOCKET_FMT KDC_DIR "/%s.socket" - #define DEFAULT_TIMEOUT 5 - #define DEFAULT_RETRIES 3 -+#define MAX_SECRET_LEN 1024 - - typedef struct token_type_st { - char *name; -@@ -76,6 +77,52 @@ struct otp_state_st { - - static void request_send(request *req); - -+static krb5_error_code -+read_secret_file(const char *secret_file, char **secret) -+{ -+ char buf[MAX_SECRET_LEN]; -+ krb5_error_code retval; -+ char *filename; -+ FILE *file; -+ int i, j; -+ -+ *secret = NULL; -+ -+ retval = k5_path_join(KDC_DIR, secret_file, &filename); -+ if (retval != 0) { -+ com_err("otp", retval, "Unable to resolve secret file '%s'", filename); -+ return retval; -+ } -+ -+ file = fopen(filename, "r"); -+ if (file == NULL) { -+ retval = errno; -+ com_err("otp", retval, "Unable to open secret file '%s'", filename); -+ return retval; -+ } -+ -+ if (fgets(buf, sizeof(buf), file) == NULL) -+ retval = EIO; -+ fclose(file); -+ if (retval != 0) { -+ com_err("otp", retval, "Unable to read secret file '%s'", filename); -+ return retval; -+ } -+ -+ /* Strip whitespace. */ -+ for (i = 0; buf[i] != '\0'; i++) { -+ if (!isspace(buf[i])) -+ break; -+ } -+ for (j = strlen(buf) - i; j > 0; j--) { -+ if (!isspace(buf[j - 1])) -+ break; -+ } -+ -+ *secret = k5memdup0(&buf[i], j - i, &retval); -+ return retval; -+} -+ - /* Free the contents of a single token type. */ - static void - token_type_free(token_type *type) -@@ -125,8 +172,7 @@ 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; -+ char *server = NULL, *name_copy = NULL, *secret = NULL, *pstr = NULL; - int strip_realm, timeout, retries; - - memset(out, 0, sizeof(*out)); -@@ -152,16 +198,27 @@ token_type_decode(profile_t profile, con - } - - /* Get the secret (optional for Unix-domain sockets). */ -- default_secret = (*server == '/') ? "" : NULL; -- retval = profile_get_string(profile, "otp", name, "secret", default_secret, -- &secret); -+ retval = profile_get_string(profile, "otp", name, "secret", NULL, &pstr); - if (retval != 0) - goto cleanup; -- if (secret == NULL) { -- com_err("otp", EINVAL, "Secret not specified in token type '%s'", -- name); -- retval = EINVAL; -- goto cleanup; -+ if (pstr != NULL) { -+ retval = read_secret_file(pstr, &secret); -+ profile_release_string(pstr); -+ if (retval != 0) -+ goto cleanup; -+ } else { -+ if (server[0] != '/') { -+ com_err("otp", EINVAL, "Secret missing (token type '%s')", name); -+ retval = EINVAL; -+ goto cleanup; -+ } -+ -+ /* Use the default empty secret for UNIX domain stream sockets. */ -+ secret = strdup(""); -+ if (secret == NULL) { -+ retval = ENOMEM; -+ goto cleanup; -+ } - } - - /* Get the timeout (profile value in seconds, result in milliseconds). */ -@@ -521,6 +578,7 @@ otp_state_verify(otp_state *state, verto - { - krb5_error_code retval; - request *rqst = NULL; -+ char *name; - - if (state->radius == NULL) { - retval = krad_client_new(state->ctx, ctx, &state->radius); -@@ -548,8 +606,14 @@ otp_state_verify(otp_state *state, verto - - retval = tokens_decode(state->ctx, princ, state->types, config, - &rqst->tokens); -- if (retval != 0) -+ if (retval != 0) { -+ if (krb5_unparse_name(state->ctx, princ, &name) == 0) { -+ com_err("otp", retval, -+ "Can't decode otp config string for principal '%s'", name); -+ krb5_free_unparsed_name(state->ctx, name); -+ } - goto error; -+ } - - request_send(rqst); - return; ---- krb5-1.11.3/src/plugins/preauth/otp/main.c -+++ krb5-1.11.3/src/plugins/preauth/otp/main.c -@@ -204,7 +204,9 @@ otp_edata(krb5_context context, krb5_kdc - - /* Determine if otp is enabled for the user. */ - retval = cb->get_string(context, rock, "otp", &config); -- if (retval != 0 || config == NULL) -+ if (retval == 0 && config == NULL) -+ retval = ENOENT; -+ if (retval != 0) - goto out; - cb->free_string(context, rock, config); - -@@ -305,7 +307,7 @@ otp_verify(krb5_context context, krb5_da - - /* Get the principal's OTP configuration string. */ - retval = cb->get_string(context, rock, "otp", &config); -- if (config == NULL) -+ if (retval == 0 && config == NULL) - retval = KRB5_PREAUTH_FAILED; - if (retval != 0) { - free(rs); ---- krb5-1.11.3/src/lib/krad/remote.c -+++ krb5-1.11.3/src/lib/krad/remote.c -@@ -36,9 +36,10 @@ - - #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) -+#define FLAGS_NONE VERTO_EV_FLAG_NONE -+#define FLAGS_READ VERTO_EV_FLAG_IO_READ -+#define FLAGS_WRITE VERTO_EV_FLAG_IO_WRITE -+#define FLAGS_BASE VERTO_EV_FLAG_PERSIST | VERTO_EV_FLAG_IO_ERROR - - TAILQ_HEAD(request_head, request_st); - -@@ -58,6 +59,7 @@ - struct krad_remote_st { - krb5_context kctx; - verto_ctx *vctx; -+ int fd; - verto_ev *io; - char *secret; - struct addrinfo *info; -@@ -69,6 +71,9 @@ - static void - on_io(verto_ctx *ctx, verto_ev *ev); - -+static void -+on_timeout(verto_ctx *ctx, verto_ev *ev); -+ - /* Iterate over the set of outstanding packets. */ - static const krad_packet * - iterator(request **out) -@@ -121,91 +126,131 @@ - } - } - --/* Handle when packets receive no response within their alloted time. */ --static void --on_timeout(verto_ctx *ctx, verto_ev *ev) -+/* Start the timeout timer for the request. */ -+static krb5_error_code -+request_start_timer(request *r, verto_ctx *vctx) - { -- request *req = verto_get_private(ev); -+ verto_del(r->timer); - -- req->timer = NULL; /* Void the timer event. */ -+ r->timer = verto_add_timeout(vctx, VERTO_EV_FLAG_NONE, on_timeout, -+ r->timeout); -+ if (r->timer != NULL) -+ verto_set_private(r->timer, r, NULL); - -- /* 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; -- } -+ return (r->timer == NULL) ? ENOMEM : 0; -+} - -- request_finish(req, ETIMEDOUT, NULL); -+/* Disconnect from the remote host. */ -+static void -+remote_disconnect(krad_remote *rr) -+{ -+ close(rr->fd); -+ verto_del(rr->io); -+ rr->fd = -1; -+ rr->io = NULL; - } - --/* Connect to the remote host. */ -+/* Add the specified flags to the remote. This automatically manages the -+ * lifecyle of the underlying event. Also connects if disconnected. */ - static krb5_error_code --remote_connect(krad_remote *rr) -+remote_add_flags(krad_remote *remote, verto_ev_flag flags) - { -- int i, sock = -1; -- verto_ev *ev; -+ verto_ev_flag curflags = VERTO_EV_FLAG_NONE; -+ int i; - -- sock = socket(rr->info->ai_family, rr->info->ai_socktype, -- rr->info->ai_protocol); -- if (sock < 0) -- return errno; -+ flags &= (FLAGS_READ | FLAGS_WRITE); -+ if (remote == NULL || flags == FLAGS_NONE) -+ return EINVAL; -+ -+ /* If there is no connection, connect. */ -+ if (remote->fd < 0) { -+ verto_del(remote->io); -+ remote->io = NULL; -+ -+ remote->fd = socket(remote->info->ai_family, remote->info->ai_socktype, -+ remote->info->ai_protocol); -+ if (remote->fd < 0) -+ return errno; - -- i = connect(sock, rr->info->ai_addr, rr->info->ai_addrlen); -- if (i < 0) { -- i = errno; -- close(sock); -- return i; -+ i = connect(remote->fd, remote->info->ai_addr, -+ remote->info->ai_addrlen); -+ if (i < 0) { -+ i = errno; -+ remote_disconnect(remote); -+ return i; -+ } - } - -- ev = verto_add_io(rr->vctx, FLAGS_READ, on_io, sock); -- if (ev == NULL) { -- close(sock); -- return ENOMEM; -+ if (remote->io == NULL) { -+ remote->io = verto_add_io(remote->vctx, FLAGS_BASE | flags, -+ on_io, remote->fd); -+ if (remote->io == NULL) -+ return ENOMEM; -+ verto_set_private(remote->io, remote, NULL); - } - -- rr->io = ev; -- verto_set_private(rr->io, rr, NULL); -+ curflags = verto_get_flags(remote->io); -+ if ((curflags & flags) != flags) -+ verto_set_flags(remote->io, FLAGS_BASE | curflags | flags); -+ - return 0; - } - --/* Disconnect and reconnect to the remote host. */ --static krb5_error_code --remote_reconnect(krad_remote *rr, int errnum) -+/* Remove the specified flags to the remote. This automatically manages the -+ * lifecyle of the underlying event. */ -+static void -+remote_del_flags(krad_remote *remote, verto_ev_flag flags) -+{ -+ if (remote == NULL || remote->io == NULL) -+ return; -+ -+ flags = verto_get_flags(remote->io) & (FLAGS_READ | FLAGS_WRITE) & ~flags; -+ if (flags == FLAGS_NONE) { -+ verto_del(remote->io); -+ remote->io = NULL; -+ return; -+ } -+ -+ verto_set_flags(remote->io, FLAGS_BASE | flags); -+} -+ -+/* Close the connection and start the timers of all outstanding requests. */ -+static void -+remote_shutdown(krad_remote *rr) - { - 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; -+ remote_disconnect(rr); - -+ /* Start timers for all unsent packets. */ - 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; -+ if (r->timer == NULL) { -+ retval = request_start_timer(r, rr->vctx); -+ if (retval != 0) -+ request_finish(r, retval, NULL); - } - } -- -- return 0; - } - --/* Close the connection and call the callbacks of all oustanding requests. */ -+/* Handle when packets receive no response within their alloted time. */ - static void --remote_shutdown(krad_remote *rr, int errnum) -+on_timeout(verto_ctx *ctx, verto_ev *ev) - { -- verto_del(rr->io); -- rr->io = NULL; -- while (!TAILQ_EMPTY(&rr->list)) -- request_finish(TAILQ_FIRST(&rr->list), errnum, NULL); -+ request *req = verto_get_private(ev); -+ krb5_error_code retval = ETIMEDOUT; -+ -+ req->timer = NULL; /* Void the timer event. */ -+ -+ /* If we have more retries to perform, resend the packet. */ -+ if (req->retries-- > 1) { -+ req->sent = 0; -+ retval = remote_add_flags(req->rr, FLAGS_WRITE); -+ if (retval == 0) -+ return; -+ } -+ -+ request_finish(req, retval, NULL); - } - - /* Write data to the socket. */ -@@ -213,8 +258,8 @@ - on_io_write(krad_remote *rr) - { - const krb5_data *tmp; -+ ssize_t written; - request *r; -- int i; - - TAILQ_FOREACH(r, &rr->list, list) { - tmp = krad_packet_encode(r->request); -@@ -224,45 +269,38 @@ - 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) { -+ written = sendto(verto_get_fd(rr->io), tmp->data + r->sent, -+ tmp->length - r->sent, 0, NULL, 0); -+ if (written < 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); -+ /* This error can't be worked around. */ -+ remote_shutdown(rr); - 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. */ -+ r->sent += written; - 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) -+ if (request_start_timer(r, rr->vctx) != 0) { - request_finish(r, ENOMEM, NULL); -- else -- verto_set_private(r->timer, r, NULL); -+ return; -+ } -+ -+ if (remote_add_flags(rr, FLAGS_READ) != 0) { -+ remote_shutdown(rr); -+ return; -+ } - } - - return; - } - -- verto_set_flags(rr->io, FLAGS_READ); -+ remote_del_flags(rr, FLAGS_WRITE); -+ return; - } - - /* Read data from the socket. */ -@@ -280,9 +318,9 @@ - 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); -+ /* If we received a malformed packet on a stream socket, -+ * assume the socket to be unrecoverable. */ -+ remote_shutdown(rr); - return; - } - } -@@ -295,26 +333,11 @@ - 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); -+ /* The socket is unrecoverable. */ -+ remote_shutdown(rr); - return; -+ } else if (i == 0) { -+ remote_del_flags(rr, FLAGS_READ); - } - - /* If we have a partial read or just the header, try again. */ -@@ -374,6 +397,7 @@ - tmp->vctx = vctx; - tmp->buffer = make_data(tmp->buffer_, 0); - TAILQ_INIT(&tmp->list); -+ tmp->fd = -1; - - tmp->secret = strdup(secret); - if (tmp->secret == NULL) -@@ -389,10 +413,6 @@ - tmp->info->ai_next = NULL; - tmp->info->ai_canonname = NULL; - -- retval = remote_connect(tmp); -- if (retval != 0) -- goto error; -- - *rr = tmp; - return 0; - -@@ -414,7 +434,7 @@ - if (rr->info != NULL) - free(rr->info->ai_addr); - free(rr->info); -- verto_del(rr->io); -+ remote_disconnect(rr); - free(rr); - } - -@@ -440,21 +460,14 @@ - } - } - -- 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); -+ retval = remote_add_flags(rr, FLAGS_WRITE); -+ if (retval != 0) -+ goto error; - - TAILQ_INSERT_TAIL(&rr->list, r, list); - if (pkt != NULL) ---- krb5-1.11.3/src/lib/krad/t_attr.c -+++ krb5-1.11.3/src/lib/krad/t_attr.c -@@ -29,7 +29,7 @@ - - #include "t_test.h" - --const static char encoded[] = { -+const static unsigned char encoded[] = { - 0xba, 0xfc, 0xed, 0x50, 0xe1, 0xeb, 0xa6, 0xc3, - 0xc1, 0x75, 0x20, 0xe9, 0x10, 0xce, 0xc2, 0xcb - }; ---- krb5-1.11.3/src/lib/krad/t_attrset.c -+++ krb5-1.11.3/src/lib/krad/t_attrset.c -@@ -34,7 +34,7 @@ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - --const static char encpass[] = { -+const static unsigned char encpass[] = { - 0x58, 0x8d, 0xff, 0xda, 0x37, 0xf9, 0xe4, 0xca, - 0x19, 0xae, 0x49, 0xb7, 0x16, 0x6d, 0x58, 0x27 - }; ---- krb5-1.11.3/src/lib/krad/t_daemon.h -+++ krb5-1.11.3/src/lib/krad/t_daemon.h -@@ -51,8 +51,8 @@ - static krb5_boolean - daemon_start(int argc, const char **argv) - { -- sigset_t set; -- int sig; -+ int fds[2]; -+ char buf[1]; - - if (argc != 3 || argv == NULL) - return FALSE; -@@ -60,30 +60,23 @@ - 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) -+ if (pipe(fds) != 0) - return FALSE; - -+ /* Start the child process with the write end of the pipe as stdout. */ - daemon_pid = fork(); - if (daemon_pid == 0) { -- close(STDOUT_FILENO); -- open("/dev/null", O_WRONLY); -+ dup2(fds[1], STDOUT_FILENO); -+ close(fds[0]); -+ close(fds[1]); - exit(execlp(argv[1], argv[1], argv[2], NULL)); - } -+ close(fds[1]); - -- if (sigwait(&set, &sig) != 0 || sig == SIGCHLD) { -- daemon_stop(); -- daemon_pid = 0; -+ /* The child will write a sentinel character when it is listening. */ -+ if (read(fds[0], buf, 1) != 1 || *buf != '~') - return FALSE; -- } -+ close(fds[0]); - - atexit(daemon_stop); - return TRUE; ---- krb5-1.11.3/src/lib/krad/t_daemon.py -+++ krb5-1.11.3/src/lib/krad/t_daemon.py -@@ -33,7 +33,7 @@ - try: - from pyrad import dictionary, packet, server - except ImportError: -- sys.stdout.write("pyrad not found!\n") -+ sys.stderr.write("pyrad not found!\n") - sys.exit(0) - - # We could use a dictionary file, but since we need -@@ -49,28 +49,25 @@ - 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) -+ -+# Write a sentinel character to let the parent process know we're listening. -+sys.stdout.write("~") -+sys.stdout.flush() -+ - srv.Run() diff --git a/SOURCES/krb5-1.11.3-prompter1.patch b/SOURCES/krb5-1.11.3-prompter1.patch deleted file mode 100644 index e8d393d..0000000 --- a/SOURCES/krb5-1.11.3-prompter1.patch +++ /dev/null @@ -1,91 +0,0 @@ -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 deleted file mode 100644 index 015284d..0000000 --- a/SOURCES/krb5-1.11.3-prompter2.patch +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index 0fe0b28..0000000 --- a/SOURCES/krb5-1.11.3-skew3.patch +++ /dev/null @@ -1,28 +0,0 @@ -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.11.3.tar.gz.asc b/SOURCES/krb5-1.11.3.tar.gz.asc deleted file mode 100644 index 689d9f5..0000000 --- a/SOURCES/krb5-1.11.3.tar.gz.asc +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v1.4.13 (SunOS) - -iQEVAwUAUa0O8hUCTNN0nXiJAQIQwQf+JYdvidDVlCtx9a4kBmV5amjXB/S28i75 -6fduVwB7H0bWGFcmwzrSPqTZdbtPf9WnJMtaeNzwxcXVcF51sZIR1lR9nGKIpF7c -GTr9GDNkxeTnH3ERcmVOGAjPeJi6psbjesFRv8+ctPr6JqFpg0WYy7Ah5AgJZHBB -t6UkXUM9POFqsjeQA+I99sroTKbC+uptJv83RmJN12+Ug5sVZHryzC63iXq8OuIX -9cie0yI+V45LnUJ8Qq5uwZ3VKZTv2nVc/FUq68NQmz24n1JiHm6exXKdzIsnccLp -83SFJB7uOQfNPptz0Eumim+etparnL0miwuTl2uCwqJi4Vc93V4SOw== -=+Cg2 ------END PGP SIGNATURE----- diff --git a/SOURCES/krb5-1.11.5-move-otp-sockets.patch b/SOURCES/krb5-1.11.5-move-otp-sockets.patch deleted file mode 100644 index 14a2355..0000000 --- a/SOURCES/krb5-1.11.5-move-otp-sockets.patch +++ /dev/null @@ -1,180 +0,0 @@ -Adjusted to apply after the local doublelog patch, and to avoid adding -changes to otp.rst, which wasn't added by the original backports. - -commit 1e4bdcfed2c7bda94d5c135cc32a5993ca032501 -Author: Nathaniel McCallum -Date: Wed Feb 5 10:59:46 2014 -0500 - - Move OTP sockets to KDC_RUN_DIR - - Some system configurations expect Unix-domain sockets to live under - /run or /var/run, and not other parts of /var where persistent - application state lives. Define a new directory KDC_RUN_DIR using - $runstatedir (new in autoconf 2.70, so fall back to $localstatedir/run - if it's not set) and use that for the default socket path. - - [ghudson@mit.edu: commit message, otp.rst formatting fix] - - ticket: 7859 (new) - -diff --git a/doc/conf.py b/doc/conf.py -index f015fc8..bc8b2bd 100644 ---- a/doc/conf.py -+++ b/doc/conf.py -@@ -231,6 +231,7 @@ if 'mansubs' in tags: - sbindir = '``@SBINDIR@``' - libdir = '``@LIBDIR@``' - localstatedir = '``@LOCALSTATEDIR@``' -+ runstatedir = '``@RUNSTATEDIR@``' - sysconfdir = '``@SYSCONFDIR@``' - ccache = '``@CCNAME@``' - keytab = '``@KTNAME@``' -@@ -243,6 +244,7 @@ else: - sbindir = ':ref:`SBINDIR `' - libdir = ':ref:`LIBDIR `' - localstatedir = ':ref:`LOCALSTATEDIR `' -+ runstatedir = ':ref:`RUNSTATEDIR `' - sysconfdir = ':ref:`SYSCONFDIR `' - ccache = ':ref:`DEFCCNAME `' - keytab = ':ref:`DEFKTNAME `' -@@ -262,6 +264,7 @@ else: - rst_epilog += '.. |sbindir| replace:: %s\n' % sbindir - rst_epilog += '.. |libdir| replace:: %s\n' % libdir - rst_epilog += '.. |kdcdir| replace:: %s\\ ``/krb5kdc``\n' % localstatedir -+ rst_epilog += '.. |kdcrundir| replace:: %s\\ ``/krb5kdc``\n' % runstatedir - rst_epilog += '.. |sysconfdir| replace:: %s\n' % sysconfdir - rst_epilog += '.. |ccache| replace:: %s\n' % ccache - rst_epilog += '.. |keytab| replace:: %s\n' % keytab -diff --git a/doc/mitK5defaults.rst b/doc/mitK5defaults.rst -index 89b8f4c..838dabb 100644 ---- a/doc/mitK5defaults.rst -+++ b/doc/mitK5defaults.rst -@@ -17,6 +17,7 @@ KDC config file :ref:`kdc.conf(5)` |kdcdir|\ ``/kdc.conf`` **KRB - KDC database path (DB2) |kdcdir|\ ``/principal`` - Master key :ref:`stash_definition` |kdcdir|\ ``/.k5.``\ *realm* - Admin server ACL file :ref:`kadm5.acl(5)` |kdcdir|\ ``/kadm5.acl`` -+OTP socket directory |kdcrundir| - Plugin base directory |libdir|\ ``/krb5/plugins`` - :ref:`rcache_definition` directory ``/var/tmp`` **KRB5RCACHEDIR** - Master key default enctype |defmkey| -@@ -64,6 +65,7 @@ Description Symbolic name Custom build path Typical - User programs BINDIR ``/usr/local/bin`` ``/usr/bin`` - Libraries and plugins LIBDIR ``/usr/local/lib`` ``/usr/lib`` - Parent of KDC state dir LOCALSTATEDIR ``/usr/local/var`` ``/var`` -+Parent of KDC runtime dir RUNSTATEDIR ``/usr/local/var/run`` ``/run`` - Administrative programs SBINDIR ``/usr/local/sbin`` ``/usr/sbin`` - Alternate krb5.conf dir SYSCONFDIR ``/usr/local/etc`` ``/etc`` - Default ccache name DEFCCNAME ``FILE:/tmp/krb5cc_%{uid}`` ``FILE:/tmp/krb5cc_%{uid}`` -diff --git a/src/Makefile.in b/src/Makefile.in -index a8bc990..1725093 100644 ---- a/src/Makefile.in -+++ b/src/Makefile.in -@@ -64,6 +64,7 @@ INSTALLMKDIRS = $(KRB5ROOT) $(KRB5MANROOT) $(KRB5OTHERMKDIRS) \ - $(KRB5_AD_MODULE_DIR) \ - $(KRB5_LIBKRB5_MODULE_DIR) \ - @localstatedir@ @localstatedir@/krb5kdc \ -+ @runstatedir@ @runstatedir@/krb5kdc \ - $(KRB5_INCSUBDIRS) $(datadir) $(EXAMPLEDIR) - - install-strip: -diff --git a/src/configure.in b/src/configure.in -index 2145d54..c2eaf78 100644 ---- a/src/configure.in -+++ b/src/configure.in -@@ -1,5 +1,11 @@ - K5_AC_INIT([aclocal.m4]) - -+# If $runstatedir isn't set by autoconf (<2.70), set it manually. -+if test x"$runstatedir" == x; then -+ runstatedir=$localstatedir/run -+fi -+AC_SUBST(runstatedir) -+ - CONFIG_RULES - KRB5_VERSION=K5_VERSION - AC_SUBST(KRB5_VERSION) -diff --git a/src/doc/Makefile.in b/src/doc/Makefile.in -index a6bb7c5..b07e16a 100644 ---- a/src/doc/Makefile.in -+++ b/src/doc/Makefile.in -@@ -7,6 +7,7 @@ DOXYGEN=doxygen - - docsrc=$(top_srcdir)/../doc - localstatedir=@localstatedir@ -+runstatedir=@runstatedir@ - sysconfdir=@sysconfdir@ - DEFCCNAME=@DEFCCNAME@ - DEFKTNAME=@DEFKTNAME@ -@@ -113,6 +114,7 @@ paths.py: - echo 'sbindir = "``$(SERVER_BINDIR)``"' >> $@ - echo 'libdir = "``$(KRB5_LIBDIR)``"' >> $@ - echo 'localstatedir = "``$(localstatedir)``"' >> $@ -+ echo 'runstatedir = "``$(runstatedir)``"' >> $@ - echo 'sysconfdir = "``$(sysconfdir)``"' >> $@ - echo 'ccache = "``$(DEFCCNAME)``"' >> $@ - echo 'keytab = "``$(DEFKTNAME)``"' >> $@ -diff --git a/src/include/Makefile.in b/src/include/Makefile.in -index e13042a..f83ff4e 100644 ---- a/src/include/Makefile.in -+++ b/src/include/Makefile.in -@@ -53,6 +53,7 @@ autoconf.stamp: $(srcdir)/autoconf.h.in $(BUILDTOP)/config.status - - SYSCONFDIR = @sysconfdir@ - LOCALSTATEDIR = @localstatedir@ -+RUNSTATEDIR = @runstatedir@ - BINDIR = @bindir@ - SBINDIR = @sbindir@ - LIBDIR = @libdir@ -@@ -66,6 +67,7 @@ PROCESS_REPLACE = -e "s+@KRB5RCTMPDIR+$(KRB5RCTMPDIR)+" \ - -e "s+@MODULEDIR+$(MODULE_DIR)+" \ - -e "s+@GSSMODULEDIR+$(GSS_MODULE_DIR)+" \ - -e 's+@LOCALSTATEDIR+$(LOCALSTATEDIR)+' \ -+ -e 's+@RUNSTATEDIR+$(RUNSTATEDIR)+' \ - -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"+' \ -diff --git a/src/include/osconf.hin b/src/include/osconf.hin -index 90ab86d..871503a 100644 ---- a/src/include/osconf.hin -+++ b/src/include/osconf.hin -@@ -59,6 +59,7 @@ - #define PLUGIN_EXT "@DYNOBJEXT" - - #define KDC_DIR "@LOCALSTATEDIR/krb5kdc" -+#define KDC_RUN_DIR "@RUNSTATEDIR/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" -diff --git a/src/man/Makefile.in b/src/man/Makefile.in -index 4dd2448..2b9c892 100644 ---- a/src/man/Makefile.in -+++ b/src/man/Makefile.in -@@ -5,6 +5,7 @@ SPHINX_BUILD=sphinx-build - GROFF=@GROFF@ - GROFF_MAN=$(GROFF) -mtty-char -Tascii -mandoc -c - localstatedir=@localstatedir@ -+runstatedir=@runstatedir@ - sysconfdir=@sysconfdir@ - DEFCCNAME=@DEFCCNAME@ - DEFKTNAME=@DEFKTNAME@ -@@ -44,6 +45,7 @@ $(docsrc)/version.py: $(top_srcdir)/patchlevel.h - -e 's|@SBINDIR@|$(SERVER_BINDIR)|g' \ - -e 's|@LIBDIR@|$(KRB5_LIBDIR)|g' \ - -e 's|@LOCALSTATEDIR@|$(localstatedir)|g' \ -+ -e 's|@RUNSTATEDIR@|$(runstatedir)|g' \ - -e 's|@SYSCONFDIR@|$(sysconfdir)|g' \ - -e 's|@CCNAME@|$(DEFCCNAME)|g' \ - -e 's|@KTNAME@|$(DEFKTNAME)|g' \ -diff --git a/src/plugins/preauth/otp/otp_state.c b/src/plugins/preauth/otp/otp_state.c -index a4d7e3b..4643dff 100644 ---- a/src/plugins/preauth/otp/otp_state.c -+++ b/src/plugins/preauth/otp/otp_state.c -@@ -40,7 +40,7 @@ - #endif - - #define DEFAULT_TYPE_NAME "DEFAULT" --#define DEFAULT_SOCKET_FMT KDC_DIR "/%s.socket" -+#define DEFAULT_SOCKET_FMT KDC_RUN_DIR "/%s.socket" - #define DEFAULT_TIMEOUT 5 - #define DEFAULT_RETRIES 3 - #define MAX_SECRET_LEN 1024 diff --git a/SOURCES/krb5-1.12-api.patch b/SOURCES/krb5-1.12-api.patch new file mode 100644 index 0000000..f5432a3 --- /dev/null +++ b/SOURCES/krb5-1.12-api.patch @@ -0,0 +1,27 @@ +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. + +--- krb5/src/lib/krb5/krb/princ_comp.c ++++ krb5/src/lib/krb5/krb/princ_comp.c +@@ -41,6 +41,10 @@ realm_compare_flags(krb5_context context + const krb5_data *realm1 = &princ1->realm; + const krb5_data *realm2 = &princ2->realm; + ++ if (princ1 == NULL || princ2 == NULL) ++ return FALSE; ++ if (realm1 == NULL || realm2 == NULL) ++ return FALSE; + if (realm1->length != realm2->length) + return FALSE; + if (realm1->length == 0) +@@ -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 (princ1->type == KRB5_NT_ENTERPRISE_PRINCIPAL) { diff --git a/SOURCES/krb5-1.12-buildconf.patch b/SOURCES/krb5-1.12-buildconf.patch new file mode 100644 index 0000000..11b816f --- /dev/null +++ b/SOURCES/krb5-1.12-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 -Wl,--warn-shared-textrel' + # + 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/build-tools/krb5-config.in ++++ krb5/src/build-tools/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.12-kpasswd-skip-address-check.patch b/SOURCES/krb5-1.12-kpasswd-skip-address-check.patch new file mode 100644 index 0000000..9873b93 --- /dev/null +++ b/SOURCES/krb5-1.12-kpasswd-skip-address-check.patch @@ -0,0 +1,55 @@ +commit b562400826409deceb0d52ffbe6570670ee9db55 +Author: Nalin Dahyabhai +Date: Wed Oct 9 15:03:16 2013 -0400 + + Don't check kpasswd reply address + + Don't check the address of the kpasswd server when parsing the reply + we received from it. If the server's address was modified by a proxy + or other network element, the user will be incorrectly warned that the + password change failed when it succeeded. The check is unnecessary as + the kpasswd protocol is not subject to a reflection attack. + + [ghudson@mit.edu: edit commit message] + + ticket: 7886 (new) + +diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c +index 462910f..4d8abd9 100644 +--- a/src/lib/krb5/os/changepw.c ++++ b/src/lib/krb5/os/changepw.c +@@ -214,7 +214,6 @@ change_set_password(krb5_context context, + krb5_data *result_string) + { + krb5_data chpw_rep; +- krb5_address remote_kaddr; + krb5_boolean use_tcp = 0; + GETSOCKNAME_ARG3_TYPE addrlen; + krb5_error_code code = 0; +@@ -272,26 +271,6 @@ change_set_password(krb5_context context, + break; + } + +- if (remote_addr.ss_family == AF_INET) { +- remote_kaddr.addrtype = ADDRTYPE_INET; +- remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr); +- remote_kaddr.contents = +- (krb5_octet *) &ss2sin(&remote_addr)->sin_addr; +- } else if (remote_addr.ss_family == AF_INET6) { +- remote_kaddr.addrtype = ADDRTYPE_INET6; +- remote_kaddr.length = sizeof(ss2sin6(&remote_addr)->sin6_addr); +- remote_kaddr.contents = +- (krb5_octet *) &ss2sin6(&remote_addr)->sin6_addr; +- } else { +- break; +- } +- +- if ((code = krb5_auth_con_setaddrs(callback_ctx.context, +- callback_ctx.auth_context, +- NULL, +- &remote_kaddr))) +- break; +- + code = krb5int_rd_chpw_rep(callback_ctx.context, + callback_ctx.auth_context, + &chpw_rep, &local_result_code, diff --git a/SOURCES/krb5-1.12-ksu-no-ccache.patch b/SOURCES/krb5-1.12-ksu-no-ccache.patch new file mode 100644 index 0000000..67346b4 --- /dev/null +++ b/SOURCES/krb5-1.12-ksu-no-ccache.patch @@ -0,0 +1,36 @@ +commit 26e202d26b47d62fbff4f153fc7f03cc300cc4ab +Author: Nalin Dahyabhai +Date: Mon Sep 8 13:34:05 2014 -0400 + + Fix ksu crash in cases where it obtains the TGT + + In order to allow ksu to use any locally-present service key for + verifying creds, the previous change to ksu switched from using a + retrieved or obtained TGT to fetch creds for the local "host" service, + and then passing those creds to krb5_verify_init_creds(), to passing the + retrieved TGT directly to krb5_verify_init_creds(). It did not take + care to retrieve the TGT from the temporary ccache if it had obtained + them, and in those cases it would attempt to verify NULL creds. + +diff --git a/src/clients/ksu/krb_auth_su.c b/src/clients/ksu/krb_auth_su.c +index dd0a127..bd37c9c 100644 +--- a/src/clients/ksu/krb_auth_su.c ++++ b/src/clients/ksu/krb_auth_su.c +@@ -122,6 +122,17 @@ krb5_boolean krb5_auth_check(context, client_pname, hostname, options, + return FALSE; + } + ++ retval = krb5_cc_retrieve_cred(context, cc, ++ KRB5_TC_MATCH_SRV_NAMEONLY | ++ KRB5_TC_SUPPORTED_KTYPES, ++ &tgtq, &tgt); ++ ++ if (! retval) retval = krb5_check_exp(context, tgt.times); ++ ++ if (retval){ ++ com_err(prog_name, retval, _("while getting initial credentials")); ++ return (FALSE) ; ++ } + #else + plain_dump_principal (context, client); + fprintf(stderr, diff --git a/SOURCES/krb5-1.12-ksu-path.patch b/SOURCES/krb5-1.12-ksu-path.patch new file mode 100644 index 0000000..65552c9 --- /dev/null +++ b/SOURCES/krb5-1.12-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"' + + KSU_LIBS=@KSU_LIBS@ + PAM_LIBS=@PAM_LIBS@ diff --git a/SOURCES/krb5-1.12-ksu-untyped-default-ccache-name.patch b/SOURCES/krb5-1.12-ksu-untyped-default-ccache-name.patch new file mode 100644 index 0000000..4e1f835 --- /dev/null +++ b/SOURCES/krb5-1.12-ksu-untyped-default-ccache-name.patch @@ -0,0 +1,46 @@ +commit bda574576a5a2d0613fecf12d820e0adcbedf95c +Author: Nalin Dahyabhai +Date: Mon Sep 8 13:15:40 2014 -0400 + + In ksu, handle typeless default_ccache_name values + + When a configured or compiled-in default ccache name doesn't contain a + cache type and ':' as a prefix, add one to the writeable value that we + construct when we go to look it up. This lets the rest of the + application always assume that it'll be there. + + [ghudson@mit.edu: minor style changes] + + ticket: 8007 (new) + target_version: 1.13 + tags: pullup + +diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c +index 47fa820..622c36a 100644 +--- a/src/clients/ksu/main.c ++++ b/src/clients/ksu/main.c +@@ -819,7 +819,7 @@ get_configured_defccname(krb5_context context, char **target_out) + { + krb5_error_code retval; + const char *defname; +- char *target; ++ char *target = NULL; + + *target_out = NULL; + +@@ -838,7 +838,14 @@ get_configured_defccname(krb5_context context, char **target_out) + } + + defname = krb5_cc_default_name(context); +- target = (defname == NULL) ? NULL : strdup(defname); ++ if (defname != NULL) { ++ if (strchr(defname, ':') != NULL) { ++ target = strdup(defname); ++ } else { ++ if (asprintf(&target, "FILE:%s", defname) < 0) ++ target = NULL; ++ } ++ } + if (target == NULL) { + com_err(prog_name, ENOMEM, _("while determining target ccache name")); + return ENOMEM; diff --git a/SOURCES/krb5-1.12-ktany.patch b/SOURCES/krb5-1.12-ktany.patch new file mode 100644 index 0000000..88f1a7e --- /dev/null +++ b/SOURCES/krb5-1.12-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) { ++ free(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) { ++ free(data->name); ++ free(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]); ++ free(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; ++ free(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) { ++ free(cdata); ++ return(kerror); ++ } ++ } ++ ++ if (i == data->nchoices) { ++ /* Everyone returned ENOENT, so no go. */ ++ free(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); ++ free(cdata); ++ return(kerror); ++} ++ ++static void ++cleanup(context, data, nchoices) ++ krb5_context context; ++ krb5_ktany_data *data; ++ int nchoices; ++{ ++ int i; ++ ++ free(data->name); ++ for (i = 0; i < nchoices; i++) ++ krb5_kt_close(context, data->choices[i]); ++ free(data->choices); ++ free(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.12-nodelete-plugins.patch b/SOURCES/krb5-1.12-nodelete-plugins.patch new file mode 100644 index 0000000..88fb8c6 --- /dev/null +++ b/SOURCES/krb5-1.12-nodelete-plugins.patch @@ -0,0 +1,59 @@ +commit 0f46175d632ae03ab7d4cfba5e62534d31e128e0 +Author: Greg Hudson +Date: Wed Jun 25 11:41:54 2014 -0400 + + Load plugins with RTLD_NODELETE if possible + + On platforms which support RTLD_NODELETE, use it to load plugin + modules. While using this flag makes plugins stay in the process map + after libkrb5/libgssapi_krb5 are unloaded, it solves several problems: + + 1. It prevents plugin modules which link against OpenSSL (PKINIT and + k5tls) from repeatedly initializing instances of libssl or libcrypto, + leaking heap memory each time. This is only an issue because we + cannot safely uninitialize OpenSSL. + + 2. It prevents finalization ordering issues from causing a process + crash when unloading libgssapi_krb5 (issue #7135). + + 3. It makes memory leak tracing with valgrind easier. + + ticket: 7947 (new) + +diff --git a/src/util/support/plugins.c b/src/util/support/plugins.c +index a04dfc3..ca4b128 100644 +--- a/src/util/support/plugins.c ++++ b/src/util/support/plugins.c +@@ -45,6 +45,20 @@ + + #include "k5-platform.h" + ++#if USE_DLOPEN ++#ifdef RTLD_GROUP ++#define GROUP RTLD_GROUP ++#else ++#define GROUP 0 ++#endif ++#ifdef RTLD_NODELETE ++#define NODELETE RTLD_NODELETE ++#else ++#define NODELETE 0 ++#endif ++#define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL | GROUP | NODELETE) ++#endif ++ + #if USE_DLOPEN && USE_CFBUNDLE + #include + +@@ -257,11 +271,6 @@ krb5int_open_plugin (const char *filepath, struct plugin_file_handle **h, struct + } + #endif /* USE_CFBUNDLE */ + +-#ifdef RTLD_GROUP +-#define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL | RTLD_GROUP) +-#else +-#define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL) +-#endif + if (!err) { + handle = dlopen(filepath, PLUGIN_DLOPEN_FLAGS); + if (handle == NULL) { diff --git a/SOURCES/krb5-1.12-pwdch-fast.patch b/SOURCES/krb5-1.12-pwdch-fast.patch index 4751c9f..3b7d4bb 100644 --- a/SOURCES/krb5-1.12-pwdch-fast.patch +++ b/SOURCES/krb5-1.12-pwdch-fast.patch @@ -1,4 +1,4 @@ -From 0c00989f5bdaf9adf6d243455fbc7056bd0013f5 Mon Sep 17 00:00:00 2001 +From 230858394d2dded001ef3d2029daa6c468aca097 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Fri, 28 Feb 2014 14:49:35 -0500 Subject: [PATCH] Use preauth options when changing password @@ -14,7 +14,6 @@ ticket: 7868 npmccallum: * include tests from 06817686bfdef99523f300464bcbb0c8b037a27d - * backport from 1.12 to 1.11 --- src/lib/krb5/krb/gic_pwd.c | 63 +++++++++++++++++++++++++++++++++++++--------- src/tests/Makefile.in | 1 + @@ -23,10 +22,10 @@ npmccallum: create mode 100644 src/tests/t_changepw.py diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c -index 9fdb8934a0765395ebc2b875d31b393d954bcbb4..c6c3161ca777698f0a7cbb789df34e51fa85b12c 100644 +index a97823f6b51b7393755e82f36612c30b64096754..6aec7c3a71f99d2194b09374b296327174e6d4b8 100644 --- a/src/lib/krb5/krb/gic_pwd.c +++ b/src/lib/krb5/krb/gic_pwd.c -@@ -241,6 +241,54 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options, +@@ -242,6 +242,54 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options, (*prompter)(context, data, 0, banner, 0, 0); } @@ -43,7 +42,7 @@ index 9fdb8934a0765395ebc2b875d31b393d954bcbb4..c6c3161ca777698f0a7cbb789df34e51 + */ +static krb5_get_init_creds_opt * +make_chpw_options(krb5_get_init_creds_opt *in, krb5_gic_opt_ext *storage1, -+ krb5_gic_opt_private *storage2) ++ gic_opt_private *storage2) +{ + krb5_gic_opt_ext *in_ext; + krb5_get_init_creds_opt *opt; @@ -51,7 +50,7 @@ index 9fdb8934a0765395ebc2b875d31b393d954bcbb4..c6c3161ca777698f0a7cbb789df34e51 + /* Copy the application's options to storage. */ + if (in == NULL) { + storage1->flags = 0; -+ } else if (krb5_gic_opt_is_extended(in)) { ++ } else if (gic_opt_is_extended(in)) { + in_ext = (krb5_gic_opt_ext *)in; + *storage1 = *in_ext; + *storage2 = *in_ext->opt_private; @@ -72,7 +71,7 @@ index 9fdb8934a0765395ebc2b875d31b393d954bcbb4..c6c3161ca777698f0a7cbb789df34e51 + opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_ANONYMOUS; + + /* The output ccache should only be used for the actual ticket. */ -+ if (krb5_gic_opt_is_extended(opt)) ++ if (gic_opt_is_extended(opt)) + storage2->out_ccache = NULL; + + return opt; @@ -81,16 +80,16 @@ index 9fdb8934a0765395ebc2b875d31b393d954bcbb4..c6c3161ca777698f0a7cbb789df34e51 krb5_error_code KRB5_CALLCONV krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, -@@ -258,6 +306,8 @@ krb5_get_init_creds_password(krb5_context context, +@@ -259,6 +307,8 @@ krb5_get_init_creds_password(krb5_context context, int tries; krb5_creds chpw_creds; krb5_get_init_creds_opt *chpw_opts = NULL; + krb5_gic_opt_ext storage1; -+ krb5_gic_opt_private storage2; ++ gic_opt_private storage2; struct gak_password gakpw; krb5_data pw0, pw1; char banner[1024], pw0array[1024], pw1array[1024]; -@@ -347,16 +397,7 @@ krb5_get_init_creds_password(krb5_context context, +@@ -345,16 +395,7 @@ krb5_get_init_creds_password(krb5_context context, /* ok, we have an expired password. Give the user a few chances to change it */ @@ -105,10 +104,10 @@ index 9fdb8934a0765395ebc2b875d31b393d954bcbb4..c6c3161ca777698f0a7cbb789df34e51 - krb5_get_init_creds_opt_set_proxiable(chpw_opts, 0); - + chpw_opts = make_chpw_options(options, &storage1, &storage2); - if ((ret = krb5int_get_init_creds(context, &chpw_creds, client, - prompter, data, - start_time, "kadmin/changepw", chpw_opts, -@@ -473,8 +514,6 @@ cleanup: + ret = k5_get_init_creds(context, &chpw_creds, client, prompter, data, + start_time, "kadmin/changepw", chpw_opts, + krb5_get_as_key_password, &gakpw, &use_master, +@@ -471,8 +512,6 @@ cleanup: warn_pw_expiry(context, options, prompter, data, in_tkt_service, as_reply); @@ -118,17 +117,17 @@ index 9fdb8934a0765395ebc2b875d31b393d954bcbb4..c6c3161ca777698f0a7cbb789df34e51 memset(pw0array, 0, sizeof(pw0array)); memset(pw1array, 0, sizeof(pw1array)); diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in -index 9f76e9a7fad23e03b37e067d58c75fd7eaa8e673..74a6bdcff95618b6c9c77d5b50a243790af557e3 100644 +index 62523895d53da24844141a6ada6cab23e77dd9e6..55f1d6419f8d924a6f9a2971d36f1eac6d293d32 100644 --- a/src/tests/Makefile.in +++ b/src/tests/Makefile.in -@@ -71,6 +71,7 @@ check-pytests:: hist t_init_creds +@@ -94,6 +94,7 @@ check-pytests:: t_init_creds t_localauth $(RUNPYTEST) $(srcdir)/t_iprop.py $(PYTESTFLAGS) - $(RUNPYTEST) $(srcdir)/t_anonpkinit.py $(PYTESTFLAGS) - $(RUNPYTEST) $(srcdir)/t_lockout.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_kprop.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_policy.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_changepw.py $(PYTESTFLAGS) - $(RUNPYTEST) $(srcdir)/t_kadm5_hook.py $(PYTESTFLAGS) - $(RUNPYTEST) $(srcdir)/t_kdb_locking.py $(PYTESTFLAGS) - $(RUNPYTEST) $(srcdir)/t_keyrollover.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_pkinit.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_otp.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_localauth.py $(PYTESTFLAGS) diff --git a/src/tests/t_changepw.py b/src/tests/t_changepw.py new file mode 100644 index 0000000000000000000000000000000000000000..0b9832668e618b3db8d88cf388ec918898bb4df3 diff --git a/SOURCES/krb5-1.12-selinux-label.patch b/SOURCES/krb5-1.12-selinux-label.patch new file mode 100644 index 0000000..395f5f7 --- /dev/null +++ b/SOURCES/krb5-1.12-selinux-label.patch @@ -0,0 +1,979 @@ +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@ + KRB_INCLUDES = -I$(BUILDTOP)/include -I$(top_srcdir)/include + LDFLAGS = @LDFLAGS@ + 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 KRB5_KDB_MAX_LIFE (60*60*24) /* one day */ + #define KRB5_KDB_MAX_RLIFE (60*60*24*7) /* one week */ +--- 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/build-tools/krb5-config.in ++++ krb5/src/build-tools/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 */ + k5_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/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) + + DEPLIBS= + +--- krb5/src/util/support/selinux.c ++++ krb5/src/util/support/selinux.c +@@ -0,0 +1,381 @@ ++/* ++ * Copyright 2007,2008,2009,2011,2012,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: ++ * ++ * 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); ++ k5_mutex_lock(&labeled_mutex); ++ if (stat(pathname, &st) != 0) { ++ st.st_mode = S_IRUSR | S_IWUSR; ++ } ++ retval = push_fscreatecon(pathname, st.st_mode); ++ return retval ? retval : (void *) -1; ++} ++ ++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); ++ k5_mutex_lock(&labeled_mutex); ++ ctx = push_fscreatecon(path, 0); ++ fp = fopen(path, mode); ++ errno_save = errno; ++ pop_fscreatecon(ctx); ++ k5_mutex_unlock(&labeled_mutex); ++ errno = errno_save; ++ 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); ++ k5_mutex_lock(&labeled_mutex); ++ ctx = push_fscreatecon(path, 0); ++ fd = creat(path, mode); ++ errno_save = errno; ++ pop_fscreatecon(ctx); ++ k5_mutex_unlock(&labeled_mutex); ++ errno = errno_save; ++ 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); ++ k5_mutex_lock(&labeled_mutex); ++ ctx = push_fscreatecon(path, mode); ++ ret = mknod(path, mode, dev); ++ errno_save = errno; ++ pop_fscreatecon(ctx); ++ k5_mutex_unlock(&labeled_mutex); ++ errno = errno_save; ++ 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); ++ k5_mutex_lock(&labeled_mutex); ++ ctx = push_fscreatecon(path, S_IFDIR); ++ ret = mkdir(path, mode); ++ errno_save = errno; ++ pop_fscreatecon(ctx); ++ k5_mutex_unlock(&labeled_mutex); ++ errno = errno_save; ++ 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); ++ k5_mutex_lock(&labeled_mutex); ++ 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; ++ 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 + if (caller == FKPROPLOG) + 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.12-system-exts.patch b/SOURCES/krb5-1.12-system-exts.patch new file mode 100644 index 0000000..b90fb1b --- /dev/null +++ b/SOURCES/krb5-1.12-system-exts.patch @@ -0,0 +1,53 @@ +On a glibc system, EAI_NODATA isn't defined unless _GNU_SOURCE is. The +recommended thing is to use AC_USE_SYSTEM_EXTENSIONS to get all extensions +defined, but that would require fixups in varous other places, so we go for the +smaller change here. + +--- krb5-1.11/src/lib/krb5/os/hostrealm.c ++++ krb5-1.11/src/lib/krb5/os/hostrealm.c +@@ -30,6 +30,9 @@ + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ++/* We need to have EAI_NODATA and friends declared. */ ++#define _GNU_SOURCE ++ + #include "k5-int.h" + #include "os-proto.h" + #include "fake-addrinfo.h" +--- krb5-1.11/src/lib/krb5/os/sendto_kdc.c ++++ krb5-1.11/src/lib/krb5/os/sendto_kdc.c +@@ -27,6 +27,9 @@ + /* Send packet to KDC for realm; wait for response, retransmitting + * as necessary. */ + ++/* We need to have EAI_NODATA and friends declared. */ ++#define _GNU_SOURCE ++ + #include "fake-addrinfo.h" + #include "k5-tls.h" + #include "k5-int.h" +--- krb5-1.11/src/util/support/fake-addrinfo.c ++++ krb5-1.11/src/util/support/fake-addrinfo.c +@@ -101,6 +101,9 @@ + * these functions, and throw all this away. Pleeease? :-) + */ + ++/* We need to have EAI_NODATA and friends declared. */ ++#define _GNU_SOURCE ++ + #include "port-sockets.h" + #include "socket-utils.h" + #include "k5-platform.h" +--- krb5-1.12/src/lib/krad/client.c ++++ krb5-1.12/src/lib/krad/client.c +@@ -27,6 +27,9 @@ + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ++/* We need to have EAI_NODATA and friends declared. */ ++#define _GNU_SOURCE ++ + #include + #include "internal.h" + diff --git a/SOURCES/krb5-1.12.1-pam.patch b/SOURCES/krb5-1.12.1-pam.patch new file mode 100644 index 0000000..5a8e65e --- /dev/null +++ b/SOURCES/krb5-1.12.1-pam.patch @@ -0,0 +1,747 @@ +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/src/aclocal.m4.pam krb5/src/aclocal.m4 +--- krb5/src/aclocal.m4.pam 2009-11-22 12:00:45.000000000 -0500 ++++ krb5/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/src/clients/ksu/main.c.pam krb5/src/clients/ksu/main.c +--- krb5/src/clients/ksu/main.c.pam 2009-11-02 22:27:56.000000000 -0500 ++++ krb5/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 +@@ -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 KS_TEMPORARY_CACHE "MEMORY:_ksu" +@@ -586,6 +592,23 @@ 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); ++ exit(1); ++ } ++ if (appl_pam_requires_chauthtok()) { ++ fprintf(stderr, "Password change required for %s.\n", ++ target_user); ++ 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,24 @@ + + 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); ++ exit(1); ++ } ++ if (appl_pam_requires_chauthtok()) { ++ fprintf(stderr, "Password change required for %s.\n", ++ target_user); ++ exit(1); ++ } ++ force_fork++; ++ } ++#endif + } + + if( some_rest_copy){ +@@ -720,6 +745,30 @@ + 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); ++ 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); ++ 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/src/clients/ksu/Makefile.in.pam krb5/src/clients/ksu/Makefile.in +--- krb5/src/clients/ksu/Makefile.in.pam 2009-11-22 13:13:29.000000000 -0500 ++++ krb5/src/clients/ksu/Makefile.in 2010-03-05 11:55:14.000000000 -0500 +@@ -7,12 +7,14 @@ + DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/bin /local/bin"' + + 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/src/clients/ksu/pam.c.pam krb5/src/clients/ksu/pam.c +--- krb5/src/clients/ksu/pam.c.pam 2010-03-05 10:48:08.000000000 -0500 ++++ krb5/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/src/clients/ksu/pam.h.pam krb5/src/clients/ksu/pam.h +--- krb5/src/clients/ksu/pam.h.pam 2010-03-05 10:48:08.000000000 -0500 ++++ krb5/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/src/configure.in.pam krb5/src/configure.in +--- krb5/src/configure.in.pam 2009-12-31 18:13:56.000000000 -0500 ++++ krb5/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.12.2.tar.gz.asc b/SOURCES/krb5-1.12.2.tar.gz.asc new file mode 100644 index 0000000..fc16e6f --- /dev/null +++ b/SOURCES/krb5-1.12.2.tar.gz.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1 + +iQEVAwUAU+lJVhUCTNN0nXiJAQIpkgf9HczaywhoXEZYbVORXAxDGrb8ADlAnFdY +htRjqJ8xTmj0yMtPF1NJk4ian/u9ksc7qZ9JQg7F64gy/7098RlCfsTMT/b3qp0r +0cmNiTMYq19igxHy9qWm0JonudDQhUulmIMi/58nBXc7IblhaVtlDnQNbA8qpg9W +RLdn0qyeksVWAIxJ1KKsZTbZ4+U1OOPE2npZ7nHeLeYmz7rKqorQQM+NNxu+/dtB +eo0fmeeX7bXPE2Xe/kYw7HSfIhRMHy1oH0fi9AAZnREA00/xgPq+JqhC3hIloqlk +NDTJk2+cKZnyuDh+nyuS7wGsExqJCWjFSE5mrJiJ6N0YS0hsLn+7aA== +=O612 +-----END PGP SIGNATURE----- diff --git a/SOURCES/krb5-1.12ish-kpasswd_tcp.patch b/SOURCES/krb5-1.12ish-kpasswd_tcp.patch new file mode 100644 index 0000000..4fdfca4 --- /dev/null +++ b/SOURCES/krb5-1.12ish-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 + &sl, strategy, &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 (!no_udp) { ++ 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); ++ no_udp = 1; ++ continue; ++ default: ++ break; ++ } ++ } + break; + } + diff --git a/SOURCES/krb5-1.12ish-tls-plugins.patch b/SOURCES/krb5-1.12ish-tls-plugins.patch new file mode 100644 index 0000000..9004f74 --- /dev/null +++ b/SOURCES/krb5-1.12ish-tls-plugins.patch @@ -0,0 +1,1680 @@ +Adapt to headers being included in a different order in sendto_kdc.c. +Drop portions which drop checkhost.c and checkhost.h. + +commit 472349d2a47fbc7db82e46ba46411b95c312fc1f +Author: Greg Hudson +Date: Sun Jun 22 10:42:14 2014 -0400 + + Move KKDCP OpenSSL code to an internal plugin + + Create an internal pluggable interface "tls" with one in-tree dynamic + plugin module named "k5tls". Move all of the OpenSSL calls to the + plugin module, and make the libkrb5 code load and invoke the plugin. + This way we do not load or initialize libssl unless an HTTP proxy is + used. + + ticket: 7929 + +diff --git a/src/Makefile.in b/src/Makefile.in +index 5e2cf4e..92bb60a 100644 +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -20,6 +20,7 @@ SUBDIRS=util include lib \ + @ldap_plugin_dir@ \ + plugins/preauth/otp \ + plugins/preauth/pkinit \ ++ plugins/tls/k5tls \ + kdc kadmin slave clients appl tests \ + config-files build-tools man doc @po@ + WINSUBDIRS=include util lib ccapi windows clients appl +@@ -62,7 +63,7 @@ INSTALLMKDIRS = $(KRB5ROOT) $(KRB5MANROOT) $(KRB5OTHERMKDIRS) \ + $(KRB5_LIBDIR) $(KRB5_INCDIR) \ + $(KRB5_DB_MODULE_DIR) $(KRB5_PA_MODULE_DIR) \ + $(KRB5_AD_MODULE_DIR) \ +- $(KRB5_LIBKRB5_MODULE_DIR) \ ++ $(KRB5_LIBKRB5_MODULE_DIR) $(KRB5_TLS_MODULE_DIR) \ + @localstatedir@ @localstatedir@/krb5kdc \ + $(KRB5_INCSUBDIRS) $(datadir) $(EXAMPLEDIR) \ + $(PKGCONFIG_DIR) +diff --git a/src/config/pre.in b/src/config/pre.in +index e1d7e4b..fd8ee56 100644 +--- a/src/config/pre.in ++++ b/src/config/pre.in +@@ -213,6 +213,7 @@ KRB5_DB_MODULE_DIR = $(MODULE_DIR)/kdb + KRB5_PA_MODULE_DIR = $(MODULE_DIR)/preauth + KRB5_AD_MODULE_DIR = $(MODULE_DIR)/authdata + KRB5_LIBKRB5_MODULE_DIR = $(MODULE_DIR)/libkrb5 ++KRB5_TLS_MODULE_DIR = $(MODULE_DIR)/tls + KRB5_LOCALEDIR = @localedir@ + GSS_MODULE_DIR = @libdir@/gss + KRB5_INCSUBDIRS = \ +diff --git a/src/configure.in b/src/configure.in +index 8aa513e..43509ab 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -308,6 +308,11 @@ no) + ;; + esac + ++if test "$PROXY_TLS_IMPL" = no; then ++ AC_DEFINE(PROXY_TLS_IMPL_NONE,1, ++ [Define if no HTTP TLS implementation is selected]) ++fi ++ + AC_SUBST(PROXY_TLS_IMPL) + AC_SUBST(PROXY_TLS_IMPL_CFLAGS) + AC_SUBST(PROXY_TLS_IMPL_LIBS) +@@ -1386,6 +1391,7 @@ dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test + plugins/authdata/greet + plugins/authdata/greet_client + plugins/authdata/greet_server ++ plugins/tls/k5tls + + clients clients/klist clients/kinit clients/kvno + clients/kdestroy clients/kpasswd clients/ksu clients/kswitch +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index 9f14ee0..38846eb 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -1083,7 +1083,8 @@ struct plugin_interface { + #define PLUGIN_INTERFACE_LOCALAUTH 5 + #define PLUGIN_INTERFACE_HOSTREALM 6 + #define PLUGIN_INTERFACE_AUDIT 7 +-#define PLUGIN_NUM_INTERFACES 8 ++#define PLUGIN_INTERFACE_TLS 8 ++#define PLUGIN_NUM_INTERFACES 9 + + /* Retrieve the plugin module of type interface_id and name modname, + * storing the result into module. */ +@@ -1126,6 +1127,7 @@ typedef struct krb5_preauth_context_st krb5_preauth_context; + struct ccselect_module_handle; + struct localauth_module_handle; + struct hostrealm_module_handle; ++struct k5_tls_vtable_st; + struct _krb5_context { + krb5_magic magic; + krb5_enctype *in_tkt_etypes; +@@ -1169,6 +1171,9 @@ struct _krb5_context { + /* hostrealm module stuff */ + struct hostrealm_module_handle **hostrealm_handles; + ++ /* TLS module vtable (if loaded) */ ++ struct k5_tls_vtable_st *tls; ++ + /* error detail info */ + struct errinfo err; + +diff --git a/src/include/k5-tls.h b/src/include/k5-tls.h +new file mode 100644 +index 0000000..0661c05 +--- /dev/null ++++ b/src/include/k5-tls.h +@@ -0,0 +1,104 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* include/k5-tls.h - internal pluggable interface for TLS */ ++/* ++ * Copyright (C) 2014 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 internal pluggable interface allows libkrb5 to load an in-tree module ++ * providing TLS support at runtime. It is currently tailored for the needs of ++ * the OpenSSL module as used for HTTP proxy support. As an internal ++ * interface, it can be changed to fit different implementations and consumers ++ * without regard for backward compatibility. ++ */ ++ ++#ifndef K5_TLS_H ++#define K5_TLS_H ++ ++#include "k5-int.h" ++ ++/* An abstract type for localauth module data. */ ++typedef struct k5_tls_handle_st *k5_tls_handle; ++ ++typedef enum { ++ DATA_READ, DONE, WANT_READ, WANT_WRITE, ERROR_TLS ++} k5_tls_status; ++ ++/* ++ * Create a handle for fd, where the server certificate must match servername ++ * and be trusted according to anchors. anchors is a null-terminated list ++ * using the DIR:/FILE:/ENV: syntax borrowed from PKINIT. If anchors is null, ++ * use the system default trust anchors. ++ */ ++typedef krb5_error_code ++(*k5_tls_setup_fn)(krb5_context context, SOCKET fd, const char *servername, ++ char **anchors, k5_tls_handle *handle_out); ++ ++/* ++ * Write len bytes of data using TLS. Return DONE if writing is complete, ++ * WANT_READ or WANT_WRITE if the underlying socket must be readable or ++ * writable to continue, and ERROR_TLS if the TLS channel or underlying socket ++ * experienced an error. After WANT_READ or WANT_WRITE, the operation will be ++ * retried with the same arguments even if some data has already been written. ++ * (OpenSSL makes this contract easy to fulfill. For other implementations we ++ * might want to change it.) ++ */ ++typedef k5_tls_status ++(*k5_tls_write_fn)(krb5_context context, k5_tls_handle handle, ++ const void *data, size_t len); ++ ++/* ++ * Read up to data_size bytes of data using TLS. Return DATA_READ and set ++ * *len_out if any data is read. Return DONE if there is no more data to be ++ * read on the connection, WANT_READ or WANT_WRITE if the underlying socket ++ * must be readable or writable to continue, and ERROR_TLS if the TLS channel ++ * or underlying socket experienced an error. ++ * ++ * After DATA_READ, there may still be pending buffered data to read. The ++ * caller must call this method again with additional buffer space before ++ * selecting for reading on the underlying socket. ++ */ ++typedef k5_tls_status ++(*k5_tls_read_fn)(krb5_context context, k5_tls_handle handle, void *data, ++ size_t data_size, size_t *len_out); ++ ++/* Release a handle. Do not pass a null pointer. */ ++typedef void ++(*k5_tls_free_handle_fn)(krb5_context context, k5_tls_handle handle); ++ ++/* All functions are mandatory unless they are all null, in which case the ++ * caller should assume that TLS is unsupported. */ ++typedef struct k5_tls_vtable_st { ++ k5_tls_setup_fn setup; ++ k5_tls_write_fn write; ++ k5_tls_read_fn read; ++ k5_tls_free_handle_fn free_handle; ++} *k5_tls_vtable; ++ ++#endif /* K5_TLS_H */ +diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h +index 9e75b29..a0aa85a 100644 +--- a/src/include/k5-trace.h ++++ b/src/include/k5-trace.h +@@ -324,23 +324,11 @@ void krb5int_trace(krb5_context context, const char *fmt, ...); + TRACE(c, "Resolving hostname {str}", hostname) + #define TRACE_SENDTO_KDC_RESPONSE(c, len, raddr) \ + TRACE(c, "Received answer ({int} bytes) from {raddr}", len, raddr) +-#define TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MISMATCH(c, hostname) \ +- TRACE(c, "HTTPS certificate name mismatch: server certificate is " \ +- "not for \"{str}\"", hostname) +-#define TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MATCH(c, hostname) \ +- TRACE(c, "HTTPS certificate name matched \"{str}\"", hostname) +-#define TRACE_SENDTO_KDC_HTTPS_NO_REMOTE_CERTIFICATE(c) \ +- TRACE(c, "HTTPS server certificate not received") +-#define TRACE_SENDTO_KDC_HTTPS_PROXY_CERTIFICATE_ERROR(c, depth, \ +- namelen, name, \ +- err, errs) \ +- TRACE(c, "HTTPS certificate error at {int} ({lenstr}): " \ +- "{int} ({str})", depth, namelen, name, err, errs) +-#define TRACE_SENDTO_KDC_HTTPS_ERROR_CONNECT(c, raddr) \ ++#define TRACE_SENDTO_KDC_HTTPS_ERROR_CONNECT(c, raddr) \ + TRACE(c, "HTTPS error connecting to {raddr}", raddr) +-#define TRACE_SENDTO_KDC_HTTPS_ERROR_RECV(c, raddr, err) \ +- TRACE(c, "HTTPS error receiving from {raddr}: {errno}", raddr, err) +-#define TRACE_SENDTO_KDC_HTTPS_ERROR_SEND(c, raddr) \ ++#define TRACE_SENDTO_KDC_HTTPS_ERROR_RECV(c, raddr) \ ++ TRACE(c, "HTTPS error receiving from {raddr}", raddr) ++#define TRACE_SENDTO_KDC_HTTPS_ERROR_SEND(c, raddr) \ + TRACE(c, "HTTPS error sending to {raddr}", raddr) + #define TRACE_SENDTO_KDC_HTTPS_SEND(c, raddr) \ + TRACE(c, "Sending HTTPS request to {raddr}", raddr) +@@ -383,6 +371,19 @@ void krb5int_trace(krb5_context context, const char *fmt, ...); + TRACE(c, "TGS reply didn't decode with subkey; trying session key " \ + "({keyblock)}", keyblock) + ++#define TRACE_TLS_ERROR(c, errs) \ ++ TRACE(c, "TLS error: {str}", errs) ++#define TRACE_TLS_NO_REMOTE_CERTIFICATE(c) \ ++ TRACE(c, "TLS server certificate not received") ++#define TRACE_TLS_CERT_ERROR(c, depth, namelen, name, err, errs) \ ++ TRACE(c, "TLS certificate error at {int} ({lenstr}): {int} ({str})", \ ++ depth, namelen, name, err, errs) ++#define TRACE_TLS_SERVER_NAME_MISMATCH(c, hostname) \ ++ TRACE(c, "TLS certificate name mismatch: server certificate is " \ ++ "not for \"{str}\"", hostname) ++#define TRACE_TLS_SERVER_NAME_MATCH(c, hostname) \ ++ TRACE(c, "TLS certificate name matched \"{str}\"", hostname) ++ + #define TRACE_TKT_CREDS(c, creds, cache) \ + TRACE(c, "Getting credentials {creds} using ccache {ccache}", \ + creds, cache) +diff --git a/src/lib/krb5/Makefile.in b/src/lib/krb5/Makefile.in +index 472c008..d9cddc1 100644 +--- a/src/lib/krb5/Makefile.in ++++ b/src/lib/krb5/Makefile.in +@@ -56,8 +56,7 @@ RELDIR=krb5 + SHLIB_EXPDEPS = \ + $(TOPLIBD)/libk5crypto$(SHLIBEXT) \ + $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB) +-SHLIB_EXPLIBS=-lk5crypto -lcom_err $(PROXY_TLS_IMPL_LIBS) $(SUPPORT_LIB) \ +- @GEN_LIB@ $(LIBS) ++SHLIB_EXPLIBS=-lk5crypto -lcom_err $(SUPPORT_LIB) @GEN_LIB@ $(LIBS) + + all-unix:: all-liblinks + +diff --git a/src/lib/krb5/krb/copy_ctx.c b/src/lib/krb5/krb/copy_ctx.c +index 4237023..322c288 100644 +--- a/src/lib/krb5/krb/copy_ctx.c ++++ b/src/lib/krb5/krb/copy_ctx.c +@@ -81,6 +81,7 @@ krb5_copy_context(krb5_context ctx, krb5_context *nctx_out) + nctx->ccselect_handles = NULL; + nctx->localauth_handles = NULL; + nctx->hostrealm_handles = NULL; ++ nctx->tls = NULL; + nctx->kdblog_context = NULL; + nctx->trace_callback = NULL; + nctx->trace_callback_data = NULL; +diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c +index 6801bb1..6548f36 100644 +--- a/src/lib/krb5/krb/init_ctx.c ++++ b/src/lib/krb5/krb/init_ctx.c +@@ -319,6 +319,7 @@ krb5_free_context(krb5_context ctx) + k5_localauth_free_context(ctx); + k5_plugin_free_context(ctx); + free(ctx->plugin_base_dir); ++ free(ctx->tls); + + ctx->magic = 0; + free(ctx); +diff --git a/src/lib/krb5/krb/plugin.c b/src/lib/krb5/krb/plugin.c +index 8b62c7b..7375f51 100644 +--- a/src/lib/krb5/krb/plugin.c ++++ b/src/lib/krb5/krb/plugin.c +@@ -55,7 +55,8 @@ const char *interface_names[] = { + "ccselect", + "localauth", + "hostrealm", +- "audit" ++ "audit", ++ "tls" + }; + + /* Return the context's interface structure for id, or NULL if invalid. */ +diff --git a/src/lib/krb5/krb5_libinit.c b/src/lib/krb5/krb5_libinit.c +index b72bc58..eb40124 100644 +--- a/src/lib/krb5/krb5_libinit.c ++++ b/src/lib/krb5/krb5_libinit.c +@@ -55,8 +55,6 @@ int krb5int_lib_init(void) + if (err) + return err; + +- k5_sendto_kdc_initialize(); +- + return 0; + } + +diff --git a/src/lib/krb5/os/Makefile.in b/src/lib/krb5/os/Makefile.in +index fa8a093..ea68990 100644 +--- a/src/lib/krb5/os/Makefile.in ++++ b/src/lib/krb5/os/Makefile.in +@@ -2,7 +2,7 @@ mydir=lib$(S)krb5$(S)os + BUILDTOP=$(REL)..$(S)..$(S).. + DEFINES=-DLIBDIR=\"$(KRB5_LIBDIR)\" -DBINDIR=\"$(CLIENT_BINDIR)\" \ + -DSBINDIR=\"$(ADMIN_BINDIR)\" +-LOCALINCLUDES= $(PROXY_TLS_IMPL_CFLAGS) -I$(top_srcdir)/util/profile ++LOCALINCLUDES= -I$(top_srcdir)/util/profile + + ##DOS##BUILDTOP = ..\..\.. + ##DOS##PREFIXDIR=os +@@ -13,7 +13,6 @@ STLIBOBJS= \ + c_ustime.o \ + ccdefname.o \ + changepw.o \ +- checkhost.o \ + dnsglue.o \ + dnssrv.o \ + expand_path.o \ +diff --git a/src/lib/krb5/os/deps b/src/lib/krb5/os/deps +index d56ff30..211354c 100644 +--- a/src/lib/krb5/os/deps ++++ b/src/lib/krb5/os/deps +@@ -49,17 +49,6 @@ changepw.so changepw.po $(OUTPRE)changepw.$(OBJEXT): \ + $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + changepw.c os-proto.h +-checkhost.so checkhost.po $(OUTPRE)checkhost.$(OBJEXT): \ +- $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ +- $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ +- $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ +- $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ +- $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ +- $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ +- $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/k5-utf8.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 checkhost.c checkhost.h + dnsglue.so dnsglue.po $(OUTPRE)dnsglue.$(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 \ +@@ -429,7 +418,7 @@ sendto_kdc.so sendto_kdc.po $(OUTPRE)sendto_kdc.$(OBJEXT): \ + $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ +- $(top_srcdir)/include/socket-utils.h checkhost.h os-proto.h \ ++ $(top_srcdir)/include/socket-utils.h os-proto.h \ + sendto_kdc.c + sn2princ.so sn2princ.po $(OUTPRE)sn2princ.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ +diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c +index 1f2039c..160a2d0 100644 +--- a/src/lib/krb5/os/locate_kdc.c ++++ b/src/lib/krb5/os/locate_kdc.c +@@ -177,7 +177,6 @@ oom: + return ENOMEM; + } + +-#ifdef PROXY_TLS_IMPL_OPENSSL + static void + parse_uri_if_https(char *host_or_uri, k5_transport *transport, char **host, + char **uri_path) +@@ -195,13 +194,6 @@ parse_uri_if_https(char *host_or_uri, k5_transport *transport, char **host, + } + } + } +-#else +-static void +-parse_uri_if_https(char *host_or_uri, k5_transport *transport, char **host, +- char **uri) +-{ +-} +-#endif + + /* Return true if server is identical to an entry in list. */ + static krb5_boolean +diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h +index 34bf028..69ee376 100644 +--- a/src/lib/krb5/os/os-proto.h ++++ b/src/lib/krb5/os/os-proto.h +@@ -187,6 +187,5 @@ krb5_error_code localauth_k5login_initvt(krb5_context context, int maj_ver, + krb5_plugin_vtable vtable); + krb5_error_code localauth_an2ln_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable); +-void k5_sendto_kdc_initialize(void); + + #endif /* KRB5_LIBOS_INT_PROTO__ */ +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index a572831..2242240 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -54,6 +54,7 @@ + * as necessary. */ + + #include "fake-addrinfo.h" ++#include "k5-tls.h" + #include "k5-int.h" + + #include "os-proto.h" +@@ -74,15 +75,6 @@ + #endif + #endif + +-#ifdef PROXY_TLS_IMPL_OPENSSL +-#include +-#include +-#include +-#include +-#include +-#include "checkhost.h" +-#endif +- + #define MAX_PASS 3 + #define DEFAULT_UDP_PREF_LIMIT 1465 + #define HARD_UDP_LIMIT 32700 /* could probably do 64K-epsilon ? */ +@@ -147,29 +139,30 @@ struct conn_state { + const char *uri_path; + const char *servername; + char *https_request; +-#ifdef PROXY_TLS_IMPL_OPENSSL +- SSL *ssl; +-#endif ++ k5_tls_handle tls; + } http; + }; + +-#ifdef PROXY_TLS_IMPL_OPENSSL +-/* Extra-data identifier, used to pass context into the verify callback. */ +-static int ssl_ex_context_id = -1; +-static int ssl_ex_conn_id = -1; +-#endif +- +-void +-k5_sendto_kdc_initialize(void) ++/* Set up context->tls. On allocation failure, return ENOMEM. On plugin load ++ * failure, set context->tls to point to a nulled vtable and return 0. */ ++static krb5_error_code ++init_tls_vtable(krb5_context context) + { +-#ifdef PROXY_TLS_IMPL_OPENSSL +- SSL_library_init(); +- SSL_load_error_strings(); +- OpenSSL_add_all_algorithms(); ++ krb5_plugin_initvt_fn initfn; + +- ssl_ex_context_id = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); +- ssl_ex_conn_id = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); +-#endif ++ if (context->tls != NULL) ++ return 0; ++ ++ context->tls = calloc(1, sizeof(*context->tls)); ++ if (context->tls == NULL) ++ return ENOMEM; ++ ++ /* Attempt to load the module; just let it stay nulled out on failure. */ ++ k5_plugin_register_dyn(context, PLUGIN_INTERFACE_TLS, "k5tls", "tls"); ++ if (k5_plugin_load(context, PLUGIN_INTERFACE_TLS, "k5tls", &initfn) == 0) ++ (*initfn)(context, 0, 0, (krb5_plugin_vtable)context->tls); ++ ++ return 0; + } + + /* Get current time in milliseconds. */ +@@ -184,21 +177,15 @@ get_curtime_ms(time_ms *time_out) + return 0; + } + +-#ifdef PROXY_TLS_IMPL_OPENSSL + static void +-free_http_ssl_data(struct conn_state *state) ++free_http_tls_data(krb5_context context, struct conn_state *state) + { +- SSL_free(state->http.ssl); +- state->http.ssl = NULL; ++ if (state->http.tls != NULL) ++ context->tls->free_handle(context, state->http.tls); ++ state->http.tls = NULL; + free(state->http.https_request); + state->http.https_request = NULL; + } +-#else +-static void +-free_http_ssl_data(struct conn_state *state) +-{ +-} +-#endif + + #ifdef USE_POLL + +@@ -532,7 +519,6 @@ static fd_handler_fn service_udp_read; + static fd_handler_fn service_https_write; + static fd_handler_fn service_https_read; + +-#ifdef PROXY_TLS_IMPL_OPENSSL + static krb5_error_code + make_proxy_request(struct conn_state *state, const krb5_data *realm, + const krb5_data *message, char **req_out, size_t *len_out) +@@ -585,14 +571,6 @@ cleanup: + krb5_free_data(NULL, encoded_pm); + return ret; + } +-#else +-static krb5_error_code +-make_proxy_request(struct conn_state *state, const krb5_data *realm, +- const krb5_data *message, char **req_out, size_t *len_out) +-{ +- abort(); +-} +-#endif + + /* Set up the actual message we will send across the underlying transport to + * communicate the payload message, using one or both of state->out.sgbuf. */ +@@ -963,7 +941,7 @@ static void + kill_conn(krb5_context context, struct conn_state *conn, + struct select_state *selstate) + { +- free_http_ssl_data(conn); ++ free_http_tls_data(context, conn); + + if (socktype_for_transport(conn->addr.transport) == SOCK_STREAM) + TRACE_SENDTO_KDC_TCP_DISCONNECT(context, &conn->addr); +@@ -1145,249 +1123,44 @@ service_udp_read(krb5_context context, const krb5_data *realm, + return TRUE; + } + +-#ifdef PROXY_TLS_IMPL_OPENSSL +-/* Output any error strings that OpenSSL's accumulated as tracing messages. */ +-static void +-flush_ssl_errors(krb5_context context) +-{ +- unsigned long err; +- char buf[128]; +- +- while ((err = ERR_get_error()) != 0) { +- ERR_error_string_n(err, buf, sizeof(buf)); +- TRACE_SENDTO_KDC_HTTPS_ERROR(context, buf); +- } +-} +- +-static krb5_error_code +-load_http_anchor_file(X509_STORE *store, const char *path) +-{ +- FILE *fp; +- STACK_OF(X509_INFO) *sk = NULL; +- X509_INFO *xi; +- int i; +- +- fp = fopen(path, "r"); +- if (fp == NULL) +- return errno; +- sk = PEM_X509_INFO_read(fp, NULL, NULL, NULL); +- fclose(fp); +- if (sk == NULL) +- return ENOENT; +- for (i = 0; i < sk_X509_INFO_num(sk); i++) { +- xi = sk_X509_INFO_value(sk, i); +- if (xi->x509 != NULL) +- X509_STORE_add_cert(store, xi->x509); +- } +- sk_X509_INFO_pop_free(sk, X509_INFO_free); +- return 0; +-} +- +-static krb5_error_code +-load_http_anchor_dir(X509_STORE *store, const char *path) +-{ +- DIR *d = NULL; +- struct dirent *dentry = NULL; +- char filename[1024]; +- krb5_boolean found_any = FALSE; +- +- d = opendir(path); +- if (d == NULL) +- return ENOENT; +- while ((dentry = readdir(d)) != NULL) { +- if (dentry->d_name[0] != '.') { +- snprintf(filename, sizeof(filename), "%s/%s", +- path, dentry->d_name); +- if (load_http_anchor_file(store, filename) == 0) +- found_any = TRUE; +- } +- } +- closedir(d); +- return found_any ? 0 : ENOENT; +-} +- +-static krb5_error_code +-load_http_anchor(SSL_CTX *ctx, const char *location) ++/* Set up conn->http.tls. Return true on success. */ ++static krb5_boolean ++setup_tls(krb5_context context, const krb5_data *realm, ++ struct conn_state *conn, struct select_state *selstate) + { +- X509_STORE *store; +- const char *envloc; +- +- store = SSL_CTX_get_cert_store(ctx); +- if (strncmp(location, "FILE:", 5) == 0) { +- return load_http_anchor_file(store, location + 5); +- } else if (strncmp(location, "DIR:", 4) == 0) { +- return load_http_anchor_dir(store, location + 4); +- } else if (strncmp(location, "ENV:", 4) == 0) { +- envloc = getenv(location + 4); +- if (envloc == NULL) +- return ENOENT; +- return load_http_anchor(ctx, envloc); +- } +- return EINVAL; +-} ++ krb5_error_code ret; ++ krb5_boolean ok = FALSE; ++ char **anchors = NULL, *realmstr = NULL; ++ const char *names[4]; + +-static krb5_error_code +-load_http_verify_anchors(krb5_context context, const krb5_data *realm, +- SSL_CTX *sctx) +-{ +- const char *anchors[4]; +- char **values = NULL, *realmz; +- unsigned int i; +- krb5_error_code err; ++ if (init_tls_vtable(context) != 0 || context->tls->setup == NULL) ++ return FALSE; + +- realmz = k5memdup0(realm->data, realm->length, &err); +- if (realmz == NULL) ++ realmstr = k5memdup0(realm->data, realm->length, &ret); ++ if (realmstr == NULL) + goto cleanup; + + /* Load the configured anchors. */ +- anchors[0] = KRB5_CONF_REALMS; +- anchors[1] = realmz; +- anchors[2] = KRB5_CONF_HTTP_ANCHORS; +- anchors[3] = NULL; +- if (profile_get_values(context->profile, anchors, &values) == 0) { +- for (i = 0; values[i] != NULL; i++) { +- err = load_http_anchor(sctx, values[i]); +- if (err != 0) +- break; +- } +- profile_free_list(values); +- } else { +- /* Use the library defaults. */ +- if (SSL_CTX_set_default_verify_paths(sctx) != 1) +- err = ENOENT; +- } +- +-cleanup: +- free(realmz); +- return err; +-} +- +-static krb5_boolean +-ssl_check_name_or_ip(X509 *x, const char *expected_name) +-{ +- struct in_addr in; +- struct in6_addr in6; +- +- if (inet_aton(expected_name, &in) != 0 || +- inet_pton(AF_INET6, expected_name, &in6) != 0) { +- return k5_check_cert_address(x, expected_name); +- } else { +- return k5_check_cert_servername(x, expected_name); +- } +-} ++ names[0] = KRB5_CONF_REALMS; ++ names[1] = realmstr; ++ names[2] = KRB5_CONF_HTTP_ANCHORS; ++ names[3] = NULL; ++ ret = profile_get_values(context->profile, names, &anchors); ++ if (ret != 0 && ret != PROF_NO_RELATION) ++ goto cleanup; + +-static int +-ssl_verify_callback(int preverify_ok, X509_STORE_CTX *store_ctx) +-{ +- X509 *x; +- SSL *ssl; +- BIO *bio; +- krb5_context context; +- int err, depth; +- struct conn_state *conn = NULL; +- const char *cert = NULL, *errstr, *expected_name; +- size_t count; +- +- ssl = X509_STORE_CTX_get_ex_data(store_ctx, +- SSL_get_ex_data_X509_STORE_CTX_idx()); +- context = SSL_get_ex_data(ssl, ssl_ex_context_id); +- conn = SSL_get_ex_data(ssl, ssl_ex_conn_id); +- /* We do have the peer's cert, right? */ +- x = X509_STORE_CTX_get_current_cert(store_ctx); +- if (x == NULL) { +- TRACE_SENDTO_KDC_HTTPS_NO_REMOTE_CERTIFICATE(context); +- return 0; +- } +- /* Figure out where we are. */ +- depth = X509_STORE_CTX_get_error_depth(store_ctx); +- if (depth < 0) +- return 0; +- /* If there's an error at this level that we're not ignoring, fail. */ +- err = X509_STORE_CTX_get_error(store_ctx); +- if (err != X509_V_OK) { +- bio = BIO_new(BIO_s_mem()); +- if (bio != NULL) { +- X509_NAME_print_ex(bio, x->cert_info->subject, 0, 0); +- count = BIO_get_mem_data(bio, &cert); +- errstr = X509_verify_cert_error_string(err); +- TRACE_SENDTO_KDC_HTTPS_PROXY_CERTIFICATE_ERROR(context, depth, +- count, cert, err, +- errstr); +- BIO_free(bio); +- } +- return 0; +- } +- /* If we're not looking at the peer, we're done and everything's ok. */ +- if (depth != 0) +- return 1; +- /* Check if the name we expect to find is in the certificate. */ +- expected_name = conn->http.servername; +- if (ssl_check_name_or_ip(x, expected_name)) { +- TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MATCH(context, expected_name); +- return 1; +- } else { +- TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MISMATCH(context, expected_name); ++ if (context->tls->setup(context, conn->fd, conn->http.servername, anchors, ++ &conn->http.tls) != 0) { ++ TRACE_SENDTO_KDC_HTTPS_ERROR_CONNECT(context, &conn->addr); ++ goto cleanup; + } +- /* The name didn't match. */ +- return 0; +-} + +-/* +- * Set up structures that we use to manage the SSL handling for this connection +- * and apply any non-default settings. Kill the connection and return false if +- * anything goes wrong while we're doing that; return true otherwise. +- */ +-static krb5_boolean +-setup_ssl(krb5_context context, const krb5_data *realm, +- struct conn_state *conn, struct select_state *selstate) +-{ +- int e; +- long options; +- SSL_CTX *ctx = NULL; +- SSL *ssl = NULL; ++ ok = TRUE; + +- if (ssl_ex_context_id == -1 || ssl_ex_conn_id == -1) +- goto kill_conn; +- +- /* Do general SSL library setup. */ +- ctx = SSL_CTX_new(SSLv23_client_method()); +- if (ctx == NULL) +- goto kill_conn; +- options = SSL_CTX_get_options(ctx); +- SSL_CTX_set_options(ctx, options | SSL_OP_NO_SSLv2); +- +- SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, ssl_verify_callback); +- X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), 0); +- e = load_http_verify_anchors(context, realm, ctx); +- if (e != 0) +- goto kill_conn; +- +- ssl = SSL_new(ctx); +- if (ssl == NULL) +- goto kill_conn; +- +- if (!SSL_set_ex_data(ssl, ssl_ex_context_id, context)) +- goto kill_conn; +- if (!SSL_set_ex_data(ssl, ssl_ex_conn_id, conn)) +- goto kill_conn; +- +- /* Tell the SSL library about the socket. */ +- if (!SSL_set_fd(ssl, conn->fd)) +- goto kill_conn; +- SSL_set_connect_state(ssl); +- +- SSL_CTX_free(ctx); +- conn->http.ssl = ssl; +- +- return TRUE; +- +-kill_conn: +- TRACE_SENDTO_KDC_HTTPS_ERROR_CONNECT(context, &conn->addr); +- flush_ssl_errors(context); +- SSL_free(ssl); +- SSL_CTX_free(ctx); +- kill_conn(context, conn, selstate); +- return FALSE; ++cleanup: ++ free(realmstr); ++ profile_free_list(anchors); ++ return ok; + } + + /* Set conn->state to READING when done; otherwise, call a cm_set_. */ +@@ -1395,50 +1168,41 @@ static krb5_boolean + service_https_write(krb5_context context, const krb5_data *realm, + struct conn_state *conn, struct select_state *selstate) + { +- ssize_t nwritten; +- int e; ++ k5_tls_status st; + + /* If this is our first time in here, set up the SSL context. */ +- if (conn->http.ssl == NULL && !setup_ssl(context, realm, conn, selstate)) ++ if (conn->http.tls == NULL && !setup_tls(context, realm, conn, selstate)) { ++ kill_conn(context, conn, selstate); + return FALSE; ++ } + + /* Try to transmit our request to the server. */ +- nwritten = SSL_write(conn->http.ssl, SG_BUF(conn->out.sgp), +- SG_LEN(conn->out.sgbuf)); +- if (nwritten <= 0) { +- e = SSL_get_error(conn->http.ssl, nwritten); +- if (e == SSL_ERROR_WANT_READ) { +- cm_read(selstate, conn->fd); +- return FALSE; +- } else if (e == SSL_ERROR_WANT_WRITE) { +- cm_write(selstate, conn->fd); +- return FALSE; +- } ++ st = context->tls->write(context, conn->http.tls, SG_BUF(conn->out.sgp), ++ SG_LEN(conn->out.sgbuf)); ++ if (st == DONE) { ++ TRACE_SENDTO_KDC_HTTPS_SEND(context, &conn->addr); ++ cm_read(selstate, conn->fd); ++ conn->state = READING; ++ } else if (st == WANT_READ) { ++ cm_read(selstate, conn->fd); ++ } else if (st == WANT_WRITE) { ++ cm_write(selstate, conn->fd); ++ } else if (st == ERROR_TLS) { + TRACE_SENDTO_KDC_HTTPS_ERROR_SEND(context, &conn->addr); +- flush_ssl_errors(context); + kill_conn(context, conn, selstate); +- return FALSE; + } + +- /* Done writing, switch to reading. */ +- TRACE_SENDTO_KDC_HTTPS_SEND(context, &conn->addr); +- cm_read(selstate, conn->fd); +- conn->state = READING; + return FALSE; + } + +-/* +- * Return true on readable data, call a cm_read/write function and return +- * false if the SSL layer needs it, kill the connection otherwise. +- */ ++/* Return true on finished data. Call a cm_read/write function and return ++ * false if the TLS layer needs it. Kill the connection on error. */ + static krb5_boolean + https_read_bytes(krb5_context context, struct conn_state *conn, + struct select_state *selstate) + { +- size_t bufsize; +- ssize_t nread; +- krb5_boolean readbytes = FALSE; +- int e = 0; ++ size_t bufsize, nread; ++ k5_tls_status st; + char *tmp; + struct incoming_message *in = &conn->in; + +@@ -1458,31 +1222,26 @@ https_read_bytes(krb5_context context, struct conn_state *conn, + in->bufsize = bufsize; + } + +- nread = SSL_read(conn->http.ssl, &in->buf[in->pos], +- in->bufsize - in->pos - 1); +- if (nread <= 0) ++ st = context->tls->read(context, conn->http.tls, &in->buf[in->pos], ++ in->bufsize - in->pos - 1, &nread); ++ if (st != DATA_READ) + break; ++ + in->pos += nread; + in->buf[in->pos] = '\0'; +- readbytes = TRUE; + } + +- e = SSL_get_error(conn->http.ssl, nread); +- if (e == SSL_ERROR_WANT_READ) { ++ if (st == DONE) ++ return TRUE; ++ ++ if (st == WANT_READ) { + cm_read(selstate, conn->fd); +- return FALSE; +- } else if (e == SSL_ERROR_WANT_WRITE) { ++ } else if (st == WANT_WRITE) { + cm_write(selstate, conn->fd); +- return FALSE; +- } else if ((e == SSL_ERROR_ZERO_RETURN) || +- (e == SSL_ERROR_SYSCALL && nread == 0 && readbytes)) { +- return TRUE; ++ } else if (st == ERROR_TLS) { ++ TRACE_SENDTO_KDC_HTTPS_ERROR_RECV(context, &conn->addr); ++ kill_conn(context, conn, selstate); + } +- +- e = readbytes ? SOCKET_ERRNO : ECONNRESET; +- TRACE_SENDTO_KDC_HTTPS_ERROR_RECV(context, &conn->addr, e); +- flush_ssl_errors(context); +- kill_conn(context, conn, selstate); + return FALSE; + } + +@@ -1531,20 +1290,6 @@ kill_conn: + kill_conn(context, conn, selstate); + return FALSE; + } +-#else +-static krb5_boolean +-service_https_write(krb5_context context, const krb5_data *realm, +- struct conn_state *conn, struct select_state *selstate) +-{ +- abort(); +-} +-static krb5_boolean +-service_https_read(krb5_context context, const krb5_data *realm, +- struct conn_state *conn, struct select_state *selstate) +-{ +- abort(); +-} +-#endif + + /* Return the maximum of endtime and the endtime fields of all currently active + * TCP connections. */ +@@ -1765,7 +1510,7 @@ cleanup: + if (socktype_for_transport(state->addr.transport) == SOCK_STREAM) + TRACE_SENDTO_KDC_TCP_DISCONNECT(context, &state->addr); + closesocket(state->fd); +- free_http_ssl_data(state); ++ free_http_tls_data(context, state); + } + if (state->state == READING && state->in.buf != udpbuf) + free(state->in.buf); +diff --git a/src/plugins/tls/k5tls/Makefile.in b/src/plugins/tls/k5tls/Makefile.in +new file mode 100644 +index 0000000..4d58df0 +--- /dev/null ++++ b/src/plugins/tls/k5tls/Makefile.in +@@ -0,0 +1,22 @@ ++mydir=plugins$(S)tls$(S)k5tls ++BUILDTOP=$(REL)..$(S)..$(S).. ++MODULE_INSTALL_DIR = $(KRB5_TLS_MODULE_DIR) ++LOCALINCLUDES= $(PROXY_TLS_IMPL_CFLAGS) ++ ++LIBBASE=k5tls ++LIBMAJOR=0 ++LIBMINOR=0 ++RELDIR=../plugins/tls/k5tls ++SHLIB_EXPDEPS= $(KRB5_DEPLIB) $(SUPPORT_DEPLIB) ++SHLIB_EXPLIBS= $(KRB5_LIB) $(SUPPORT_LIB) $(PROXY_TLS_IMPL_LIBS) ++ ++STLIBOBJS=openssl.o notls.o ++ ++SRCS=$(srcdir)/openssl.c $(srcdir)/notls.c ++ ++all-unix:: all-liblinks ++install-unix:: install-libs ++clean-unix:: clean-libs clean-libobjs ++ ++@libnover_frag@ ++@libobj_frag@ +diff --git a/src/plugins/tls/k5tls/deps b/src/plugins/tls/k5tls/deps +new file mode 100644 +index 0000000..a6088a7 +--- /dev/null ++++ b/src/plugins/tls/k5tls/deps +@@ -0,0 +1,25 @@ ++# ++# Generated makefile dependencies follow. ++# ++openssl.so openssl.po $(OUTPRE)openssl.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ ++ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ ++ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ ++ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ ++ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-tls.h \ ++ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/k5-utf8.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 openssl.c ++notls.so notls.po $(OUTPRE)notls.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ ++ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ ++ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ ++ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ ++ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-tls.h \ ++ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/k5-utf8.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 notls.c +diff --git a/src/plugins/tls/k5tls/k5tls.exports b/src/plugins/tls/k5tls/k5tls.exports +new file mode 100644 +index 0000000..d67d928 +--- /dev/null ++++ b/src/plugins/tls/k5tls/k5tls.exports +@@ -0,0 +1 @@ ++tls_k5tls_initvt +diff --git a/src/plugins/tls/k5tls/notls.c b/src/plugins/tls/k5tls/notls.c +new file mode 100644 +index 0000000..7be0a4a +--- /dev/null ++++ b/src/plugins/tls/k5tls/notls.c +@@ -0,0 +1,53 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* plus/tls/k5tls/none.c - Stub TLS module implementation */ ++/* ++ * Copyright (C) 2014 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 dummy module is used if no TLS implemented is selected. */ ++ ++#include "k5-int.h" ++#include "k5-utf8.h" ++#include "k5-tls.h" ++ ++#ifdef PROXY_TLS_IMPL_NONE ++ ++krb5_error_code ++tls_k5tls_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable); ++ ++krb5_error_code ++tls_k5tls_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable) ++{ ++ /* Leave all vtable functions nulled. */ ++ return 0; ++} ++ ++#endif /* PROXY_TLS_IMPL_NONE */ +diff --git a/src/plugins/tls/k5tls/openssl.c b/src/plugins/tls/k5tls/openssl.c +new file mode 100644 +index 0000000..0691a34 +--- /dev/null ++++ b/src/plugins/tls/k5tls/openssl.c +@@ -0,0 +1,570 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* plugins/tls/k5tls/openssl.c - OpenSSL TLS module implementation */ ++/* ++ * Copyright 2013,2014 Red Hat, Inc. ++ * ++ * 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-utf8.h" ++#include "k5-tls.h" ++ ++#ifdef PROXY_TLS_IMPL_OPENSSL ++#include ++#include ++#include ++#include ++#include ++ ++struct k5_tls_handle_st { ++ SSL *ssl; ++ char *servername; ++}; ++ ++static int ex_context_id = -1; ++static int ex_handle_id = -1; ++ ++MAKE_INIT_FUNCTION(init_openssl); ++ ++int ++init_openssl() ++{ ++ SSL_library_init(); ++ SSL_load_error_strings(); ++ OpenSSL_add_all_algorithms(); ++ ex_context_id = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); ++ ex_handle_id = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); ++ return 0; ++} ++ ++static void ++flush_errors(krb5_context context) ++{ ++ unsigned long err; ++ char buf[128]; ++ ++ while ((err = ERR_get_error()) != 0) { ++ ERR_error_string_n(err, buf, sizeof(buf)); ++ TRACE_TLS_ERROR(context, buf); ++ } ++} ++ ++/* Return the passed-in character, lower-cased if it's an ASCII character. */ ++static inline char ++ascii_tolower(char p) ++{ ++ if (KRB5_UPPER(p)) ++ return p + ('a' - 'A'); ++ return p; ++} ++ ++/* ++ * Check a single label. If allow_wildcard is true, and the presented name ++ * includes a wildcard, return true and note that we matched a wildcard. ++ * Otherwise, for both the presented and expected values, do a case-insensitive ++ * comparison of ASCII characters, and a case-sensitive comparison of ++ * everything else. ++ */ ++static krb5_boolean ++label_match(const char *presented, size_t plen, const char *expected, ++ size_t elen, krb5_boolean allow_wildcard, krb5_boolean *wildcard) ++{ ++ unsigned int i; ++ ++ if (allow_wildcard && plen == 1 && presented[0] == '*') { ++ *wildcard = TRUE; ++ return TRUE; ++ } ++ ++ if (plen != elen) ++ return FALSE; ++ ++ for (i = 0; i < elen; i++) { ++ if (ascii_tolower(presented[i]) != ascii_tolower(expected[i])) ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++/* Break up the two names and check them, label by label. */ ++static krb5_boolean ++domain_match(const char *presented, size_t plen, const char *expected) ++{ ++ const char *p, *q, *r, *s; ++ int n_label; ++ krb5_boolean used_wildcard = FALSE; ++ ++ n_label = 0; ++ p = presented; ++ r = expected; ++ while (p < presented + plen && *r != '\0') { ++ q = memchr(p, '.', plen - (p - presented)); ++ if (q == NULL) ++ q = presented + plen; ++ s = r + strcspn(r, "."); ++ if (!label_match(p, q - p, r, s - r, n_label == 0, &used_wildcard)) ++ return FALSE; ++ p = q < presented + plen ? q + 1 : q; ++ r = *s ? s + 1 : s; ++ n_label++; ++ } ++ if (used_wildcard && n_label <= 2) ++ return FALSE; ++ if (p == presented + plen && *r == '\0') ++ return TRUE; ++ return FALSE; ++} ++ ++/* Fetch the list of subjectAltNames from a certificate. */ ++static GENERAL_NAMES * ++get_cert_sans(X509 *x) ++{ ++ int ext; ++ X509_EXTENSION *san_ext; ++ ++ ext = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); ++ if (ext < 0) ++ return NULL; ++ san_ext = X509_get_ext(x, ext); ++ if (san_ext == NULL) ++ return NULL; ++ return X509V3_EXT_d2i(san_ext); ++} ++ ++/* Fetch a CN value from the subjct name field, returning its length, or -1 if ++ * there is no subject name or it contains no CN value. */ ++static int ++get_cert_cn(X509 *x, char *buf, size_t bufsize) ++{ ++ X509_NAME *name; ++ ++ name = X509_get_subject_name(x); ++ if (name == NULL) ++ return -1; ++ return X509_NAME_get_text_by_NID(name, NID_commonName, buf, bufsize); ++} ++ ++/* Return true if text matches any of the addresses we can recover from x. */ ++static krb5_boolean ++check_cert_address(X509 *x, const char *text) ++{ ++ char buf[1024]; ++ GENERAL_NAMES *sans; ++ GENERAL_NAME *san = NULL; ++ ASN1_OCTET_STRING *ip; ++ krb5_boolean found_ip_san = FALSE, matched = FALSE; ++ int n_sans, i; ++ int name_length; ++ struct in_addr sin; ++ struct in6_addr sin6; ++ ++ /* Parse the IP address into an octet string. */ ++ ip = M_ASN1_OCTET_STRING_new(); ++ if (ip == NULL) ++ return FALSE; ++ if (inet_pton(AF_INET, text, &sin)) { ++ M_ASN1_OCTET_STRING_set(ip, &sin, sizeof(sin)); ++ } else if (inet_pton(AF_INET6, text, &sin6)) { ++ M_ASN1_OCTET_STRING_set(ip, &sin6, sizeof(sin6)); ++ } else { ++ ASN1_OCTET_STRING_free(ip); ++ return FALSE; ++ } ++ ++ /* Check for matches in ipaddress subjectAltName values. */ ++ sans = get_cert_sans(x); ++ if (sans != NULL) { ++ n_sans = sk_GENERAL_NAME_num(sans); ++ for (i = 0; i < n_sans; i++) { ++ san = sk_GENERAL_NAME_value(sans, i); ++ if (san->type != GEN_IPADD) ++ continue; ++ found_ip_san = TRUE; ++ matched = (ASN1_OCTET_STRING_cmp(ip, san->d.iPAddress) == 0); ++ if (matched) ++ break; ++ } ++ sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free); ++ } ++ ASN1_OCTET_STRING_free(ip); ++ ++ if (found_ip_san) ++ return matched; ++ ++ /* Check for a match against the CN value in the peer's subject name. */ ++ name_length = get_cert_cn(x, buf, sizeof(buf)); ++ if (name_length >= 0) { ++ /* Do a string compare to check if it's an acceptable value. */ ++ return strlen(text) == (size_t)name_length && ++ strncmp(text, buf, name_length) == 0; ++ } ++ ++ /* We didn't find a match. */ ++ return FALSE; ++} ++ ++/* Return true if expected matches any of the names we can recover from x. */ ++static krb5_boolean ++check_cert_servername(X509 *x, const char *expected) ++{ ++ char buf[1024]; ++ GENERAL_NAMES *sans; ++ GENERAL_NAME *san = NULL; ++ unsigned char *dnsname; ++ krb5_boolean found_dns_san = FALSE, matched = FALSE; ++ int name_length, n_sans, i; ++ ++ /* Check for matches in dnsname subjectAltName values. */ ++ sans = get_cert_sans(x); ++ if (sans != NULL) { ++ n_sans = sk_GENERAL_NAME_num(sans); ++ for (i = 0; i < n_sans; i++) { ++ san = sk_GENERAL_NAME_value(sans, i); ++ if (san->type != GEN_DNS) ++ continue; ++ found_dns_san = TRUE; ++ dnsname = NULL; ++ name_length = ASN1_STRING_to_UTF8(&dnsname, san->d.dNSName); ++ if (dnsname == NULL) ++ continue; ++ matched = domain_match((char *)dnsname, name_length, expected); ++ OPENSSL_free(dnsname); ++ if (matched) ++ break; ++ } ++ sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free); ++ } ++ ++ if (matched) ++ return TRUE; ++ if (found_dns_san) ++ return matched; ++ ++ /* Check for a match against the CN value in the peer's subject name. */ ++ name_length = get_cert_cn(x, buf, sizeof(buf)); ++ if (name_length >= 0) ++ return domain_match(buf, name_length, expected); ++ ++ /* We didn't find a match. */ ++ return FALSE; ++} ++ ++static krb5_boolean ++check_cert_name_or_ip(X509 *x, const char *expected_name) ++{ ++ struct in_addr in; ++ struct in6_addr in6; ++ ++ if (inet_pton(AF_INET, expected_name, &in) != 0 || ++ inet_pton(AF_INET6, expected_name, &in6) != 0) { ++ return check_cert_address(x, expected_name); ++ } else { ++ return check_cert_servername(x, expected_name); ++ } ++} ++ ++static int ++verify_callback(int preverify_ok, X509_STORE_CTX *store_ctx) ++{ ++ X509 *x; ++ SSL *ssl; ++ BIO *bio; ++ krb5_context context; ++ int err, depth; ++ k5_tls_handle handle; ++ const char *cert = NULL, *errstr, *expected_name; ++ size_t count; ++ ++ ssl = X509_STORE_CTX_get_ex_data(store_ctx, ++ SSL_get_ex_data_X509_STORE_CTX_idx()); ++ context = SSL_get_ex_data(ssl, ex_context_id); ++ handle = SSL_get_ex_data(ssl, ex_handle_id); ++ assert(context != NULL && handle != NULL); ++ /* We do have the peer's cert, right? */ ++ x = X509_STORE_CTX_get_current_cert(store_ctx); ++ if (x == NULL) { ++ TRACE_TLS_NO_REMOTE_CERTIFICATE(context); ++ return 0; ++ } ++ /* Figure out where we are. */ ++ depth = X509_STORE_CTX_get_error_depth(store_ctx); ++ if (depth < 0) ++ return 0; ++ /* If there's an error at this level that we're not ignoring, fail. */ ++ err = X509_STORE_CTX_get_error(store_ctx); ++ if (err != X509_V_OK) { ++ bio = BIO_new(BIO_s_mem()); ++ if (bio != NULL) { ++ X509_NAME_print_ex(bio, x->cert_info->subject, 0, 0); ++ count = BIO_get_mem_data(bio, &cert); ++ errstr = X509_verify_cert_error_string(err); ++ TRACE_TLS_CERT_ERROR(context, depth, count, cert, err, errstr); ++ BIO_free(bio); ++ } ++ return 0; ++ } ++ /* If we're not looking at the peer, we're done and everything's ok. */ ++ if (depth != 0) ++ return 1; ++ /* Check if the name we expect to find is in the certificate. */ ++ expected_name = handle->servername; ++ if (check_cert_name_or_ip(x, expected_name)) { ++ TRACE_TLS_SERVER_NAME_MATCH(context, expected_name); ++ return 1; ++ } else { ++ TRACE_TLS_SERVER_NAME_MISMATCH(context, expected_name); ++ } ++ /* The name didn't match. */ ++ return 0; ++} ++ ++static krb5_error_code ++load_anchor_file(X509_STORE *store, const char *path) ++{ ++ FILE *fp; ++ STACK_OF(X509_INFO) *sk = NULL; ++ X509_INFO *xi; ++ int i; ++ ++ fp = fopen(path, "r"); ++ if (fp == NULL) ++ return errno; ++ sk = PEM_X509_INFO_read(fp, NULL, NULL, NULL); ++ fclose(fp); ++ if (sk == NULL) ++ return ENOENT; ++ for (i = 0; i < sk_X509_INFO_num(sk); i++) { ++ xi = sk_X509_INFO_value(sk, i); ++ if (xi->x509 != NULL) ++ X509_STORE_add_cert(store, xi->x509); ++ } ++ sk_X509_INFO_pop_free(sk, X509_INFO_free); ++ return 0; ++} ++ ++static krb5_error_code ++load_anchor_dir(X509_STORE *store, const char *path) ++{ ++ DIR *d = NULL; ++ struct dirent *dentry = NULL; ++ char filename[1024]; ++ krb5_boolean found_any = FALSE; ++ ++ d = opendir(path); ++ if (d == NULL) ++ return ENOENT; ++ while ((dentry = readdir(d)) != NULL) { ++ if (dentry->d_name[0] != '.') { ++ snprintf(filename, sizeof(filename), "%s/%s", ++ path, dentry->d_name); ++ if (load_anchor_file(store, filename) == 0) ++ found_any = TRUE; ++ } ++ } ++ closedir(d); ++ return found_any ? 0 : ENOENT; ++} ++ ++static krb5_error_code ++load_anchor(SSL_CTX *ctx, const char *location) ++{ ++ X509_STORE *store; ++ const char *envloc; ++ ++ store = SSL_CTX_get_cert_store(ctx); ++ if (strncmp(location, "FILE:", 5) == 0) { ++ return load_anchor_file(store, location + 5); ++ } else if (strncmp(location, "DIR:", 4) == 0) { ++ return load_anchor_dir(store, location + 4); ++ } else if (strncmp(location, "ENV:", 4) == 0) { ++ envloc = getenv(location + 4); ++ if (envloc == NULL) ++ return ENOENT; ++ return load_anchor(ctx, envloc); ++ } ++ return EINVAL; ++} ++ ++static krb5_error_code ++load_anchors(krb5_context context, char **anchors, SSL_CTX *sctx) ++{ ++ unsigned int i; ++ krb5_error_code ret; ++ ++ if (anchors != NULL) { ++ for (i = 0; anchors[i] != NULL; i++) { ++ ret = load_anchor(sctx, anchors[i]); ++ if (ret) ++ return ret; ++ } ++ } else { ++ /* Use the library defaults. */ ++ if (SSL_CTX_set_default_verify_paths(sctx) != 1) ++ return ENOENT; ++ } ++ ++ return 0; ++} ++ ++static krb5_error_code ++setup(krb5_context context, SOCKET fd, const char *servername, ++ char **anchors, k5_tls_handle *handle_out) ++{ ++ int e; ++ long options; ++ SSL_CTX *ctx = NULL; ++ SSL *ssl = NULL; ++ k5_tls_handle handle = NULL; ++ ++ *handle_out = NULL; ++ ++ (void)CALL_INIT_FUNCTION(init_openssl); ++ if (ex_context_id == -1 || ex_handle_id == -1) ++ return KRB5_PLUGIN_OP_NOTSUPP; ++ ++ /* Do general SSL library setup. */ ++ ctx = SSL_CTX_new(SSLv23_client_method()); ++ if (ctx == NULL) ++ goto error; ++ options = SSL_CTX_get_options(ctx); ++ SSL_CTX_set_options(ctx, options | SSL_OP_NO_SSLv2); ++ ++ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback); ++ X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), 0); ++ e = load_anchors(context, anchors, ctx); ++ if (e != 0) ++ goto error; ++ ++ ssl = SSL_new(ctx); ++ if (ssl == NULL) ++ goto error; ++ ++ if (!SSL_set_fd(ssl, fd)) ++ goto error; ++ SSL_set_connect_state(ssl); ++ ++ /* Create a handle and allow verify_callback to access it. */ ++ handle = malloc(sizeof(*handle)); ++ if (handle == NULL || !SSL_set_ex_data(ssl, ex_handle_id, handle)) ++ goto error; ++ ++ handle->ssl = ssl; ++ handle->servername = strdup(servername); ++ if (handle->servername == NULL) ++ goto error; ++ *handle_out = handle; ++ SSL_CTX_free(ctx); ++ return 0; ++ ++error: ++ flush_errors(context); ++ free(handle); ++ SSL_free(ssl); ++ SSL_CTX_free(ctx); ++ return KRB5_PLUGIN_OP_NOTSUPP; ++} ++ ++static k5_tls_status ++write_tls(krb5_context context, k5_tls_handle handle, const void *data, ++ size_t len) ++{ ++ int nwritten, e; ++ ++ /* Try to transmit our request; allow verify_callback to access context. */ ++ if (!SSL_set_ex_data(handle->ssl, ex_context_id, context)) ++ return ERROR_TLS; ++ nwritten = SSL_write(handle->ssl, data, len); ++ (void)SSL_set_ex_data(handle->ssl, ex_context_id, NULL); ++ if (nwritten > 0) ++ return DONE; ++ ++ e = SSL_get_error(handle->ssl, nwritten); ++ if (e == SSL_ERROR_WANT_READ) ++ return WANT_READ; ++ else if (e == SSL_ERROR_WANT_WRITE) ++ return WANT_WRITE; ++ flush_errors(context); ++ return ERROR_TLS; ++} ++ ++static k5_tls_status ++read_tls(krb5_context context, k5_tls_handle handle, void *data, ++ size_t data_size, size_t *len_out) ++{ ++ ssize_t nread; ++ int e; ++ ++ *len_out = 0; ++ ++ /* Try to read response data; allow verify_callback to access context. */ ++ if (!SSL_set_ex_data(handle->ssl, ex_context_id, context)) ++ return ERROR_TLS; ++ nread = SSL_read(handle->ssl, data, data_size); ++ (void)SSL_set_ex_data(handle->ssl, ex_context_id, NULL); ++ if (nread > 0) { ++ *len_out = nread; ++ return DATA_READ; ++ } ++ ++ e = SSL_get_error(handle->ssl, nread); ++ if (e == SSL_ERROR_WANT_READ) ++ return WANT_READ; ++ else if (e == SSL_ERROR_WANT_WRITE) ++ return WANT_WRITE; ++ ++ if (e == SSL_ERROR_ZERO_RETURN || (e == SSL_ERROR_SYSCALL && nread == 0)) ++ return DONE; ++ ++ flush_errors(context); ++ return ERROR_TLS; ++} ++ ++static void ++free_handle(krb5_context context, k5_tls_handle handle) ++{ ++ SSL_free(handle->ssl); ++ free(handle->servername); ++ free(handle); ++} ++ ++krb5_error_code ++tls_k5tls_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable); ++ ++krb5_error_code ++tls_k5tls_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable) ++{ ++ k5_tls_vtable vt; ++ ++ vt = (k5_tls_vtable)vtable; ++ vt->setup = setup; ++ vt->write = write_tls; ++ vt->read = read_tls; ++ vt->free_handle = free_handle; ++ return 0; ++} ++ ++#endif /* PROXY_TLS_IMPL_OPENSSL */ diff --git a/SOURCES/krb5-1.13_kinit_C_loop_krb5bug243.patch b/SOURCES/krb5-1.13_kinit_C_loop_krb5bug243.patch new file mode 100644 index 0000000..f9aa870 --- /dev/null +++ b/SOURCES/krb5-1.13_kinit_C_loop_krb5bug243.patch @@ -0,0 +1,118 @@ +From d5755694b620570defeecee772def90a2733c6cc Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Tue, 20 Jan 2015 13:48:34 -0500 +Subject: [PATCH 1/2] Do not loop on principal unknown errors + +If the canonicalize flag is set, the MIT KDC always return the client +principal when KRB5_KDC_ERR_C_PRICIPAL_UNKNOWN is returned. + +Check that this is really a referral by testing that the returned +client realm differs from the requested one. + +[ghudson@mit.edu: simplified and narrowed is_referral() contract. +Note that a WRONG_REALM response with e-data or FAST error padata +could now be passed through k5_preauth_tryagain() if it has an empty +crealm or a crealm equal to the requested client realm. Such a +response is unexpected in practice and there is nothing dangerous +about handling it this way.] + +ticket: 8060 +target_version: 1.13.1 +tags: pullup +--- + src/lib/krb5/krb/get_in_tkt.c | 40 +++++++++++++--------------------------- + 1 file changed, 13 insertions(+), 27 deletions(-) + +diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c +index 2c2b654..f9bc027 100644 +--- a/src/lib/krb5/krb/get_in_tkt.c ++++ b/src/lib/krb5/krb/get_in_tkt.c +@@ -1379,33 +1379,23 @@ note_req_timestamp(krb5_context context, krb5_init_creds_context ctx, + AUTH_OFFSET : UNAUTH_OFFSET; + } + +-/* Determine whether the client realm in a KRB-ERROR is empty. */ +-static krb5_boolean +-is_empty_crealm(krb5_error *err) +-{ +- +- return (err->client == NULL || err->client->realm.length == 0); +-} +- + /* +- * Determine whether a KRB-ERROR is a referral to another realm. ++ * Determine whether err is a client referral to another realm, given the ++ * previously requested client principal name. + * +- * RFC 6806 Section 7 requires that KDCs return the referral realm in +- * an error type WRONG_REALM, but Microsoft Windows Server 2003 (and +- * possibly others) return the realm in a PRINCIPAL_UNKNOWN message. +- * Detect this case by looking for a non-empty client.realm field in +- * such responses. ++ * RFC 6806 Section 7 requires that KDCs return the referral realm in an error ++ * type WRONG_REALM, but Microsoft Windows Server 2003 (and possibly others) ++ * return the realm in a PRINCIPAL_UNKNOWN message. + */ + static krb5_boolean +-is_referral(krb5_init_creds_context ctx) ++is_referral(krb5_context context, krb5_error *err, krb5_principal client) + { +- krb5_error *err = ctx->err_reply; +- +- if (err->error == KDC_ERR_WRONG_REALM) +- return TRUE; +- if (err->error != KDC_ERR_C_PRINCIPAL_UNKNOWN) ++ if (err->error != KDC_ERR_WRONG_REALM && ++ err->error != KDC_ERR_C_PRINCIPAL_UNKNOWN) ++ return FALSE; ++ if (err->client == NULL) + return FALSE; +- return !is_empty_crealm(err); ++ return !krb5_realm_compare(context, err->client, client); + } + + static krb5_error_code +@@ -1467,12 +1457,8 @@ init_creds_step_reply(krb5_context context, + ctx->preauth_to_use); + ctx->preauth_required = TRUE; + +- } else if (canon_flag && is_referral(ctx)) { +- if (is_empty_crealm(ctx->err_reply)) { +- /* Only WRONG_REALM referral types can reach this. */ +- code = KRB5KDC_ERR_WRONG_REALM; +- goto cleanup; +- } ++ } else if (canon_flag && is_referral(context, ctx->err_reply, ++ ctx->request->client)) { + TRACE_INIT_CREDS_REFERRAL(context, &ctx->err_reply->client->realm); + /* Rewrite request.client with realm from error reply */ + krb5_free_data_contents(context, &ctx->request->client->realm); + +From c0778ab2252ece4c3510788d9b72f7f5e3bb05dd Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 23 Jan 2015 12:52:31 -0500 +Subject: [PATCH 2/2] Add test for kinit -C WRONG_REALM response + +ticket: 8060 +--- + src/tests/t_general.py | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/tests/t_general.py b/src/tests/t_general.py +index 98e77a2..5349b05 100755 +--- a/src/tests/t_general.py ++++ b/src/tests/t_general.py +@@ -33,6 +33,13 @@ + + realm = K5Realm(create_host=False) + ++# Test that WRONG_REALM responses aren't treated as referrals unless ++# they contain a crealm field pointing to a different realm. ++# (Regression test for #8060.) ++out = realm.run([kinit, '-C', 'notfoundprinc'], expected_code=1) ++if 'not found in Kerberos database' not in out: ++ fail('Expected error message not seen in kinit -C output') ++ + # Spot-check KRB5_TRACE output + tracefile = os.path.join(realm.testdir, 'trace') + realm.run(['env', 'KRB5_TRACE=' + tracefile, kinit, realm.user_princ], diff --git a/SOURCES/krb5-1.7-ktany.patch b/SOURCES/krb5-1.7-ktany.patch deleted file mode 100644 index 902f328..0000000 --- a/SOURCES/krb5-1.7-ktany.patch +++ /dev/null @@ -1,351 +0,0 @@ -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 deleted file mode 100644 index 9cc9cd2..0000000 --- a/SOURCES/krb5-1.8-api.patch +++ /dev/null @@ -1,30 +0,0 @@ -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-CVE-2013-1417.patch b/SOURCES/krb5-CVE-2013-1417.patch deleted file mode 100644 index 9b1d0b6..0000000 --- a/SOURCES/krb5-CVE-2013-1417.patch +++ /dev/null @@ -1,68 +0,0 @@ -commit 4c023ba43c16396f0d199e2df1cfa59b88b62acc -Author: Tom Yu -Date: Fri Jun 21 17:58:25 2013 -0400 - - KDC null deref due to referrals [CVE-2013-1417] - - An authenticated remote client can cause a KDC to crash by making a - valid TGS-REQ to a KDC serving a realm with a single-component name. - The process_tgs_req() function dereferences a null pointer because an - unusual failure condition causes a helper function to return success. - - While attempting to provide cross-realm referrals for host-based - service principals, the find_referral_tgs() function could return a - TGS principal for a zero-length realm name (indicating that the - hostname in the service principal has no known realm associated with - it). - - Subsequently, the find_alternate_tgs() function would attempt to - construct a path to this empty-string realm, and return success along - with a null pointer in its output parameter. This happens because - krb5_walk_realm_tree() returns a list of length one when it attempts - to construct a transit path between a single-component realm and the - empty-string realm. This list causes a loop in find_alternate_tgs() - to iterate over zero elements, resulting in the unexpected output of a - null pointer, which process_tgs_req() proceeds to dereference because - there is no error condition. - - Add an error condition to find_referral_tgs() when - krb5_get_host_realm() returns an empty realm name. Also add an error - condition to find_alternate_tgs() to handle the length-one output from - krb5_walk_realm_tree(). - - The vulnerable configuration is not likely to arise in practice. - (Realm names that have a single component are likely to be test - realms.) Releases prior to krb5-1.11 are not vulnerable. - - Thanks to Sol Jerome for reporting this problem. - - CVSSv2: AV:N/AC:M/Au:S/C:N/I:N/A:P/E:H/RL:O/RC:C - - (cherry picked from commit 3c7f1c21ffaaf6c90f1045f0f5440303c766acc0) - - ticket: 7668 - version_fixed: 1.11.4 - status: resolved - -diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c -index d41bc5d..745a48e 100644 ---- a/src/kdc/do_tgs_req.c -+++ b/src/kdc/do_tgs_req.c -@@ -1057,6 +1057,8 @@ find_alternate_tgs(kdc_realm_t *kdc_active_realm, krb5_principal princ, - goto cleanup; - } - cleanup: -+ if (retval == 0 && server_ptr == NULL) -+ retval = KRB5_KDB_NOENTRY; - if (retval != 0) - *status = "UNKNOWN_SERVER"; - -@@ -1149,7 +1151,7 @@ find_referral_tgs(kdc_realm_t *kdc_active_realm, krb5_kdc_req *request, - goto cleanup; - } - /* Don't return a referral to the empty realm or the service realm. */ -- if (realms == NULL || realms[0] == '\0' || -+ if (realms == NULL || realms[0] == NULL || *realms[0] == '\0' || - data_eq_string(srealm, realms[0])) { - retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; - goto cleanup; diff --git a/SOURCES/krb5-CVE_2014_5353_fix_LDAP_misused_policy_name_crash.patch b/SOURCES/krb5-CVE_2014_5353_fix_LDAP_misused_policy_name_crash.patch new file mode 100644 index 0000000..e96c360 --- /dev/null +++ b/SOURCES/krb5-CVE_2014_5353_fix_LDAP_misused_policy_name_crash.patch @@ -0,0 +1,63 @@ +From d1f707024f1d0af6e54a18885322d70fa15ec4d3 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 5 Dec 2014 14:01:39 -0500 +Subject: [PATCH] Fix LDAP misused policy name crash [CVE-2014-5353] + +In krb5_ldap_get_password_policy_from_dn, if LDAP_SEARCH returns +successfully with no results, return KRB5_KDB_NOENTRY instead of +returning success with a zeroed-out policy object. This fixes a null +dereference when an admin attempts to use an LDAP ticket policy name +as a password policy name. + +CVE-2014-5353: + +In MIT krb5, when kadmind is configured to use LDAP for the KDC +database, an authenticated remote attacker can cause a NULL dereference +by attempting to use a named ticket policy object as a password policy +for a principal. The attacker needs to be authenticated as a user who +has the elevated privilege for setting password policy by adding or +modifying principals. + +Queries to LDAP scoped to the krbPwdPolicy object class will correctly +not return entries of other classes, such as ticket policy objects, but +may return success with no returned elements if an object with the +requested DN exists in a different object class. In this case, the +routine to retrieve a password policy returned success with a password +policy object that consisted entirely of zeroed memory. In particular, +accesses to the policy name will dereference a NULL pointer. KDC +operation does not access the policy name field, but most kadmin +operations involving the principal with incorrect password policy +will trigger the crash. + +Thanks to Patrik Kis for reporting this problem. + +CVSSv2 Vector: AV:N/AC:M/Au:S/C:N/I:N/A:C/E:H/RL:OF/RC:C + +[kaduk@mit.edu: CVE description and CVSS score] + +ticket: 8051 (new) +target_version: 1.13.1 +tags: pullup +--- + src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c +index 522773e..6779f51 100644 +--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c ++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c +@@ -314,10 +314,11 @@ krb5_ldap_get_password_policy_from_dn(krb5_context context, char *pol_name, + LDAP_SEARCH(pol_dn, LDAP_SCOPE_BASE, "(objectclass=krbPwdPolicy)", password_policy_attributes); + + ent=ldap_first_entry(ld, result); +- if (ent != NULL) { +- if ((st = populate_policy(context, ld, ent, pol_name, *policy)) != 0) +- goto cleanup; ++ if (ent == NULL) { ++ st = KRB5_KDB_NOENTRY; ++ goto cleanup; + } ++ st = populate_policy(context, ld, ent, pol_name, *policy); + + cleanup: + ldap_msgfree(result); diff --git a/SOURCES/krb5-CVE_2014_5354_support_keyless_principals_in_LDAP.patch b/SOURCES/krb5-CVE_2014_5354_support_keyless_principals_in_LDAP.patch new file mode 100644 index 0000000..01aef2c --- /dev/null +++ b/SOURCES/krb5-CVE_2014_5354_support_keyless_principals_in_LDAP.patch @@ -0,0 +1,113 @@ +From 04038bf3633c4b909b5ded3072dc88c8c419bf16 Mon Sep 17 00:00:00 2001 +From: Ben Kaduk +Date: Wed, 19 Nov 2014 12:04:46 -0500 +Subject: [PATCH] Support keyless principals in LDAP [CVE-2014-5354] + +Operations like "kadmin -q 'addprinc -nokey foo'" or +"kadmin -q 'purgekeys -all foo'" result in principal entries with +no keys present, so krb5_encode_krbsecretkey() would just return +NULL, which then got unconditionally dereferenced in +krb5_add_ber_mem_ldap_mod(). + +Apply some fixes to krb5_encode_krbsecretkey() to handle zero-key +principals better, correct the test for an allocation failure, and +slightly restructure the cleanup handler to be shorter and more +appropriate for the usage. Once it no longer short-circuits when +n_key_data is zero, it will produce an array of length two with both +entries NULL, which is treated as an empty list by the LDAP library, +the correct behavior for a keyless principal. + +However, attributes with empty values are only handled by the LDAP +library for Modify operations, not Add operations (which only get +a sequence of Attribute, with no operation field). Therefore, only +add an empty krbprincipalkey to the modlist when we will be performing a +Modify, and not when we will be performing an Add, which is conditional +on the (misspelled) create_standalone_prinicipal boolean. + +CVE-2014-5354: + +In MIT krb5, when kadmind is configured to use LDAP for the KDC +database, an authenticated remote attacker can cause a NULL +dereference by inserting into the database a principal entry which +contains no long-term keys. + +In order for the LDAP KDC backend to translate a principal entry +from the database abstraction layer into the form expected by the +LDAP schema, the principal's keys are encoded into a +NULL-terminated array of length-value entries to be stored in the +LDAP database. However, the subroutine which produced this array +did not correctly handle the case where no keys were present, +returning NULL instead of an empty array, and the array was +unconditionally dereferenced while adding to the list of LDAP +operations to perform. + +Versions of MIT krb5 prior to 1.12 did not expose a way for +principal entries to have no long-term key material, and +therefore are not vulnerable. + + CVSSv2 Vector: AV:N/AC:M/Au:S/C:N/I:N/A:P/E:H/RL:OF/RC:C + +ticket: 8041 (new) +tags: pullup +target_version: 1.13.1 +subject: kadmind with ldap backend crashes when putting keyless entries +--- + src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c | 25 +++++++++++++++------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +index 3e560d9..10b5982 100644 +--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c ++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +@@ -406,14 +406,14 @@ krb5_encode_krbsecretkey(krb5_key_data *key_data_in, int n_key_data, + int num_versions = 1; + int i, j, last; + krb5_error_code err = 0; +- krb5_key_data *key_data; ++ krb5_key_data *key_data = NULL; + +- if (n_key_data <= 0) ++ if (n_key_data < 0) + return NULL; + + /* Make a shallow copy of the key data so we can alter it. */ + key_data = k5calloc(n_key_data, sizeof(*key_data), &err); +- if (key_data_in == NULL) ++ if (key_data == NULL) + goto cleanup; + memcpy(key_data, key_data_in, n_key_data * sizeof(*key_data)); + +@@ -467,9 +467,8 @@ krb5_encode_krbsecretkey(krb5_key_data *key_data_in, int n_key_data, + free(key_data); + if (err != 0) { + if (ret != NULL) { +- for (i = 0; i <= num_versions; i++) +- if (ret[i] != NULL) +- free (ret[i]); ++ for (i = 0; ret[i] != NULL; i++) ++ free (ret[i]); + free (ret); + ret = NULL; + } +@@ -1036,9 +1035,19 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry, + bersecretkey = krb5_encode_krbsecretkey (entry->key_data, + entry->n_key_data, mkvno); + +- if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey", +- LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0) ++ if (bersecretkey == NULL) { ++ st = ENOMEM; + goto cleanup; ++ } ++ /* An empty list of bervals is only accepted for modify operations, ++ * not add operations. */ ++ if (bersecretkey[0] != NULL || !create_standalone_prinicipal) { ++ st = krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey", ++ LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, ++ bersecretkey); ++ if (st != 0) ++ goto cleanup; ++ } + + if (!(entry->mask & KADM5_PRINCIPAL)) { + memset(strval, 0, sizeof(strval)); diff --git a/SOURCES/krb5-aarch64.patch b/SOURCES/krb5-aarch64.patch deleted file mode 100644 index fd8649e..0000000 --- a/SOURCES/krb5-aarch64.patch +++ /dev/null @@ -1,411 +0,0 @@ -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 deleted file mode 100644 index f64b1f0..0000000 --- a/SOURCES/krb5-cccol-primary.patch +++ /dev/null @@ -1,85 +0,0 @@ -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-kadm5clntmit_libsoname_version_downgrade.patch b/SOURCES/krb5-kadm5clntmit_libsoname_version_downgrade.patch new file mode 100644 index 0000000..9f81bd8 --- /dev/null +++ b/SOURCES/krb5-kadm5clntmit_libsoname_version_downgrade.patch @@ -0,0 +1,11 @@ +--- a/src/lib/kadm5/clnt/Makefile.in ++++ b/src/lib/kadm5/clnt/Makefile.in +@@ -3,7 +3,7 @@ + LOCALINCLUDES = -I$(BUILDTOP)/include/kadm5 + + LIBBASE=kadm5clnt_mit +-LIBMAJOR=9 ++LIBMAJOR=8 + LIBMINOR=0 + STOBJLISTS=../OBJS.ST OBJS.ST + SHLIB_EXPDEPS=\ diff --git a/SOURCES/krb5-keyring-strtol.patch b/SOURCES/krb5-keyring-strtol.patch deleted file mode 100644 index 790bbc1..0000000 --- a/SOURCES/krb5-keyring-strtol.patch +++ /dev/null @@ -1,41 +0,0 @@ -commit 5ac159e220297a8f62dd5edcec6f9b988b0627ea -Author: Nalin Dahyabhai -Date: Mon Nov 11 13:10:08 2013 -0500 - - Catch more strtol() failures when using KEYRINGs - - When parsing what should be a UID while resolving a KEYRING ccache - name, don't just depend on strtol() to set errno when the residual - that we pass to it can't be parsed as a number. In addition to - checking errno, pass in and check the value of an "endptr". - - [ghudson@mit.edu: simplified slightly] - - ticket: 7764 (new) - target_version: 1.12 - tags: pullup - -diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c -index 795ccd6..a07a0dc 100644 ---- a/src/lib/krb5/ccache/cc_keyring.c -+++ b/src/lib/krb5/ccache/cc_keyring.c -@@ -593,7 +593,7 @@ get_collection(const char *anchor_name, const char *collection_name, - { - krb5_error_code ret; - key_serial_t persistent_id, anchor_id, possess_id = 0; -- char *ckname; -+ char *ckname, *cnend; - long uidnum; - - *collection_id_out = 0; -@@ -607,8 +607,8 @@ get_collection(const char *anchor_name, const char *collection_name, - */ - if (*collection_name != '\0') { - errno = 0; -- uidnum = strtol(collection_name, NULL, 10); -- if (errno) -+ uidnum = strtol(collection_name, &cnend, 10); -+ if (errno || *cnend != '\0') - return KRB5_KCC_INVALID_UID; - } else { - uidnum = geteuid(); diff --git a/SOURCES/krb5-ksu_not_working_with_default_principal.patch b/SOURCES/krb5-ksu_not_working_with_default_principal.patch new file mode 100644 index 0000000..01ecdac --- /dev/null +++ b/SOURCES/krb5-ksu_not_working_with_default_principal.patch @@ -0,0 +1,52 @@ +From 3a32e1e6e644c6092f48cf6b6f2d0b8635b3dd52 Mon Sep 17 00:00:00 2001 +From: Nalin Dahyabhai +Date: Wed, 30 Jul 2014 17:12:31 -0400 +Subject: [PATCH] In ksu, without the -e flag, also check .k5users + +When ksu was explicitly told to spawn a shell, a line in .k5users which +listed "*" as the allowed command would cause the principal named on the +line to be considered as a candidate for authentication. + +When ksu was not passed a command to run, which implicitly meant that +the invoking user wanted to run the target user's login shell, knowledge +that the principal was a valid candidate was ignored, which could cause +a less optimal choice of the default target principal. + +This doesn't impact the authorization checks which we perform later. + +ticket: 7983 (new) +--- + src/clients/ksu/heuristic.c | 19 ++++++------------- + 1 file changed, 6 insertions(+), 13 deletions(-) + +diff --git a/src/clients/ksu/heuristic.c b/src/clients/ksu/heuristic.c +index c7e691c..99b54e5 100644 +--- a/src/clients/ksu/heuristic.c ++++ b/src/clients/ksu/heuristic.c +@@ -264,20 +264,13 @@ get_authorized_princ_names(luser, cmd, princ_list) + + close_time(k5users_flag,users_fp, k5login_flag, login_fp); + +- if (cmd) { +- retval = list_union(k5login_list, k5users_filt_list, &combined_list); +- if (retval){ +- close_time(k5users_flag,users_fp, k5login_flag,login_fp); +- return retval; +- } +- *princ_list = combined_list; +- return 0; +- } else { +- if (k5users_filt_list != NULL) +- free(k5users_filt_list); +- *princ_list = k5login_list; +- return 0; ++ retval = list_union(k5login_list, k5users_filt_list, &combined_list); ++ if (retval){ ++ close_time(k5users_flag,users_fp, k5login_flag,login_fp); ++ return retval; + } ++ *princ_list = combined_list; ++ return 0; + } + + static void close_time(k5users_flag, users_fp, k5login_flag, login_fp) diff --git a/SOURCES/krb5-master-compatible-keys.patch b/SOURCES/krb5-master-compatible-keys.patch new file mode 100644 index 0000000..7c36e05 --- /dev/null +++ b/SOURCES/krb5-master-compatible-keys.patch @@ -0,0 +1,56 @@ +commit 4f99c75eb6b1a53d78b26648e39309261e37755c +Author: Nalin Dahyabhai +Date: Tue Mar 18 16:39:47 2014 -0400 + + Try compatible keys in rd_req_dec "any" path + + When we go to decrypt a ticket using a keytab, we have two code paths. + + In the first (traditional) one, we try to read an entry that exactly + matches the principal name, enctype, and kvno from the ticket, and then + attempt to decrypt the ticket using the entry's key. The keytab + routines helpfully return an entry so long as it's of a key type that's + compatible with the ticket being decrypted, fixing up the enctype in the + entry structure while doing so, allowing us to decrypt a DES-CBC-CRC + ticket with a DES-CBC-MD5 key. + + In the second code path, we try the key of every entry which loosely + matches the principal name from the ticket and which exactly matches its + enctype, meaning that the ticket/keytab pair above won't work if the + principal name is one which suggests we shouldn't be matching entries + exactly. + + This change modifies the "any" path to also try to decrypt the ticket + with compatible keys. + + [ghudson@mit.edu: avoid stuffing too much logic in one conditional] + + ticket: 7883 (new) + +diff --git a/src/lib/krb5/krb/rd_req_dec.c b/src/lib/krb5/krb/rd_req_dec.c +index 4b952f5..fbd088d 100644 +--- a/src/lib/krb5/krb/rd_req_dec.c ++++ b/src/lib/krb5/krb/rd_req_dec.c +@@ -167,6 +167,8 @@ decrypt_ticket(krb5_context context, const krb5_ap_req *req, + krb5_error_code ret; + krb5_keytab_entry ent; + krb5_kt_cursor cursor; ++ krb5_boolean similar; ++ krb5_enctype req_etype = req->ticket->enc_part.enctype; + + #ifdef LEAN_CLIENT + return KRB5KRB_AP_WRONG_PRINC; +@@ -189,8 +191,12 @@ decrypt_ticket(krb5_context context, const krb5_ap_req *req, + goto cleanup; + + while ((ret = krb5_kt_next_entry(context, keytab, &ent, &cursor)) == 0) { +- if (ent.key.enctype == req->ticket->enc_part.enctype && ++ ret = krb5_c_enctype_compare(context, ent.key.enctype, req_etype, ++ &similar); ++ if (ret == 0 && similar && + krb5_sname_match(context, server, ent.principal)) { ++ /* Coerce inexact matches to the request enctype. */ ++ ent.key.enctype = req_etype; + ret = try_one_entry(context, req, &ent, keyblock_out); + if (ret == 0) { + TRACE_RD_REQ_DECRYPT_ANY(context, ent.principal, &ent.key); diff --git a/SOURCES/krb5-master-empty-credstore.patch b/SOURCES/krb5-master-empty-credstore.patch deleted file mode 100644 index b6cd7ef..0000000 --- a/SOURCES/krb5-master-empty-credstore.patch +++ /dev/null @@ -1,43 +0,0 @@ -commit 970304b558a360e08d8421ef92245d2df0ac5e49 -Author: Greg Hudson -Date: Thu Jan 16 11:49:04 2014 -0500 - - Allow empty store in gss_acquire_cred_from - - There is no reason to deny a zero-length cred store, so don't check - for it in val_acq_cred_args or val_add_cred_args. - - ticket: 7836 (new) - target_version: 1.12.2 - tags: pullup - -diff --git a/src/lib/gssapi/mechglue/g_acquire_cred.c b/src/lib/gssapi/mechglue/g_acquire_cred.c -index 03b67e3..b9a3142 100644 ---- a/src/lib/gssapi/mechglue/g_acquire_cred.c -+++ b/src/lib/gssapi/mechglue/g_acquire_cred.c -@@ -80,12 +80,6 @@ val_acq_cred_args( - return GSS_S_FAILURE; - } - -- if (cred_store != NULL && cred_store->count == 0) { -- *minor_status = EINVAL; -- map_errcode(minor_status); -- return GSS_S_FAILURE; -- } -- - return (GSS_S_COMPLETE); - } - -@@ -302,12 +296,6 @@ val_add_cred_args( - return GSS_S_FAILURE; - } - -- if (cred_store != NULL && cred_store->count == 0) { -- *minor_status = EINVAL; -- map_errcode(minor_status); -- return GSS_S_FAILURE; -- } -- - return (GSS_S_COMPLETE); - } - diff --git a/SOURCES/krb5-master-gss_oid_leak.patch b/SOURCES/krb5-master-gss_oid_leak.patch deleted file mode 100644 index 9613823..0000000 --- a/SOURCES/krb5-master-gss_oid_leak.patch +++ /dev/null @@ -1,28 +0,0 @@ -commit 1cda48a7ed4069cfc052f974ec3d76a9137c8c5a -Author: Simo Sorce -Date: Fri Dec 13 12:00:41 2013 -0500 - - Fix memory leak in SPNEGO initiator - - If we eliminate a mechanism from the initiator list because - gss_init_sec_context fails, free the memory for that mech OID before - removing it from the list. - - [ghudson@mit.edu: clarified commit message] - - ticket: 7803 (new) - target_version: 1.12.1 - tags: pullup - -diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c -index 818a1b4..06cfab0 100644 ---- a/src/lib/gssapi/spnego/spnego_mech.c -+++ b/src/lib/gssapi/spnego/spnego_mech.c -@@ -890,6 +890,7 @@ init_ctx_call_init(OM_uint32 *minor_status, - * can do this with recursion. If all mechanisms produce errors, the - * caller should get the error from the first mech in the list. - */ -+ gssalloc_free(sc->mech_set->elements->elements); - memmove(sc->mech_set->elements, sc->mech_set->elements + 1, - --sc->mech_set->count * sizeof(*sc->mech_set->elements)); - if (sc->mech_set->count == 0) diff --git a/SOURCES/krb5-master-ignore-empty-unnecessary-final-token.patch b/SOURCES/krb5-master-ignore-empty-unnecessary-final-token.patch deleted file mode 100644 index 3ebb888..0000000 --- a/SOURCES/krb5-master-ignore-empty-unnecessary-final-token.patch +++ /dev/null @@ -1,37 +0,0 @@ -commit 37af638b742dbd642eb70092e4f7781c3f69d86d -Author: Greg Hudson -Date: Tue Dec 10 12:04:18 2013 -0500 - - Fix SPNEGO one-hop interop against old IIS - - IIS 6.0 and similar return a zero length reponse buffer in the last - SPNEGO packet when context initiation is performed without mutual - authentication. In this case the underlying Kerberos mechanism has - already completed successfully on the first invocation, and SPNEGO - does not expect a mech response token in the answer. If we get an - empty mech response token when the mech is complete during - negotiation, ignore it. - - [ghudson@mit.edu: small code style and commit message changes] - - ticket: 7797 (new) - target_version: 1.12.1 - tags: pullup - -diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c -index 3937662..d82934b 100644 ---- a/src/lib/gssapi/spnego/spnego_mech.c -+++ b/src/lib/gssapi/spnego/spnego_mech.c -@@ -760,6 +760,12 @@ init_ctx_nego(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc, - map_errcode(minor_status); - ret = GSS_S_DEFECTIVE_TOKEN; - } -+ } else if ((*responseToken)->length == 0 && sc->mech_complete) { -+ /* Handle old IIS servers returning empty token instead of -+ * null tokens in the non-mutual auth case. */ -+ *negState = ACCEPT_COMPLETE; -+ *tokflag = NO_TOKEN_SEND; -+ ret = GSS_S_COMPLETE; - } else if (sc->mech_complete) { - /* Reject spurious mech token. */ - ret = GSS_S_DEFECTIVE_TOKEN; diff --git a/SOURCES/krb5-master-init_referral.patch b/SOURCES/krb5-master-init_referral.patch deleted file mode 100644 index ae3d3b8..0000000 --- a/SOURCES/krb5-master-init_referral.patch +++ /dev/null @@ -1,47 +0,0 @@ -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-keyring-expiration.patch b/SOURCES/krb5-master-keyring-expiration.patch deleted file mode 100644 index 2c58cb0..0000000 --- a/SOURCES/krb5-master-keyring-expiration.patch +++ /dev/null @@ -1,127 +0,0 @@ -commit 29e60c5b7ac0980606971afc6fd6028bcf0c7f0f -Author: Simo Sorce -Date: Fri Nov 15 16:36:05 2013 -0500 - - Set expiration time on keys and keyrings - - By setting the timeout based on the credetial's timeout we let the - system automatically cleanup expired credentials. - - [ghudson@mit.edu: simplified code slightly] - - ticket: 7769 (new) - target_version: 1.12 - tags: pullup - -diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c -index 2192fa5..1a0f1df 100644 ---- a/src/lib/krb5/ccache/cc_keyring.c -+++ b/src/lib/krb5/ccache/cc_keyring.c -@@ -818,21 +818,68 @@ cleanup: - - 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 cache_id, krb5_boolean legacy_type, -+ key_serial_t *key_out) - { - key_serial_t key; - -+ *key_out = -1; - 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) -+ if (key != -1) { -+ *key_out = key; - return 0; -- else if (errno != EINVAL && errno != ENODEV) -+ } 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; -+ if (key == -1) -+ return errno; -+ *key_out = key; -+ return 0; -+} -+ -+static void -+update_keyring_expiration(krb5_context context, krb5_ccache id) -+{ -+ krb5_krcc_data *d = (krb5_krcc_data *)id->data; -+ krb5_cc_cursor cursor; -+ krb5_creds creds; -+ krb5_timestamp now, endtime = 0; -+ unsigned int timeout; -+ -+ /* -+ * We have no way to know what is the actual timeout set on the keyring. -+ * We also cannot keep track of it in a local variable as another process -+ * can always modify the keyring independently, so just always enumerate -+ * all keys and find out the highest endtime time. -+ */ -+ -+ /* Find the maximum endtime of all creds in the cache. */ -+ if (krb5_krcc_start_seq_get(context, id, &cursor) != 0) -+ return; -+ for (;;) { -+ if (krb5_krcc_next_cred(context, id, &cursor, &creds) != 0) -+ break; -+ if (creds.times.endtime > endtime) -+ endtime = creds.times.endtime; -+ krb5_free_cred_contents(context, &creds); -+ } -+ (void)krb5_krcc_end_seq_get(context, id, &cursor); -+ -+ if (endtime == 0) /* No creds with end times */ -+ return; -+ -+ if (krb5_timeofday(context, &now) != 0) -+ return; -+ -+ /* Setting the timeout to zero would reset the timeout, so we set it to one -+ * second instead if creds are already expired. */ -+ timeout = (endtime > now) ? endtime - now : 1; -+ (void)keyctl_set_timeout(d->cache_id, timeout); - } - - /* -@@ -1497,6 +1544,8 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds) - char *payload = NULL; - unsigned int payloadlen; - char *keyname = NULL; -+ key_serial_t cred_key; -+ krb5_timestamp now; - - DEBUG_PRINT(("krb5_krcc_store: entered\n")); - -@@ -1523,12 +1572,24 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds) - DEBUG_PRINT(("krb5_krcc_store: adding new key '%s' to keyring %d\n", - keyname, d->cache_id)); - kret = add_cred_key(keyname, payload, payloadlen, d->cache_id, -- d->is_legacy_type); -+ d->is_legacy_type, &cred_key); - if (kret) - goto errout; - - krb5_krcc_update_change_time(d); - -+ /* Set appropriate timeouts on cache keys. */ -+ kret = krb5_timeofday(context, &now); -+ if (kret) -+ goto errout; -+ -+ if (creds->times.endtime > now) -+ (void)keyctl_set_timeout(cred_key, creds->times.endtime - now); -+ -+ update_keyring_expiration(context, id); -+ -+ kret = KRB5_OK; -+ - errout: - if (keyname) - krb5_free_unparsed_name(context, keyname); diff --git a/SOURCES/krb5-master-keyring-kdcsync.patch b/SOURCES/krb5-master-keyring-kdcsync.patch deleted file mode 100644 index 3079bf2..0000000 --- a/SOURCES/krb5-master-keyring-kdcsync.patch +++ /dev/null @@ -1,108 +0,0 @@ -commit e99c688913a7761c6adea9488ea9355f43539883 -Author: Greg Hudson -Date: Thu Jan 16 17:48:54 2014 -0500 - - Get time offsets for all keyring ccaches - - Move the time offset lookup from krb5_krcc_resolve to make_cache, so - that we fetch time offsets for caches created by - krb5_krcc_ptcursor_next. - - ticket: 7820 - target_version: 1.12.2 - tags: pullup - -diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c -index a0c8035..27bad9d 100644 ---- a/src/lib/krb5/ccache/cc_keyring.c -+++ b/src/lib/krb5/ccache/cc_keyring.c -@@ -1077,11 +1077,13 @@ krb5_krcc_destroy(krb5_context context, krb5_ccache id) - - /* 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) -+make_cache(krb5_context context, 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_os_context os_ctx = &context->os_context; - krb5_ccache ccache = NULL; - krb5_krcc_data *d; - key_serial_t pkey = 0; -@@ -1108,6 +1110,18 @@ make_cache(key_serial_t collection_id, key_serial_t cache_id, - ccache->data = d; - ccache->magic = KV5M_CCACHE; - *cache_out = ccache; -+ -+ /* Lookup time offsets if necessary. */ -+ if ((context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) && -+ !(os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)) { -+ if (krb5_krcc_get_time_offsets(context, ccache, -+ &os_ctx->time_offset, -+ &os_ctx->usec_offset) == 0) { -+ os_ctx->os_flags &= ~KRB5_OS_TOFFSET_TIME; -+ os_ctx->os_flags |= KRB5_OS_TOFFSET_VALID; -+ } -+ } -+ - return 0; - } - -@@ -1134,7 +1148,6 @@ make_cache(key_serial_t collection_id, key_serial_t cache_id, - static krb5_error_code KRB5_CALLCONV - krb5_krcc_resolve(krb5_context context, krb5_ccache *id, const char *residual) - { -- krb5_os_context os_ctx = &context->os_context; - krb5_error_code ret; - key_serial_t collection_id, cache_id; - char *anchor_name = NULL, *collection_name = NULL, *subsidiary_name = NULL; -@@ -1161,22 +1174,11 @@ krb5_krcc_resolve(krb5_context context, krb5_ccache *id, const char *residual) - if (cache_id < 0) - cache_id = 0; - -- ret = make_cache(collection_id, cache_id, anchor_name, collection_name, -- subsidiary_name, id); -+ ret = make_cache(context, collection_id, cache_id, anchor_name, -+ collection_name, subsidiary_name, id); - if (ret) - goto cleanup; - -- /* Lookup time offsets if necessary. */ -- if ((context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) && -- !(os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)) { -- if (krb5_krcc_get_time_offsets(context, *id, -- &os_ctx->time_offset, -- &os_ctx->usec_offset) == 0) { -- os_ctx->os_flags &= ~KRB5_OS_TOFFSET_TIME; -- os_ctx->os_flags |= KRB5_OS_TOFFSET_VALID; -- } -- } -- - cleanup: - free(anchor_name); - free(collection_name); -@@ -1928,8 +1930,9 @@ krb5_krcc_ptcursor_next(krb5_context context, krb5_cc_ptcursor cursor, - 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); -+ return make_cache(context, data->collection_id, cache_id, -+ data->anchor_name, data->collection_name, -+ first_name, cache_out); - } - } - -@@ -1967,7 +1970,7 @@ krb5_krcc_ptcursor_next(krb5_context context, krb5_cc_ptcursor cursor, - - /* We found a valid key */ - data->next_key++; -- ret = make_cache(data->collection_id, key, data->anchor_name, -+ ret = make_cache(context, data->collection_id, key, data->anchor_name, - data->collection_name, subsidiary_name, cache_out); - free(description); - return ret; diff --git a/SOURCES/krb5-master-keyring-offsets.patch b/SOURCES/krb5-master-keyring-offsets.patch deleted file mode 100644 index b54e84b..0000000 --- a/SOURCES/krb5-master-keyring-offsets.patch +++ /dev/null @@ -1,311 +0,0 @@ -commit fb4817a32d0c369049e0868468dd2eb75487630d -Author: Simo Sorce -Date: Thu Nov 14 17:23:59 2013 -0500 - - Add support to store time offsets in cc_keyring - - The code follows the same model used for the memory ccache type. Time - offsets are stored in each credential cache in a special key just like - the principal name. Legacy session caches do not store timestamps as - legacy code would fail when iterating over the new offset key. - - [ghudson@mit.edu: minor formatting changes; note legacy session - exception in commit message] - - ticket: 7768 (new) - target_version: 1.12 - tags: pullup - -diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c -index a07a0dc..2192fa5 100644 ---- a/src/lib/krb5/ccache/cc_keyring.c -+++ b/src/lib/krb5/ccache/cc_keyring.c -@@ -189,6 +189,11 @@ debug_print(char *fmt, ...) - #define KRCC_PERSISTENT_KEYRING_NAME "_krb" - - /* -+ * Name of the key holding time offsets for the individual cache -+ */ -+#define KRCC_TIME_OFFSETS "__krb5_time_offsets__" -+ -+/* - * Keyring name prefix and length of random name part - */ - #define KRCC_NAME_PREFIX "krb_ccache_" -@@ -217,6 +222,7 @@ typedef struct _krb5_krcc_cursor - int numkeys; - int currkey; - key_serial_t princ_id; -+ key_serial_t offsets_id; - key_serial_t *keys; - } *krb5_krcc_cursor; - -@@ -340,6 +346,12 @@ 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 krb5_error_code krb5_krcc_save_time_offsets -+(krb5_context context, krb5_ccache id, krb5_int32 time_offset, -+ krb5_int32 usec_offset); -+static krb5_error_code krb5_krcc_get_time_offsets -+(krb5_context context, krb5_ccache id, krb5_int32 *time_offset, -+ krb5_int32 *usec_offset); - - /* Routines to parse a key from a keyring into a cred structure */ - static krb5_error_code krb5_krcc_parse -@@ -410,6 +422,12 @@ krb5_krcc_parse_index(krb5_context context, krb5_int32 *version, - static krb5_error_code - krb5_krcc_unparse_index(krb5_context context, krb5_int32 version, - const char *primary, void **datapp, int *lenptr); -+static krb5_error_code -+krb5_krcc_parse_offsets(krb5_context context, krb5_int32 *time_offset, -+ krb5_int32 *usec_offset, void *payload, int psize); -+static krb5_error_code -+krb5_krcc_unparse_offsets(krb5_context context, krb5_int32 time_offset, -+ krb5_int32 usec_offset, void **datapp, int *lenptr); - - /* Note the following is a stub function for Linux */ - extern krb5_error_code krb5_change_cache(void); -@@ -835,6 +853,7 @@ krb5_krcc_initialize(krb5_context context, krb5_ccache id, - krb5_principal princ) - { - krb5_krcc_data *data = (krb5_krcc_data *)id->data; -+ krb5_os_context os_ctx = &context->os_context; - krb5_error_code kret; - const char *cache_name, *p; - -@@ -863,6 +882,15 @@ krb5_krcc_initialize(krb5_context context, krb5_ccache id, - (void)keyctl_link(data->cache_id, KEY_SPEC_SESSION_KEYRING); - - kret = krb5_krcc_save_principal(context, id, princ); -+ -+ /* Save time offset if it is valid and this is not a legacy cache. Legacy -+ * applications would fail to parse the new key in the cache keyring. */ -+ if (!is_legacy_cache_name(data->name) && -+ (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)) { -+ kret = krb5_krcc_save_time_offsets(context, id, os_ctx->time_offset, -+ os_ctx->usec_offset); -+ } -+ - if (kret == KRB5_OK) - krb5_change_cache(); - -@@ -1039,6 +1067,7 @@ make_cache(key_serial_t collection_id, key_serial_t cache_id, - static krb5_error_code KRB5_CALLCONV - krb5_krcc_resolve(krb5_context context, krb5_ccache *id, const char *residual) - { -+ krb5_os_context os_ctx = &context->os_context; - krb5_error_code ret; - key_serial_t collection_id, cache_id; - char *anchor_name = NULL, *collection_name = NULL, *subsidiary_name = NULL; -@@ -1067,6 +1096,19 @@ krb5_krcc_resolve(krb5_context context, krb5_ccache *id, const char *residual) - - ret = make_cache(collection_id, cache_id, anchor_name, collection_name, - subsidiary_name, id); -+ if (ret) -+ goto cleanup; -+ -+ /* Lookup time offsets if necessary. */ -+ if ((context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) && -+ !(os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)) { -+ if (krb5_krcc_get_time_offsets(context, *id, -+ &os_ctx->time_offset, -+ &os_ctx->usec_offset) == 0) { -+ os_ctx->os_flags &= ~KRB5_OS_TOFFSET_TIME; -+ os_ctx->os_flags |= KRB5_OS_TOFFSET_VALID; -+ } -+ } - - cleanup: - free(anchor_name); -@@ -1122,6 +1164,8 @@ krb5_krcc_start_seq_get(krb5_context context, krb5_ccache id, - } - - krcursor->princ_id = d->princ_id; -+ krcursor->offsets_id = keyctl_search(d->cache_id, KRCC_KEY_TYPE_USER, -+ KRCC_TIME_OFFSETS, 0); - krcursor->numkeys = size / sizeof(key_serial_t); - krcursor->keys = keys; - -@@ -1174,8 +1218,10 @@ krb5_krcc_next_cred(krb5_context context, krb5_ccache id, - 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) { -+ /* If we're pointing at the entry with the principal, or at the key -+ * with the time offsets, skip it. */ -+ while (krcursor->keys[krcursor->currkey] == krcursor->princ_id || -+ krcursor->keys[krcursor->currkey] == krcursor->offsets_id) { - krcursor->currkey++; - /* Check if we have now reached the end */ - if (krcursor->currkey >= krcursor->numkeys) -@@ -1621,6 +1667,84 @@ errout: - return kret; - } - -+static krb5_error_code -+krb5_krcc_save_time_offsets(krb5_context context, krb5_ccache id, -+ krb5_int32 time_offset, krb5_int32 usec_offset) -+{ -+ krb5_krcc_data *d = (krb5_krcc_data *)id->data; -+ krb5_error_code kret; -+ key_serial_t newkey; -+ void *payload = NULL; -+ int psize; -+ -+ k5_cc_mutex_assert_locked(context, &d->lock); -+ -+ /* Prepare the payload. */ -+ kret = krb5_krcc_unparse_offsets(context, time_offset, usec_offset, -+ &payload, &psize); -+ CHECK_N_GO(kret, errout); -+ -+ /* Add new key into keyring. */ -+ newkey = add_key(KRCC_KEY_TYPE_USER, KRCC_TIME_OFFSETS, payload, psize, -+ d->cache_id); -+ if (newkey == -1) { -+ kret = errno; -+ DEBUG_PRINT(("Error adding time offsets key: %s\n", strerror(kret))); -+ } else { -+ kret = KRB5_OK; -+ krb5_krcc_update_change_time(d); -+ } -+ -+errout: -+ free(payload); -+ return kret; -+} -+ -+static krb5_error_code -+krb5_krcc_get_time_offsets(krb5_context context, krb5_ccache id, -+ krb5_int32 *time_offset, krb5_int32 *usec_offset) -+{ -+ krb5_krcc_data *d = (krb5_krcc_data *)id->data; -+ krb5_error_code kret; -+ key_serial_t key; -+ krb5_int32 t, u; -+ void *payload = NULL; -+ int psize; -+ -+ k5_cc_mutex_lock(context, &d->lock); -+ -+ if (!d->cache_id) { -+ kret = KRB5_FCC_NOFILE; -+ goto errout; -+ } -+ -+ key = keyctl_search(d->cache_id, KRCC_KEY_TYPE_USER, KRCC_TIME_OFFSETS, 0); -+ if (key == -1) { -+ kret = ENOENT; -+ goto errout; -+ } -+ -+ psize = keyctl_read_alloc(key, &payload); -+ if (psize == -1) { -+ DEBUG_PRINT(("Reading time offsets key %d: %s\n", -+ key, strerror(errno))); -+ kret = KRB5_CC_IO; -+ goto errout; -+ } -+ -+ kret = krb5_krcc_parse_offsets(context, &t, &u, payload, psize); -+ if (kret) -+ goto errout; -+ -+ *time_offset = t; -+ *usec_offset = u; -+ -+errout: -+ free(payload); -+ k5_cc_mutex_unlock(context, &d->lock); -+ return kret; -+} -+ - struct krcc_ptcursor_data { - key_serial_t collection_id; - char *anchor_name; -@@ -2656,6 +2780,83 @@ errout: - return kret; - } - -+static krb5_error_code -+krb5_krcc_parse_offsets(krb5_context context, krb5_int32 *time_offset, -+ krb5_int32 *usec_offset, void *payload, int psize) -+{ -+ krb5_error_code kret; -+ krb5_krcc_bc bc; -+ -+ bc.bpp = payload; -+ bc.endp = bc.bpp + psize; -+ -+ kret = krb5_krcc_parse_int32(context, time_offset, &bc); -+ CHECK_OUT(kret); -+ -+ kret = krb5_krcc_parse_int32(context, usec_offset, &bc); -+ CHECK_OUT(kret); -+ -+ return KRB5_OK; -+} -+ -+static krb5_error_code -+krb5_krcc_unparse_offsets_internal(krb5_context context, -+ krb5_int32 time_offset, -+ krb5_int32 usec_offset, -+ krb5_krcc_bc *bc) -+{ -+ krb5_error_code kret; -+ -+ kret = krb5_krcc_unparse_int32(context, time_offset, bc); -+ CHECK_OUT(kret); -+ -+ kret = krb5_krcc_unparse_int32(context, usec_offset, bc); -+ CHECK_OUT(kret); -+ -+ return KRB5_OK; -+} -+ -+static krb5_error_code -+krb5_krcc_unparse_offsets(krb5_context context, krb5_int32 time_offset, -+ krb5_int32 usec_offset, void **datapp, int *lenptr) -+{ -+ krb5_error_code kret; -+ krb5_krcc_bc bc; -+ char *buf; -+ -+ if (!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_offsets_internal(context, time_offset, -+ usec_offset, &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_offsets_internal(context, time_offset, -+ usec_offset, &bc); -+ CHECK(kret); -+ -+ /* Success! */ -+ *datapp = buf; -+ *lenptr = bc.bpp - buf; -+ kret = KRB5_OK; -+ -+errout: -+ if (kret) -+ free(buf); -+ return kret; -+} - /* - * Utility routine: called by krb5_krcc_* functions to keep - * result of krb5_krcc_last_change_time up to date. diff --git a/SOURCES/krb5-master-keyringccops.patch b/SOURCES/krb5-master-keyringccops.patch deleted file mode 100644 index e979314..0000000 --- a/SOURCES/krb5-master-keyringccops.patch +++ /dev/null @@ -1,63 +0,0 @@ -commit bfdc0955657ba83940c63d1d9771b09edc0cb453 -Author: Nalin Dahyabhai -Date: Thu Dec 5 13:54:09 2013 -0500 - - Flag no-such-keyring errors in get/set-flags ccops - - When attempting to use a keyring cache that doesn't exist, return - KRB5_FCC_NOFILE errors during ccache get/set flags ops, and set an error - message when we fail to read a principal name, bringing us more in line - with the behavior we already have when using file-based caches. - -diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c -index 1a0f1df..421b228 100644 ---- a/src/lib/krb5/ccache/cc_keyring.c -+++ b/src/lib/krb5/ccache/cc_keyring.c -@@ -1521,16 +1521,34 @@ krb5_krcc_remove_cred(krb5_context context, krb5_ccache cache, - static krb5_error_code KRB5_CALLCONV - krb5_krcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags) - { -+ krb5_krcc_data *d = (krb5_krcc_data *) id->data; -+ - DEBUG_PRINT(("krb5_krcc_set_flags: entered\n")); - -+ k5_cc_mutex_lock(context, &d->lock); -+ if (!d->cache_id) { -+ k5_cc_mutex_unlock(context, &d->lock); -+ return KRB5_FCC_NOFILE; -+ } -+ k5_cc_mutex_unlock(context, &d->lock); -+ - return KRB5_OK; - } - - static krb5_error_code KRB5_CALLCONV - krb5_krcc_get_flags(krb5_context context, krb5_ccache id, krb5_flags * flags) - { -+ krb5_krcc_data *d = (krb5_krcc_data *) id->data; -+ - DEBUG_PRINT(("krb5_krcc_get_flags: entered\n")); - -+ k5_cc_mutex_lock(context, &d->lock); -+ if (!d->cache_id) { -+ k5_cc_mutex_unlock(context, &d->lock); -+ return KRB5_FCC_NOFILE; -+ } -+ k5_cc_mutex_unlock(context, &d->lock); -+ - *flags = 0; - return KRB5_OK; - } -@@ -1707,6 +1725,12 @@ krb5_krcc_retrieve_principal(krb5_context context, krb5_ccache id, - if (!d->cache_id || !d->princ_id) { - princ = 0L; - kret = KRB5_FCC_NOFILE; -+ if (d->name) { -+ krb5_set_error_message(context, kret, -+ _("Credentials cache keyring '%s' " -+ "not found"), -+ d->name); -+ } - goto errout; - } - diff --git a/SOURCES/krb5-master-keytab_close.patch b/SOURCES/krb5-master-keytab_close.patch deleted file mode 100644 index d020ae6..0000000 --- a/SOURCES/krb5-master-keytab_close.patch +++ /dev/null @@ -1,39 +0,0 @@ -commit decccbcb5075f8fbc28a535a9b337afc84a15dee -Author: Greg Hudson -Date: Mon Dec 16 15:37:56 2013 -0500 - - Fix GSS krb5 acceptor acquire_cred error handling - - When acquiring acceptor creds with a specified name, if we fail to - open a replay cache, we leak the keytab handle. If there is no - specified name and we discover that there is no content in the keytab, - we leak the keytab handle and return the wrong major code. Memory - leak reported by Andrea Campi. - - ticket: 7805 - target_version: 1.12.1 - tags: pullup - -diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c -index 0efcad4..9547207 100644 ---- a/src/lib/gssapi/krb5/acquire_cred.c -+++ b/src/lib/gssapi/krb5/acquire_cred.c -@@ -225,6 +225,7 @@ acquire_accept_cred(krb5_context context, - code = krb5_get_server_rcache(context, &cred->name->princ->data[0], - &cred->rcache); - if (code) { -+ krb5_kt_close(context, kt); - *minor_status = code; - return GSS_S_FAILURE; - } -@@ -232,8 +233,9 @@ acquire_accept_cred(krb5_context context, - /* Make sure we have a keytab with keys in it. */ - code = krb5_kt_have_content(context, kt); - if (code) { -+ krb5_kt_close(context, kt); - *minor_status = code; -- return GSS_S_FAILURE; -+ return GSS_S_CRED_UNAVAIL; - } - } - diff --git a/SOURCES/krb5-master-kinit-cccol.patch b/SOURCES/krb5-master-kinit-cccol.patch deleted file mode 100644 index 58542fd..0000000 --- a/SOURCES/krb5-master-kinit-cccol.patch +++ /dev/null @@ -1,314 +0,0 @@ -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-mechd.patch b/SOURCES/krb5-master-mechd.patch new file mode 100644 index 0000000..965a436 --- /dev/null +++ b/SOURCES/krb5-master-mechd.patch @@ -0,0 +1,275 @@ +commit 123c14fd8862ee8f11f6084d25958cb380655f35 +Author: Günther Deschner +Date: Wed Mar 5 16:21:55 2014 +0100 + + Remove dead code from the mechglue initialization + + The stat check in gss_indicate_mechs had no consequent and would have + been redundant with logic in updateMechList if it did. + + [ghudson@mit.edu: elaborated commit message; removed unused + g_mechSetTime and now-irrelevant comment] + +diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c +index 48a825e..c6904e0 100644 +--- a/src/lib/gssapi/mechglue/g_initialize.c ++++ b/src/lib/gssapi/mechglue/g_initialize.c +@@ -91,7 +91,6 @@ static gss_mech_info g_mechListTail = NULL; + static k5_mutex_t g_mechListLock = K5_MUTEX_PARTIAL_INITIALIZER; + static time_t g_confFileModTime = (time_t)0; + +-static time_t g_mechSetTime = (time_t)0; + static gss_OID_set_desc g_mechSet = { 0, NULL }; + static k5_mutex_t g_mechSetLock = K5_MUTEX_PARTIAL_INITIALIZER; + +@@ -213,8 +212,6 @@ gss_indicate_mechs(minorStatus, mechSet_out) + OM_uint32 *minorStatus; + gss_OID_set *mechSet_out; + { +- char *fileName; +- struct stat fileInfo; + OM_uint32 status; + + /* Initialize outputs. */ +@@ -233,16 +230,6 @@ gss_OID_set *mechSet_out; + if (*minorStatus != 0) + return (GSS_S_FAILURE); + +- fileName = MECH_CONF; +- +- /* +- * If we have already computed the mechanisms supported and if it +- * is still valid; make a copy and return to caller, +- * otherwise build it first. +- */ +- if ((stat(fileName, &fileInfo) == 0 && +- fileInfo.st_mtime > g_mechSetTime)) { +- } /* if g_mechSet is out of date or not initialized */ + if (build_mechSet()) + return GSS_S_FAILURE; + +@@ -289,20 +276,6 @@ build_mechSet(void) + */ + k5_mutex_lock(&g_mechListLock); + +-#if 0 +- /* +- * this checks for the case when we need to re-construct the +- * g_mechSet structure, but the mechanism list is upto date +- * (because it has been read by someone calling +- * gssint_get_mechanism) +- */ +- if (fileInfo.st_mtime > g_confFileModTime) +- { +- g_confFileModTime = fileInfo.st_mtime; +- loadConfigFile(fileName); +- } +-#endif +- + updateMechList(); + + /* + +commit 05cbef80d53f49d30a5d0563501226dc173734d4 +Author: Günther Deschner +Date: Wed Mar 5 15:25:43 2014 +0100 + + Load mechglue config files from /etc/gss/mech.d + + In addition to loading /etc/gss/mech, glob for *.conf files in + /etc/gss/mech.d. Load only config files which have changed since the + highest mtime we saw in the previous scan. Scan at most once per + second to avoid excessive numbers of filesystem syscalls for busy + GSSAPI applications. + + [ghudson@mit.edu: rewrote commit message; style changes; added + once-per-second throttle on glob/stat calls] + + ticket: 7882 (new) + +diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c +index c6904e0..f0acf1a 100644 +--- a/src/lib/gssapi/mechglue/g_initialize.c ++++ b/src/lib/gssapi/mechglue/g_initialize.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + #define M_DEFAULT "default" + +@@ -58,6 +59,7 @@ + #ifndef MECH_CONF + #define MECH_CONF "/etc/gss/mech" + #endif ++#define MECH_CONF_PATTERN MECH_CONF ".d/*.conf" + + /* Local functions */ + static void addConfigEntry(const char *oidStr, const char *oid, +@@ -90,6 +92,7 @@ static gss_mech_info g_mechList = NULL; + static gss_mech_info g_mechListTail = NULL; + static k5_mutex_t g_mechListLock = K5_MUTEX_PARTIAL_INITIALIZER; + static time_t g_confFileModTime = (time_t)0; ++static time_t g_confLastCall = (time_t)0; + + static gss_OID_set_desc g_mechSet = { 0, NULL }; + static k5_mutex_t g_mechSetLock = K5_MUTEX_PARTIAL_INITIALIZER; +@@ -383,6 +386,56 @@ const gss_OID oid; + return (modOptions); + } /* gssint_get_modOptions */ + ++/* Return the mtime of filename or its eventual symlink target (if it is a ++ * symlink), whichever is larger. Return (time_t)-1 if lstat or stat fails. */ ++static time_t ++check_link_mtime(const char *filename, time_t *mtime_out) ++{ ++ struct stat st1, st2; ++ ++ if (lstat(filename, &st1) != 0) ++ return (time_t)-1; ++ if (!S_ISLNK(st1.st_mode)) ++ return st1.st_mtime; ++ if (stat(filename, &st2) != 0) ++ return (time_t)-1; ++ return (st1.st_mtime > st2.st_mtime) ? st1.st_mtime : st2.st_mtime; ++} ++ ++/* Try to load any config files which have changed since the last call. Config ++ * files are MECH_CONF and any files matching MECH_CONF_PATTERN. */ ++static void ++loadConfigFiles() ++{ ++ glob_t globbuf; ++ time_t highest_mtime = 0, mtime, now; ++ char **pathptr; ++ ++ /* Don't glob and stat more than once per second. */ ++ if (time(&now) == (time_t)-1 || now == g_confLastCall) ++ return; ++ g_confLastCall = now; ++ ++ globbuf.gl_offs = 1; ++ if (glob(MECH_CONF_PATTERN, GLOB_DOOFFS, NULL, &globbuf) != 0) ++ return; ++ globbuf.gl_pathv[0] = MECH_CONF; ++ ++ for (pathptr = globbuf.gl_pathv; *pathptr != NULL; pathptr++) { ++ mtime = check_link_mtime(*pathptr, &mtime); ++ if (mtime == (time_t)-1) ++ continue; ++ if (mtime > highest_mtime) ++ highest_mtime = mtime; ++ if (mtime > g_confFileModTime) ++ loadConfigFile(*pathptr); ++ } ++ g_confFileModTime = highest_mtime; ++ ++ globbuf.gl_pathv[0] = NULL; ++ globfree(&globbuf); ++} ++ + /* + * determines if the mechList needs to be updated from file + * and performs the update. +@@ -401,17 +454,7 @@ updateMechList(void) + loadConfigFromRegistry(HKEY_CURRENT_USER, MECH_KEY); + loadConfigFromRegistry(HKEY_LOCAL_MACHINE, MECH_KEY); + #else /* _WIN32 */ +- char *fileName; +- struct stat fileInfo; +- +- fileName = MECH_CONF; +- +- /* check if mechList needs updating */ +- if (stat(fileName, &fileInfo) != 0 || +- g_confFileModTime >= fileInfo.st_mtime) +- return; +- g_confFileModTime = fileInfo.st_mtime; +- loadConfigFile(fileName); ++ loadConfigFiles(); + #endif /* !_WIN32 */ + + /* Load any unloaded interposer mechanisms immediately, to make sure we + +commit ac98187641f6943ae571606c0b6a97f236f9b60c +Author: Greg Hudson +Date: Wed May 28 23:51:49 2014 -0400 + + Read /etc/gss/mech if no mech.d/*.conf found + + Always read /etc/gss/mech, even if globbing /etc/gss/mech.d/*.conf + doesn't work. Doing this using GLOB_DOOFFS proved error-prone, so use + a simpler approach: factor out the per-pathname handling into a helper + function load_if_changed, call it with MECH_CONF before the glob, then + pass each glob result through the helper. + + ticket: 7925 + +diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c +index f0acf1a..8bce14c 100644 +--- a/src/lib/gssapi/mechglue/g_initialize.c ++++ b/src/lib/gssapi/mechglue/g_initialize.c +@@ -402,38 +402,45 @@ check_link_mtime(const char *filename, time_t *mtime_out) + return (st1.st_mtime > st2.st_mtime) ? st1.st_mtime : st2.st_mtime; + } + ++/* Load pathname if it is newer than last. Update *highest to the maximum of ++ * its current value and pathname's mod time. */ ++static void ++load_if_changed(const char *pathname, time_t last, time_t *highest) ++{ ++ time_t mtime; ++ ++ mtime = check_link_mtime(pathname, &mtime); ++ if (mtime == (time_t)-1) ++ return; ++ if (mtime > *highest) ++ *highest = mtime; ++ if (mtime > last) ++ loadConfigFile(pathname); ++} ++ + /* Try to load any config files which have changed since the last call. Config + * files are MECH_CONF and any files matching MECH_CONF_PATTERN. */ + static void + loadConfigFiles() + { + glob_t globbuf; +- time_t highest_mtime = 0, mtime, now; +- char **pathptr; ++ time_t highest = 0, now; ++ char **path; + + /* Don't glob and stat more than once per second. */ + if (time(&now) == (time_t)-1 || now == g_confLastCall) + return; + g_confLastCall = now; + +- globbuf.gl_offs = 1; +- if (glob(MECH_CONF_PATTERN, GLOB_DOOFFS, NULL, &globbuf) != 0) +- return; +- globbuf.gl_pathv[0] = MECH_CONF; ++ load_if_changed(MECH_CONF, g_confFileModTime, &highest); + +- for (pathptr = globbuf.gl_pathv; *pathptr != NULL; pathptr++) { +- mtime = check_link_mtime(*pathptr, &mtime); +- if (mtime == (time_t)-1) +- continue; +- if (mtime > highest_mtime) +- highest_mtime = mtime; +- if (mtime > g_confFileModTime) +- loadConfigFile(*pathptr); ++ if (glob(MECH_CONF_PATTERN, 0, NULL, &globbuf) == 0) { ++ for (path = globbuf.gl_pathv; *path != NULL; path++) ++ load_if_changed(*path, g_confFileModTime, &highest); ++ globfree(&globbuf); + } +- g_confFileModTime = highest_mtime; + +- globbuf.gl_pathv[0] = NULL; +- globfree(&globbuf); ++ g_confFileModTime = highest; + } + + /* diff --git a/SOURCES/krb5-master-move-otp-sockets.patch b/SOURCES/krb5-master-move-otp-sockets.patch new file mode 100644 index 0000000..8d86930 --- /dev/null +++ b/SOURCES/krb5-master-move-otp-sockets.patch @@ -0,0 +1,203 @@ +Adjusted to apply to 1.12.2. + +commit 1e4bdcfed2c7bda94d5c135cc32a5993ca032501 +Author: Nathaniel McCallum +Date: Wed Feb 5 10:59:46 2014 -0500 + + Move OTP sockets to KDC_RUN_DIR + + Some system configurations expect Unix-domain sockets to live under + /run or /var/run, and not other parts of /var where persistent + application state lives. Define a new directory KDC_RUN_DIR using + $runstatedir (new in autoconf 2.70, so fall back to $localstatedir/run + if it's not set) and use that for the default socket path. + + [ghudson@mit.edu: commit message, otp.rst formatting fix] + + ticket: 7859 (new) + +diff --git a/doc/admin/otp.rst b/doc/admin/otp.rst +index 0abd5ff..f12c36d 100644 +--- a/doc/admin/otp.rst ++++ b/doc/admin/otp.rst +@@ -23,7 +23,7 @@ the following format:: + + [otp] + = { +- server = (default: $KDCDIR/.socket) ++ server = (default: see below) + secret = + timeout = (default: 5 [seconds]) + retries = (default: 3) +@@ -33,7 +33,8 @@ the following format:: + If the server field begins with '/', it will be interpreted as a UNIX + socket. Otherwise, it is assumed to be in the format host:port. When + a UNIX domain socket is specified, the secret field is optional and an +-empty secret is used by default. ++empty secret is used by default. If the server field is not ++specified, it defaults to |kdcrundir|\ ``/.socket``. + + When forwarding the request over RADIUS, by default the principal is + used in the User-Name attribute of the RADIUS packet. The strip_realm +diff --git a/doc/conf.py b/doc/conf.py +index f015fc8..bc8b2bd 100644 +--- a/doc/conf.py ++++ b/doc/conf.py +@@ -231,6 +231,7 @@ if 'mansubs' in tags: + sbindir = '``@SBINDIR@``' + libdir = '``@LIBDIR@``' + localstatedir = '``@LOCALSTATEDIR@``' ++ runstatedir = '``@RUNSTATEDIR@``' + sysconfdir = '``@SYSCONFDIR@``' + ccache = '``@CCNAME@``' + keytab = '``@KTNAME@``' +@@ -243,6 +244,7 @@ else: + sbindir = ':ref:`SBINDIR `' + libdir = ':ref:`LIBDIR `' + localstatedir = ':ref:`LOCALSTATEDIR `' ++ runstatedir = ':ref:`RUNSTATEDIR `' + sysconfdir = ':ref:`SYSCONFDIR `' + ccache = ':ref:`DEFCCNAME `' + keytab = ':ref:`DEFKTNAME `' +@@ -262,6 +264,7 @@ else: + rst_epilog += '.. |sbindir| replace:: %s\n' % sbindir + rst_epilog += '.. |libdir| replace:: %s\n' % libdir + rst_epilog += '.. |kdcdir| replace:: %s\\ ``/krb5kdc``\n' % localstatedir ++ rst_epilog += '.. |kdcrundir| replace:: %s\\ ``/krb5kdc``\n' % runstatedir + rst_epilog += '.. |sysconfdir| replace:: %s\n' % sysconfdir + rst_epilog += '.. |ccache| replace:: %s\n' % ccache + rst_epilog += '.. |keytab| replace:: %s\n' % keytab +diff --git a/doc/mitK5defaults.rst b/doc/mitK5defaults.rst +index 89b8f4c..838dabb 100644 +--- a/doc/mitK5defaults.rst ++++ b/doc/mitK5defaults.rst +@@ -17,6 +17,7 @@ KDC config file :ref:`kdc.conf(5)` |kdcdir|\ ``/kdc.conf`` **KRB + KDC database path (DB2) |kdcdir|\ ``/principal`` + Master key :ref:`stash_definition` |kdcdir|\ ``/.k5.``\ *realm* + Admin server ACL file :ref:`kadm5.acl(5)` |kdcdir|\ ``/kadm5.acl`` ++OTP socket directory |kdcrundir| + Plugin base directory |libdir|\ ``/krb5/plugins`` + :ref:`rcache_definition` directory ``/var/tmp`` **KRB5RCACHEDIR** + Master key default enctype |defmkey| +@@ -64,6 +65,7 @@ Description Symbolic name Custom build path Typical + User programs BINDIR ``/usr/local/bin`` ``/usr/bin`` + Libraries and plugins LIBDIR ``/usr/local/lib`` ``/usr/lib`` + Parent of KDC state dir LOCALSTATEDIR ``/usr/local/var`` ``/var`` ++Parent of KDC runtime dir RUNSTATEDIR ``/usr/local/var/run`` ``/run`` + Administrative programs SBINDIR ``/usr/local/sbin`` ``/usr/sbin`` + Alternate krb5.conf dir SYSCONFDIR ``/usr/local/etc`` ``/etc`` + Default ccache name DEFCCNAME ``FILE:/tmp/krb5cc_%{uid}`` ``FILE:/tmp/krb5cc_%{uid}`` +diff --git a/src/Makefile.in b/src/Makefile.in +index a8bc990..1725093 100644 +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -64,6 +64,7 @@ INSTALLMKDIRS = $(KRB5ROOT) $(KRB5MANROOT) $(KRB5OTHERMKDIRS) \ + $(KRB5_AD_MODULE_DIR) \ + $(KRB5_LIBKRB5_MODULE_DIR) $(KRB5_TLS_MODULE_DIR) \ + @localstatedir@ @localstatedir@/krb5kdc \ ++ @runstatedir@ @runstatedir@/krb5kdc \ + $(KRB5_INCSUBDIRS) $(datadir) $(EXAMPLEDIR) \ + $(PKGCONFIG_DIR) + +diff --git a/src/configure.in b/src/configure.in +index 2145d54..c2eaf78 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -9,6 +9,12 @@ + fi + AC_SUBST(SYSCONFCONF) + ++# If $runstatedir isn't set by autoconf (<2.70), set it manually. ++if test x"$runstatedir" == x; then ++ runstatedir=$localstatedir/run ++fi ++AC_SUBST(runstatedir) ++ + CONFIG_RULES + KRB5_VERSION=K5_VERSION + AC_SUBST(KRB5_VERSION) +diff --git a/src/doc/Makefile.in b/src/doc/Makefile.in +index a6bb7c5..b07e16a 100644 +--- a/src/doc/Makefile.in ++++ b/src/doc/Makefile.in +@@ -7,6 +7,7 @@ DOXYGEN=doxygen + + docsrc=$(top_srcdir)/../doc + localstatedir=@localstatedir@ ++runstatedir=@runstatedir@ + sysconfdir=@sysconfdir@ + DEFCCNAME=@DEFCCNAME@ + DEFKTNAME=@DEFKTNAME@ +@@ -113,6 +114,7 @@ paths.py: + echo 'sbindir = "``$(SERVER_BINDIR)``"' >> $@ + echo 'libdir = "``$(KRB5_LIBDIR)``"' >> $@ + echo 'localstatedir = "``$(localstatedir)``"' >> $@ ++ echo 'runstatedir = "``$(runstatedir)``"' >> $@ + echo 'sysconfdir = "``$(sysconfdir)``"' >> $@ + echo 'ccache = "``$(DEFCCNAME)``"' >> $@ + echo 'keytab = "``$(DEFKTNAME)``"' >> $@ +diff --git a/src/include/Makefile.in b/src/include/Makefile.in +index e13042a..f83ff4e 100644 +--- a/src/include/Makefile.in ++++ b/src/include/Makefile.in +@@ -53,6 +53,7 @@ autoconf.stamp: $(srcdir)/autoconf.h.in $(BUILDTOP)/config.status + + SYSCONFDIR = @sysconfdir@ + LOCALSTATEDIR = @localstatedir@ ++RUNSTATEDIR = @runstatedir@ + BINDIR = @bindir@ + SBINDIR = @sbindir@ + LIBDIR = @libdir@ +@@ -66,6 +67,7 @@ PROCESS_REPLACE = -e "s+@KRB5RCTMPDIR+$(KRB5RCTMPDIR)+" \ + -e "s+@MODULEDIR+$(MODULE_DIR)+" \ + -e "s+@GSSMODULEDIR+$(GSS_MODULE_DIR)+" \ + -e 's+@LOCALSTATEDIR+$(LOCALSTATEDIR)+' \ ++ -e 's+@RUNSTATEDIR+$(RUNSTATEDIR)+' \ + -e 's+@SYSCONFDIR+$(SYSCONFDIR)+' \ + -e 's+@DYNOBJEXT+$(DYNOBJEXT)+' \ + -e 's+@SYSCONFCONF+$(SYSCONFCONF)+' +diff --git a/src/include/osconf.hin b/src/include/osconf.hin +index 90ab86d..871503a 100644 +--- a/src/include/osconf.hin ++++ b/src/include/osconf.hin +@@ -59,6 +59,7 @@ + #define PLUGIN_EXT "@DYNOBJEXT" + + #define KDC_DIR "@LOCALSTATEDIR/krb5kdc" ++#define KDC_RUN_DIR "@RUNSTATEDIR/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" +diff --git a/src/man/Makefile.in b/src/man/Makefile.in +index 4dd2448..2b9c892 100644 +--- a/src/man/Makefile.in ++++ b/src/man/Makefile.in +@@ -5,6 +5,7 @@ SPHINX_BUILD=sphinx-build + GROFF=@GROFF@ + GROFF_MAN=$(GROFF) -mtty-char -Tascii -mandoc -c + localstatedir=@localstatedir@ ++runstatedir=@runstatedir@ + sysconfdir=@sysconfdir@ + DEFCCNAME=@DEFCCNAME@ + DEFKTNAME=@DEFKTNAME@ +@@ -44,6 +45,7 @@ $(docsrc)/version.py: $(top_srcdir)/patchlevel.h + -e 's|@SBINDIR@|$(SERVER_BINDIR)|g' \ + -e 's|@LIBDIR@|$(KRB5_LIBDIR)|g' \ + -e 's|@LOCALSTATEDIR@|$(localstatedir)|g' \ ++ -e 's|@RUNSTATEDIR@|$(runstatedir)|g' \ + -e 's|@SYSCONFDIR@|$(sysconfdir)|g' \ + -e 's|@CCNAME@|$(DEFCCNAME)|g' \ + -e 's|@KTNAME@|$(DEFKTNAME)|g' \ +diff --git a/src/plugins/preauth/otp/otp_state.c b/src/plugins/preauth/otp/otp_state.c +index a4d7e3b..4643dff 100644 +--- a/src/plugins/preauth/otp/otp_state.c ++++ b/src/plugins/preauth/otp/otp_state.c +@@ -40,7 +40,7 @@ + #endif + + #define DEFAULT_TYPE_NAME "DEFAULT" +-#define DEFAULT_SOCKET_FMT KDC_DIR "/%s.socket" ++#define DEFAULT_SOCKET_FMT KDC_RUN_DIR "/%s.socket" + #define DEFAULT_TIMEOUT 5 + #define DEFAULT_RETRIES 3 + #define MAX_SECRET_LEN 1024 diff --git a/SOURCES/krb5-master-no-malloc0.patch b/SOURCES/krb5-master-no-malloc0.patch deleted file mode 100644 index e5b0e63..0000000 --- a/SOURCES/krb5-master-no-malloc0.patch +++ /dev/null @@ -1,39 +0,0 @@ -commit 13fd26e1863c79f616653f6a10a58c01f65fceff -Author: Greg Hudson -Date: Fri Dec 6 18:56:56 2013 -0500 - - Avoid malloc(0) in SPNEGO get_input_token - - If we read a zero-length token in spnego_mech.c's get_input_token(), - set the value pointer to NULL instead of calling malloc(0). - - ticket: 7794 (new) - -diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c -index 24c3440..3937662 100644 ---- a/src/lib/gssapi/spnego/spnego_mech.c -+++ b/src/lib/gssapi/spnego/spnego_mech.c -@@ -3140,14 +3140,17 @@ get_input_token(unsigned char **buff_in, unsigned int buff_length) - return (NULL); - - input_token->length = len; -- input_token->value = gssalloc_malloc(input_token->length); -+ if (input_token->length > 0) { -+ input_token->value = gssalloc_malloc(input_token->length); -+ if (input_token->value == NULL) { -+ free(input_token); -+ return (NULL); -+ } - -- if (input_token->value == NULL) { -- free(input_token); -- return (NULL); -+ memcpy(input_token->value, *buff_in, input_token->length); -+ } else { -+ input_token->value = NULL; - } -- -- (void) memcpy(input_token->value, *buff_in, input_token->length); - *buff_in += input_token->length; - return (input_token); - } diff --git a/SOURCES/krb5-master-rcache-acquirecred-leak.patch b/SOURCES/krb5-master-rcache-acquirecred-leak.patch deleted file mode 100644 index 0ae7b34..0000000 --- a/SOURCES/krb5-master-rcache-acquirecred-leak.patch +++ /dev/null @@ -1,26 +0,0 @@ -commit 9df0c4bdce6b88a01af51e4bbb9a365db00256d5 -Author: Greg Hudson -Date: Wed Jan 15 14:41:54 2014 -0500 - - Clean up rcache if GSS krb5 acquire_cred fails - - The error handler in acquire_cred_context didn't release the rcache, - which would cause it to leak if we failed after acquire_accept_cred. - - ticket: 7818 (new) - target_version: 1.12.2 - tags: pullup - -diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c -index 37cc6b5..f625c0c 100644 ---- a/src/lib/gssapi/krb5/acquire_cred.c -+++ b/src/lib/gssapi/krb5/acquire_cred.c -@@ -829,6 +829,8 @@ error_out: - if (cred->keytab) - krb5_kt_close(context, cred->keytab); - #endif /* LEAN_CLIENT */ -+ if (cred->rcache) -+ krb5_rc_close(context, cred->rcache); - if (cred->name) - kg_release_name(context, &cred->name); - k5_mutex_destroy(&cred->lock); diff --git a/SOURCES/krb5-master-rcache-acquirecred-source.patch b/SOURCES/krb5-master-rcache-acquirecred-source.patch new file mode 100644 index 0000000..71c3876 --- /dev/null +++ b/SOURCES/krb5-master-rcache-acquirecred-source.patch @@ -0,0 +1,136 @@ +commit 7dad0bee30fbbde8cfc0eacd2d1487c198a004a1 +Author: Simo Sorce +Date: Thu Dec 26 19:05:34 2013 -0500 + + Add rcache feature to gss_acquire_cred_from + + The "rcache" cred store entry can specify a replay cache type and name + to be used with the credentials being acquired. + + [ghudson@mit.edu: split up, simplified, and altered to fit preparatory + commits] + + ticket: 7819 (new) + +diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c +index f625c0c..5d680f9 100644 +--- a/src/lib/gssapi/krb5/acquire_cred.c ++++ b/src/lib/gssapi/krb5/acquire_cred.c +@@ -180,7 +180,8 @@ cleanup: + + static OM_uint32 + acquire_accept_cred(krb5_context context, OM_uint32 *minor_status, +- krb5_keytab req_keytab, krb5_gss_cred_id_rec *cred) ++ krb5_keytab req_keytab, const char *rcname, ++ krb5_gss_cred_id_rec *cred) + { + OM_uint32 major; + krb5_error_code code; +@@ -189,6 +190,20 @@ acquire_accept_cred(krb5_context context, OM_uint32 *minor_status, + + assert(cred->keytab == NULL); + ++ /* If we have an explicit rcache name, open it. */ ++ if (rcname != NULL) { ++ code = krb5_rc_resolve_full(context, &rc, rcname); ++ if (code) { ++ major = GSS_S_FAILURE; ++ goto cleanup; ++ } ++ code = krb5_rc_recover_or_initialize(context, rc, context->clockskew); ++ if (code) { ++ major = GSS_S_FAILURE; ++ goto cleanup; ++ } ++ } ++ + if (req_keytab != NULL) { + code = krb5_kt_dup(context, req_keytab, &kt); + } else { +@@ -221,12 +236,14 @@ acquire_accept_cred(krb5_context context, OM_uint32 *minor_status, + goto cleanup; + } + +- /* Open the replay cache for this principal. */ +- code = krb5_get_server_rcache(context, &cred->name->princ->data[0], +- &rc); +- if (code) { +- major = GSS_S_FAILURE; +- goto cleanup; ++ if (rc == NULL) { ++ /* Open the replay cache for this principal. */ ++ code = krb5_get_server_rcache(context, &cred->name->princ->data[0], ++ &rc); ++ if (code) { ++ major = GSS_S_FAILURE; ++ goto cleanup; ++ } + } + } else { + /* Make sure we have a keytab with keys in it. */ +@@ -718,8 +735,8 @@ 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 client_keytab, +- krb5_keytab keytab, krb5_boolean iakerb, +- gss_cred_id_t *output_cred_handle, ++ krb5_keytab keytab, const char *rcname, ++ krb5_boolean iakerb, gss_cred_id_t *output_cred_handle, + OM_uint32 *time_rec) + { + krb5_gss_cred_id_t cred = NULL; +@@ -775,7 +792,7 @@ acquire_cred_context(krb5_context context, OM_uint32 *minor_status, + * in cred->name if desired_princ is specified. + */ + if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { +- ret = acquire_accept_cred(context, minor_status, keytab, cred); ++ ret = acquire_accept_cred(context, minor_status, keytab, rcname, cred); + if (ret != GSS_S_COMPLETE) + goto error_out; + } +@@ -867,7 +884,7 @@ 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, NULL, keytab, +- iakerb, output_cred_handle, time_rec); ++ NULL, iakerb, output_cred_handle, time_rec); + + out: + krb5_free_context(context); +@@ -1135,7 +1152,7 @@ krb5_gss_acquire_cred_from(OM_uint32 *minor_status, + krb5_keytab client_keytab = NULL; + krb5_keytab keytab = NULL; + krb5_ccache ccache = NULL; +- const char *value; ++ const char *rcname, *value; + OM_uint32 ret; + + code = gss_krb5int_initialize_library(); +@@ -1191,9 +1208,14 @@ krb5_gss_acquire_cred_from(OM_uint32 *minor_status, + } + } + ++ ret = kg_value_from_cred_store(cred_store, KRB5_CS_RCACHE_URN, &rcname); ++ if (GSS_ERROR(ret)) ++ goto out; ++ + ret = acquire_cred_context(context, minor_status, desired_name, NULL, + time_req, cred_usage, ccache, client_keytab, +- keytab, 0, output_cred_handle, time_rec); ++ keytab, rcname, 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 0167816..8e4f6d9 100644 +--- a/src/lib/gssapi/krb5/gssapiP_krb5.h ++++ b/src/lib/gssapi/krb5/gssapiP_krb5.h +@@ -1260,6 +1260,7 @@ data_to_gss(krb5_data *input_k5data, gss_buffer_t output_buffer) + #define KRB5_CS_CLI_KEYTAB_URN "client_keytab" + #define KRB5_CS_KEYTAB_URN "keytab" + #define KRB5_CS_CCACHE_URN "ccache" ++#define KRB5_CS_RCACHE_URN "rcache" + + OM_uint32 + kg_value_from_cred_store(gss_const_key_value_set_t cred_store, diff --git a/SOURCES/krb5-master-rcache-acquirecred-test.patch b/SOURCES/krb5-master-rcache-acquirecred-test.patch new file mode 100644 index 0000000..e8eef5e --- /dev/null +++ b/SOURCES/krb5-master-rcache-acquirecred-test.patch @@ -0,0 +1,82 @@ +commit 6f8d5135334c9ddb674f9824e750872b3b0642ea +Author: Greg Hudson +Date: Thu Jan 16 11:49:55 2014 -0500 + + Add test for gss_acquire_cred_from rcache feature + +diff --git a/src/tests/gssapi/t_credstore.c b/src/tests/gssapi/t_credstore.c +index 575f96d..e28f5d0 100644 +--- a/src/tests/gssapi/t_credstore.c ++++ b/src/tests/gssapi/t_credstore.c +@@ -46,7 +46,9 @@ main(int argc, char *argv[]) + gss_cred_usage_t cred_usage = GSS_C_BOTH; + gss_OID_set mechs = GSS_C_NO_OID_SET; + gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; +- krb5_boolean store_creds = FALSE; ++ gss_ctx_id_t ictx = GSS_C_NO_CONTEXT, actx = GSS_C_NO_CONTEXT; ++ gss_buffer_desc itok, atok; ++ krb5_boolean store_creds = FALSE, replay = FALSE; + char opt; + + /* Parse options. */ +@@ -54,6 +56,8 @@ main(int argc, char *argv[]) + opt = (*argv)[1]; + if (opt == 's') + store_creds = TRUE; ++ else if (opt == 'r') ++ replay = TRUE; + else if (opt == 'a') + cred_usage = GSS_C_ACCEPT; + else if (opt == 'b') +@@ -101,6 +105,31 @@ main(int argc, char *argv[]) + &store, &cred, NULL, NULL); + check_gsserr("gss_acquire_cred_from", major, minor); + ++ if (replay) { ++ /* Induce a replay using cred as the acceptor cred, to test the replay ++ * cache indicated by the store. */ ++ major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &ictx, name, ++ &mech_krb5, 0, GSS_C_INDEFINITE, ++ GSS_C_NO_CHANNEL_BINDINGS, ++ GSS_C_NO_BUFFER, NULL, &itok, NULL, NULL); ++ check_gsserr("gss_init_sec_context", major, minor); ++ (void)gss_delete_sec_context(&minor, &ictx, NULL); ++ ++ major = gss_accept_sec_context(&minor, &actx, cred, &itok, ++ GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL, ++ &atok, NULL, NULL, NULL); ++ check_gsserr("gss_accept_sec_context(1)", major, minor); ++ (void)gss_release_buffer(&minor, &atok); ++ (void)gss_delete_sec_context(&minor, &actx, NULL); ++ ++ major = gss_accept_sec_context(&minor, &actx, cred, &itok, ++ GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL, ++ &atok, NULL, NULL, NULL); ++ check_gsserr("gss_accept_sec_context(2)", major, minor); ++ (void)gss_release_buffer(&minor, &atok); ++ (void)gss_delete_sec_context(&minor, &actx, NULL); ++ } ++ + gss_release_name(&minor, &name); + gss_release_cred(&minor, &cred); + free(store.elements); +diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py +index 74139e4..106910d 100755 +--- a/src/tests/gssapi/t_gssapi.py ++++ b/src/tests/gssapi/t_gssapi.py +@@ -91,6 +91,15 @@ realm.kinit(service_cs, None, ['-k', '-t', servicekeytab]) + realm.run(['./t_credstore', '-s', 'p:' + service_cs, 'ccache', storagecache, + 'keytab', servicekeytab]) + ++# Test rcache feature of cred stores. t_credstore -r should produce a ++# replay error normally, but not with rcache set to "none:". ++output = realm.run(['./t_credstore', '-r', '-a', 'p:' + realm.host_princ], ++ expected_code=1) ++if 'gss_accept_sec_context(2): Request is a replay' not in output: ++ fail('Expected replay error not seen in t_credstore output') ++realm.run(['./t_credstore', '-r', '-a', 'p:' + realm.host_princ, ++ 'rcache', 'none:']) ++ + # Verify that we can't acquire acceptor creds without a keytab. + os.remove(realm.keytab) + output = realm.run(['./t_accname', 'p:abc'], expected_code=1) diff --git a/SOURCES/krb5-master-spnego_error_messages.patch b/SOURCES/krb5-master-spnego_error_messages.patch deleted file mode 100644 index 0a14bd3..0000000 --- a/SOURCES/krb5-master-spnego_error_messages.patch +++ /dev/null @@ -1,175 +0,0 @@ -Test tweaked for 1.11.3. - -commit d160bc733a3dbeb6d84f4e175234ff18738d9f66 -Author: Simo Sorce -Date: Tue Dec 17 16:15:14 2013 -0500 - - Let SPNEGO display mechanism errors - - To avoid potential recursion we use a thread local variable that tells - us whether the ancestor was called via spnego_gss_display_name(). If - we detect recursion, we assume that we returned a com_err code like - ENOMEM and call error_message(); in the worst case that will result in - an "Unknown error" message. - - [ghudson@mit.edu: Edited comments and commit message; removed an - unneeded line of code.] - - ticket: 7045 - target_version: 1.12.1 - tags: pullup - -diff --git a/src/include/k5-thread.h b/src/include/k5-thread.h -index 1b7fa69..ab46ec3 100644 ---- a/src/include/k5-thread.h -+++ b/src/include/k5-thread.h -@@ -406,6 +406,7 @@ typedef enum { - K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, - K5_KEY_GSS_KRB5_CCACHE_NAME, - K5_KEY_GSS_KRB5_ERROR_MESSAGE, -+ K5_KEY_GSS_SPNEGO_STATUS, - #if defined(__MACH__) && defined(__APPLE__) - K5_KEY_IPC_CONNECTION_INFO, - #endif -diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c -index 06cfab0..7e4bf90 100644 ---- a/src/lib/gssapi/spnego/spnego_mech.c -+++ b/src/lib/gssapi/spnego/spnego_mech.c -@@ -85,8 +85,8 @@ extern int gssint_put_der_length(unsigned int, unsigned char **, unsigned int); - - - /* private routines for spnego_mechanism */ --static spnego_token_t make_spnego_token(char *); --static gss_buffer_desc make_err_msg(char *); -+static spnego_token_t make_spnego_token(const char *); -+static gss_buffer_desc make_err_msg(const char *); - static int g_token_size(gss_OID_const, unsigned int); - static int g_make_token_header(gss_OID_const, unsigned int, - unsigned char **, unsigned int); -@@ -316,6 +316,12 @@ int gss_krb5int_lib_init(void); - - int gss_spnegoint_lib_init(void) - { -+ int err; -+ -+ err = k5_key_register(K5_KEY_GSS_SPNEGO_STATUS, NULL); -+ if (err) -+ return err; -+ - #ifdef _GSS_STATIC_LINK - return gss_spnegomechglue_init(); - #else -@@ -1791,7 +1797,6 @@ cleanup: - } - #endif /* LEAN_CLIENT */ - -- - /*ARGSUSED*/ - OM_uint32 KRB5_CALLCONV - spnego_gss_display_status( -@@ -1802,6 +1807,9 @@ spnego_gss_display_status( - OM_uint32 *message_context, - gss_buffer_t status_string) - { -+ OM_uint32 maj = GSS_S_COMPLETE; -+ int ret; -+ - dsyslog("Entering display_status\n"); - - *message_context = 0; -@@ -1832,13 +1840,31 @@ spnego_gss_display_status( - "return a valid token")); - break; - default: -- status_string->length = 0; -- status_string->value = ""; -+ /* Not one of our minor codes; might be from a mech. Call back -+ * to gss_display_status, but first check for recursion. */ -+ if (k5_getspecific(K5_KEY_GSS_SPNEGO_STATUS) != NULL) { -+ /* Perhaps we returned a com_err code like ENOMEM. */ -+ const char *err = error_message(status_value); -+ *status_string = make_err_msg(err); -+ break; -+ } -+ /* Set a non-null pointer value; doesn't matter which one. */ -+ ret = k5_setspecific(K5_KEY_GSS_SPNEGO_STATUS, &ret); -+ if (ret != 0) { -+ *minor_status = ret; -+ maj = GSS_S_FAILURE; -+ break; -+ } -+ maj = gss_display_status(minor_status, status_value, -+ status_type, mech_type, -+ message_context, status_string); -+ /* This is unlikely to fail; not much we can do if it does. */ -+ (void)k5_setspecific(K5_KEY_GSS_SPNEGO_STATUS, NULL); - break; - } - - dsyslog("Leaving display_status\n"); -- return (GSS_S_COMPLETE); -+ return maj; - } - - -@@ -3550,13 +3576,13 @@ negotiate_mech(gss_OID_set supported, gss_OID_set received, - * these routines will be changes to return the error string. - */ - static spnego_token_t --make_spnego_token(char *name) -+make_spnego_token(const char *name) - { - return (spnego_token_t)strdup(name); - } - - static gss_buffer_desc --make_err_msg(char *name) -+make_err_msg(const char *name) - { - gss_buffer_desc buffer; - -commit 4faca53e3a8ee213d43da8998f6889e7bfd36248 -Author: Greg Hudson -Date: Wed Dec 18 16:03:16 2013 -0500 - - Test SPNEGO error message in t_s4u.py - - Now that #7045 is fixed, we can check for the correct error message - from t_s4u2proxy_krb5 with --spnego. - - ticket: 7045 - -diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py -index 67dc810..e4aa259 100644 ---- a/src/tests/gssapi/t_s4u.py -+++ b/src/tests/gssapi/t_s4u.py -@@ -30,12 +30,12 @@ if ('auth1: ' + realm.user_princ not in output or - 'NOT_ALLOWED_TO_DELEGATE' not in output): - fail('krb5 -> s4u2proxy') - --# Again with SPNEGO. Bug #7045 prevents us from checking the error --# message, but we can at least exercise the code. -+# Again with SPNEGO. - output = realm.run_as_server(['./t_s4u2proxy_krb5', '--spnego', usercache, - storagecache, '-', pservice1, pservice2], - expected_code=1) --if ('auth1: ' + realm.user_princ not in output): -+if ('auth1: ' + realm.user_princ not in output or -+ 'NOT_ALLOWED_TO_DELEGATE' not in output): - fail('krb5 -> s4u2proxy (SPNEGO)') - - # Try krb5 -> S4U2Proxy without forwardable user creds. This should -@@ -66,10 +66,9 @@ if 'NOT_ALLOWED_TO_DELEGATE' not in output: - fail('s4u2self') - - # Again with SPNEGO. This uses SPNEGO for the initial authentication, --# but still uses krb5 for S4U2Proxy (the delegated cred is returned as -+# but still uses krb5 for S4U2Proxy--the delegated cred is returned as - # a krb5 cred, not a SPNEGO cred, and t_s4u uses the delegated cred --# directly rather than saving and reacquiring it) so bug #7045 does --# not apply and we can verify the error message. -+# directly rather than saving and reacquiring it. - output = realm.run_as_server(['./t_s4u', '--spnego', puser, pservice2], - expected_code=1) - if 'NOT_ALLOWED_TO_DELEGATE' not in output: - fail('s4u2self') diff --git a/SOURCES/krb5-master-strdupcheck.patch b/SOURCES/krb5-master-strdupcheck.patch new file mode 100644 index 0000000..4c9d0c1 --- /dev/null +++ b/SOURCES/krb5-master-strdupcheck.patch @@ -0,0 +1,23 @@ +commit b6810da129512b6d0200580d78d22d38cc214e21 +Author: Lukas Slebodnik +Date: Sat Jun 21 17:09:31 2014 +0200 + + Fix error check in krb5_ldap_parse_principal_name + + Test the correct variable for NULL to detect a strdup failure. + + [ghudson@mit.edu: clarified commit message] + +diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c +index 21695a9..44bf339 100644 +--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c ++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c +@@ -412,7 +412,7 @@ krb5_ldap_parse_principal_name(char *i_princ_name, char **o_princ_name) + at_rlm_name = strrchr(i_princ_name, '@'); + if (!at_rlm_name) { + *o_princ_name = strdup(i_princ_name); +- if (!o_princ_name) ++ if (!*o_princ_name) + return ENOMEM; + } else { + k5_buf_init_dynamic(&buf); diff --git a/SOURCES/krb5-master-test_gss_no_udp.patch b/SOURCES/krb5-master-test_gss_no_udp.patch deleted file mode 100644 index 866647d..0000000 --- a/SOURCES/krb5-master-test_gss_no_udp.patch +++ /dev/null @@ -1,41 +0,0 @@ -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 deleted file mode 100644 index bc6afed..0000000 --- a/SOURCES/krb5-master-test_no_pmap.patch +++ /dev/null @@ -1,244 +0,0 @@ -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_cve_2014_9421_2014_9422_2014_9423_2014_5352_krb5-1.12.2-final.patch b/SOURCES/krb5_cve_2014_9421_2014_9422_2014_9423_2014_5352_krb5-1.12.2-final.patch new file mode 100644 index 0000000..c7bb9a2 --- /dev/null +++ b/SOURCES/krb5_cve_2014_9421_2014_9422_2014_9423_2014_5352_krb5-1.12.2-final.patch @@ -0,0 +1,331 @@ +diff --git a/src/kadmin/server/kadm_rpc_svc.c b/src/kadmin/server/kadm_rpc_svc.c +index 3837931..f4d2a7c 100644 +--- a/src/kadmin/server/kadm_rpc_svc.c ++++ b/src/kadmin/server/kadm_rpc_svc.c +@@ -4,7 +4,7 @@ + * + */ + +-#include ++#include + #include + #include /* for gss_nt_krb5_name */ + #include +@@ -296,14 +296,8 @@ check_rpcsec_auth(struct svc_req *rqstp) + c1 = krb5_princ_component(kctx, princ, 0); + c2 = krb5_princ_component(kctx, princ, 1); + realm = krb5_princ_realm(kctx, princ); +- if (strncmp(handle->params.realm, realm->data, realm->length) == 0 +- && strncmp("kadmin", c1->data, c1->length) == 0) { +- +- if (strncmp("history", c2->data, c2->length) == 0) +- goto fail_princ; +- else +- success = 1; +- } ++ success = data_eq_string(*realm, handle->params.realm) && ++ data_eq_string(*c1, "kadmin") && !data_eq_string(*c2, "history"); + + fail_princ: + if (!success) { +diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c +index b3d1db0..a18cfb0 100644 +--- a/src/lib/gssapi/krb5/context_time.c ++++ b/src/lib/gssapi/krb5/context_time.c +@@ -40,7 +40,7 @@ krb5_gss_context_time(minor_status, context_handle, time_rec) + + ctx = (krb5_gss_ctx_id_rec *) context_handle; + +- if (! ctx->established) { ++ if (ctx->terminated || !ctx->established) { + *minor_status = KG_CTX_INCOMPLETE; + return(GSS_S_NO_CONTEXT); + } +diff --git a/src/lib/gssapi/krb5/export_sec_context.c b/src/lib/gssapi/krb5/export_sec_context.c +index 18a3a34..1b3de68 100644 +--- a/src/lib/gssapi/krb5/export_sec_context.c ++++ b/src/lib/gssapi/krb5/export_sec_context.c +@@ -45,6 +45,11 @@ krb5_gss_export_sec_context(minor_status, context_handle, interprocess_token) + *minor_status = 0; + + ctx = (krb5_gss_ctx_id_t) *context_handle; ++ if (ctx->terminated) { ++ *minor_status = KG_CTX_INCOMPLETE; ++ return (GSS_S_NO_CONTEXT); ++ } ++ + context = ctx->k5_context; + kret = krb5_gss_ser_init(context); + if (kret) +diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h +index 0167816..42d16ad 100644 +--- a/src/lib/gssapi/krb5/gssapiP_krb5.h ++++ b/src/lib/gssapi/krb5/gssapiP_krb5.h +@@ -204,6 +204,7 @@ typedef struct _krb5_gss_ctx_id_rec { + unsigned int established : 1; + unsigned int have_acceptor_subkey : 1; + unsigned int seed_init : 1; /* XXX tested but never actually set */ ++ unsigned int terminated : 1; + OM_uint32 gss_flags; + unsigned char seed[16]; + krb5_gss_name_t here; +diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c +index a408259..088219a 100644 +--- a/src/lib/gssapi/krb5/gssapi_krb5.c ++++ b/src/lib/gssapi/krb5/gssapi_krb5.c +@@ -369,7 +369,7 @@ krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status, + + ctx = (krb5_gss_ctx_id_rec *) context_handle; + +- if (!ctx->established) ++ if (ctx->terminated || !ctx->established) + return GSS_S_NO_CONTEXT; + + for (i = 0; i < sizeof(krb5_gss_inquire_sec_context_by_oid_ops)/ +diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c +index eacb0fd..096df2a 100644 +--- a/src/lib/gssapi/krb5/inq_context.c ++++ b/src/lib/gssapi/krb5/inq_context.c +@@ -105,7 +105,7 @@ krb5_gss_inquire_context(minor_status, context_handle, initiator_name, + + ctx = (krb5_gss_ctx_id_rec *) context_handle; + +- if (! ctx->established) { ++ if (ctx->terminated || !ctx->established) { + *minor_status = KG_CTX_INCOMPLETE; + return(GSS_S_NO_CONTEXT); + } +diff --git a/src/lib/gssapi/krb5/k5seal.c b/src/lib/gssapi/krb5/k5seal.c +index bd1e2a6..b11b615 100644 +--- a/src/lib/gssapi/krb5/k5seal.c ++++ b/src/lib/gssapi/krb5/k5seal.c +@@ -342,7 +342,7 @@ kg_seal(minor_status, context_handle, conf_req_flag, qop_req, + + ctx = (krb5_gss_ctx_id_rec *) context_handle; + +- if (! ctx->established) { ++ if (ctx->terminated || !ctx->established) { + *minor_status = KG_CTX_INCOMPLETE; + return(GSS_S_NO_CONTEXT); + } +diff --git a/src/lib/gssapi/krb5/k5sealiov.c b/src/lib/gssapi/krb5/k5sealiov.c +index 0b99a77..0f80095 100644 +--- a/src/lib/gssapi/krb5/k5sealiov.c ++++ b/src/lib/gssapi/krb5/k5sealiov.c +@@ -284,7 +284,7 @@ kg_seal_iov(OM_uint32 *minor_status, + } + + ctx = (krb5_gss_ctx_id_rec *)context_handle; +- if (!ctx->established) { ++ if (ctx->terminated || !ctx->established) { + *minor_status = KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } +diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c +index b65c83c..9e78550 100644 +--- a/src/lib/gssapi/krb5/k5unseal.c ++++ b/src/lib/gssapi/krb5/k5unseal.c +@@ -492,7 +492,7 @@ kg_unseal(minor_status, context_handle, input_token_buffer, + + ctx = (krb5_gss_ctx_id_rec *) context_handle; + +- if (! ctx->established) { ++ if (ctx->terminated || !ctx->established) { + *minor_status = KG_CTX_INCOMPLETE; + return(GSS_S_NO_CONTEXT); + } +diff --git a/src/lib/gssapi/krb5/k5unsealiov.c b/src/lib/gssapi/krb5/k5unsealiov.c +index 8d6a2da..191de2c 100644 +--- a/src/lib/gssapi/krb5/k5unsealiov.c ++++ b/src/lib/gssapi/krb5/k5unsealiov.c +@@ -628,7 +628,7 @@ kg_unseal_iov(OM_uint32 *minor_status, + OM_uint32 code; + + ctx = (krb5_gss_ctx_id_rec *)context_handle; +- if (!ctx->established) { ++ if (ctx->terminated || !ctx->established) { + *minor_status = KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } +diff --git a/src/lib/gssapi/krb5/lucid_context.c b/src/lib/gssapi/krb5/lucid_context.c +index dc129e1..50d8cc9 100644 +--- a/src/lib/gssapi/krb5/lucid_context.c ++++ b/src/lib/gssapi/krb5/lucid_context.c +@@ -75,6 +75,11 @@ gss_krb5int_export_lucid_sec_context( + *minor_status = 0; + *data_set = GSS_C_NO_BUFFER_SET; + ++ if (ctx->terminated || !ctx->established) { ++ *minor_status = KG_CTX_INCOMPLETE; ++ return GSS_S_NO_CONTEXT; ++ } ++ + retval = generic_gss_oid_decompose(minor_status, + GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID, + GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH, +diff --git a/src/lib/gssapi/krb5/prf.c b/src/lib/gssapi/krb5/prf.c +index a0fbcda..4831f9f 100644 +--- a/src/lib/gssapi/krb5/prf.c ++++ b/src/lib/gssapi/krb5/prf.c +@@ -60,6 +60,10 @@ krb5_gss_pseudo_random(OM_uint32 *minor_status, + ns.data = NULL; + + ctx = (krb5_gss_ctx_id_t)context; ++ if (ctx->terminated || !ctx->established) { ++ *minor_status = KG_CTX_INCOMPLETE; ++ return GSS_S_NO_CONTEXT; ++ } + + switch (prf_key) { + case GSS_C_PRF_KEY_FULL: +diff --git a/src/lib/gssapi/krb5/process_context_token.c b/src/lib/gssapi/krb5/process_context_token.c +index ae33180..a672f48 100644 +--- a/src/lib/gssapi/krb5/process_context_token.c ++++ b/src/lib/gssapi/krb5/process_context_token.c +@@ -39,11 +39,18 @@ krb5_gss_process_context_token(minor_status, context_handle, + + ctx = (krb5_gss_ctx_id_t) context_handle; + +- if (! ctx->established) { ++ if (ctx->terminated || !ctx->established) { + *minor_status = KG_CTX_INCOMPLETE; + return(GSS_S_NO_CONTEXT); + } + ++ /* We only support context deletion tokens for now, and RFC 4121 does not ++ * define a context deletion token. */ ++ if (ctx->proto) { ++ *minor_status = 0; ++ return(GSS_S_DEFECTIVE_TOKEN); ++ } ++ + /* "unseal" the token */ + + if (GSS_ERROR(majerr = kg_unseal(minor_status, context_handle, +@@ -52,8 +59,8 @@ krb5_gss_process_context_token(minor_status, context_handle, + KG_TOK_DEL_CTX))) + return(majerr); + +- /* that's it. delete the context */ +- +- return(krb5_gss_delete_sec_context(minor_status, &context_handle, +- GSS_C_NO_BUFFER)); ++ /* Mark the context as terminated, but do not delete it (as that would ++ * leave the caller with a dangling context handle). */ ++ ctx->terminated = 1; ++ return(GSS_S_COMPLETE); + } +diff --git a/src/lib/gssapi/krb5/wrap_size_limit.c b/src/lib/gssapi/krb5/wrap_size_limit.c +index 7bc4221..ed5c599 100644 +--- a/src/lib/gssapi/krb5/wrap_size_limit.c ++++ b/src/lib/gssapi/krb5/wrap_size_limit.c +@@ -95,7 +95,7 @@ krb5_gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, + } + + ctx = (krb5_gss_ctx_id_rec *) context_handle; +- if (! ctx->established) { ++ if (ctx->terminated || !ctx->established) { + *minor_status = KG_CTX_INCOMPLETE; + return(GSS_S_NO_CONTEXT); + } +diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h +index e56b9c1..2b5145e 100644 +--- a/src/lib/gssapi/mechglue/mglueP.h ++++ b/src/lib/gssapi/mechglue/mglueP.h +@@ -25,7 +25,6 @@ do { \ + */ + typedef struct gss_union_ctx_id_struct { + struct gss_union_ctx_id_struct *loopback; +- struct gss_union_ctx_id_struct *interposer; + gss_OID mech_type; + gss_ctx_id_t internal_ctx_id; + } gss_union_ctx_id_desc, *gss_union_ctx_id_t; +diff --git a/src/lib/kadm5/kadm_rpc_xdr.c b/src/lib/kadm5/kadm_rpc_xdr.c +index 42ac783..975f94c 100644 +--- a/src/lib/kadm5/kadm_rpc_xdr.c ++++ b/src/lib/kadm5/kadm_rpc_xdr.c +@@ -320,6 +320,7 @@ bool_t xdr_krb5_tl_data(XDR *xdrs, krb5_tl_data **tl_data_head) + free(tl); + tl = tl2; + } ++ *tl_data_head = NULL; + break; + + case XDR_ENCODE: +@@ -1096,6 +1097,7 @@ xdr_krb5_principal(XDR *xdrs, krb5_principal *objp) + case XDR_FREE: + if(*objp != NULL) + krb5_free_principal(context, *objp); ++ *objp = NULL; + break; + } + return TRUE; +diff --git a/src/lib/rpc/auth_gssapi_misc.c b/src/lib/rpc/auth_gssapi_misc.c +index 53bdb98..a05ea19 100644 +--- a/src/lib/rpc/auth_gssapi_misc.c ++++ b/src/lib/rpc/auth_gssapi_misc.c +@@ -322,7 +322,6 @@ bool_t auth_gssapi_unwrap_data( + if (! (*xdr_func)(&temp_xdrs, xdr_ptr)) { + PRINTF(("gssapi_unwrap_data: deserializing arguments failed\n")); + gss_release_buffer(minor, &out_buf); +- xdr_free(xdr_func, xdr_ptr); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } +diff --git a/src/lib/rpc/svc_auth_gss.c b/src/lib/rpc/svc_auth_gss.c +index 8da7003..ea8149b 100644 +--- a/src/lib/rpc/svc_auth_gss.c ++++ b/src/lib/rpc/svc_auth_gss.c +@@ -68,16 +68,6 @@ extern const gss_OID_desc * const gss_mech_spkm3; + + extern SVCAUTH svc_auth_none; + +-/* +- * from mit-krb5-1.2.1 mechglue/mglueP.h: +- * Array of context IDs typed by mechanism OID +- */ +-typedef struct gss_union_ctx_id_t { +- gss_OID mech_type; +- gss_ctx_id_t internal_ctx_id; +-} gss_union_ctx_id_desc, *gss_union_ctx_id_t; +- +- + static auth_gssapi_log_badauth_func log_badauth = NULL; + static caddr_t log_badauth_data = NULL; + static auth_gssapi_log_badauth2_func log_badauth2 = NULL; +@@ -242,16 +232,8 @@ svcauth_gss_accept_sec_context(struct svc_req *rqst, + gd->ctx = GSS_C_NO_CONTEXT; + goto errout; + } +- /* +- * ANDROS: krb5 mechglue returns ctx of size 8 - two pointers, +- * one to the mechanism oid, one to the internal_ctx_id +- */ +- if ((gr->gr_ctx.value = mem_alloc(sizeof(gss_union_ctx_id_desc))) == NULL) { +- fprintf(stderr, "svcauth_gss_accept_context: out of memory\n"); +- goto errout; +- } +- memcpy(gr->gr_ctx.value, gd->ctx, sizeof(gss_union_ctx_id_desc)); +- gr->gr_ctx.length = sizeof(gss_union_ctx_id_desc); ++ gr->gr_ctx.value = "xxxx"; ++ gr->gr_ctx.length = 4; + + /* gr->gr_win = 0x00000005; ANDROS: for debugging linux kernel version... */ + gr->gr_win = sizeof(gd->seqmask) * 8; +@@ -523,8 +505,6 @@ gssrpc__svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, + + if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) { + gss_release_buffer(&min_stat, &gr.gr_token); +- mem_free(gr.gr_ctx.value, +- sizeof(gss_union_ctx_id_desc)); + ret_freegc (AUTH_FAILED); + } + *no_dispatch = TRUE; +@@ -534,7 +514,6 @@ gssrpc__svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, + + gss_release_buffer(&min_stat, &gr.gr_token); + gss_release_buffer(&min_stat, &gd->checksum); +- mem_free(gr.gr_ctx.value, sizeof(gss_union_ctx_id_desc)); + if (!call_stat) + ret_freegc (AUTH_FAILED); + diff --git a/SOURCES/persistent_keyring.patch b/SOURCES/persistent_keyring.patch deleted file mode 100644 index 2e625b8..0000000 --- a/SOURCES/persistent_keyring.patch +++ /dev/null @@ -1,3309 +0,0 @@ -Pared down from the git commits, with a wrapper 'run' added 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,18 @@ 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); -+ - /* - * 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 index 08260a2..d405896 100644 --- a/SPECS/krb5.spec +++ b/SPECS/krb5.spec @@ -40,10 +40,10 @@ Summary: The Kerberos network authentication system Name: krb5 -Version: 1.11.3 -Release: 49%{?dist} +Version: 1.12.2 +Release: 14%{?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 +# http://web.mit.edu/kerberos/dist/krb5/1.12/krb5-1.12.2-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 @@ -72,104 +72,78 @@ Source39: krb5-krb5kdc.conf BuildRequires: cmake # Carry this locally until it's available in a packaged form. -Source100: nss_wrapper-0.0-20130719153839Z.git6cb59864.bz2 +Source100: nss_wrapper-0.0-20140204195100.git3d58327.tar.xz Source101: noport.c +Source102: socket_wrapper-0.0-20140204194748.gitf3b2ece.tar.xz -Patch6: krb5-1.10-ksu-path.patch -Patch12: krb5-1.7-ktany.patch -Patch16: krb5-1.10-buildconf.patch +Patch1: krb5-1.12-pwdch-fast.patch +Patch6: krb5-1.12-ksu-path.patch +Patch12: krb5-1.12-ktany.patch +Patch16: krb5-1.12-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 +Patch39: krb5-1.12-api.patch +Patch59: krb5-1.12ish-kpasswd_tcp.patch +Patch60: krb5-1.12.1-pam.patch +Patch63: krb5-1.12-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 -Patch140: krb5-CVE-2013-1417.patch -Patch141: krb5-1.11.3-client-loop.patch -Patch142: krb5-master-keyring-offsets.patch -Patch143: krb5-master-keyring-expiration.patch -Patch144: krb5-1.11-preauthcore.patch -Patch145: krb5-master-keyringccops.patch -Patch146: krb5-master-no-malloc0.patch -Patch147: krb5-master-ignore-empty-unnecessary-final-token.patch -Patch148: krb5-master-gss_oid_leak.patch -Patch149: krb5-master-keytab_close.patch -Patch150: krb5-1.11.3-copy_context.patch -Patch151: krb5-master-spnego_error_messages.patch -Patch152: krb5-master-keyring-kdcsync.patch - -Patch154: krb5-master-rcache-internal-const.patch -Patch155: krb5-master-rcache-acquirecred-cleanup.patch -Patch156: krb5-master-rcache-acquirecred-leak.patch -Patch157: krb5-1.11-rcache-acquirecred-source.patch -Patch158: krb5-master-empty-credstore.patch -Patch159: krb5-1.11.3-1.12.1-credstoretest.patch -Patch160: krb5-1.11-rcache-acquirecred-test.patch - -Patch161: krb5-1.11-spnego-preserve-oid.patch - -Patch162: krb5-1.12-pwdch-fast.patch - -Patch163: krb5-1.11.3-nodelete-pkinit.patch -Patch164: 0001-Don-t-leak-the-creds-we-don-t-plan-to-copy-over.patch -Patch165: 0003-Handlers-won-t-take-care-of-initializing-err.patch -Patch166: 0004-Don-t-leak-the-per-request-preauth-context.patch - -# Patches for otp plugin backport -Patch201: krb5-1.11.2-keycheck.patch -Patch202: krb5-1.11.2-otp.patch -Patch203: krb5-1.11.3-otp2.patch -Patch204: krb5-1.11.5-move-otp-sockets.patch - -# Patches for kernel-persistent-keyring support (backport) -Patch301: persistent_keyring.patch -Patch302: krb5-master-kinit-cccol.patch -Patch303: krb5-keyring-strtol.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 +Patch136: krb5-master-rcache-internal-const.patch +Patch137: krb5-master-rcache-acquirecred-cleanup.patch +Patch139: krb5-master-rcache-acquirecred-source.patch +Patch141: krb5-master-rcache-acquirecred-test.patch +Patch142: krb5-master-move-otp-sockets.patch +Patch145: krb5-master-mechd.patch +Patch146: krb5-master-strdupcheck.patch +Patch147: krb5-master-compatible-keys.patch +Patch148: krb5-1.12-system-exts.patch +Patch201: 0001-In-ksu-merge-krb5_ccache_copy-and-_restricted.patch +Patch202: 0002-In-ksu-don-t-stat-not-on-disk-ccache-residuals.patch +Patch203: 0003-Use-an-intermediate-memory-cache-in-ksu.patch +Patch204: 0004-Make-ksu-respect-the-default_ccache_name-setting.patch +Patch205: 0005-Copy-config-entries-to-the-ksu-target-ccache.patch +Patch206: 0006-Use-more-randomness-for-ksu-secondary-cache-names.patch +Patch207: 0007-Make-krb5_cc_new_unique-create-DIR-directories.patch +Patch300: krb5-1.12-kpasswd-skip-address-check.patch +Patch301: 0000-Refactor-cm-functions-in-sendto_kdc.c.patch +Patch302: 0001-Simplify-sendto_kdc.c.patch +Patch303: 0002-Add-helper-to-determine-if-a-KDC-is-the-master.patch +Patch304: 0003-Use-k5_transport-_strategy-enums-for-k5_sendto.patch +Patch305: 0004-Build-support-for-TLS-used-by-HTTPS-proxy-support.patch +Patch306: 0005-Add-ASN.1-codec-for-KKDCP-s-KDC-PROXY-MESSAGE.patch +Patch307: 0006-Dispatch-style-protocol-switching-for-transport.patch +Patch308: 0007-HTTPS-transport-Microsoft-KKDCPP-implementation.patch +Patch309: 0008-Load-custom-anchors-when-using-KKDCP.patch +Patch310: 0009-Check-names-in-the-server-s-cert-when-using-KKDCP.patch +Patch311: 0010-Add-some-longer-form-docs-for-HTTPS.patch +Patch312: 0011-Have-k5test.py-provide-runenv-to-python-tests.patch +Patch313: 0012-Add-a-simple-KDC-proxy-test-server.patch +Patch314: 0013-Add-tests-for-MS-KKDCP-client-support.patch +Patch315: krb5-1.12ish-tls-plugins.patch +Patch316: krb5-1.12-nodelete-plugins.patch +Patch317: krb5-1.12-ksu-untyped-default-ccache-name.patch +Patch318: krb5-1.12-ksu-no-ccache.patch +Patch319: krb5-kadm5clntmit_libsoname_version_downgrade.patch +Patch320: krb5-ksu_not_working_with_default_principal.patch +Patch321: krb5-CVE_2014_5353_fix_LDAP_misused_policy_name_crash.patch +Patch322: krb5-CVE_2014_5354_support_keyless_principals_in_LDAP.patch +Patch323: krb5_cve_2014_9421_2014_9422_2014_9423_2014_5352_krb5-1.12.2-final.patch +Patch324: krb5-1.13_kinit_C_loop_krb5bug243.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 +BuildRequires: autoconf, bison, flex, gawk, gettext, pkgconfig, sed %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6 -BuildRequires: libcom_err-devel, libss-devel +BuildRequires: libcom_err-devel, libedit-devel, libss-devel %endif BuildRequires: gzip, ncurses-devel, tar -BuildRequires: python-sphinx +BuildRequires: python-sphinx, texlive-pdftex # The texlive package got a lot more complicated here. %if 0%{?fedora} > 17 || 0%{?rhel} > 6 # Taken from \usepackage directives produced by sphinx: @@ -211,6 +185,11 @@ BuildRequires: iproute %if 0%{?fedora} >= 9 BuildRequires: python-pyrad %endif +%if 0%{?fedora} >= 8 +%ifarch %{ix86} x86_64 +BuildRequires: yasm +%endif +%endif %if %{WITH_LDAP} BuildRequires: openldap-devel @@ -353,20 +332,39 @@ 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 -%patch303 -p1 -b .keyring-strtol - -%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 +%setup -q -a 3 -a 100 -a 102 +ln NOTICE LICENSE + +%patch201 -p1 -b .In-ksu-merge-krb5_ccache_copy-and-_restricted +%patch202 -p1 -b .In-ksu-don-t-stat-not-on-disk-ccache-residuals +%patch203 -p1 -b .Use-an-intermediate-memory-cache-in-ksu +%patch204 -p1 -b .Make-ksu-respect-the-default_ccache_name-setting +%patch205 -p1 -b .Copy-config-entries-to-the-ksu-target-ccache +%patch206 -p1 -b .Use-more-randomness-for-ksu-secondary-cache-names +%patch207 -p1 -b .Make-krb5_cc_new_unique-create-DIR-directories + +%patch300 -p1 -b .kpasswd-skip-address-check +%patch301 -p1 -b .Refactor-cm-functions-in-sendto_kdc.c +%patch302 -p1 -b .Simplify-sendto_kdc.c +%patch303 -p1 -b .Add-helper-to-determine-if-a-KDC-is-the-master +%patch304 -p1 -b .Use-k5_transport-_strategy-enums-for-k5_sendto +%patch305 -p1 -b .Build-support-for-TLS-used-by-HTTPS-proxy-support +%patch306 -p1 -b .Add-ASN.1-codec-for-KKDCP-s-KDC-PROXY-MESSAGE +%patch307 -p1 -b .Dispatch-style-protocol-switching-for-transport +%patch308 -p1 -b .HTTPS-transport-Microsoft-KKDCPP-implementation +%patch309 -p1 -b .Load-custom-anchors-when-using-KKDCP +%patch310 -p1 -b .Check-names-in-the-server-s-cert-when-using-KKDCP +%patch311 -p1 -b .Add-some-longer-form-docs-for-HTTPS +%patch312 -p1 -b .Have-k5test.py-provide-runenv-to-python-tests +%patch313 -p1 -b .Add-a-simple-KDC-proxy-test-server +%patch314 -p1 -b .Add-tests-for-MS-KKDCP-client-support +%patch315 -p1 -b .tls-plugins +%patch316 -p1 -b .nodelete-plugins +%patch317 -p1 -b .ksu-untyped-default-ccache-name +%patch318 -p1 -b .ksu-no-ccache +chmod u+x src/util/paste-kdcproxy.py + +%patch1 -p1 -b .pwdch-fast %patch60 -p1 -b .pam @@ -379,72 +377,36 @@ ln -s NOTICE LICENSE %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 -%patch140 -p1 -b .CVE-2013-1417 -%patch141 -p1 -b .client-loop -%patch142 -p1 -b .keyring-offsets -%patch143 -p1 -b .keyring-expiration -%patch144 -p0 -b .preauthcore -%patch145 -p1 -b .keyringccops -%patch146 -p1 -b .no-malloc0 -%patch147 -p1 -b .ignore-empty-unnecessary-final-token -%patch148 -p1 -b .gss_oid_leak -%patch149 -p1 -b .keytab_close -%patch150 -p1 -b .copy_context -%patch151 -p1 -b .spnego_error_messages -%patch152 -p1 -b .keyring-kdcsync - -%patch154 -p1 -b .rcache-internal-const -%patch155 -p1 -b .rcache-acquirecred-cleanup -%patch156 -p1 -b .rcache-acquirecred-leak -%patch157 -p1 -b .rcache-acquirecred-source -%patch158 -p1 -b .empty-credstore -%patch159 -p1 -b .credstoretest -%patch160 -p1 -b .rcache-acquirecred-test - -%patch161 -p1 -b .spnego-preserve-oid -%patch162 -p1 -b .pwdch-fast -%patch163 -p1 -b .nodelete-pkinit -%patch164 -p1 -b .Don-t-leak-the-creds-we-don-t-plan-to-copy-over -%patch165 -p1 -b .Handlers-won-t-take-care-of-initializing-err -%patch166 -p1 -b .Don-t-leak-the-per-request-preauth-context - -%patch201 -p1 -b .keycheck -%patch202 -p1 -b .otp -%patch203 -p1 -b .otp2 -%patch204 -p1 -b .move-otp-sockets + +%patch136 -p1 -b .rcache-internal-const +%patch137 -p1 -b .rcache-acquirecred-cleanup +%patch139 -p1 -b .rcache-acquirecred-source +%patch141 -p1 -b .rcache-acquirecred-test +%patch142 -p1 -b .move-otp-sockets +%patch145 -p1 -b .master-mechd +%patch146 -p1 -b .master-strdupcheck +%patch147 -p1 -b .master-compatible-keys +%patch148 -p1 -b .system-exts +%patch319 -p1 -b .krb5-kadm5clntmit_libsoname_version_downgrade +%patch320 -p1 -b .krb5-ksu_not_working_with_default_principal +%patch321 -p1 -b .krb5-cve_2014_5353_fix_ldap_misused_policy_name_crash +%patch322 -p1 -b .krb5-cve_2014_5354_support_keyless_principals_in_ldap +%patch323 -p1 -b .krb5_cve_2014_9421_2014_9422_2014_9423_2014_5352_krb5-1.12.2-final +%patch324 -p1 -b .krb5_1_13_kinit_C_loop_krb5bug243 + # Take the execute bit off of documentation. -chmod -x doc/krb5-protocol/*.txt +chmod -x doc/krb5-protocol/*.txt doc/ccapi/*.html # Generate an FDS-compatible LDIF file. inldif=src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif @@ -464,8 +426,9 @@ pushd src ./util/reconf --verbose popd -# Create build space for the test wrapper. +# Create build spaces for the test wrappers. mkdir -p nss_wrapper/build +mkdir -p socket_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. @@ -473,7 +436,6 @@ 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` @@ -556,7 +518,7 @@ popd configured_kdcrundir=`grep KDC_RUN_DIR src/include/osconf.h | awk '{print $NF}'` configured_kdcrundir=`eval echo $configured_kdcrundir` if test "$configured_kdcrundir" != %{_localstatedir}/run/krb5kdc ; then - exit 1 + exit 1 fi # Build the docs. @@ -572,11 +534,15 @@ 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. +# Build the test wrappers. pushd nss_wrapper/build cmake .. make popd +pushd socket_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 @@ -592,9 +558,10 @@ fi # 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" +echo 127.0.0.1 $NSS_WRAPPER_HOSTNAME $NSS_WRAPPER_HOSTNAME localhost localhost >"$NSS_WRAPPER_HOSTS" NOPORT=53,111; export NOPORT -LD_PRELOAD=`pwd`/noport.so:`pwd`/nss_wrapper/build/src/libnss_wrapper.so ; export LD_PRELOAD +SOCKET_WRAPPER_DIR=`pwd`/sockets; mkdir -p $SOCKET_WRAPPER_DIR; export SOCKET_WRAPPER_DIR +LD_PRELOAD=`pwd`/noport.so:`pwd`/nss_wrapper/build/src/libnss_wrapper.so:`pwd`/socket_wrapper/build/src/libsocket_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 @@ -625,6 +592,10 @@ 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 +# Parent of groups of configuration files for a list of loadable GSS mechs +# ("mechs"). This location is not relative to sysconfdir, and is also +# hard-coded in g_initialize.c. +mkdir -m 755 -p $RPM_BUILD_ROOT/etc/gss/mech.d # 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. @@ -709,6 +680,7 @@ 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/tls install -pdm 755 $RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/authdata # The rest of the binaries, headers, libraries, and docs. @@ -805,8 +777,8 @@ fi # 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 +if [ $1 -eq 1 ] ; then + # Initial installation /bin/systemctl daemon-reload >/dev/null 2>&1 || : fi %else @@ -857,7 +829,7 @@ exit 0 %if %{WITH_SYSTEMD} %triggerun server -- krb5-server < 1.9.1-13 # Save the current service runlevel info -# User must manually run +# User must manually run # systemd-sysv-convert --apply krb5kdc # systemd-sysv-convert --apply kadmin # systemd-sysv-convert --apply kprop @@ -984,7 +956,7 @@ exit 0 %{_sbindir}/krb5kdc %{_mandir}/man8/krb5kdc.8* -# This is here for people who want to test their server, and also +# 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* @@ -1010,10 +982,13 @@ exit 0 %files libs -f %{gettext_domain}.lang %defattr(-,root,root,-) -%doc README NOTICE LICENSE +%doc README NOTICE +%{!?_licensedir:%global license %%doc} +%license LICENSE %docdir %{_mandir} -# This is a hard-coded, not-dependent-on-the-configure-script path. +# These are hard-coded, not-dependent-on-the-configure-script paths. %dir /etc/gss +%dir /etc/gss/mech.d %verify(not md5 size mtime) %config(noreplace) /etc/krb5.conf /%{_mandir}/man5/.k5identity.5* /%{_mandir}/man5/.k5login.5* @@ -1043,6 +1018,7 @@ exit 0 %dir %{_libdir}/krb5 %dir %{_libdir}/krb5/plugins %dir %{_libdir}/krb5/plugins/* +%{_libdir}/krb5/plugins/tls/k5tls.so %{_libdir}/krb5/plugins/kdb/db2.so %dir %{_var}/kerberos %dir %{_var}/kerberos/krb5 @@ -1086,6 +1062,7 @@ exit 0 %{_libdir}/libkrad.so %{_libdir}/libkrb5.so %{_libdir}/libkrb5support.so +%{_libdir}/pkgconfig/* %{_bindir}/krb5-config %{_bindir}/sclient @@ -1104,32 +1081,146 @@ exit 0 %{_sbindir}/gss-server %{_sbindir}/uuserver + %changelog -* Tue Mar 11 2014 Nalin Dahyabhai - 1.11.3-49 -- mark the pkinit module "nodelete" so that applications which cause it - to be loaded and unloaded repeatedly don't suffer from memory loss when - libcrypto is initialized, allocating memory in the process, and then - unloaded along with the module (most of #1063732) -- when copying creds from one ccache to another, if we single out one - server for which creds shouldn't be copied, don't leak the memory - that those creds use (a bit more of #1063732) -- fix an uninitialized variable warning that could, rarely, cause a - service-unavailable error to be reported when a server was merely - unreachable (spotted while chasing #1063732) -- don't leak the per-request context allocated by preauth modules (a - bit more of #1063732) - -* Wed Mar 5 2014 Nathaniel McCallum - 1.11.3-48 -- add Nathaniel's backported fix for to make password changes work properly - when performed while obtaining creds over FAST (RT#7868, #1072579) - -* Tue Feb 18 2014 Nalin Dahyabhai - 1.11.3-47 +* Mon Jan 26 2015 Roland Mainz - 1.12.2-14 +- fix for kinit -C loops (#1184629, MIT/krb5 issue 243, "Do not + loop on principal unknown errors"). + +* Mon Jan 12 2015 Roland Mainz - 1.12.2-13 +- fix for CVE-2014-5352 (#1179856) "gss_process_context_token() + incorrectly frees context (MITKRB5-SA-2015-001)" +- fix for CVE-2014-9421 (#1179857) "kadmind doubly frees partial + deserialization results (MITKRB5-SA-2015-001)" +- fix for CVE-2014-9422 (#1179861) "kadmind incorrectly + validates server principal name (MITKRB5-SA-2015-001)" +- fix for CVE-2014-9423 (#1179863) "libgssrpc server applications + leak uninitialized bytes (MITKRB5-SA-2015-001)" + +* Mon Dec 22 2014 Roland Mainz - 1.12.2-12 +- fix for CVE-2014-5354 (#1174546) "krb5: NULL pointer + dereference when using keyless entries" + +* Mon Dec 22 2014 Roland Mainz - 1.12.2-11 +- fix for CVE-2014-5353 (#1174543) "Fix LDAP misused policy + name crash" + +* Sun Dec 7 2014 Roland Mainz - 1.12.2-10 +- In ksu, without the -e flag, also check .k5users (#1105489) + When ksu was explicitly told to spawn a shell, a line in .k5users which + listed "*" as the allowed command would cause the principal named on the + line to be considered as a candidate for authentication. + When ksu was not passed a command to run, which implicitly meant that + the invoking user wanted to run the target user's login shell, knowledge + that the principal was a valid candidate was ignored, which could cause + a less optimal choice of the default target principal. + This doesn't impact the authorization checks which we perform later. + Patch by Nalin Dahyabhai + +* Wed Dec 3 2014 Roland Mainz - 1.12.2-9 +- Undo libkadmclnt SONAME change (from 8 to 9) which originally + happened in the krb5 1.12 rebase (#1166012) but broke + rubygem-rkerberos (sort of ruby language bindings for + libkadmclnt&co.) dependicies, as side effect of + rubygem-rkerberos using private interfaces in libkadmclnt. + +* Mon Sep 8 2014 Nalin Dahyabhai - 1.12.2-8 +- fix the problem where the %%license file has been a dangling symlink +- ksu: pull in fix from pull #206 to avoid breakage when the + default_ccache_name doesn't include a cache type as a prefix +- ksu: pull in a proposed fix for pull #207 to avoid breakage when the + invoking user doesn't already have a ccache + +* Sat Sep 6 2014 Nalin Dahyabhai - 1.12.2-7 +- pull in patch from master to load plugins with RTLD_NODELETE, when + defined (RT#7947) + +* Fri Sep 5 2014 Nalin Dahyabhai - 1.12.2-6 +- backport patch to make the client skip checking the server's reply + address when processing responses to password-change requests, which + between NAT and upcoming HTTPS support, can cause us to erroneously + report an error to the user when the server actually reported success + (RT#7886) +- backport support for accessing KDCs and kpasswd services via HTTPS + proxies (marked by being specified as https URIs instead as hostnames + or hostname-and-port), such as the one implemented in python-kdcproxy + (RT#7929, #109919), and pick up a subsequent patch to build HTTPS + as a plugin + +* Thu Aug 28 2014 Nalin Dahyabhai - 1.12.2-5 +- backport fix for trying all compatible keys when not being strict about + acceptor names while reading AP-REQs (RT#7883, #1078888) +- define _GNU_SOURCE in files where we use EAI_NODATA, to make sure that + it's declared (#1059730,#1084068,#1109102) + +* Tue Aug 26 2014 Nalin Dahyabhai - 1.12.2-4 +- kpropd hasn't bothered with -S since 1.11; stop trying to use that flag + in the systemd unit file + +* Wed Aug 20 2014 Nalin Dahyabhai - 1.12.2-3 +- pull in upstream fix for an incorrect check on the value returned by a + strdup() call (#1132062) + +* Sun Aug 17 2014 Fedora Release Engineering - 1.12.1-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Sun Aug 17 2014 Fedora Release Engineering - 1.12.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Fri Aug 15 2014 Nalin Dahyabhai - 1.12.2-1 +- update to 1.12.2 + - drop patch for RT#7820, fixed in 1.12.2 + - drop patch for #231147, fixed as RT#3277 in 1.12.2 + - drop patch for RT#7818, fixed in 1.12.2 + - drop patch for RT#7836, fixed in 1.12.2 + - drop patch for RT#7858, fixed in 1.12.2 + - drop patch for RT#7924, fixed in 1.12.2 + - drop patch for RT#7926, fixed in 1.12.2 + - drop patches for CVE-2014-4341/CVE-2014-4342, included in 1.12.2 + - drop patch for CVE-2014-4343, included in 1.12.2 + - drop patch for CVE-2014-4344, included in 1.12.2 + - drop patch for CVE-2014-4345, included in 1.12.2 +- replace older proposed changes for ksu with backports of the changes + after review and merging upstream (#1015559, #1026099, #1118347) + +* Thu Aug 7 2014 Nalin Dahyabhai - 1.12.1-14 +- incorporate fix for MITKRB5-SA-2014-001 (CVE-2014-4345) + +* Mon Jul 21 2014 Nalin Dahyabhai - 1.12.1-13 +- gssapi: pull in upstream fix for a possible NULL dereference + in spnego (CVE-2014-4344) + +* Wed Jul 16 2014 Nalin Dahyabhai - 1.12.1-12 +- gssapi: pull in proposed fix for a double free in initiators (David + Woodhouse, CVE-2014-4343, #1117963) + +* Sat Jul 12 2014 Tom Callaway - 1.12.1-11 +- fix license handling + +* Mon Jul 7 2014 Nalin Dahyabhai - 1.12.1-10 +- pull in fix for denial of service by injection of malformed GSSAPI tokens + (CVE-2014-4341, CVE-2014-4342, #1116181) + +* Tue Jun 24 2014 Nalin Dahyabhai - 1.12.1-9 +- pull in changes from upstream which add processing of the contents of + /etc/gss/mech.d/*.conf when loading GSS modules (#1102839) + +* Thu Jun 12 2014 Nalin Dahyabhai - 1.12.1-8 +- pull in fix for building against tcl 8.6 (#1107061) + +* Sun Jun 08 2014 Fedora Release Engineering - 1.12.1-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Tue Mar 04 2014 Nathaniel McCallum - 1.12.1-6 +- Backport fix for change password requests when using FAST (RT#7868) + +* Mon Feb 17 2014 Nalin Dahyabhai - 1.12.1-5 - spnego: pull in patch from master to restore preserving the OID of the mechanism the initiator requested when we have multiple OIDs for the same mechanism, so that we reply using the same mechanism OID and the initiator - doesn't get confused (#1066002, RT#7858) + doesn't get confused (#1066000, RT#7858) -* Mon Feb 10 2014 Nalin Dahyabhai - 1.11.3-46 +* Fri Feb 7 2014 Nalin Dahyabhai - 1.12.1-4 - pull in patch from master to move the default directory which the KDC uses when computing the socket path for a local OTP daemon from the database directory (/var/kerberos/krb5kdc) to the newly-added run directory @@ -1139,33 +1230,78 @@ exit 0 boot-time - own /var/run/krb5kdc -* Fri Jan 24 2014 Daniel Mach - 1.11.3-45 -- Mass rebuild 2014-01-24 - -* Tue Jan 21 2014 Nalin Dahyabhai - 1.11.3-44 -- pull in and backport multiple changes to allow replay caches to be added to - a GSS credential store as "rcache"-type credentials (RT#7818/#7819/#7836, - #1056078/#1056080) - -* Fri Jan 17 2014 Nalin Dahyabhai - 1.11.3-43 -- switch to upstream's fix for #1030607 +* Fri Jan 31 2014 Nalin Dahyabhai - 1.12.1-3 +- refresh nss_wrapper and add socket_wrapper to the %%check environment -* Wed Jan 15 2014 Nalin Dahyabhai - 1.11.3-42 -- add proposed patch to fix the GSSAPI library's checks for expired - client creds in gss_init_sec_context() so that they work with keyring - caches (RT#7820, #1030607) +* Fri Jan 31 2014 Nalin Dahyabhai +- add currently-proposed changes to teach ksu about credential cache + collections and the default_ccache_name setting (#1015559,#1026099) -* Fri Dec 27 2013 Daniel Mach - 1.11.3-41 -- Mass rebuild 2013-12-27 +* Tue Jan 21 2014 Nalin Dahyabhai - 1.12.1-2 +- pull in multiple changes to allow replay caches to be added to a GSS + credential store as "rcache"-type credentials (RT#7818/#7819/#7836, + #1056078/#1056080) -* Thu Dec 19 2013 Nalin Dahyabhai - 1.11.3-40 +* Fri Jan 17 2014 Nalin Dahyabhai - 1.12.1-1 +- update to 1.12.1 + - drop patch for RT#7794, included now + - drop patch for RT#7797, included now + - drop patch for RT#7803, included now + - drop patch for RT#7805, included now + - drop patch for RT#7807, included now + - drop patch for RT#7045, included now + - drop patches for RT#7813 and RT#7815, included now + - add patch to always retrieve the KDC time offsets from keyring caches, + so that we don't mistakenly interpret creds as expired before their + time when our clock is ahead of the KDC's (RT#7820, #1030607) + +* Mon Jan 13 2014 Nalin Dahyabhai - 1.12-11 +- update the PIC patch for iaesx86.s to not use ELF relocations to the version + that landed upstream (RT#7815, #1045699) + +* Thu Jan 9 2014 Nalin Dahyabhai +- pass -Wl,--warn-shared-textrel to the compiler when we're creating shared + libraries + +* Thu Jan 9 2014 Nalin Dahyabhai - 1.12-10 +- amend the PIC patch for iaesx86.s to also save/restore ebx in the + functions where we modify it, because the ELF spec says we need to + +* Mon Jan 6 2014 Nalin Dahyabhai - 1.12-9 +- grab a more-commented version of the most recent patch from upstream + master +- make a guess at making the 32-bit AES-NI implementation sufficiently + position-independent to not require execmod permissions for libk5crypto + (more of #1045699) + +* Thu Jan 2 2014 Nalin Dahyabhai - 1.12-8 +- add patch from Dhiru Kholia for the AES-NI implementations to allow + libk5crypto to be properly marked as not needing an executable stack + on arches where they're used (#1045699, and so many others) + +* Thu Jan 2 2014 Nalin Dahyabhai - 1.12-7 +- revert that last change for a bit while sorting out execstack when we + use AES-NI (#1045699) + +* Thu Dec 19 2013 Nalin Dahyabhai - 1.12-6 +- add yasm as a build requirement for AES-NI support, on arches that have + yasm and AES-NI + +* Thu Dec 19 2013 Nalin Dahyabhai - 1.12-5 - pull in fix from master to make reporting of errors encountered by the SPNEGO mechanism work better (RT#7045, part of #1043962) -* Thu Dec 19 2013 Nalin Dahyabhai - 1.11.3-39 +* Thu Dec 19 2013 Nalin Dahyabhai +- update a test wrapper to properly handle things that the new libkrad does, + and add python-pyrad as a build requirement so that we can run its tests + +* Wed Dec 18 2013 Nalin Dahyabhai - 1.12-4 +- revise previous patch to initialize one more element + +* Wed Dec 18 2013 Nalin Dahyabhai - 1.12-3 - backport fixes to krb5_copy_context (RT#7807, #1044735/#1044739) -* Wed Dec 18 2013 Nalin Dahyabhai - 1.11.3-38 +* Wed Dec 18 2013 Nalin Dahyabhai - 1.12-2 - pull in fix from master to return a NULL pointer rather than allocating zero bytes of memory if we read a zero-length input token (RT#7794, part of #1043962) @@ -1177,61 +1313,74 @@ exit 0 cases which could occur while obtaining acceptor credentials (RT#7805, part of #1043962) -* Tue Dec 17 2013 Nalin Dahyabhai - 1.11.3-37 -- backport additional changes to libkrad to make it function more like - the version in upstream 1.12, and a few things in the OTP plugin as - well (most visibly, that the secret that's shared with the RADIUS server - is read from a file rather than used directly) (#1040056) - -* Thu Dec 5 2013 Nalin Dahyabhai - 1.11.3-36 -- backport fix to avoid double-freeing in the client when we're configured - to use a clpreauth module that isn't actually a clpreauth module (#1035203) -- implement checks for the keyring ccache not existing in the keyring - get/set-flags methods, and set an error message if we fail to read - the principal name from a kernel ccache (#1034690) - -* Mon Nov 18 2013 Nalin Dahyabhai - 1.11.3-35 -- backport fix to not spin on a short read when reading the length of a - response over TCP (RT#7508, #1029674) +* Wed Dec 11 2013 Nalin Dahyabhai - 1.12-1 +- update to 1.12 final + +* Mon Dec 2 2013 Nalin Dahyabhai - 1.12-beta2.0 +- update to beta2 + - drop obsolete backports for storing KDC time offsets and expiration times + in keyring credential caches + +* Tue Nov 19 2013 Nalin Dahyabhai - 1.12-beta1.0 +- rebase to master +- update to beta1 + - drop obsolete backport of fix for RT#7706 + +* Mon Nov 18 2013 Nalin Dahyabhai - 1.11.4-2 - pull in fix to store KDC time offsets in keyring credential caches (RT#7768, #1030607) - pull in fix to set expiration times on credentials stored in keyring credential caches (RT#7769, #1031724) -* Fri Nov 15 2013 Nalin Dahyabhai - 1.11.3-34 -- incorporate fix for a KDC NULL pointer dereference while handling referrals - (CVE-2013-1417, #1030745) +* Tue Nov 12 2013 Nalin Dahyabhai - 1.11.4-1 +- update to 1.11.4 + - drop patch for RT#7650, obsoleted + - drop patch for RT#7706, obsoleted as RT#7723 + - drop patch for CVE-2013-1418/CVE-2013-6800, included in 1.11.4 -* Tue Nov 12 2013 Nalin Dahyabhai - 1.11.3-33 -- also handle cache collections when performing heuristics to determine a - target principal name (#1030002, actually more of #1015559) +* Tue Nov 12 2013 Nalin Dahyabhai - 1.11.3-31 +- switch to the simplified version of the patch for #1029110 (RT#7764) -* Tue Nov 12 2013 Nalin Dahyabhai - 1.11.3-32 +* Mon Nov 11 2013 Nalin Dahyabhai - 1.11.3-30 - check more thoroughly for errors when resolving KEYRING ccache names of type "persistent", which should only have a numeric UID as the next part of the name (#1029110) -* 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/CVE-2013-6800) + realms simultaneously (RT#7756, CVE-2013-1418/CVE-2013-6800, + #1026997/#1031501) -* Tue Nov 5 2013 Nalin Dahyabhai - 1.11.3-28 +* Mon Nov 4 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 + when non-FILE: caches are in use (#1026099), 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) +* Thu Oct 17 2013 Nalin Dahyabhai - 1.12-alpha1.0 +- initial update to alpha1 + - drop backport of persistent keyring support + - drop backport for RT#7689 + - drop obsolete patch for fixing a use-before-init in a test program + - drop obsolete patch teaching config.guess/config.sub about aarch64-linux + - drop backport for RT#7598 + - drop backport for RT#7172 + - drop backport for RT#7642 + - drop backport for RT#7643 + - drop 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; obsolete + - drop backports for RT#7682 + - drop backport for RT#7709 + - drop backport for RT#7590 and partial backport for RT#7680 + - drop OTP backport + - drop backports for RT#7656 and RT#7657 +- BuildRequires: libedit-devel to prefer it +- BuildRequires: pkgconfig, since configure uses it + * Wed Oct 16 2013 Nalin Dahyabhai - 1.11.3-26 - create and own /etc/gss (#1019937) @@ -2538,7 +2687,7 @@ exit 0 * 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)