dect
/
asterisk
Archived
13
0
Fork 0

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
This commit is contained in:
tilghman 2009-10-22 19:10:04 +00:00
parent 81747b8a32
commit ebf4490c90
3 changed files with 200 additions and 59 deletions

View File

@ -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
------------------

View File

@ -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;
/* 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;
}
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);
}
/* 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);

View File

@ -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