// // DemoAndLicensing.m // // Created by Andrew Salamon on 12/6/07. // Copyright 2007 Machine Perception Laboratory, University of California San Diego. All rights reserved. // #include "DemoAndLicensing.h" #ifdef WIN32 #include "DemoAndLicensing_Win.h" #endif #include #include #include #include // For system independent path support #include #include #include // For basename and extension namespace bf = boost::filesystem; namespace CERT { static DemoAndLicensing *sharedDemoObj = NULL; DemoAndLicensing * DemoAndLicensing::sharedDemo() { if( !sharedDemoObj ) { #ifdef WIN32 sharedDemoObj = new DemoAndLicensing_Win; #else sharedDemoObj = new DemoAndLicensing; #endif } return sharedDemoObj; } DemoAndLicensing::DemoAndLicensing() : filename(".mplab"), demoLength(90), started(false) { allowedPaths.push_back("/Library"); allowedPaths.push_back("/Users/Shared"); allowedPaths.push_back("~/Library"); } DemoAndLicensing::~DemoAndLicensing() { } bool DemoAndLicensing::startDemo() { return writeDemoStartDate(); } bool DemoAndLicensing::isDemo() { readDemoStartDate(); return started; } void DemoAndLicensing::setStartFromTime( time_t startTime ) { startDate = bg::date_from_tm( *localtime( &startTime ) ); started = true; } bool DemoAndLicensing::hasDemoEnded() { if( !started ) return false; if( !readDemoStartDate() ) { // This should mean that we haven't yet written the start date to a file // If we fail to write the file, then return true, meaning we can't run as a demo return !writeDemoStartDate(); } bg::date today = bg::day_clock::local_day(); if( today < startDate ) return true; // If the current date is before the start something is wrong bg::days daysUsed = today - startDate; if( daysUsed > demoLength ) return true; return false; } bool DemoAndLicensing::readDemoStartDate() { if( started ) return true; for( std::vector::iterator iter = allowedPaths.begin(); iter != allowedPaths.end(); ++iter ) { // make a boost path from the iterator, add the filename, try to read from it bf::path bfPath; try { bfPath = bf::path( *iter, bf::native ); bfPath /= bf::path( filename, bf::native ); } catch( const std::exception &error ) { // std::cerr << error.what() << std::endl; } catch( ... ) { } if( bf::exists( bfPath ) && !bf::is_directory( bfPath ) ) { try { std::ifstream ifs( bfPath.native_file_string().c_str() ); if( ifs.good() ) { time_t dateNum; if( ifs >> dateNum ) { // de-obfuscate it and turn it into a date dateNum = deobfuscate( dateNum ); if( !validateStartDate( dateNum ) ) return false; setStartFromTime( dateNum ); pathUsed = bfPath.native_file_string(); return true; } } } catch( ... ) { } } } return false; } bool DemoAndLicensing::validateStartDate( time_t startTime ) { // Do some sanity checking on the date bg::date today = bg::day_clock::local_day(); bg::date startDate = bg::date_from_tm( *localtime( &startTime ) ); if( startDate > today ) return false; return true; } bool DemoAndLicensing::writeDemoStartDate() { if( started ) return true; return writeDemoStartDate( time( NULL ) ); } bool DemoAndLicensing::writeDemoStartDate( time_t startTime ) { if( started ) return true; if( !validateStartDate( startTime ) ) return false; for( std::vector::iterator iter = allowedPaths.begin(); iter != allowedPaths.end(); ++iter ) { bf::path dir; bf::path bfPath; try { dir = bf::path( *iter, bf::native ); bfPath = dir / bf::path( filename, bf::native ); } catch( const std::exception &error ) { // std::cerr << error.what() << std::endl; } catch( ... ) { } // We could try creating the directory if necessary // template bool create_directory(const Path& dp); if( bf::exists( dir ) && bf::is_directory( dir ) ) { try { std::ofstream ofs( bfPath.native_file_string().c_str() ); if( ofs.good() ) { // time_t dateInt = time( NULL ); setStartFromTime( startTime ); startTime = obfuscate( startTime ); ofs << startTime; pathUsed = bfPath.native_file_string(); return true; } } catch( ... ) { } } } return false; } std::string DemoAndLicensing::getFilename() { return filename; } void DemoAndLicensing::setFilename( const std::string &value ) { filename = value; } std::vector DemoAndLicensing::getAllowedPaths() { return allowedPaths; } //std::vector //DemoAndLicensing::normalizePaths( const std::vector &paths ) //{ // NSMutableArray *newPaths = [NSMutableArray array]; // NSEnumerator *pathEnum = [paths objectEnumerator]; // NSString *path; // while( path = [pathEnum nextObject] ) // { // path = [[[path stringByExpandingTildeInPath] stringByResolvingSymlinksInPath] stringByStandardizingPath]; // [newPaths addObject:path]; // } // return [[newPaths copy] autorelease]; //} void DemoAndLicensing::setAllowedPaths( const std::vector &value ) { allowedPaths = value; } unsigned int DemoAndLicensing::getDemoLength() { return demoLength.days(); } void DemoAndLicensing::setDemoLength( unsigned int _days ) { demoLength = bg::days( _days ); } bg::date DemoAndLicensing::demoEndDate() { bg::date endDate; if( readDemoStartDate() ) endDate = startDate + demoLength; return endDate; } bg::date DemoAndLicensing::demoStartDate() { return startDate; } void DemoAndLicensing::notifyUserDemoEnded() { std::cout << "The CERT evaluation period has ended." << std::endl; std::cout << "Please contact MPLab if you have any questions: http://mplab.ucsd.edu" << std::endl; } void DemoAndLicensing::notifyUserDemoNotAllowed() { std::cout << "Unable to start the CERT evaluation." << std::endl; std::cout << "Please contact MPLab if you have any questions: http://mplab.ucsd.edu" << std::endl; } void DemoAndLicensing::notifyUserDemoLeft() { std::cout << "This is an evaluation version of CERT." << std::endl; if( started ) { std::cout << "The evaluation period will end on " << demoEndDate() << "." << std::endl; } else { std::cout << "The evaluation period is " << demoLength.days() << " days but has not yet started." << std::endl; } } // These obfuscation methods are an attempt to write a rotating (or circular) bitwise shift. static int mask7 = 1 + 2 + 4 + 8 + 16 + 32 + 64; static int rt = 7; static int bitCnt = sizeof(int) * 8; int DemoAndLicensing::obfuscate( int num ) { int mask = mask7; int hold = num & mask; // save the 7 right most bits int clearmask = mask7 << (bitCnt - rt); clearmask = ~clearmask; // bitwise complement int tmp1 = num >> rt; tmp1 = tmp1 & clearmask; // Clear the leftmost 7 bits which might have been set to 1 by the shift int hold2 = hold << (bitCnt - rt); // move the saved bits to the other end int tmp2 = hold2 | tmp1; // paste them together return tmp2; } int DemoAndLicensing::deobfuscate( int num ) { int clearmask = ~mask7; int mask = mask7 << (bitCnt - rt); int hold = num & mask; hold = hold >> (bitCnt - rt); hold = hold & mask7; num = num << rt; num = num & clearmask; num = num | hold; return num; } /* Possible code for converting ~'s into absolute paths. Not sure which of the headers are needed for this snippet. #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__CYGWIN__) #include #endif // File path resolution function // Argument: A path which may be relative, and include ~ references. // Returns: The corresponding fully qualified absolute path. // Throws: std::invalid_argument if the argument is an empty string; // SystemError if anyting goes wrong with the API calls. // Notes: It is not required that the named file, or any directory // component of the path argument, actually exists. std::string resolve_path(const std::string& path) { // Some of this code is based on item 2.9 of the Unix programming FAQ // (http://www.erlenstar.demon.co.uk/unix/faq_toc.html) // First, check for the trivial case if (path.empty()) throw std::invalid_argument("The path is empty"); std::string resolved(path); // Special case for Cygwin, in case we get handed a native path #if defined(__CYGWIN__) std::vector buffer(PATH_MAX); cygwin_conv_to_full_posix_path(path.c_str(), &buffer[0]); resolved = &buffer[0]; #endif if (resolved[0] == '~') { std::string prefix; std::string::size_type slash(resolved.find_first_of('/')); if (resolved.size() == 1 || slash == 1) { const char* home(std::getenv("HOME")); if (home == 0) { std::vector buffer(sysconf(_SC_GETPW_R_SIZE_MAX)); passwd temp_pwd; passwd* pwd(0); int rc(getpwuid_r(getuid(), &temp_pwd, &buffer[0], buffer.size(), &pwd)); if (rc != 0) throw SystemError("getpwuid_r(getuid()) failed", rc); if (pwd != 0) prefix = pwd->pw_dir; } else { prefix = home; } } else { std::string user; if (slash == std::string::npos) user = resolved.substr(1); else user = resolved.substr(1, slash - 1); std::vector buffer(sysconf(_SC_GETPW_R_SIZE_MAX)); passwd temp_pwd; passwd* pwd(0); int rc(getpwnam_r(user.c_str(), &temp_pwd, &buffer[0], buffer.size(), &pwd)); if (rc != 0 && rc != ENOENT) throw SystemError("getpwnam_r(" + user + ") failed", rc); if (rc != ENOENT && pwd != 0) prefix = pwd->pw_dir; } if (!prefix.empty()) { if (prefix[prefix.size() - 1] == '/') prefix.resize(prefix.size() - 1); resolved.replace(0, slash, prefix); } } */ } // end namespace CERT