/* $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
*/
syntax highlighted by Code2HTML, v. 0.9.1