linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] keyutils: request_key and DNS resolver changes
@ 2018-09-13 14:08 David Howells
  2018-09-13 14:08 ` [PATCH 1/3] request-key: Provide a command line option to suppress execution David Howells
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: David Howells @ 2018-09-13 14:08 UTC (permalink / raw)
  To: keyrings; +Cc: dhowells, linux-nfs, linux-cifs, linux-security-module


Here's a set of keyutils patches that makes it possible to override the DNS
resolver (or any other upcall target).  This allows the kafs-utils package to
override requests to the dns resolver and make use of static configuration in
addition to DNS lookups.  This allows this function to be moved out of
keyutils and allows the dependency on krb5 to be removed.

The following changes are made:

 (1) request-key now has better command-line option support for debugging the
     configuration.

 (2) request-key now reads all its config files and searches for the best
     match rather than the first match.

     'Best match' is defined as the match with the least number of characters
     skipped by a wildcard, first in the left most column, then in the next
     column and so on.

     So in the following two config lines:

    	create  dns_resolver *		*	/sbin/key.dns_resolver %k
	create  dns_resolver afsdb:*	*	/sbin/dns_afsdb %k

     For dns_resolver keys, the second line is preferred if the description
     matches "afsdb:*" - no matter the order in which they're encountered -
     but the first line will be used otherwise.

 (3) The AFS cellservdb config file parsing is removed from key.dns_resolver
     and the dependencies for the krb5 profile functions are dropped.
    
The patches can also be found here:

	https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/keyutils.git

on branch next (bottom 3 patches).

Thanks,
David
---
David Howells (3):
      request-key: Provide a command line option to suppress execution
      request-key: Find best match rather than first match
      Remove the dependency on MIT Kerberos


 Makefile               |    2 
 dns.afsdb.c            |  268 ++++---------------------------
 keyutils.spec          |    2 
 man/request-key.8      |   31 +++-
 man/request-key.conf.5 |   36 ++--
 request-key.c          |  419 +++++++++++++++++++++++++++++-------------------
 6 files changed, 336 insertions(+), 422 deletions(-)

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] request-key: Provide a command line option to suppress execution
  2018-09-13 14:08 [PATCH 0/3] keyutils: request_key and DNS resolver changes David Howells
@ 2018-09-13 14:08 ` David Howells
  2018-09-13 14:08 ` [PATCH 2/3] request-key: Find best match rather than first match David Howells
  2018-09-13 14:08 ` [PATCH 3/3] Remove the dependency on MIT Kerberos David Howells
  2 siblings, 0 replies; 4+ messages in thread
From: David Howells @ 2018-09-13 14:08 UTC (permalink / raw)
  To: keyrings; +Cc: dhowells, linux-nfs, linux-cifs, linux-security-module

Allow "-x" to be passed on the command line to the request-key program to
suppress side effects and target execution.  This makes it easier to debug
the program and its configuration by allowing it to be driven from the
command line.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 request-key.c |   78 +++++++++++++++++++++++++++++++++------------------------
 1 file changed, 45 insertions(+), 33 deletions(-)

diff --git a/request-key.c b/request-key.c
index 3762e9a..ecd7b79 100644
--- a/request-key.c
+++ b/request-key.c
@@ -24,6 +24,7 @@
 #include <signal.h>
 #include <syslog.h>
 #include <unistd.h>
+#include <getopt.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <ctype.h>
@@ -32,8 +33,9 @@
 #include "keyutils.h"
 
 
-static int xdebug;
+static int verbosity;
 static int xnolog;
+static int debug_mode;
 static char *xkey;
 static char *xuid;
 static char *xgid;
