Example #1
0
    /*
     * Uses the currently set locale to read a pre-defined file and then compares
     * the output with a reference file that is read with the UTF-8 functions.
     * These should of course be the same for this test to be successful.
     *
     * What encoded file should be read for a certain locale, and which reference file
     * should be used to test against is handled with a configurations file
     * that has the name "scxfile_test-locale-map.txt" that consists of multiple 
     * lines like this:
     * <name of locale> <name of encoded file> <name of reference file>
     * 
     * The "encoded file" is read with named locale active into an array.
     * The reference file is read with our own UTF-8 decoding routines, into 
     * another array. These two should result in exactly the same result for this
     * test to be successful.
     * 
     * If you're writing a new encoded or reference file, you'll at some point need
     * to see exactly what it contains byte-for-byte. The this command will be 
     * useful: "od -t x1 <filename>".
     *
     * If the current locale is not found in the configuration file, this results
     * in a warning.
     */
    void TestReadFilesWithPresetCharacterConversion()
    {
        bool found = false;

        std::wifstream locmap("./testfiles/scxfile_test-locale-map.txt");
        wstring locName, encodedFileName, referenceFileName;

        // This is the name of the currently selected locale for the Ctype facet
        wstring presetLocaleName(SCXLocaleContext::GetCtypeName());

        if (presetLocaleName == L"C" || presetLocaleName == L"POSIX") {
            SCXUNIT_WARNING(L"Testing with C/POSIX locale is meaningless.");
        }

        wcout << "\nTesting preset locale " << presetLocaleName << endl;

        while (locmap) {
            locmap >> locName >> encodedFileName >> referenceFileName;

            // Diagnostic output
            // wcout << "Name " << locName << endl;
            // wcout << "File " << encodedFileName << endl;
            // wcout << "File " << referenceFileName << endl;

            if (locName == presetLocaleName) {
                // wcout << L"found " << locName << endl;
                found = true;
                break;
            }
        }

        if (!found) {
            SCXUNIT_WARNING(L"Can't find preset locale " + presetLocaleName + L" in locale-map.txt. Please add it and test again.");
            return;
        }

        SCXFilePath encodedFileFP;
        encodedFileFP.SetDirectory(L"./testfiles/");
        encodedFileFP.SetFilename(encodedFileName);

        SCXFilePath referenceFileFP;
        referenceFileFP.SetDirectory(L"./testfiles/");
        referenceFileFP.SetFilename(referenceFileName);

        SCXStream::NLFs nlfs;
        vector<wstring> localLines;
        vector<wstring> utf8Lines;
        SCXFile::ReadAllLines(encodedFileFP, localLines, nlfs);
        SCXFile::ReadAllLinesAsUTF8(referenceFileFP, utf8Lines, nlfs);
        CPPUNIT_ASSERT_MESSAGE("Failure for preset locale " + locale().name(),
                               localLines == utf8Lines);

    }
    /**
     From the necessary file, read the domains and return a unique list
     of potential domains.
     
     */
    vector<SCXFilePath> WebLogicFileReader::GetDomains()
    {
        SCX_LOGTRACE(m_log, L"WebLogicFileReader::GetDomains");

        vector<SCXFilePath> domains;

        // Logic necessary for reading WebLogic 11g domains
        SCXFilePath domainRegistryXml;
        domainRegistryXml.SetDirectory(m_installationPath);
        domainRegistryXml.SetFilename(
                WEBLOGIC_DOMAIN_REGISTRY_XML_FILENAME);
        
        if (DoesDomainRegistryXmlExist(domainRegistryXml))
        {
            ReadDomainRegistryXml(domainRegistryXml, domains);
        }

        // Logic necessary for reading WebLogic 10g domains
        SCXFilePath nodemanagerDomains;
        nodemanagerDomains.SetDirectory(m_installationPath);
        nodemanagerDomains.AppendDirectory(WEBLOGIC_NODEMANAGER_DOMAINS_DIRECTORY);
        nodemanagerDomains.SetFilename(WEBLOGIC_NODEMANAGER_DOMAINS_FILENAME);

        if (DoesNodemanagerDomainsExist(nodemanagerDomains))
        {
            ReadNodemanagerDomains(nodemanagerDomains, domains);
        }
        
        // There may be duplicates in the list, it is necessary to
        // sort the list of domains and return only the unique instances.
        sort(domains.begin(), domains.end(), SortPath());
        vector<SCXFilePath>::iterator tmp = 
                unique(domains.begin(), domains.end());
        domains.resize(tmp-domains.begin());
                
        SCX_LOGTRACE(m_log, 
                wstring(L"WebLogicFileReader::GetDomains() - ").
                append(L"Found ").append(StrFrom(domains.size())).append(L" domain(s)"));

        return domains;
    }
