cifs-utils: add latest cifs-upcall cleanup patches

Add a number of cleanup patches to make cifs.upcall more efficient.
Note that these do have the potential to break some configurations
if they depend on the directory-scanning behavior of the original
patches, but hopefully no one is actually relying on that.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
This commit is contained in:
Jeff Layton 2016-08-22 08:46:02 -04:00
parent 21488a46d7
commit e32823e183
4 changed files with 464 additions and 0 deletions

View File

@ -0,0 +1,28 @@
From bbbf7133aec555c5d27ee3163d6045ecfc4673d9 Mon Sep 17 00:00:00 2001
From: Jeff Layton <jlayton@samba.org>
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 <jlayton@samba.org>
---
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

View File

@ -0,0 +1,215 @@
From 9be6e885c3bd63aa6ae9e6351e1b33a4b15d9183 Mon Sep 17 00:00:00 2001
From: Jeff Layton <jlayton@samba.org>
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 <jlayton@samba.org>
---
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

View File

@ -0,0 +1,214 @@
From a3743af0c579cee61b816080de978ae7a7663b05 Mon Sep 17 00:00:00 2001
From: Jeff Layton <jlayton@samba.org>
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 <jlayton@samba.org>
---
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

View File

@ -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