As reported in trac #387, an x509 DN can contain duplicate fields.
Previously, we would overwrite any previous field value with a new one if
we would process a second same-name field. Now, instead, append _$N,
starting at N=1 to the name for each consequent field to export all fields
to the enviroment.
v2 - make better use of const qualifiers in env_set_get(), and use strcpy()
instead of memcpy() in setenv_str_incr()
Signed-off-by: Steffan Karger <steffan@karger.me>
Acked-by: Selva Nair <selva.nair@gmail.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <CAA1AbxLoZpanyqfpJuroMeOj_M=gU5JB+pqZqRxYqaiNP754-g@mail.gmail.com>
URL: http://article.gmane.org/gmane.network.openvpn.devel/10654
Signed-off-by: Gert Doering <gert@greenie.muc.de>
User-visible Changes
--------------------
+- For certificate DNs with duplicate fields, e.g. "OU=one,OU=two", both fields
+ are now exported to the environment, where each second and later occurrence
+ of a field get _$N appended to it's field name, starting at N=1. For the
+ example above, that would result in e.g. X509_0_OU=one, X509_0_OU_1=two.
+ Note that this breaks setups that rely on the fact that OpenVPN would
+ previously (incorrectly) only export the last occurence of a field.
+
- proto udp and proto tcp specify to use IPv4 and IPv6. The new
options proto udp4 and tcp4 specify to use IPv4 only.
env_set_add_nolock (es, str);
}
+const char*
+env_set_get (const struct env_set *es, const char *name)
+{
+ const struct env_item *item = es->list;
+ while (item && !env_string_equal(item->string, name)) {
+ item = item->next;
+ }
+ return item ? item->string : NULL;
+}
+
void
env_set_print (int msglevel, const struct env_set *es)
{
msg (M_WARN, "setenv_str_safe: name overflow");
}
+void setenv_str_incr(struct env_set *es, const char *name, const char *value)
+{
+ unsigned int counter = 1;
+ const size_t tmpname_len = strlen(name) + 5; /* 3 digits counter max */
+ char *tmpname = gc_malloc(tmpname_len, true, NULL);
+ strcpy(tmpname, name);
+ while (NULL != env_set_get(es, tmpname) && counter < 1000)
+ {
+ ASSERT (openvpn_snprintf (tmpname, tmpname_len, "%s_%u", name, counter));
+ counter++;
+ }
+ if (counter < 1000)
+ {
+ setenv_str (es, tmpname, value);
+ }
+ else
+ {
+ msg (D_TLS_DEBUG_MED, "Too many same-name env variables, ignoring: %s", name);
+ }
+ free (tmpname);
+}
+
void
setenv_del (struct env_set *es, const char *name)
{
void setenv_str_safe (struct env_set *es, const char *name, const char *value);
void setenv_del (struct env_set *es, const char *name);
+/**
+ * Store the supplied name value pair in the env_set. If the variable with the
+ * supplied name already exists, append _N to the name, starting at N=1.
+ */
+void setenv_str_incr(struct env_set *es, const char *name, const char *value);
+
void setenv_int_i (struct env_set *es, const char *name, const int value, const int i);
void setenv_str_i (struct env_set *es, const char *name, const char *value, const int i);
void env_set_destroy (struct env_set *es);
bool env_set_del (struct env_set *es, const char *str);
void env_set_add (struct env_set *es, const char *str);
+const char* env_set_get (const struct env_set *es, const char *name);
void env_set_print (int msglevel, const struct env_set *es);
objbuf);
string_mod (name_expand, CC_PRINT, CC_CRLF, '_');
string_mod ((char*)buf, CC_PRINT, CC_CRLF, '_');
- setenv_str (es, name_expand, (char*)buf);
+ setenv_str_incr (es, name_expand, (char*)buf);
free (name_expand);
OPENSSL_free (buf);
}
/* Check both strings, set environment variable */
string_mod (name_expand, CC_PRINT, CC_CRLF, '_');
string_mod ((char*)s, CC_PRINT, CC_CRLF, '_');
- setenv_str (es, name_expand, (char*)s);
+ setenv_str_incr (es, name_expand, (char*)s);
name = name->next;
}