From: Daniel P. Berrange Date: Fri, 3 Jun 2016 15:57:02 +0000 (+0100) Subject: gnutls_priority_init: multiple @KEYWORD lookups with fallback X-Git-Tag: gnutls_3_5_1~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6b6d9dd44e;p=thirdparty%2Fgnutls.git gnutls_priority_init: multiple @KEYWORD lookups with fallback 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 --- diff --git a/lib/priority.c b/lib/priority.c index 0f8bc934ad..c5918a28d5 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,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.