CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/CondCore/DBCommon/src/DecodingKey.cc

Go to the documentation of this file.
00001 #include "CondCore/DBCommon/interface/DecodingKey.h"
00002 #include "CondCore/DBCommon/interface/FileUtils.h"
00003 #include "CondCore/DBCommon/interface/Exception.h"
00004 #include "CondCore/DBCommon/interface/Cipher.h"
00005 //
00006 #include <sstream>
00007 #include <string.h>
00008 #include <fstream>
00009 #include <vector>
00010 #include <pwd.h>
00011 #include <ctime>
00012 
00013 constexpr char ItemSeparator = ';';
00014 constexpr char LineSeparator = '!';
00015 
00016 // character set same as base64, except for last two (missing are + and / ) 
00017 static const char* b64str =
00018     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
00019 
00020 static const std::string KEY_HEADER("Cond_Authentication_Key");
00021 
00022 static const std::string NAMEPREFIX("N=");
00023 static const std::string KEYPREFIX("K=");
00024 static const std::string OWNERPREFIX("O=");
00025 
00026 static const std::string DATEPREFIX("D=");
00027 
00028 static const std::string SERVICEPREFIX("S=");
00029 static const std::string CONNECTIONPREFIX("C=");
00030 static const std::string USERPREFIX("U=");
00031 static const std::string PASSWORDPREFIX("P=");
00032 
00033 static const std::string DEFAULT_SERVICE("Cond_Default_Service");
00034 
00035 namespace cond {
00036   char randomChar(){
00037     int irand = ::rand()%(::strlen(b64str));
00038     return b64str[irand];
00039   }
00040 
00041   std::string getLoginName(){
00042     std::string loginName("");
00043     struct passwd* userp = ::getpwuid(::getuid());
00044     if(userp) {
00045       char* uName = userp->pw_name;
00046       if(uName){
00047         loginName += uName;
00048       }
00049     }
00050     if(loginName.empty()){
00051       std::string  msg("Cannot determine login name.");
00052       throwException(msg,"DecodingKey::getLoginName");     
00053     }
00054     return loginName;
00055   }
00056 
00057   void parseLineForNamedParams( const std::string& line, std::map<std::string,std::string>& params ){
00058     std::stringstream str( line );
00059     std::string paramName("");
00060     std::string paramValue("");  
00061     while( str.good() ){
00062       std::string item("");
00063       getline( str, item, ItemSeparator);
00064       if( item.size()>3 ){
00065         paramName = item.substr(0,2);
00066         paramValue = item.substr(2);
00067         params.insert( std::make_pair( paramName, paramValue ) );
00068       }  
00069     }
00070   }
00071 
00072 }
00073 
00074 std::string cond::KeyGenerator::make( size_t keySize ){
00075   ::srand( m_iteration+2 );
00076   int rseed = ::rand();
00077   int seed = ::time( NULL)%10 + rseed;
00078   ::srand( seed );
00079   std::string ret("");
00080   for( size_t i=0;i<keySize; i++ ){
00081     ret += randomChar();
00082   }
00083   m_iteration++;
00084   return ret;
00085 }
00086 
00087 std::string cond::KeyGenerator::makeWithRandomSize( size_t maxSize ){
00088   ::srand( m_iteration+2 );
00089   int rseed = ::rand();
00090   int seed = ::time( NULL)%10 + rseed;
00091   ::srand( seed );
00092   size_t sz = rand()%maxSize;
00093   return make( sz );
00094 }
00095 
00096 const std::string cond::DecodingKey::FILE_NAME("db.key");
00097 const std::string cond::DecodingKey::FILE_PATH(".cms_cond/"+FILE_NAME);
00098 
00099 std::string cond::DecodingKey::templateFile(){
00100   std::stringstream s;
00101   s<<NAMEPREFIX<<"<principal_name>"<<std::endl;
00102   s<<OWNERPREFIX<<"<owner_name, optional>"<<std::endl;
00103   s<<KEYPREFIX<<"<key, leave empty if generated>"<<std::endl;
00104   //s<<DATEPREFIX<<"<expiring date, optional>"<<std::endl;
00105   s<<SERVICEPREFIX<<"<service_name0>;"<<CONNECTIONPREFIX<<"<service0_connection_string>;"<<USERPREFIX<<"<user0_name>;"<<PASSWORDPREFIX<<"<password0>;"<<std::endl;
00106   s<<SERVICEPREFIX<<"<service_name1>;"<<CONNECTIONPREFIX<<"<service1_connection_string>;"<<USERPREFIX<<"<user1_name>;"<<PASSWORDPREFIX<<"<password1>;"<<std::endl;
00107   s<<SERVICEPREFIX<<"<service_name2>;"<<CONNECTIONPREFIX<<"<service2_connection_string>;"<<USERPREFIX<<"<user2_name>;"<<PASSWORDPREFIX<<"<password2>;"<<std::endl;
00108   return s.str();
00109 }
00110 
00111 size_t cond::DecodingKey::init( const std::string& keyFileName, const std::string& password, bool readMode ){
00112   if(keyFileName.empty()){
00113     std::string msg("Provided key file name is empty.");
00114     throwException(msg,"DecodingKey::init");    
00115   }
00116   m_fileName = keyFileName;
00117   m_pwd = password;
00118   m_mode = readMode;
00119   m_principalName.clear();
00120   m_principalKey.clear();
00121   m_owner.clear();
00122   m_services.clear();
00123   size_t nelem = 0;
00124   if( m_mode ){
00125     std::ifstream keyFile (m_fileName.c_str(),std::ios::in|std::ios::binary|std::ios::ate);
00126     if (keyFile.is_open()){
00127       size_t fsize = keyFile.tellg();
00128       unsigned char* buff = (unsigned char*)malloc( fsize );
00129       keyFile.seekg (0, std::ios::beg);
00130       keyFile.read (reinterpret_cast<char*>(buff), fsize);
00131       Cipher cipher( m_pwd );
00132       std::string content = cipher.decrypt( buff, fsize );
00133       free ( buff );
00134       // skip the header + line separator
00135       if( content.substr( 0, KEY_HEADER.size() )!=KEY_HEADER ){
00136         std::string msg("Provided key content is invalid.");    
00137         throwException(msg,"DecodingKey::init");        
00138       } 
00139       std::stringstream str( content.substr( KEY_HEADER.size()+1) );
00140       while( str.good() ){
00141         std::string line;
00142         getline ( str, line,LineSeparator ); 
00143         if(line.size()>3 ){
00144           if( line.substr(0,2)==NAMEPREFIX ){
00145             m_principalName = line.substr(2);
00146           } else if ( line.substr(0,2)== KEYPREFIX ){
00147             m_principalKey = line.substr(2);
00148           } else if ( line.substr(0,2)== OWNERPREFIX ){
00149             m_owner = line.substr(2);
00150           } else if ( line.substr(0,2)== SERVICEPREFIX ){
00151             std::stringstream serviceStr( line.substr(2) );
00152             std::vector<std::string> sdata;
00153             while( serviceStr.good() ){
00154               sdata.push_back( std::string("") );
00155               getline( serviceStr, sdata.back(), ItemSeparator);
00156             }
00157             std::map< std::string, ServiceCredentials >::iterator iS =  m_services.insert( std::make_pair( sdata[0], ServiceCredentials() ) ).first;
00158             iS->second.connectionString = sdata[1];
00159             iS->second.userName = sdata[2];
00160             iS->second.password = sdata[3];
00161             nelem++;
00162           }
00163         }
00164       }
00165       keyFile.close();
00166       if( m_principalName.empty() || m_principalKey.empty() ){
00167         std::string msg = "Provided key is invalid.";
00168         throwException(msg,"DecodingKey::init");    
00169       }
00170       if( !m_owner.empty() ){
00171         std::string currentUser = getLoginName();
00172         if(m_owner != currentUser ){
00173           m_principalName.clear();
00174           m_principalKey.clear();
00175           m_owner.clear();
00176           m_services.clear();
00177           std::string msg = "Provided key is invalid for user=" + currentUser;
00178           throwException(msg,"DecodingKey::init");    
00179         }
00180       }
00181     } else {
00182       std::string msg = "Provided Key File \""+m_fileName+"\" is invalid.";
00183       throwException(msg,"DecodingKey::init");      
00184     }
00185   }
00186   return nelem;
00187 }
00188 
00189 size_t cond::DecodingKey::createFromInputFile( const std::string& inputFileName, size_t generatedKeySize ){
00190   size_t nelem = 0;
00191   if(inputFileName.empty()){
00192     std::string msg("Provided input file name is empty.");
00193     throwException(msg,"DecodingKey::readFromInputFile");    
00194   }
00195   m_principalName.clear();
00196   m_principalKey.clear();
00197   m_owner.clear();
00198   m_services.clear();
00199   std::ifstream inputFile (inputFileName.c_str());
00200   if (inputFile.is_open()){
00201     std::map<std::string,std::string> params;
00202     while ( inputFile.good() ){
00203       std::string line;
00204       getline (inputFile, line);
00205       params.clear();
00206       if(line.size()>3 ){
00207         if( line.substr(0,2)==NAMEPREFIX ){
00208           m_principalName = line.substr(2);
00209         } else if ( line.substr(0,2)== KEYPREFIX ){
00210           m_principalKey = line.substr(2);
00211         } else if ( line.substr(0,2)== OWNERPREFIX ){
00212           m_owner = line.substr(2);
00213         } else if ( line.substr(0,2)== SERVICEPREFIX ){
00214           parseLineForNamedParams( line, params );
00215           std::string& serviceName = params[ SERVICEPREFIX ];
00216           ServiceCredentials creds;
00217           creds.connectionString = params[ CONNECTIONPREFIX ];
00218           creds.userName = params[ USERPREFIX ];
00219           creds.password = params[ PASSWORDPREFIX ];
00220           m_services.insert( std::make_pair( serviceName, creds ) );
00221           nelem++;
00222         }
00223       }
00224     }
00225     inputFile.close();
00226     if( m_principalKey.empty() && generatedKeySize){
00227       KeyGenerator gen;
00228       m_principalKey = gen.make( generatedKeySize );
00229     }
00230 
00231   } else {
00232     std::string msg = "Provided Input File \""+inputFileName+"\n is invalid.";
00233     throwException(msg,"DecodingKey::readFromInputFile");      
00234   }
00235   return nelem;
00236 }
00237 
00238 void cond::DecodingKey::list( std::ostream& out ){
00239   out <<NAMEPREFIX<<m_principalName<<std::endl;
00240   out <<KEYPREFIX<<m_principalKey<<std::endl;
00241   out <<OWNERPREFIX<<m_owner<<std::endl;
00242   for( std::map< std::string, ServiceCredentials >::const_iterator iS = m_services.begin();
00243        iS != m_services.end(); iS++ ){
00244     out <<SERVICEPREFIX<<iS->first<<";";
00245     out <<CONNECTIONPREFIX<<iS->second.connectionString<<";";
00246     out <<USERPREFIX<<iS->second.userName<<";";
00247     out <<PASSWORDPREFIX<<iS->second.password<<";"<<std::endl;
00248   }
00249 }
00250 
00251 void cond::DecodingKey::flush(){
00252   std::ofstream outFile ( m_fileName.c_str(),std::ios::binary);
00253   if (outFile.is_open()){
00254     std::stringstream content;
00255     content << KEY_HEADER << LineSeparator;
00256     if( !m_principalName.empty() ){
00257       content << NAMEPREFIX << m_principalName << LineSeparator;
00258     }
00259     if( !m_principalKey.empty() ){
00260       content << KEYPREFIX << m_principalKey << LineSeparator;
00261     }
00262     if( !m_owner.empty() ){
00263       content << OWNERPREFIX << m_owner << LineSeparator;
00264     }
00265     for( std::map< std::string, ServiceCredentials >::const_iterator iD = m_services.begin();
00266          iD != m_services.end(); ++iD ){
00267       content << SERVICEPREFIX << iD->first << ItemSeparator;
00268       content << iD->second.connectionString << ItemSeparator;
00269       content << iD->second.userName << ItemSeparator;
00270       content << iD->second.password << ItemSeparator;
00271       content << LineSeparator;
00272     }
00273     Cipher cipher( m_pwd );
00274     unsigned char* out;
00275     size_t outSize = cipher.encrypt( content.str(), out );
00276     outFile.write( reinterpret_cast<char*>(out),outSize);
00277     free (out );
00278   } else {
00279     std::string msg("");
00280     msg += "Provided Key File \""+m_fileName+"\n is invalid.";
00281     throwException(msg,"DecodingKey::flush");            
00282   }
00283   outFile.close();
00284 }
00285   
00286 void cond::DecodingKey::addDefaultService( const std::string& connectionString ){
00287   addService( DEFAULT_SERVICE, connectionString, "", "" );  
00288 }
00289 
00290 void cond::DecodingKey::addService( const std::string& serviceName, 
00291                                     const std::string& connectionString, 
00292                                     const std::string& userName, 
00293                                     const std::string& password ){  
00294   std::map< std::string, ServiceCredentials >::iterator iK = m_services.find( serviceName );
00295   if( iK == m_services.end() ){
00296     iK = m_services.insert( std::make_pair( serviceName, ServiceCredentials() ) ).first;
00297   }
00298   iK->second.connectionString = connectionString;
00299   iK->second.userName = userName;
00300   iK->second.password = password;
00301 }
00302