[svn-commits] tilghman: trunk r225406 - in /trunk: ./ apps/ configs/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Oct 22 14:10:10 CDT 2009


Author: tilghman
Date: Thu Oct 22 14:10:04 2009
New Revision: 225406

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=225406
Log:
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

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

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=225406&r1=225405&r2=225406
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Thu Oct 22 14:10:04 2009
@@ -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 @@
  * 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
 ------------------

Modified: trunk/apps/app_voicemail.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_voicemail.c?view=diff&rev=225406&r1=225405&r2=225406
==============================================================================
--- trunk/apps/app_voicemail.c (original)
+++ trunk/apps/app_voicemail.c Thu Oct 22 14:10:04 2009
@@ -471,6 +471,12 @@
 	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 @@
 	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 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 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 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 @@
 		}
 	} 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 @@
 	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");
+	/* 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;
+				}
+			}
+			/* 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;
+			}
+		}
+		/* 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;
 				}
-				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 */
-		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");
-					break;
-				}
-				if (!var)		
-					ast_variable_update(cat, "vmsecret", new, NULL, 0);
-				else
-					ast_variable_append(cat, var);
-			}
-		}
-		/* 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");
+			}
+			/* 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");
+			}
+		}
 	}
 }
 
@@ -9860,25 +9906,37 @@
 	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 @@
 	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 @@
 			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 @@
 					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 @@
 	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);

Modified: trunk/configs/voicemail.conf.sample
URL: http://svnview.digium.com/svn/asterisk/trunk/configs/voicemail.conf.sample?view=diff&rev=225406&r1=225405&r2=225406
==============================================================================
--- trunk/configs/voicemail.conf.sample (original)
+++ trunk/configs/voicemail.conf.sample Thu Oct 22 14:10:04 2009
@@ -274,9 +274,28 @@
 			;     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




More information about the svn-commits mailing list