[gnutls-devel] [PATCH] gnutls_priority_init: multiple @KEYWORD lookups with fallback

Daniel P. Berrange berrange at redhat.com
Fri Jun 3 17:57:02 CEST 2016


The support for using "@KEYWORD" as a priority string is very
useful to separate selection of priorities from application
specific code or config files. It is, however, not general
enough to fully serve all reasonable use cases.

For example, consider an application sets

  gnutls_priority_set_direct(session, "@SYSTEM", NULL);

The system administrator can modify the global priorities
file to change what "@SYSTEM" resolves to for all apps using
GNUTLS. As soon as one application wishes to have a slightly
different configuration from others on the host, you have to
go back and start modifying application specific configuration
files once more. This is bad for the system administrator as
it means there's no longer one single place where they can
see the priority configuration for all apps.

They may try to get around this problem by configuring the
app to use a different keyword, instead of a full priority
string, eg "@LIBVIRT". So the global priorities file can
now define entries for both "SYSTEM" and "LIBVIRT". This
has still placed a burden on the administrator change the
config in two places - both libvirt config files and the
global priorities file.

What is more desirable is if applications were able to provide
a list of keywords that would be tried in order, picking the
first that existed. For example, libvirt could be written to
request the following by default

  gnutls_priority_set_direct(session, "@LIBVIRT,SYSTEM", NULL);

With this, gnutls would first try to find the "LIBVIRT" keyword
in the global configuration file, and if that is not present,
then it would fallback to trying to find the "SYSTEM" keyword.

This provides nice "out of the box" behaviour for system
administrators, whereby the app would be using "SYSTEM" initially
and if the admin wishes to give the app a custom configuration,
they can simply modify the global priorities file to add in the
application specific keyword "LIBVIRT". There is never a need
for the sysadmin to modify any application specific configuration
files any more. It is exclusively controlled in one place via the
global priorities file.

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 lib/priority.c | 98 +++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 66 insertions(+), 32 deletions(-)

diff --git a/lib/priority.c b/lib/priority.c
index 5fcc97f..faa9e9b 100644
--- a/lib/priority.c
+++ b/lib/priority.c
@@ -999,8 +999,8 @@ char *_gnutls_resolve_priorities(const char* priorities)
 char *p = (char*)priorities;
 char *additional = NULL;
 char *ret = NULL;
-char *ss, *line = NULL;
-unsigned ss_len;
+char *ss, *ss_next, *line = NULL;
+unsigned ss_len, ss_next_len;
 int l;
 FILE* fp = NULL;
 size_t n, n2 = 0, line_size;
@@ -1010,40 +1010,64 @@ size_t n, n2 = 0, line_size;
 
 	if (*p == '@') {
 		ss = p+1;
-
-		additional = strchr(p, ':');
+		additional = strchr(ss, ':');
 		if (additional != NULL) {
-			ss_len = additional - ss;
 			additional++;
-		} else {
-			ss_len = strlen(ss);
 		}
 
+		do {
+			ss_next = strchr(ss, ',');
+			if (ss_next != NULL) {
+				if (additional && ss_next > additional)
+					ss_next = NULL;
+				else
+					ss_next++;
+			}
+
+			if (ss_next) {
+				ss_len = ss_next - ss - 1;
+				ss_next_len = additional - ss_next - 1;
+			} else if (additional) {
+				ss_len = additional - ss - 1;
+				ss_next_len = 0;
+			} else {
+				ss_len = strlen(ss);
+				ss_next_len = 0;
+			}
+
 #ifdef HAVE_FMEMOPEN
-		/* Always try to refresh the cached data, to
-		 * allow it to be updated without restarting
-		 * all applications
-		 */
-		_gnutls_update_system_priorities();
-		fp = fmemopen(system_priority_buf, system_priority_buf_size, "r");
+			/* Always try to refresh the cached data, to
+			 * allow it to be updated without restarting
+			 * all applications
+			 */
+			_gnutls_update_system_priorities();
+			fp = fmemopen(system_priority_buf, system_priority_buf_size, "r");
 #else
-		fp = fopen(system_priority_file, "r");
+			fp = fopen(system_priority_file, "r");
 #endif
-		if (fp == NULL) {/* fail */
-			ret = NULL;
-			goto finish;
-		}
-
-		do {
-			l = getline(&line, &line_size, fp);
-			if (l > 0) {
-				p = check_str(line, line_size, ss, ss_len);
-				if (p != NULL)
-					break;
+			if (fp == NULL) {/* fail */
+				ret = NULL;
+				goto finish;
 			}
-		} while (l>0);
+
+			do {
+				l = getline(&line, &line_size, fp);
+				if (l > 0) {
+					p = check_str(line, line_size, ss, ss_len);
+					if (p != NULL)
+						break;
+				}
+			} while (l>0);
+
+			_gnutls_debug_log("resolved '%.*s' to '%s', next '%.*s'\n",
+					  ss_len, ss, p ? : "", ss_next_len, ss_next ? : "");
+			ss = ss_next;
+			fclose(fp);
+			fp = NULL;
+		} while (ss && p == NULL);
 
 		if (p == NULL) {
+			_gnutls_debug_log("unable to resolve %s\n", priorities);
 			ret = NULL;
 			goto finish;
 		}
@@ -1129,12 +1153,22 @@ finish:
  * "NONE" means nothing is enabled.  This disables even protocols and
  * compression methods.
  *
- * "@KEYWORD" The system administrator imposed settings. The provided keywords
- * will be expanded from a configuration-time provided file - default is:
- * /etc/gnutls/default-priorities. Any keywords that follow it, will 
- * be appended to the expanded string. If there is no system string,
- * then the function will fail. The system file should be formatted
- * as "KEYWORD=VALUE", e.g., "SYSTEM=NORMAL:+ARCFOUR-128".
+ * "@KEYWORD1,KEYWORD2,..." The system administrator imposed settings.
+ * The provided keyword(s) will be expanded from a configuration-time
+ * provided file - default is: /etc/gnutls/default-priorities.
+ * Any attributes that follow it, will be appended to the expanded
+ * string. If multiple keywords are provided, separated by commas,
+ * then the first keyword that exists in the configuration file
+ * will be used. At least one of the keywords must exist, or this
+ * function will return an error. Typical usage would be to specify
+ * an application specified keyword first, followed by "SYSTEM" as
+ * a default fallback. e.g., "@LIBVIRT, at SYSTEM:!-VERS-SSL3.0" will
+ * first try to find a config file entry matching "LIBVIRT", but if
+ * that does not exist will use the entry for "SYSTEM". If "SYSTEM"
+ * does not exist either, an error will be returned. In all cases,
+ * the SSL3.0 protocol will be disabled. The system priority file
+ * entries should be formatted as "KEYWORD=VALUE", e.g.,
+ * "SYSTEM=NORMAL:+ARCFOUR-128".
  *
  * Special keywords are "!", "-" and "+".
  * "!" or "-" appended with an algorithm will remove this algorithm.
-- 
2.5.5




More information about the Gnutls-devel mailing list