Index: apps/app_voicemail.c =================================================================== --- apps/app_voicemail.c (revision 214938) +++ apps/app_voicemail.c (working copy) @@ -458,6 +458,11 @@ OPT_ARG_ARRAY_SIZE = 3, }; +enum vm_passwordlocation { + OPT_PWLOC_CONFFILE = 0, + OPT_PWLOC_SPOOLDIR = 1, +}; + AST_APP_OPTIONS(vm_app_options, { AST_APP_OPTION('s', OPT_SILENT), AST_APP_OPTION('b', OPT_BUSY_GREETING), @@ -723,6 +728,7 @@ static int skipms; static int maxlogins; static int minpassword; +static int passwordlocation; /*! Poll mailboxes for changes since there is something external to * app_voicemail that may change them. */ @@ -822,6 +828,8 @@ static void apply_options(struct ast_vm_user *vmu, const char *options); static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum); static int is_valid_dtmf(const char *key); +static void read_password_from_file(const char *secretfn, char *password, int passwordlen); +static int write_password_to_file(const char *secretfn, const char *password); #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE)) static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit); @@ -1289,9 +1297,30 @@ char *category = NULL, *value = NULL, *new = NULL; const char *tmp = NULL; struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS }; + char secretfn[PATH_MAX] = ""; + if (!change_password_realtime(vmu, newpassword)) return; + /* check if we should store the secret in the spool directory next to the messages */ + switch (passwordlocation) { + case OPT_PWLOC_SPOOLDIR: + snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret", VM_SPOOL_DIR, vmu->context, vmu->mailbox); + if (write_password_to_file(secretfn, newpassword)==0) { + if (option_verbose > 3) + ast_verbose( VERBOSE_PREFIX_4 "writing voicemail password to file %s succeeded\n", secretfn); + reset_user_pw(vmu->context, vmu->mailbox, newpassword); + return; + } else { + if (option_verbose > 3) + ast_verbose( VERBOSE_PREFIX_4 "writing voicemail password to file %s failed, keeping old password\n", secretfn); + return; + } + break; + default: + ; + } + /* check voicemail.conf */ if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) { while ((category = ast_category_browse(cfg, category))) { @@ -9785,6 +9814,7 @@ struct ast_vm_user *vmu; char *mailbox_full; int new = 0, old = 0, urgent = 0; + char secretfn[PATH_MAX] = ""; tmp = ast_strdupa(data); @@ -9805,6 +9835,15 @@ if (stringp && (s = strsep(&stringp, ","))) apply_options(vmu, s); + switch (passwordlocation) { + case OPT_PWLOC_SPOOLDIR: + snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret", VM_SPOOL_DIR, vmu->context, vmu->mailbox); + read_password_from_file(secretfn, vmu->password, sizeof(vmu->password)); + break; + default: + ; + } + mailbox_full = alloca(strlen(box) + strlen(context) + 1); strcpy(mailbox_full, box); strcat(mailbox_full, "@"); @@ -10488,6 +10527,7 @@ int x; int tmpadsi[4]; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; + char secretfn[PATH_MAX] = ""; ast_unload_realtime("voicemail"); ast_unload_realtime("voicemail_data"); @@ -10981,6 +11021,13 @@ val = "no"; ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD); + if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) + val = "voicemail.conf"; + if (!(strcmp(val,"spooldir"))) + passwordlocation = OPT_PWLOC_SPOOLDIR; + else + passwordlocation = OPT_PWLOC_CONFFILE; + poll_freq = DEFAULT_POLL_FREQ; if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) { if (sscanf(val, "%30u", &poll_freq) != 1) { @@ -11001,6 +11048,15 @@ populate_defaults(current); apply_options_full(current, ast_variable_browse(ucfg, cat)); ast_copy_string(current->context, userscontext, sizeof(current->context)); + + switch (passwordlocation) { + case OPT_PWLOC_SPOOLDIR: + snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret", VM_SPOOL_DIR, current->context, current->mailbox); + read_password_from_file(secretfn, current->password, sizeof(current->password)); + break; + default: + ; + } } } ast_config_destroy(ucfg); @@ -11136,6 +11192,47 @@ return res; } +static void read_password_from_file(const char *secretfn, char *password, int passwordlen) { + struct ast_config *pwconf; + struct ast_flags config_flags = { 0 }; + + pwconf = ast_config_load(secretfn, config_flags); + if (pwconf) { + const char *val = ast_variable_retrieve(pwconf, "general", "password"); + if (val) { + ast_copy_string(password, val, passwordlen); + return; + } + } + ast_log (LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn); +} + +static int write_password_to_file(const char *secretfn, const char *password) { + struct ast_config *conf; + struct ast_category *cat; + struct ast_variable *var; + + if (!(conf=ast_config_new())) { + ast_log(LOG_ERROR, "Error creating new config structure\n"); + return -1; + } + if (!(cat=ast_category_new("general","",1))) { + ast_log(LOG_ERROR, "Error creating new category structure\n"); + return -1; + } + if (!(var=ast_variable_new("password",password,""))) { + ast_log(LOG_ERROR, "Error creating new variable structure\n"); + return -1; + } + ast_category_append(conf,cat); + ast_variable_append(cat,var); + if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) { + ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn); + return -1; + } + return 0; +} + static int reload(void) { return load_config(1); Index: configs/voicemail.conf.sample =================================================================== --- configs/voicemail.conf.sample (revision 214938) +++ configs/voicemail.conf.sample (working copy) @@ -274,6 +274,22 @@ ; The default is "no". ; tempgreetwarn=yes ; Remind the user that their temporary greeting is set +;passwordlocation=spooldir ; Usually the voicemail password (vmsecret) is stored in the configuration file + ; This is sometimes annoying as Asterisk does modify the configuration file if user + ; changes its vmsecret. By setting this option you can specify where Asterisk should + ; read/write the vmsecret. Supported options: + ; voicemail.conf: This is the default option. The secret is read/write from voicemail.conf + ; (or users.conf is used) + ; spooldir: The secret is stored in a separate file in the users voicemail spool + ; directy. For example if voicemail is configured for user 1234 in voicemail + ; context default, then the secret will be stored in (unless you change the spooldir) + ; /var/spool/asterisk/voicemail/default/1234/secret + ; If the this option is turned on, but the secret file does not exist, it falls back + ; and reads the vmsecret specified from the configuration file (voicemail.conf + ; or users.conf)(if an vmsecret is defined there). Make sure that normal Linux users + ; are not allowed to access asterisk's spool directory as the secret is stored in + ; plain text. + ; Note: This option is ignored for realtime voiceboxes. ;messagewrap=no ; Enable next/last message to wrap around to ; first (from last) and last (from first) message ; The default is "no".