[asterisk-commits] tilghman: trunk r115582 - in /trunk: ./ apps/ configs/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri May 9 12:28:07 CDT 2008


Author: tilghman
Date: Fri May  9 12:28:06 2008
New Revision: 115582

URL: http://svn.digium.com/view/asterisk?view=rev&rev=115582
Log:
Allow a password change to be validated by an external script.
(closes issue #12090)
 Reported by: jaroth
 Patches: 
       vm-check-newpassword.diff.txt uploaded by mvanbaak (license 7)
       20080509__bug12090.diff.txt uploaded by Corydon76 (license 14)

Modified:
    trunk/CHANGES
    trunk/apps/app_voicemail.c
    trunk/configs/voicemail.conf.sample

Modified: trunk/CHANGES
URL: http://svn.digium.com/view/asterisk/trunk/CHANGES?view=diff&rev=115582&r1=115581&r2=115582
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Fri May  9 12:28:06 2008
@@ -42,6 +42,11 @@
    quite helpful.
  * Voicemail now permits a mailbox setting to wrap around from first to last
    messages, if the "messagewrap" option is set to a true value.
+ * Voicemail now permits an external script to be run, for password validation.
+   The script should output "VALID" or "INVALID" on stdout, depending upon the
+   wish to validate or invalidate the password given.  Arguments are:
+   "mailbox" "context" "oldpass" "newpass".  See the sample voicemail.conf for
+   more details
  * Dial has a new option: F(context^extension^pri), which permits a callee to
    continue in the dialplan, at the specified label, if the caller hangs up.
  * ChanSpy and ExtenSpy have a new option, 's' which suppresses speaking the

Modified: trunk/apps/app_voicemail.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_voicemail.c?view=diff&rev=115582&r1=115581&r2=115582
==============================================================================
--- trunk/apps/app_voicemail.c (original)
+++ trunk/apps/app_voicemail.c Fri May  9 12:28:06 2008
@@ -201,6 +201,8 @@
 
 #define MAXMSG 100
 #define MAXMSGLIMIT 9999
+
+#define MINPASSWORD 0 /*!< Default minimum mailbox password length */
 
 #define BASELINELEN 72
 #define BASEMAXINLINE 256
@@ -472,6 +474,7 @@
 static char VM_SPOOL_DIR[PATH_MAX];
 
 static char ext_pass_cmd[128];
+static char ext_pass_check_cmd[128];
 
 int my_umask;
 
@@ -587,6 +590,7 @@
 static int maxgreet;
 static int skipms;
 static int maxlogins;
+static int minpassword;
 
 /*! Poll mailboxes for changes since there is something external to
  *  app_voicemail that may change them. */
@@ -645,6 +649,7 @@
 static char vm_passchanged[80] = "vm-passchanged";
 static char vm_reenterpassword[80] = "vm-reenterpassword";
 static char vm_mismatch[80] = "vm-mismatch";
+static char vm_invalid_password[80] = "vm-invalid-password";
 
 static struct ast_flags globalflags = {0};
 
@@ -820,6 +825,85 @@
 	} else if (!strcasecmp(var, "options")) {
 		apply_options(vmu, value);
 	}
