// The following code makes a few assumptions:
// - You have downloaded and built my fksec classes
//   (http://mvps.org/win32/security/fksec.html)
// - You have a reasonable grasp of what they do (not hard)
// - The header files are in a directory listed in either
//   the INCLUDE environment variable (command line compile)
//   or in the IDE's include path (Tools | Options,
//   Directories)
// - The library file is in a directory listed in either
//   the LIB environment variable (command line compile)
//   or in the IDE's library path (Tools | Options,
//   Directories)

// compiles with:
// cl -GX -MT ownership.cpp
// cl -GX -Z7 -MTd -D _DEBUG ownership.cpp -link -debug

#define _MBCS 1
#include <iostream>
#include <iomanip>
#include <string>
#include <windows.h>
#include "fksec.h"
#pragma hdrstop

#ifdef _DEBUG
#pragma comment( lib, "fksecd.lib" )
#else
#pragma comment( lib, "fksec.lib" )
#endif
#pragma comment( lib, "netapi32.lib" )


using namespace std;


void Grab( const char *what );
void GrabFile( const char *what );


bool haveOwner = false;
fksec::sid newOwner;


int main( int argc, char *argv[] )
{
	int i;

	if ( argc < 2 )
	{
		cout << endl << "Usage: ownership [-p privname] [-o new-owner] object [object ...]" << endl << endl
			<< "privname is an NT privilege name; for taking ownership, you may" << endl
			<< "want to play with SeRestorePrivilege, SeTakeOwnershipPrivilege," << endl
			<< "or both." << endl << endl
			<< "new-owner is the name or textual SID of the new owner.  If the" << endl
			<< "-o switch is omitted, the current owner is reported." << endl << endl
			<< "object is the name of the object you wish to take ownership of." << endl
			<< "Currently, only file system objects are supported." << endl;
		return 1;
	}

	for ( i = 1; i < argc; ++ i )
	{
		if ( argv[i][0] == '-' )
		{
			switch ( argv[i][1] )
			{
				case 'p':
					if ( i + 1 >= argc )
					{
						clog << "\"" << argv[i] << "\" requires a privilege name." << endl <<
							"Run this program without arguments for help." << endl;
						break;
					}
					++ i;
					try { fksec::priv( argv[i] ).Enable(); }
					catch ( fksec::ex *e )
					{
						if ( e->GetErr() == fksec::errInvalidPriv )
							clog << "Ignoring unknown privilege: \"" << argv[i] << "\"." << endl;
						else if ( e->GetErr() == fksec::errStubbornPriv )
							clog << "Privilege cannot be enabled: do you have \"" << argv[i] << "\"?" << endl;
						else
							clog << "An unexpected error condition has laid me by the lee when trying to enable" << endl
								<< "\"" << argv[i] << "\". Here are the gory details:" << endl << *e;
						delete e;
					}
					break;
				case 'o':
					if ( i + 1 >= argc )
					{
						clog << "\"" << argv[i] << "\" requires an owner name." << endl <<
							"Run this program without arguments for help." << endl;
						break;
					}
					++ i;
					try {
						haveOwner = false;
						newOwner = argv[i];
						haveOwner = true;
					}
					catch ( fksec::ex *e )
					{
						if ( e->GetErr() == fksec::errInvalidSid )
							clog << "The account name or textual SID \"" << argv[i] << "\""
								<< endl << "was not found and has been ignored." << endl;
						else
							clog << "There seems to be a problem with the new owner's user name" << endl
								<< "\"" << argv[i] << "\". Here are the gory details:" << endl << *e;
						delete e;
					}
					break;
				default:
					clog << "Ignoring illegal option: \"" << argv[i] << "\"." << endl <<
						"Run this program without arguments for help." << endl;
					break;
			}
		}
		else // not a command line option, try taking ownership
			Grab( argv[i] );
	}

	return 0;
}


void GrabFile( const char *what )
{
	fksec::sd sd;

	// read SD
	try { fksec::GetFileSecurity( what, OWNER_SECURITY_INFORMATION, sd ); }
	catch ( fksec::ex *e )
	{
		clog << "Skipping file \"" << what << "\", error " << GetLastError() << " from GetFileSecurity()." << endl;
		delete e;
		return;
	}
	cout << "File \"" << what << "\" is owned by " << sd.GetOwnerSid() << endl;

	// if needed:
	// set owner, write SD back
	if ( haveOwner )
	{
		try
		{
			sd.SetOwnerSid( newOwner );
			fksec::SetFileSecurity( what, OWNER_SECURITY_INFORMATION, sd );
			// re-read the SD to make sure that all is well
			fksec::GetFileSecurity( what, OWNER_SECURITY_INFORMATION, sd );
			cout << "File \"" << what << "\" is now owned by " << sd.GetOwnerSid() << endl;
		}
		catch ( fksec::ex *e )
		{
			clog << "Skipping file \"" << what << "\", error " << GetLastError() << " setting ownership." << endl;
			delete e;
			return;
		}
	}
}


void Grab( const char *what )
{
	// this is where we will soon sort files from other things
	GrabFile( what );
}

