diff -ruN openvpn-1.3.2-p1/options.c openvpn-1.3.2/options.c
--- openvpn-1.3.2-p1/options.c	Mon Mar 10 14:21:06 2003
+++ openvpn-1.3.2/options.c	Tue Mar 11 19:15:21 2003
@@ -38,6 +38,22 @@
 
 #include "memdbg.h"
 
+
+struct VarEntry {
+	char			*name;
+	char			*value;
+	struct VarEntry	*prev;
+	struct VarEntry	*next;
+};
+
+struct VarEntry	*VarHead = NULL;
+void	VarDefine(char *, char *);
+void	VarDelete(char *);
+char	*ExpandVars(char *);
+
+char	*VarFile = NULL;
+int		VarLine = 0;
+
 static const char usage_message[] =
   "%s\n"
   "\n"
@@ -45,6 +61,8 @@
   "--help          : Show options.\n"
   "--version       : Show copyright and version information.\n"
   "--config file   : Read configuration options from file.\n"
+  "--set name value: Set config-variable.\n"
+  "--unset name    : Unset config-variable.\n"
   "\n"
   "Tunnel Options:\n"
   "--local host    : Local host name or ip address.\n"
@@ -618,10 +636,38 @@
 }
 
 static int
-add_option (struct options *options, int i, char *p1, char *p2, char *p3,
+add_option (struct options *options, int i, char *p1, char *p2r, char *p3r,
 	    const char* file, int line, int level)
 {
-  if (!file)
+  char	*p2 = p2r;
+  char	*p3 = p3r;
+
+  char	pd[1024];
+
+
+  if(file)
+    {
+
+      VarFile = (char*)file;
+      VarLine = line;
+
+      if(p2r)
+        {
+          memset(pd, 0, sizeof(pd));
+          strncpy(pd, ExpandVars(p2r), sizeof(pd));
+          p2 = gc_malloc(strlen(pd) + 1);
+          strncpy(p2, pd, strlen(pd));
+        }
+
+      if(p3r)
+        {
+          memset(pd, 0, sizeof(pd));
+          strncpy(pd, ExpandVars(p3r), sizeof(pd));
+          p3 = gc_malloc(strlen(pd) + 1);
+          strncpy(p3, pd, strlen(pd));
+        }
+    }
+  else
     {
       file = "[CMD-LINE]";
       line = 1;
@@ -1062,6 +1108,16 @@
       options->persist_mode = 1;
     }
 #endif
+  else if (streq (p1, "set") && p2 && p3)
+    {
+      i += 2;
+      VarDefine(p2, p3);
+    }
+  else if (streq (p1, "unset") && p2)
+    {
+      ++i;
+      VarDelete(p2);
+    }
   else
     {
       if (file)
@@ -1109,4 +1165,290 @@
 	}
       i = add_option (options, i, p1, p2, p3, NULL, 0, 0);
     }
+}
+
+
+/****************************************************************************
+ *
+ * Function: VarAlloc()
+ *
+ * Purpose: allocates memory for a variable
+ *
+ * Arguments: none
+ *
+ * Returns: pointer to new VarEntry
+ *
+ ***************************************************************************/
+struct VarEntry *
+VarAlloc() {
+	struct VarEntry	*new;
+
+
+	if((new = (struct VarEntry *)malloc(sizeof(struct VarEntry))) == NULL) {
+		fprintf(stderr, "ERROR: cannot allocate memory for VarEntry.");
+		exit(1);
+	}
+
+	new->name = NULL;
+	new->value = NULL;
+	new->prev = NULL;
+	new->next = NULL;
+
+	return(new);
+}
+
+
+/****************************************************************************
+ *
+ * Function: VarDefine(char *, char *)
+ *
+ * Purpose: define the contents of a variable
+ *
+ * Arguments: name => the name of the variable
+ *            value => the contents of the variable
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void
+VarDefine(char *name, char *value) {
+	struct VarEntry	*p;
+	int		found = 0;
+
+
+	if(! VarHead) {
+		p = VarAlloc();
+		p->name = strdup(name);
+		p->value = strdup(value);
+		p->prev = p;
+		p->next = p;
+
+		VarHead = p;
+
+		return;
+	}
+
+	p = VarHead;
+	do {
+		if(strcasecmp(p->name, name) == 0) {
+			found = 1;
+			break;
+		}
+
+		p = p->next;
+	} while(p != VarHead);
+
+	if(found) {
+		if(p->value)
+			free(p->value);
+
+		p->value = strdup(value);
+	} else {
+		p = VarAlloc();
+		p->name = strdup(name);
+		p->value = strdup(value);
+		p->prev = VarHead;
+		p->next = VarHead->next;
+		p->next->prev = p;
+		VarHead->next = p;
+	}	
+}
+
+
+/****************************************************************************
+ *
+ * Function: VarDelete(char *)
+ *
+ * Purpose: deletes a defined variable
+ *
+ * Arguments: name => the name of the variable
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void
+VarDelete(char *name) {
+	struct VarEntry	*p;
+
+
+	if(! VarHead)
+		return;
+
+	p = VarHead;
+	do {
+		if(strcasecmp(p->name, name) == 0) {
+			p->prev->next = p->next;
+			p->next->prev = p->prev;
+
+			if(VarHead == p)
+				if((VarHead = p->next) == p)
+					VarHead = NULL;
+
+			if(p->name)
+				free(p->name);
+
+			if(p->value)
+				free(p->value);
+
+			free(p);
+
+			return;
+		}
+
+		p = p->next;
+	} while(p != VarHead);
+}
+
+
+/****************************************************************************
+ *
+ * Function: VarGet(char *)
+ *
+ * Purpose: get the contents of a variable
+ *
+ * Arguments: name => the name of the variable
+ *
+ * Returns: char * to contents of variable or NULL
+ *
+ ***************************************************************************/
+char *
+VarGet(char *name) {
+	struct VarEntry	*p;
+
+
+	if(! VarHead)
+		return(NULL);
+
+	p = VarHead;
+	do {
+		if(strcasecmp(p->name, name) == 0)
+			return(p->value);
+
+		p = p->next;
+	} while(p != VarHead);
+
+	return(NULL);
+}
+
+
+/****************************************************************************
+ *
+ * Function: ExpandVars(char *)
+ *
+ * Purpose: expand all variables in a string
+ *
+ * Arguments: string => the name of the variable
+ *
+ * Returns: char * to the expanded string
+ *
+ ***************************************************************************/
+char *
+ExpandVars(char *string) {
+	static char	estring[1024];
+	char		rawvarname[128],
+			varname[128],
+			varaux[128],
+			varbuffer[128],
+			varmodifier,
+			*varcontents;
+	int		varname_completed,
+			c, i, j, iv, jv,
+			l_string,
+			name_only;
+
+
+	if(!string || ! *string || ! strchr(string, '$'))
+		return(string);
+
+
+	bzero(estring, sizeof(estring));
+
+	i = j = 0;
+	l_string = strlen(string);
+	while(i < l_string && j < sizeof(estring) - 1) {
+		c = string[i++];
+		if(c == '$') {
+			bzero(rawvarname, sizeof(rawvarname));
+			varname_completed = 0;
+			name_only = 1;
+			iv = i;
+			jv = 0;
+
+			if(string[i] == '(') {
+				name_only = 0;
+				iv = i + 1;
+			}
+
+			while(!varname_completed && iv < l_string && jv < sizeof(rawvarname) - 1) {
+				c = string[iv++];
+				if((name_only && !(isalnum(c) || c == '_')) || (! name_only && c == ')')) {
+					varname_completed = 1;
+
+					if(name_only)
+						iv--;
+				} else {
+					rawvarname[jv++] = c;
+				}
+			}
+
+			if(varname_completed) {
+				char	*p;
+
+				i = iv;
+
+				varcontents = NULL;
+
+				bzero(varname, sizeof(varname));
+				bzero(varaux, sizeof(varaux));
+				varmodifier = ' ';
+
+				if((p = strchr(rawvarname, ':'))) {
+					strncpy(varname, rawvarname, p - rawvarname);
+
+					if(strlen(p) >= 2) {
+						varmodifier = *(p + 1);
+						strcpy(varaux, p + 2);
+					}
+				} else
+					strcpy(varname, rawvarname);
+					
+				bzero(varbuffer, sizeof(varbuffer));
+
+				varcontents = VarGet(varname);
+
+				switch(varmodifier) {
+				case '-':
+					if(! varcontents || ! strlen(varcontents))
+						varcontents = varaux;
+					break;
+
+				case '?':
+					if(! varcontents || ! strlen(varcontents)) {
+                 		fprintf(stderr, "ERROR Line %s (%d): ", (VarFile ? VarFile : "<stdin>"), VarLine);
+
+						if(strlen(varaux))
+                 			fprintf(stderr, "%s\n", varaux);
+						else
+                 			fprintf(stderr, "Undefined variable \"%s\"\n", varname);
+
+						exit(1);
+					}
+
+					break;
+				}
+
+				if(varcontents) {
+					int	l_varcontents = strlen(varcontents);
+
+					iv = 0;
+					while(iv < l_varcontents && j < sizeof(estring) - 1)
+						estring[j++] = varcontents[iv++];
+				}
+			} else
+				estring[j++] = '$';
+		} else
+			estring[j++] = c;
+	}
+
+	return(estring);
 }
