New Helsinki University Module. By Ere Maijala
authorAdam Dickmeiss <adam@indexdata.dk>
Sat, 25 Mar 2006 10:56:28 +0000 (10:56 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Sat, 25 Mar 2006 10:56:28 +0000 (10:56 +0000)
src/Makefile.am
src/mod_helsinki.cpp [new file with mode: 0644]

index 9f712f5..d117d71 100644 (file)
@@ -1,4 +1,4 @@
-## $Id: Makefile.am,v 1.11 2005-10-27 22:38:03 adam Exp $
+## $Id: Makefile.am,v 1.12 2006-03-25 10:56:28 adam Exp $
 
 AM_CXXFLAGS = $(YAZPPINC) -I$(srcdir)/../include $(XSLT_CFLAGS) $(USEMARCONINC)
 
@@ -27,4 +27,8 @@ libyazproxy_la_LIBADD = $(XSLT_LIBS)
 mod_proxy_sample_la_SOURCES = mod_sample.cpp
 mod_proxy_sample_la_LDFLAGS = -rpath $(pkglibdir) -module -avoid-version
 
-pkglib_LTLIBRARIES = mod_proxy_sample.la
+mod_proxy_helsinki_la_SOURCES = mod_helsinki.cpp
+mod_proxy_helsinki_la_LDFLAGS = -rpath $(pkglibdir) -module -avoid-version
+
+pkglib_LTLIBRARIES = mod_proxy_sample.la mod_proxy_helsinki.la
+
diff --git a/src/mod_helsinki.cpp b/src/mod_helsinki.cpp
new file mode 100644 (file)
index 0000000..5558c87
--- /dev/null
@@ -0,0 +1,266 @@
+/* $Id: mod_helsinki.cpp,v 1.1 2006-03-25 10:56:28 adam Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <yazproxy/module.h>
+
+#include <yaz/log.h>
+
+#include <time.h>
+
+#if HAVE_XSLT
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xinclude.h>
+#include <libxslt/xsltutils.h>
+#include <libxslt/transform.h>
+#endif
+
+struct IP_ADDRESS
+{
+    unsigned int a1, a2, a3, a4;
+};
+
+void *my_init(void)
+{
+    return 0;  // no private data for handler
+}
+
+void my_destroy(void *p)
+{
+    // private data destroy
+}
+
+void zero_address(IP_ADDRESS *addr)
+{
+    addr->a1 = addr->a2 = addr->a3 = addr->a4 = 0;
+}
+
+int str_to_address(const char *str, IP_ADDRESS *addr)
+{
+    zero_address(addr);
+    return sscanf(str, "%3u.%3u.%3u.%3u", &addr->a1, &addr->a2, &addr->a3, &addr->a4);
+}
+
+void str_to_address_range(const char *str,
+                          IP_ADDRESS *range_lo,
+                          IP_ADDRESS *range_hi)
+{
+    char lo[16], hi[16];
+    *lo = '\0';
+    *hi = '\0';
+    int num = sscanf(str, "%15[^-]-%15s", lo, hi);
+
+    if (num == 1)
+    {
+        // Create a range from a single address or a part of it (e.g. 192.168)
+        num = str_to_address(lo, range_lo);
+        if (num == 1)
+        {
+            range_hi->a1 = range_lo->a1;
+            range_hi->a2 = range_hi->a3 = range_hi->a4 = 255;
+        }
+        else if (num == 2)
+        {
+            range_hi->a1 = range_lo->a1;
+            range_hi->a2 = range_lo->a2;
+            range_hi->a3 = range_hi->a4 = 255;
+        }
+        else if (num == 3)
+        {
+            range_hi->a1 = range_lo->a1;
+            range_hi->a2 = range_lo->a2;
+            range_hi->a3 = range_lo->a3;
+            range_hi->a4 = 255;
+        }
+        else
+        {
+            range_hi->a1 = range_lo->a1;
+            range_hi->a2 = range_lo->a2;
+            range_hi->a3 = range_lo->a3;
+            range_hi->a4 = range_lo->a4;
+        }
+        return;
+    }
+
+    // If a range is specified, both ends need to be full addresses
+    if (str_to_address(lo, range_lo) != 4 || str_to_address(hi, range_hi) != 4)
+    {
+        zero_address(range_lo);
+        zero_address(range_hi);
+    }
+}
+
+unsigned int address_to_int(IP_ADDRESS addr)
+{
+    return addr.a1 << 24 | addr.a2 << 16 | addr.a3 << 8 | addr.a4;
+}
+
+int my_authenticate(void *user_handle,
+                    const char *target_name,
+                    void *element_ptr,
+                    const char *user, const char *group, const char *password,
+                    const char *peer_IP)
+{
+    // see if we have an "args" attribute
+    const char *args = 0;
+#if HAVE_XSLT
+    xmlNodePtr ptr = (xmlNodePtr) element_ptr;
+    struct _xmlAttr *attr;
+
+    for (attr = ptr->properties; attr; attr = attr->next)
+    {
+        if (!strcmp((const char *) attr->name, "args") &&
+            attr->children && attr->children->type == XML_TEXT_NODE)
+            args = (const char *) attr->children->content;
+    }
+#endif
+    // args holds args (or NULL if none are provided)
+
+    yaz_log(YLOG_LOG, "Authentication: authenticating user %s, address %s", user ? user : "-", peer_IP ? peer_IP : "-");
+
+    // authentication handler
+    char user_file[255], ip_file[255];
+    *user_file = '\0';
+    *ip_file = '\0';
+    sscanf(args, "%254[^:]:%254s", user_file, ip_file);
+
+    yaz_log(YLOG_LOG, "Authentication: user file: %s, ip file: %s", user_file, ip_file);
+
+    // Check if the IP address is listed in the file of allowed address ranges.
+    // The format of the file:
+    // 192.168.0
+    // 192.168.0.100
+    // 192.168.0.1-192.168.0.200
+    int status = YAZPROXY_RET_PERM;
+    if (ip_file && peer_IP)
+    {
+        yaz_log(YLOG_LOG, "Authentication: checking ip address");
+
+        const char *pIP = peer_IP;
+        if (strncmp(pIP, "tcp:", 4) == 0)
+            pIP += 4;
+        IP_ADDRESS peer_address;
+        if (str_to_address(pIP, &peer_address) != 4)
+            yaz_log(YLOG_WARN, "Authentication: could not decode peer IP address %s properly", pIP);
+        unsigned int peer_address_int = address_to_int(peer_address);
+
+        FILE *f = fopen(ip_file, "r");
+        if (!f)
+        {
+            yaz_log(YLOG_WARN, "Authentication: could not open ip authentication file %s", ip_file);
+                return YAZPROXY_RET_PERM;
+        }
+        while (!feof(f))
+        {
+            char line[255];
+            *line = '\0';
+            fgets(line, 254, f);
+            line[254] = '\0';
+
+            // Remove comments
+            char *comment_pos = strchr(line, '#');
+            if (comment_pos)
+                *comment_pos = '\0';
+
+            IP_ADDRESS range_lo, range_hi;
+            str_to_address_range(line, &range_lo, &range_hi);
+            if (address_to_int(range_lo) <= peer_address_int && peer_address_int <= address_to_int(range_hi))
+            {
+                status = YAZPROXY_RET_OK;
+                break;
+            }
+        }
+        fclose(f);
+        if (status == YAZPROXY_RET_OK)
+        {
+            yaz_log(YLOG_LOG, "Authentication: IP address %s allowed", pIP);
+            return YAZPROXY_RET_OK;
+        }
+    }
+
+    if (!user || !password || !*user_file)
+    {
+        yaz_log(YLOG_WARN, "Authentication: no user name, password or user file specified");
+            return YAZPROXY_RET_PERM;
+    }
+
+    time_t current_time;
+    time(&current_time);
+    struct tm *local_time = localtime(&current_time);
+    char current_date[10];
+    sprintf(current_date, "%04d%02d%02d", local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday);
+
+    FILE *f = fopen(user_file, "r");
+    if (!f)
+    {
+        yaz_log(YLOG_WARN, "Authentication: could not open user authentication file %s", user_file);
+            return YAZPROXY_RET_PERM;
+    }
+    while (!feof(f))
+    {
+        char line[255];
+        *line = '\0';
+        fgets(line, 254, f);
+        line[254] = '\0';
+        char *p = strchr(line, '\n');
+        if (p) *p = '\0';
+
+        char f_user[255], f_password[255], f_expiry[255];
+        *f_user = '\0';
+        *f_password = '\0';
+        *f_expiry = '\0';
+        sscanf(line, "%254[^:]:%254[^:]:%254s", f_user, f_password, f_expiry);
+
+        if (strcmp(user, f_user) == 0 && strcmp(password, f_password) == 0 && (!*f_expiry || strcmp(current_date, f_expiry) <= 0))
+        {
+            status = YAZPROXY_RET_OK;
+            break;
+        }
+    }
+    fclose(f);
+    yaz_log(YLOG_LOG, "Authentication: %s for user %s", status == YAZPROXY_RET_OK ? "successful" : "failed", user);
+    return status;
+}
+
+Yaz_ProxyModule_int0 interface0 = {
+    my_init,
+    my_destroy,
+    my_authenticate
+};
+
+Yaz_ProxyModule_entry yazproxy_module = {
+    0,                            // interface version
+    "helsinki",                     // name
+    "Helsinki Module for YAZ Proxy",// description
+    &interface0
+};
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */