File: check.c

package info (click to toggle)
pam-geoip 2.1.1-8
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 164 kB
  • sloc: ansic: 498; makefile: 98
file content (97 lines) | stat: -rw-r--r-- 3,143 bytes parent folder | download | duplicates (3)
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
 */