Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 12:50:23

0001 #include "CondCore/CondDB/interface/DecodingKey.h"
0002 #include "CondCore/CondDB/interface/FileUtils.h"
0003 #include "CondCore/CondDB/interface/Exception.h"
0004 #include "CondCore/CondDB/interface/Cipher.h"
0005 //
0006 #include <sstream>
0007 #include <cstring>
0008 #include <fstream>
0009 #include <vector>
0010 #include <pwd.h>
0011 #include <ctime>
0012 #include <unistd.h>
0013 
0014 constexpr char ItemSeparator = ';';
0015 constexpr char LineSeparator = '!';
0016 
0017 // character set same as base64, except for last two (missing are + and / )
0018 static const char* b64str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
0019 
0020 static const std::string KEY_HEADER("Cond_Authentication_Key");
0021 
0022 static const std::string VERSIONPREFIX("V=");
0023 static const std::string NAMEPREFIX("N=");
0024 static const std::string KEYPREFIX("K=");
0025 static const std::string OWNERPREFIX("O=");
0026 
0027 static const std::string DATEPREFIX("D=");
0028 
0029 static const std::string SERVICEPREFIX("S=");
0030 static const std::string CONNECTIONPREFIX("C=");
0031 static const std::string USERPREFIX("U=");
0032 static const std::string PASSWORDPREFIX("P=");
0033 
0034 static const std::string DEFAULT_SERVICE("Cond_Default_Service");
0035 
0036 namespace cond {
0037   char randomChar() {
0038     int irand = ::rand() % (::strlen(b64str));
0039     return b64str[irand];
0040   }
0041 
0042   std::string getLoginName() {
0043     std::string loginName("");
0044     struct passwd* userp = ::getpwuid(::getuid());
0045     if (userp) {
0046       char* uName = userp->pw_name;
0047       if (uName) {
0048         loginName += uName;
0049       }
0050     }
0051     if (loginName.empty()) {
0052       std::string msg("Cannot determine login name.");
0053       throwException(msg, "DecodingKey::getLoginName");
0054     }
0055     return loginName;
0056   }
0057 
0058   void parseLineForNamedParams(const std::string& line, std::map<std::string, std::string>& params) {
0059     std::stringstream str(line);
0060     std::string paramName("");
0061     std::string paramValue("");
0062     while (str.good()) {
0063       std::string item("");
0064       getline(str, item, ItemSeparator);
0065       if (item.size() > 3) {
0066         paramName = item.substr(0, 2);
0067         paramValue = item.substr(2);
0068         params.insert(std::make_pair(paramName, paramValue));
0069       }
0070     }
0071   }
0072 
0073 }  // namespace cond
0074 
0075 std::string cond::auth::KeyGenerator::make(size_t keySize) {
0076   ::srand(m_iteration + 2);
0077   int rseed = ::rand();
0078   int seed = ::time(nullptr) % 10 + rseed;
0079   ::srand(seed);
0080   std::string ret("");
0081   for (size_t i = 0; i < keySize; i++) {
0082     ret += randomChar();
0083   }
0084   m_iteration++;
0085   return ret;
0086 }
0087 
0088 std::string cond::auth::KeyGenerator::makeWithRandomSize(size_t maxSize) {
0089   ::srand(m_iteration + 2);
0090   int rseed = ::rand();
0091   int seed = ::time(nullptr) % 10 + rseed;
0092   ::srand(seed);
0093   size_t sz = rand() % maxSize;
0094   return make(sz);
0095 }
0096 
0097 std::string cond::auth::DecodingKey::templateFile() {
0098   std::stringstream s;
0099   s << VERSIONPREFIX << KEY_FMT_VERSION << std::endl;
0100   s << NAMEPREFIX << "<principal_name>" << std::endl;
0101   s << OWNERPREFIX << "<owner_name, optional>" << std::endl;
0102   s << KEYPREFIX << "<key, leave empty if generated>" << std::endl;
0103   //s<<DATEPREFIX<<"<expiring date, optional>"<<std::endl;
0104   s << SERVICEPREFIX << "<service_name0>;" << CONNECTIONPREFIX << "<service0_connection_string>;" << USERPREFIX
0105     << "<user0_name>;" << PASSWORDPREFIX << "<password0>;" << std::endl;
0106   s << SERVICEPREFIX << "<service_name1>;" << CONNECTIONPREFIX << "<service1_connection_string>;" << USERPREFIX
0107     << "<user1_name>;" << PASSWORDPREFIX << "<password1>;" << std::endl;
0108   s << SERVICEPREFIX << "<service_name2>;" << CONNECTIONPREFIX << "<service2_connection_string>;" << USERPREFIX
0109     << "<user2_name>;" << PASSWORDPREFIX << "<password2>;" << std::endl;
0110   return s.str();
0111 }
0112 
0113 size_t cond::auth::DecodingKey::init(const std::string& keyFileName, const std::string& password, bool readMode) {
0114   if (keyFileName.empty()) {
0115     std::string msg("Provided key file name is empty.");
0116     throwException(msg, "DecodingKey::init");
0117   }
0118   m_fileName = keyFileName;
0119   m_pwd = password;
0120   m_mode = readMode;
0121   m_version.clear();
0122   m_principalName.clear();
0123   m_principalKey.clear();
0124   m_owner.clear();
0125   m_services.clear();
0126   size_t nelem = 0;
0127   if (m_mode) {
0128     std::ifstream keyFile(m_fileName.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
0129     if (keyFile.is_open()) {
0130       size_t fsize = keyFile.tellg();
0131       unsigned char* buff = (unsigned char*)malloc(fsize);
0132       keyFile.seekg(0, std::ios::beg);
0133       keyFile.read(reinterpret_cast<char*>(buff), fsize);
0134       Cipher cipher(m_pwd);
0135       std::string content = cipher.decrypt(buff, fsize);
0136       free(buff);
0137       // skip the header + line separator
0138       if (content.substr(0, KEY_HEADER.size()) != KEY_HEADER) {
0139         std::string msg("Provided key content is invalid.");
0140         throwException(msg, "DecodingKey::init");
0141       }
0142       std::stringstream str(content.substr(KEY_HEADER.size() + 1));
0143       while (str.good()) {
0144         std::string line;
0145         getline(str, line, LineSeparator);
0146         if (line.size() > 3) {
0147           if (line.substr(0, 2) == VERSIONPREFIX) {
0148             m_version = line.substr(2);
0149           } else if (line.substr(0, 2) == NAMEPREFIX) {
0150             m_principalName = line.substr(2);
0151           } else if (line.substr(0, 2) == KEYPREFIX) {
0152             m_principalKey = line.substr(2);
0153           } else if (line.substr(0, 2) == OWNERPREFIX) {
0154             m_owner = line.substr(2);
0155           } else if (line.substr(0, 2) == SERVICEPREFIX) {
0156             std::stringstream serviceStr(line.substr(2));
0157             std::vector<std::string> sdata;
0158             while (serviceStr.good()) {
0159               sdata.push_back(std::string(""));
0160               getline(serviceStr, sdata.back(), ItemSeparator);
0161             }
0162             std::map<std::string, ServiceCredentials>::iterator iS =
0163                 m_services.insert(std::make_pair(sdata[0], ServiceCredentials())).first;
0164             iS->second.connectionString = sdata[1];
0165             iS->second.userName = sdata[2];
0166             iS->second.password = sdata[3];
0167             nelem++;
0168           }
0169         }
0170       }
0171       keyFile.close();
0172       if (m_principalName.empty() || m_principalKey.empty()) {
0173         std::string msg = "Provided key is invalid.";
0174         throwException(msg, "DecodingKey::init");
0175       }
0176       if (!m_owner.empty()) {
0177         std::string currentUser = getLoginName();
0178         if (m_owner != currentUser) {
0179           m_principalName.clear();
0180           m_principalKey.clear();
0181           m_owner.clear();
0182           m_services.clear();
0183           std::string msg = "Provided key is invalid for user=" + currentUser;
0184           throwException(msg, "DecodingKey::init");
0185         }
0186       }
0187     } else {
0188       std::string msg = "Required Key File \"" + m_fileName + "\" is missing or unreadable.";
0189       throwException(msg, "DecodingKey::init");
0190     }
0191   }
0192   return nelem;
0193 }
0194 
0195 size_t cond::auth::DecodingKey::createFromInputFile(const std::string& inputFileName, size_t generatedKeySize) {
0196   size_t nelem = 0;
0197   if (inputFileName.empty()) {
0198     std::string msg("Provided input file name is empty.");
0199     throwException(msg, "DecodingKey::readFromInputFile");
0200   }
0201   m_version.clear();
0202   m_principalName.clear();
0203   m_principalKey.clear();
0204   m_owner.clear();
0205   m_services.clear();
0206   std::ifstream inputFile(inputFileName.c_str());
0207   if (inputFile.is_open()) {
0208     std::map<std::string, std::string> params;
0209     while (inputFile.good()) {
0210       std::string line;
0211       getline(inputFile, line);
0212       params.clear();
0213       if (line.size() > 3) {
0214         if (line.substr(0, 2) == VERSIONPREFIX) {
0215           m_version = line.substr(2);
0216         } else if (line.substr(0, 2) == NAMEPREFIX) {
0217           m_principalName = line.substr(2);
0218         } else if (line.substr(0, 2) == KEYPREFIX) {
0219           m_principalKey = line.substr(2);
0220         } else if (line.substr(0, 2) == OWNERPREFIX) {
0221           m_owner = line.substr(2);
0222         } else if (line.substr(0, 2) == SERVICEPREFIX) {
0223           parseLineForNamedParams(line, params);
0224           std::string& serviceName = params[SERVICEPREFIX];
0225           ServiceCredentials creds;
0226           creds.connectionString = params[CONNECTIONPREFIX];
0227           creds.userName = params[USERPREFIX];
0228           creds.password = params[PASSWORDPREFIX];
0229           m_services.insert(std::make_pair(serviceName, creds));
0230           nelem++;
0231         }
0232       }
0233     }
0234     inputFile.close();
0235     if (m_principalKey.empty() && generatedKeySize) {
0236       KeyGenerator gen;
0237       m_principalKey = gen.make(generatedKeySize);
0238     }
0239 
0240   } else {
0241     std::string msg = "Provided Input File \"" + inputFileName + "\n is invalid.";
0242     throwException(msg, "DecodingKey::readFromInputFile");
0243   }
0244   return nelem;
0245 }
0246 
0247 void cond::auth::DecodingKey::list(std::ostream& out) {
0248   out << VERSIONPREFIX << m_version << std::endl;
0249   out << NAMEPREFIX << m_principalName << std::endl;
0250   out << KEYPREFIX << m_principalKey << std::endl;
0251   out << OWNERPREFIX << m_owner << std::endl;
0252   for (std::map<std::string, ServiceCredentials>::const_iterator iS = m_services.begin(); iS != m_services.end();
0253        iS++) {
0254     out << SERVICEPREFIX << iS->first << ";";
0255     out << CONNECTIONPREFIX << iS->second.connectionString << ";";
0256     out << USERPREFIX << iS->second.userName << ";";
0257     out << PASSWORDPREFIX << iS->second.password << ";" << std::endl;
0258   }
0259 }
0260 
0261 void cond::auth::DecodingKey::flush() {
0262   std::ofstream outFile(m_fileName.c_str(), std::ios::binary);
0263   if (outFile.is_open()) {
0264     std::stringstream content;
0265     content << KEY_HEADER << LineSeparator;
0266     if (!m_version.empty()) {
0267       content << VERSIONPREFIX << m_version << LineSeparator;
0268     }
0269     if (!m_principalName.empty()) {
0270       content << NAMEPREFIX << m_principalName << LineSeparator;
0271     }
0272     if (!m_principalKey.empty()) {
0273       content << KEYPREFIX << m_principalKey << LineSeparator;
0274     }
0275     if (!m_owner.empty()) {
0276       content << OWNERPREFIX << m_owner << LineSeparator;
0277     }
0278     for (std::map<std::string, ServiceCredentials>::const_iterator iD = m_services.begin(); iD != m_services.end();
0279          ++iD) {
0280       content << SERVICEPREFIX << iD->first << ItemSeparator;
0281       content << iD->second.connectionString << ItemSeparator;
0282       content << iD->second.userName << ItemSeparator;
0283       content << iD->second.password << ItemSeparator;
0284       content << LineSeparator;
0285     }
0286     Cipher cipher(m_pwd);
0287     unsigned char* out;
0288     size_t outSize = cipher.encrypt(content.str(), out);
0289     outFile.write(reinterpret_cast<char*>(out), outSize);
0290     free(out);
0291   } else {
0292     std::string msg("");
0293     msg += "Provided Key File \"" + m_fileName + "\n is invalid.";
0294     throwException(msg, "DecodingKey::flush");
0295   }
0296   outFile.close();
0297 }
0298 
0299 void cond::auth::DecodingKey::addDefaultService(const std::string& connectionString) {
0300   addService(DEFAULT_SERVICE, connectionString, "", "");
0301 }
0302 
0303 void cond::auth::DecodingKey::addService(const std::string& serviceName,
0304                                          const std::string& connectionString,
0305                                          const std::string& userName,
0306                                          const std::string& password) {
0307   std::map<std::string, ServiceCredentials>::iterator iK = m_services.find(serviceName);
0308   if (iK == m_services.end()) {
0309     iK = m_services.insert(std::make_pair(serviceName, ServiceCredentials())).first;
0310   }
0311   iK->second.connectionString = connectionString;
0312   iK->second.userName = userName;
0313   iK->second.password = password;
0314 }