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>
... | ... |
@@ -36,6 +36,13 @@ LZ4 Compression |
36 | 36 |
|
37 | 37 |
User-visible Changes |
38 | 38 |
-------------------- |
39 |
+- For certificate DNs with duplicate fields, e.g. "OU=one,OU=two", both fields |
|
40 |
+ are now exported to the environment, where each second and later occurrence |
|
41 |
+ of a field get _$N appended to it's field name, starting at N=1. For the |
|
42 |
+ example above, that would result in e.g. X509_0_OU=one, X509_0_OU_1=two. |
|
43 |
+ Note that this breaks setups that rely on the fact that OpenVPN would |
|
44 |
+ previously (incorrectly) only export the last occurence of a field. |
|
45 |
+ |
|
39 | 46 |
- proto udp and proto tcp specify to use IPv4 and IPv6. The new |
40 | 47 |
options proto udp4 and tcp4 specify to use IPv4 only. |
41 | 48 |
|
... | ... |
@@ -607,6 +607,16 @@ env_set_add (struct env_set *es, const char *str) |
607 | 607 |
env_set_add_nolock (es, str); |
608 | 608 |
} |
609 | 609 |
|
610 |
+const char* |
|
611 |
+env_set_get (const struct env_set *es, const char *name) |
|
612 |
+{ |
|
613 |
+ const struct env_item *item = es->list; |
|
614 |
+ while (item && !env_string_equal(item->string, name)) { |
|
615 |
+ item = item->next; |
|
616 |
+ } |
|
617 |
+ return item ? item->string : NULL; |
|
618 |
+} |
|
619 |
+ |
|
610 | 620 |
void |
611 | 621 |
env_set_print (int msglevel, const struct env_set *es) |
612 | 622 |
{ |
... | ... |
@@ -741,6 +751,28 @@ setenv_str_safe (struct env_set *es, const char *name, const char *value) |
741 | 741 |
msg (M_WARN, "setenv_str_safe: name overflow"); |
742 | 742 |
} |
743 | 743 |
|
744 |
+void setenv_str_incr(struct env_set *es, const char *name, const char *value) |
|
745 |
+{ |
|
746 |
+ unsigned int counter = 1; |
|
747 |
+ const size_t tmpname_len = strlen(name) + 5; /* 3 digits counter max */ |
|
748 |
+ char *tmpname = gc_malloc(tmpname_len, true, NULL); |
|
749 |
+ strcpy(tmpname, name); |
|
750 |
+ while (NULL != env_set_get(es, tmpname) && counter < 1000) |
|
751 |
+ { |
|
752 |
+ ASSERT (openvpn_snprintf (tmpname, tmpname_len, "%s_%u", name, counter)); |
|
753 |
+ counter++; |
|
754 |
+ } |
|
755 |
+ if (counter < 1000) |
|
756 |
+ { |
|
757 |
+ setenv_str (es, tmpname, value); |
|
758 |
+ } |
|
759 |
+ else |
|
760 |
+ { |
|
761 |
+ msg (D_TLS_DEBUG_MED, "Too many same-name env variables, ignoring: %s", name); |
|
762 |
+ } |
|
763 |
+ free (tmpname); |
|
764 |
+} |
|
765 |
+ |
|
744 | 766 |
void |
745 | 767 |
setenv_del (struct env_set *es, const char *name) |
746 | 768 |
{ |
... | ... |
@@ -133,6 +133,12 @@ void setenv_str (struct env_set *es, const char *name, const char *value); |
133 | 133 |
void setenv_str_safe (struct env_set *es, const char *name, const char *value); |
134 | 134 |
void setenv_del (struct env_set *es, const char *name); |
135 | 135 |
|
136 |
+/** |
|
137 |
+ * Store the supplied name value pair in the env_set. If the variable with the |
|
138 |
+ * supplied name already exists, append _N to the name, starting at N=1. |
|
139 |
+ */ |
|
140 |
+void setenv_str_incr(struct env_set *es, const char *name, const char *value); |
|
141 |
+ |
|
136 | 142 |
void setenv_int_i (struct env_set *es, const char *name, const int value, const int i); |
137 | 143 |
void setenv_str_i (struct env_set *es, const char *name, const char *value, const int i); |
138 | 144 |
|
... | ... |
@@ -142,6 +148,7 @@ struct env_set *env_set_create (struct gc_arena *gc); |
142 | 142 |
void env_set_destroy (struct env_set *es); |
143 | 143 |
bool env_set_del (struct env_set *es, const char *str); |
144 | 144 |
void env_set_add (struct env_set *es, const char *str); |
145 |
+const char* env_set_get (const struct env_set *es, const char *name); |
|
145 | 146 |
|
146 | 147 |
void env_set_print (int msglevel, const struct env_set *es); |
147 | 148 |
|
... | ... |
@@ -448,7 +448,7 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert) |
448 | 448 |
objbuf); |
449 | 449 |
string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); |
450 | 450 |
string_mod ((char*)buf, CC_PRINT, CC_CRLF, '_'); |
451 |
- setenv_str (es, name_expand, (char*)buf); |
|
451 |
+ setenv_str_incr (es, name_expand, (char*)buf); |
|
452 | 452 |
free (name_expand); |
453 | 453 |
OPENSSL_free (buf); |
454 | 454 |
} |
... | ... |
@@ -245,7 +245,7 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert) |
245 | 245 |
/* Check both strings, set environment variable */ |
246 | 246 |
string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); |
247 | 247 |
string_mod ((char*)s, CC_PRINT, CC_CRLF, '_'); |
248 |
- setenv_str (es, name_expand, (char*)s); |
|
248 |
+ setenv_str_incr (es, name_expand, (char*)s); |
|
249 | 249 |
|
250 | 250 |
name = name->next; |
251 | 251 |
} |