Blame SOURCES/0010-cifs-Allow-DNS-resolver-key-to-expire.patch

75f41f
From bc41dbe55098629101fbf286755e123c9a2b6b77 Mon Sep 17 00:00:00 2001
75f41f
From: Paulo Alcantara <paulo@paulo.ac>
75f41f
Date: Wed, 13 Feb 2019 16:09:41 -0200
75f41f
Subject: [PATCH 10/36] cifs: Allow DNS resolver key to expire
75f41f
75f41f
This patch introduces a new '--expire' option that allows the user to
75f41f
set a timeout value for the dns resolver key -- which is typically
75f41f
useful for hostnames that may get their ip addresses changed under
75f41f
long running mounts.
75f41f
75f41f
The default timeout value is set to 10 minutes.
75f41f
75f41f
Signed-off-by: Paulo Alcantara <palcantara@suse.de>
75f41f
(cherry picked from commit b101af793c8415f298072d06841a278df0368bc3)
75f41f
Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
75f41f
---
75f41f
 cifs.upcall.c      | 82 +++++++++++++++++++++++++++++++++++++++---------------
75f41f
 cifs.upcall.rst.in |  5 +++-
75f41f
 2 files changed, 64 insertions(+), 23 deletions(-)
75f41f
75f41f
diff --git a/cifs.upcall.c b/cifs.upcall.c
75f41f
index 89563fd..c92ee62 100644
75f41f
--- a/cifs.upcall.c
75f41f
+++ b/cifs.upcall.c
75f41f
@@ -63,6 +63,8 @@
75f41f
 static krb5_context	context;
75f41f
 static const char	*prog = "cifs.upcall";
75f41f
 
75f41f
+#define DNS_RESOLVER_DEFAULT_TIMEOUT 600 /* 10 minutes */
75f41f
+
75f41f
 typedef enum _sectype {
75f41f
 	NONE = 0,
75f41f
 	KRB5,
75f41f
@@ -749,19 +751,48 @@ decode_key_description(const char *desc, struct decoded_args *arg)
75f41f
 	return retval;
75f41f
 }
75f41f
 
75f41f
-static int cifs_resolver(const key_serial_t key, const char *key_descr)
75f41f
+static int setup_key(const key_serial_t key, const void *data, size_t datalen)
75f41f
+{
75f41f
+	int rc;
75f41f
+
75f41f
+	rc = keyctl_instantiate(key, data, datalen, 0);
75f41f
+	if (rc) {
75f41f
+		switch (errno) {
75f41f
+		case ENOMEM:
75f41f
+		case EDQUOT:
75f41f
+			rc = keyctl_clear(key);
75f41f
+			if (rc) {
75f41f
+				syslog(LOG_ERR, "%s: keyctl_clear: %s",
75f41f
+				       __func__, strerror(errno));
75f41f
+				return rc;
75f41f
+			}
75f41f
+			rc = keyctl_instantiate(key, data, datalen, 0);
75f41f
+			break;
75f41f
+		default:
75f41f
+			;
75f41f
+		}
75f41f
+	}
75f41f
+	if (rc) {
75f41f
+		syslog(LOG_ERR, "%s: keyctl_instantiate: %s",
75f41f
+		       __func__, strerror(errno));
75f41f
+	}
75f41f
+	return rc;
75f41f
+}
75f41f
+
75f41f
+static int cifs_resolver(const key_serial_t key, const char *key_descr,
75f41f
+			 const char *key_buf, unsigned expire_time)
75f41f
 {
75f41f
 	int c;
75f41f
 	struct addrinfo *addr;
75f41f
 	char ip[INET6_ADDRSTRLEN];
75f41f
 	void *p;
75f41f
-	const char *keyend = key_descr;
75f41f
+	const char *keyend = key_buf;
75f41f
 	/* skip next 4 ';' delimiters to get to description */
75f41f
 	for (c = 1; c <= 4; c++) {
75f41f
 		keyend = index(keyend + 1, ';');
75f41f
 		if (!keyend) {
75f41f
 			syslog(LOG_ERR, "invalid key description: %s",
75f41f
-			       key_descr);
75f41f
+			       key_buf);
75f41f
 			return 1;
75f41f
 		}
75f41f
 	}
75f41f
@@ -787,15 +818,21 @@ static int cifs_resolver(const key_serial_t key, const char *key_descr)
75f41f
 		return 1;
75f41f
 	}
75f41f
 
