--- radiusd.h.orig	Wed Nov  4 07:39:25 1998
+++ radiusd.h	Sun Dec 13 13:53:17 1998
@@ -63,4 +63,5 @@
 	int			attribute;
 	int			type;
+	int			exec;
 	int			length; /* of strvalue */
 	UINT4			lvalue;
@@ -226,4 +227,5 @@
 int		user_find(char *name, VALUE_PAIR *,
 				VALUE_PAIR **, VALUE_PAIR **);
+int		userparse(char *buffer, VALUE_PAIR **first_pair);
 void		presuf_setup(VALUE_PAIR *request_pairs);
 int		hints_setup(VALUE_PAIR *request_pairs);
@@ -264,3 +266,3 @@
 /* exec.c */
 char		*radius_xlate(char *, VALUE_PAIR *req, VALUE_PAIR *reply);
-
+int radius_exec_list(VALUE_PAIR *request, VALUE_PAIR *reply, VALUE_PAIR *first_pair);
--- files.c.orig	Sat Oct 31 16:27:40 1998
+++ files.c	Sun Dec 13 14:10:56 1998
@@ -55,5 +55,4 @@
 #include	"radiusd.h"
 
-static	int userparse(char *buffer, VALUE_PAIR **first_pair);
 static	int  huntgroup_match(VALUE_PAIR *, char *);
 #ifdef NDBM
@@ -1026,4 +1025,15 @@
 			check_tmp = paircopy(pl->check);
 			reply_tmp = paircopy(pl->reply);
+			/*
+			 *  Backtick support by Alan DeKok <aland@ox.org>
+			 *  For example:
+			 *
+			 *  Session-Timeout = `echo 5`
+			 *
+			 *  FIXME: check error codes!
+			 *         What do we do if there's a problem?
+			 */
+			radius_exec_list(request_pairs, *reply_pairs, reply_tmp);
+			
 			pairmove(reply_pairs, &reply_tmp);
 			pairmove(check_pairs, &check_tmp);
@@ -1078,12 +1088,14 @@
  *	past the data field.
  */
-static	void fieldcpy(char *string, int len, char **uptr)
+static	int fieldcpy(char *string, int len, char **uptr)
 {
 	char	*ptr;
+	char	c;
 
 	ptr = *uptr;
-	if(*ptr == '"') {
+	c = *ptr;
+	if (c == '"' || c == '`') {
 		ptr++;
-		while(*ptr != '"' && *ptr != '\0' && *ptr != '\n') {
+		while(*ptr != c && *ptr != '\0' && *ptr != '\n') {
 			if (len-- > 0)
 				*string++ = *ptr++;
@@ -1092,9 +1104,9 @@
 		}
 		*string = '\0';
-		if(*ptr == '"') {
+		if(*ptr == c) {
 			ptr++;
 		}
 		*uptr = ptr;
-		return;
+		return (c == '"' ? 1 : 2);
 	}
 
@@ -1108,5 +1120,5 @@
 	*string = '\0';
 	*uptr = ptr;
-	return;
+	return 0;		/* not a quoted string */
 }
 
@@ -1119,5 +1131,5 @@
  *	Parse the buffer to extract the attribute-value pairs.
  */
-static int userparse(char *buffer, VALUE_PAIR **first_pair)
+int userparse(char *buffer, VALUE_PAIR **first_pair)
 {
 	int		mode;
@@ -1168,5 +1180,5 @@
 		case PARSE_MODE_VALUE:
 			/* Value */
-			fieldcpy(valstr, sizeof(valstr), &buffer);
+			x = fieldcpy(valstr, sizeof(valstr), &buffer);
 			if((pair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) ==
 						(VALUE_PAIR *)NULL) {
@@ -1177,4 +1189,17 @@
 			pair->attribute = attr->value;
 			pair->type = attr->type;
+
+			/*
+			 *  Check for `foo` as value
+			 */
+			if (x == 2) {
+				pair->exec = 1;
+				strcpy(pair->strvalue, valstr);
+				pairadd(first_pair, pair);
+				mode = PARSE_MODE_NAME;
+				break;
+			} else {
+				pair->exec = 0;
+			}
 
 			switch(pair->type) {
--- exec.c.orig	Sun Dec 13 13:09:34 1998
+++ exec.c	Sun Dec 13 14:18:37 1998
@@ -301,2 +301,60 @@
 }
 
+/*
+ *  Backtick support by Alan DeKok <aland@ox.org>
+ *
+ *  Loop over the given list, parsing any backtick commands.
+ *  For each backtick'd attribute, a 'Exec-Program-Wait' is done,
+ *  and the output is used as a value string to the userparse() routine.
+ *
+ *  Some of the translations are taken from the PREVIOUS reply attributes
+ *
+ *	%f   Framed IP address
+ *	%c   Callback-Number
+ *	%t   MTU
+ *	%a   Protocol (SLIP/PPP)
+ *
+ *  That is, the following will NOT work:
+ *
+ * DEFAULT Framed-Protocol = PPP
+ *         Framed-MTU = `/find/mtu/for/protocol/ %a`
+ * 
+ *  NO error checking is done.  This is bad. :(
+ */
+int radius_exec_list(VALUE_PAIR *request, VALUE_PAIR *reply, VALUE_PAIR *first_pair)
+{
+  int rcode;
+  char buffer[1024];
+  char *user_msg;
+  VALUE_PAIR *pair, *parsed, *next;
+
+  for (pair = first_pair; pair; pair = pair->next) {
+    if (!pair->exec) continue;
+
+    DEBUG("Backticks: %s = `%s`", pair->name, pair->strvalue);
+
+    /*
+     *  Exec the program
+     */
+    rcode = radius_exec_program(pair->strvalue, request, reply, 1, &user_msg);
+    
+    if (pair->type != PW_TYPE_STRING) {
+      sprintf(buffer, "%s = %s", pair->name, user_msg);
+    } else {
+      sprintf(buffer, "%s = \"%s\"", pair->name, user_msg);
+    }
+    parsed = NULL;
+    if (userparse(buffer, &parsed) != 0) {
+      DEBUG("error parsing %s", buffer);
+      return -1;
+    }
+
+    next = pair->next;
+    memcpy(pair, parsed, sizeof(VALUE_PAIR));
+    parsed->next = NULL;
+    pairfree(parsed);
+    pair->next = next;
+  }
+
+  return 0;
+}