+}
+
+static char *vm_check_password_shell(char *command, char *buf, size_t len) 
+{
+	int fds[2], pid = 0;
+
+	memset(buf, 0, len);
+
+	if (pipe(fds)) {
+		snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
+	} else {
+		/* good to go*/
+		pid = ast_safe_fork(0);
+
+		if (pid < 0) {
+			/* ok maybe not */
+			close(fds[0]);
+			close(fds[1]);
+			snprintf(buf, len, "FAILURE: Fork failed");
+		} else if (pid) {
+			/* parent */
+			close(fds[1]);
+			read(fds[0], buf, len);
+			close(fds[0]);
+		} else {
+			/*  child */
+			AST_DECLARE_APP_ARGS(arg,
+				AST_APP_ARG(v)[20];
+			);
+			char *mycmd = ast_strdupa(command);
+
+			close(fds[0]);
+			dup2(fds[1], STDOUT_FILENO);
+			close(fds[1]);
+			ast_close_fds_above_n(STDOUT_FILENO);
+
+			AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
+
+			execv(arg.v[0], arg.v); 
+			printf("FAILURE: %s", strerror(errno));
+			_exit(0);
+		}
+	}
+	return buf;
+}
+
+/*!
+ * \brief Check that password meets minimum required length
+ * \param vmu The voicemail user to change the password for.
+ * \param password The password string to check
+ *
+ * \return zero on ok, 1 on not ok.
+ */
+static int check_password(struct ast_vm_user *vmu, char *password)
+{
+	/* check minimum length */
+	if (strlen(password) < minpassword)
+		return 1;
+	if (!ast_strlen_zero(ext_pass_check_cmd)) {
+		char cmd[255], buf[255];
+
+		ast_log(LOG_DEBUG, "Verify password policies for %s\n", password);
+
+		snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
+		if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
+			ast_debug(5, "Result: %s\n", buf);
+			if (!strncasecmp(buf, "VALID", 5)) {
+				ast_debug(3, "Passed password check: '%s'\n", buf);
+				return 0;
+			} else if (!strncasecmp(buf, "FAILURE", 7)) {
+				ast_log(LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
+				return 0;
+			} else {
+				ast_log(LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
+				return 1;
+			}
+		}
+	}
+	return 0;
 }
 
 /*! 
@@ -7121,19 +7205,25 @@
 		cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
 		if (cmd < 0 || cmd == 't' || cmd == '#')
 			return cmd;
-		newpassword2[1] = '\0';
-		newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
-		if (cmd == '#')
-			newpassword2[0] = '\0';
-		if (cmd < 0 || cmd == 't' || cmd == '#')
-			return cmd;
-		cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
-		if (cmd < 0 || cmd == 't' || cmd == '#')
-			return cmd;
-		if (!strcmp(newpassword, newpassword2))
-			break;
-		ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
-		cmd = ast_play_and_wait(chan, vm_mismatch);
+		cmd = check_password(vmu, newpassword); /* perform password validation */
+		if (cmd != 0) {
+			ast_log(LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
+			cmd = ast_play_and_wait(chan, vm_invalid_password);
+		} else {
+			newpassword2[1] = '\0';
+			newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
+			if (cmd == '#')
+				newpassword2[0] = '\0';
+			if (cmd < 0 || cmd == 't' || cmd == '#')
+				return cmd;
+			cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
+			if (cmd < 0 || cmd == 't' || cmd == '#')
+				return cmd;
+			if (!strcmp(newpassword, newpassword2))
+				break;
+			ast_log(LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
+			cmd = ast_play_and_wait(chan, vm_mismatch);
+		}
 		if (++tries == 3)
 			return -1;
 	}
@@ -7252,6 +7342,12 @@
 				if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
 					break;
 				}
+			}
+			cmd = check_password(vmu, newpassword); /* perform password validation */
+			if (cmd != 0) {
+				ast_log(LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
+				cmd = ast_play_and_wait(chan, vm_invalid_password);
+				break;
 			}
 			newpassword2[1] = '\0';
 			newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
@@ -9003,6 +9099,7 @@
 	AST_LIST_UNLOCK(&zones);
 
 	memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
+	memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
 
 	if (cfg) {
 		/* General settings */
@@ -9089,6 +9186,12 @@
 		} else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
 			ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
 			pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
+		}
+ 
+		/* External password validation command */
+		if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
+			ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
+			ast_log(LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
 		}
 
 #ifdef IMAP_STORAGE
@@ -9277,6 +9380,15 @@
 			}
 		}
 
+		minpassword = MINPASSWORD;
+		if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
+			if (sscanf(val, "%d", &x) == 1) {
+				minpassword = x;
+			} else {
+				ast_log(LOG_WARNING, "Invalid minimum password length.  Default to %d\n", minpassword);
+			}
+		}
+
 		/* Force new user to record name ? */
 		if (!(val = ast_variable_retrieve(cfg, "general", "forcename"))) 
 			val = "no";
@@ -9399,6 +9511,8 @@
 			ast_copy_string(vm_password, val, sizeof(vm_password));
 		if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
 			ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
+		if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
+			ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
 		if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
 			ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
 		if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))

Modified: trunk/configs/voicemail.conf.sample
URL: http://svn.digium.com/view/asterisk/trunk/configs/voicemail.conf.sample?view=diff&rev=115582&r1=115581&r2=115582
==============================================================================
--- trunk/configs/voicemail.conf.sample (original)
+++ trunk/configs/voicemail.conf.sample Fri May  9 12:28:06 2008
@@ -78,6 +78,13 @@
 ; the externpassnotify option below instead.
 ;externpass=/usr/bin/myapp
 ;externpassnotify=/usr/bin/myapp
+
+; If you need to have an external program, i.e. /usr/bin/myapp
+; called when a user changes her voicemail password, uncomment this:
+;externpasscheck=/usr/bin/myapp
+; Arguments for this script are:
+; mailbox context oldpass newpass
+
 ; For the directory, you can override the intro file if you want
 ;directoryintro=dir-intro
 ; The character set for voicemail messages can be specified here
@@ -245,6 +252,7 @@
 ;messagewrap=no	; Enable next/last message to wrap around to
 			; first (from last) and last (from first) message
 			; The default is "no".
+; minpassword=0 ; Enforce minimum password length
 
 ; vm-password=custom_sound
 			;     Customize which sound file is used instead of the default
@@ -264,6 +272,9 @@
 			;     Customize which sound file is used instead of the default
 			;     prompt that says: "The passwords you entered and re-entered
 			;     did not match.  Please try again."
+; vm-invalid-password=custom_sound
+			;     Customize which sound file is used instead of the default
+			;     prompt that says: ...
 ; listen-control-forward-key=#	; Customize the key that fast-forwards message playback
 ; listen-control-reverse-key=*	; Customize the key that rewinds message playback
 ; listen-control-pause-key=0	; Customize the key that pauses/unpauses message playback




More information about the asterisk-commits mailing list