aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2009-10-22 19:10:04 +0000
committertilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2009-10-22 19:10:04 +0000
commitebf4490c905a8b67f8f20d6c3aaec4c1b60646c4 (patch)
treef5168bb7b002e7fa8ac186ecb6c5abb55ce7327e
parent81747b8a3229e626dace95ffe0806b3173fb57fa (diff)
Permit storage of voicemail secrets in a separate file, located within the spool directory.
(closes issue #14276) Reported by: klaus3000 Patches: app_voicemail.c-svn-trunk-r214898.txt uploaded by klaus3000 (license 65) Tested by: jamesgolovich git-svn-id: http://svn.digium.com/svn/asterisk/trunk@225406 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--CHANGES6
-rw-r--r--apps/app_voicemail.c228
-rw-r--r--configs/voicemail.conf.sample25
3 files changed, 200 insertions, 59 deletions
diff --git a/CHANGES b/CHANGES
index 32c304aaa..e6e003b50 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,7 +9,7 @@
======================================================================
------------------------------------------------------------------------------
---- Functionality changes from Asterisk 1.6.2 to Asterisk 1.6.3 -------------
+--- Functionality changes from Asterisk 1.6.2 to Asterisk 1.8 ----------------
------------------------------------------------------------------------------
SIP Changes
@@ -83,6 +83,10 @@ Applications
* The MeetMe application now turns on the DENOISE() function by default, for
each participant. In our tests, this has significantly decreased background
noise (especially noisy data centers).
+ * Voicemail now permits storage of secrets in a separate file, located in the
+ spool directory of each individual user. The control for this is located in
+ the "passwordlocation" option in voicemail.conf. Please see the sample
+ configuration for more information.
Dialplan Functions
------------------
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index 422590fe8..9fad4744d 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -471,6 +471,12 @@ enum vm_option_args {
OPT_ARG_ARRAY_SIZE = 3,
};
+enum vm_passwordlocation {
+ OPT_PWLOC_VOICEMAILCONF = 0,
+ OPT_PWLOC_SPOOLDIR = 1,
+ OPT_PWLOC_USERSCONF = 2,
+};
+
AST_APP_OPTIONS(vm_app_options, {
AST_APP_OPTION('s', OPT_SILENT),
AST_APP_OPTION('b', OPT_BUSY_GREETING),
@@ -601,6 +607,7 @@ struct ast_vm_user {
int maxmsg; /*!< Maximum number of msgs per folder for this mailbox */
int maxdeletedmsg; /*!< Maximum number of deleted msgs saved for this mailbox */
int maxsecs; /*!< Maximum number of seconds per message for this mailbox */
+ int passwordlocation; /*!< Storage location of the password */
#ifdef IMAP_STORAGE
char imapuser[80]; /*!< IMAP server login */
char imappassword[80]; /*!< IMAP server password if authpassword not defined */
@@ -738,6 +745,7 @@ static int maxgreet;
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. */
@@ -838,6 +846,8 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
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);
@@ -875,6 +885,7 @@ static char *strip_control(const char *input, char *buf, size_t buflen)
static void populate_defaults(struct ast_vm_user *vmu)
{
ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
+ vmu->passwordlocation = passwordlocation;
if (saydurationminfo)
vmu->saydurationm = saydurationminfo;
ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
@@ -996,6 +1007,12 @@ static void apply_option(struct ast_vm_user *vmu, const char *var, const char *v
}
} else if (!strcasecmp(var, "volgain")) {
sscanf(value, "%30lf", &vmu->volgain);
+ } else if (!strcasecmp(var, "passwordlocation")) {
+ if (!strcasecmp(value, "spooldir")) {
+ vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
+ } else {
+ vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
+ }
} else if (!strcasecmp(var, "options")) {
apply_options(vmu, value);
}
@@ -1316,65 +1333,94 @@ static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
char *category = NULL, *value = NULL, *new = NULL;
const char *tmp = NULL;
struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
+ char secretfn[PATH_MAX] = "";
+ int found = 0;
+
if (!change_password_realtime(vmu, newpassword))
return;
- /* check voicemail.conf */
- if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
- while ((category = ast_category_browse(cfg, category))) {
- if (!strcasecmp(category, vmu->context)) {
- if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
- ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
- break;
- }
- value = strstr(tmp, ",");
- if (!value) {
- ast_log(AST_LOG_WARNING, "variable has bad format.\n");
- break;
- }
- new = alloca((strlen(value)+strlen(newpassword)+1));
- sprintf(new, "%s%s", newpassword, value);
- if (!(cat = ast_category_get(cfg, category))) {
- ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
- break;
+ /* check if we should store the secret in the spool directory next to the messages */
+ switch (vmu->passwordlocation) {
+ case OPT_PWLOC_SPOOLDIR:
+ snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
+ if (write_password_to_file(secretfn, newpassword) == 0) {
+ ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
+ reset_user_pw(vmu->context, vmu->mailbox, newpassword);
+ ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
+ break;
+ } else {
+ ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
+ }
+ /* Fall-through */
+ case OPT_PWLOC_VOICEMAILCONF:
+ if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
+ while ((category = ast_category_browse(cfg, category))) {
+ if (!strcasecmp(category, vmu->context)) {
+ if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
+ ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
+ break;
+ }
+ value = strstr(tmp, ",");
+ if (!value) {
+ ast_log(AST_LOG_WARNING, "variable has bad format.\n");
+ break;
+ }
+ new = alloca((strlen(value) + strlen(newpassword) + 1));
+ sprintf(new, "%s%s", newpassword, value);
+ if (!(cat = ast_category_get(cfg, category))) {
+ ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
+ break;
+ }
+ ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
+ found = 1;
}
- ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
+ }
+ /* save the results */
+ if (found) {
+ reset_user_pw(vmu->context, vmu->mailbox, newpassword);
+ ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
+ ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
+ break;
}
}
- /* save the results */
- reset_user_pw(vmu->context, vmu->mailbox, newpassword);
- ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
- ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
- }
- category = NULL;
- var = NULL;
- /* check users.conf and update the password stored for the mailbox*/
- /* if no vmsecret entry exists create one. */
- if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
- ast_debug(4, "we are looking for %s\n", vmu->mailbox);
- while ((category = ast_category_browse(cfg, category))) {
- ast_debug(4, "users.conf: %s\n", category);
- if (!strcasecmp(category, vmu->mailbox)) {
- if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
- ast_debug(3, "looks like we need to make vmsecret!\n");
- var = ast_variable_new("vmsecret", newpassword, "");
- }
- new = alloca(strlen(newpassword)+1);
- sprintf(new, "%s", newpassword);
- if (!(cat = ast_category_get(cfg, category))) {
- ast_debug(4, "failed to get category!\n");
+ /* Fall-through */
+ case OPT_PWLOC_USERSCONF:
+ /* check users.conf and update the password stored for the mailbox */
+ /* if no vmsecret entry exists create one. */
+ if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
+ ast_debug(4, "we are looking for %s\n", vmu->mailbox);
+ for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
+ ast_debug(4, "users.conf: %s\n", category);
+ if (!strcasecmp(category, vmu->mailbox)) {
+ if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
+ ast_debug(3, "looks like we need to make vmsecret!\n");
+ var = ast_variable_new("vmsecret", newpassword, "");
+ } else {
+ var = NULL;
+ }
+ new = alloca(strlen(newpassword) + 1);
+ sprintf(new, "%s", newpassword);
+ if (!(cat = ast_category_get(cfg, category))) {
+ ast_debug(4, "failed to get category!\n");
+ ast_free(var);
+ break;
+ }
+ if (!var) {
+ ast_variable_update(cat, "vmsecret", new, NULL, 0);
+ } else {
+ ast_variable_append(cat, var);
+ }
+ found = 1;
break;
}
- if (!var)
- ast_variable_update(cat, "vmsecret", new, NULL, 0);
- else
- ast_variable_append(cat, var);
+ }
+ /* save the results and clean things up */
+ if (found) {
+ reset_user_pw(vmu->context, vmu->mailbox, newpassword);
+ ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
+ ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
}
}
- /* save the results and clean things up */
- reset_user_pw(vmu->context, vmu->mailbox, newpassword);
- ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
- ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
}
}
@@ -9860,25 +9906,37 @@ static int append_mailbox(const char *context, const char *box, const char *data
struct ast_vm_user *vmu;
char *mailbox_full;
int new = 0, old = 0, urgent = 0;
+ char secretfn[PATH_MAX] = "";
tmp = ast_strdupa(data);
if (!(vmu = find_or_create(context, box)))
return -1;
-
+
populate_defaults(vmu);
stringp = tmp;
- if ((s = strsep(&stringp, ",")))
+ if ((s = strsep(&stringp, ","))) {
ast_copy_string(vmu->password, s, sizeof(vmu->password));
- if (stringp && (s = strsep(&stringp, ",")))
+ }
+ if (stringp && (s = strsep(&stringp, ","))) {
ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
- if (stringp && (s = strsep(&stringp, ",")))
+ }
+ if (stringp && (s = strsep(&stringp, ","))) {
ast_copy_string(vmu->email, s, sizeof(vmu->email));
- if (stringp && (s = strsep(&stringp, ",")))
+ }
+ if (stringp && (s = strsep(&stringp, ","))) {
ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
- if (stringp && (s = strsep(&stringp, ",")))
+ }
+ if (stringp && (s = strsep(&stringp, ","))) {
apply_options(vmu, s);
+ }
+
+ switch (vmu->passwordlocation) {
+ case OPT_PWLOC_SPOOLDIR:
+ snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
+ read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
+ }
mailbox_full = alloca(strlen(box) + strlen(context) + 1);
strcpy(mailbox_full, box);
@@ -10563,6 +10621,7 @@ static int load_config(int reload)
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");
@@ -11061,6 +11120,15 @@ static int load_config(int reload)
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_VOICEMAILCONF;
+ }
+
poll_freq = DEFAULT_POLL_FREQ;
if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
if (sscanf(val, "%30u", &poll_freq) != 1) {
@@ -11081,6 +11149,15 @@ static int load_config(int reload)
populate_defaults(current);
apply_options_full(current, ast_variable_browse(ucfg, cat));
ast_copy_string(current->context, userscontext, sizeof(current->context));
+ if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
+ current->passwordlocation = OPT_PWLOC_USERSCONF;
+ }
+
+ switch (current->passwordlocation) {
+ case OPT_PWLOC_SPOOLDIR:
+ snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
+ read_password_from_file(secretfn, current->password, sizeof(current->password));
+ }
}
}
ast_config_destroy(ucfg);
@@ -11216,6 +11293,47 @@ static int sayname(struct ast_channel *chan, const char *mailbox, const char *co
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);
diff --git a/configs/voicemail.conf.sample b/configs/voicemail.conf.sample
index 18615dcd8..024f158cd 100644
--- a/configs/voicemail.conf.sample
+++ b/configs/voicemail.conf.sample
@@ -274,9 +274,28 @@ sendvoicemail=yes ; Allow the user to compose and send a voicemail while inside
; The default is "no".
; tempgreetwarn=yes ; Remind the user that their temporary greeting is set
-;messagewrap=no ; Enable next/last message to wrap around to
- ; first (from last) and last (from first) message
- ; The default is "no".
+; passwordlocation=spooldir
+ ; Usually the voicemail password (vmsecret) is stored in
+ ; this configuration file. 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 from
+ ; and written to voicemail.conf (or users.conf).
+ ; spooldir:
+ ; The secret is stored in a separate file in the user's
+ ; voicemail spool directory in a file named secret.conf.
+ ; Please ensure that normal Linux users are not
+ ; permitted to access Asterisk's spool directory as the
+ ; secret is stored in plain text. If a secret is not
+ ; found in this directory, the password in
+ ; voicemail.conf (or users.conf) will be used.
+ ; Note that this option does not affect password storage for
+ ; realtime users, which are still stored in the realtime
+ ; backend.
+; 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