Example #3
0
 //! Search for an existing filename using case insensitive comparision
 SCXFilePath SearchExistingFilename(const wstring &directory, const wstring &name) {
     vector<SCXCoreLib::SCXFilePath> files = SCXDirectory::GetFiles(directory);
     for (size_t nr = 0; nr < files.size(); nr++) {
         if (StrCompare(files[nr].GetFilename(), name, true) == 0) {
             return files[nr];
         }
     }
     // No existing name found, return the original path
     SCXFilePath original;
     original.SetDirectory(directory);
     original.SetFilename(name);
     return original;
 }
Example #4
0
    /**
        Creates a temp file and writes to it

        \param[in]  fileContent    Content to write to file.
        \returns    Complete path of newly created file.

     */
    SCXFilePath SCXFile::CreateTempFile(const std::wstring& fileContent) {
        /**
         * The code below behaves as it does because of limitations in the
         * various temp file functions.
         *
         * \li Use the tempnam function to retrieve an "appropriate" directory
         *     to store files in.
         * \li Only use the directory part of what is returned and append a
         *     pattern to use for creating temporary file.
         * \li Use the pattern as argument to mkstemp which is the recommended
         *     function since it avoids race conditions.
         *
         */
        SCXFilePath pattern;
        char* fp = tempnam(0, 0);
        if (fp == 0) {
            throw SCXInternalErrorException(
                UnexpectedErrno(L"Failed to find an appropriate temporary file directory", errno),
                SCXSRCLOCATION);
        }

        try
        {
            pattern = SCXFileSystem::DecodePath(fp);
        }
        catch ( SCXCoreLib::SCXException& e )
        {
            free(fp);
            fp = 0;
            SCXRETHROW(e, L"Unable to decode file path." );
        }

        free(fp);
        fp = 0;
        pattern.SetFilename(L"scxXXXXXX");
        std::string patternString = SCXFileSystem::EncodePath(pattern);
        std::vector<char> buf;

        buf.resize( patternString.length()+1, 0 );
        strcpy(&buf[0], patternString.c_str());

        mode_t oldUmask = umask(077);
        int fileDescriptor = mkstemp(&buf[0]);
        umask(oldUmask);

        if (fileDescriptor == -1) {
            std::wstring problem(L"Failed to create temporary file from pattern " + pattern.Get());
            throw SCXInternalErrorException(UnexpectedErrno(problem, errno), SCXSRCLOCATION);
        }

        SCXFilePath filepath = SCXFileSystem::DecodePath(&buf[0]);

        std::ostringstream fileContentStream;
        SCXStream::WriteAsUTF8(fileContentStream, fileContent);
        std::string fileContentUTF8 = fileContentStream.str();
        ssize_t written = write(fileDescriptor, fileContentUTF8.c_str(), fileContentUTF8.length());
        if (written == -1) {
            std::wstring problem(L"Failed to write to temporary file " + filepath.Get());
            close(fileDescriptor);
            throw SCXInternalErrorException(UnexpectedErrno(problem, errno), SCXSRCLOCATION);
        }

        close(fileDescriptor);
        return filepath;
    }
