File indexing completed on 2024-07-22 23:30:51
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
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
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 }
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
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
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 }