// Copyright (c) 2013, IOnU Security, Inc. // Copyright (c) 2016, Sequence Logic, Inc. All rights reserved. /** * CloudGuardURN implementation. */ #include "cloudguardurn.h" #include "../internal.h" #ifdef WIN32 #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT _WIN32_WINNT_WINXP #include #else #include #include #include #endif #include #include #ifdef WIN32 #include #endif #include #include using namespace sequencelogic; namespace { /** * Validate URN parts... */ bool validateURNPart(const std::string &urnPart, int nLength); /** * Generate a UUID. */ std::string getUUID(); /** * This is kind of a hack. This function needs to be linked into any code that directly links 'cppcoreobjects.lib'. * However, it was meant to be internal to the DLL. */ int SplitString2(const std::string &strToSplit, const char ch, std::vector &splitStrings) { int nRetVal = 0; splitStrings.clear(); std::string::size_type nStart = 0; while (strToSplit.find(ch, nStart) != std::string::npos) { splitStrings.push_back(strToSplit.substr(nStart, strToSplit.find(ch, nStart) - nStart)); ++nRetVal; nStart = strToSplit.find(ch, nStart)+1; } // Check for a last arg... if (nStart <= strToSplit.length()) { splitStrings.push_back(strToSplit.substr(nStart)); ++nRetVal; } return nRetVal; } }; const char CloudGuardURN::NAMESPACE[] = "urn:sl:"; /** * Exact length of NSS specific part of URN. */ const int CloudGuardURN::NSS_LENGTH = SL_URN_VAN_LEN + 1 + SL_URN_PMO_LEN + 1 + SL_URN_DEV_LEN + 1 + SL_URN_DOC_LEN; bool CloudGuardURN::isDoNotGenerateUUID(const char *pIdStr) { // There are certain reserved document ID values bool bRetVal = false; bRetVal = ( (pIdStr != NULL) && (pIdStr[0] != '\0') && ((strcmp(pIdStr, PMO_ALL_ID) == 0) || (strcmp(pIdStr, TEST_VAN_ID) == 0) || (strcmp(pIdStr, BROWSER_DEVICE_ID) == 0) || (strcmp(pIdStr, HEADLESS_DEVICE_ID) == 0) || (strcmp(pIdStr, TEST_DEVICE_ID) == 0) || (strcmp(pIdStr, GROUP_DOC_DEVICE_ID) == 0) || (strncmp(pIdStr, "000000", 6) == 0)) ); return bRetVal; } CloudGuardURN& CloudGuardURN::operator=(const CloudGuardURN &rhs) { if (this != &rhs) setUrn(rhs.getUrn()); return *this; } /** * Get the NSS part of the URN string... */ std::string CloudGuardURN::toNSS() const { std::string retVal (_urn, ::strlen(NAMESPACE)); return retVal; } /** * Set the URN strings. */ bool CloudGuardURN::setUrn(const std::string &urnStr) { bool bRetVal = true; std::vector urnParts; int nNumParts = SplitString2(urnStr, ':', urnParts); if ((nNumParts < 3) || (nNumParts > 6)) bRetVal = false; else { // check parts // 0 urn // 1 sl // 2 van // 3 pmo // 4 device // 5 doc if ((nNumParts > 5) && (urnParts[5] != "")) { if (validateURNPart(urnParts[2], SL_URN_VAN_LEN) && validateURNPart(urnParts[3], SL_URN_PMO_LEN) && validateURNPart(urnParts[4], SL_URN_DEV_LEN) && validateURNPart(urnParts[5], SL_URN_DOC_LEN)) { _type = PMO_DEVICE_DOCUMENT; _vanID = urnParts[2]; _pmoID = urnParts[3]; _deviceID = urnParts[4]; _docID = urnParts[5]; } else bRetVal = false; } else if ((nNumParts > 4) && (urnParts[4] != "")) { if (validateURNPart(urnParts[2], SL_URN_VAN_LEN) && validateURNPart(urnParts[3], SL_URN_PMO_LEN) && validateURNPart(urnParts[4], SL_URN_DEV_LEN) ) { _type = PMO_DEVICE; _vanID = urnParts[2]; _pmoID = urnParts[3]; _deviceID = urnParts[4]; _docID = ""; } else bRetVal = false; } else if ((nNumParts > 3) && (urnParts[3] != "")) { if (validateURNPart(urnParts[2], SL_URN_VAN_LEN) && validateURNPart(urnParts[3], SL_URN_PMO_LEN) ) { _type = PMO; _vanID = urnParts[2]; _pmoID = urnParts[3]; _deviceID = ""; _docID = ""; } else bRetVal = false; } else if ((nNumParts > 2) && (urnParts[2] != "")) { if (validateURNPart(urnParts[2], SL_URN_VAN_LEN) ) { _type = VAN; _vanID = urnParts[2]; _pmoID = ""; _deviceID = ""; _docID = ""; } else bRetVal = false; } if (bRetVal) _urn = urnStr; } return bRetVal; } bool CloudGuardURN::setUrn(const std::string &van, const std::string &pmo, const std::string &dev/* = ""*/, const std::string &doc/* = ""*/) { std::stringstream urnStrStream; urnStrStream << NAMESPACE << van << ":" << pmo << ":" << dev << ":" << doc; return setUrn(urnStrStream.str()); } /** * Get an URN as type X. */ CloudGuardURN CloudGuardURN::as(URN_TYPE nType) const { CloudGuardURN retVal; if (_type == nType) retVal = *this; else { switch (nType) { case VAN: retVal.setUrn(getVANID(), ""); break; case PMO: retVal.setUrn(getVANID(), getPMOID()); break; case PMO_DEVICE: retVal.setUrn(getVANID(), getPMOID(), getDeviceID()); break; case PMO_DEVICE_DOCUMENT: retVal.setUrn(getVANID(), getPMOID(), getDeviceID(), getDocumentID()); break; case INVALID: default: break; } } return retVal; } /** * Generate a unique (probabilistically anyway) UUID of length given. * Does not generate reserved values. * @param len * @return */ std::string CloudGuardURN::generateUUID(int len) { std::string uuidStr = PMO_ALL_ID; do { uuidStr = getUUID(); std::remove_if(uuidStr.begin(), uuidStr.end(), [] (std::string::value_type nChar) { return (nChar == '-'); }); if (static_cast(uuidStr.length()) > len) uuidStr = uuidStr.substr(0, len); std::transform(uuidStr.begin(), uuidStr.end(), uuidStr.begin(), std::bind2nd(std::ptr_fun(std::toupper), std::locale())); } while (isDoNotGenerateUUID(uuidStr)); return uuidStr; } /** * Reset an URN (clear it out). */ void CloudGuardURN::reset() { _urn = ""; _vanID = ""; _pmoID = ""; _deviceID = ""; _docID = ""; _type = INVALID; } namespace sequencelogic { std::ostream &operator<<(std::ostream &out, const CloudGuardURN *pUrn) { if (pUrn != NULL) out << pUrn->getUrn(); return out; } } namespace { /** * Validate URN parts... */ bool validateURNPart(const std::string &urnPart, int nLength) { bool bRetVal = true; if (urnPart.length() != static_cast(nLength)) bRetVal = false; else { const std::locale &loc = std::locale(); for (unsigned int i = 0; bRetVal && (i < urnPart.length()); ++i) { char tmpChar = urnPart[i]; bRetVal = (std::isdigit(tmpChar, loc) || (('a' <= tmpChar) && (tmpChar <= 'f')) || (('A' <= tmpChar) && (tmpChar <= 'F'))); } } return bRetVal; } /** * Generate a UUID. */ std::string getUUID() { #ifdef WIN32 UUID uuid; RPC_CSTR pTmpBuf; ::UuidCreate(&uuid); ::UuidToString(&uuid, &pTmpBuf); std::string retVal = reinterpret_cast (pTmpBuf); ::RpcStringFree(&pTmpBuf); return retVal; #else uuid_t uuid; uuid_generate_random (uuid); char retVal[37]; uuid_unparse (uuid, retVal); return retVal; #endif } }