Browse code

Support duplicate x509 field values in environment

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>

Steffan Karger authored on 2015/11/29 18:39:24
Showing 5 changed files
... ...
@@ -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
     }