int main()

in source/code/shared/tools/scx_ssl_config/scx_ssl_config.cpp [69:340]


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 clientcertFlag ("-c");
    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;
    bool clientCert = false;
#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 (clientcertFlag == argv[i])
        {
        	clientCert = true;
        }
        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!)
    int rc = 0;
    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;
            // Upgrade from 2012R2 should update the key ownership to omi:omi
            rc = UpdateKeyOwnership(keyPath);
        }
    }

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

        // 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);
}