diff --git a/0001-aclocal-fix-typo-in-idmap.m4.patch b/0001-aclocal-fix-typo-in-idmap.m4.patch new file mode 100644 index 0000000..9f32bc3 --- /dev/null +++ b/0001-aclocal-fix-typo-in-idmap.m4.patch @@ -0,0 +1,28 @@ +From bbbf7133aec555c5d27ee3163d6045ecfc4673d9 Mon Sep 17 00:00:00 2001 +From: Jeff Layton +Date: Tue, 12 Jul 2016 16:53:25 -0400 +Subject: [cifs-utils PATCH 1/3] aclocal: fix typo in idmap.m4 + +We really don't want to do the same check twice. + +Signed-off-by: Jeff Layton +--- + aclocal/idmap.m4 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/aclocal/idmap.m4 b/aclocal/idmap.m4 +index 3ccdae3ab968..4e16a46568a1 100644 +--- a/aclocal/idmap.m4 ++++ b/aclocal/idmap.m4 +@@ -19,7 +19,7 @@ if test $enable_cifsidmap != "no" -o $enable_cifsacl != "no"; then + ]) + fi + +-if test $enable_cifsacl != "no" -o $enable_cifsacl != "no"; then ++if test $enable_cifsidmap != "no" -o $enable_cifsacl != "no"; then + ac_wbc_save_LDFLAGS="$LDFLAGS" + ac_wbc_save_LIBS="$LIBS" + LDFLAGS="$LDFLAGS $WBCLIENT_LIBS" +-- +2.7.4 + diff --git a/0002-cifs.upcall-use-krb5-routines-to-get-default-ccname.patch b/0002-cifs.upcall-use-krb5-routines-to-get-default-ccname.patch new file mode 100644 index 0000000..a4dc81f --- /dev/null +++ b/0002-cifs.upcall-use-krb5-routines-to-get-default-ccname.patch @@ -0,0 +1,215 @@ +From 9be6e885c3bd63aa6ae9e6351e1b33a4b15d9183 Mon Sep 17 00:00:00 2001 +From: Jeff Layton +Date: Sun, 21 Aug 2016 09:42:59 -0400 +Subject: [cifs-utils PATCH 2/3] cifs.upcall: use krb5 routines to get default + ccname + +Currently we end up groveling around in /tmp, trying to guess what the +credcache will be. Instead, just get the default ccname for the user, +and then see if it has a valid tgt. If it doesn't then we try to use +the keytab to init the credcache before proceeding. + +Signed-off-by: Jeff Layton +--- + cifs.upcall.c | 148 +++++++++++----------------------------------------------- + 1 file changed, 27 insertions(+), 121 deletions(-) + +diff --git a/cifs.upcall.c b/cifs.upcall.c +index e8544c2b68ad..d0f6d089d8e1 100644 +--- a/cifs.upcall.c ++++ b/cifs.upcall.c +@@ -52,12 +52,6 @@ + #include "spnego.h" + #include "cifs_spnego.h" + +-#define CIFS_DEFAULT_KRB5_DIR "/tmp" +-#define CIFS_DEFAULT_KRB5_USER_DIR "/run/user/%U" +-#define CIFS_DEFAULT_KRB5_PREFIX "krb5cc" +- +-#define MAX_CCNAME_LEN PATH_MAX + 5 +- + static const char *prog = "cifs.upcall"; + typedef enum _sectype { + NONE = 0, +@@ -178,13 +172,34 @@ err_cache: + return credtime; + } + +-static int krb5cc_filter(const struct dirent *dirent) ++static char * ++get_default_cc(void) + { +- /* subtract 1 for the null terminator */ +- return !strncmp(dirent->d_name, CIFS_DEFAULT_KRB5_PREFIX, +- sizeof(CIFS_DEFAULT_KRB5_PREFIX) - 1); ++ krb5_error_code ret; ++ const char *ccname; ++ char *rcc = NULL; ++ krb5_context context = NULL; ++ ++ ret = krb5_init_context(&context); ++ if (ret) { ++ syslog(LOG_DEBUG, "krb5_init_context: %d", (int)ret); ++ return NULL; ++ } ++ ++ ccname = krb5_cc_default_name(context); ++ if (!ccname) { ++ syslog(LOG_DEBUG, "krb5_cc_default returned NULL."); ++ goto out_free_context; ++ } ++ ++ if (get_tgt_time(ccname)) ++ rcc = strdup(ccname); ++out_free_context: ++ krb5_free_context(context); ++ return rcc; + } + ++ + static char * + init_cc_from_keytab(const char *keytab_name, const char *user) + { +@@ -263,109 +278,6 @@ icfk_cleanup: + return ccname; + } + +-/* resolve a pattern to an actual directory path */ +-static char *resolve_krb5_dir(const char *pattern, uid_t uid) +-{ +- char name[MAX_CCNAME_LEN]; +- int i; +- size_t j; +- for (i = 0, j = 0; (pattern[i] != '\0') && (j < sizeof(name)); i++) { +- switch (pattern[i]) { +- case '%': +- switch (pattern[i + 1]) { +- case '%': +- name[j++] = pattern[i]; +- i++; +- break; +- case 'U': +- j += snprintf(name + j, sizeof(name) - j, +- "%lu", (unsigned long) uid); +- i++; +- break; +- } +- break; +- default: +- name[j++] = pattern[i]; +- break; +- } +- } +- if ((j > 0) && (j < sizeof(name))) +- return strndup(name, MAX_CCNAME_LEN); +- else +- return NULL; +-} +- +-/* search for a credcache that looks like a likely candidate */ +-static char *find_krb5_cc(const char *dirname, uid_t uid, +- char **best_cache, time_t *best_time) +-{ +- struct dirent **namelist; +- struct stat sbuf; +- char ccname[MAX_CCNAME_LEN], *credpath; +- int i, n; +- time_t cred_time; +- +- n = scandir(dirname, &namelist, krb5cc_filter, NULL); +- if (n < 0) { +- syslog(LOG_DEBUG, "%s: scandir error on directory '%s': %s", +- __func__, dirname, strerror(errno)); +- return NULL; +- } +- +- for (i = 0; i < n; i++) { +- snprintf(ccname, sizeof(ccname), "FILE:%s/%s", dirname, +- namelist[i]->d_name); +- credpath = ccname + 5; +- syslog(LOG_DEBUG, "%s: considering %s", __func__, credpath); +- +- if (lstat(credpath, &sbuf)) { +- syslog(LOG_DEBUG, "%s: stat error on '%s': %s", +- __func__, credpath, strerror(errno)); +- free(namelist[i]); +- continue; +- } +- if (sbuf.st_uid != uid) { +- syslog(LOG_DEBUG, "%s: %s is owned by %u, not %u", +- __func__, credpath, sbuf.st_uid, uid); +- free(namelist[i]); +- continue; +- } +- if (S_ISDIR(sbuf.st_mode)) { +- snprintf(ccname, sizeof(ccname), "DIR:%s/%s", dirname, +- namelist[i]->d_name); +- credpath = ccname + 4; +- } else +- if (!S_ISREG(sbuf.st_mode)) { +- syslog(LOG_DEBUG, "%s: %s is not a regular file", +- __func__, credpath); +- free(namelist[i]); +- continue; +- } +- if (!(cred_time = get_tgt_time(ccname))) { +- syslog(LOG_DEBUG, "%s: %s is not a valid credcache.", +- __func__, ccname); +- free(namelist[i]); +- continue; +- } +- +- if (cred_time <= *best_time) { +- syslog(LOG_DEBUG, "%s: %s expires sooner than current " +- "best.", __func__, ccname); +- free(namelist[i]); +- continue; +- } +- +- syslog(LOG_DEBUG, "%s: %s is valid ccache", __func__, ccname); +- free(*best_cache); +- *best_cache = strndup(ccname, MAX_CCNAME_LEN); +- *best_time = cred_time; +- free(namelist[i]); +- } +- free(namelist); +- +- return *best_cache; +-} +- + static int + cifs_krb5_get_req(const char *host, const char *ccname, + DATA_BLOB * mechtoken, DATA_BLOB * sess_key) +@@ -841,13 +753,12 @@ int main(const int argc, char *const argv[]) + unsigned int have; + long rc = 1; + int c, try_dns = 0, legacy_uid = 0; +- char *buf, *ccdir = NULL, *ccname = NULL, *best_cache = NULL; ++ char *buf, *ccname = NULL; + char hostbuf[NI_MAXHOST], *host; + struct decoded_args arg; + const char *oid; + uid_t uid; + char *keytab_name = NULL; +- time_t best_time = 0; + + hostbuf[0] = '\0'; + memset(&arg, 0, sizeof(arg)); +@@ -954,13 +865,8 @@ int main(const int argc, char *const argv[]) + syslog(LOG_ERR, "setuid: %s", strerror(errno)); + goto out; + } +- ccdir = resolve_krb5_dir(CIFS_DEFAULT_KRB5_USER_DIR, uid); +- if (ccdir != NULL) +- find_krb5_cc(ccdir, uid, &best_cache, &best_time); +- ccname = find_krb5_cc(CIFS_DEFAULT_KRB5_DIR, uid, &best_cache, +- &best_time); +- SAFE_FREE(ccdir); + ++ ccname = get_default_cc(); + /* Couldn't find credcache? Try to use keytab */ + if (ccname == NULL && arg.username != NULL) + ccname = init_cc_from_keytab(keytab_name, arg.username); +-- +2.7.4 + diff --git a/0003-cifs.upcall-make-the-krb5_context-a-static-global-va.patch b/0003-cifs.upcall-make-the-krb5_context-a-static-global-va.patch new file mode 100644 index 0000000..b8086c8 --- /dev/null +++ b/0003-cifs.upcall-make-the-krb5_context-a-static-global-va.patch @@ -0,0 +1,214 @@ +From a3743af0c579cee61b816080de978ae7a7663b05 Mon Sep 17 00:00:00 2001 +From: Jeff Layton +Date: Mon, 22 Aug 2016 07:34:21 -0400 +Subject: [cifs-utils PATCH 3/3] cifs.upcall: make the krb5_context a static + global variable + +There's no need to keep initing a new context for every function. Just +do it once and reuse as needed. + +Signed-off-by: Jeff Layton +--- + cifs.upcall.c | 61 ++++++++++++++++------------------------------------------- + 1 file changed, 16 insertions(+), 45 deletions(-) + +diff --git a/cifs.upcall.c b/cifs.upcall.c +index d0f6d089d8e1..8448d00f6061 100644 +--- a/cifs.upcall.c ++++ b/cifs.upcall.c +@@ -52,7 +52,9 @@ + #include "spnego.h" + #include "cifs_spnego.h" + +-static const char *prog = "cifs.upcall"; ++static krb5_context context; ++static const char *prog = "cifs.upcall"; ++ + typedef enum _sectype { + NONE = 0, + KRB5, +@@ -69,9 +71,7 @@ typedef enum _sectype { + * @return pointer to the realm + * + */ +- +-static char *cifs_krb5_principal_get_realm(krb5_context context __attribute__ ((unused)), +- krb5_principal principal) ++static char *cifs_krb5_principal_get_realm(krb5_principal principal) + { + #ifdef HAVE_KRB5_PRINCIPAL_GET_REALM /* Heimdal */ + return krb5_principal_get_realm(context, principal); +@@ -104,7 +104,6 @@ krb5_auth_con_getsendsubkey(krb5_context context, + /* does the ccache have a valid TGT? */ + static time_t get_tgt_time(const char *ccname) + { +- krb5_context context; + krb5_ccache ccache; + krb5_cc_cursor cur; + krb5_creds creds; +@@ -112,11 +111,6 @@ static time_t get_tgt_time(const char *ccname) + time_t credtime = 0; + char *realm = NULL; + +- if (krb5_init_context(&context)) { +- syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__); +- return 0; +- } +- + if (krb5_cc_resolve(context, ccname, &ccache)) { + syslog(LOG_DEBUG, "%s: unable to resolve krb5 cache", __func__); + goto err_cache; +@@ -137,7 +131,7 @@ static time_t get_tgt_time(const char *ccname) + goto err_ccstart; + } + +- if ((realm = cifs_krb5_principal_get_realm(context, principal)) == NULL) { ++ if ((realm = cifs_krb5_principal_get_realm(principal)) == NULL) { + syslog(LOG_DEBUG, "%s: unable to get realm", __func__); + goto err_ccstart; + } +@@ -168,34 +162,23 @@ err_princ: + #endif + krb5_cc_close(context, ccache); + err_cache: +- krb5_free_context(context); + return credtime; + } + + static char * + get_default_cc(void) + { +- krb5_error_code ret; + const char *ccname; + char *rcc = NULL; +- krb5_context context = NULL; +- +- ret = krb5_init_context(&context); +- if (ret) { +- syslog(LOG_DEBUG, "krb5_init_context: %d", (int)ret); +- return NULL; +- } + + ccname = krb5_cc_default_name(context); + if (!ccname) { + syslog(LOG_DEBUG, "krb5_cc_default returned NULL."); +- goto out_free_context; ++ return NULL; + } + + if (get_tgt_time(ccname)) + rcc = strdup(ccname); +-out_free_context: +- krb5_free_context(context); + return rcc; + } + +@@ -203,7 +186,6 @@ out_free_context: + static char * + init_cc_from_keytab(const char *keytab_name, const char *user) + { +- krb5_context context = NULL; + krb5_error_code ret; + krb5_creds my_creds; + krb5_keytab keytab = NULL; +@@ -213,12 +195,6 @@ init_cc_from_keytab(const char *keytab_name, const char *user) + + memset((char *) &my_creds, 0, sizeof(my_creds)); + +- ret = krb5_init_context(&context); +- if (ret) { +- syslog(LOG_DEBUG, "krb5_init_context: %d", (int)ret); +- goto icfk_cleanup; +- } +- + if (keytab_name) + ret = krb5_kt_resolve(context, keytab_name, &keytab); + else +@@ -273,8 +249,6 @@ icfk_cleanup: + krb5_cc_close(context, cc); + if (keytab) + krb5_kt_close(context, keytab); +- if (context) +- krb5_free_context(context); + return ccname; + } + +@@ -284,7 +258,6 @@ cifs_krb5_get_req(const char *host, const char *ccname, + { + krb5_error_code ret; + krb5_keyblock *tokb; +- krb5_context context; + krb5_ccache ccache; + krb5_creds in_creds, *out_creds; + krb5_data apreq_pkt, in_data; +@@ -292,26 +265,19 @@ cifs_krb5_get_req(const char *host, const char *ccname, + #if defined(HAVE_KRB5_AUTH_CON_SETADDRS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) + static const uint8_t gss_cksum[24] = { 0x10, 0x00, /* ... */}; + #endif +- +- ret = krb5_init_context(&context); +- if (ret) { +- syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__); +- return ret; +- } +- + if (ccname) { + ret = krb5_cc_resolve(context, ccname, &ccache); + if (ret) { + syslog(LOG_DEBUG, "%s: unable to resolve %s to ccache\n", + __func__, ccname); +- goto out_free_context; ++ return ret; + } + } else { + ret = krb5_cc_default(context, &ccache); + if (ret) { + syslog(LOG_DEBUG, "%s: krb5_cc_default: %d", + __func__, (int)ret); +- goto out_free_context; ++ return ret; + } + } + +@@ -383,7 +349,6 @@ cifs_krb5_get_req(const char *host, const char *ccname, + /* MIT krb5 < 1.7 is missing the prototype, but still has the symbol */ + #if !HAVE_DECL_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE + krb5_error_code krb5_auth_con_set_req_cksumtype( +- krb5_context context, + krb5_auth_context auth_context, + krb5_cksumtype cksumtype); + #endif +@@ -427,8 +392,6 @@ out_free_ccache: + krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); + #endif + krb5_cc_close(context, ccache); +-out_free_context: +- krb5_free_context(context); + return ret; + } + +@@ -866,6 +829,12 @@ int main(const int argc, char *const argv[]) + goto out; + } + ++ rc = krb5_init_context(&context); ++ if (rc) { ++ syslog(LOG_ERR, "unable to init krb5 context: %ld", rc); ++ goto out; ++ } ++ + ccname = get_default_cc(); + /* Couldn't find credcache? Try to use keytab */ + if (ccname == NULL && arg.username != NULL) +@@ -1006,6 +975,8 @@ out: + } + data_blob_free(&secblob); + data_blob_free(&sess_key); ++ if (context) ++ krb5_free_context(context); + SAFE_FREE(ccname); + SAFE_FREE(arg.hostname); + SAFE_FREE(arg.ip); +-- +2.7.4 + diff --git a/cifs-utils.spec b/cifs-utils.spec index 78a3fde..2cc3375 100644 --- a/cifs-utils.spec +++ b/cifs-utils.spec @@ -18,6 +18,10 @@ Requires(post): /usr/sbin/alternatives Requires(preun): /usr/sbin/alternatives Source0: https://download.samba.org/pub/linux-cifs/cifs-utils/%{name}-%{version}.tar.bz2 +Patch1: 0001-aclocal-fix-typo-in-idmap.m4.patch +Patch2: 0002-cifs.upcall-use-krb5-routines-to-get-default-ccname.patch +Patch3: 0003-cifs.upcall-make-the-krb5_context-a-static-global-va.patch + %description The SMB/CIFS protocol is a standard file sharing protocol widely deployed @@ -52,6 +56,9 @@ provide these credentials to the kernel automatically at login. %prep %setup -q -n %{name}-%{version}%{pre_release} +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 %build autoreconf -i