From: Steve Dickson <steved@redhat.com>
To: Linux NFS Mailing list <linux-nfs@vger.kernel.org>
Subject: [PATCH 2/3] nfs-utils: Add support for further ${variable} expansions in nfs.conf
Date: Wed, 14 Apr 2021 14:10:39 -0400 [thread overview]
Message-ID: <20210414181040.7108-3-steved@redhat.com> (raw)
In-Reply-To: <20210414181040.7108-1-steved@redhat.com>
From: Alice Mitchell <ajmitchell@redhat.com>
This adds support for substituting in the systems machine_id or
the hostname as the unique id, and caches the results
Signed-off-by: Alice Mitchell <ajmitchell@redhat.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
---
support/nfs/conffile.c | 260 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 249 insertions(+), 11 deletions(-)
diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
index fd4a17ad..d03de012 100644
--- a/support/nfs/conffile.c
+++ b/support/nfs/conffile.c
@@ -40,6 +40,7 @@
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <linux/if_alg.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
@@ -114,12 +115,66 @@ struct conf_binding {
char *tag;
char *value;
int is_default;
+ char *cache;
};
LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256];
+typedef char * (*expand_fn_t)(void);
+struct expansion_types {
+ const char *name;
+ expand_fn_t func;
+};
+
+typedef struct {
+ uint8_t bytes[16];
+} id128_t;
+
+/*
+ * Application ID for use with generating a machine-id string
+ */
+static id128_t nfs_appid = {.bytes = {0xff,0x3b,0xf0,0x0f,0x34,0xa6,0x43,0xc5, \
+ 0x93,0xdd,0x16,0xdc,0x7c,0xeb,0x88,0xc8}};
+
const char *modified_by = NULL;
+static __inline__ char
+hexchar(int x) {
+ static const char table[16] = "0123456789abcdef";
+ return table[x & 15];
+}
+
+static __inline__ int
+unhexchar(char h)
+{
+ if (h >= '0' && h <= '9')
+ return h - '0';
+ if (h >= 'a' && h <= 'f')
+ return h - 'a' + 10;
+ if (h >= 'A' && h <= 'F')
+ return h - 'A' + 10;
+ return -1;
+}
+
+static char *
+tohexstr(const unsigned char *data, int len)
+{
+ int i;
+ char *result = NULL;
+
+ result = calloc(1, (len*2)+1);
+ if (!result) {
+ xlog(L_ERROR, "malloc error formatting string");
+ return NULL;
+ }
+
+ for (i = 0; i < len; i++) {
+ result[i*2] = hexchar(data[i] >> 4);
+ result[i*2+1] = hexchar(data[i] & 0x0F);
+ }
+ return result;
+}
+
static __inline__ uint8_t
conf_hash(const char *s)
{
@@ -132,6 +187,193 @@ conf_hash(const char *s)
return hash;
}
+static int
+id128_from_string(const char s[], id128_t *ret)
+{
+ id128_t t;
+ unsigned int n, i;
+ for (n=0, i=0; n<16; ) {
+ int a, b;
+ a = unhexchar(s[i++]);
+ if (a < 0)
+ return 1;
+ b = unhexchar(s[i++]);
+ if (b < 0)
+ return 1;
+
+ t.bytes[n++] = (a << 4) | b;
+ }
+ if (s[i] != 0)
+ return 1;
+ if (ret)
+ *ret = t;
+ return 0;
+}
+
+/*
+ * cryptographic hash (sha256) data into a hex encoded string
+ */
+static char *
+strhash(unsigned char *key, size_t keylen, unsigned char *data, size_t dlen)
+{
+ union {
+ struct sockaddr sa;
+ struct sockaddr_alg alg;
+ } sa;
+ int sock = -1;
+ int hfd = -1;
+ uint8_t digest[129];
+ int n;
+ char *result = NULL;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.alg.salg_family = AF_ALG;
+ strcpy((char *)sa.alg.salg_type, "hash");
+ strcpy((char *)sa.alg.salg_name, "hmac(sha256)");
+
+ sock = socket(AF_ALG, SOCK_SEQPACKET|SOCK_CLOEXEC, 0);
+ if (sock < 0) {
+ xlog(L_ERROR, "error creating socket");
+ goto cleanup;
+ }
+
+ if (bind(sock, (struct sockaddr *)&sa.sa, sizeof(sa)) < 0) {
+ xlog(L_ERROR, "error opening khash interface");
+ goto cleanup;
+ }
+
+ if (key && keylen > 0) {
+ if (setsockopt(sock, SOL_ALG, ALG_SET_KEY, key, keylen) < 0) {
+ xlog(L_ERROR, "Error setting key: %s", strerror(errno));
+ goto cleanup;
+ }
+ }
+
+ hfd = accept4(sock, NULL, 0, SOCK_CLOEXEC);
+ if (hfd < 0) {
+ xlog(L_ERROR, "Error initiating khash: %s", strerror(errno));
+ goto cleanup;
+ }
+
+ n = send(hfd, data, dlen, 0);
+ if (n < 0) {
+ xlog(L_ERROR, "Error updating khash: %s", strerror(errno));
+ goto cleanup;
+ }
+
+ n = recv(hfd, digest, sizeof(digest), 0);
+ if (n < 0) {
+ xlog(L_ERROR, "Error fetching khash: %s", strerror(errno));
+ goto cleanup;
+ }
+
+ result = tohexstr(digest, n);
+cleanup:
+ if (sock != -1)
+ close(sock);
+ if (hfd != -1)
+ close(hfd);
+ if (hfd != -1)
+ close(hfd);
+
+ return result;
+}
+
+/*
+ * Read one line of content from a file
+ */
+static char *
+read_oneline(const char *filename)
+{
+ char *content = conf_readfile(filename);
+ char *end;
+
+ if (content == NULL)
+ return NULL;
+
+ /* trim to only the first line */
+ end = strchr(content, '\n');
+ if (end != NULL)
+ *end = '\0';
+ end = strchr(content, '\r');
+ if (end != NULL)
+ *end = '\0';
+
+ return content;
+}
+
+static char *
+expand_machine_id(void)
+{
+ char *key = read_oneline("/etc/machine-id");
+ id128_t mid;
+ char * result = NULL;
+ size_t idlen = 0;
+
+ if (key == NULL)
+ return NULL;
+
+ idlen = strlen(key);
+ if (!id128_from_string(key, &mid)) {
+ result = strhash(mid.bytes, sizeof(mid), nfs_appid.bytes, sizeof(nfs_appid));
+ if (result && strlen(result) > idlen)
+ result[idlen]=0;
+ }
+ free(key);
+ return result;
+}
+
+static char *
+expand_hostname(void)
+{
+ int maxlen = HOST_NAME_MAX + 1;
+ char * hostname = calloc(1, maxlen);
+
+ if (!hostname)
+ return NULL;
+ if ((gethostname(hostname, maxlen)) == -1) {
+ free(hostname);
+ return NULL;
+ }
+ return hostname;
+}
+
+static struct expansion_types var_expansions[] = {
+ { "machine-id", expand_machine_id },
+ { "hostname", expand_hostname },
+};
+
+/* Deal with more complex variable substitutions */
+static char *
+expand_variable(const char *name)
+{
+ size_t len;
+
+ if (name == NULL || name[0] != '$')
+ return NULL;
+
+ len = strlen(name);
+ if (name[1] == '{' && name[len-1] == '}') {
+ char *varname = strndupa(&name[2], len-3);
+
+ for (size_t i=0; i<sizeof(var_expansions); i++) {
+ if (!strcasecmp(varname, var_expansions[i].name)) {
+ return var_expansions[i].func();
+ }
+ }
+ xlog_warn("get_conf: Unknown variable ${%s}", varname);
+ } else {
+ /* expand $name from [environment] section,
+ * or from environment
+ */
+ char *env = getenv(&name[1]);
+ if (env == NULL || *env == 0)
+ env = conf_get_section("environment", NULL, &name[1]);
+ return env;
+ }
+ return NULL;
+}
+
/*
* free all the component parts of a conf_binding struct
*/
@@ -147,6 +389,8 @@ static void free_confbind(struct conf_binding *cb)
free(cb->tag);
if (cb->value)
free(cb->value);
+ if (cb->cache)
+ free(cb->cache);
free(cb);
}
@@ -921,7 +1165,7 @@ char *
conf_get_section(const char *section, const char *arg, const char *tag)
{
struct conf_binding *cb;
-retry:
+
cb = LIST_FIRST (&conf_bindings[conf_hash (section)]);
for (; cb; cb = LIST_NEXT (cb, link)) {
if (strcasecmp(section, cb->section) != 0)
@@ -933,19 +1177,13 @@ retry:
if (strcasecmp(tag, cb->tag) != 0)
continue;
if (cb->value[0] == '$') {
- /* expand $name from [environment] section,
- * or from environment
- */
- char *env = getenv(cb->value+1);
- if (env && *env)
- return env;
- section = "environment";
- tag = cb->value + 1;
- goto retry;
+ if (!cb->cache)
+ cb->cache = expand_variable(cb->value);
+ return cb->cache;
}
return cb->value;
}
- return 0;
+ return NULL;
}
/*
--
2.30.2
next prev parent reply other threads:[~2021-04-14 18:09 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-04-14 18:10 [PATCH 0/3] Enable the setting of a kernel module parameter from nfs.conf Steve Dickson
2021-04-14 18:10 ` [PATCH 1/3] nfs-utils: Enable the retrieval of raw config settings without expansion Steve Dickson
2021-05-06 17:29 ` Steve Dickson
2021-04-14 18:10 ` Steve Dickson [this message]
2021-04-14 18:10 ` [PATCH 3/3] nfs-utils: Update nfs4_unique_id module parameter from the nfs.conf value Steve Dickson
2021-04-14 23:26 ` [PATCH 0/3] Enable the setting of a kernel module parameter from nfs.conf Chuck Lever III
2021-04-15 15:33 ` Steve Dickson
2021-04-15 16:37 ` Chuck Lever III
2021-04-15 23:30 ` Trond Myklebust
2021-04-16 0:40 ` Trond Myklebust
2021-04-17 16:33 ` Steve Dickson
2021-04-17 18:09 ` Trond Myklebust
2021-04-17 16:18 ` Steve Dickson
2021-04-17 16:36 ` Chuck Lever III
2021-04-17 17:50 ` Steve Dickson
2021-04-18 16:51 ` Chuck Lever III
2021-04-20 13:11 ` Steve Dickson
2021-04-20 14:09 ` Chuck Lever III
2021-04-20 14:31 ` Trond Myklebust
2021-04-20 17:18 ` J. Bruce Fields
2021-04-20 17:28 ` Trond Myklebust
2021-04-20 17:40 ` bfields
2021-04-20 17:53 ` Trond Myklebust
2021-04-20 18:16 ` bfields
2021-04-20 19:30 ` Steve Dickson
2021-04-20 18:47 ` Steve Dickson
2021-04-20 18:26 ` Steve Dickson
2021-05-13 0:29 ` NeilBrown
2021-05-18 12:38 ` Steve Dickson
2021-05-21 2:39 ` NeilBrown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210414181040.7108-3-steved@redhat.com \
--to=steved@redhat.com \
--cc=linux-nfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).