You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
8.1 KiB
270 lines
8.1 KiB
From: Sipwise Development Team <support@sipwise.com>
|
|
Date: Mon, 21 Feb 2022 14:17:23 +0100
|
|
Subject: sipwise_vm_add_pcre_support
|
|
|
|
---
|
|
Makefile | 4 +-
|
|
apps/app_voicemail.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
2 files changed, 178 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index 9ee80e1..69eccd0 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -12,10 +12,11 @@ MODULES_DIR=$(INSTALL_PREFIX)$(ASTLIBDIR)
|
|
ASTETCDIR=$(INSTALL_PREFIX)/etc/asterisk
|
|
|
|
CC?=gcc
|
|
+PKG_CONFIG?=pkg-config
|
|
OPTIMIZE=-O2
|
|
DEBUG=-g
|
|
|
|
-LIBS+=
|
|
+LIBS+=$(shell $(PKG_CONFIG) --libs libpcre2-8)
|
|
CFLAGS+=-pipe -fPIC
|
|
CFLAGS+=-Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
|
|
CFLAGS+=-Wno-format-truncation
|
|
@@ -24,6 +25,7 @@ CFLAGS+=-Wno-sign-compare
|
|
CFLAGS+=-Wno-unused-parameter
|
|
CFLAGS+=-Wno-unused-variable
|
|
CFLAGS+=-D_REENTRANT -D_GNU_SOURCE -DODBC_STORAGE
|
|
+CFLAGS+=$(shell $(PKG_CONFIG) --cflags libpcre2-8) -DPCRE2_CODE_UNIT_WIDTH=8
|
|
|
|
all: _all
|
|
@echo " +-------- app_voicemail Build Complete --------+"
|
|
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
|
|
index 7667ae1..e9d5ec3 100644
|
|
--- a/apps/app_voicemail.c
|
|
+++ b/apps/app_voicemail.c
|
|
@@ -112,6 +112,9 @@
|
|
#include "asterisk/threadstorage.h"
|
|
#endif
|
|
|
|
+#include <ctype.h>
|
|
+#include <pcre2.h>
|
|
+
|
|
/*** DOCUMENTATION
|
|
<application name="VoiceMail" language="en_US">
|
|
<synopsis>
|
|
@@ -1081,6 +1084,8 @@ static int maxlogins = 3;
|
|
static int minpassword = MINPASSWORD;
|
|
static int passwordlocation;
|
|
static char aliasescontext[MAX_VM_CONTEXT_LEN];
|
|
+static char sw_normalize_user_match[256];
|
|
+static char sw_normalize_user_replace[256];
|
|
|
|
/*! Poll mailboxes for changes since there is something external to
|
|
* app_voicemail that may change them. */
|
|
@@ -1317,6 +1322,134 @@ static int inprocess_count(const char *context, const char *mailbox, int delta)
|
|
static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
|
|
#endif
|
|
|
|
+/* Sipwise PCRE2 helper functions adapted from contrib of pcre:
|
|
+
|
|
+ Written by: Bert Driehuis <driehuis@playbeing.org>
|
|
+ Copyright (c) 2000 Bert Driehuis
|
|
+
|
|
+ Permission is granted to anyone to use this software for any purpose on any
|
|
+ computer system, and to redistribute it freely, subject to the following
|
|
+ restrictions:
|
|
+
|
|
+ 1. This software is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
+
|
|
+ 2. The origin of this software must not be misrepresented, either by
|
|
+ explicit claim or by omission.
|
|
+
|
|
+ 3. Altered versions must be plainly marked as such, and must not be
|
|
+ misrepresented as being the original software.
|
|
+
|
|
+ 4. If PCRE is embedded in any software that is released under the GNU
|
|
+ General Purpose Licence (GPL), then the terms of that licence shall
|
|
+ supersede any condition above with which it is incompatible.
|
|
+*/
|
|
+#define MAXCAPTURE 50
|
|
+
|
|
+static int findreplen(const char *rep, int nmat, const int *replen)
|
|
+{
|
|
+ int len = 0;
|
|
+ int val;
|
|
+ char *cp = (char *)rep;
|
|
+
|
|
+ while (*cp) {
|
|
+ if (*cp == '$' && isdigit(cp[1])) {
|
|
+ val = strtoul(&cp[1], &cp, 10);
|
|
+ if (val && val <= nmat)
|
|
+ len += replen[val -1];
|
|
+ else
|
|
+ fprintf(stderr, "repl %d out of range\n", val);
|
|
+ } else {
|
|
+ cp++;
|
|
+ len++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return len;
|
|
+}
|
|
+
|
|
+static void doreplace(char *out, const char *rep,
|
|
+ int nmat, int *replen, const char **repstr)
|
|
+{
|
|
+ int val;
|
|
+ char *cp = (char *)rep;
|
|
+
|
|
+ while (*cp) {
|
|
+ if (*cp == '$' && isdigit(cp[1])) {
|
|
+ val = strtoul(&cp[1], &cp, 10);
|
|
+ if (val && val <= nmat) {
|
|
+ strncpy(out, repstr[val - 1], replen[val - 1]);
|
|
+ out += replen[val -1];
|
|
+ }
|
|
+ } else {
|
|
+ *out++ = *cp++;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static char *edit(const char *str, int len, const char *rep,
|
|
+ int nmat, const size_t *ovec)
|
|
+{
|
|
+ int i, slen, rlen;
|
|
+ const size_t *mvec = ovec;
|
|
+ char *res, *cp;
|
|
+ int replen[MAXCAPTURE];
|
|
+ const char *repstr[MAXCAPTURE];
|
|
+
|
|
+ nmat--;
|
|
+ ovec += 2;
|
|
+ for (i = 0; i < nmat; i++) {
|
|
+ replen[i] = ovec[i * 2 + 1] - ovec[i * 2];
|
|
+ repstr[i] = &str[ovec[i * 2]];
|
|
+ }
|
|
+ slen = len;
|
|
+ len -= mvec[1] - mvec[0];
|
|
+ len += rlen = findreplen(rep, nmat, replen);
|
|
+ cp = res = ast_malloc(len + 1);
|
|
+ if (mvec[0] > 0) {
|
|
+ strncpy(cp, str, mvec[0]);
|
|
+ cp += mvec[0];
|
|
+ }
|
|
+ doreplace(cp, rep, nmat, replen, repstr);
|
|
+ cp += rlen;
|
|
+ if (mvec[1] < slen)
|
|
+ strcpy(cp, &str[mvec[1]]);
|
|
+ res[len] = 0;
|
|
+
|
|
+ return res;
|
|
+}
|
|
+
|
|
+static char *pcre_subst(const pcre2_code *ppat,
|
|
+ const char *str, int len,
|
|
+ int offset, int options, const char *rep)
|
|
+{
|
|
+ int nmat;
|
|
+ pcre2_match_data *md;
|
|
+ size_t *ovec;
|
|
+
|
|
+ md = pcre2_match_data_create(MAXCAPTURE, NULL);
|
|
+ if (!md)
|
|
+ return NULL;
|
|
+
|
|
+ nmat = pcre2_match(ppat, (PCRE2_SPTR8)str, len, offset, options,
|
|
+ md, NULL);
|
|
+ if (nmat <= 0) {
|
|
+ pcre2_match_data_free(md);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ ovec = pcre2_get_ovector_pointer(md);
|
|
+ pcre2_match_data_free(md);
|
|
+
|
|
+ if (!ovec)
|
|
+ return NULL;
|
|
+
|
|
+ return edit(str, len, rep, nmat, ovec);
|
|
+}
|
|
+
|
|
+/* end of pcre helper functions */
|
|
+
|
|
/*!
|
|
* \brief Strips control and non 7-bit clean characters from input string.
|
|
*
|
|
@@ -11317,6 +11450,10 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_
|
|
int useadsi = 0, valid = 0, logretries = 0;
|
|
char password[AST_MAX_EXTENSION], *passptr = NULL;
|
|
struct ast_vm_user vmus, *vmu = NULL;
|
|
+ int errcode;
|
|
+ size_t erroffset;
|
|
+ pcre2_code *ppat = NULL;
|
|
+ char *normalized_mailbox;
|
|
|
|
/* If ADSI is supported, setup login screen */
|
|
adsi_begin(chan, &useadsi);
|
|
@@ -11327,6 +11464,17 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_
|
|
return -1;
|
|
}
|
|
|
|
+ if (sw_normalize_user_match[0] != '\0' &&
|
|
+ sw_normalize_user_replace[0] != '\0') {
|
|
+ // TODO: could be done once on start
|
|
+ ppat = pcre2_compile((PCRE2_SPTR8)sw_normalize_user_match, PCRE2_ZERO_TERMINATED, 0, &errcode, &erroffset, NULL);
|
|
+ if (ppat == NULL) {
|
|
+ ast_log(LOG_WARNING, "Couldn't compile user match regex '%s': %d at offset %zd\n",
|
|
+ sw_normalize_user_match, errcode, erroffset);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
/* Authenticate them and get their mailbox/password */
|
|
|
|
while (!valid && (logretries < max_logins)) {
|
|
@@ -11356,6 +11504,18 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_
|
|
if (useadsi)
|
|
adsi_password(chan);
|
|
|
|
+ if (ppat) {
|
|
+ ast_log(LOG_NOTICE, "Trying to rewrite user input '%s' using s/%s/%s/\n",
|
|
+ mailbox, sw_normalize_user_match, sw_normalize_user_replace);
|
|
+ normalized_mailbox = pcre_subst(ppat, mailbox, strlen(mailbox), 0, 0, sw_normalize_user_replace);
|
|
+ if(normalized_mailbox) {
|
|
+ ast_log(LOG_NOTICE, "Rewrote mailbox user input '%s' to %s\n",
|
|
+ mailbox, normalized_mailbox);
|
|
+ ast_copy_string(mailbox, normalized_mailbox, mailbox_size);
|
|
+ ast_free(normalized_mailbox);
|
|
+ }
|
|
+ }
|
|
+
|
|
if (!ast_strlen_zero(prefix)) {
|
|
char fullusername[80];
|
|
|
|
@@ -14349,6 +14509,8 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
|
|
char secretfn[PATH_MAX] = "";
|
|
long tps_queue_low;
|
|
long tps_queue_high;
|
|
+ const char *ast_sw_normalize_user_match = NULL;
|
|
+ const char *ast_sw_normalize_user_replace = NULL;
|
|
|
|
#ifdef IMAP_STORAGE
|
|
ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
|
|
@@ -14421,6 +14583,19 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
|
|
ast_set2_flag((&globalflags), ast_true(val), VM_ODBC_AUDIO_ON_DISK);
|
|
|
|
#endif
|
|
+
|
|
+ /* sipwise sw_normalize_user_match/replace */
|
|
+ if ((ast_sw_normalize_user_match = ast_variable_retrieve(cfg, "general", "sw_normalize_user_match"))) {
|
|
+ ast_copy_string(sw_normalize_user_match, ast_sw_normalize_user_match, sizeof(sw_normalize_user_match));
|
|
+ } else {
|
|
+ sw_normalize_user_match[0] = '\0';
|
|
+ }
|
|
+ if ((ast_sw_normalize_user_replace = ast_variable_retrieve(cfg, "general", "sw_normalize_user_replace"))) {
|
|
+ ast_copy_string(sw_normalize_user_replace, ast_sw_normalize_user_replace, sizeof(sw_normalize_user_replace));
|
|
+ } else {
|
|
+ sw_normalize_user_replace[0] = '\0';
|
|
+ }
|
|
+
|
|
/* Mail command */
|
|
strcpy(mailcmd, SENDMAIL);
|
|
if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
|