diff --git a/mbuni/configure.ac b/mbuni/configure.ac index 0ae0dac..48376a0 100644 --- a/mbuni/configure.ac +++ b/mbuni/configure.ac @@ -10,6 +10,7 @@ AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_CC AC_PROG_RANLIB +AC_PROG_LIBTOOL # Checks for libraries. # FIXME: Replace `main' with a function in `-lcrypto': diff --git a/mbuni/mmlib/Makefile.am b/mbuni/mmlib/Makefile.am index f49b58a..07c0aca 100644 --- a/mbuni/mmlib/Makefile.am +++ b/mbuni/mmlib/Makefile.am @@ -1,4 +1,9 @@ noinst_LIBRARIES = libmms.a libmms_a_SOURCES = mms_billing.c mms_billing.h mms_msg.c mms_msg.h mms_queue.c mms_queue.h mms_strings.c mms_strings.h mms_uaprof.c mms_uaprof.h mms_util.c mms_util.h mms_resolve.c - +plugindir = $(libdir)/mbuni +plugin_LTLIBRARIES = libmms_billing_shell.la libmms_resolve_shell.la libmms_resolve_all_local.la libmms_detokenize_shell.la +libmms_billing_shell_la_SOURCES = mms_billing_shell.c +libmms_resolve_shell_la_SOURCES = mms_resolve_shell.c +libmms_resolve_all_local_la_SOURCES = mms_resolve_all_local.c +libmms_detokenize_shell_la_SOURCES = mms_detokenize_shell.c diff --git a/mbuni/mmlib/mms_billing_shell.c b/mbuni/mmlib/mms_billing_shell.c new file mode 100644 index 0000000..1c42827 --- /dev/null +++ b/mbuni/mmlib/mms_billing_shell.c @@ -0,0 +1,48 @@ +#include +#include + +#include "mms_billing.h" + +static Octstr *script = NULL; + +static void *mms_billingmodule_init(char *settings) +{ + script = octstr_create(settings); + return NULL; +} + + +static int mms_billingmodule_fini(void *module_data) +{ + return 0; +} + +static double mms_billmsg(Octstr *from, List *to, unsigned long msg_size, void *module_data) +{ + int i; + + if (script == NULL || octstr_len(script) == 0) + return 0; + for (i=0;i +#include +#include "mms_detokenize.h" +#include "mms_util.h" + +static int mms_detokenizer_init(char *settings) +{ + return 0; +} + +static int mms_detokenizer_fini(void) +{ + return 0; +} + +static Octstr *mms_detokenize(Octstr * token) +{ + /* Return the MSISDN matching the token as a new Octstr */ + return octstr_create("+45xxxxxx"); +} + +/* The function itself. */ +MmsTokenize mms_detokenizefuncs = { + mms_detokenizer_init, + mms_detokenize, + mms_detokenize_fini +}; diff --git a/mbuni/mmlib/mms_detokenize.h b/mbuni/mmlib/mms_detokenize.h new file mode 100644 index 0000000..be4c0bd --- /dev/null +++ b/mbuni/mmlib/mms_detokenize.h @@ -0,0 +1,29 @@ +#ifndef __MMS_DETOKENIZE_INCLUDED__ +#define __MMS_DETOKENIZE_INCLUDED__ + +#include +#include "gwlib/gwlib.h" + +/* Detokenizer module. This file provides prototypes for all detokenizer functions. + * The idea is that for each site a DSO will be created that can resolve a token into an + * msisdn. This is useful if you're creating a multioperator setup or if your wap gateway + * doesn't pass the MSISDN as a header and you want to secure yourself against MSISDN spoofing + */ + +typedef struct MmsDetokenizerFuncStruct { +/* This function is called once to initialise the detokenizer module. Return 0 on succeful + * initialization. + */ + int (*mms_detokenizer_init)(char *settings); + +/* Looks up the token and returns the msisdn as a new Octstr. + * Return NULL on error, otherwise an Octstr + */ + Octstr *(*mms_detokenize)(Octstr * token); + + int (*mms_detokenizer_fini)(void); +} MmsDetokenizerFuncStruct; + +extern MmsDetokenizerFuncStruct mms_detokenizefuncs; /* The module must expose this symbol. */ + +#endif diff --git a/mbuni/mmlib/mms_detokenize_shell.c b/mbuni/mmlib/mms_detokenize_shell.c new file mode 100644 index 0000000..167298e --- /dev/null +++ b/mbuni/mmlib/mms_detokenize_shell.c @@ -0,0 +1,43 @@ +#include +#include +#include "mms_detokenize.h" +#include "mms_util.h" + +Octstr *script; + +static int mms_detokenizer_init(char *settings) +{ + script = octstr_create(settings); + return 0; +} + +static int mms_detokenizer_fini(void) +{ + return 0; +} + +static Octstr *mms_detokenize(Octstr * token) +{ + Octstr *s; + FILE *fp; + char buf[4096]; + + if (script == NULL || octstr_len(script) == 0) + return NULL; + + s = octstr_format("%s '%s'", octstr_get_cstr(script), octstr_get_cstr(token)); + fp = popen(octstr_get_cstr(s), "r"); + octstr_destroy(s); + fgets(buf, 4096, fp); + s = octstr_create(buf); + octstr_strip_crlfs(s); + pclose(fp); + return s; +} + +/* The function itself. */ +MmsDetokenizerFuncStruct mms_detokenizefuncs = { + mms_detokenizer_init, + mms_detokenize, + mms_detokenizer_fini +}; diff --git a/mbuni/mmlib/mms_resolve_shell.c b/mbuni/mmlib/mms_resolve_shell.c new file mode 100644 index 0000000..9b8a1ad --- /dev/null +++ b/mbuni/mmlib/mms_resolve_shell.c @@ -0,0 +1,46 @@ +#include +#include +#include "mms_resolve.h" +#include "mms_util.h" + +static Octstr *script = NULL; + +static void *mms_resolvermodule_init(char *settings) +{ + script = octstr_imm(settings); + return NULL; +} + +static int mms_resolvermodule_fini(void *module_data) +{ + return 0; +} + +static Octstr *mms_resolve(Octstr * phonenum, void *module_data, void *settings_p, void *proxyrelays_p) +{ + Octstr *s; + FILE *fp; + char buf[4096]; + + if (script == NULL || octstr_len(script) == 0) + return 0; + + s = octstr_format("%s '%s' ", octstr_get_cstr(phonenum)); + fp = popen(octstr_get_cstr(s), "r"); + octstr_destroy(s); + + fgets(buf, 4096, fp); + s = octstr_create(buf); + octstr_strip_crlfs(s); + + pclose(fp); + + return s; +} + +/* The function itself. */ +MmsResolverFuncStruct mms_resolvefuncs = { + mms_resolvermodule_init, + mms_resolve, + mms_resolvermodule_fini +}; diff --git a/mbuni/mmlib/mms_util.c b/mbuni/mmlib/mms_util.c index 3afddf3..ada4aca 100644 --- a/mbuni/mmlib/mms_util.c +++ b/mbuni/mmlib/mms_util.c @@ -187,6 +187,21 @@ MmsBoxSettings *mms_load_mmsbox_settings(Cfg *cfg) m->mms_resolver_module_data = m->mms_resolvefuncs->mms_resolvermodule_init(octstr_get_cstr(m->resolver_params)); + m->detokenizer_params = cfg_getx(grp, octstr_imm("detokenizer-module-parameters")); + + /* Get and load the detokenizer lib if any. */ + if ((m->mms_detokenizefuncs = load_module(grp, "detokenizer-library", "mms_detokenizefuncs"))) { + if (m->mms_detokenizefuncs->mms_detokenizer_init == NULL || + m->mms_detokenizefuncs->mms_detokenize == NULL || + m->mms_detokenizefuncs->mms_detokenizer_fini == NULL) + panic(0, "Missing or NULL functions in detokenizer module!"); + if (m->mms_detokenizefuncs->mms_detokenizer_init(octstr_get_cstr(m->detokenizer_params))) + panic(0, "Detokenizer module failed to initialize"); + } else + m->mms_detokenizefuncs = NULL; + + m->allow_ip_type = 0; + return m; } @@ -236,7 +251,7 @@ Octstr *mms_makefetchurl(char *qf, Octstr *token, } -Octstr *mms_find_sender_msisdn(Octstr **send_url, List *request_hdrs, Octstr *msisdn_header) +Octstr *mms_find_sender_msisdn(Octstr **send_url, List *request_hdrs, Octstr *msisdn_header, MmsDetokenizerFuncStruct* detokenizerfuncs) { /* Either we have a WAP gateway header as defined, or we look for * last part of url as our number. @@ -252,7 +267,12 @@ Octstr *mms_find_sender_msisdn(Octstr **send_url, List *request_hdrs, Octstr *ms if (l && list_len(l) > 1) { int i, n = list_len(l); Octstr *s; - phonenum = octstr_duplicate(list_get(l, list_len(l) - 1)); + + if (detokenizerfuncs) { + phonenum = detokenizerfuncs->mms_detokenize(list_get(l, list_len(l) - 1)); + } else { + phonenum = octstr_duplicate(list_get(l, list_len(l) - 1)); + } /* After getting it, remove it from the end... */ for (i = 0, s = octstr_create(""); i < n-1; i++) { @@ -262,6 +282,7 @@ Octstr *mms_find_sender_msisdn(Octstr **send_url, List *request_hdrs, Octstr *ms } octstr_destroy(xsend_url); *send_url = s; + } if (l) list_destroy(l, (list_item_destructor_t *)octstr_destroy); diff --git a/mbuni/mmlib/mms_util.h b/mbuni/mmlib/mms_util.h index 506311f..8f3ac58 100644 --- a/mbuni/mmlib/mms_util.h +++ b/mbuni/mmlib/mms_util.h @@ -9,6 +9,7 @@ #include "mms_msg.h" #include "mms_billing.h" #include "mms_resolve.h" +#include "mms_detokenize.h" /* Send errors */ #define MMS_SEND_OK 0 @@ -63,6 +64,12 @@ typedef struct MmsBoxSettings { MmsResolverFuncStruct *mms_resolvefuncs; /* Link to resolver funcs. */ void *mms_resolver_module_data; + Octstr *detokenizer_params; + MmsDetokenizerFuncStruct *mms_detokenizefuncs; /* Link to detokenizer funcs. */ + void *mms_detokenizer_module_data; + + int allow_ip_type; + Octstr *prov_notify; Octstr *prov_notify_arg; Octstr *prov_getstatus; @@ -107,7 +114,7 @@ extern Octstr *mms_getqf_fromtransid(Octstr *transid); extern int mms_decodefetchurl(Octstr *fetch_url, Octstr **qf, Octstr **token); -Octstr *mms_find_sender_msisdn(Octstr **send_url, List *request_hdrs, Octstr *msisdn_header); +Octstr *mms_find_sender_msisdn(Octstr **send_url, List *request_hdrs, Octstr *msisdn_header, MmsDetokenizerFuncStruct *detokenizerfuncs); Octstr *mms_find_sender_ip(List *request_hdrs, Octstr *ip_header, Octstr *ip, int *isv6); extern Octstr *mms_isodate(time_t t); diff --git a/mbuni/mmsc/mmsproxy.c b/mbuni/mmsc/mmsproxy.c index dddfbd5..f0d7252 100644 --- a/mbuni/mmsc/mmsproxy.c +++ b/mbuni/mmsc/mmsproxy.c @@ -135,15 +135,20 @@ int main(int argc, char *argv[]) /* Get the sender address. */ - h.base_client_addr = mms_find_sender_msisdn(&h.url, h.headers, settings->wap_gw_msisdn_header); - + + h.base_client_addr = mms_find_sender_msisdn(&h.url, h.headers, settings->wap_gw_msisdn_header, settings->mms_detokenizefuncs); + if (!h.base_client_addr) { /* Set to IP sender... XXXX assumes ipv4 only for now*/ - int ipv6 = 0; - h.base_client_addr = mms_find_sender_ip(h.headers, - settings->wap_gw_ip_header, - h.ip, &ipv6); - h.client_addr = octstr_format("%S/TYPE=IPv%s", - h.ip, ipv6 ? "6" : "4"); + if (settings->allow_ip_type) { + int ipv6 = 0; + h.base_client_addr = mms_find_sender_ip(h.headers, + settings->wap_gw_ip_header, + h.ip, &ipv6); + h.client_addr = octstr_format("%S/TYPE=IPv%s", + h.ip, ipv6 ? "6" : "4"); + } else { + h.client_addr = NULL; + } } else { normalize_number(octstr_get_cstr(settings->unified_prefix), &h.base_client_addr); h.client_addr = octstr_format("%S/TYPE=PLMN", h.base_client_addr); @@ -461,8 +466,6 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) http_header_add(rh, "Pragma", "no-cache"); http_header_add(rh, "Cache-Control", "no-cache"); - - if (!h->body) { /* A body is required. */ http_header_add(rh, "Content-Type", "text/plain"); hstatus = HTTP_FORBIDDEN; @@ -471,8 +474,8 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) goto done; } - - m = mms_frombinary(h->body, h->client_addr); + + m = mms_frombinary(h->body, h->client_addr ? h->client_addr : octstr_imm("") ); if (!m) { http_header_add(rh, "Content-Type", "text/plain"); @@ -502,42 +505,46 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) Octstr *subject; time_t expiryt, deliveryt; - Octstr *otransid, *value; + Octstr *otransid = NULL, *value = NULL; int dlr; - collect_senddata(mh, &to, &from, &subject, &otransid, &expiryt, &deliveryt); - /*Delete some headers that must be sent on. */ - mms_remove_headers(m, "Bcc"); - mms_remove_headers(m, "X-Mms-Delivery-Time"); - mms_remove_headers(m, "X-Mms-Expiry"); - mms_remove_headers(m, "X-Mms-Sender-Visibility"); - + if (!h->client_addr) { + mresp = mms_sendconf("Error-sending-address-unresolved", "None", octstr_get_cstr(otransid),0); + } else { - value = http_header_value(mh, octstr_imm("X-Mms-Delivery-Report")); - if (value && - octstr_case_compare(value, octstr_imm("Yes")) == 0) - dlr = 1; - else - dlr = 0; + /*Delete some headers that must be sent on. */ + mms_remove_headers(m, "Bcc"); + mms_remove_headers(m, "X-Mms-Delivery-Time"); + mms_remove_headers(m, "X-Mms-Expiry"); + mms_remove_headers(m, "X-Mms-Sender-Visibility"); + + + value = http_header_value(mh, octstr_imm("X-Mms-Delivery-Report")); + if (value && + octstr_case_compare(value, octstr_imm("Yes")) == 0) + dlr = 1; + else + dlr = 0; - qf = mms_queue_add(from, to, NULL, subject, - NULL, NULL, deliveryt, expiryt, m, NULL, dlr, - octstr_get_cstr(settings->global_queuedir)); - - if (!qf) - mresp = mms_sendconf("Error-transient-failure", "None", octstr_get_cstr(otransid),0); - else { - Octstr *transid = mms_maketransid(octstr_get_cstr(qf), settings->host_alias); - mresp = mms_sendconf("Ok", octstr_get_cstr(transid), octstr_get_cstr(otransid),0); + qf = mms_queue_add(from, to, NULL, subject, + NULL, NULL, deliveryt, expiryt, m, NULL, dlr, + octstr_get_cstr(settings->global_queuedir)); + + if (!qf) + mresp = mms_sendconf("Error-transient-failure", "None", octstr_get_cstr(otransid),0); + else { + Octstr *transid = mms_maketransid(octstr_get_cstr(qf), settings->host_alias); + mresp = mms_sendconf("Ok", octstr_get_cstr(transid), octstr_get_cstr(otransid),0); - /* Log to access log */ - mms_log("Received", from, to, msize, transid, NULL, NULL, "MM1", h->ua); + /* Log to access log */ + mms_log("Received", from, to, msize, transid, NULL, NULL, "MM1", h->ua); - octstr_destroy(transid); - octstr_destroy(qf); + octstr_destroy(transid); + octstr_destroy(qf); + } } if (otransid) @@ -885,7 +892,8 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) if (h->base_client_addr) octstr_destroy(h->base_client_addr); - octstr_destroy(h->client_addr); + if (h->client_addr) + octstr_destroy(h->client_addr); if (h->ua) octstr_destroy(h->ua); if (h->body) octstr_destroy(h->body); diff --git a/mbuni/todo b/mbuni/todo index b2683f1..4fff15f 100644 --- a/mbuni/todo +++ b/mbuni/todo @@ -3,3 +3,4 @@ - In content adaptation: Colour depth adjustment - logging a la access.log (one log per interface -- mm1-log, mm4-log, etc) - Need to parameterise some values: tmp dir, response messages (say on failed content adaptation) +- Tests