示例#1
0
void DJCheckValidComputerName(
    PCSTR pszComputerName,
    LWException **exc)
{
    size_t dwLen;
    size_t i;

    if (IsNullOrEmptyString(pszComputerName))
    {
        LW_RAISE_EX(exc, ERROR_INVALID_COMPUTERNAME, "Invalid hostname", "Hostname is empty");
        goto cleanup;
    }

    dwLen = strlen(pszComputerName);

    //Zero length hostnames are already handled above
    if (dwLen > 63)
    {
        LW_RAISE_EX(exc, ERROR_INVALID_COMPUTERNAME, "Invalid hostname", "The name '%s' is %d characters long. Hostnames may only be up to 63 characters long.", pszComputerName, dwLen);
        goto cleanup;
    }

    if (!strcasecmp(pszComputerName, "linux") ||
        !strcasecmp(pszComputerName, "localhost"))
    {
        LW_RAISE_EX(exc, ERROR_INVALID_COMPUTERNAME, "Invalid hostname", "The hostname may not be 'linux' or 'localhost'.");
        goto cleanup;
    }

    if (pszComputerName[0] == '-' || pszComputerName[dwLen - 1] == '-')
    {
        LW_RAISE_EX(exc, ERROR_INVALID_COMPUTERNAME, "Invalid hostname", "The hostname may not start or end with a hyphen.");
        goto cleanup;
    }

    for(i = 0; i < dwLen; i++)
    {
        char c = pszComputerName[i];
        if (!(c == '-' ||
              (c >= 'a' && c <= 'z') ||
              (c >= 'A' && c <= 'Z') ||
              (c >= '0' && c <= '9'))) {
            LW_RAISE_EX(exc, ERROR_INVALID_COMPUTERNAME, "Invalid hostname", "The given hostname, '%s', contains a '%c'. Valid hostnames may only contain hyphens, letters, and digits.", pszComputerName, c);
            goto cleanup;
        }
    }

cleanup:
    ;
}
示例#2
0
static QueryResult QueryStopDaemons(const JoinProcessOptions *options, LWException **exc)
{
    DWORD dwError = 0;
    BOOLEAN running;
    QueryResult result = FullyConfigured;

    if (options->enableMultipleJoins)
    {
        result = NotApplicable;
        goto cleanup;
    }

    /* Check for gpagentd */

    dwError = DJGetServiceStatus("gpagent", &running);
    if (dwError == LW_ERROR_NO_SUCH_SERVICE)
    {
        /* The gpagentd may not be installed so ignore */
        running = FALSE;
        dwError = 0;
    }
    if (dwError)
    {
        LW_RAISE_EX(exc, dwError,
                "Received error while querying lwsmd.",
                "Received error while querying lwsmd.");
        goto cleanup;
    }

    if(running)
        result = NotConfigured;
    
cleanup:
    return result;
}
示例#3
0
static QueryResult QueryStartDaemons(const JoinProcessOptions *options, LWException **exc)
{
    DWORD dwError = 0;
    BOOLEAN running;
    QueryResult result = FullyConfigured;
    const ModuleState *stopState = DJGetModuleStateByName((JoinProcessOptions *)options, "stop");

    if(!options->joiningDomain)
    {
        result = NotApplicable;
        goto cleanup;
    }

    dwError = DJGetServiceStatus("gpagent", &running);
    if (dwError == LW_ERROR_NO_SUCH_SERVICE)
    {
        /* The gpagentd may not be installed so ignore */
        running = TRUE;
        dwError = 0;
    }
    if (dwError)
    {
        LW_RAISE_EX(exc, dwError,
                "Received error while querying lwsmd.",
                "Received error while querying lwsmd.");
        goto cleanup;
    }

    if(!running)
        result = NotConfigured;

    if(stopState != NULL && stopState->runModule)
        result = NotConfigured;

cleanup:
    return result;
}
示例#4
0
BOOLEAN FindSshAndConfig(
        PCSTR pSshOrSshd,
        PSTR *ppSshBinary,
        PSTR *ppSshConfig,
        LWException **ppExc)
{
    DWORD ceError = ERROR_SUCCESS;
    /* Mac OS X stores the configuration in /etc */
    /* CSW ssh on Solaris uses /opt/csw/etc/ssh */
    const PCSTR ppSshConfigPaths[] = {
        "/etc/ssh",
        "/opt/ssh/etc",
        "/usr/local/etc",
        "/etc",
        "/etc/openssh",
        "/usr/openssh/etc",
        "/opt/csw/etc/ssh",
        NULL
    };
    DWORD foundConfigCount = 0;
    PSTR* ppFoundConfigs = NULL;

    /* Solaris Sparc 10 stores sshd in /usr/lib/ssh */
    /* Experian says their sshd is at /usr/openssh/sbin/sshd */
    /* CSW ssh on Solaris uses /opt/csw/sbin/sshd */
    const PCSTR ppSshBinaryPaths[] = {
        "/usr/sbin",
        "/opt/ssh/sbin",
        "/usr/local/sbin",
        "/usr/bin",
        "/opt/ssh/bin",
        "/usr/local/bin",
        "/usr/lib/ssh",
        "/usr/openssh/sbin",
        "/usr/openssh/bin",
        "/opt/csw/sbin",
        "/opt/csw/bin",
        "/opt/ssh/hpux64/sbin",
        NULL
    };
    DWORD foundBinaryCount = 0;
    PSTR* ppFoundBinaries = NULL;
    PSTR pConfigFilename = NULL;
    PSTR pBinaryFilename = NULL;
    PSTR pFoundConfigList = NULL;
    PSTR pFoundBinaryList = NULL;
    DWORD index = 0;

    *ppSshBinary = NULL;
    *ppSshConfig = NULL;

    LW_CLEANUP_CTERR(ppExc, CTAllocateStringPrintf(
        &pConfigFilename, "%s_config", pSshOrSshd));
    LW_CLEANUP_CTERR(ppExc, CTAllocateStringPrintf(
        &pBinaryFilename, "%s", pSshOrSshd));

    ceError = LwFindFilesInPaths(
                    pConfigFilename,
                    LWFILE_REGULAR,
                    ppSshConfigPaths,
                    &foundConfigCount,
                    &ppFoundConfigs);
    LW_CLEANUP_CTERR(ppExc, ceError);

    ceError = LwRemoveDuplicateInodes(
                    &foundConfigCount,
                    ppFoundConfigs);
    LW_CLEANUP_CTERR(ppExc, ceError);

    ceError = LwFindFilesInPaths(
                    pBinaryFilename,
                    LWFILE_REGULAR,
                    ppSshBinaryPaths,
                    &foundBinaryCount,
                    &ppFoundBinaries);
    LW_CLEANUP_CTERR(ppExc, ceError);

    ceError = LwRemoveDuplicateInodes(
                    &foundBinaryCount,
                    ppFoundBinaries);
    LW_CLEANUP_CTERR(ppExc, ceError);

    // Ssh version A.04.40.005 on HP-UX Itanimum has these paths:
    //  /opt/ssh/hpux64/sbin/sshd (ELF-64 IA64)
    //  /opt/ssh/sbin/sshd (ELF-32 IA64)
    //  /usr/sbin/sshd (symlink to /opt/ssh/hpux64/sbin/sshd)
    //
    // Ssh version A.04.30.007 on HP-UX Itanimum has these paths:
    //  /opt/ssh/hpux64/sbin/sshd (ELF-64 IA64)
    //  /opt/ssh/sbin/sshd (ELF-32 IA64)
    //  /usr/sbin/sshd (symlink to /opt/ssh/sbin/sshd)
    //
    // Both files point to the same config path. An exception must exist for
    // this case since the inodes are different for the two architectures.
    //
    // The symlink at /usr/sbin/sshd wins the duplication removal process. So
    // if it is found, the other path must be removed.
    
    for (index = 0; index < foundBinaryCount; index++)
    {
        if (!strcmp(ppFoundBinaries[index], "/usr/sbin/sshd"))
        {
            // Remove /opt/ssh/sbin/sshd or /opt/ssh/hpux64/sbin/sshd if they
            // are in the list
            for (index = 0; index < foundBinaryCount; index++)
            {
                if (!strcmp(ppFoundBinaries[index], "/opt/ssh/sbin/sshd") ||
                    !strcmp(ppFoundBinaries[index],
                        "/opt/ssh/hpux64/sbin/sshd"))
                {
                    LW_SAFE_FREE_STRING(ppFoundBinaries[index]);
                    memmove(&ppFoundBinaries[index],
                            &ppFoundBinaries[index+1],
                            (foundBinaryCount - index - 1) *
                                sizeof(ppFoundBinaries[index]));
                    foundBinaryCount--;
                    break;
                }
            }
            break;
        }
    }

    if ((foundConfigCount | foundBinaryCount) > 0 && foundConfigCount != foundBinaryCount)
    {
        ceError = CombinePaths(
                        foundConfigCount,
                        ppFoundConfigs,
                        &pFoundConfigList);
        LW_CLEANUP_CTERR(ppExc, ceError);

        ceError = CombinePaths(
                        foundBinaryCount,
                        ppFoundBinaries,
                        &pFoundBinaryList);
        LW_CLEANUP_CTERR(ppExc, ceError);

        if ((foundConfigCount | foundBinaryCount) == 1)
        {
            ceError = ERROR_FILE_NOT_FOUND;
        }
        else
        {
            ceError = ERROR_DUPLICATE_SERVICE_NAME;
        }

        LW_RAISE_EX(ppExc, ceError,
                "Unable to find ssh binary",
"A %s config file was at %s, and a %s binary file was found at %s. Exactly one config file and one binary must exist on the system in a standard location. Uninstall any unused copies of ssh.",
                pSshOrSshd,
                pFoundConfigList,
                pSshOrSshd,
                pFoundBinaryList);
    }

    if (foundConfigCount == 1)
    {
        DJ_LOG_INFO("Found config file %s", ppFoundConfigs[0]);
        *ppSshConfig = ppFoundConfigs[0];
        ppFoundConfigs[0] = NULL;
    }
    if (foundBinaryCount == 1)
    {
        DJ_LOG_INFO("Found binary %s", ppFoundBinaries[0]);
        *ppSshBinary = ppFoundBinaries[0];
        ppFoundBinaries[0] = NULL;
    }

cleanup:
    if (ppFoundConfigs)
    {
        LwFreeStringArray(
                ppFoundConfigs,
                foundConfigCount);
    }
    if (ppFoundBinaries)
    {
        LwFreeStringArray(
                ppFoundBinaries,
                foundBinaryCount);
    }
    LW_SAFE_FREE_STRING(pConfigFilename);
    LW_SAFE_FREE_STRING(pBinaryFilename);
    LW_SAFE_FREE_STRING(pFoundConfigList);
    LW_SAFE_FREE_STRING(pFoundBinaryList);
    return (foundConfigCount == 1);
}
示例#5
0
void
DJManageDaemons(
    BOOLEAN bStart,
    LWException **exc
    )
{
    BOOLEAN bFileExists = TRUE;
    FILE* fp = NULL;
    LWException *innerExc = NULL;
    int i;
    PLSA_LOG_INFO pLogInfo = NULL;
    BOOLEAN bLsassContacted = FALSE;
    DWORD dwError = 0;
    LW_HANDLE hLsa = NULL;

    LW_CLEANUP_CTERR(exc, CTCheckFileExists(PWGRD, &bFileExists));
    if(bFileExists)
    {
        //Shutdown pwgr (a nscd-like daemon) on HP-UX because it only handles
        //usernames up to 8 characters in length.
        LW_TRY(exc, DJStartStopDaemon("pwgr", FALSE, &LW_EXC));
        LW_CLEANUP_CTERR(exc, CTRunSedOnFile(PWGRD, PWGRD, FALSE, "s/=1/=0/"));
    }

    if(bStart)
    {
        // Set registry value for gpagentd to autostart.
        dwError = SetBooleanRegistryValue("Services\\gpagent", "Autostart", TRUE);
        // Trigger gpagentd start
        dwError = DJStartService("gpagent");

        // Make sure lsass is responding
        bLsassContacted = FALSE;
        for (i = 0; !bLsassContacted && i < 30; i++)
        {
            DJ_LOG_INFO("Trying to contact lsassd");
            if (hLsa)
            {
                LsaCloseServer(hLsa);
                hLsa = NULL;
            }
            dwError = LsaOpenServer(&hLsa);
            if (dwError == ERROR_FILE_NOT_FOUND ||
                    dwError == LW_ERROR_ERRNO_ECONNREFUSED)
            {
                DJ_LOG_INFO("Failed with %d", dwError);
                dwError = 0;
                sleep(1);
                continue;
            }
            LW_CLEANUP_CTERR(exc, dwError);
            LW_CLEANUP_CTERR(exc, LsaGetLogInfo(hLsa, &pLogInfo));
            bLsassContacted = TRUE;
        }
        if (!bLsassContacted)
        {
            LW_RAISE_EX(exc, ERROR_SERVICE_NOT_ACTIVE, "Unable to reach lsassd", "The lsass daemon could not be reached for 30 seconds after trying to start it. Please verify it is running.");
            goto cleanup;
        }
    }
    else
    {
        dwError = SetBooleanRegistryValue("Services\\gpagent", "Autostart", FALSE);

        dwError = DJStopService("gpagent");
    }

cleanup:
    CTSafeCloseFile(&fp);
    if (pLogInfo)
    {
        LsaFreeLogInfo(pLogInfo);
    }
    if (hLsa)
    {
        LsaCloseServer(hLsa);
    }

    LW_HANDLE(&innerExc);
}
示例#6
0
void DoLeaveNew(int argc, char **argv, int columns, LWException **exc)
{
    JoinProcessOptions options;
    BOOLEAN advanced = FALSE;
    BOOLEAN preview = FALSE;
    DynamicArray enableModules, disableModules, ignoreModules;
    DynamicArray detailModules;
    size_t i;
    PSTR moduleDetails = NULL;
    PSTR wrapped = NULL;
    int passwordIndex = -1;

    DJZeroJoinProcessOptions(&options);
    memset(&enableModules, 0, sizeof(enableModules));
    memset(&disableModules, 0, sizeof(disableModules));
    memset(&ignoreModules, 0, sizeof(ignoreModules));
    memset(&detailModules, 0, sizeof(detailModules));

    while(argc > 0 && CTStrStartsWith(argv[0], "--"))
    {
        if(!strcmp(argv[0], "--advanced"))
            advanced = TRUE;
        else if(!strcmp(argv[0], "--preview"))
            preview = TRUE;
        else if(argc < 2)
        {
            LW_RAISE(exc, LW_ERROR_SHOW_USAGE);
            goto cleanup;
        }
        else if(!strcmp(argv[0], "--enable"))
        {
            LW_CLEANUP_CTERR(exc, CTArrayAppend(&enableModules, sizeof(PCSTR *), &argv[1], 1));
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--disable"))
        {
            if(!strcmp(argv[1], "ssh")){
                options.ignoreSsh = TRUE;
            }
            else {
                options.ignoreSsh = FALSE;
                LW_CLEANUP_CTERR(exc, CTArrayAppend(&disableModules, sizeof(PCSTR *), &argv[1], 1));
            }
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--ignore"))
        {
            LW_CLEANUP_CTERR(exc, CTArrayAppend(&ignoreModules, sizeof(PCSTR *), &argv[1], 1));
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--details"))
        {
            LW_CLEANUP_CTERR(exc, CTArrayAppend(&detailModules, sizeof(PCSTR *), &argv[1], 1));
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--multiple"))
        {
            options.enableMultipleJoins = TRUE;
            LW_CLEANUP_CTERR(exc, CTStrdup(argv[1], &options.domainName));
            argv++;
            argc--;
        }
        else
        {
            LW_RAISE(exc, LW_ERROR_SHOW_USAGE);
            goto cleanup;
        }
        argv++;
        argc--;
    }

    if(argc == 2)
    {
        LW_CLEANUP_CTERR(exc, CTStrdup(argv[1], &options.password));
        passwordIndex = 1;
    }
    else if(argc > 2)
    {
        LW_RAISE(exc, LW_ERROR_SHOW_USAGE);
        goto cleanup;
    }
    options.joiningDomain = FALSE;

    DJ_LOG_INFO("Domainjoin invoked with %d arg(s) to the leave command:", argc);
    for(i = 0; i < argc; i++)
    {
        DJ_LOG_INFO("    [%s]", i == passwordIndex ? "<password>" : argv[i]);
    }

    if(argc > 0)
    {
        LW_CLEANUP_CTERR(exc, CTStrdup(argv[0], &options.username));
    }

    options.warningCallback = PrintWarning;
    options.showTraces = advanced;
    LW_CLEANUP_CTERR(exc, DJGetComputerName(&options.computerName));

    LW_TRY(exc, DJInitModuleStates(&options, &LW_EXC));

    for(i = 0; i < enableModules.size; i++)
    {
        PCSTR module = *(PCSTR *)CTArrayGetItem(
                    &enableModules, i, sizeof(PCSTR));
        if(CTArrayFindString(&disableModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being disabled and enabled", module);
            goto cleanup;
        }
        if(CTArrayFindString(&ignoreModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being ignored and enabled", module);
            goto cleanup;
        }
        LW_TRY(exc, DJSetModuleDisposition(&options, module, EnableModule, &LW_EXC));
    }

    for(i = 0; i < disableModules.size; i++)
    {
        PCSTR module = *(PCSTR *)CTArrayGetItem(
                    &disableModules, i, sizeof(PCSTR));
        if(CTArrayFindString(&enableModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being disabled and enabled", module);
            goto cleanup;
        }
        if(CTArrayFindString(&ignoreModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being disabled and ignored", module);
            goto cleanup;
        }
        LW_TRY(exc, DJSetModuleDisposition(&options, module, DisableModule, &LW_EXC));
    }

    for(i = 0; i < ignoreModules.size; i++)
    {
        PCSTR module = *(PCSTR *)CTArrayGetItem(
                    &ignoreModules, i, sizeof(PCSTR));
        if(CTArrayFindString(&enableModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being ignored and enabled", module);
            goto cleanup;
        }
        if(CTArrayFindString(&disableModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being ignored and disabled", module);
            goto cleanup;
        }
        LW_TRY(exc, DJSetModuleDisposition(&options, module, IgnoreModule, &LW_EXC));
    }

    for(i = 0; i < detailModules.size; i++)
    {
        PCSTR module = *(PCSTR *)CTArrayGetItem(
                    &detailModules, i, sizeof(PCSTR));
        ModuleState *state = DJGetModuleStateByName(&options, module);
        if(state == NULL)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Unable to find module.", "Please check the spelling of '%s'. This module cannot be found", module);
            goto cleanup;
        }
        PrintModuleState(state);
    }
    if(detailModules.size > 0)
    {
        PrintStateKey();
    }
    for(i = 0; i < detailModules.size; i++)
    {
        PCSTR module = *(PCSTR *)CTArrayGetItem(
                    &detailModules, i, sizeof(PCSTR));
        ModuleState *state = DJGetModuleStateByName(&options, module);
        CT_SAFE_FREE_STRING(moduleDetails);
        CT_SAFE_FREE_STRING(wrapped);
        LW_TRY(exc, moduleDetails = state->module->GetChangeDescription(&options, &LW_EXC));
        LW_CLEANUP_CTERR(exc, CTWordWrap(moduleDetails, &wrapped, 4, columns));
        fprintf(stdout, "\nDetails for '%s':\n%s\n", state->module->longName, wrapped);
    }
    if(detailModules.size > 0)
        goto cleanup;

    LW_TRY(exc, PrintJoinHeader(&options, &LW_EXC));

    if(preview)
    {
        PrintModuleStates(advanced, &options);
        if(!advanced)
            LW_TRY(exc, DJCheckRequiredEnabled(&options, &LW_EXC));
        goto cleanup;
    }

    LW_TRY(exc, DJCheckRequiredEnabled(&options, &LW_EXC));

    if (options.username != NULL && IsNullOrEmptyString(options.password))
    {
        CT_SAFE_FREE_STRING(options.password);

        LW_CLEANUP_CTERR(exc, FillMissingPassword(options.username,
                    &options.password));
    }

    LW_TRY(exc, DJRunJoinProcess(&options, &LW_EXC));
    fprintf(stdout, "SUCCESS\n");

cleanup:
    DJFreeJoinProcessOptions(&options);
    CTArrayFree(&enableModules);
    CTArrayFree(&disableModules);
    CTArrayFree(&ignoreModules);
    CTArrayFree(&detailModules);
    CT_SAFE_FREE_STRING(moduleDetails);
    CT_SAFE_FREE_STRING(wrapped);
}
示例#7
0
void DoJoin(int argc, char **argv, int columns, LWException **exc)
{
    JoinProcessOptions options;
    BOOLEAN advanced = FALSE;
    BOOLEAN preview = FALSE;
    DynamicArray enableModules, disableModules, ignoreModules;
    DynamicArray detailModules;
    size_t i;
    int passwordIndex = -1;
    PSTR moduleDetails = NULL;
    PSTR wrapped = NULL;

    DJZeroJoinProcessOptions(&options);
    memset(&enableModules, 0, sizeof(enableModules));
    memset(&disableModules, 0, sizeof(disableModules));
    memset(&ignoreModules, 0, sizeof(ignoreModules));
    memset(&detailModules, 0, sizeof(detailModules));

    while(argc > 0 && CTStrStartsWith(argv[0], "--"))
    {
        if(!strcmp(argv[0], "--advanced"))
            advanced = TRUE;
        else if(!strcmp(argv[0], "--preview"))
            preview = TRUE;
        else if(!strcmp(argv[0], "--ignore-firewall-ntp"))
        {
            printf("Warning: --ignore-firewall-ntp is deprecated. This behavior is now default.\n");
        }
        else if(!strcmp(argv[0], "--ignore-pam"))
            options.ignorePam = TRUE;
        else if(!strcmp(argv[0], "--notimesync"))
            options.disableTimeSync = TRUE;
        else if(!strcmp(argv[0], "--multiple"))
            options.enableMultipleJoins = TRUE;
        else if(!strcmp(argv[0], "--nohosts"))
        {
            PCSTR module = "hostname";
            LW_CLEANUP_CTERR(exc, CTArrayAppend(&disableModules, sizeof(PCSTR), &module, 1));
        }
        else if(argc < 2)
        {
            LW_RAISE(exc, LW_ERROR_SHOW_USAGE);
            goto cleanup;
        }
        else if(!strcmp(argv[0], "--enable"))
        {
            LW_CLEANUP_CTERR(exc, CTArrayAppend(&enableModules, sizeof(PCSTR), &argv[1], 1));
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--disable"))
        {
            if(!strcmp(argv[1], "ssh")){
                options.ignoreSsh = TRUE;
            }
            else {
                options.ignoreSsh = FALSE;
                LW_CLEANUP_CTERR(exc, CTArrayAppend(&disableModules, sizeof(PCSTR), &argv[1], 1));
            }
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--ignore"))
        {
            LW_CLEANUP_CTERR(exc, CTArrayAppend(&ignoreModules, sizeof(PCSTR), &argv[1], 1));
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--details"))
        {
            LW_CLEANUP_CTERR(exc, CTArrayAppend(&detailModules, sizeof(PCSTR), &argv[1], 1));
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--ou"))
        {
            DJ_LOG_INFO("Domainjoin invoked with option --ou %s", argv[1]);
            CT_SAFE_FREE_STRING(options.ouName);
            LW_CLEANUP_CTERR(exc, CTStrdup(argv[1], &options.ouName));
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--uac-flags"))
        {
            DJ_LOG_INFO("Domainjoin invoked with option --uac-flags %s", argv[1]);
            CT_SAFE_FREE_STRING(options.ouName);
            options.uacFlags = strtoul(argv[1], NULL, 0);
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--assumeDefaultDomain"))
        {
            DJ_LOG_INFO("Domainjoin invoked with option --assumeDefaultDomain");
            options.setAssumeDefaultDomain = TRUE;

            if (!strcasecmp(argv[1], "yes") || !strcasecmp(argv[1], "true") ||
                !strcasecmp(argv[1], "on"))
            {
                options.assumeDefaultDomain = TRUE;
            }
            else if (!strcasecmp(argv[1], "no") ||
                !strcasecmp(argv[1], "false") ||
                !strcasecmp(argv[1], "off"))
            {
                options.assumeDefaultDomain = FALSE;
            }
            else
            {
                LW_RAISE(exc, LW_ERROR_SHOW_USAGE);
                goto cleanup;
            }
            argv++;
            argc--;
        }
        else if(!strcmp(argv[0], "--userDomainPrefix"))
        {
            DJ_LOG_INFO("Domainjoin invoked with option --userDomainPrefix %s", argv[1]);
            options.setAssumeDefaultDomain = TRUE;
            options.assumeDefaultDomain = TRUE;
            CT_SAFE_FREE_STRING(options.userDomainPrefix);
            LW_CLEANUP_CTERR(exc, CTStrdup(argv[1], &options.userDomainPrefix));
            CTStrToUpper(options.userDomainPrefix);
            argv++;
            argc--;
        }
        else
        {
            LW_RAISE(exc, LW_ERROR_SHOW_USAGE);
            goto cleanup;
        }
        argv++;
        argc--;
    }

    if(argc == 3)
    {
        LW_CLEANUP_CTERR(exc, CTStrdup(argv[2], &options.password));
        passwordIndex = 2;
    }
    // The join username is not required in preview or details mode.
    else if(argc == 1 && (preview || detailModules.size != 0) )
        ;
    else if(argc != 2)
    {
        LW_RAISE(exc, LW_ERROR_SHOW_USAGE);
        goto cleanup;
    }
    options.joiningDomain = TRUE;

    DJ_LOG_INFO("Domainjoin invoked with %d arg(s) to the join command:", argc);
    for(i = 0; i < argc; i++)
    {
        DJ_LOG_INFO("    [%s]", i == passwordIndex ? "<password>" : argv[i]);
    }

    LW_CLEANUP_CTERR(exc, CTStrdup(
        argv[0], &options.domainName));
    if(argc > 1)
    {
        LW_CLEANUP_CTERR(exc, CTStrdup(argv[1], &options.username));
    }

    options.warningCallback = PrintWarning;
    options.showTraces = advanced;
    LW_CLEANUP_CTERR(exc, DJGetComputerName(&options.computerName));

    LW_TRY(exc, DJInitModuleStates(&options, &LW_EXC));

    for(i = 0; i < enableModules.size; i++)
    {
        PCSTR module = *(PCSTR *)CTArrayGetItem(
                    &enableModules, i, sizeof(PCSTR));
        if(CTArrayFindString(&disableModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being disabled and enabled", module);
            goto cleanup;
        }
        if(CTArrayFindString(&ignoreModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being ignored and enabled", module);
            goto cleanup;
        }
        LW_TRY(exc, DJSetModuleDisposition(&options, module, EnableModule, &LW_EXC));
    }

    for(i = 0; i < disableModules.size; i++)
    {
        PCSTR module = *(PCSTR *)CTArrayGetItem(
                    &disableModules, i, sizeof(PCSTR));
        if(CTArrayFindString(&enableModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being disabled and enabled", module);
            goto cleanup;
        }
        if(CTArrayFindString(&ignoreModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being ignored and enabled", module);
            goto cleanup;
        }
        LW_TRY(exc, DJSetModuleDisposition(&options, module, DisableModule, &LW_EXC));
    }

    for(i = 0; i < ignoreModules.size; i++)
    {
        PCSTR module = *(PCSTR *)CTArrayGetItem(
                    &ignoreModules, i, sizeof(PCSTR));
        if(CTArrayFindString(&enableModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being enabled and ignored", module);
            goto cleanup;
        }
        if(CTArrayFindString(&disableModules, module) != -1)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Module already specified", "The module '%s' is listed as being disabled and ignored", module);
            goto cleanup;
        }
        LW_TRY(exc, DJSetModuleDisposition(&options, module, IgnoreModule, &LW_EXC));
    }

    for(i = 0; i < detailModules.size; i++)
    {
        PCSTR module = *(PCSTR *)CTArrayGetItem(
                    &detailModules, i, sizeof(PCSTR));
        ModuleState *state = DJGetModuleStateByName(&options, module);
        if(state == NULL)
        {
            LW_RAISE_EX(exc, ERROR_INVALID_PARAMETER, "Unable to find module.", "Please check the spelling of '%s'. This module cannot be found", module);
            goto cleanup;
        }
        PrintModuleState(state);
    }
    if(detailModules.size > 0)
    {
        PrintStateKey();
    }
    for(i = 0; i < detailModules.size; i++)
    {
        PCSTR module = *(PCSTR *)CTArrayGetItem(
                    &detailModules, i, sizeof(PCSTR));
        ModuleState *state = DJGetModuleStateByName(&options, module);
        CT_SAFE_FREE_STRING(moduleDetails);
        CT_SAFE_FREE_STRING(wrapped);
        LW_TRY(exc, moduleDetails = state->module->GetChangeDescription(&options, &LW_EXC));
        LW_CLEANUP_CTERR(exc, CTWordWrap(moduleDetails, &wrapped, 4, columns));
        fprintf(stdout, "\nDetails for '%s':\n%s\n", state->module->longName, wrapped);
    }
    if(detailModules.size > 0)
        goto cleanup;

    LW_TRY(exc, PrintJoinHeader(&options, &LW_EXC));

    if(preview)
    {
        PrintModuleStates(advanced, &options);
        if(!advanced)
            LW_TRY(exc, DJCheckRequiredEnabled(&options, &LW_EXC));
        goto cleanup;
    }

    LW_TRY(exc, DJCheckRequiredEnabled(&options, &LW_EXC));

    if (IsNullOrEmptyString(options.password))
    {
        CT_SAFE_FREE_STRING(options.password);

        LW_CLEANUP_CTERR(exc, FillMissingPassword(options.username,
                    &options.password));
    }

    LW_TRY(exc, DJRunJoinProcess(&options, &LW_EXC));
    fprintf(stdout, "SUCCESS\n");

cleanup:
    DJFreeJoinProcessOptions(&options);
    CTArrayFree(&enableModules);
    CTArrayFree(&disableModules);
    CTArrayFree(&ignoreModules);
    CTArrayFree(&detailModules);
    CT_SAFE_FREE_STRING(moduleDetails);
    CT_SAFE_FREE_STRING(wrapped);
}