/* $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 #include #include #include #include #include #if HAVE_XSLT #include #include #include #include #include #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 */