radiusd-livingston (2.1-19) src/menu.c

Summary

 src/menu.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 58 insertions(+), 10 deletions(-)

    
download this patch

Patch contents

--- radiusd-livingston-2.1.orig/src/menu.c
+++ radiusd-livingston-2.1/src/menu.c
@@ -65,6 +65,7 @@
 #include	<signal.h>
 #include	<errno.h>
 #include	<sys/wait.h>
+#include	<string.h>
 
 #include	"radius.h"
 
@@ -72,6 +73,47 @@
 extern char	*radacct_dir;
 extern char	*progname;
 
+/*************************************************************************
+ *
+ *      Function: validfilename
+ *
+ *      Purpose: Check to make sure a filename is valid
+ *               I.e. weed out nasties
+ *
+ *************************************************************************/
+
+/* Valid characters in a filename */
+static char *validfilname_chars =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890#-+ \t/";
+
+int
+validfilename(filename)
+char *filename;
+{
+        /* Not a valid filename if it is NULL or zero length */
+        if(filename==NULL || *filename=='\0'){
+                return(0);
+        }
+
+        /* Check each character in the filename to make sure
+         * it is valid as per validfilname_chars
+         */
+        while(*filename!='\0'){
+                if(strchr(validfilname_chars, *filename)==NULL){
+                        return(0);
+                }
+                filename++;
+        }
+
+        /* Not a filename if it ends with a '/' */
+        if(*filename=='/'){
+                return(0);
+        }
+
+        return(1);
+}
+
+
 void
 process_menu(authreq, activefd, pw_digest)
 AUTH_REQ	*authreq;
@@ -84,10 +126,10 @@
 	VALUE_PAIR	*get_attribute();
 	VALUE_PAIR	*menu_pairs();
 	VALUE_PAIR	*pairalloc();
-	char		menu_name[128];
+	char		menu_name[256];
 	char		menu_input[32];
 	int		i;
-	char		state_value[128];
+	char		state_value[256];
 	void		send_accept();
 	void		send_reject();
 	void		pairfree();
@@ -96,7 +138,8 @@
 	if((attr = get_attribute(authreq->request, PW_STATE)) !=
 		(VALUE_PAIR *)NULL && strncmp(attr->strvalue, "MENU=", 5) == 0){
 
-		strcpy(menu_name, &attr->strvalue[5]);
+		strncpy(menu_name, &attr->strvalue[5], sizeof(menu_name)-1);
+                menu_name[sizeof(menu_name)-1] = '\0';
 
 		/* The menu input is in the Password Field */
 		attr = get_attribute(authreq->request, PW_PASSWORD);
@@ -121,7 +164,8 @@
 							(VALUE_PAIR *)NULL) {
 
 		/* Change this to a menu state */
-		sprintf(state_value, "MENU=%s", term_attr->strvalue);
+		snprintf(state_value, sizeof(state_value), "MENU=%s", 
+                        term_attr->strvalue);
 		term_attr->attribute = PW_STATE;
 		strcpy(term_attr->strvalue, state_value);
 		strcpy(term_attr->name, "Challenge-State");
@@ -168,7 +212,8 @@
 	int	len;
 
 	sprintf(menu_buffer, "%s/menus/%s", radius_dir, menu_name);
-	if((fd = fopen(menu_buffer, "r")) == (FILE *)NULL) {
+	if(!validfilename(menu_buffer) || 
+                (fd = fopen(menu_buffer, "r")) == (FILE *)NULL) {
 		return("\r\n*** User Menu is Not Available ***\r\n");
 	}
 
@@ -176,7 +221,7 @@
 	nread = 0;
 	ptr = menu_buffer;
 	*ptr = '\0';
-	while(fgets(ptr, 4096 - nread, fd) != NULL && nread < 4096) {
+	while(fgets(ptr, 4096 - nread - 4, fd) != NULL && nread < 4096) {
 
 		if(mode == 0) {
 			if(strncmp(ptr, "menu", 4) == 0) {
@@ -221,14 +266,16 @@
 	int	fclose();
 
 	sprintf(buffer, "%s/menus/%s", radius_dir, menu_name);
-	if((fd = fopen(buffer, "r")) == (FILE *)NULL) {
+	if(!validfilename(buffer) || 
+                (fd = fopen(buffer, "r")) == (FILE *)NULL) {
 		return((VALUE_PAIR *)NULL);
 	}
 
 	/* Skip past the menu */
 	mode = 0;
 	nread = 0;
-	while(fgets(buffer, sizeof(buffer), fd) != NULL) {
+	while(fgets(buffer, sizeof(buffer) - 1, fd) != NULL) {
+                buffer[sizeof(buffer)-1]='\0';
 		if(mode == 0) {
 			if(strncmp(buffer, "menu", 4) == 0) {
 				mode = 1;
@@ -251,7 +298,8 @@
 	reply_first = (VALUE_PAIR *)NULL;
 
 	/* Look for a matching menu entry */
-	while(fgets(buffer, sizeof(buffer), fd) != NULL) {
+	while(fgets(buffer, sizeof(buffer)-1, fd) != NULL) {
+                buffer[sizeof(buffer)-1]='\0';
 
 		/* Terminate the buffer */
 		ptr = buffer;
@@ -265,7 +313,7 @@
 		if(strcmp(selection, buffer) == 0 ||
 					strcmp("DEFAULT", buffer) == 0) {
 			/* We have a match */
-			while(fgets(buffer, sizeof(buffer), fd) != NULL) {
+			while(fgets(buffer, sizeof(buffer)-1, fd) != NULL) {
 			    if(*buffer == ' ' || *buffer == '\t') {
 				/*
 				 * Parse the reply values