@@ -75,7 +77,7 @@ static void debug(const char *fmt, ...)
 {
 	va_list va;
 
-	if (xdebug) {
+	if (verbosity) {
 		va_start(va, fmt);
 		vfprintf(stderr, fmt, va);
 		va_end(va);
@@ -97,7 +99,7 @@ static void error(const char *fmt, ...)
 {
 	va_list va;
 
-	if (xdebug) {
+	if (verbosity) {
 		va_start(va, fmt);
 		vfprintf(stderr, fmt, va);
 		va_end(va);
@@ -132,7 +134,7 @@ int main(int argc, char *argv[])
 {
 	key_serial_t key;
 	char *ktype, *kdesc, *buf, *callout_info;
-	int ret, ntype, dpos, n, fd;
+	int ret, ntype, dpos, n, fd, opt;
 
 	if (argc == 2 && strcmp(argv[1], "--version") == 0) {
 		printf("request-key from %s (Built %s)\n",
@@ -144,22 +146,25 @@ int main(int argc, char *argv[])
 	signal(SIGBUS, oops);
 	signal(SIGPIPE, SIG_IGN);
 
-	for (;;) {
-		if (argc > 1 && strcmp(argv[1], "-d") == 0) {
-			xdebug++;
-			argv++;
-			argc--;
-		}
-		else if (argc > 1 && strcmp(argv[1], "-n") == 0) {
+	while (opt = getopt(argc, argv, "dnv"),
+	       opt != -1) {
+		switch (opt) {
+		case 'd':
+			debug_mode = 1;
+			break;
+		case 'n':
 			xnolog = 1;
-			argv++;
-			argc--;
-		}
-		else
 			break;
+		case 'v':
+			verbosity++;
+			break;
+		}
 	}
 
-	if (argc != 8 && argc != 9)
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 7 && argc != 8)
 		error("Unexpected argument count: %d\n", argc);
 
 	fd = open("/dev/null", O_RDWR);
@@ -177,24 +182,26 @@ int main(int argc, char *argv[])
 			error("dup failed: %m\n");
 	}
 
-	xkey = argv[2];
-	xuid = argv[3];
-	xgid = argv[4];
-	xthread_keyring = argv[5];
-	xprocess_keyring = argv[6];
-	xsession_keyring = argv[7];
+	xkey = argv[1];
+	xuid = argv[2];
+	xgid = argv[3];
+	xthread_keyring = argv[4];
+	xprocess_keyring = argv[5];
+	xsession_keyring = argv[6];
 
 	key = atoi(xkey);
 
 	/* assume authority over the key
 	 * - older kernel doesn't support this function
 	 */
-	ret = keyctl_assume_authority(key);
-	if (ret < 0 && !(argc == 9 || errno == EOPNOTSUPP))
-		error("Failed to assume authority over key %d (%m)\n", key);
+	if (!debug_mode) {
+		ret = keyctl_assume_authority(key);
+		if (ret < 0 && !(argc == 8 || errno == EOPNOTSUPP))
+			error("Failed to assume authority over key %d (%m)\n", key);
+	}
 
 	/* ask the kernel to describe the key to us */
-	if (xdebug < 2) {
+	if (!debug_mode) {
 		ret = keyctl_describe_alloc(key, &buf);
 		if (ret < 0)
 			goto inaccessible;
@@ -220,7 +227,7 @@ int main(int argc, char *argv[])
 	debug("Key desc: %s\n", kdesc);
 
 	/* get hold of the callout info */
-	callout_info = argv[8];
+	callout_info = argv[7];
 
 	if (!callout_info) {
 		void *tmp;
@@ -234,7 +241,7 @@ int main(int argc, char *argv[])
 	debug("CALLOUT: '%s'\n", callout_info);
 
 	/* determine the action to perform */
-	lookup_action(argv[1],		/* op */
+	lookup_action(argv[0],		/* op */
 		      key,		/* ID of key under construction */
 		      ktype,		/* key type */
 		      kdesc,		/* key description */
@@ -267,7 +274,7 @@ static void lookup_action(char *op,
 
 	/* search the config file for a command to run */
 	if (strlen(ktype) <= sizeof(conffile) - 30) {
-		if (xdebug < 2)
+		if (verbosity < 2)
 			snprintf(conffile, sizeof(conffile) - 1,
 				 "/etc/request-key.d/%s.conf", ktype);
 		else
@@ -280,7 +287,7 @@ static void lookup_action(char *op,
 			error("Cannot open %s: %m\n", conffile);
 	}
 
-	if (xdebug < 2)
+	if (verbosity < 2)
 		snprintf(conffile, sizeof(conffile) - 1, "/etc/request-key.conf");
 	else
 		snprintf(conffile, sizeof(conffile) - 1, "request-key.conf");
@@ -596,7 +603,7 @@ static void execute_program(char *op,
 
 	argv[argc] = NULL;
 
-	if (xdebug) {
+	if (verbosity) {
 		char **ap;
 
 		debug("%s %s\n", pipeit ? "PipeThru" : "Run", prog);
@@ -611,6 +618,11 @@ static void execute_program(char *op,
 	/* if the last argument is a single bar, we spawn off the program dangling on the end of
 	 * three pipes and read the key material from the program, otherwise we just exec
 	 */
+	if (debug_mode) {
+		printf("-- exec disabled --\n");
+		exit(0);
+	}
+
 	if (pipeit)
 		pipe_to_program(op, key, ktype, kdesc, callout_info, prog, argv);
 
@@ -791,7 +803,7 @@ static void pipe_to_program(char *op,
 				nl++;
 				n = nl - errbuf;
 
-				if (xdebug)
+				if (verbosity)
 					fprintf(stderr, "Child: %*.*s", n, n, errbuf);
 
 				if (!xnolog) {
@@ -815,7 +827,7 @@ static void pipe_to_program(char *op,
 			if (espace == 0) {
 				int n = sizeof(errbuf);
 
-				if (xdebug)
+				if (verbosity)
 					fprintf(stderr, "Child: %*.*s", n, n, errbuf);
 
 				if (!xnolog) {

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] request-key: Find best match rather than first match
  2018-09-13 14:08 [PATCH 0/3] keyutils: request_key and DNS resolver changes David Howells
  2018-09-13 14:08 ` [PATCH 1/3] request-key: Provide a command line option to suppress execution David Howells
@ 2018-09-13 14:08 ` David Howells
  2018-09-13 14:08 ` [PATCH 3/3] Remove the dependency on MIT Kerberos David Howells
  2 siblings, 0 replies; 4+ messages in thread
From: David Howells @ 2018-09-13 14:08 UTC (permalink / raw)
  To: keyrings; +Cc: dhowells, linux-nfs, linux-cifs, linux-security-module

When an upcall happens currently, either a file by the name
"/etc/request-key.d/<type>.conf" is scanned or the default file
"/etc/request-key.conf" is scanned and then the first match (including
wildcards) is selected.

Change this to read all the files in the conf directory and then read the
default file.  The best rule is then chosen and executed.

"Best" is defined as the rule with the least number of characters that are
skipped by matching a wildcard (e.g. string "foo:bar" matches pattern
"foo:*" with the number of characters being skipped being 3).

Further, the operation, type, description and callout_info columns are
matched individually and in order, so that a skip of 1 in the operation
column, say, is less preferable than an exact match there and a skip of 2
in the type column.

For example, take:

	create  dns_resolver afsdb:*	*	/sbin/key.afsdb %k
	create  dns_resolver afsdb:*	hello*	/sbin/key.xxxx %k

if both lines match, the second one will be picked, but, on the other hand,
with:

	create  dns_resolver afsdb:*	*	/sbin/key.afsdb %k
	creat*  dns_resolver afsdb:*	hello*	/sbin/key.xxxx %k

the first will be picked.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 man/request-key.8      |   31 ++++
 man/request-key.conf.5 |   36 +++--
 request-key.c          |  367 +++++++++++++++++++++++++++++-------------------
 3 files changed, 267 insertions(+), 167 deletions(-)

diff --git a/man/request-key.8 b/man/request-key.8
index b008d80..50a7506 100644
--- a/man/request-key.8
+++ b/man/request-key.8
@@ -18,18 +18,41 @@ This program is invoked by the kernel when the kernel is asked for a key that
 it doesn't have immediately available. The kernel creates a partially set up
 key and then calls out to this program to instantiate it. It is not intended
 to be called directly.
+.PP
+However, for debugging purposes, it can be given some options on the command
+line:
+.IP \fB-d\fP
+Turn on debugging mode.  In this mode, no attempts are made to access any keys
+and, if a handler program is selected, it won't be executed; instead, this
+program will print a message and exit 0.
+.IP \fB-D <description>\fP
+In debugging mode, use the proposed key description specified with this rather
+than the sample ("user;0;0;1f0000;debug:1234") built into the program.
+.IP \fB-l\fP
+Use configuration from the current directory.  The program will use
+.IR request-key.d/* " and " request-key.conf
+from the current directory rather than from
+.IR /etc .
+.IP \fB-n\fP
+Don't log to the system log.  Ordinarily, error messages and debugging messages
+will be copied to the system log - this will prevent that.
+.IP \fB-v\fP
+Turn on debugging output.  This may be specified multiple times to produce
+increasing levels of verbosity.
+.IP \fB--version\fP
+Print the program version and exit.
 .SH ERRORS
 All errors will be logged to the syslog.
 .SH FILES
 .ul
-/etc/request\-key.conf
+/etc/request\-key.d/*.conf
 .ul 0
-Instantiation handler configuration file.
+Individual configuration files.
 .P
 .ul
-/etc/request\-key.d/<keytype>.conf
+/etc/request\-key.conf
 .ul 0
-Keytype specific configuration file.
+Fallback configuration file.
 .SH SEE ALSO
 .ad l
 .nh
diff --git a/man/request-key.conf.5 b/man/request-key.conf.5
index 49facad..276c771 100644
--- a/man/request-key.conf.5
+++ b/man/request-key.conf.5
@@ -12,20 +12,24 @@
 request\-key.conf \- Instantiation handler configuration file
 .SH DESCRIPTION
 .P
-This file and its associated key-type specific variants are used by the
-/sbin/request\-key program to determine which program it should run to
-instantiate a key.
+These files are used by the /sbin/request\-key program to determine which
+program it should run to instantiate a key.
 .P
-request\-key looks first in /etc/request\-key.d/ for a file of the key type name
-plus ".conf" that it can use.  If that is not found, it will fall back to
-/etc/request\-key.conf.
+request\-key looks for the best match, reading all the following files:
+.IP
+	/etc/request\-key.d/*.conf
+.br
+	/etc/request\-key.conf
+.P
+If it doesn't find a match, it will return an error
+and the kernel will automatically negate the key.
 .P
-request\-key scans through the chosen file one line at a time until it
-finds a match, which it will then use. If it doesn't find a match, it'll return
-an error and the kernel will automatically negate the key.
+The best match is defined as the line with the shortest wildcard skips, ranking
+the columns in order left to right.  If two lines have the same length skips,
+then the first read is the one taken.
 .P
-Any blank line or line beginning with a hash mark '#' is considered to be a
-comment and ignored.
+In the files, any blank line or line beginning with a hash mark '#' is
+considered to be a comment and ignored.
 .P
 All other lines are assumed to be command lines with a number of white space
 separated fields:
@@ -36,10 +40,10 @@ The first four fields are used to match the parameters passed to request\-key by
 the kernel. \fIop\fR is the operation type; currently the only supported
 operation is "create".
 .P
-\fItype\fR, \fIdescription\fR and \fIcallout\-info\fR match the three parameters
-passed to \fBkeyctl request2\fR or the \fBrequest_key()\fR system call. Each of
-these may contain one or more asterisk '*' characters as wildcards anywhere
-within the string.
+\fItype\fR, \fIdescription\fR and \fIcallout\-info\fR match the three
+parameters passed to \fBkeyctl request2\fR or the \fBrequest_key()\fR system
+call.  Each of these may contain one asterisk '*' character as a wildcard
+anywhere within the string.
 .P
 Should a match be made, the program specified by <prog> will be exec'd. This
 must have a fully qualified path name. argv[0] will be set from the part of the
@@ -135,7 +139,7 @@ the payload.
 .ul 0
 .br
 .ul
-/etc/request\-key.d/<keytype>.conf
+/etc/request\-key.d/*.conf
 .ul 0
 .SH SEE ALSO
 \fBkeyctl\fR(1), \fBrequest\-key.conf\fR(5)
diff --git a/request-key.c b/request-key.c
index ecd7b79..293fa2f 100644
--- a/request-key.c
+++ b/request-key.c
@@ -24,6 +24,8 @@
 #include <signal.h>
 #include <syslog.h>
 #include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
 #include <getopt.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -33,44 +35,54 @@
 #include "keyutils.h"
 
 
+struct parameters {
+	key_serial_t	key_id;
+	char		*op;
+	char		*key_type;
+	char		*key_desc;
+	char		*callout_info;
+	char		*key;
+	char		*uid;
+	char		*gid;
+	char		*thread_keyring;
+	char		*process_keyring;
+	char		*session_keyring;
+	int		len;
+	int		oplen;
+	int		ktlen;
+	int		kdlen;
+	int		cilen;
+
+};
+
 static int verbosity;
+static int xlocaldirs;
 static int xnolog;
 static int debug_mode;
-static char *xkey;
-static char *xuid;
-static char *xgid;
-static char *xthread_keyring;
-static char *xprocess_keyring;
-static char *xsession_keyring;
-static char conffile[256];
+static char conffile[PATH_MAX + 1];
 static int confline;
 static int norecurse;
 
-static void lookup_action(char *op,
-			  key_serial_t key,
-			  char *ktype,
-			  char *kdesc,
-			  char *callout_info)
+static char cmd[4096 + 2], cmd_conffile[PATH_MAX + 1];
+static unsigned int cmd_wildness[4] = { UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX };
+static int cmd_len, cmd_confline;
+
+static void lookup_action(struct parameters *params)
 	__attribute__((noreturn));
+static void scan_conf_dir(struct parameters *params, const char *confdir);
+static void scan_conf_file(struct parameters *params, int dirfd, const char *conffile);
 
-static void execute_program(char *op,
-			    key_serial_t key,
-			    char *ktype,
-			    char *kdesc,
-			    char *callout_info,
+static void execute_program(struct parameters *params,
 			    char *cmdline)
 	__attribute__((noreturn));
 
-static void pipe_to_program(char *op,
-			    key_serial_t key,
-			    char *ktype,
-			    char *kdesc,
-			    char *callout_info,
+static void pipe_to_program(struct parameters *params,
 			    char *prog,
 			    char **argv)
 	__attribute__((noreturn));
 
-static int match(const char *pattern, int plen, const char *datum, int dlen);
+static int match(const char *pattern, int plen, const char *datum, int dlen,
+		 unsigned int *wildness);
 
 static void debug(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 static void debug(const char *fmt, ...)
@@ -132,8 +144,9 @@ static void oops(int x)
  */
 int main(int argc, char *argv[])
 {
-	key_serial_t key;
-	char *ktype, *kdesc, *buf, *callout_info;
+	struct parameters params;
+	char *test_desc = "user;0;0;1f0000;debug:1234";
+	char *buf;
 	int ret, ntype, dpos, n, fd, opt;
 
 	if (argc == 2 && strcmp(argv[1], "--version") == 0) {
@@ -146,12 +159,18 @@ int main(int argc, char *argv[])
 	signal(SIGBUS, oops);
 	signal(SIGPIPE, SIG_IGN);
 
-	while (opt = getopt(argc, argv, "dnv"),
+	while (opt = getopt(argc, argv, "D:dlnv"),
 	       opt != -1) {
 		switch (opt) {
+		case 'D':
+			test_desc = optarg;
+			break;
 		case 'd':
 			debug_mode = 1;
 			break;
+		case 'l':
+			xlocaldirs = 1;
+			break;
 		case 'n':
 			xnolog = 1;
 			break;
@@ -182,32 +201,34 @@ int main(int argc, char *argv[])
 			error("dup failed: %m\n");
 	}
 
-	xkey = argv[1];
-	xuid = argv[2];
-	xgid = argv[3];
-	xthread_keyring = argv[4];
-	xprocess_keyring = argv[5];
-	xsession_keyring = argv[6];
+	params.op		= argv[0];
+	params.key		= argv[1];
+	params.uid		= argv[2];
+	params.gid		= argv[3];
+	params.thread_keyring	= argv[4];
+	params.process_keyring	= argv[5];
+	params.session_keyring	= argv[6];
+	params.callout_info	= argv[7];
 
-	key = atoi(xkey);
+	params.key_id = atoi(params.key);
 
 	/* assume authority over the key
 	 * - older kernel doesn't support this function
 	 */
 	if (!debug_mode) {
-		ret = keyctl_assume_authority(key);
+		ret = keyctl_assume_authority(params.key_id);
 		if (ret < 0 && !(argc == 8 || errno == EOPNOTSUPP))
-			error("Failed to assume authority over key %d (%m)\n", key);
+			error("Failed to assume authority over key %d (%m)\n",
+			      params.key_id);
 	}
 
 	/* ask the kernel to describe the key to us */
 	if (!debug_mode) {
-		ret = keyctl_describe_alloc(key, &buf);
+		ret = keyctl_describe_alloc(params.key_id, &buf);
 		if (ret < 0)
 			goto inaccessible;
-	}
-	else {
-		buf = strdup("user;0;0;1f0000;debug:1234");
+	} else {
+		buf = strdup(test_desc);
 	}
 
 	/* extract the type and description from the key */
@@ -219,37 +240,34 @@ int main(int argc, char *argv[])
 	if (n != 1)
 		error("Failed to parse key description\n");
 
-	ktype = buf;
-	ktype[ntype] = 0;
-	kdesc = buf + dpos;
+	params.key_type = buf;
+	params.key_type[ntype] = 0;
+	params.key_desc = buf + dpos;
 
-	debug("Key type: %s\n", ktype);
-	debug("Key desc: %s\n", kdesc);
+	debug("Key type: %s\n", params.key_type);
+	debug("Key desc: %s\n", params.key_desc);
 
 	/* get hold of the callout info */
-	callout_info = argv[7];
-
-	if (!callout_info) {
+	if (!params.callout_info) {
 		void *tmp;
 
 		if (keyctl_read_alloc(KEY_SPEC_REQKEY_AUTH_KEY, &tmp) < 0)
 			error("Failed to retrieve callout info (%m)\n");
 
-		callout_info = tmp;
+		params.callout_info = tmp;
 	}
 
-	debug("CALLOUT: '%s'\n", callout_info);
+	debug("CALLOUT: '%s'\n", params.callout_info);
 
 	/* determine the action to perform */
-	lookup_action(argv[0],		/* op */
-		      key,		/* ID of key under construction */
-		      ktype,		/* key type */
-		      kdesc,		/* key description */
-		      callout_info	/* call out information */
-		      );
+	params.oplen = strlen(params.op);
+	params.ktlen = strlen(params.key_type);
+	params.kdlen = strlen(params.key_desc);
+	params.cilen = strlen(params.callout_info);
+	lookup_action(&params);
 
 inaccessible:
-	error("Key %d is inaccessible (%m)\n", key);
+	error("Key %d is inaccessible (%m)\n", params.key_id);
 
 } /* end main() */
 
@@ -257,52 +275,88 @@ inaccessible:
 /*
  * determine the action to perform
  */
-static void lookup_action(char *op,
-			  key_serial_t key,
-			  char *ktype,
-			  char *kdesc,
-			  char *callout_info)
+static void lookup_action(struct parameters *params)
+{
+	if (!xlocaldirs) {
+		scan_conf_dir(params, "/etc/request-key.d");
+		scan_conf_file(params, AT_FDCWD, "/etc/request-key.conf");
+	} else {
+		scan_conf_dir(params, "request-key.d");
+		scan_conf_file(params, AT_FDCWD, "request-key.conf");
+	}
+
+	if (cmd_len > 0)
+		execute_program(params, cmd);
+
+	file_error("No matching action\n");
+}
+
+/*****************************************************************************/
+/*
+ * Scan the files in a configuration directory.
+ */
+static void scan_conf_dir(struct parameters *params, const char *confdir)
+{
+	struct dirent *d;
+	DIR *dir;
+	int l;
+
+	debug("__ SCAN %s __\n", confdir);
+
+	dir = opendir(confdir);
+	if (!dir) {
+		if (errno == ENOENT)
+			return;
+		error("Cannot open %s: %m\n", confdir);
+	}
+
+	while ((d = readdir(dir))) {
+		if (d->d_name[0] == '.')
+			continue;
+		if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
+			continue;
+		l = strlen(d->d_name);
+		if (l < 5)
+			continue;
+		if (memcmp(d->d_name + l - 5, ".conf", 5) != 0)
+			continue;
+		scan_conf_file(params, dirfd(dir), d->d_name);
+	}
+
+	closedir(dir);
+}
+
+/*****************************************************************************/
+/*
+ * Scan the contents of a configuration file.
+ */
+static void scan_conf_file(struct parameters *params, int dirfd, const char *conffile)
 {
 	char buf[4096 + 2], *p, *q;
 	FILE *conf;
-	int len, oplen, ktlen, kdlen, cilen;
-
-	oplen = strlen(op);
-	ktlen = strlen(ktype);
-	kdlen = strlen(kdesc);
-	cilen = strlen(callout_info);
-
-	/* search the config file for a command to run */
-	if (strlen(ktype) <= sizeof(conffile) - 30) {
-		if (verbosity < 2)
-			snprintf(conffile, sizeof(conffile) - 1,
-				 "/etc/request-key.d/%s.conf", ktype);
-		else
-			snprintf(conffile, sizeof(conffile) - 1,
-				 "request-key.d/%s.conf", ktype);
-		conf = fopen(conffile, "r");
-		if (conf)
-			goto opened_conf_file;
-		if (errno != ENOENT)
-			error("Cannot open %s: %m\n", conffile);
+	int fd;
+
+	debug("__ read %s __\n", conffile);
+
+	fd = openat(dirfd, conffile, O_RDONLY);
+	if (fd < 0) {
+		if (errno == ENOENT)
+			return;
+		error("Cannot open %s: %m\n", conffile);
 	}
 
-	if (verbosity < 2)
-		snprintf(conffile, sizeof(conffile) - 1, "/etc/request-key.conf");
-	else
-		snprintf(conffile, sizeof(conffile) - 1, "request-key.conf");
-	conf = fopen(conffile, "r");
+	conf = fdopen(fd, "r");
 	if (!conf)
 		error("Cannot open %s: %m\n", conffile);
 
-opened_conf_file:
-	debug("Opened config file '%s'\n", conffile);
-
 	for (confline = 1;; confline++) {
+		unsigned int wildness[4] = {};
+		unsigned int len;
+
 		/* read the file line-by-line */
 		if (!fgets(buf, sizeof(buf), conf)) {
 			if (feof(conf))
-				error("Cannot find command to construct key %d\n", key);
+				break;
 			file_error("error %m\n");
 		}
 
@@ -324,7 +378,7 @@ opened_conf_file:
 			goto syntax_error;
 		*p = 0;
 
-		if (!match(q, p - q, op, oplen))
+		if (!match(q, p - q, params->op, params->oplen, &wildness[0]))
 			continue;
 
 		p++;
@@ -340,7 +394,7 @@ opened_conf_file:
 			goto syntax_error;
 		*p = 0;
 
-		if (!match(q, p - q, ktype, ktlen))
+		if (!match(q, p - q, params->key_type, params->ktlen, &wildness[1]))
 			continue;
 
 		p++;
@@ -356,7 +410,7 @@ opened_conf_file:
 			goto syntax_error;
 		*p = 0;
 
-		if (!match(q, p - q, kdesc, kdlen))
+		if (!match(q, p - q, params->key_desc, params->kdlen, &wildness[2]))
 			continue;
 
 		p++;
@@ -372,42 +426,64 @@ opened_conf_file:
 			goto syntax_error;
 		*p = 0;
 
-		if (!match(q, p - q, callout_info, cilen))
+		if (!match(q, p - q, params->callout_info, params->cilen, &wildness[3]))
 			continue;
 
 		p++;
 
-		debug("%s:%d: Line matches\n", conffile, confline);
-
-		/* we've got an action */
+		/* we've got a match */
 		while (isspace(*p)) p++;
 		if (!*p)
 			goto syntax_error;
 
-		fclose(conf);
-
-		execute_program(op, key, ktype, kdesc, callout_info, p);
+		debug("%s:%d: Line matches '%s' (%u,%u,%u,%u)\n",
+		      conffile, confline, p,
+		      wildness[0], wildness[1], wildness[2], wildness[3]);
+
+		if (wildness[0] < cmd_wildness[0] ||
+		    (wildness[0] == cmd_wildness[0] &&
+		     wildness[1] < cmd_wildness[1]) ||
+		    (wildness[0] == cmd_wildness[0] &&
+		     wildness[1] == cmd_wildness[1] &&
+		     wildness[2] < cmd_wildness[2]) ||
+		    (wildness[0] == cmd_wildness[0] &&
+		     wildness[1] == cmd_wildness[1] &&
+		     wildness[2] == cmd_wildness[2] &&
+		     wildness[3] < cmd_wildness[3])
+		    ) {
+			memcpy(cmd_wildness, wildness, sizeof(cmd_wildness));
+			cmd_len = len - (p - buf);
+			cmd_confline = confline;
+			debug("%s:%d: Prefer command (%u,%u,%u,%u)\n",
+			      conffile, confline,
+			      wildness[0], wildness[1], wildness[2], wildness[3]);
+			memcpy(cmd, p, cmd_len + 1);
+			strcpy(cmd_conffile, conffile);
+		}
 	}
 
-	file_error("No matching action\n");
+	fclose(conf);
+	return;
 
 syntax_error:
 	line_error("Syntax error\n");
-
-} /* end lookup_action() */
+}
 
 /*****************************************************************************/
 /*
  * attempt to match a datum to a pattern
  * - one asterisk is allowed anywhere in the pattern to indicate a wildcard
  * - returns true if matched, false if not
+ * - adds the total number of chars skipped by wildcard to *_wildness
  */
-static int match(const char *pattern, int plen, const char *datum, int dlen)
+static int match(const char *pattern, int plen, const char *datum, int dlen,
+		 unsigned int *_wildness)
 {
 	const char *asterisk;
 	int n;
 
-	debug("match(%*.*s,%*.*s)\n", plen, plen, pattern, dlen, dlen, datum);
+	if (verbosity >= 2)
+		debug("match(%*.*s,%*.*s)", plen, plen, pattern, dlen, dlen, datum);
 
 	asterisk = memchr(pattern, '*', plen);
 	if (!asterisk) {
@@ -426,12 +502,11 @@ static int match(const char *pattern, int plen, const char *datum, int dlen)
 		/* wildcard at beginning of pattern */
 		pattern++;
 		if (!*pattern)
-			goto yes; /* "*" matches everything */
+			goto yes_wildcard; /* "*" matches everything */
 
 		/* match the end of the datum */
-		plen--;
-		if (memcmp(pattern, datum + (dlen - plen), plen) == 0)
-			goto yes;
+		if (memcmp(pattern, datum + (dlen - (plen - 1)), plen - 1) == 0)
+			goto yes_wildcard;
 		goto no;
 	}
 
@@ -440,20 +515,28 @@ static int match(const char *pattern, int plen, const char *datum, int dlen)
 		goto no;
 
 	if (!asterisk[1])
-		goto yes; /* "abc*" matches */
+		goto yes_wildcard; /* "abc*" matches */
 
 	/* match the end of the datum */
 	asterisk++;
 	n = plen - n - 1;
 	if (memcmp(pattern, datum + (dlen - n), n) == 0)
-		goto yes;
+		goto yes_wildcard;
 
 no:
-	debug(" = no\n");
+	if (verbosity >= 2)
+		debug(" = no\n");
 	return 0;
 
 yes:
-	debug(" = yes\n");
+	if (verbosity >= 2)
+		debug(" = yes (w=0)\n");
+	return 1;
+
+yes_wildcard:
+	*_wildness += dlen - (plen - 1);
+	if (verbosity >= 2)
+		debug(" = yes (w=%u)\n", dlen - (plen - 1));
 	return 1;
 
 } /* end match() */
@@ -462,18 +545,13 @@ yes:
 /*
  * execute a program to deal with a key
  */
-static void execute_program(char *op,
-			    key_serial_t key,
-			    char *ktype,
-			    char *kdesc,
-			    char *callout_info,
-			    char *cmdline)
+static void execute_program(struct parameters *params, char *cmdline)
 {
 	char *argv[256];
 	char *prog, *p, *q;
 	int argc, pipeit;
 
-	debug("execute_program('%s','%s')\n", callout_info, cmdline);
+	debug("execute_program('%s','%s')\n", params->callout_info, cmdline);
 
 	/* if the commandline begins with a bar, then we pipe the callout data into it and read
 	 * back the payload data
@@ -532,16 +610,16 @@ static void execute_program(char *op,
 		/* single character macros */
 		if (!q[1]) {
 			switch (*q) {
-			case 'o': argv[argc] = op;			continue;
-			case 'k': argv[argc] = xkey;			continue;
-			case 't': argv[argc] = ktype;			continue;
-			case 'd': argv[argc] = kdesc;			continue;
-			case 'c': argv[argc] = callout_info;		continue;
-			case 'u': argv[argc] = xuid;			continue;
-			case 'g': argv[argc] = xgid;			continue;
-			case 'T': argv[argc] = xthread_keyring;		continue;
-			case 'P': argv[argc] = xprocess_keyring;	continue;
-			case 'S': argv[argc] = xsession_keyring;	continue;
+			case 'o': argv[argc] = params->op;		continue;
+			case 'k': argv[argc] = params->key;		continue;
+			case 't': argv[argc] = params->key_type;	continue;
+			case 'd': argv[argc] = params->key_desc;	continue;
+			case 'c': argv[argc] = params->callout_info;	continue;
+			case 'u': argv[argc] = params->uid;		continue;
+			case 'g': argv[argc] = params->gid;		continue;
+			case 'T': argv[argc] = params->thread_keyring;	continue;
+			case 'P': argv[argc] = params->process_keyring;	continue;
+			case 'S': argv[argc] = params->session_keyring;	continue;
 			default:
 				line_error("Unsupported macro\n");
 			}
@@ -624,7 +702,7 @@ static void execute_program(char *op,
 	}
 
 	if (pipeit)
-		pipe_to_program(op, key, ktype, kdesc, callout_info, prog, argv);
+		pipe_to_program(params, prog, argv);
 
 	/* attempt to execute the command */
 	execv(prog, argv);
@@ -635,22 +713,16 @@ static void execute_program(char *op,
 
 /*****************************************************************************/
 /*
- * pipe the callout information to the specified program and retrieve the payload data over another
- * pipe
+ * pipe the callout information to the specified program and retrieve the
+ * payload data over another pipe
  */
-static void pipe_to_program(char *op,
-			    key_serial_t key,
-			    char *ktype,
-			    char *kdesc,
-			    char *callout_info,
-			    char *prog,
-			    char **argv)
+static void pipe_to_program(struct parameters *params, char *prog, char **argv)
 {
 	char errbuf[512], payload[32768 + 1], *pp, *pc, *pe;
 	int ipi[2], opi[2], epi[2], childpid;
 	int ifl, ofl, efl, npay, ninfo, espace, tmp;
 
-	debug("pipe_to_program(%s -> %s)", callout_info, prog);
+	debug("pipe_to_program(%s -> %s)", params->callout_info, prog);
 
 	if (pipe(ipi) < 0 || pipe(opi) < 0 || pipe(epi) < 0)
 		error("pipe failed: %m");
@@ -700,8 +772,8 @@ static void pipe_to_program(char *op,
 	    fcntl(FROMSTDERR, F_SETFL, efl) < 0)
 		error("fcntl/F_SETFL failed: %m");
 
-	ninfo = strlen(callout_info);
-	pc = callout_info;
+	ninfo = params->cilen;
+	pc = params->callout_info;
 
 	npay = sizeof(payload);
 	pp = payload;
@@ -858,7 +930,8 @@ static void pipe_to_program(char *op,
 
 		norecurse = 1;
 		debug("child exited %d\n", WEXITSTATUS(tmp));
-		lookup_action("negate", key, ktype, kdesc, callout_info);
+		params->op = "negate";
+		lookup_action(params);
 	}
 
 	if (WIFSIGNALED(tmp)) {
@@ -866,14 +939,14 @@ static void pipe_to_program(char *op,
 			error("child died on signal %d\n", WTERMSIG(tmp));
 
 		norecurse = 1;
-		debug("child died on signal %d\n", WTERMSIG(tmp));
-		lookup_action("negate", key, ktype, kdesc, callout_info);
+		params->op = "negate";
+		lookup_action(params);
 	}
 
 	/* attempt to instantiate the key */
 	debug("instantiate with %td bytes\n", pp - payload);
 
-	if (keyctl_instantiate(key, payload, pp - payload, 0) < 0)
+	if (keyctl_instantiate(params->key_id, payload, pp - payload, 0) < 0)
 		error("instantiate key failed: %m\n");
 
 	debug("instantiation successful\n");

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] Remove the dependency on MIT Kerberos
  2018-09-13 14:08 [PATCH 0/3] keyutils: request_key and DNS resolver changes David Howells
  2018-09-13 14:08 ` [PATCH 1/3] request-key: Provide a command line option to suppress execution David Howells
  2018-09-13 14:08 ` [PATCH 2/3] request-key: Find best match rather than first match David Howells
@ 2018-09-13 14:08 ` David Howells
  2 siblings, 0 replies; 4+ messages in thread
From: David Howells @ 2018-09-13 14:08 UTC (permalink / raw)
  To: keyrings; +Cc: dhowells, linux-nfs, linux-cifs, linux-security-module

Remove the dependency on MIT Kerberos as not everyone has it available.

With the "use best match" change to /sbin/request-key, the kafs-client
package can install a more specific handler for dns_resolver afsdb:*
requests in front of the default one.

This means that the dns resolver program only needs to look up DNS records
and can ignore any static kafs configuration.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 Makefile      |    2 
 dns.afsdb.c   |  268 ++++++++-------------------------------------------------
 keyutils.spec |    2 
 3 files changed, 37 insertions(+), 235 deletions(-)

diff --git a/Makefile b/Makefile
index 5ce6746..96b5df7 100644
--- a/Makefile
+++ b/Makefile
@@ -153,7 +153,7 @@ request-key: request-key.o $(LIB_DEPENDENCY)
 
 key.dns_resolver: key.dns_resolver.o dns.afsdb.o $(LIB_DEPENDENCY)
 	$(CC) -L. $(CFLAGS) $(LDFLAGS) $(RPATH) -o $@ \
-		key.dns_resolver.o dns.afsdb.o -lkrb5 -lcom_err -lkeyutils -lresolv
+		key.dns_resolver.o dns.afsdb.o -lkeyutils -lresolv
 
 key.dns_resolver.o: key.dns_resolver.c key.dns.h
 dns.afsdb.o: dns.afsdb.c key.dns.h
diff --git a/dns.afsdb.c b/dns.afsdb.c
index 4e24815..064d9c8 100644
--- a/dns.afsdb.c
+++ b/dns.afsdb.c
@@ -36,179 +36,9 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include "key.dns.h"
-#include <profile.h>
 
-static const char *afs_cellservdb[] = {
-	"/etc/kafs/cellservdb.conf",
-	"/usr/share/kafs/cellservdb.conf",
-	NULL
-};
-
-static profile_t afs_conf;
-static bool afs_cell_in_conf;
-static bool afs_prefer_dns;
 static unsigned long afs_ttl = ULONG_MAX;
 
-/*
- * Check that a configured address is valid and add it to the list of addresses
- * if okay.
- */
-static void afs_conf_add_address(char *addr)
-{
-	char *p, *q, *port = NULL;
-	size_t plen = 0;
-
-	if (!addr[0])
-		return;
-
-	if (addr[0] == '[') {
-		/* IPv6 */
-		struct in6_addr in6;
-
-		p = strchr(addr + 1, ']');
-		if (!p)
-			return;
-		*p = 0;
-		if (inet_pton(AF_INET6, addr + 1, &in6) == 0)
-			return;
-		*p++ = ']';
-	} else {
-		struct in_addr in;
-
-		p = strchr(addr, ':');
-		if (p)
-			*p = 0;
-		if (inet_pton(AF_INET, addr, &in) == 0)
-			return;
-		if (p)
-			*p = ':';
-	}
-
-	/* See if there's a port specifier as well */
-	if (p && *p) {
-		if (*p != ':')
-			return;
-		p++;
-		port = p;
-		plen = strlen(port);
-		if (plen > 5)
-			return;
-		strtoul(p, &q, 10);
-		if (q != port + plen)
-			return;
-	}
-
-	append_address_to_payload(addr);
-}
-
-/*
- * Parse the cell database file
- */
-static void afs_conf_find_cell(const char *cell)
-{
-	const char *filter[6];
-	char **list;
-	long res;
-	int tmp;
-
-	/* Parse the cell database file */
-	res = profile_init(afs_cellservdb, &afs_conf);
-	if (res != 0) {
-		afs_prefer_dns = true;
-		goto error;
-	}
-
-	/* Check to see if the named cell is in the list */
-	filter[0] = "cells";
-	filter[1] = cell;
-	filter[2] = NULL;
-
-	res = profile_get_subsection_names(afs_conf, filter, &list);
-	if (res != 0) {
-		afs_prefer_dns = true;
-		goto error;
-	}
-
-	if (!list[0]) {
-		info("cell not configured\n");
-		afs_cell_in_conf = false;
-		afs_prefer_dns = true;
-	} else {
-		afs_cell_in_conf = true;
-
-		/* Retrieve the use_dns value for the cell */
-		res = profile_get_boolean(afs_conf, "cells", cell, "use_dns", 1, &tmp);
-		if (res != 0) {
-			afs_prefer_dns = true;
-			goto error;
-		}
-
-		if (tmp)
-			afs_prefer_dns = true;
-		else
-			info("cell sets use_dns=no");
-	}
-
-	return;
-
-error:
-	_error("cellservdb: %s", error_message(res));
-}
-
-/*
- * Get list of server names from the config file.
- */
-static char **afs_conf_list_servers(const char *cell)
-{
-	const char *filter[] = {
-		"cells",
-		cell,
-		"servers",
-		NULL
-	};
-	char **servers;
-	long res;
-
-	res = profile_get_subsection_names(afs_conf, filter, &servers);
-	if (res != 0)
-		goto error;
-
-	return servers;
-
-error:
-	_error("cellservdb: %s", error_message(res));
-	return NULL;
-}
-
-/*
- * Get list of addresses for a server from the config file.
- */
-static int afs_conf_list_addresses(const char *cell, const char *server)
-{
-	const char *filter[] = {
-		"cells",
-		cell,
-		"servers",
-		server,
-		"address",
-		NULL
-	};
-	char **list, **p;
-	long res;
-
-	res = profile_get_values(afs_conf, filter, &list);
-	if (res != 0)
-		goto error;
-
-	for (p = list; *p; p++)
-		afs_conf_add_address(*p);
-	return 0;
-
-error:
-	_error("cellservdb: %s", error_message(res));
-	return -1;
-}
-
 /*
  *
  */
@@ -377,40 +207,6 @@ static void srv_hosts_to_addrs(ns_msg handle, ns_sect section)
 	info("ttl: %u", ttl);
 }
 
-/*
- * Instantiate the key.
- */
-static __attribute__((noreturn))
-void afs_instantiate(const char *cell)
-{
-	int ret;
-
-	/* set the key's expiry time from the minimum TTL encountered */
-	if (!debug_mode) {
-		ret = keyctl_set_timeout(key, afs_ttl);
-		if (ret == -1)
-			error("%s: keyctl_set_timeout: %m", __func__);
-	}
-
-	/* handle a lack of results */
-	if (payload_index == 0)
-		nsError(NO_DATA, cell);
-
-	/* must include a NUL char at the end of the payload */
-	payload[payload_index].iov_base = "";
-	payload[payload_index++].iov_len = 1;
-	dump_payload();
-
-	/* load the key with data key */
-	if (!debug_mode) {
-		ret = keyctl_instantiate_iov(key, payload, payload_index, 0);
-		if (ret == -1)
-			error("%s: keyctl_instantiate: %m", __func__);
-	}
-
-	exit(0);
-}
-
 /*
  * Look up an AFSDB record to get the VL server addresses.
  */
@@ -487,45 +283,53 @@ static int dns_query_VL_SRV(const char *cell)
 	return 0;
 }
 
+/*
+ * Instantiate the key.
+ */
+static __attribute__((noreturn))
+void afs_instantiate(const char *cell)
+{
+	int ret;
+
+	/* set the key's expiry time from the minimum TTL encountered */
+	if (!debug_mode) {
+		ret = keyctl_set_timeout(key, afs_ttl);
+		if (ret == -1)
+			error("%s: keyctl_set_timeout: %m", __func__);
+	}
+
+	/* handle a lack of results */
+	if (payload_index == 0)
+		nsError(NO_DATA, cell);
+
+	/* must include a NUL char at the end of the payload */
+	payload[payload_index].iov_base = "";
+	payload[payload_index++].iov_len = 1;
+	dump_payload();
+
+	/* load the key with data key */
+	if (!debug_mode) {
+		ret = keyctl_instantiate_iov(key, payload, payload_index, 0);
+		if (ret == -1)
+			error("%s: keyctl_instantiate: %m", __func__);
+	}
+
+	exit(0);
+}
+
 /*
  * Look up VL servers for AFS.
  */
 void afs_look_up_VL_servers(const char *cell, char *options)
 {
-	char **servers;
-
 	/* Is the IP address family limited? */
 	if (strcmp(options, "ipv4") == 0)
 		mask = INET_IP4_ONLY;
 	else if (strcmp(options, "ipv6") == 0)
 		mask = INET_IP6_ONLY;
 
-	afs_conf_find_cell(cell);
-
-	if (afs_prefer_dns) {
-		if (dns_query_VL_SRV(cell) == 0)
-			goto instantiate;
-		if (dns_query_AFSDB(cell) == 0)
-			goto instantiate;
-	}
-
-	if (!afs_cell_in_conf)
-		goto instantiate; /* Record a negative result */
-
-	servers = afs_conf_list_servers(cell);
-	if (!servers) {
-		debug("conf: no servers");
-		goto instantiate; /* Record a negative result */
-	}
-
-	for (; *servers; servers++) {
-		char *server = *servers;
-
-		debug("conf server %s", server);
-		if (dns_resolver(server, NULL) < 0)
-			afs_conf_list_addresses(cell, server);
-	}
+	if (dns_query_VL_SRV(cell) != 0)
+		dns_query_AFSDB(cell);
 
-instantiate:
 	afs_instantiate(cell);
 }
diff --git a/keyutils.spec b/keyutils.spec
index 4303f94..544fe7c 100644
--- a/keyutils.spec
+++ b/keyutils.spec
@@ -17,9 +17,7 @@ Source0: http://people.redhat.com/~dhowells/keyutils/keyutils-%{version}.tar.bz2
 
 BuildRequires: gcc
 BuildRequires: glibc-kernheaders >= 2.4-9.1.92
-BuildRequires: krb5-devel
 Requires: %{name}-libs%{?_isa} = %{version}-%{release}
-Requires: krb5-libs
 
 %description
 Utilities to control the kernel key management facility and to provide

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2018-09-13 19:18 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-13 14:08 [PATCH 0/3] keyutils: request_key and DNS resolver changes David Howells
2018-09-13 14:08 ` [PATCH 1/3] request-key: Provide a command line option to suppress execution David Howells
2018-09-13 14:08 ` [PATCH 2/3] request-key: Find best match rather than first match David Howells
2018-09-13 14:08 ` [PATCH 3/3] Remove the dependency on MIT Kerberos David Howells

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).