Index: apps/app_voicemail.c =================================================================== --- apps/app_voicemail.c (revision 104869) +++ apps/app_voicemail.c (working copy) @@ -462,6 +462,7 @@ static char VM_SPOOL_DIR[PATH_MAX]; static char ext_pass_cmd[128]; +static char ext_pass_confirm_cmd[128]; int my_umask; @@ -1017,6 +1018,80 @@ } } +static char *vm_confirm_password_shell(char *command, char *buf, size_t len) +{ + int fds[2], pid = 0; + char *ret = NULL; + + memset(buf, 0, len); + + if (pipe(fds)) { + ast_log(LOG_WARNING, "Pipe/Exec failed\n"); + } else { + /* good to go*/ + pid = fork(); + + if (pid < 0) { + /* ok maybe not */ + ast_log(LOG_WARNING, "Fork failed\n"); + close(fds[0]); + close(fds[1]); + } else if (pid) { + /* parent */ + close(fds[1]); + read(fds[0], buf, len); + close(fds[0]); + ret = buf; + } else { + /* child */ + char *argv[255] = { 0 }; + + int argc = 0; + char *p; + char *mycmd = ast_strdupa(command); + + close(fds[0]); + dup2(fds[1], STDOUT_FILENO); + argv[argc++] = mycmd; + + do { + if ((p = strchr(mycmd, ' '))) { + *p = '\0'; + mycmd = ++p; + argv[argc++] = mycmd; + } + } + while (p); + + close(fds[1]); + execv(argv[0], argv); + /* DoH! */ + ast_log(LOG_ERROR, "exec of %s failed\n", argv[0]); + exit(0); + } + + } + + return buf; +} + +static int vm_confirm_password(struct ast_vm_user *vmu, char *newpassword) +{ + char cmd[255], buf[255]; + + ast_log(LOG_DEBUG, "Verify password policies for %s\n", newpassword); + + snprintf(cmd,255,"%s %s %s %s",ext_pass_confirm_cmd,vmu->mailbox,vmu->password,newpassword); + if (vm_confirm_password_shell(cmd, buf, sizeof(buf))) { + ast_log(LOG_DEBUG, "Result: %s\n", buf); + if (!strcasecmp(buf, "VALID")) { + ast_log(LOG_DEBUG, "VALID : %s\n", buf); + return 1; + } + } + return 0; +} + static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder) { return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder); @@ -6462,6 +6537,15 @@ if (++tries == 3) return -1; } + + if (!ast_strlen_zero(ext_pass_confirm_cmd)) { + if (!vm_confirm_password(vmu, newpassword)) { + ast_log(LOG_NOTICE,"Password doesn't match policies for user %s (%s != %s)\n", vms->username, newpassword, newpassword2); + cmd = ast_play_and_wait(chan, "pm-invalid-option"); + break; + } + } + if (pwdchange & PWDCHANGE_INTERNAL) vm_change_password(vmu, newpassword); if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) @@ -6896,8 +6980,10 @@ if (passptr[0] == '-') passptr++; } if (vmu && !strcmp(passptr, password)) + pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS"); valid++; else { + pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default"); if (!ast_strlen_zero(prefix)) mailbox[0] = '\0'; @@ -8208,6 +8294,7 @@ AST_LIST_UNLOCK(&zones); memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd)); + memset(ext_pass_confirm_cmd, 0, sizeof(ext_pass_confirm_cmd)); if (cfg) { /* General settings */ @@ -8295,7 +8382,13 @@ 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", "externconfirm"))) { + ast_copy_string(ext_pass_confirm_cmd, val, sizeof(ext_pass_confirm_cmd)); + ast_log(LOG_DEBUG, "found externconfirm: %s\n", ext_pass_confirm_cmd); + } + #ifdef IMAP_STORAGE /* IMAP server address */ if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) { Index: configs/voicemail.conf.sample =================================================================== --- configs/voicemail.conf.sample (revision 104869) +++ configs/voicemail.conf.sample (working copy) @@ -78,6 +78,11 @@ ; 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 change his voicemail password, uncomment this: +;externconfirm=/usr/bin/myapp + ; 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