Example #5
0
/**
   main function.

   \param argc size of \a argv[]
   \param argv array of string pointers from the command line.
   \returns 0 on success, otherwise, 1 on error.

   Usage: scxgencert [-d domain]  [-h hostname] [-g targetpath] [-e days] [-s days]
   \n -v             toggle the debug flag.
   \n -?             print the help message and exit.
   \n -g targetpath  target path where certificates should be written
   \n -s days        days to offset valid start date with
   \n -e days        days to offset valid end date with
   \n -d domain      domain name
   \n -h host        hostname
   \n -b bits        number of key bits (defaults to 2048)

   Result Code
   \n -1  an exception has occured
   \n  0  success
   \n >1  an error occured while executing the command.

*/
int main(int argc, char *argv[])
{
    // commandline switches
    const string helpFlag       ("-?");
    const string bitsFlag       ("-b");
    const string domainFlag     ("-d");
    const string enddaysFlag    ("-e");
    const string forceFlag      ("-f");
    const string generateFlag   ("-g");
    const string hostFlag       ("-h");
    const string startdaysFlag  ("-s");
    const string debugFlag      ("-v");
    const string testFlag       ("-t"); // Undocummented, for testing only

    // Control variables built from command line arguments (defaulted as needed by SCX)
    bool debugMode = false;
    bool testMode = false;
    bool doGenerateCert = false;
    wstring targetPath = L"/etc/opt/omi/ssl";
    int startDays = -365;
    int endDays = 7300;
#if defined(hpux) && defined(hppa)
    int bits = 1024;
#else
    int bits = 2048;
#endif

    SCXCoreLib::NameResolver mi;
    wstring hostname;
    wstring domainname;

    wstring specified_hostname;
    wstring specified_domainname;

    int i = 1;
    for (; i < argc; ++i)
    {
        if (debugFlag == argv[i])
        {
            debugMode = ! debugMode;
            wcout << L"Setting debugMode=" << (debugMode ? L"true" :L"false") << endl;
        }
        else if (helpFlag == argv[i])
        {
            usage(argv[0], 0);
        }
        else if (forceFlag == argv[i])
        {
            doGenerateCert = true;
        }
        else if(bitsFlag == argv[i])
        {
            if (++i >= argc)
            {
                wcout << L"Enter number of bits." << endl;
                usage(argv[0], 1);
            }
            bits = (int) SCXCoreLib::StrToLong(SCXCoreLib::StrFromUTF8(argv[i]));
            if (0 == bits || 0 != bits%512)
            {
                wcout << L"Bits must be non-zero dividable by 512." << endl;
                usage(argv[0], 1);
            }
        }
        else if(domainFlag == argv[i])
        {
            if (++i >= argc)
            {
                wcout << L"Enter a domain name." << endl;
                usage(argv[0], 1);
            }

            // Some platforms fail to convert if locale is not right (SLES 11 for instance).
            // Note we do not print domain name  because wcout will also fail to
            // properly convert, displaying a mangled string and further confusing
            // the user. Using cout is not an option because it will not print a
            // non-convertible string at all....
            try
            {
                specified_domainname = SCXCoreLib::StrFromMultibyte(argv[i], true);
            }
            catch(const SCXCoreLib::SCXStringConversionException &ex)
            {
                wcout << L"Not able to convert domain name. Consider adjusting your locale setting. Exiting." << endl;
                exit(3);
            }
        }
        else if(hostFlag == argv[i])
        {
            if (++i >= argc)
            {
                wcout << "Enter a hostname." << endl;
                usage(argv[0], 1);
            }

            // Host name is expected to be 7 bit so conversion is in most cases a no-op
            // If it fails prompt user and quit
            try
            {
                specified_hostname = SCXCoreLib::StrFromMultibyte(argv[i], true);
            }
            catch(const SCXCoreLib::SCXStringConversionException &e)
            {
                wcout << L"Not able to convert host name, \'" << argv[i] << "\'." << endl;
                wcout << L"Please specify a host name that uses only 7-bit ASCII characters." << endl;
                exit(4);
            }
        }
        else if (generateFlag == argv[i])
        {
            // Ensure the path argument exists.
            if (++i >= argc)
            {
                wcout << "Enter a target path to generate certificates." << endl;
                usage(argv[0], 1);
            }

            try
            {
                targetPath = SCXCoreLib::StrFromMultibyte(argv[i], true);
            }
            catch(SCXCoreLib::SCXStringConversionException)
            {
                wcout << L"Not able to convert target path, \'" << argv[i] << "\'." << endl;
                wcout << L"Consider adjusting your locale by changing the LC_CTYPE environment variable." << endl;
                exit(4);
            }
        }
        else if (startdaysFlag == argv[i])
        {
            // Ensure the value argument exists.
            if (++i >= argc)
            {
                wcout << "Enter a value for start days." << endl;
                usage(argv[0], 1);
            }
            startDays = (int) SCXCoreLib::StrToLong(SCXCoreLib::StrFromUTF8(argv[i]));
        }
        else if (enddaysFlag == argv[i])
        {
            // Ensure the value argument exists.
            if (++i >= argc || SCXCoreLib::StrToLong(SCXCoreLib::StrFromUTF8(argv[i])) == 0)
            {
                wcout << "Enter a non-zero value for end days." << endl;
                usage(argv[0], 1);
            }
            endDays = (int) SCXCoreLib::StrToLong(SCXCoreLib::StrFromUTF8(argv[i]));
        }
        else if (testFlag == argv[i])
        {
            testMode = true;
        }
        else
        {
            break;
        }
    }

    // Fail if all arguments are not used.
    if (i < argc) {
        wcout << L"Unused arguments:" << endl;
        for (; i < argc; ++i)
        {
            wcout << L"\t" << argv[i] << endl;
        }
        wcout << endl;
        usage(argv[0], 1);
    }

    hostname = specified_hostname;
    domainname = specified_domainname;

    if(hostname.empty())
    {
        std::string hostname_raw = "";
        try
        {
            // This can fail because there are string conversions done in GetHostname()
            hostname = mi.GetHostname(&hostname_raw);
        }
        catch(SCXCoreLib::SCXStringConversionException)
        {
            // Note: We should never see this because host names are s'pose to be 7 bit ASCII
            // Can get away with conversion of stdout here because we are dying, and can do it exactly once ...
            fwide(stdout, -1);
            cout << "Unable to convert default host name \'" << hostname_raw << "\'." << endl;
            cout << "This might be caused by a host name that contains UTF-8 characters that are invalid given your current locale." << endl;
            // MUST exit here, due to fwide() call above ... cannot call fwide() more than once w/out closing/reopening handle
            exit(3);
        }
        catch(SCXCoreLib::SCXErrnoERANGE_Exception &e)
        {
            cout << SCXCoreLib::StrToUTF8(e.Where()) << endl
                 << SCXCoreLib::StrToUTF8(e.What()) << endl;
            exit(3);
        }
    }

    // If the user did not supply a domain name, use default.
    if(domainname.empty())
    {
        domainname = mi.GetDomainname();
    }

    if(debugMode)
    {
        // Show what we would have used - even if user specified specific host/domain
        wcout << L"Generated hostname:   \"" << mi.GetHostname()
              << L"\" (" << mi.DumpSourceString(mi.GetHostnameSource()) << L")" << endl;
        wcout << L"Generated domainname: \"" << mi.GetDomainname()
              << L"\" (" << mi.DumpSourceString(mi.GetDomainnameSource()) << L")" << endl << endl;

        wcout << L"Using Host Name:     " << hostname << endl;
        wcout << L"Using Domain Name:   " << domainname << endl;
        wcout << L"Start Days:          " << startDays << endl;
        wcout << L"End Days:            " << endDays << endl;
        wcout << L"Cert Length:         " << bits << endl;
        wcout << L"Target Path:         " << targetPath << endl << endl;
    }

    // We only generate the certificate if "-f" was specified, or if no certificate exists
    // (Note: If no certificate exists, we should still return a success error code!)
    if (!doGenerateCert)
    {
        SCXFilePath keyPath;
        keyPath.SetDirectory(targetPath);
        keyPath.SetFilename(L"omikey.pem");

        SCXCoreLib::SCXFileInfo keyInfo(keyPath);
        if ( ! keyInfo.Exists() )
        {
            doGenerateCert = true;
        }
        else
        {
            wcerr << L"Certificate not generated - '" << keyPath.Get() << "' exists" << endl;
        }
    }

    int rc = 0;
    if (doGenerateCert)
    {
        rc = DoGenerate(targetPath, startDays, endDays, hostname, domainname, bits, debugMode);

        // When the domain or host name is specified through the command line we do not allow recovery.
        // Add an exception to this rule for testing purposes.
        if  ( (specified_domainname.empty() && specified_hostname.empty()) || testMode )
        {
            // When the domain or hostname is not RFC compliant, openssl fails to generate a cerificate.
            // We will try to fallback.
            if ( rc == ERROR_CERT_GENERATE )
            {
                wcout << "Hostname or domain likely not RFC compliant, trying fallback: \"localhost.local\"" << endl;
                rc = DoGenerate(targetPath, startDays, endDays, L"localhost", L"local", bits, debugMode);
            }
        }
    }

    if (debugMode)
    {
        wcout << L"return code = " << rc << endl;
    }
    exit(rc);
}
Example #6
0
/**
    Generate Key and Certificate
    \param[in] targetPath Path where the certificates should be written.
    \param[in] startDays Days to offset valid start date.
    \param[in] endDays Days to offset valid end date.
    \param[in] hostname Hostname to put into the certificate.
    \param[in] domainname Domainname to put into the certificate.
    \param[in] bits Number of bits in key.
    \returns Zero on success.
*/
static int DoGenerate(const wstring & targetPath, int startDays, int endDays,
                      const wstring & hostname, const wstring & domainname,
                      int bits, bool bDebug)
{
    // Output what we'll be using for certificate generation
    wcout << L"Generating certificate with hostname=\"" << hostname << L"\"";
    if (domainname.length())
    {
        wcout << L", domainname=\"" << domainname << L"\"" ;
    }
    wcout << endl;

    std::wstring c_certFilename(L"omi-host-");  // Remainder must be generated
    const std::wstring c_keyFilename(L"omikey.pem");

    int rc = 0;
    // Do not allow an exception to slip out
    try
    {
        // The certificate filename must be something like omi-host-<hostname>.pem; generate it
        c_certFilename.append(hostname);
        c_certFilename.append(L".pem");

        SCXFilePath keyPath;
        keyPath.SetDirectory(targetPath);
        keyPath.SetFilename(c_keyFilename);
        SCXFilePath certPath;
        certPath.SetDirectory(targetPath);
        certPath.SetFilename(c_certFilename);
        SCXSSLCertificateLocalizedDomain cert(keyPath, certPath, startDays, endDays, hostname, domainname, bits);

        std::ostringstream debugChatter;
        debugChatter << endl;

        try
        {
            cert.Generate(debugChatter);
        }
        catch(const SCXCoreLib::SCXStringConversionException &ex)
        {
            if(bDebug)
                wcout << debugChatter.str().c_str();

            wcerr  << endl << "Generation of certificate raised an exception" << endl;
            wcerr << ex.Where() << endl;
            wcerr << ex.What() << endl;

            return 2;
        }
        catch(const SCXSSLException &e_ssl)
        {
            if(bDebug)
            {
                wcout << debugChatter.str().c_str();
                debugChatter.str("");
            }

            wcerr << e_ssl.What() << endl;
            return ERROR_CERT_GENERATE;
        }
        catch(const SCXCoreLib::SCXFilePathNotFoundException &ex)
        {
            wcerr  << endl << "Generation of certificate raised an exception" << endl;
            wcerr  << "Output path \"" << ex.GetPath().Get() << "\" does not exist" << endl;
            return 4;
        }

        if(bDebug)
        {
            wcout << debugChatter.str().c_str();
        }

        /*
        ** We actually have three certificate files in total:
        **
        ** Certificate File: omi-host-<hostname>.pem  (public)
        ** Key File:         omi-key.pem              (private)
        ** Soft link:        omi.pem  (soft link to certificate file, used by openwsman)
        **
        **
        ** Create the soft link to point to the certificate file.
        */

        SCXFilePath fpLinkFile;
        fpLinkFile.SetDirectory(targetPath);
        fpLinkFile.SetFilename(L"omi.pem");

        std::string sLinkFile = SCXCoreLib::StrToMultibyte(fpLinkFile.Get());
        std::string sCertFile = SCXCoreLib::StrToMultibyte(certPath.Get());

        rc = unlink(sLinkFile.c_str());
        if (0 != rc && ENOENT != errno) {
            throw SCXCoreLib::SCXErrnoFileException(L"unlink", fpLinkFile.Get(), errno, SCXSRCLOCATION);
        }

        rc = symlink(sCertFile.c_str(), sLinkFile.c_str());
        if (0 != rc) {
            throw SCXCoreLib::SCXErrnoFileException(L"unlink", fpLinkFile.Get(), errno, SCXSRCLOCATION);
        }

        /*
        ** Finally, make sure the permissions are right:
        ** The pub key gets 444, the priv key gets 400
        */

        rc = chmod(sCertFile.c_str(), 00444);
        if (0 != rc) {
            throw SCXCoreLib::SCXErrnoFileException(L"chmod", certPath.Get(), errno, SCXSRCLOCATION);
        }

        std::string sKeyFile = SCXCoreLib::StrToMultibyte(keyPath.Get());
        rc = chmod(sKeyFile.c_str(), 00400);
        if (0 != rc) {
            throw SCXCoreLib::SCXErrnoFileException(L"chmod", keyPath.Get(), errno, SCXSRCLOCATION);
        }
    }
    catch(const SCXCoreLib::SCXException & e)
    {
        wcout << e.Where() << endl
              << e.What() << endl;
        // use -1 to indicate an exception occured.
        rc = -1;
    }
    return rc;
}