/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2005 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_ppg_pushuser.c: Implementation of wap_push_ppg_pushuser.h header. * * By Aarno Syvänen for Wiral Ltd and Global Networks Inc. */ #include "wap_push_ppg_pushuser.h" #include "numhash.h" #include "gwlib/regex.h" /*************************************************************************** * * Global data structures * * Hold user specific data for one ppg user */ struct WAPPushUser { Octstr *name; /* the name of the user */ Octstr *username; /* the username of this ppg user */ Octstr *password; /* and password */ Octstr *country_prefix; Octstr *allowed_prefix; /* phone number prefixes allowed by this user when pushing*/ regex_t *allowed_prefix_regex; Octstr *denied_prefix; /* and denied ones */ regex_t *denied_prefix_regex; Numhash *white_list; /* phone numbers of this user, used for push*/ regex_t *white_list_regex; Numhash *black_list; /* numbers should not be used for push*/ regex_t *black_list_regex; Octstr *user_deny_ip; /* this user allows pushes from these IPs*/ Octstr *user_allow_ip; /* and denies them from these*/ Octstr *smsc_id; /* force push SMs to this smsc */ Octstr *default_smsc_id; /* use this smsc as a default for push SMs */ Octstr *dlr_url; /* default dlr url from this user */ Octstr *smsbox_id; /* use this smsbox for sending dlrs back*/ }; typedef struct WAPPushUser WAPPushUser; /* * Hold user specific data of all ppg users */ struct WAPPushUserList { List *list; Dict *names; }; typedef struct WAPPushUserList WAPPushUserList; static WAPPushUserList *users = NULL; /* * This hash table stores time when a specific ip is allowed to try next time. */ static Dict *next_try = NULL; /*********************************************************************************** * * Prototypes of internal functions */ static void destroy_users_list(void *l); static WAPPushUserList *pushusers_create(long number_of_users); static WAPPushUser *create_oneuser(CfgGroup *grp); static void destroy_oneuser(void *p); static int oneuser_add(CfgGroup *cfg); static void oneuser_dump(WAPPushUser *u); static WAPPushUser *user_find_by_username(Octstr *username); static int password_matches(WAPPushUser *u, Octstr *password); static int ip_allowed_by_user(WAPPushUser *u, Octstr *ip); static int prefix_allowed(WAPPushUser *u, Octstr *number); static int whitelisted(WAPPushUser *u, Octstr *number); static int blacklisted(WAPPushUser *u, Octstr *number); static int wildcarded_ip_found(Octstr *ip, Octstr *needle, Octstr *ip_sep); static int response(List *push_headers, Octstr **username, Octstr **password); static void challenge(HTTPClient *c, List *push_headers); static void reply(HTTPClient *c, List *push_headers); static int parse_cgivars_for_username(List *cgivars, Octstr **username); static int parse_cgivars_for_password(List *cgivars, Octstr **password); static int compare_octstr_sequence(Octstr *os1, Octstr *os2, long start); static Octstr *forced_smsc(WAPPushUser *u); static Octstr *default_smsc(WAPPushUser *u); /**************************************************************************** * * Implementation of external functions */ /* * Initialize the whole module and fill the push users list. */ int wap_push_ppg_pushuser_list_add(List *list, long number_of_pushes, long number_of_users) { CfgGroup *grp; next_try = dict_create(number_of_pushes, octstr_destroy_item); users = pushusers_create(number_of_users); gw_assert(list); while (list && (grp = gwlist_extract_first(list))) { if (oneuser_add(grp) == -1) { gwlist_destroy(list, NULL); return 0; } } gwlist_destroy(list, NULL); return 1; } void wap_push_ppg_pushuser_list_destroy(void) { dict_destroy(next_try); if (users == NULL) return; gwlist_destroy(users->list, destroy_oneuser); dict_destroy(users->names); gw_free(users); } enum { NO_USERNAME = -1, NO_PASSWORD = 0, HEADER_AUTHENTICATION = 1 }; #define ADDITION 0.1 /* * This function does authentication possible before compiling the control * document. This means: * a) password authentication by url or by headers (it is, by basic * authentication response, see rfc 2617, chapter 2) * b) if this does not work, basic authentication by challenge - * response * c) enforcing various ip lists * * Check does ppg allows a connection from this at all, then try to find username * and password from headers, then from url. If both fails, try basic authentica- * tion. Then check does this user allow a push from this ip, then check the pass- * word. * * For protection against brute force and partial protection for denial of serv- * ice attacks, an exponential backup algorithm is used. Time when a specific ip * is allowed to reconnect, is stored in Dict next_try. If an ip tries to recon- * nect before this (three attemps are allowed, then exponential seconds are add- * ed to the limit) we make a new challenge. We do the corresponding check before * testing passwords; after all, it is an authorization failure that causes a new * challenge. * * Rfc 2617, chapter 1 states that if we do not accept credentials of an user's, * we must send a new challenge to the user. * * Output an authenticated username. * This function should be called only when there are a push users list; the * caller is responsible for this. */ int wap_push_ppg_pushuser_authenticate(HTTPClient *c, List *cgivars, Octstr *ip, List *push_headers, Octstr **username) { time_t now; static long next = 0L; /* used only in this thread (and this function) */ long next_time; Octstr *next_time_os; static long multiplier = 1L; /* ditto */ WAPPushUser *u; Octstr *copy, *password; int ret; copy = octstr_duplicate(ip); time(&now); next_time_os = NULL; if ((ret = response(push_headers, username, &password)) == NO_USERNAME) { if (!parse_cgivars_for_username(cgivars, username)) { error(0, "no user specified, challenging regardless"); goto listed; } } if (password == NULL) parse_cgivars_for_password(cgivars, &password); u = user_find_by_username(*username); if (!ip_allowed_by_user(u, ip)) { goto not_listed; } next = 0; if ((next_time_os = dict_get(next_try, ip)) != NULL) { octstr_parse_long(&next_time, next_time_os, 0, 10); if (difftime(now, (time_t) next_time) < 0) { error(0, "another try from %s, not much time used", octstr_get_cstr(copy)); goto listed; } } if (u == NULL) { error(0, "user %s is not allowed by users list, challenging", octstr_get_cstr(*username)); goto listed; } if (!password_matches(u, password)) { error(0, "wrong or missing password in request from %s, challenging" , octstr_get_cstr(copy)); goto listed; } dict_remove(next_try, ip); /* no restrictions after authentica- tion */ octstr_destroy(password); octstr_destroy(copy); octstr_destroy(next_time_os); return 1; not_listed: octstr_destroy(password); octstr_destroy(copy); reply(c, push_headers); octstr_destroy(next_time_os); return 0; listed: challenge(c, push_headers); multiplier <<= 1; next = next + multiplier * ADDITION; next += now; next_time_os = octstr_format("%ld", next); dict_put(next_try, ip, next_time_os); octstr_destroy(copy); octstr_destroy(password); return 0; } /* * This function checks phone number for allowed prefixes, black lists and white * lists. Note that the phone number necessarily follows the international format * (a requirement by our pap compiler). */ int wap_push_ppg_pushuser_client_phone_number_acceptable(Octstr *username, Octstr *number) { WAPPushUser *u; u = user_find_by_username(username); if (!prefix_allowed(u, number)) { error(0, "Number %s not allowed by user %s (wrong prefix)", octstr_get_cstr(number), octstr_get_cstr(username)); return 0; } if (blacklisted(u, number)) { error(0, "Number %s not allowed by user %s (blacklisted)", octstr_get_cstr(number), octstr_get_cstr(username) ); return 0; } if (!whitelisted(u, number)) { error(0, "Number %s not allowed by user %s (not whitelisted)", octstr_get_cstr(number), octstr_get_cstr(username) ); return 0; } return 1; } int wap_push_ppg_pushuser_search_ip_from_wildcarded_list(Octstr *haystack, Octstr *needle, Octstr *gwlist_sep, Octstr *ip_sep) { List *ips; long i; Octstr *configured_ip; gw_assert(haystack); gw_assert(gwlist_sep); gw_assert(ip_sep); /*There are no wildcards in the list*/ if (octstr_search_char(haystack, '*', 0) < 0) { if (octstr_search(haystack, needle, 0) >= 0) { return 1; } else { return 0; } } /*There are wildcards in the list*/ configured_ip = NULL; ips = octstr_split(haystack, gwlist_sep); for (i = 0; i < gwlist_len(ips); ++i) { configured_ip = gwlist_get(ips, i); if (wildcarded_ip_found(configured_ip, needle, ip_sep)) goto found; } gwlist_destroy(ips, octstr_destroy_item); return 0; found: gwlist_destroy(ips, octstr_destroy_item); return 1; } /* * Returns smsc-id that pushes by this user must use, * NULL when there was an error. */ Octstr *wap_push_ppg_pushuser_smsc_id_get(Octstr *username) { WAPPushUser *u; Octstr *smsc_id; if ((u = user_find_by_username(username)) == NULL) { /* no user found with this username */ return NULL; } if ((smsc_id = forced_smsc(u)) != NULL) return octstr_duplicate(smsc_id); smsc_id = default_smsc(u); return octstr_duplicate(smsc_id); } /* * Returns default dlr url for this user. */ Octstr *wap_push_ppg_pushuser_dlr_url_get(Octstr *username) { WAPPushUser *u; Octstr *dlr_url; u = user_find_by_username(username); dlr_url = u->dlr_url; return octstr_duplicate(dlr_url); } /* * Returns default dlr smsbox id for this user. */ Octstr *wap_push_ppg_pushuser_smsbox_id_get(Octstr *username) { WAPPushUser *u; Octstr *smsbox_id; u = user_find_by_username(username); smsbox_id = u->smsbox_id; return octstr_duplicate(smsbox_id); } /*************************************************************************** * * Implementation of internal functions */ static void destroy_users_list(void *l) { gwlist_destroy(l, NULL); } static WAPPushUserList *pushusers_create(long number_of_users) { users = gw_malloc(sizeof(WAPPushUserList)); users->list = gwlist_create(); users->names = dict_create(number_of_users, destroy_users_list); return users; } /* * Allocate memory for one push user and read configuration data to it. We initial- * ize all fields to NULL, because the value NULL means that the configuration did * not have this variable. * Return NULL when failure, a pointer to the data structure otherwise. */ static WAPPushUser *create_oneuser(CfgGroup *grp) { WAPPushUser *u; Octstr *grpname, *os; grpname = cfg_get(grp, octstr_imm("wap-push-user")); if (grpname == NULL) { error(0, "all users group (wap-push-user) are missing"); goto no_grpname; } u = gw_malloc(sizeof(WAPPushUser)); u->name = NULL; u->username = NULL; u->allowed_prefix = NULL; u->allowed_prefix_regex = NULL; u->denied_prefix = NULL; u->denied_prefix_regex = NULL; u->white_list = NULL; u->white_list_regex = NULL; u->black_list = NULL; u->black_list_regex = NULL; u->user_deny_ip = NULL; u->user_allow_ip = NULL; u->smsc_id = NULL; u->default_smsc_id = NULL; u->name = cfg_get(grp, octstr_imm("wap-push-user")); if (u->name == NULL) { warning(0, "user name missing, dump follows"); oneuser_dump(u); goto error; } u->username = cfg_get(grp, octstr_imm("ppg-username")); u->password = cfg_get(grp, octstr_imm("ppg-password")); if (u->username == NULL) { warning(0, "login name for user %s missing, dump follows", octstr_get_cstr(u->name)); oneuser_dump(u); goto error; } if (u->password == NULL) { warning(0, "password for user %s missing, dump follows", octstr_get_cstr(u->name)); oneuser_dump(u); goto error; } u->user_deny_ip = cfg_get(grp, octstr_imm("deny-ip")); u->user_allow_ip = cfg_get(grp, octstr_imm("allow-ip")); u->country_prefix = cfg_get(grp, octstr_imm("country-prefix")); u->allowed_prefix = cfg_get(grp, octstr_imm("allowed-prefix")); u->denied_prefix = cfg_get(grp, octstr_imm("denied-prefix")); u->smsc_id = cfg_get(grp, octstr_imm("forced-smsc")); u->default_smsc_id = cfg_get(grp, octstr_imm("default-smsc")); u->dlr_url = cfg_get(grp, octstr_imm("dlr-url")); u->smsbox_id = cfg_get(grp, octstr_imm("smsbox-id")); os = cfg_get(grp, octstr_imm("white-list")); if (os != NULL) { u->white_list = numhash_create(octstr_get_cstr(os)); octstr_destroy(os); } os = cfg_get(grp, octstr_imm("black-list")); if (os != NULL) { u->black_list = numhash_create(octstr_get_cstr(os)); octstr_destroy(os); } if ((os = cfg_get(grp, octstr_imm("allowed-prefix-regex"))) != NULL) { if ((u->allowed_prefix_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); }; if ((os = cfg_get(grp, octstr_imm("denied-prefix-regex"))) != NULL) { if ((u->denied_prefix_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); }; if ((os = cfg_get(grp, octstr_imm("white-list-regex"))) != NULL) { if ((u->white_list_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); }; if ((os = cfg_get(grp, octstr_imm("black-list-regex"))) != NULL) { if ((u->black_list_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); }; octstr_destroy(grpname); return u; no_grpname: octstr_destroy(grpname); return NULL; error: octstr_destroy(grpname); destroy_oneuser(u); return NULL; } static void destroy_oneuser(void *p) { WAPPushUser *u; u = p; if (u == NULL) return; octstr_destroy(u->name); octstr_destroy(u->username); octstr_destroy(u->password); octstr_destroy(u->country_prefix); octstr_destroy(u->allowed_prefix); octstr_destroy(u->denied_prefix); numhash_destroy(u->white_list); numhash_destroy(u->black_list); octstr_destroy(u->user_deny_ip); octstr_destroy(u->user_allow_ip); octstr_destroy(u->smsc_id); octstr_destroy(u->default_smsc_id); if (u->black_list_regex != NULL) gw_regex_destroy(u->black_list_regex); if (u->white_list_regex != NULL) gw_regex_destroy(u->white_list_regex); if (u->denied_prefix_regex != NULL) gw_regex_destroy(u->denied_prefix_regex); if (u->allowed_prefix_regex != NULL) gw_regex_destroy(u->allowed_prefix_regex); gw_free(u); } static void oneuser_dump(WAPPushUser *u) { if (u == NULL) { debug("wap.push.ppg.pushuser", 0, "no user found"); return; } debug("wap.push.ppg.pushuser", 0, "Dumping user data: Name of the user:"); octstr_dump(u->name, 0); debug("wap.push.ppg.pushuser", 0, "username:"); octstr_dump(u->username, 0); debug("wap.push.ppg.pushuser", 0, "omitting password"); debug("wap-push.ppg.pushuser", 0, "country prefix"); octstr_dump(u->country_prefix, 0); debug("wap.push.ppg.pushuser", 0, "allowed prefix list:"); octstr_dump(u->allowed_prefix, 0); debug("wap.push.ppg.pushuser", 0, "denied prefix list:"); octstr_dump(u->denied_prefix, 0); debug("wap.push.ppg.pushuser", 0, "denied ip list:"); octstr_dump(u->user_deny_ip, 0); debug("wap.push.ppg.pushuser", 0, "allowed ip list:"); octstr_dump(u->user_allow_ip, 0); debug("wap.push.ppg.pushuser", 0, "send via smsc-id:"); octstr_dump(u->smsc_id, 0); debug("wap.push.ppg.pushuser", 0, "use default smsc:"); octstr_dump(u->default_smsc_id, 0); debug("wap.push.ppg.pushuser", 0, "end of the dump"); } /* * Add an user to the push users list */ static int oneuser_add(CfgGroup *grp) { WAPPushUser *u; List *list; u = create_oneuser(grp); if (u == NULL) return -1; gwlist_append(users->list, u); list = dict_get(users->names, u->username); if (list == NULL) { list = gwlist_create(); dict_put(users->names, u->username, list); } return 0; } static WAPPushUser *user_find_by_username(Octstr *username) { WAPPushUser *u; long i; List *list; if (username == NULL) return NULL; if ((list = dict_get(users->names, username)) == NULL) return NULL; for (i = 0; i < gwlist_len(users->list); ++i) { u = gwlist_get(users->list, i); if (octstr_compare(u->username, username) == 0) return u; } return NULL; } static int password_matches(WAPPushUser *u, Octstr *password) { if (password == NULL) return 0; return octstr_compare(u->password, password) == 0; } static int wildcarded_ip_found(Octstr *ip, Octstr *needle, Octstr *ip_sep) { List *ip_fragments, *needle_fragments; long i; Octstr *ip_fragment, *needle_fragment; ip_fragments = octstr_split(ip, ip_sep); needle_fragments = octstr_split(needle, ip_sep); gw_assert(gwlist_len(ip_fragments) == gwlist_len(needle_fragments)); for (i = 0; i < gwlist_len(ip_fragments); ++i) { ip_fragment = gwlist_get(ip_fragments, i); needle_fragment = gwlist_get(needle_fragments, i); if (octstr_compare(ip_fragment, needle_fragment) != 0 && octstr_compare(ip_fragment, octstr_imm("*")) != 0) goto not_found; } gwlist_destroy(ip_fragments, octstr_destroy_item); gwlist_destroy(needle_fragments, octstr_destroy_item); return 1; not_found: gwlist_destroy(ip_fragments, octstr_destroy_item); gwlist_destroy(needle_fragments, octstr_destroy_item); return 0; } /* * Deny_ip = '*.*.*.*' is here taken literally: no ips allowed by this user * (definitely strange, but not a fatal error). */ static int ip_allowed_by_user(WAPPushUser *u, Octstr *ip) { Octstr *copy, *ip_copy; if (u == NULL) { warning(0, "user not found from the users list"); goto no_user; } copy = octstr_duplicate(u->username); if (u->user_deny_ip == NULL && u->user_allow_ip == NULL) goto allowed; if (u->user_deny_ip) { if (octstr_compare(u->user_deny_ip, octstr_imm("*.*.*.*")) == 0) { warning(0, "no ips allowed for %s", octstr_get_cstr(copy)); goto denied; } } if (u->user_allow_ip) if (octstr_compare(u->user_allow_ip, octstr_imm("*.*.*.*")) == 0) goto allowed; if (u->user_deny_ip) { if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(u->user_deny_ip, ip, octstr_imm(";"), octstr_imm("."))) { goto denied; } } if (u->user_allow_ip) { if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(u->user_allow_ip, ip, octstr_imm(";"), octstr_imm("."))) { goto allowed; } } octstr_destroy(copy); warning(0, "ip not found from either ip list, deny it"); return 0; allowed: octstr_destroy(copy); return 1; denied: ip_copy = octstr_duplicate(ip); warning(0, "%s denied by user %s", octstr_get_cstr(ip_copy), octstr_get_cstr(copy)); octstr_destroy(copy); octstr_destroy(ip_copy); return 0; no_user: return 0; } /* * HTTP basic authentication server response is defined in rfc 2617, chapter 2. * Return 1, when we found username and password from headers, 0, when there were * no password and -1 when there were no username (or no Authorization header at * all, or an unparsable one). Username and password value 'NULL' means no user- * name or password supplied. */ static int response(List *push_headers, Octstr **username, Octstr **password) { Octstr *header_value, *basic; size_t basic_len; List *auth_list; *username = NULL; *password = NULL; if ((header_value = http_header_find_first(push_headers, "Authorization")) == NULL) goto no_response3; octstr_strip_blanks(header_value); basic = octstr_imm("Basic"); basic_len = octstr_len(basic); if (octstr_ncompare(header_value, basic, basic_len) != 0) goto no_response1; octstr_delete(header_value, 0, basic_len); octstr_strip_blanks(header_value); octstr_base64_to_binary(header_value); auth_list = octstr_split(header_value, octstr_imm(":")); if (gwlist_len(auth_list) != 2) goto no_response2; *username = octstr_duplicate(gwlist_get(auth_list, 0)); *password = octstr_duplicate(gwlist_get(auth_list, 1)); if (username == NULL) { goto no_response2; } if (password == NULL) { goto no_response4; } debug("wap.push.ppg.pushuser", 0, "we have an username and a password in" " authorization header"); gwlist_destroy(auth_list, octstr_destroy_item); octstr_destroy(header_value); return HEADER_AUTHENTICATION; no_response1: octstr_destroy(header_value); return NO_USERNAME; no_response2: gwlist_destroy(auth_list, octstr_destroy_item); octstr_destroy(header_value); return NO_USERNAME; no_response3: return NO_USERNAME; no_response4: gwlist_destroy(auth_list, octstr_destroy_item); octstr_destroy(header_value); return NO_PASSWORD; } /* * HTTP basic authentication server challenge is defined in rfc 2617, chapter 2. * Only WWW-Authenticate header is required here by specs. This function does not * release memory used by push headers, the caller must do this. */ static void challenge(HTTPClient *c, List *push_headers) { Octstr *challenge, *realm; int http_status; List *reply_headers; realm = octstr_format("%s", "Basic realm="); octstr_append(realm, get_official_name()); octstr_format_append(realm, "%s", "\"wappush\""); reply_headers = http_create_empty_headers(); http_header_add(reply_headers, "WWW-Authenticate", octstr_get_cstr(realm)); http_status = HTTP_UNAUTHORIZED; challenge = octstr_imm("You must show your credentials.\n"); http_send_reply(c, http_status, reply_headers, challenge); octstr_destroy(realm); http_destroy_headers(reply_headers); } /* * This function does not release memory used by push headers, the caller must do this. */ static void reply(HTTPClient *c, List *push_headers) { int http_status; Octstr *denied; List *reply_headers; reply_headers = http_create_empty_headers(); http_status = HTTP_FORBIDDEN; denied = octstr_imm("You are not allowed to use this service. Do not retry.\n"); http_send_reply(c, http_status, push_headers, denied); http_destroy_headers(reply_headers); } /* * Note that the phone number necessarily follows the international format (a requi- * rement by our pap compiler). So we add country prefix to listed prefixes, if one * is configured. */ static int prefix_allowed(WAPPushUser *u, Octstr *number) { List *allowed, *denied; long i; Octstr *listed_prefix; allowed = NULL; denied = NULL; if (u == NULL) goto no_user; if ( u->allowed_prefix == NULL && u->denied_prefix == NULL && u->allowed_prefix_regex == NULL && u->denied_prefix_regex == NULL) goto no_configuration; if (u->denied_prefix != NULL) { denied = octstr_split(u->denied_prefix, octstr_imm(";")); for (i = 0; i < gwlist_len(denied); ++i) { listed_prefix = gwlist_get(denied, i); if (u->country_prefix != NULL) octstr_insert(listed_prefix, u->country_prefix, 0); if (compare_octstr_sequence(number, listed_prefix, 0) == 0) { goto denied; } } } /* note: country-prefix _must_be included in the pattern */ if (u->denied_prefix_regex != NULL) if (gw_regex_match_pre(u->denied_prefix_regex, number) == 1) goto denied; if (u->allowed_prefix_regex == NULL && u->allowed_prefix == NULL) goto no_allowed_config; if (u->allowed_prefix != NULL) { allowed = octstr_split(u->allowed_prefix, octstr_imm(";")); for (i = 0; i < gwlist_len(allowed); ++i) { listed_prefix = gwlist_get(allowed, i); if (u->country_prefix != NULL) octstr_insert(listed_prefix, u->country_prefix, 0); if (compare_octstr_sequence(number, listed_prefix, 0) == 0) { goto allowed; } } } /* note: country-prefix _must_ be included in the pattern */ if (u->allowed_prefix_regex != NULL) if (gw_regex_match_pre(u->allowed_prefix_regex, number) == 1) goto allowed; /* * Here we have an intentional fall-through. It will removed when memory cleaning * functions are implemented. */ denied: gwlist_destroy(allowed, octstr_destroy_item); gwlist_destroy(denied, octstr_destroy_item); return 0; allowed: gwlist_destroy(allowed, octstr_destroy_item); gwlist_destroy(denied, octstr_destroy_item); return 1; no_configuration: return 1; no_user: return 0; no_allowed_config: gwlist_destroy(denied, octstr_destroy_item); return 1; } static int whitelisted(WAPPushUser *u, Octstr *number) { int result = 1; if (u->white_list != NULL) result = numhash_find_number(u->white_list, number); if ((result == 0) && (u->white_list_regex != NULL)) result = gw_regex_match_pre(u->white_list_regex, number); return result; } static int blacklisted(WAPPushUser *u, Octstr *number) { int result = 0; if (u->black_list != NULL) result = numhash_find_number(u->black_list, number); if ((result == 0) && (u->black_list_regex != NULL)) result = gw_regex_match_pre(u->black_list_regex, number); return result; } /* * 'NULL' means here 'no value found'. * Return 1 when we found username, 0 when we did not. */ static int parse_cgivars_for_username(List *cgivars, Octstr **username) { *username = NULL; *username = octstr_duplicate(http_cgi_variable(cgivars, "username")); if (*username == NULL) { return 0; } return 1; } static int parse_cgivars_for_password(List *cgivars, Octstr **password) { *password = NULL; *password = octstr_duplicate(http_cgi_variable(cgivars, "password")); if (*password == NULL) { return 0; } return 1; } /* * Compare an octet string os2 with a sequence of an octet string os1. The sequence * starts with a position start. */ static int compare_octstr_sequence(Octstr *os1, Octstr *os2, long start) { int ret; unsigned char *prefix; long end; if (octstr_len(os2) == 0) return 1; if (octstr_len(os1) == 0) return -1; prefix = NULL; if (start != 0) { prefix = gw_malloc(start); octstr_get_many_chars(prefix, os1, 0, start); octstr_delete(os1, 0, start); } end = start + octstr_len(os2); ret = octstr_ncompare(os1, os2, end - start); if (start != 0) { octstr_insert_data(os1, 0, prefix, start); gw_free(prefix); } return ret; } static Octstr *forced_smsc(WAPPushUser *u) { return u->smsc_id; } static Octstr *default_smsc(WAPPushUser *u) { return u->default_smsc_id; }