--- /dev/null
+/* $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(¤t_time);
+ struct tm *local_time = localtime(¤t_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
+ */