示例#1
0
static DWORD AddFormattedLine(NsswitchConf *conf, const char *filename, const char *linestr, const char **endptr)
{
    DWORD ceError = ERROR_SUCCESS;
    NsswitchEntry lineObj;
    const char *pos = linestr;
    const char *token_start = NULL;
    CTParseToken token;

    memset(&lineObj, 0, sizeof(lineObj));
    memset(&token, 0, sizeof(token));

    /* Find the leading whitespace in the line */
    token_start = pos;
    while(isblank(*pos)) pos++;
    GCE(ceError = CTStrndup(token_start, pos - token_start, &lineObj.leadingWhiteSpace));

    /* Read the name of the entry and attach its trailing : or = */
    GCE(ceError = CTReadToken(&pos, &lineObj.name, "=: \t", ";#\r\n", ""));

    /* Create an array of the modules for this entry */
    while(strchr("\r\n;#", *pos) == NULL)
    {
        GCE(ceError = CTReadToken(&pos, &token, ", \t", ";#\r\n", ""));
        GCE(ceError = CTArrayAppend(&lineObj.modules, sizeof(CTParseToken), &token, 1));
        memset(&token, 0, sizeof(token));
    }

    /*Read the comment, if there is one*/
    token_start = pos;
    while(strchr("\r\n", *pos) == NULL) pos++;

    if(pos != token_start)
        GCE(ceError = CTStrndup(token_start, pos - token_start, &lineObj.comment));

    GCE(ceError = CTArrayAppend(&conf->lines, sizeof(lineObj), &lineObj, 1));
    memset(&lineObj, 0, sizeof(lineObj));

    if(endptr != NULL)
        *endptr = pos;

cleanup:
    FreeNsswitchEntryContents(&lineObj);
    CTFreeParseTokenContents(&token);

    return ceError;
}
示例#2
0
static DWORD NullTerminate(StringBuffer *buffer)
{
    DWORD ceError = CTArrayAppend(buffer, 1, "\0", 1);
    CLEANUP_ON_DWORD(ceError);
    buffer->size--;
cleanup:
    return ceError;
}
示例#3
0
DWORD
CTStringBufferAppendLength(StringBuffer* buffer, const char* str, unsigned int length)
{
    DWORD ceError = CTArrayAppend(buffer, 1, str, length);
    CLEANUP_ON_DWORD(ceError);
    ceError = NullTerminate(buffer);
    CLEANUP_ON_DWORD(ceError);

cleanup:
    return ceError;
}
示例#4
0
static DWORD AddFormattedLine(struct SshConf *conf, const char *filename, const char *linestr, const char **endptr)
{
    DWORD ceError = ERROR_SUCCESS;
    struct SshLine lineObj;
    const char *pos = linestr;
    const char *token_start = NULL;

    memset(&lineObj, 0, sizeof(lineObj));

    /* Find the leading whitespace in the line */
    token_start = pos;
    while(isblank(*pos)) pos++;
    BAIL_ON_CENTERIS_ERROR(ceError = CTStrndup(token_start, pos - token_start, &lineObj.leadingWhiteSpace));

    /* Find the option name in the line */
    token_start = pos;
    while(!isspace((int)*pos) && *pos != '\0' && *pos != '#')
    {
        pos++;
    }
    BAIL_ON_CENTERIS_ERROR(ceError = CTStrndup(token_start, pos - token_start, &lineObj.name.value));

    /* Find the blank space separating the option name and option value */
    token_start = pos;
    while(isblank(*pos)) pos++;
    BAIL_ON_CENTERIS_ERROR(ceError = CTStrndup(token_start, pos - token_start, &lineObj.name.trailingSeparator));

    /* Find the option value */
    token_start = pos;
    //This token can contain spaces and tabs
    while(*pos != '\0' && *pos != '#' && *pos != '\n' && *pos != '\r') pos++;
    //But not at the end, so trim off the trailing white space
    while(pos > token_start && isblank(pos[-1])) pos--;
    BAIL_ON_CENTERIS_ERROR(ceError = CTStrndup(token_start, pos - token_start, &lineObj.value.value));

    /* Find the line's trailing whitespace and comment */
    token_start = pos;
    while(*pos != '\0' && *pos != '\n' && *pos != '\r') pos++;
    BAIL_ON_CENTERIS_ERROR(ceError = CTStrndup(token_start, pos - token_start, &lineObj.value.trailingSeparator));

    BAIL_ON_CENTERIS_ERROR(ceError = CTArrayAppend(&conf->private_data, sizeof(lineObj), &lineObj, 1));
    memset(&lineObj, 0, sizeof(lineObj));
    UpdatePublicLines(conf);

    if(endptr != NULL)
        *endptr = pos;
    conf->modified = 1;

error:
    FreeSshLineContents(&lineObj);
    return ceError;
}
示例#5
0
static DWORD AddEntry(NsswitchConf *conf, const DistroInfo *distro,
        int *addedIndex, const char *name)
{
    DWORD ceError = ERROR_SUCCESS;
    int line = -1;
    NsswitchEntry lineObj;
    const NsswitchEntry *copy;

    memset(&lineObj, 0, sizeof(lineObj));
    GCE(ceError = CTStrdup(name, &lineObj.name.value));

    for(line = 0; line < conf->lines.size; line++)
    {
        copy = GetEntry(conf, line);
        if(copy->name.value != NULL)
        {
            GCE(ceError = CTStrdup(copy->name.trailingSeparator, &lineObj.name.trailingSeparator));
            break;
        }
    }

    if(lineObj.name.trailingSeparator == NULL)
    {
        //Couldn't find an existing line to copy the separator from. We'll
        //have to guess based on the OS
        if(distro->os == OS_AIX)
            GCE(ceError = CTStrdup(" = ", &lineObj.name.trailingSeparator));
        else
            GCE(ceError = CTStrdup(": ", &lineObj.name.trailingSeparator));
    }

    GCE(ceError = CTArrayAppend(&conf->lines,
                sizeof(NsswitchEntry), &lineObj, 1));
    memset(&lineObj, 0, sizeof(lineObj));
    conf->modified = 1;
    if(addedIndex != NULL)
        *addedIndex = conf->lines.size - 1;

cleanup:
    FreeNsswitchEntryContents(&lineObj);
    return ceError;
}
示例#6
0
/* Copy a ssh configuration line and add it below the old line. */
static DWORD SetOption(struct SshConf *conf, const char *name, const char *value)
{
    DWORD ceError = ERROR_SUCCESS;
    int line = -1;
    DynamicArray printedLine;
    struct SshLine lineObj;
    int found = 0;

    memset(&lineObj, 0, sizeof(struct SshLine));
    memset(&printedLine, 0, sizeof(printedLine));

    for(line = 0; line < conf->lineCount; line++)
    {
        line = FindOption(conf, line, name);
        if(line == -1)
            break;
        found++;
        if(!strcmp(conf->lines[line].value.value, value))
            continue;

        //Insert a commented out version of the line
        BAIL_ON_CENTERIS_ERROR(ceError = GetPrintedLine(&printedLine, conf, line));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup("",
            &lineObj.leadingWhiteSpace));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup("",
            &lineObj.name.value));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup("",
            &lineObj.name.trailingSeparator));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup("",
            &lineObj.value.value));
        BAIL_ON_CENTERIS_ERROR(ceError = CTAllocateStringPrintf(
            &lineObj.value.trailingSeparator,
            "#Overwritten by lwidentity: %s",
            printedLine.data));
        BAIL_ON_CENTERIS_ERROR(ceError = CTArrayInsert(&conf->private_data,
                    line, sizeof(struct SshLine), &lineObj, 1));
        memset(&lineObj, 0, sizeof(lineObj));
        UpdatePublicLines(conf);
        conf->modified = 1;
        line++;

        //Change the option value of the line
        CT_SAFE_FREE_STRING(conf->lines[line].value.value);
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup(value,
            &conf->lines[line].value.value));
    }

    /*If the option wasn't already in the file, search for comments that
      mention the option, and insert the line after the comment*/
    for(line = 0; !found && line < conf->lineCount; line++)
    {
        if(strstr(conf->lines[line].value.trailingSeparator, name) == NULL)
            continue;

        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup("",
            &lineObj.leadingWhiteSpace));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup(name,
            &lineObj.name.value));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup(" ",
            &lineObj.name.trailingSeparator));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup(value,
            &lineObj.value.value));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup("",
            &lineObj.value.trailingSeparator));
        BAIL_ON_CENTERIS_ERROR(ceError = CTArrayInsert(&conf->private_data,
                    line + 1, sizeof(struct SshLine), &lineObj, 1));
        memset(&lineObj, 0, sizeof(lineObj));
        conf->modified = 1;
        found++;
    }

    /*If the option wasn't even in a comment, just add the option at the
      end of the file
      */
    if(!found)
    {
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup("",
            &lineObj.leadingWhiteSpace));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup(name,
            &lineObj.name.value));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup(" ",
            &lineObj.name.trailingSeparator));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup(value,
            &lineObj.value.value));
        BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup("",
            &lineObj.value.trailingSeparator));
        BAIL_ON_CENTERIS_ERROR(ceError = CTArrayAppend(&conf->private_data,
                    sizeof(struct SshLine), &lineObj, 1));
        memset(&lineObj, 0, sizeof(lineObj));
        conf->modified = 1;
    }

error:
    UpdatePublicLines(conf);
    FreeSshLineContents(&lineObj);
    CTArrayFree(&printedLine);
    return ceError;
}
示例#7
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);
}
示例#8
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);
}