/*************************************************************************** * Copyright (C) 2005 Meni Livne * * * * This program 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 of the License, or * * (at your option) any later version. * * * * This program 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 this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #ifdef WIN32 #include #include #else #include #include #endif #include #include "phish.h" #include "phish_settings.h" #include "phish_opdb_server.h" #include "phish_local_xml.h" #include "phish_safelist.h" #include "phish_util_net.h" /* name of directory used to store phish-related files: settings, the safe list file and the downloaded XML file */ #define PHISH_DIR ".phish" /* name of settings file */ #define PHISH_SETTINGS_FILE "phishrc" static char *phish_dir_path; /* full path to phish directory */ static char *settings_path = NULL; /* full path to settings file */ static char *safelist_path = NULL; /* full path to safe list file */ static char *local_xml_path = NULL; /* full path to local XML file */ static char *client_ua = NULL; /* client identification string */ static char *full_ua = NULL; /* full user agent used to send to server */ static phish_settings_t settings; /* global settings */ static phish_util_url_t query_url; /* parsed URL for site queries */ static phish_util_url_t country_url; /* parsed URL for country queries */ static phish_util_url_t reporting_url; /* parsed URL for reporting sites */ static phish_util_url_t xml_url; /* parsed URL for XML file on server */ static phish_safelist_t *safelist; /* global safe list */ /* This is incremented each time phish_init() is called, and decremented each time phish_shutdown() is called. This is needed for browsers with support for multiple tabs and/or windows, each of which containing a toolbar which uses this library, for knowing when to actually shut the library down. */ static unsigned int refcount = 0; static void cleanup() { phish_util_deleteURL(&xml_url); phish_util_deleteURL(&reporting_url); phish_util_deleteURL(&country_url); phish_util_deleteURL(&query_url); free(full_ua); free(client_ua); free(local_xml_path); free(safelist_path); free(settings_path); phish_settings_free(&settings); } phish_result_t phish_init(const char *user_agent, const char *client_version) { char *home_dir; #ifdef WIN32 WSADATA wsaData; home_dir = getenv("APPDATA"); #else struct passwd *pw = getpwuid(getuid()); home_dir = pw->pw_dir; #endif if (refcount > 0) { refcount++; return PHISH_SUCCESS; } /* initialise URL structures */ phish_util_initURL(&query_url); phish_util_initURL(&country_url); phish_util_initURL(&reporting_url); phish_util_initURL(&xml_url); /* find out phish directory path */ phish_dir_path = malloc(strlen(home_dir) + 1 + strlen(PHISH_DIR) + 1); if (phish_dir_path == NULL) { return PHISH_ERR_MEMORY; } sprintf(phish_dir_path, "%s/%s", home_dir, PHISH_DIR); /* find out settings file path */ settings_path = malloc(strlen(phish_dir_path) + 1 + strlen(PHISH_SETTINGS_FILE) + 1); if (settings_path == NULL) { free(phish_dir_path); return PHISH_ERR_MEMORY; } sprintf(settings_path, "%s/%s", phish_dir_path, PHISH_SETTINGS_FILE); /* create phish directory if it doesn't yet exist under user's home dir */ #ifndef WIN32 mkdir(phish_dir_path, 0700); #else mkdir(phish_dir_path); #endif /* load settings */ phish_settings_init(&settings); phish_settings_load(&settings, settings_path); /* find out safe list file path */ safelist_path = malloc(strlen(phish_dir_path) + 1 + strlen(phish_settings_safeListFile(&settings)) + 1); if (safelist_path == NULL) { cleanup(); free(phish_dir_path); return PHISH_ERR_MEMORY; } sprintf(safelist_path, "%s/%s", phish_dir_path, phish_settings_safeListFile(&settings)); /* find out local XML file path */ local_xml_path = malloc(strlen(phish_dir_path) + 1 + strlen(phish_settings_localXMLFile(&settings)) + 1); if (local_xml_path == NULL) { cleanup(); free(phish_dir_path); return PHISH_ERR_MEMORY; } sprintf(local_xml_path, "%s/%s", phish_dir_path, phish_settings_localXMLFile(&settings)); free(phish_dir_path); /* parse URL of query script on server */ if (phish_util_strToURL(phish_settings_siteQueryURL(&settings), &query_url) != PHISH_SUCCESS) { cleanup(); return PHISH_ERR_SETTINGS; } if (query_url.port == -1) query_url.port = 80; /* parse URL of country query script on server */ if (phish_util_strToURL(phish_settings_countryQueryURL(&settings), &country_url) != PHISH_SUCCESS) { cleanup(); return PHISH_ERR_SETTINGS; } if (country_url.port == -1) country_url.port = 80; /* parse URL to report sites on server */ if (phish_util_strToURL(phish_settings_reportSiteURL(&settings), &reporting_url) != PHISH_SUCCESS) { cleanup(); return PHISH_ERR_SETTINGS; } if (reporting_url.port == -1) reporting_url.port = 80; /* parse URL of XML file to download */ if (phish_util_strToURL(phish_settings_remoteXMLURL(&settings), &xml_url) != PHISH_SUCCESS) { cleanup(); return PHISH_ERR_SETTINGS; } if (xml_url.port == -1) xml_url.port = 80; client_ua = malloc(strlen(client_version) + 2 + strlen(PHISH_LIB_NAME) + 1 + strlen(PHISH_LIB_VERSION) + 1); if (client_ua == NULL) { cleanup(); return PHISH_ERR_MEMORY; } sprintf(client_ua, "%s; %s/%s", client_version, PHISH_LIB_NAME, PHISH_LIB_VERSION); full_ua = malloc(strlen(user_agent) + 2 + strlen(client_ua) + 1 + 1); if (full_ua == NULL) { cleanup(); return PHISH_ERR_MEMORY; } sprintf(full_ua, "%s (%s)", user_agent, client_ua); /* open safe list */ phish_safelist_open(safelist_path, &safelist); #ifdef WIN32 WSAStartup( MAKEWORD( 2, 2 ), &wsaData ); #endif refcount++; return PHISH_SUCCESS; } phish_result_t phish_shutdown() { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; else if (refcount > 1) { refcount--; return PHISH_SUCCESS; } phish_safelist_write(safelist_path, safelist); phish_safelist_close(safelist); phish_settings_write(&settings, settings_path); cleanup(); #ifdef WIN32 WSACleanup(); #endif refcount--; return PHISH_SUCCESS; } static void initURLData(phish_url_data_t *url_data) { url_data->risk_level = PHISH_RISK_UNKNOWN; url_data->server = -1; url_data->ip = -1; url_data->path = -1; url_data->domain = -1; url_data->comments_length = 0; url_data->comments = NULL; url_data->user_scheme = -1; url_data->suspicious_host = -1; strcpy(url_data->country, "--"); } static phish_risk_t calculateRisk(phish_url_data_t *results) { int rating = 1; if (results->server == -1) { if (results->ip == 1 && results->path == 1) rating = 7; else if (results->ip == 1) rating = 5; } else if (results->domain != 1) { if (results->ip == 1 && results->server == 1 && results->path == 1) rating = 9; else if (results->ip == 1 && (results->server == 1 || results->path == 1)) rating = 7; else if (results->server == 1 && results->path == 1) rating = 8; else if (results->server == 1) rating = 6; else if (results->ip == 1) rating = 5; } else { if (results->ip == 1 && results->server == 1 && results->path == 1) rating = 9; else if (results->ip == 1 && results->server == 1) rating = 7; else if (results->server == 1 && results->path == 1) rating = 8; else if (results->server == 1 || (results->ip == 1 && results->path == 1)) rating = 6; else if (results->ip == 1) rating = 4; else if (results->path == 1) rating = 5; else rating = 3; } if (results->user_scheme == 1) rating++; if (results->suspicious_host == 1) rating++; if (rating > 10) rating = 10; if (rating == 1) return PHISH_RISK_LOW; if (rating == 2 || rating == 3) return PHISH_RISK_MEDIUM; else return PHISH_RISK_HIGH; } phish_result_t phish_checkURL(const char *url, phish_url_data_t *results) { char *ip; phish_util_url_t p_url; phish_result_t r; if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; phish_util_initURL(&p_url); r = phish_util_strToURL(url, &p_url); if (r != PHISH_SUCCESS) return r; /* get IP of host of URL given */ r = phish_util_hostToIP(p_url.host, &ip); if (r != PHISH_SUCCESS) /* the URL does not have a valid IP address */ { phish_util_deleteURL(&p_url); return r; } /* initialise results */ initURLData(results); switch(phish_settings_runningMode(&settings)) { case PHISH_ONLINE_MODE: r = phish_opdbserver_checkURL(&query_url, &p_url, ip, full_ua, results); break; case PHISH_OFFLINE_MODE: r = phish_localxml_checkURL(local_xml_path, &p_url, ip, results); break; default: break; } phish_util_checkURLScheme(&p_url, results); phish_util_deleteURL(&p_url); free(ip); if (r == PHISH_SUCCESS) results->risk_level = calculateRisk(results); return r; } phish_result_t phish_checkCountry(const char *url, phish_url_data_t *results) { char *ip; phish_util_url_t p_url; phish_result_t r; if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; phish_util_initURL(&p_url); r = phish_util_strToURL(url, &p_url); if (r != PHISH_SUCCESS) return r; /* get IP of host of URL given */ r = phish_util_hostToIP(p_url.host, &ip); if (r != PHISH_SUCCESS) /* the URL does not have a valid IP address */ { phish_util_deleteURL(&p_url); return r; } /* initialise results */ initURLData(results); r = phish_opdbserver_checkCountry(&country_url, ip, full_ua, results); phish_util_deleteURL(&p_url); free(ip); return r; } phish_result_t phish_deleteURLData(phish_url_data_t *url_data) { free(url_data->comments); return PHISH_SUCCESS; } phish_result_t phish_checkSafeList(const char *url, int *reply) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *reply = phish_safelist_checkURL(url, safelist); return PHISH_SUCCESS; } phish_result_t phish_downloadDBAsXML() { char *new_etag; phish_result_t r; if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; r = phish_opdbserver_downloadDBAsXML(&xml_url, full_ua, local_xml_path, phish_settings_remoteXMLETag(&settings), &new_etag); if (r == PHISH_SUCCESS) { phish_settings_setRemoteXMLETag(&settings, new_etag); free(new_etag); } return r; } phish_result_t phish_getReportingURL(const char *url, char **result) { phish_result_t r; if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; r = phish_opdbserver_getReportingURL(&reporting_url, client_ua, url, result); return r; } phish_result_t phish_getSafeListFirst(phish_safe_list_entry_t **entry) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *entry = (phish_safe_list_entry_t *)phish_safelist_first(safelist); return PHISH_SUCCESS; } phish_result_t phish_getSafeListNext(phish_safe_list_entry_t *entry, phish_safe_list_entry_t **next) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *next = (phish_safe_list_entry_t *) phish_safelist_next((phish_safelist_entry_t *)entry); return PHISH_SUCCESS; } phish_result_t phish_getSafeListData(phish_safe_list_entry_t *entry, const char **url) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *url = phish_safelist_entryData((phish_safelist_entry_t *)entry); return PHISH_SUCCESS; } phish_result_t phish_addToCurrentSafeList(const char *url) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; return phish_safelist_add(url, safelist); } phish_result_t phish_addToSafeList(phish_safe_list_t *list, const char *url) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; return phish_safelist_add(url, (phish_safelist_t *)list); } phish_result_t phish_newSafeList(phish_safe_list_t **list) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; return phish_safeList_new((phish_safelist_t **)list); } phish_result_t phish_setSafeList(phish_safe_list_t *list) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; if (safelist != (phish_safelist_t *)list) { phish_safelist_close(safelist); safelist = (phish_safelist_t *)list; } return PHISH_SUCCESS; } phish_result_t phish_saveSafeList() { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; phish_safelist_write(safelist_path, safelist); return PHISH_SUCCESS; } phish_result_t phish_saveSettings() { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; phish_settings_write(&settings, settings_path); return PHISH_SUCCESS; } phish_result_t phish_runningMode(phish_mode_t *result) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *result = phish_settings_runningMode(&settings); return PHISH_SUCCESS; } phish_result_t phish_siteQueryURL(const char **result) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *result = phish_settings_siteQueryURL(&settings); return PHISH_SUCCESS; } phish_result_t phish_countryQueryURL(const char **result) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *result = phish_settings_countryQueryURL(&settings); return PHISH_SUCCESS; } phish_result_t phish_reportSiteURL(const char **result) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *result = phish_settings_reportSiteURL(&settings); return PHISH_SUCCESS; } phish_result_t phish_remoteXMLURL(const char **result) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *result = phish_settings_remoteXMLURL(&settings); return PHISH_SUCCESS; } phish_result_t phish_localXMLFile(const char **result) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *result = phish_settings_localXMLFile(&settings); return PHISH_SUCCESS; } phish_result_t phish_safeListFile(const char **result) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; *result = phish_settings_safeListFile(&settings); return PHISH_SUCCESS; } phish_result_t phish_setRunningMode(phish_mode_t mode) { if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; phish_settings_setRunningMode(&settings, mode); return PHISH_SUCCESS; } phish_result_t phish_setSiteQueryURL(const char *url) { phish_util_url_t new_url; if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; /* parse new URL */ phish_util_initURL(&new_url); if (phish_util_strToURL(url, &new_url) != PHISH_SUCCESS) { return PHISH_ERR_SETTINGS; } if (new_url.port == -1) new_url.port = 80; phish_settings_setSiteQueryURL(&settings, url); phish_util_deleteURL(&query_url); query_url = new_url; return PHISH_SUCCESS; } phish_result_t phish_setCountryQueryURL(const char *url) { phish_util_url_t new_url; if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; /* parse new URL */ phish_util_initURL(&new_url); if (phish_util_strToURL(url, &new_url) != PHISH_SUCCESS) { return PHISH_ERR_SETTINGS; } if (new_url.port == -1) new_url.port = 80; phish_settings_setCountryQueryURL(&settings, url); phish_util_deleteURL(&country_url); country_url = new_url; return PHISH_SUCCESS; } phish_result_t phish_setReportSiteURL(const char *url) { phish_util_url_t new_url; if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; /* parse new URL */ phish_util_initURL(&new_url); if (phish_util_strToURL(url, &new_url) != PHISH_SUCCESS) { return PHISH_ERR_SETTINGS; } if (new_url.port == -1) new_url.port = 80; phish_settings_setReportSiteURL(&settings, url); phish_util_deleteURL(&reporting_url); reporting_url = new_url; return PHISH_SUCCESS; } phish_result_t phish_setRemoteXMLURL(const char *url) { phish_util_url_t new_url; if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; /* parse new URL */ phish_util_initURL(&new_url); if (phish_util_strToURL(url, &new_url) != PHISH_SUCCESS) { return PHISH_ERR_SETTINGS; } if (new_url.port == -1) new_url.port = 80; phish_settings_setRemoteXMLURL(&settings, url); phish_util_deleteURL(&xml_url); xml_url = new_url; return PHISH_SUCCESS; } phish_result_t phish_setLocalXMLFile(const char *path) { char *new_path; if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; new_path = malloc(strlen(phish_dir_path) + 1 + strlen(path) + 1); if (new_path == NULL) { return PHISH_ERR_MEMORY; } phish_settings_setLocalXMLFile(&settings, path); free(local_xml_path); local_xml_path = new_path; sprintf(local_xml_path, "%s/%s", phish_dir_path, path); return PHISH_SUCCESS; } phish_result_t phish_setSafeListFile(const char *path) { char *new_path; if (refcount == 0) return PHISH_ERR_NOT_INITIALISED; new_path = malloc(strlen(phish_dir_path) + 1 + strlen(path) + 1); if (new_path == NULL) { return PHISH_ERR_MEMORY; } phish_settings_setSafeListFile(&settings, path); /* write and close old safe list */ phish_safelist_write(safelist_path, safelist); phish_safelist_close(safelist); free(safelist_path); safelist_path = new_path; sprintf(safelist_path, "%s/%s", phish_dir_path, path); /* open new safe list */ phish_safelist_open(safelist_path, &safelist); return PHISH_SUCCESS; }