wap_push_ppg_pushuser.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:24k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * wap_push_ppg_pushuser.c: Implementation of wap_push_ppg_pushuser.h header.
  3.  *
  4.  * By Aarno Syv鋘en for Wiral Ltd and Global Networks Inc.
  5.  */
  6. #include "wap_push_ppg_pushuser.h"
  7. #include "numhash.h"
  8. /***************************************************************************
  9.  *
  10.  * Global data structures
  11.  *
  12.  * Hold authentication data for one ppg user
  13.  */
  14. struct WAPPushUser {
  15.     Octstr *name;                      /* the name of the user */
  16.     Octstr *username;                  /* the username of this ppg user */
  17.     Octstr *password;                  /* and password */
  18.     Octstr *country_prefix;
  19.     Octstr *allowed_prefix;            /* phone number prefixes allowed by 
  20.                                           this user when pushing*/
  21.     Octstr *denied_prefix;             /* and denied ones */
  22.     Numhash *white_list;               /* phone numbers of this user, used for 
  23.                                           push*/
  24.     Numhash *black_list;               /* numbers should not be used for push*/
  25.     Octstr *user_deny_ip;              /* this user allows pushes from these 
  26.                                           IPs*/
  27.     Octstr *user_allow_ip;             /* and denies them from these*/
  28. };
  29. typedef struct WAPPushUser WAPPushUser;
  30. /*
  31.  * Hold authentication data of all ppg users
  32.  */
  33. struct WAPPushUserList {
  34.     List *list;
  35.     Dict *names;
  36. }; 
  37. typedef struct WAPPushUserList WAPPushUserList; 
  38. static WAPPushUserList *users = NULL;
  39. /*
  40.  * This hash table stores time when a specific ip is allowed to try next time.
  41.  */
  42. static Dict *next_try = NULL;
  43. /***********************************************************************************
  44.  *
  45.  * Prototypes of internal functions
  46.  */
  47. static void destroy_users_list(void *l);
  48. static WAPPushUserList *pushusers_create(long number_of_users);
  49. static WAPPushUser *create_oneuser(CfgGroup *grp);
  50. static void destroy_oneuser(void *p);
  51. static int oneuser_add(CfgGroup *cfg);
  52. static void oneuser_dump(WAPPushUser *u);
  53. static WAPPushUser *user_find_by_username(Octstr *username);
  54. static int password_matches(WAPPushUser *u, Octstr *password);
  55. static int ip_allowed_by_user(WAPPushUser *u, Octstr *ip);
  56. static int prefix_allowed(WAPPushUser *u, Octstr *number);
  57. static int whitelisted(WAPPushUser *u, Octstr *number);
  58. static int blacklisted(WAPPushUser *u, Octstr *number);
  59. static int wildcarded_ip_found(Octstr *ip, Octstr *needle, Octstr *ip_sep);
  60. static int response(List *push_headers, Octstr **username, Octstr **password);
  61. static void challenge(HTTPClient *c, List *push_headers);
  62. static void reply(HTTPClient *c, List *push_headers);
  63. static int parse_cgivars_for_username(List *cgivars, Octstr **username);
  64. static int parse_cgivars_for_password(List *cgivars, Octstr **password);
  65. static int compare_octstr_sequence(Octstr *os1, Octstr *os2, long start);
  66. /****************************************************************************
  67.  *
  68.  * Implementation of external functions
  69.  */
  70. /*
  71.  * Initialize the whole module and fill the push users list.
  72.  */
  73. int wap_push_ppg_pushuser_list_add(List *list, long number_of_pushes, 
  74.                                    long number_of_users)
  75. {
  76.     CfgGroup *grp;
  77.     next_try = dict_create(number_of_pushes, octstr_destroy_item);
  78.     users = pushusers_create(number_of_users);
  79.     gw_assert(list);
  80.     while (list && (grp = list_extract_first(list))) {
  81.         if (oneuser_add(grp) == -1) {
  82.         list_destroy(list, NULL);
  83.             return 0;
  84.         }
  85.     }
  86.     list_destroy(list, NULL);
  87.     return 1;
  88. }
  89. void wap_push_ppg_pushuser_list_destroy(void)
  90. {
  91.     dict_destroy(next_try);
  92.     if (users == NULL)
  93.         return;
  94.     list_destroy(users->list, destroy_oneuser);
  95.     dict_destroy(users->names);
  96.     gw_free(users);
  97. }
  98. enum {
  99.     NO_USERNAME = -1,
  100.     NO_PASSWORD = 0,
  101.     HEADER_AUTHENTICATION = 1
  102. };
  103. #define ADDITION  0.1
  104. /*
  105.  * This function does authentication possible before compiling the control 
  106.  * document. This means:
  107.  *           a) password authentication by url or by headers (it is, by basic
  108.  *              authentication response, see rfc 2617, chapter 2) 
  109.  *           b) if this does not work, basic authentication by challenge - 
  110.  *              response 
  111.  *           c) enforcing various ip lists
  112.  *
  113.  * Check does ppg allows a connection from this at all, then try to find username 
  114.  * and password from headers, then from url. If both fails, try basic authentica-
  115.  * tion. Then check does this user allow a push from this ip, then check the pass-
  116.  * word.
  117.  *
  118.  * For protection against brute force and partial protection for denial of serv-
  119.  * ice attacks, an exponential backup algorithm is used. Time when a specific ip  
  120.  * is allowed to reconnect, is stored in Dict next_try. If an ip tries to recon-
  121.  * nect before this (three attemps are allowed, then exponential seconds are add-
  122.  * ed to the limit) we make a new challenge. We do the corresponding check before
  123.  * testing passwords; after all, it is an authorization failure that causes a new
  124.  * challenge. 
  125.  *
  126.  * Rfc 2617, chapter 1 states that if we do not accept credentials of an user's, 
  127.  * we must send a new challenge to the user.
  128.  *
  129.  * Output an authenticated username.
  130.  * This function should be called only when there are a push users list; the 
  131.  * caller is responsible for this.
  132.  */
  133. int wap_push_ppg_pushuser_authenticate(HTTPClient *c, List *cgivars, Octstr *ip, 
  134.                                        List *push_headers, Octstr **username) {
  135.         time_t now;
  136.         static long next = 0L;            /* used only in this thread (and this 
  137.                                              function) */
  138.         long next_time;
  139.         Octstr *next_time_os;
  140.         static long multiplier = 1L;      /* ditto */
  141.         WAPPushUser *u;
  142.         Octstr *copy,
  143.                *password;
  144.         int ret;
  145.         
  146.         copy = octstr_duplicate(ip);
  147.         time(&now);
  148.         next_time_os = NULL;
  149.         if ((ret = response(push_headers, username, &password)) == NO_USERNAME) { 
  150.             if (!parse_cgivars_for_username(cgivars, username)) {
  151.                 error(0, "no user specified, challenging regardless");
  152.             goto listed;
  153.             }
  154.         }
  155.         if (password == NULL)
  156.             parse_cgivars_for_password(cgivars, &password);
  157.         u = user_find_by_username(*username);
  158.         if (!ip_allowed_by_user(u, ip)) {
  159.         goto not_listed;
  160.         }
  161.         next = 0;       
  162.         if ((next_time_os = dict_get(next_try, ip)) != NULL) {
  163.         octstr_parse_long(&next_time, next_time_os, 0, 10);
  164.             if (difftime(now, (time_t) next_time) < 0) {
  165.             error(0, "another try from %s, not much time used", 
  166.                       octstr_get_cstr(copy));
  167.             goto listed;
  168.             }
  169.         }
  170.         if (u == NULL) {
  171.         error(0, "user %s is not allowed by users list, challenging",
  172.                   octstr_get_cstr(*username));
  173.         goto listed;
  174.         }
  175.         if (!password_matches(u, password)) {
  176.         error(0, "wrong or missing password in request from %s, challenging" , 
  177.                   octstr_get_cstr(copy));
  178.             goto listed;
  179.         }
  180.         dict_remove(next_try, ip);       /* no restrictions after authentica-
  181.                                             tion */
  182.         octstr_destroy(password);
  183.         octstr_destroy(copy);
  184.         octstr_destroy(next_time_os);
  185.         return 1;
  186. not_listed:
  187.         octstr_destroy(password);
  188.         octstr_destroy(copy); 
  189.         reply(c, push_headers);
  190.         octstr_destroy(next_time_os);
  191.         return 0;
  192. listed:
  193.         challenge(c, push_headers);
  194.         multiplier <<= 1;
  195.         next = next + multiplier * ADDITION;
  196.         next += now;
  197.         next_time_os = octstr_format("%ld", next);
  198.         dict_put(next_try, ip, next_time_os);
  199.         
  200.         octstr_destroy(copy);
  201.         octstr_destroy(password);
  202.         
  203.         return 0;
  204. }
  205. /*
  206.  * This function checks phone number for allowed prefixes, black lists and white
  207.  * lists. Note that the phone number necessarily follows the international format 
  208.  * (a requirement by our pap compiler).
  209.  */
  210. int wap_push_ppg_pushuser_client_phone_number_acceptable(Octstr *username, 
  211.         Octstr *number)
  212. {
  213.     WAPPushUser *u;
  214.     u = user_find_by_username(username);
  215.     if (!prefix_allowed(u, number)) {
  216.         error(0, "Number %s not allowed by user %s (wrong prefix)", 
  217.               octstr_get_cstr(number), octstr_get_cstr(username));
  218.         return 0;
  219.     }
  220.     if (blacklisted(u, number)) {
  221.         error(0, "Number %s not allowed by user %s (blacklisted)", 
  222.               octstr_get_cstr(number), octstr_get_cstr(username) );
  223.         return 0;
  224.     }
  225.     if (!whitelisted(u, number)) {
  226.         error(0, "Number %s not allowed by user %s (not whitelisted)", 
  227.               octstr_get_cstr(number), octstr_get_cstr(username) );
  228.         return 0;
  229.     }
  230.     return 1;
  231. }
  232. int wap_push_ppg_pushuser_search_ip_from_wildcarded_list(Octstr *haystack, 
  233.         Octstr *needle, Octstr *list_sep, Octstr *ip_sep)
  234. {
  235.     List *ips;
  236.     long i;
  237.     Octstr *configured_ip;
  238.     gw_assert(haystack);
  239.     gw_assert(list_sep);
  240.     gw_assert(ip_sep);
  241.     /*There are no wildcards in the list*/    
  242.     if (octstr_search_char(haystack, '*', 0) < 0) {
  243.         if (octstr_search(haystack, needle, 0) >= 0) {
  244.         return 1;
  245.         } else { 
  246.         return 0;
  247.         }
  248.     }
  249.     
  250.     /*There are wildcards in the list*/
  251.     configured_ip = NULL;
  252.     ips = octstr_split(haystack, list_sep);
  253.     for (i = 0; i < list_len(ips); ++i) {
  254.         configured_ip = list_get(ips, i);
  255.         if (wildcarded_ip_found(configured_ip, needle, ip_sep))
  256.         goto found;
  257.     }
  258.     list_destroy(ips, octstr_destroy_item);
  259.     return 0;
  260. found:
  261.     list_destroy(ips, octstr_destroy_item);
  262.     return 1;
  263. }
  264. /***************************************************************************
  265.  *
  266.  * Implementation of internal functions
  267.  */
  268. static void destroy_users_list(void *l)
  269. {
  270.     list_destroy(l, NULL);
  271. }
  272. static WAPPushUserList *pushusers_create(long number_of_users) 
  273. {
  274.     users = gw_malloc(sizeof(WAPPushUserList));
  275.     users->list = list_create();
  276.     users->names = dict_create(number_of_users, destroy_users_list);
  277.     return users;
  278. }
  279. /*
  280.  * Allocate memory for one push user and read configuration data to it. We initial-
  281.  * ize all fields to NULL, because the value NULL means that the configuration did
  282.  * not have this variable. 
  283.  * Return NULL when failure, a pointer to the data structure otherwise.
  284.  */
  285. static WAPPushUser *create_oneuser(CfgGroup *grp)
  286. {
  287.     WAPPushUser *u;
  288.     Octstr *grpname,
  289.            *os;
  290.     grpname = cfg_get(grp, octstr_imm("wap-push-user"));
  291.     if (grpname == NULL) {
  292.         error(0, "all users group (wap-push-user) are missing");
  293.         goto no_grpname;
  294.     }
  295.    
  296.     u = gw_malloc(sizeof(WAPPushUser));
  297.     u->name = NULL;
  298.     u->username = NULL;                  
  299.     u->allowed_prefix = NULL;           
  300.     u->denied_prefix = NULL;             
  301.     u->white_list = NULL;               
  302.     u->black_list = NULL;              
  303.     u->user_deny_ip = NULL;              
  304.     u->user_allow_ip = NULL;
  305.     u->name = cfg_get(grp, octstr_imm("wap-push-user"));
  306.     if (u->name == NULL) {
  307.         warning(0, "user name missing, dump follows");
  308.         oneuser_dump(u);
  309.         goto error;
  310.     }
  311.     u->username = cfg_get(grp, octstr_imm("ppg-username"));
  312.     u->password = cfg_get(grp, octstr_imm("ppg-password"));
  313.     if (u->username == NULL) {
  314.         warning(0, "login name for user %s missing, dump follows", 
  315.               octstr_get_cstr(u->name));
  316.         oneuser_dump(u);
  317.         goto error;
  318.     }
  319.     if (u->password == NULL) {
  320.         warning(0, "password for user %s missing, dump follows", 
  321.               octstr_get_cstr(u->name));
  322.         oneuser_dump(u);
  323.         goto error;
  324.     }
  325.     u->user_deny_ip = cfg_get(grp, octstr_imm("deny-ip"));
  326.     u->user_allow_ip = cfg_get(grp, octstr_imm("allow-ip"));
  327.     u->country_prefix = cfg_get(grp, octstr_imm("country-prefix"));
  328.     u->allowed_prefix = cfg_get(grp, octstr_imm("allowed-prefix"));
  329.     u->denied_prefix = cfg_get(grp, octstr_imm("denied-prefix"));
  330.     os = cfg_get(grp, octstr_imm("white-list"));
  331.     if (os != NULL) {
  332.     u->white_list = numhash_create(octstr_get_cstr(os));
  333.     octstr_destroy(os);
  334.     }
  335.     os = cfg_get(grp, octstr_imm("black-list"));
  336.     if (os != NULL) {
  337.     u->black_list = numhash_create(octstr_get_cstr(os));
  338.     octstr_destroy(os);
  339.     }
  340.     octstr_destroy(grpname);
  341.     return u;
  342. no_grpname:
  343.     octstr_destroy(grpname);
  344.     return NULL;
  345. error:
  346.     octstr_destroy(grpname);
  347.     destroy_oneuser(u);
  348.     return NULL;
  349. }
  350. static void destroy_oneuser(void *p) 
  351. {
  352.      WAPPushUser *u;
  353.      u = p;
  354.      if (u == NULL)
  355.          return;
  356.      octstr_destroy(u->name);
  357.      octstr_destroy(u->username);  
  358.      octstr_destroy(u->password);  
  359.      octstr_destroy(u->country_prefix);              
  360.      octstr_destroy(u->allowed_prefix);           
  361.      octstr_destroy(u->denied_prefix);             
  362.      numhash_destroy(u->white_list);               
  363.      numhash_destroy(u->black_list);              
  364.      octstr_destroy(u->user_deny_ip);              
  365.      octstr_destroy(u->user_allow_ip);
  366.      gw_free(u);             
  367. }
  368. static void oneuser_dump(WAPPushUser *u)
  369. {
  370.     if (u == NULL) {
  371.         debug("wap.push.ppg.pushuser", 0, "no user found");
  372.         return;
  373.     }
  374.     debug("wap.push.ppg.pushuser", 0, "Dumping user data: Name of the user:");
  375.     octstr_dump(u->name, 0);
  376.     debug("wap.push.ppg.pushuser", 0, "username:");
  377.     octstr_dump(u->username, 0);  
  378.     debug("wap.push.ppg.pushuser", 0, "omitting password");
  379.     debug("wap-push.ppg.pushuser", 0, "country prefix");
  380.     octstr_dump(u->country_prefix, 0);   
  381.     debug("wap.push.ppg.pushuser", 0, "allowed prefix list:");            
  382.     octstr_dump(u->allowed_prefix, 0);  
  383.     debug("wap.push.ppg.pushuser", 0, "denied prefix list:");         
  384.     octstr_dump(u->denied_prefix, 0);   
  385.     debug("wap.push.ppg.pushuser", 0, "denied ip list:");                         
  386.     octstr_dump(u->user_deny_ip, 0);    
  387.     debug("wap.push.ppg.pushuser", 0, "allowed ip list:");                   
  388.     octstr_dump(u->user_allow_ip, 0);
  389.     debug("wap.push.ppg.pushuser", 0, "end of the dump");
  390. }
  391. /*
  392.  * Add an user to the push users list
  393.  */
  394. static int oneuser_add(CfgGroup *grp)
  395. {
  396.     WAPPushUser *u;
  397.     List *list;
  398.     u = create_oneuser(grp);
  399.     if (u == NULL)
  400.         return -1;
  401.     list_append(users->list, u);
  402.     list = dict_get(users->names, u->username);
  403.     if (list == NULL) {
  404.         list = list_create();
  405.         dict_put(users->names, u->username, list);
  406.     }
  407.     return 0;
  408. }
  409. static WAPPushUser *user_find_by_username(Octstr *username)
  410. {
  411.     WAPPushUser *u;
  412.     long i;
  413.     List *list;
  414.     if (username == NULL)
  415.         return NULL;
  416.     if ((list = dict_get(users->names, username)) == NULL)
  417.          return NULL;
  418.     for (i = 0; i < list_len(users->list); ++i) {
  419.          u = list_get(users->list, i);
  420.          if (octstr_compare(u->username, username) == 0)
  421.          return u;
  422.     }
  423.     return NULL;
  424. }
  425. static int password_matches(WAPPushUser *u, Octstr *password)
  426. {
  427.     if (password == NULL)
  428.         return 0;    
  429.     return octstr_compare(u->password, password) == 0;
  430. }
  431. static int wildcarded_ip_found(Octstr *ip, Octstr *needle, Octstr *ip_sep)
  432. {
  433.     List *ip_fragments,
  434.          *needle_fragments;
  435.     long i;
  436.     Octstr *ip_fragment,
  437.            *needle_fragment;
  438.     ip_fragments = octstr_split(ip, ip_sep);
  439.     needle_fragments = octstr_split(needle, ip_sep);
  440.     gw_assert(list_len(ip_fragments) == list_len(needle_fragments));
  441.     for (i = 0; i < list_len(ip_fragments); ++i) {
  442.         ip_fragment = list_get(ip_fragments, i);
  443.         needle_fragment = list_get(needle_fragments, i);
  444.         if (octstr_compare(ip_fragment, needle_fragment) != 0 && 
  445.                 octstr_compare(ip_fragment, octstr_imm("*")) != 0)
  446.           goto not_found;
  447.     }
  448.     list_destroy(ip_fragments, octstr_destroy_item);
  449.     list_destroy(needle_fragments, octstr_destroy_item);   
  450.     return 1;
  451. not_found:
  452.     list_destroy(ip_fragments, octstr_destroy_item);
  453.     list_destroy(needle_fragments, octstr_destroy_item);
  454.     return 0;
  455. }
  456. /*
  457.  * Deny_ip = '*.*.*.*' is here taken literally: no ips allowed by this user 
  458.  * (definitely strange, but not a fatal error). 
  459.  */
  460. static int ip_allowed_by_user(WAPPushUser *u, Octstr *ip)
  461. {
  462.     Octstr *copy,
  463.            *ip_copy;
  464.     
  465.     if (u == NULL) {
  466.         warning(0, "user not found from the users list");
  467.         goto no_user;
  468.     }
  469.     copy = octstr_duplicate(u->username);
  470.     if (u->user_deny_ip == NULL && u->user_allow_ip == NULL)
  471.         goto allowed;
  472.     if (u->user_deny_ip) {
  473.         if (octstr_compare(u->user_deny_ip, octstr_imm("*.*.*.*")) == 0) {
  474.             warning(0, "no ips allowed for %s", octstr_get_cstr(copy));
  475.             goto denied;
  476.         }
  477.     }
  478.     if (u->user_allow_ip)
  479.         if (octstr_compare(u->user_allow_ip, octstr_imm("*.*.*.*")) == 0)
  480.             goto allowed;
  481.     if (u->user_deny_ip) {
  482.         if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(u->user_deny_ip, 
  483.             ip, octstr_imm(";"), octstr_imm("."))) {
  484.             goto denied;
  485.         }
  486.     }
  487.     if (u->user_allow_ip) {
  488.         if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(u->user_allow_ip, 
  489.             ip, octstr_imm(";"), octstr_imm("."))) {
  490.             goto allowed;
  491.         }
  492.     }
  493.     octstr_destroy(copy);
  494.     warning(0, "ip not found from either ip list, deny it");
  495.     return 0;
  496. allowed:
  497.     octstr_destroy(copy);
  498.     return 1;
  499. denied:
  500.     ip_copy = octstr_duplicate(ip);
  501.     warning(0, "%s denied by user %s", octstr_get_cstr(ip_copy), 
  502.             octstr_get_cstr(copy));
  503.     octstr_destroy(copy);
  504.     octstr_destroy(ip_copy);
  505.     return 0;
  506. no_user:
  507.     return 0;
  508. }
  509. /*
  510.  * HTTP basic authentication server response is defined in rfc 2617, chapter 2.
  511.  * Return 1, when we found username and password from headers, 0, when there were 
  512.  * no password and -1 when there were no username (or no Authorization header at 
  513.  * all, or an unparsable one). Username and password value 'NULL' means no user-
  514.  * name or password supplied.
  515.  */
  516. static int response(List *push_headers, Octstr **username, Octstr **password)
  517. {
  518.     Octstr *header_value,
  519.            *basic;
  520.     size_t basic_len;
  521.     List *auth_list;
  522.     *username = NULL;
  523.     *password = NULL;
  524.     if ((header_value = http_header_find_first(push_headers, 
  525.             "Authorization")) == NULL)
  526.         goto no_response3; 
  527.     octstr_strip_blanks(header_value);
  528.     basic = octstr_imm("Basic");
  529.     basic_len = octstr_len(basic);
  530.     if (octstr_ncompare(header_value, basic, basic_len) != 0)
  531.         goto no_response1;
  532.     octstr_delete(header_value, 0, basic_len);
  533.     octstr_strip_blanks(header_value);
  534.     octstr_base64_to_binary(header_value);
  535.     auth_list = octstr_split(header_value, octstr_imm(":"));
  536.     if (list_len(auth_list) != 2)
  537.         goto no_response2;
  538.     
  539.     *username = octstr_duplicate(list_get(auth_list, 0));
  540.     *password = octstr_duplicate(list_get(auth_list, 1));
  541.     if (username == NULL) {
  542.         goto no_response2;
  543.     }
  544.     if (password == NULL) {
  545.         goto no_response4;
  546.     }
  547.     debug("wap.push.ppg.pushuser", 0, "we have an username and a password in" 
  548.           " authorization header");
  549.     list_destroy(auth_list, octstr_destroy_item);
  550.     octstr_destroy(header_value);
  551.     return HEADER_AUTHENTICATION;
  552. no_response1:
  553.     octstr_destroy(header_value);
  554.     return NO_USERNAME;
  555. no_response2:   
  556.     list_destroy(auth_list, octstr_destroy_item);
  557.     octstr_destroy(header_value);
  558.     return NO_USERNAME;
  559. no_response3:
  560.     return NO_USERNAME;
  561. no_response4:   
  562.     list_destroy(auth_list, octstr_destroy_item);
  563.     octstr_destroy(header_value);
  564.     return NO_PASSWORD;
  565. }
  566. /*
  567.  * HTTP basic authentication server challenge is defined in rfc 2617, chapter 2. 
  568.  * Only WWW-Authenticate header is required here by specs. This function does not
  569.  * release memory used by push headers, the caller must do this.
  570.  */
  571. static void challenge(HTTPClient *c, List *push_headers)
  572. {
  573.     Octstr *challenge,
  574.            *realm;
  575.     int http_status;
  576.     List *reply_headers;
  577.     realm = octstr_format("%s", "Basic realm=");
  578.     octstr_append(realm, get_official_name());
  579.     octstr_format_append(realm, "%s", ""wappush"");
  580.     reply_headers = http_create_empty_headers();
  581.     http_header_add(reply_headers, "WWW-Authenticate", octstr_get_cstr(realm));
  582.     http_status = HTTP_UNAUTHORIZED;
  583.     challenge = octstr_imm("You must show your credentials.n");
  584.     
  585.     http_send_reply(c, http_status, reply_headers, challenge);
  586.     octstr_destroy(realm);
  587.     http_destroy_headers(reply_headers);
  588. }
  589. /*
  590.  * This function does not release memory used by push headers, the caller must do this.
  591.  */
  592. static void reply(HTTPClient *c, List *push_headers)
  593. {
  594.     int http_status;
  595.     Octstr *denied;
  596.     List *reply_headers;
  597.     reply_headers = http_create_empty_headers();
  598.     http_status = HTTP_FORBIDDEN;
  599.     denied = octstr_imm("You are not allowed to use this service. Do not retry.n");
  600.  
  601.     http_send_reply(c, http_status, push_headers, denied);
  602.     http_destroy_headers(reply_headers);
  603. }
  604. /*
  605.  * Note that the phone number necessarily follows the international format (a requi-
  606.  * rement by our pap compiler). So we add country prefix to listed prefixes, if one
  607.  * is configured.
  608.  */
  609. static int prefix_allowed(WAPPushUser *u, Octstr *number)
  610. {
  611.     List *allowed,
  612.          *denied;
  613.     long i;
  614.     Octstr *listed_prefix;
  615.     allowed = NULL;
  616.     denied = NULL;
  617.     if (u == NULL)
  618.         goto no_user;
  619.     if (u->allowed_prefix == NULL && u->denied_prefix == NULL)
  620.         goto no_configuration;
  621.     if (u->denied_prefix != NULL) {
  622.         denied = octstr_split(u->denied_prefix, octstr_imm(";"));
  623.         for (i = 0; i < list_len(denied); ++i) {
  624.              listed_prefix = list_get(denied, i);
  625.              if (u->country_prefix != NULL)
  626.                  octstr_insert(listed_prefix, u->country_prefix, 0);
  627.              if (compare_octstr_sequence(number, listed_prefix, 
  628.                      0) == 0) {
  629.                 goto denied;
  630.              }
  631.         }
  632.     }
  633.     if (u->allowed_prefix == NULL) {
  634.         goto no_allowed_config;
  635.     }
  636.     allowed = octstr_split(u->allowed_prefix, octstr_imm(";"));
  637.     for (i = 0; i < list_len(allowed); ++i) {
  638.          listed_prefix = list_get(allowed, i);
  639.          if (u->country_prefix != NULL)
  640.              octstr_insert(listed_prefix, u->country_prefix, 0);
  641.          if (compare_octstr_sequence(number, listed_prefix, 
  642.                  0) == 0) {
  643.          goto allowed;
  644.          }
  645.     }
  646. /*
  647.  * Here we have an intentional fall-through. It will removed when memory cleaning
  648.  * functions are implemented.
  649.  */
  650. denied:         
  651.     list_destroy(allowed, octstr_destroy_item);
  652.     list_destroy(denied, octstr_destroy_item);
  653.     return 0;
  654. allowed:      
  655.     list_destroy(allowed, octstr_destroy_item);
  656.     list_destroy(denied, octstr_destroy_item);
  657.     return 1;
  658. no_configuration:
  659.     return 1;
  660. no_user:
  661.     return 0;
  662. no_allowed_config:
  663.     list_destroy(denied, octstr_destroy_item);
  664.     return 1;
  665. }
  666. static int whitelisted(WAPPushUser *u, Octstr *number)
  667. {
  668.     if (u->white_list == NULL)
  669.         return 1;
  670.     return numhash_find_number(u->white_list, number);
  671. }
  672. static int blacklisted(WAPPushUser *u, Octstr *number)
  673. {
  674.     if (u->black_list == NULL)
  675.         return 0;
  676.     return numhash_find_number(u->black_list, number);
  677. }
  678. /* 
  679.  * 'NULL' means here 'no value found'.
  680.  * Return 1 when we found username, 0 when we did not.
  681.  */
  682. static int parse_cgivars_for_username(List *cgivars, Octstr **username)
  683. {
  684.     *username = NULL;
  685.     *username = octstr_duplicate(http_cgi_variable(cgivars, "username"));
  686.     if (*username == NULL) {
  687.         return 0;
  688.     }
  689.     return 1;
  690. }
  691. static int parse_cgivars_for_password(List *cgivars, Octstr **password)
  692. {
  693.     *password = NULL;
  694.     *password = octstr_duplicate(http_cgi_variable(cgivars, "password"));
  695.     if (*password == NULL) {
  696.         return 0;
  697.     }
  698.     return 1;
  699. }
  700. /*
  701.  * Compare an octet string os2 with a sequence of an octet string os1. The sequence
  702.  * starts with a position start. 
  703.  */
  704. static int compare_octstr_sequence(Octstr *os1, Octstr *os2, long start)
  705. {
  706.     int ret;
  707.     unsigned char *prefix;
  708.     long end;
  709.     if (octstr_len(os2) == 0)
  710.         return 1;
  711.     if (octstr_len(os1) == 0)
  712.         return -1;
  713.     prefix = NULL;
  714.     if (start != 0) {
  715.         prefix = gw_malloc(start);
  716.         octstr_get_many_chars(prefix, os1, 0, start);
  717.         octstr_delete(os1, 0, start);
  718.     }
  719.     
  720.     end = start + octstr_len(os2);
  721.     ret = octstr_ncompare(os1, os2, end - start);
  722.     
  723.     if (start != 0) {
  724.         octstr_insert_data(os1, 0, prefix, start);
  725.         gw_free(prefix);
  726.     }
  727.     return ret;
  728. }