1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
/*
* check.c - account module to check GeoIP information
*
* $Id$
*
*/
#include "pam_geoip.h"
int check_service(pam_handle_t *pamh, char *services, char *srv)
{
char *str, *next;
if (!strcmp(services, "*")) return 1;
str = services;
while (*services) {
while (*str && *str != ',') ++str;
if (*str) next = str + 1;
else next = "";
*str = 0;
if (!strncmp(services, srv, strlen(services)) || !strcmp(services, "*")) return 1;
services = next;
}
return 0;
}
/* see also: http://en.wikipedia.org/wiki/Great-circle_distance */
double calc_distance(double latitude, double longitude, double geo_lat, double geo_long)
{
double distance;
float earth = 6367.46; /* km avg radius */
/* convert grad to rad: */
double la1 = latitude * M_PI / 180.0,
la2 = geo_lat * M_PI / 180.0,
lo1 = longitude * M_PI / 180.0,
lo2 = geo_long * M_PI / 180.0;
distance = atan2(sqrt(
pow(cos(la2) * sin(lo1-lo2), 2.0) +
pow(cos(la1) * sin(la2) - sin(la1) * cos(la2) * cos(lo1-lo2), 2.0)
),
sin(la1) * sin(la2) + cos(la1) * cos(la2) * cos(lo1-lo2)
);
if (distance < 0.0) distance += 2 * M_PI;
distance *= earth;
return distance;
}
int check_location(pam_handle_t *pamh, struct options *opts, char *location_string, struct locations *geo)
{
int retval = 0;
double distance;
struct locations *list, *loc;
list = loc = parse_locations(pamh, opts, location_string);
while (list) {
if (!list->country) {
if (!strcmp(geo->country, "UNKNOWN")) {
list = list->next;
continue;
}
if (opts->is_city_db) {
distance = calc_distance(list->latitude, list->longitude, geo->latitude, geo->longitude);
if (distance <= list->radius) {
pam_syslog(pamh, LOG_INFO, "distance(%.3f) < radius(%3.f)", distance, list->radius);
sprintf(location_string, "%.3f {%f,%f}", distance, geo->latitude, geo->longitude);
retval = 1;
break;
}
}
else pam_syslog(pamh, LOG_INFO, "not a city db edition, ignoring distance entry");
}
else {
if (opts->debug) pam_syslog(pamh, LOG_INFO, "location: (%s,%s) geoip: (%s,%s)", list->country, list->city, geo->country, geo->city);
if ((list->country[0] == '*' || !strcmp(list->country, geo->country)) &&
(list->city[0] == '*' || !strcmp(list->city, geo->city))
) {
if (opts->debug) pam_syslog(pamh, LOG_INFO, "location [%s,%s] matched: %s,%s", geo->country, geo->city, list->country, list->city);
sprintf(location_string, "%s,%s", geo->country, geo->city);
retval = 1;
break;
}
}
list = list->next;
}
if (loc) free_locations(loc);
return retval;
}
/*
* vim: ts=4 sw=4 expandtab
*/
|