<?php
/**
* Project: Distrubution License Class
* File: class.license.app.php
*
* Copyright (C) 2005 Oliver Lillie
*
* 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
*
* @link http://www.buggedcom.co.uk/
* @link http://www.phpclasses.org/browse/package/2298.html
* @author Oliver Lillie, buggedcom <publicmail at buggedcom dot co dot uk>
* @history---------------------------------------------
* see CHANGELOG
*/
class license_application extends padl {
/**
* The number of allowed differences between the $_SERVER vars and the vars
* stored in the key
*
* @var number
*/
var $_ALLOWED_SERVER_DIFS = 0;
/**
* The number of allowed differences between the $ip vars in the key and the ip
* vars collected from the server
*
* @var number
*/
var $_ALLOWED_IP_DIFS = 0;
/**
* the path of the license key file, remember this would be relative to the
* include path of the class file.
*/
var $_LICENSE_PATH;
/**
* Constructor
*
* @access public
* @param $use_mcrypt boolean Determines if mcrypt encryption is used or not (defaults to true,
* however if mcrypt is not available, it is set to false)
* @param $use_time boolean Sets if time binding should be used in the key (defaults to true)
* @param $use_server boolean Sets if server binding should be used in the key (defaults to true)
* @param $allow_local boolean Sets if server binding is in use then localhost servers are valid (defaults to false)
**/
function license_application($license_path='license.dat', $use_mcrypt=true, $use_time=true, $use_server=true, $allow_local=false)
{
# check to see if the class has been secured
$this->_check_secure();
$this->_LICENSE_PATH = $license_path;
$this->init($use_mcrypt, $use_time, $use_server, $allow_local);
if($this->USE_SERVER)
{
$this->_MAC = $this->_get_mac_address();
}
}
/**
* set_server_vars
*
* to protect against spoofing you should copy the $_SERVER vars into a
* seperate array right at the first line of your script so parameters can't
* be changed in unencoded php files. This doesn't have to be set. If it is
* not set then the $_SERVER is copied when _get_server_info (private) function
* is called.
*
* @access public
* @param $array array The copied $_SERVER array
**/
function set_server_vars($array)
{
# check to see if the class has been secured
$this->_check_secure();
$this->_SERVER_VARS = $array;
# some of the ip data is dependant on the $_SERVER vars, so update them
# after the vars have been set
$this->_IPS = $this->_get_ip_address();
# update the server info
$this->_SERVER_INFO = $this->_get_server_info();
}
/**
* _get_os_var
*
* gets various vars depending on the os type
*
* @access private
* @return string various values
**/
function _get_os_var($var_name, $os)
{
$var_name = strtolower($var_name);
# switch between the os's
switch($os)
{
# not sure if the string is correct for FreeBSD
# not tested
case 'freebsd' :
# not sure if the string is correct for NetBSD
# not tested
case 'netbsd' :
# not sure if the string is correct for Solaris
# not tested
case 'solaris' :
# not sure if the string is correct for SunOS
# not tested
case 'sunos' :
# darwin is mac os x
# tested only on the client os
case 'darwin' :
# switch the var name
switch($var_name)
{
case 'conf' :
$var = '/sbin/ifconfig';
break;
case 'mac' :
$var = 'ether';
break;
case 'ip' :
$var = 'inet ';
break;
}
break;
# linux variation
# tested on server
case 'linux' :
# switch the var name
switch($var_name)
{
case 'conf' :
$var = '/sbin/ifconfig';
break;
case 'mac' :
$var = 'HWaddr';
break;
case 'ip' :
$var = 'inet addr:';
break;
}
break;
}
return $var;
}
/**
* _get_config
*
* gets the server config file and returns it. tested on Linux,
* Darwin (Mac OS X), and Win XP. It may work with others as some other
* os's have similar ifconfigs to Darwin but they haven't been tested
*
* @access private
* @return string config file data
**/
function _get_config()
{
# check to see if the class has been secured
$this->_check_secure();
if(ini_get('safe_mode'))
{
# returns invalid because server is in safe mode thus not allowing
# sbin reads but will still allow it to open. a bit weird that one.
return 'SAFE_MODE';
}
# if anyone has any clues for windows environments
# or other server types let me know
$os = strtolower(PHP_OS);
if(substr($os, 0, 3)=='win')
{
# this windows version works on xp running apache
# based server. it has not been tested with anything
# else, however it should work with NT, and 2000 also
# execute the ipconfig
@exec('ipconfig/all', $lines);
# count number of lines, if none returned return MAC_404
# thanks go to Gert-Rainer Bitterlich <bitterlich -at- ima-dresden -dot- de>
if(count($lines) == 0) return 'ERROR_OPEN';
# $path the lines together
$conf = implode($this->_LINEBREAK, $lines);
}
else
{
# get the conf file name
$os_file = $this->_get_os_var('conf', $os);
# open the ipconfig
$fp = @popen($os_file, "rb");
# returns invalid, cannot open ifconfig
if (!$fp) return 'ERROR_OPEN';
# read the config
$conf = @fread($fp, 4096);
@pclose($fp);
}
return $conf;
}
/**
* _get_ip_address
*
* Used to get the MAC address of the host server. It works with Linux,
* Darwin (Mac OS X), and Win XP. It may work with others as some other
* os's have similar ifconfigs to Darwin but they haven't been tested
*
* @access private
* @return array IP Address(s) if found (Note one machine may have more than one ip)
* @return string ERROR_OPEN means config can't be found and thus not opened
* @return string IP_404 means ip adress doesn't exist in the config file and can't be found in the $_SERVER
* @return string SAFE_MODE means server is in safe mode so config can't be read
**/
function _get_ip_address()
{
$ips = array();
# get the cofig file
$conf = $this->_get_config();
# if the conf has returned and error return it
if($conf != 'SAFE_MODE' && $conf != 'ERROR_OPEN')
{
# if anyone has any clues for windows environments
# or other server types let me know
$os = strtolower(PHP_OS);
if(substr($os, 0, 3)=='win')
{
# anyone any clues on win ip's
}
else
{
# explode the conf into seperate lines for searching
$lines = explode($this->_LINEBREAK, $conf);
# get the ip delim
$ip_delim = $this->_get_os_var('ip', $os);
# ip pregmatch
$num = "(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])";
# seperate the lines
foreach ($lines as $key=>$line)
{
# check for the ip signature in the line
if(!preg_match("/^$num\\.$num\\.$num\\.$num$/", $line) && strpos($line, $ip_delim))
{
# seperate out the ip
$ip = substr($line, strpos($line, $ip_delim)+strlen($ip_delim));
$ip = trim(substr($ip, 0, strpos($ip, " ")));
# add the ip to the collection
if(!isset($ips[$ip])) $ips[$ip] = $ip;
}
}
}
}
# if the conf has returned nothing
# attempt to use the $_SERVER data
if(isset($this->_SERVER_VARS['SERVER_NAME']))
{
$ip = gethostbyname ($this->_SERVER_VARS['SERVER_NAME']);
if(!isset($ips[$ip])) $ips[$ip] = $ip;
}
if(isset($this->_SERVER_VARS['SERVER_ADDR']))
{
$name = gethostbyaddr ($this->_SERVER_VARS['SERVER_ADDR']);
$ip = gethostbyname ($name);
if(!isset($ips[$ip])) $ips[$ip] = $ip;
# if the $_SERVER addr is not the same as the returned ip include it aswell
if($addr != $this->_SERVER_VARS['SERVER_ADDR'])
{
if(!isset($ips[$this->_SERVER_VARS['SERVER_ADDR']])) $ips[$this->_SERVER_VARS['SERVER_ADDR']] = $this->_SERVER_VARS['SERVER_ADDR'];
}
}
# count return ips and return if found
if(count($ips) > 0) return $ips;
# failed to find an ip check for conf error or return 404
if($conf == 'SAFE_MODE' || $conf == 'ERROR_OPEN') return $conf;
return 'IP_404';
}
/**
* _get_mac_address
*
* Used to get the MAC address of the host server. It works with Linux,
* Darwin (Mac OS X), and Win XP. It may work with others as some other
* os's have similar ifconfigs to Darwin but they haven't been tested
*
* @access private
* @return string Mac address if found
* @return string ERROR_OPEN means config can't be found and thus not opened
* @return string MAC_404 means mac adress doesn't exist in the config file
* @return string SAFE_MODE means server is in safe mode so config can't be read
**/
function _get_mac_address()
{
# open the config file
$conf = $this->_get_config();
# if anyone has any clues for windows environments
# or other server types let me know
$os = strtolower(PHP_OS);
if(substr($os, 0, 3)=='win')
{
# explode the conf into lines to search for the mac
$lines = explode($this->_LINEBREAK, $conf);
# seperate the lines for analysis
foreach ($lines as $key=>$line)
{
# check for the mac signature in the line
# originally the check was checking for the existence of string 'physical address'
# however Gert-Rainer Bitterlich pointed out this was for english language
# based servers only. preg_match updated by Gert-Rainer Bitterlich. Thanks
if(preg_match("/([0-9a-f][0-9a-f][-:]){5}([0-9a-f][0-9a-f])/i", $line))
{
$trimmed_line = trim($line);
# take of the mac addres and return
return trim(substr($trimmed_line, strrpos($trimmed_line, " ")));
}
}
}
else
{
# get the mac delim
$mac_delim = $this->_get_os_var('mac', $os);
# get the pos of the os_var to look for
$pos = strpos($conf, $mac_delim);
if($pos)
{
# seperate out the mac address
$str1 = trim(substr($conf, ($pos+strlen($mac_delim))));
return trim(substr($str1, 0, strpos($str1, "\n")));
}
}
# failed to find the mac address
return 'MAC_404';
}
/**
* _get_server_info
*
* used to generate the server binds when server binding is needed.
*
* @access private
* @return array server bindings
* @return boolean false means that the number of bindings failed to
* meet the required number
**/
function _get_server_info()
{
if(empty($this->_SERVER_VARS))
{
$this->set_server_vars($_SERVER);
}
# get the server specific uris
$a = array();
if(isset($this->_SERVER_VARS['SERVER_ADDR']) && (!strrpos($this->_SERVER_VARS['SERVER_ADDR'], '127.0.0.1') || $this->ALLOW_LOCAL))
{
$a['SERVER_ADDR'] = $this->_SERVER_VARS['SERVER_ADDR'];
}
# corrected by Gert-Rainer Bitterlich <bitterlich -at- ima-dresden -dot- de>, Thanks
if(isset($this->_SERVER_VARS['HTTP_HOST']) && (!strrpos($this->_SERVER_VARS['HTTP_HOST'], '127.0.0.1') || $this->ALLOW_LOCAL))
{
$a['HTTP_HOST'] = $this->_SERVER_VARS['HTTP_HOST'];
}
if(isset($this->_SERVER_VARS['SERVER_NAME']))
{
$a['SERVER_NAME'] = $this->_SERVER_VARS['SERVER_NAME'];
}
if(isset($this->_SERVER_VARS['PATH_TRANSLATED']))
{
$a['PATH_TRANSLATED'] = substr($this->_SERVER_VARS['PATH_TRANSLATED'], 0, strrpos($this->_SERVER_VARS['PATH_TRANSLATED'], '/'));
}
else if(isset($this->_SERVER_VARS['SCRIPT_FILENAME']))
{
$a['SCRIPT_FILENAME'] = substr($this->_SERVER_VARS['SCRIPT_FILENAME'], 0, strrpos($this->_SERVER_VARS['SCRIPT_FILENAME'], '/'));
}
if(isset($_SERVER['SCRIPT_URI']))
{
$a['SCRIPT_URI'] = substr($this->_SERVER_VARS['SCRIPT_URI'], 0, strrpos($this->_SERVER_VARS['SCRIPT_URI'], '/'));
}
# if the number of different uris is less than the required amount,
# fail the request
if(count($a) < $this->REQUIRED_URIS)
{
return 'SERVER_FAILED';
}
return $a;
}
/**
* validate
*
* validates the server key and returns a data array.
*
* @access public
* @return array Main object in array is 'RESULT', it contains the result
* of the validation.
* OK - key is valid
* CORRUPT - key has been tampered with
* TMINUS - the key is being used before the valid start date
* EXPIRED - the key has expired
* ILLEGAL - the key is not on the same server the license was registered to
* ILLEGAL_LOCAL - the key is not allowed to be installed on a local machine
* INVALID - the the encryption key used to encrypt the key differs or the key is not complete
* EMPTY - the the key is empty
* 404 - the the key is missing
**/
function validate($str=false, $dialhome=false, $dialhost="", $dialpath="", $dialport="80")
{
# check to see if the class has been secured
$this->_check_secure();
# get the dat string
$dat_str = (!$str) ? @file_get_contents($this->_LICENSE_PATH) : $str;
if(strlen($dat_str)>0)
{
# decrypt the data
$DATA = $this->_unwrap_license($dat_str);
if(is_array($DATA))
{
# missing / incorrect id therefore it has been tampered with
if($DATA['ID'] != md5($this->ID1))
{
$DATA['RESULT'] = 'CORRUPT';
}
if($this->USE_TIME)
{
# the license is being used before it's official start
if($DATA['DATE']['START'] > time()+$this->START_DIF)
{
$DATA['RESULT'] = 'TMINUS';
}
# the license has expired
if($DATA['DATE']['END']-time() < 0 && $DATA['DATE']['SPAN'] != 'NEVER')
{
$DATA['RESULT'] = 'EXPIRED';
}
$DATA['DATE']['HUMAN']['START'] = date($this->DATE_STRING, $DATA['DATE']['START']);
$DATA['DATE']['HUMAN']['END'] = date($this->DATE_STRING, $DATA['DATE']['END']);
}
if($this->USE_SERVER)
{
$mac = $DATA['SERVER']['MAC'] == $this->_MAC;
$path = count(array_diff($this->_SERVER_INFO, $DATA['SERVER']['PATH'])) <= $this->_ALLOWED_SERVER_DIFS;
$domain = $this->_compare_domain_ip($DATA['SERVER']['DOMAIN'], $this->_IPS);
$ip = count(array_diff($this->_IPS, $DATA['SERVER']['IP'])) <= $this->_ALLOWED_IP_DIFS;
# the server details
if(!$mac || !$path || !$domain || !$ip)
{
$DATA['RESULT'] = 'ILLEGAL';
}
# check if local
$local = $this->ALLOW_LOCAL && (in_array('127.0.0.1', $DATA['SERVER']['IP']) || $DATA['PATH']['SERVER_ADDR'] == '127.0.0.1' || $DATA['PATH']['HTTP_HOST'] == '127.0.0.1');
if(!$local)
{
$DATA['RESULT'] = 'ILLEGAL_LOCAL';
}
}
# passed all current test so license is ok
if(!isset($DATA['RESULT']))
{
# dial to home server if required
if($dialhome)
{
# create the details to send to the home server
$stuff_to_send = array();
$stuff_to_send['LICENSE_DATA'] = $DATA;
$stuff_to_send['LICENSE_DATA']['KEY'] = md5($dat_str);
# dial home
$DATA['RESULT'] = $this->_call_home($stuff_to_send, $dialhost, $dialpath, $dialport);
}
else
{
# result is ok all test passed, license is legal
$DATA['RESULT'] = 'OK';
}
}
/*
*/
# data is returned for use
return $DATA;
}
else
{
# the are two reason that mean a invalid return
# 1 - the other hash key is different
# 2 - the key has been tampered with
return array('RESULT'=>'INVALID');
}
}
# returns empty because there is nothing in the dat_string
return array('RESULT'=>'EMPTY');
}
/**
* _call_home
*
* calls the dial home server (your server) andvalidates the clients license
* with the info in the mysql db
*
* @access private
* @param $data array Array that contains the info to be validated
* @param $dialhost string Host name of the server to be contacted
* @param $dialpath string Path of the script for the data to be sent to
* @param $dialport number Port Number to send the data through
* @return string Returns: the encrypted server validation result from the dial home call
* : SOCKET_FAILED => socket failed to connect to the server
**/
function _call_home($data, $dialhost, $dialpath, $dialport)
{
# post the data home
$data = $this->_post_data($dialhost, $dialpath, $data, $dialport);
return (empty($data['RESULT'])) ? 'SOCKET_FAILED' : $data['RESULT'];
}
}
?> |