75f41f
-	/* setup key */
75f41f
-	c = keyctl_instantiate(key, ip, strlen(ip) + 1, 0);
75f41f
-	if (c == -1) {
75f41f
-		syslog(LOG_ERR, "%s: keyctl_instantiate: %s", __func__,
75f41f
+	/* needed for keyctl_set_timeout() */
75f41f
+	request_key("keyring", key_descr, NULL, KEY_SPEC_THREAD_KEYRING);
75f41f
+
75f41f
+	c = setup_key(key, ip, strlen(ip) + 1);
75f41f
+	if (c) {
75f41f
+		freeaddrinfo(addr);
75f41f
+		return 1;
75f41f
+	}
75f41f
+	c = keyctl_set_timeout(key, expire_time);
75f41f
+	if (c) {
75f41f
+		syslog(LOG_ERR, "%s: keyctl_set_timeout: %s", __func__,
75f41f
 		       strerror(errno));
75f41f
 		freeaddrinfo(addr);
75f41f
 		return 1;
75f41f
 	}
75f41f
-
75f41f
 	freeaddrinfo(addr);
75f41f
 	return 0;
75f41f
 }
75f41f
@@ -864,7 +901,7 @@ lowercase_string(char *c)
75f41f
 
75f41f
 static void usage(void)
75f41f
 {
75f41f
-	fprintf(stderr, "Usage: %s [ -K /path/to/keytab] [-k /path/to/krb5.conf] [-E] [-t] [-v] [-l] key_serial\n", prog);
75f41f
+	fprintf(stderr, "Usage: %s [ -K /path/to/keytab] [-k /path/to/krb5.conf] [-E] [-t] [-v] [-l] [-e nsecs] key_serial\n", prog);
75f41f
 }
75f41f
 
75f41f
 static const struct option long_options[] = {
75f41f
@@ -874,6 +911,7 @@ static const struct option long_options[] = {
75f41f
 	{"trust-dns", 0, NULL, 't'},
75f41f
 	{"keytab", 1, NULL, 'K'},
75f41f
 	{"version", 0, NULL, 'v'},
75f41f
+	{"expire", 1, NULL, 'e'},
75f41f
 	{NULL, 0, NULL, 0}
75f41f
 };
75f41f
 
75f41f
@@ -897,13 +935,15 @@ int main(const int argc, char *const argv[])
75f41f
 	char *env_cachename = NULL;
75f41f
 	krb5_ccache ccache = NULL;
75f41f
 	struct passwd *pw;
75f41f
+	unsigned expire_time = DNS_RESOLVER_DEFAULT_TIMEOUT;
75f41f
+	const char *key_descr = NULL;
75f41f
 
75f41f
 	hostbuf[0] = '\0';
75f41f
 	memset(&arg, 0, sizeof(arg));
75f41f
 
75f41f
 	openlog(prog, 0, LOG_DAEMON);
75f41f
 
75f41f
-	while ((c = getopt_long(argc, argv, "cEk:K:ltv", long_options, NULL)) != -1) {
75f41f
+	while ((c = getopt_long(argc, argv, "cEk:K:ltve:", long_options, NULL)) != -1) {
75f41f
 		switch (c) {
75f41f
 		case 'c':
75f41f
 			/* legacy option -- skip it */
75f41f
@@ -931,6 +971,9 @@ int main(const int argc, char *const argv[])
75f41f
 			rc = 0;
75f41f
 			printf("version: %s\n", VERSION);
75f41f
 			goto out;
75f41f
+		case 'e':
75f41f
+			expire_time = strtoul(optarg, NULL, 10);
75f41f
+			break;
75f41f
 		default:
75f41f
 			syslog(LOG_ERR, "unknown option: %c", c);
75f41f
 			goto out;
75f41f
@@ -965,9 +1008,12 @@ int main(const int argc, char *const argv[])
75f41f
 
75f41f
 	syslog(LOG_DEBUG, "key description: %s", buf);
75f41f
 
75f41f
-	if ((strncmp(buf, "cifs.resolver", sizeof("cifs.resolver") - 1) == 0) ||
75f41f
-	    (strncmp(buf, "dns_resolver", sizeof("dns_resolver") - 1) == 0)) {
75f41f
-		rc = cifs_resolver(key, buf);
75f41f
+	if (strncmp(buf, "cifs.resolver", sizeof("cifs.resolver") - 1) == 0)
75f41f
+		key_descr = ".cifs.resolver";
75f41f
+	else if (strncmp(buf, "dns_resolver", sizeof("dns_resolver") - 1) == 0)
75f41f
+		key_descr = ".dns_resolver";
75f41f
+	if (key_descr) {
75f41f
+		rc = cifs_resolver(key, key_descr, buf, expire_time);
75f41f
 		goto out;
75f41f
 	}
75f41f
 
75f41f
@@ -1193,16 +1239,8 @@ retry_new_hostname:
75f41f
 	memcpy(&(keydata->data) + keydata->sesskey_len,
75f41f
 	       secblob.data, secblob.length);
75f41f
 
75f41f
-	/* setup key */
75f41f
-	rc = keyctl_instantiate(key, keydata, datalen, 0);
75f41f
-	if (rc == -1) {
75f41f
-		syslog(LOG_ERR, "keyctl_instantiate: %s", strerror(errno));
75f41f
-		goto out;
75f41f
-	}
75f41f
+	rc = setup_key(key, keydata, datalen);
75f41f
 
75f41f
-	/* BB: maybe we need use timeout for key: for example no more then
75f41f
-	 * ticket lifietime? */
75f41f
-	/* keyctl_set_timeout( key, 60); */
75f41f
 out:
75f41f
 	/*
75f41f
 	 * on error, negatively instantiate the key ourselves so that we can
75f41f
diff --git a/cifs.upcall.rst.in b/cifs.upcall.rst.in
75f41f
index 1b8df3f..08ce324 100644
75f41f
--- a/cifs.upcall.rst.in
75f41f
+++ b/cifs.upcall.rst.in
75f41f
@@ -13,7 +13,7 @@ SYNOPSIS
75f41f
 
75f41f
   cifs.upcall [--trust-dns|-t] [--version|-v] [--legacy-uid|-l]
75f41f
               [--krb5conf=/path/to/krb5.conf|-k /path/to/krb5.conf]
75f41f
-              [--keytab=/path/to/keytab|-K /path/to/keytab] {keyid}
75f41f
+              [--keytab=/path/to/keytab|-K /path/to/keytab] [--expire|-e nsecs] {keyid}
75f41f
 
75f41f
 ***********
75f41f
 DESCRIPTION
75f41f
@@ -85,6 +85,9 @@ OPTIONS
75f41f
   user. Set this option if you want cifs.upcall to use the older uid=
75f41f
   parameter instead of the creduid= parameter.
75f41f
 
75f41f
+--expire|-e
75f41f
+  Override default timeout value (600 seconds) for ``dns_resolver`` key.
75f41f
+
75f41f
 --version|-v
75f41f
   Print version number and exit.
75f41f
 
75f41f
-- 
75f41f
1.8.3.1
75f41f