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

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