Example #1
0
void VPathHandleFilePath(STREAM *S,HTTPSession *Session, TPathItem *VPath, int SendData)
{
char *Tempstr=NULL, *ptr;
char *LocalPath=NULL, *ExternalPath=NULL, *DocName=NULL;

//Document name here is whatever part of the Path is *beyond* the VPath component
DocName=HTTPServerSubstituteArgs(DocName, Session->Path+StrLen(VPath->URL), Session);


ptr=GetToken(VPath->Path,":",&Tempstr,0);
while (ptr)
{
	if (*Tempstr=='/') ExternalPath=MCatStr(ExternalPath,Tempstr,":",NULL);
	else 
	{
		if (StrLen(Tempstr)==0) LocalPath=CatStr(LocalPath,"/:");
		else LocalPath=MCatStr(LocalPath,Tempstr,":",NULL);
	}
	ptr=GetToken(ptr,":",&Tempstr,0);
}

Tempstr=CopyStr(Tempstr,"");
if (StrLen(LocalPath)) Tempstr=FindFileInPath(Tempstr,DocName,LocalPath);

if (StrLen(Tempstr)) HTTPServerSendDocument(S, Session, Tempstr, HEADERS_SENDFILE|HEADERS_USECACHE|HEADERS_KEEPALIVE);
else if (StrLen(ExternalPath))
{
	if (strcmp(Session->Method,"POST")==0)
	{
		if (VPath->Flags & PATHITEM_UPLOAD)
		{
		LogToFile(Settings.LogPath,"%s@%s (%s) uploading to %s in VPATH %s", Session->UserName,Session->ClientHost,Session->ClientIP,DocName,ExternalPath);
		ChrootProcessRequest(S, Session, "POST", DocName, ExternalPath);
		}
		else 
		{
			LogToFile(Settings.LogPath,"%s@%s (%s) uploading DENIED to %s in VPATH %s", Session->UserName,Session->ClientHost,Session->ClientIP,DocName,ExternalPath);
			HTTPServerSendHTML(S, Session, "403 Forbidden","Uploads not allowed to this path.");
		}
	}
	else
	{
	LogToFile(Settings.LogPath,"%s@%s (%s) asking for external document %s in Search path %s", Session->UserName,Session->ClientHost,Session->ClientIP,DocName,ExternalPath);
	ChrootProcessRequest(S, Session, "GETF", DocName, ExternalPath);
	}
}
//This will send '404'
else HTTPServerSendDocument(S, Session, DocName, HEADERS_SENDFILE|HEADERS_USECACHE|HEADERS_KEEPALIVE);

DestroyString(DocName);
DestroyString(Tempstr);
DestroyString(LocalPath);
DestroyString(ExternalPath);
}
Example #2
0
//This is the function we call in the child process for 'SpawnCommand'
int BASIC_FUNC_EXEC_COMMAND(void *Command, int Flags)
{
    int result;
    char *Token=NULL, *FinalCommand=NULL, *ExecPath=NULL;
    char **argv;
    const char *ptr;
    int i;

    if (Flags & SPAWN_TRUST_COMMAND) FinalCommand=CopyStr(FinalCommand, (char *) Command);
    else FinalCommand=MakeShellSafeString(FinalCommand, (char *) Command, 0);

    StripTrailingWhitespace(FinalCommand);
    if (Flags & SPAWN_NOSHELL)
    {
        argv=(char **) calloc(101,sizeof(char *));
        ptr=FinalCommand;
        ptr=GetToken(FinalCommand,"\\S",&Token,GETTOKEN_QUOTES);
        ExecPath=FindFileInPath(ExecPath,Token,getenv("PATH"));
        i=0;

        if (! (Flags & SPAWN_ARG0))
        {
            argv[0]=CopyStr(argv[0],ExecPath);
            i=1;
        }

        for (; i < 100; i++)
        {
            ptr=GetToken(ptr,"\\S",&Token,GETTOKEN_QUOTES);
            if (! ptr) break;
            argv[i]=CopyStr(argv[i],Token);
        }

        execv(ExecPath,argv);
    }
    else result=execl("/bin/sh","/bin/sh","-c",(char *) Command,NULL);

    RaiseError(ERRFLAG_ERRNO, "Spawn", "Failed to execute '%s'",Command);
//We'll never get to here unless something fails!
    DestroyString(FinalCommand);
    DestroyString(ExecPath);
    DestroyString(Token);

    return(result);
}
Example #3
0
int PipeCommandProcessorInit(TProcessingModule *ProcMod, const char *Args)
{
int result=FALSE;
char *Tempstr=NULL;
char *Name=NULL, *Value=NULL, *ptr;
STREAM *S;

ptr=GetNameValuePair(Args,"\\S","=",&Name,&Value);
while (ptr)
{
  if (strcasecmp(Name,"Command")==0) Tempstr=CopyStr(Tempstr,Value);

ptr=GetNameValuePair(ptr,"\\S","=",&Name,&Value);
}

if (! StrLen(Tempstr) )
{
	DestroyString(Name);
	DestroyString(Value);
	DestroyString(Tempstr);
	return(FALSE);
}

GetToken(Tempstr,"\\S",&Name,0);
Value=FindFileInPath(Value,Name,getenv("PATH"));

if (! StrLen(Value) )
{
	DestroyString(Name);
	DestroyString(Value);
	DestroyString(Tempstr);
	return(FALSE);
}


S=STREAMSpawnCommand(Value, COMMS_BY_PIPE);
ProcMod->Data=(void *) S;
result=TRUE;

DestroyString(Name);
DestroyString(Value);
DestroyString(Tempstr);

return(result);
}
Example #4
0
pid_t HandlePostFileRequest(STREAM *ClientCon, char *Data)
{
HTTPSession *Response;
STREAM *S;
char *Tempstr=NULL;
pid_t pid;

pid=fork();
if (pid==0)
{	
	Response=ParseSessionInfo(Data);
	Tempstr=FindFileInPath(Tempstr,Response->Path,Response->SearchPath);
	Response->Path=CopyStr(Response->Path, Tempstr);

	if (! SwitchGroup(Response->Group))
	{
		LogToFile(Settings.LogPath,"WARN: Failed to switch to group '%s' when posting  '%s'", Response->RealUser, Tempstr);
	}


	if (! SwitchUser(Response->RealUser))
	{
		LogToFile(Settings.LogPath,"ERROR: Failed to switch to user '%s' when posting to document '%s'", Tempstr);
		LogFileFlushAll(TRUE);
		_exit(0);
	}

 LogToFile(Settings.LogPath,"SWITCH USER: '******' posting document '%s'", Response->RealUser, Response->Group, Tempstr);

	STREAMWriteLine("READY\n",ClientCon); STREAMFlush(ClientCon);
	HTTPServerHandlePost(ClientCon, Response);
	
	//exit 1 means that we can keep connection alive for re-use
	LogFileFlushAll(TRUE);
	if (Response->Flags & SESSION_KEEPALIVE) _exit(1);
	_exit(0);
}
else ClientCon->State |= SS_EMBARGOED;

DestroyString(Tempstr);

return(pid);
}
Example #5
0
pid_t HandleGetFileRequest(STREAM *ClientCon, char *Data)
{
HTTPSession *Response;
char *Tempstr=NULL;
pid_t pid;


pid=fork();
if (pid==0)
{
	Response=ParseSessionInfo(Data);
	Tempstr=FindFileInPath(Tempstr,Response->Path,Response->SearchPath);
	if (! SwitchGroup(Response->Group))
	{
		LogToFile(Settings.LogPath,"WARN: Failed to switch to group '%s' when getting document '%s'", Response->RealUser, Tempstr);
	}

	if (! SwitchUser(Response->RealUser))
	{
		LogToFile(Settings.LogPath,"ERROR: Failed to switch to user '%s' when getting document '%s'", Tempstr);
		LogFileFlushAll(TRUE);
		_exit(0);
	}


	STREAMWriteLine("READY\n",ClientCon); STREAMFlush(ClientCon);
	HTTPServerSendDocument(ClientCon, Response, Tempstr, HEADERS_SENDFILE|HEADERS_USECACHE|HEADERS_KEEPALIVE);
		
	//exit 1 means that we can keep connection alive for re-use
	LogFileFlushAll(TRUE);
	if (Response->Flags & SESSION_KEEPALIVE) _exit(1);
	_exit(0);
}

DestroyString(Tempstr);

return(pid);
}
Example #6
0
//Parse a list of packing formats and their associated commands so we can offer the user
//'download as zip' in the directory webpage
char *ParsePackFormats(char *RetStr, const char *Config)
{
char *Name=NULL, *Value=NULL, *ptr, *tptr;
char *Path=NULL;

RetStr=CopyStr(RetStr,"");
ptr=GetNameValuePair(Config, ",",":",&Name,&Value);
while (ptr)
{
if (StrLen(Name) && StrLen(Value)) 
{
	if (strcasecmp(Value,"internal")==0) RetStr=MCatStr(RetStr,Name,":",Value,",",NULL);
	else
	{
		tptr=strchr(Value,' ');
		if (tptr)
		{
			*tptr='\0';
			tptr++;
		}
		//we don't want this to be null if strchr returns a null, otherwise it will
		//shorten our sting when we use MCatStr below.
		else tptr="";

		Path=FindFileInPath(Path,Value,getenv("PATH"));
		if (StrLen(Path)) RetStr=MCatStr(RetStr,Name,":",Path," ", tptr, ",",NULL);
	}
}
ptr=GetNameValuePair(ptr, ",",":",&Name,&Value);
}

DestroyString(Name);
DestroyString(Value);

return(RetStr);
}
Example #7
0
pid_t HandleCGIExecRequest(STREAM *ClientCon, char *Data)
{
char *Tempstr=NULL, *Name=NULL, *Value=NULL;
char *ScriptPath=NULL;
int result, i;
HTTPSession *Response;

	//We will never read from this stream again. Any further data will be read
	//by the process we spawn off
	ClientCon->State |= SS_EMBARGOED;
	Response=ParseSessionInfo(Data);
	CleanStr(Response->Path);
	CleanStr(Response->SearchPath);
	CleanStr(Response->StartDir);
	ScriptPath=FindFileInPath(ScriptPath,Response->Path,Response->SearchPath);

	if (access(ScriptPath,F_OK) !=0)
	{
			HTTPServerSendHTML(ClientCon, Response, "404 Not Found","Couldn't find that script.");
			LogToFile(Settings.LogPath,"No such script: %s in path %s = %s",Response->Path,Response->SearchPath,ScriptPath);
	}
	else if (
					(access(ScriptPath,X_OK) !=0) || 
					(! CheckScriptIntegrity(ScriptPath))
			)
	{
			HTTPServerSendHTML(ClientCon, Response, "403 Forbidden","You don't have permission for that.");
			LogToFile(Settings.LogPath,"Cannot execute script: %s",ScriptPath);
	}
	else
	{
		STREAMFlush(ClientCon);
		LogFileFlushAll(TRUE);
		result=fork();
		if (result==0)
		{
			//do this so that when we exec the script, anything output goes to the client
			close(0);
			dup(ClientCon->in_fd);
			close(1);
			dup(ClientCon->out_fd);

			//must use write because stream is embargoed
			write(1,"READY\n",6);

			HTTPServerExecCGI(ClientCon, Response, ScriptPath);

			//exit whether script ran or not!
			_exit(0);
		}
	}


HTTPSessionDestroy(Response);
DestroyString(ScriptPath);
DestroyString(Tempstr);
DestroyString(Name);
DestroyString(Value);


//Always return STREAM_CLOSED, so that pipe gets closed regardless of exit status of 
//forked helper process
return(STREAM_CLOSED);
}
Example #8
0
pid_t HandleWebsocketExecRequest(STREAM *ClientCon, char *Data)
{
char *Tempstr=NULL, *Name=NULL, *Value=NULL;
char *ScriptPath=NULL;
int result, i;
HTTPSession *Response;

	//We will never read from this stream again. Any further data will be read
	//by the process we spawn off
	ClientCon->State |= SS_EMBARGOED;
	Response=ParseSessionInfo(Data);
	CleanStr(Response->Path);
	CleanStr(Response->SearchPath);
	CleanStr(Response->StartDir);
	ScriptPath=FindFileInPath(ScriptPath, Response->Path, Response->SearchPath);
	LogToFile(Settings.LogPath,"Script: Found=[%s] SearchPath=[%s] ScriptName=[%s] Arguments=[%s]", ScriptPath, Response->SearchPath, Response->Path, Response->Arguments);

	if (access(ScriptPath,F_OK) !=0)
	{
			LogToFile(Settings.LogPath,"No such script: %s in path %s = %s",Response->Path, Response->SearchPath, ScriptPath);
	}
	else if (
					(access(ScriptPath,X_OK) !=0) || 
					(! CheckScriptIntegrity(ScriptPath))
			)
	{
			LogToFile(Settings.LogPath,"Cannot execute script: %s", ScriptPath);
	}
	else
	{
		STREAMFlush(ClientCon);
		result=fork();
		if (result==0)
		{
			//do this so that when we exec the script, anything output goes to the client
			close(0);
			dup(ClientCon->in_fd);
			close(1);
			dup(ClientCon->out_fd);

      if (! SwitchGroup(Response->Group))
			{
        LogToFile(Settings.LogPath,"WARN: Failed to switch to group '%s' to execute script: %s using handler '%s'", Response->RealUser, ScriptPath, Tempstr);
			}

      //Switch user. ALAYA WILL NOT RUN SCRIPTS AS ROOT!
      if (! SwitchUser(Response->RealUser))
      {
        LogToFile(Settings.LogPath,"ERROR: Failed to switch to user '%s' to execute script: %s using handler '%s'", Response->RealUser, ScriptPath, Tempstr);
				LogFileFlushAll(TRUE);
        _exit(0);
      }

			if (geteuid()==0)
			{
				LogToFile(Settings.LogPath, "Failed to switch user to '%s' for running a .cgi program. Will not run programs as 'root'. Set 'DefaultUser' in config file or command line.", Response->RealUser);
			}
			else
			{
				SetupEnvironment(Response, ScriptPath);
				Tempstr=FindScriptHandlerForScript(Tempstr,ScriptPath);
				if (Tempstr) LogToFile(Settings.LogPath,"Execute script: %s using handler '%s'",ScriptPath,Tempstr);
				else LogToFile(Settings.LogPath,"Execute script: %s QUERY_STRING= '%s'",ScriptPath,getenv("QUERY_STRING"));

				//Only do this late! Otherwise logging won't work.
				for (i=3; i < 1000; i++) close(i);

				if (StrLen(Tempstr)) execl(Tempstr, Tempstr, ScriptPath,NULL);
				else execl(ScriptPath,ScriptPath,NULL);

				//Logging won't work after we've closed all the file descriptors!
				LogToFile(Settings.LogPath,"Cannot execute script: %s",ScriptPath);
		}
		LogFileFlushAll(TRUE);
		_exit(0);
	}
	else
	{

	}
}


HTTPSessionDestroy(Response);
DestroyString(ScriptPath);
DestroyString(Tempstr);
DestroyString(Name);
DestroyString(Value);


//Always return STREAM_CLOSED, so that pipe gets closed regardless of exit status of 
//forked helper process
return(STREAM_CLOSED);
}
Example #9
0
DWORD
GetWbclientDir(
    PCSTR pSmbdPath,
    PSTR* ppDir
    )
{
    PCSTR ppBackupPaths[] = {
        "/usr/lib",
        "/usr/lib64",
        NULL,
    };
    DWORD index = 0;
    DWORD error = 0;
    BOOLEAN exists = 0;
    PSTR pFoundPath = NULL;
    PSTR pCommandLine = NULL;
    PCSTR ppArgs[] = {
        "/bin/sh",
        "-c",
        NULL,
        NULL
    };
    PSTR pSambaLibdir = NULL;

    *ppDir = NULL;

    // First see if libwbclient.so.0 is in Samba's libdir. There may be two
    // copies of libwbclient.so.0 because of different architectures. This will
    // identify which one is the primary one.
    error = LwAllocateStringPrintf(
            &pCommandLine,
            "%s -b | grep LIBDIR:",
            pSmbdPath
            );
    BAIL_ON_LSA_ERROR(error);

    ppArgs[2] = pCommandLine;

    error = CaptureOutputWithStderr(
                "/bin/sh",
                ppArgs,
                &pSambaLibdir,
                NULL);
    BAIL_ON_LSA_ERROR(error);

    LwStripWhitespace(
            pSambaLibdir,
            TRUE,
            TRUE);

    if (strstr(pSambaLibdir, ": "))
    {
        char *pValueStart = strstr(pSambaLibdir, ": ") + 2;
        memmove(
                pSambaLibdir,
                pValueStart,
                strlen(pSambaLibdir) - (pValueStart - pSambaLibdir) + 1);
    }

    error = FindFileInPath(
                    WBCLIENT_FILENAME,
                    pSambaLibdir,
                    &pFoundPath);
    if (error == ERROR_FILE_NOT_FOUND)
    {
        // Fall back to trying the two standard system paths
        error = FindFileInPath(
                        WBCLIENT_FILENAME,
                        "/usr/lib:/usr/lib64",
                        &pFoundPath);
        if (error == ERROR_FILE_NOT_FOUND)
        {
            error = 0;
        }
    }
    BAIL_ON_LSA_ERROR(error);

    if (pFoundPath)
    {
        pFoundPath[strlen(pFoundPath) - (sizeof(WBCLIENT_FILENAME) -1) - 1] = 0;
        *ppDir = pFoundPath;
        pFoundPath = NULL;
        goto cleanup;
    }

    // Could not find an existing libwbclient.so.0. This could be a Samba 3.0.x
    // build. Just stick the file in a system path.
    for (index = 0; ppBackupPaths[index]; index++)
    {
        error = LwCheckFileTypeExists(
                    ppBackupPaths[index],
                    LWFILE_DIRECTORY,
                    &exists);
        BAIL_ON_LSA_ERROR(error);

        if (exists)
        {
            error = LwAllocateString(ppBackupPaths[index], ppDir);
            BAIL_ON_LSA_ERROR(error);
            goto cleanup;
        }
    }

    // Could not find the system library paths.
    error = ERROR_FILE_NOT_FOUND;
    BAIL_ON_LSA_ERROR(error);

cleanup:
    LW_SAFE_FREE_STRING(pFoundPath);
    LW_SAFE_FREE_STRING(pCommandLine);
    LW_SAFE_FREE_STRING(pSambaLibdir);
    return error;
}
Example #10
0
int
main(
    int argc,
    char *argv[]
    )
{
    enum
    {
        UNSET,
        SHOW_HELP,
        CHECK_VERSION,
        INSTALL,
        UNINSTALL
    } mode = UNSET;
    PCSTR pSmbdPath = NULL;
    PSTR pFoundSmbdPath = NULL;
    DWORD error = 0;
    DWORD argIndex = 0;
    LW_RTL_LOG_LEVEL logLevel = LW_RTL_LOG_LEVEL_ERROR;
    PCSTR pErrorSymbol = NULL;
    PSTR pVersion = NULL;
    BOOLEAN smbdExists = FALSE;
    BOOLEAN force = FALSE;

    for (argIndex = 1; argIndex < argc; argIndex++)
    {
        if (!strcmp(argv[argIndex], "--check-version"))
        {
            if (mode == UNSET)
            {
                mode = CHECK_VERSION;
            }
            else
            {
                mode = SHOW_HELP;
            }
        }
        else if (!strcmp(argv[argIndex], "--install"))
        {
            if (mode == UNSET)
            {
                mode = INSTALL;
            }
            else
            {
                mode = SHOW_HELP;
            }
        }
        else if (!strcmp(argv[argIndex], "--uninstall"))
        {
            if (mode == UNSET)
            {
                mode = UNINSTALL;
            }
            else
            {
                mode = SHOW_HELP;
            }
        }
        else if (!strcmp(argv[argIndex], "--force"))
        {
            if (mode == INSTALL || mode== UNINSTALL)
            {
                force = TRUE;
            }
            else
            {
                mode = SHOW_HELP;
            }
        }
        else if (!strcmp(argv[argIndex], "--loglevel"))
        {
            argIndex++;
            if (argIndex >= argc)
            {
                error = ERROR_INVALID_PARAMETER;
                BAIL_ON_LSA_ERROR(error);
            }
            if (!strcmp(argv[argIndex], "error"))
            {
                logLevel = LW_RTL_LOG_LEVEL_ERROR;
            }
            else if (!strcmp(argv[argIndex], "warning"))
            {
                logLevel = LW_RTL_LOG_LEVEL_WARNING;
            }
            else if (!strcmp(argv[argIndex], "info"))
            {
                logLevel = LW_RTL_LOG_LEVEL_INFO;
            }
            else if (!strcmp(argv[argIndex], "verbose"))
            {
                logLevel = LW_RTL_LOG_LEVEL_VERBOSE;
            }
            else if (!strcmp(argv[argIndex], "debug"))
            {
                logLevel = LW_RTL_LOG_LEVEL_DEBUG;
            }
            else
            {
                error = ERROR_INVALID_PARAMETER;
                BAIL_ON_LSA_ERROR(error);
            }
        }
        else if (argIndex == argc - 1)
        {
            pSmbdPath = argv[argIndex];
        }
        else
        {
            mode = SHOW_HELP;
        }
    }

    if (mode == UNSET || mode == SHOW_HELP)
    {
        ShowUsage(argv[0]);
        goto cleanup;
    }

    LwRtlLogSetCallback(LogCallback, NULL);
    LwRtlLogSetLevel(logLevel);

    if (pSmbdPath == NULL)
    {
        PCSTR pSearchPath = "/usr/sbin:/usr/local/sbin:/usr/local/samba/sbin:/opt/csw/samba/sbin:/opt/sfw/samba/sbin:/opt/csw/bin:/usr/local/bin";
        error = FindFileInPath(
                        "smbd",
                        pSearchPath,
                        &pFoundSmbdPath);
        if (error == ERROR_FILE_NOT_FOUND)
        {
            LW_RTL_LOG_ERROR("The smbd file could not be automatically found on your system. The search path was '%s'. Pass the correct location as the last argument to this program.", pSearchPath);
        }
        BAIL_ON_LSA_ERROR(error);
        pSmbdPath = pFoundSmbdPath;
    }

    error = LwCheckFileTypeExists(
                pSmbdPath,
                LWFILE_REGULAR,
                &smbdExists);
    BAIL_ON_LSA_ERROR(error);
    
    if (!smbdExists)
    {
        error = LwCheckFileTypeExists(
                    pSmbdPath,
                    LWFILE_SYMLINK,
                    &smbdExists);
        BAIL_ON_LSA_ERROR(error);
    }

    if (!smbdExists)
    {
        LW_RTL_LOG_ERROR("Smbd file not found at path '%s'", pSmbdPath);
    }

    error = CheckSambaVersion(pSmbdPath, &pVersion);
    if (force == FALSE) 
    {
       BAIL_ON_LSA_ERROR(error);
    }
 
    if (mode == CHECK_VERSION)
    {
        fprintf(stderr, "Samba version supported\n");
    }
    else if (mode == INSTALL)
    {
        if (geteuid() != 0)
        {
            fprintf(stderr, "Please use the root account to install the Samba interop libraries\n");
            goto cleanup;
        }

        error = InstallWbclient(pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        if (pVersion && strncmp(pVersion, "3.0.", sizeof("3.0.") - 1) == 0)
        {
            // Only Samba 3.0.x needs this
            error = InstallLwiCompat(pSmbdPath);
            BAIL_ON_LSA_ERROR(error);
        }

        error = SynchronizePassword(
                    pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        fprintf(stderr, "Install successful\n");
    }
    else if (mode == UNINSTALL)
    {
        if (geteuid() != 0)
        {
            fprintf(stderr, "Please use the root account to uninstall the Samba interop libraries\n");
            goto cleanup;
        }

        error = UninstallWbclient(pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        error = UninstallLwiCompat(pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        error = DeletePassword(
                    pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        fprintf(stderr, "Uninstall successful\n");
    }
    else
    {
        fprintf(stderr, "Uninstall mode not implemented\n");
        error = ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(error);
    }

cleanup:
    LW_SAFE_FREE_STRING(pFoundSmbdPath);
    LW_SAFE_FREE_STRING(pVersion);

    if (error)
    {
        pErrorSymbol = LwWin32ErrorToName(error);
        if (pErrorSymbol != NULL)
        {
            fprintf(stderr, "Error: %s\n", pErrorSymbol);
        }
        else
        {
            fprintf(stderr, "Unknown error\n");
        }
    }
    return error;
}
int
main(
    int argc,
    char *argv[]
    )
{
    enum
    {
        UNSET,
        SHOW_HELP,
        CHECK_VERSION,
        INSTALL,
        UNINSTALL
    } mode = UNSET;
    PCSTR pSmbdPath = NULL;
    PSTR pFoundSmbdPath = NULL;
    DWORD error = 0;
    DWORD argIndex = 0;
    LW_RTL_LOG_LEVEL logLevel = LW_RTL_LOG_LEVEL_ERROR;
    PCSTR pErrorSymbol = NULL;

    for (argIndex = 1; argIndex < argc; argIndex++)
    {
        if (!strcmp(argv[argIndex], "--check-version"))
        {
            if (mode == UNSET)
            {
                mode = CHECK_VERSION;
            }
            else
            {
                mode = SHOW_HELP;
            }
        }
        else if (!strcmp(argv[argIndex], "--install"))
        {
            if (mode == UNSET)
            {
                mode = INSTALL;
            }
            else
            {
                mode = SHOW_HELP;
            }
        }
        else if (!strcmp(argv[argIndex], "--uninstall"))
        {
            if (mode == UNSET)
            {
                mode = UNINSTALL;
            }
            else
            {
                mode = SHOW_HELP;
            }
        }
        else if (!strcmp(argv[argIndex], "--loglevel"))
        {
            argIndex++;
            if (argIndex >= argc)
            {
                error = ERROR_INVALID_PARAMETER;
                BAIL_ON_LSA_ERROR(error);
            }
            if (!strcmp(argv[argIndex], "error"))
            {
                logLevel = LW_RTL_LOG_LEVEL_ERROR;
            }
            else if (!strcmp(argv[argIndex], "warning"))
            {
                logLevel = LW_RTL_LOG_LEVEL_WARNING;
            }
            else if (!strcmp(argv[argIndex], "info"))
            {
                logLevel = LW_RTL_LOG_LEVEL_INFO;
            }
            else if (!strcmp(argv[argIndex], "verbose"))
            {
                logLevel = LW_RTL_LOG_LEVEL_VERBOSE;
            }
            else if (!strcmp(argv[argIndex], "debug"))
            {
                logLevel = LW_RTL_LOG_LEVEL_DEBUG;
            }
            else
            {
                error = ERROR_INVALID_PARAMETER;
                BAIL_ON_LSA_ERROR(error);
            }
        }
        else if (argIndex == argc - 1)
        {
            pSmbdPath = argv[2];
        }
        else
        {
            mode = SHOW_HELP;
        }
    }

    if (mode == UNSET || mode == SHOW_HELP)
    {
        ShowUsage(argv[0]);
        goto cleanup;
    }

    LwRtlLogSetCallback(LogCallback, NULL);
    LwRtlLogSetLevel(logLevel);

    if (pSmbdPath == NULL)
    {
        error = FindFileInPath(
                        "smbd",
                        "/usr/sbin",
                        &pFoundSmbdPath);
        BAIL_ON_LSA_ERROR(error);
        pSmbdPath = pFoundSmbdPath;
    }

    error = CheckSambaVersion(pSmbdPath);
    BAIL_ON_LSA_ERROR(error);

    if (mode == CHECK_VERSION)
    {
        fprintf(stderr, "Samba version supported\n");
    }
    else if (mode == INSTALL)
    {
        error = InstallWbclient(pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        error = InstallLwiCompat(pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        error = SynchronizePassword(
                    pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        fprintf(stderr, "Install successful\n");
    }
    else if (mode == UNINSTALL)
    {
        error = UninstallWbclient(pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        error = UninstallLwiCompat(pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        error = DeletePassword(
                    pSmbdPath);
        BAIL_ON_LSA_ERROR(error);

        fprintf(stderr, "Uninstall successful\n");
    }
    else
    {
        fprintf(stderr, "Uninstall mode not implemented\n");
        error = ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(error);
    }

cleanup:
    LW_SAFE_FREE_STRING(pFoundSmbdPath);

    if (error)
    {
        pErrorSymbol = LwWin32ErrorToName(error);
        if (pErrorSymbol != NULL)
        {
            fprintf(stderr, "Error: %s\n", pErrorSymbol);
        }
        else
        {
            fprintf(stderr, "Unknown error\n");
        }
    }
    return error;
}