// netview.cpp : Defines the entry point for the console application.
//
/*
             _         _               
  _ __   ___| |___   _(_) _____      __
 | '_ \ / _ \ __\ \ / / |/ _ \ \ /\ / /
 | | | |  __/ |_ \ V /| |  __/\ V  V / 
 |_| |_|\___|\__| \_/ |_|\___| \_/\_/  
                        by mubix [at] hak5.org               
                        v1.1

						*/
/*
Kali 
/usr/bin/i586-mingw32msvc-g++ netview.cpp -D__MINGW32__ -DWINVER=0x0501 -DUNICODE -D_UNICODE -s -Wl,--subsystem,windows -Wall -g -I"/usr/i586-mingw32msvc/include" -I"/usr/amd64-mingw32msvc/include/sec_api" -L"/usr/i586-mingw32msvc/lib" -lws2_32 -lnetapi32 -ladvapi32 -lmingw32 -o netview.exe
*/

#ifndef _UNICODE
#define _UNICODE
#endif
#ifndef UNICODE
#define UNICODE
#endif
// C includes
#include <vector>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <cstdlib>
#include <ctime>
#include <algorithm>
					
// Windows includes 
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h> 
#include <lm.h>
#include "./banned.h"

#pragma warning(disable:4996)

using namespace std;

#ifdef __MINGW32__
// This is if __MINGW32__ is not placed as a -D flag for the complier.
// The compiler will default to _WIN32 options. 
#else

#pragma comment(lib, "netapi32.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "advapi32.lib")
#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_DEPRECATE 1
#endif

void print_help();
void netview_enum(vector<wstring> &hosts, wchar_t *domain);
void net_enum(wchar_t *host, wchar_t *domain);
void ip_enum(wchar_t *host);
void group_enum(vector<wstring> &users, wchar_t *group);
void share_enum(wchar_t *host, bool bCheckShareAccess);
void session_enum(vector<wstring> &users, wchar_t *host);
void loggedon_enum(vector<wstring> &users, wchar_t *host);
bool CanAccessFolder( LPCTSTR folderName, DWORD genericAccessRights );

#ifdef __MINGW32__
//This option is to handle the Unicode mangling with the wmain error.
//By default wmain's entry point is not found this is a temporary fix.
//https://github.com/coderforlife/mingw-unicode-main
#include "mingw-unicode.c"
#endif
int wmain(int argc, wchar_t * argv[])
{
	FILE *file_of_hosts;
	FILE *file_exclude_hosts;
	FILE *outputfile;
	BOOL bReadFromFile = FALSE;
	BOOL bDomainspecified = FALSE;
	BOOL bCheckShareAccess = FALSE;
	BOOL bReadFromFileArg = FALSE;
	BOOL bDomainArg = FALSE;
	BOOL bOutputToFile = FALSE;
	wchar_t *domain = NULL;
	wchar_t *group = NULL;
	wchar_t *host = NULL;
	wchar_t *tempHost = NULL;
	int interval = 0;
	double jitter = 0;
	char *filename;
	char *outputfilename;
	char line[255];
	char tmphost[255];
	vector<wstring> hosts;
	vector<wstring> users;
	vector<wstring> excludeHosts;

	// Don't buffer anything!
	setbuf(stdout, NULL);

	if (argc == 1)
	{ 
		print_help();
		return 0;
	}

	// Parse cmdline arguments
	for (int nArg=0; nArg < argc; nArg++)
	{
		if (!_wcsicmp(argv[nArg], L"-h"))
		{
			print_help();
			exit(0);
		}
		if (!_wcsicmp(argv[nArg], L"-o"))
		{
			if ((nArg + 1) > (argc - 1) || !_wcsicmp(argv[(nArg + 1)], L"-d") || !_wcsicmp(argv[(nArg + 1)], L"-f") || !_wcsicmp(argv[(nArg + 1)], L"-e") || !_wcsicmp(argv[(nArg + 1)], L"-g") || !_wcsicmp(argv[(nArg + 1)], L"-c") || !_wcsicmp(argv[(nArg + 1)], L"-i") || !_wcsicmp(argv[(nArg + 1)], L"-j"))
			{
				printf("[-] -o used without a file name specified\n");
				return 0;
			}
			else
			{
				const size_t newsize = 255;
				char nstring[newsize];

				#ifdef __MINGW32__
					wcstombs(nstring, argv[(nArg + 1)],newsize);
				#else	
					size_t origsize = wcslen(argv[(nArg + 1)]) + 1;				
					size_t convertedChars = 0;				
					wcstombs_s(&convertedChars, nstring, origsize, argv[(nArg + 1)], _TRUNCATE);				
				#endif

				outputfilename = nstring;

				if((outputfile=freopen(outputfilename, "w" ,stdout))==NULL) {
					printf("Cannot open %s for writing\n",outputfilename);
					exit(1);
				}
			}
		}
		if (!_wcsicmp(argv[nArg], L"-f"))
		{
			bReadFromFileArg = TRUE;
			// file flag initiated, need to check if the file is there
			if ((nArg + 1) > (argc - 1) || !_wcsicmp(argv[(nArg + 1)], L"-d") || !_wcsicmp(argv[(nArg + 1)], L"-o") || !_wcsicmp(argv[(nArg + 1)], L"-e") || !_wcsicmp(argv[(nArg + 1)], L"-g") || !_wcsicmp(argv[(nArg + 1)], L"-c") || !_wcsicmp(argv[(nArg + 1)], L"-i") || !_wcsicmp(argv[(nArg + 1)], L"-j"))
			{
				printf("[-] -f used without a file name specified\n");
				return 0;
			}
			else
			{				
				const size_t newsize = 255;
				char nstring[newsize];
				
				#ifdef __MINGW32__
					wcstombs(nstring, argv[(nArg + 1)],newsize);
				#else	
					size_t origsize = wcslen(argv[(nArg + 1)]) + 1;				
					size_t convertedChars = 0;				
					wcstombs_s(&convertedChars, nstring, origsize, argv[(nArg + 1)], _TRUNCATE);				
				#endif

				filename = nstring;
				bReadFromFile = TRUE;
			}
		}

		// check for domain argument
		if (!_wcsicmp(argv[nArg], L"-d"))
		{
			// domain flag was used
			bDomainArg = TRUE;
			// domain flag specified
			if (((nArg + 1) > (argc - 1)) || !_wcsicmp(argv[(nArg + 1)], L"-f") || !_wcsicmp(argv[(nArg + 1)], L"-o") || !_wcsicmp(argv[(nArg + 1)], L"-e") || !_wcsicmp(argv[(nArg + 1)], L"-g") || !_wcsicmp(argv[(nArg + 1)], L"-i") || !_wcsicmp(argv[(nArg + 1)], L"-c") || !_wcsicmp(argv[(nArg + 1)], L"-j"))
			{
				printf("\n[*] -d used without domain specified - using current domain\n");
			}
			else
			{
				bDomainspecified = TRUE;
				domain = argv[(nArg + 1)];
				printf("[+] Domain Specified: %ls\n", domain);
			}
		}

		// check for exclude file argument
		if (!_wcsicmp(argv[nArg], L"-e"))
		{
			if ((nArg + 1) > (argc - 1) || !_wcsicmp(argv[(nArg + 1)], L"-d") || !_wcsicmp(argv[(nArg + 1)], L"-o") || !_wcsicmp(argv[(nArg + 1)], L"-f") || !_wcsicmp(argv[(nArg + 1)], L"-g") || !_wcsicmp(argv[(nArg + 1)], L"-c") || !_wcsicmp(argv[(nArg + 1)], L"-i") || !_wcsicmp(argv[(nArg + 1)], L"-j"))
			{
				printf("[-] -e used without a file name specified\n");
				return 0;
			}
			else
			{				
				const size_t newsize = 255;
				char nstring[newsize];
				
				#ifdef __MINGW32__
					wcstombs(nstring, argv[(nArg + 1)],newsize);
				#else	
					size_t origsize = wcslen(argv[(nArg + 1)]) + 1;				
					size_t convertedChars = 0;				
					wcstombs_s(&convertedChars, nstring, origsize, argv[(nArg + 1)], _TRUNCATE);				
				#endif

				file_exclude_hosts = fopen(nstring,"r");
				if (file_exclude_hosts == NULL)
				{
					printf("[-] Exclude file not found as specified by -e\n");
				}
				else
				{
					while (fgets(line, sizeof(line)-1,file_exclude_hosts))
					{
						sscanf(line, "%s\n", tmphost);
						const size_t newsize = 255;
						wchar_t wcstring[newsize];
				
						#ifdef __MINGW32__
							mbstowcs(wcstring,tmphost,newsize);
						#else				
							size_t origsize = strlen(tmphost) + 1;				
							size_t convertedChars = 0;				
							mbstowcs_s(&convertedChars, wcstring, origsize, tmphost, _TRUNCATE);
						#endif

						wprintf(L"host: %ls\n", wcstring);
						excludeHosts.push_back(wstring(wcstring));
					}
					fclose(file_exclude_hosts);
				}

			}
		}

		// check for the group argument
		if (!_wcsicmp(argv[nArg], L"-g"))
		{
			if (((nArg + 1) > (argc - 1)) || !_wcsicmp(argv[(nArg + 1)], L"-f") || !_wcsicmp(argv[(nArg + 1)], L"-o") || !_wcsicmp(argv[(nArg + 1)], L"-e") || !_wcsicmp(argv[(nArg + 1)], L"-d") || !_wcsicmp(argv[(nArg + 1)], L"-i") || !_wcsicmp(argv[(nArg + 1)], L"-c") || !_wcsicmp(argv[(nArg + 1)], L"-j"))
			{
				printf("[*] -g used without group specified - using \"Domain Admins\"\n");
				group_enum(users, L"Domain Admins");
			}
			else
			{
				group = argv[(nArg + 1)];
				group_enum(users, group);
			}
		}

		// check if we want to check access to the found shares
		if (!_wcsicmp(argv[nArg], L"-c"))
		{
			bCheckShareAccess = TRUE;
		}

		// check for the interval argument
		if (!_wcsicmp(argv[nArg], L"-i"))
		{
			if (((nArg + 1) > (argc - 1)) || !_wcsicmp(argv[(nArg + 1)], L"-f") || !_wcsicmp(argv[(nArg + 1)], L"-o") || !_wcsicmp(argv[(nArg + 1)], L"-e") || !_wcsicmp(argv[(nArg + 1)], L"-d") || !_wcsicmp(argv[(nArg + 1)], L"-g") || !_wcsicmp(argv[(nArg + 1)], L"-c") || !_wcsicmp(argv[(nArg + 1)], L"-j"))
			{
				printf("[*] -i used without interval specified - ignoring\n");
			}
			else
			{
				interval = _wtoi(argv[(nArg + 1)]);
			}
		}

		// check for the jitter argument
		if (!_wcsicmp(argv[nArg], L"-j"))
		{
			if (((nArg + 1) > (argc - 1)) || !_wcsicmp(argv[(nArg + 1)], L"-f") || !_wcsicmp(argv[(nArg + 1)], L"-o") || !_wcsicmp(argv[(nArg + 1)], L"-e") || !_wcsicmp(argv[(nArg + 1)], L"-d") || !_wcsicmp(argv[(nArg + 1)], L"-g") || !_wcsicmp(argv[(nArg + 1)], L"-c") || !_wcsicmp(argv[(nArg + 1)], L"-i"))
			{
				printf("[*] -j used without jitter specified - ignoring\n");
			}
			else
			{
				jitter = _wtof(argv[(nArg + 1)]);
			}
		}
	}
	
	printf("\n[*] Using interval: %d\n", interval);
	printf("[*] Using jitter: %.2f\n\n", jitter);

	if (bDomainArg && bReadFromFileArg)
	{
		printf("[-] Domain and File specified, can't do both - exiting...\n\n");
		return 0;
	}

	// pull file into array if read from file done
	// pull domain via NetServerEnum into array if read from domain done
	if(bReadFromFileArg)
	{
		printf("Reading from the file\n");
		
		file_of_hosts = fopen(filename,"r");
		
		if (file_of_hosts == NULL)
		{
			printf("[-] File not found as specified by -f\n");
		}
		else
		{
			while (fgets(line, sizeof(line)-1,file_of_hosts))
			{
				sscanf(line, "%s\n", tmphost);
				const size_t newsize = 255;
				wchar_t wcstring[newsize];
				
				#ifdef __MINGW32__
					mbstowcs(wcstring,tmphost,newsize);
				#else				
					size_t origsize = strlen(tmphost) + 1;				
					size_t convertedChars = 0;				
					mbstowcs_s(&convertedChars, wcstring, origsize, tmphost, _TRUNCATE);
				#endif							
				
				hosts.push_back(wstring(wcstring));
			}
			fclose(file_of_hosts);
		}
	}

	if(bDomainArg)
	{
		netview_enum(hosts,domain);
	}
	
	printf("\n[+] Number of hosts: %d\n",hosts.size());

	for (vector<wstring>::iterator it = hosts.begin(); it != hosts.end(); ++it)
	{
		fflush(stdout);
		host = const_cast<wchar_t *>(it->c_str());
		BOOL excludeHost = FALSE;

		// check if the host is in the exclude list, ignoring case
		for (vector<wstring>::iterator it = excludeHosts.begin(); it != excludeHosts.end(); ++it){
			tempHost = const_cast<wchar_t *>(it->c_str());
			if (!_wcsnicmp(host, tempHost, wcslen(host))) {
				excludeHost = TRUE;
			}
		}

		// only enumerate the host if it wasn't in the exclude list
		if (!excludeHost){
			wprintf(L"\n\n[+] Host: %ws", host);
			//wcout << "\n\n[+] Host: " << host << endl;
			net_enum(host,domain);
			ip_enum(host);
			share_enum(host,bCheckShareAccess);
			session_enum(users, host);
			loggedon_enum(users, host);

			if (interval > 0.0){
				srand( time( NULL ) );
				int min = (int) (interval * (1-jitter));
				int max = (int) (interval * (1+jitter));
				int range = max - min + 1;
				int sleep_time = rand() % range + min;
				printf("\n[*] Sleeping: %d seconds", sleep_time);
				//wcout << "\n[*] Sleeping: " << sleep_time << " seconds" << endl;
				Sleep(sleep_time*1000);
			}
		}
	}

	if (bOutputToFile)
	{
		 fclose(outputfile);
	}
	return 0;
}

void print_help(){
	printf("\nNetview Help\n"
	"--------------------------------------------------------------------\n\n"
	"-h \t\t\t: Display this help menu\n"
	"-f filename.txt \t: Specifies a file to pull a list of hosts from\n"
	"-e filename.txt \t: Specifies a file of hostnames to exclude\n"
	"-o filename.txt \t: Out to file instead of STDOUT\n"
	"-d domain \t\t: Specifies a domain to pull a list of hosts from\n"
	"\t\t\t  uses current domain if none specified\n"
	"-g group \t\t: Specify a group name for user hunting\n"
	"\t\t\t  uses 'Domain Admins' if none specified\n"
	"-c\t\t\t: Check found shares for read access\n"
	"-i interval\t\t: Seconds to wait between enumerating hosts\n"
	"-j jitter\t\t: Percent jitter to apply to the interval (0.0-1.0)\n"
	);
	printf("\n");
}

void netview_enum(vector<wstring> &hosts, wchar_t *domain)
{
	NET_API_STATUS nStatus;
	LPWSTR pszServerName = NULL;
	DWORD dwLevel = 101;
	LPSERVER_INFO_101 pBuf = NULL;
	LPSERVER_INFO_101 pTmpBuf;
	DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
	DWORD dwEntriesRead = 0;
	DWORD dwTotalEntries = 0;
	DWORD dwServerType = SV_TYPE_SERVER;
	LPWSTR pszDomainName = domain;
	DWORD dwResumeHandle = 0;


	nStatus = NetServerEnum(pszServerName,
				dwLevel,
				(LPBYTE *) & pBuf,
				dwPrefMaxLen,
				&dwEntriesRead,
				&dwTotalEntries,
				dwServerType,
				pszDomainName,
				&dwResumeHandle);

	if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA))
	{
		if ((pTmpBuf = pBuf) != NULL)
		{
			for (unsigned int i = 0; i < dwEntriesRead; i++)
			{
				assert(pTmpBuf != NULL);
				if (pTmpBuf == NULL)
				{
					fprintf(stderr, "An access violation has occurred\n");
					break;
				}
				else
				{
					hosts.push_back(wstring(pTmpBuf->sv101_name));
	                pTmpBuf++;
				}
			}
		}
	}

	if (pBuf != NULL)
	{
		NetApiBufferFree(pBuf);
	}
}

void net_enum(wchar_t *host, wchar_t *domain)
{
	NET_API_STATUS nStatus;
	LPWSTR pszServerName = host;
	DWORD dwLevel = 101;
	LPSERVER_INFO_101 pBuf = NULL;
	LPSERVER_INFO_101 pTmpBuf;

	wprintf(L"\nEnumerating AD Info");
	//wcout << "\nEnumerating AD Info" << endl;

	nStatus = NetServerGetInfo(pszServerName,
								dwLevel,
								(LPBYTE *) & pBuf
								);

	if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA))
	{
		if ((pTmpBuf = pBuf) != NULL)
		{
			assert(pTmpBuf != NULL);
			if (pTmpBuf == NULL)
			{
				fprintf(stderr, "An access violation has occurred\n");
				return;
			}
			else
			{
				wprintf(L"[+] %ws - Comment - %s\n", host, pTmpBuf->sv101_comment);
				printf("[+] %s - OS Version - %d.%d\n", (char*)host, (int)pTmpBuf->sv101_version_major, (int)pTmpBuf->sv101_version_minor);
				if (pTmpBuf->sv101_type & SV_TYPE_DOMAIN_CTRL)
				{
					wprintf(L"[+] %ws - Domain Controller\n", host);
				}
				if (pTmpBuf->sv101_type & SV_TYPE_DOMAIN_BAKCTRL)
				{
					wprintf(L"[+] %ws - Backup Domain Controller\n", host);
				}

				if (pTmpBuf->sv101_type & SV_TYPE_SQLSERVER)
				{
					wprintf(L"[+] %ws - MSSQL Server\n", host);
				}
			}
		}
	}
	if (pBuf != NULL)
	{
		NetApiBufferFree(pBuf);
	}
}

void ip_enum(wchar_t *host)
{

	WSADATA wsaData;
	int iResult;
	int iRetval;
	DWORD dwRetval;
	
	#ifdef __MINGW32__	
	struct addrinfo *result = NULL;
   	struct addrinfo *ptr = NULL;
    	struct addrinfo hints;
	#else
	// This struct call is used for the Visual Studio Compiler and
	// does not work with the MinGW Compiler's libs as of yet.
	ADDRINFOW *result = NULL;
	ADDRINFOW *ptr = NULL;
	ADDRINFOW hints;
	#endif

	LPSOCKADDR sockaddr_ip;
	wchar_t ipstringbuffer[46];
	DWORD ipbufferlength = 46;

	printf("\nEnumerating IP Info\n");
	iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != 0)
	{
		wprintf(L"WSAStartup failed: %d\n", iResult);
		return;
	}

	ZeroMemory( &hints, sizeof(hints) );
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;


	#ifdef __MINGW32__

	char tmphost[255];
	int len = 0;
	len = wcstombs(tmphost, host, sizeof(tmphost));
	dwRetval = getaddrinfo(tmphost, 0, &hints, &result);

	#else
	// The older veriosn of getaddrinfo is used that does not support Unicode.
	dwRetval = GetAddrInfoW(host, 0, &hints, &result);
	#endif
	
	if ( dwRetval != 0 )
	{
		wprintf(L"[-] %ls - IP(s) could not be enumerated\n", host);
		WSACleanup();
		return;
	}
	else
	{
		// parse each address
		for(ptr=result; ptr != NULL ;ptr=ptr->ai_next)
		{
			switch (ptr->ai_family) {
			case AF_INET:
				wprintf(L"[+] %ls - IPv4 Address - ");
				sockaddr_ip = (LPSOCKADDR) ptr->ai_addr;
				ipbufferlength = 46;
				iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL, ipstringbuffer, &ipbufferlength);
				if (iRetval)
					wprintf(L"WSAAddressToString failed with %u\n", WSAGetLastError() );
				else
					wprintf(L"%ls\n", ipstringbuffer);
					break;
			case AF_INET6:
				wprintf(L"[+] %ws - IPv6 Address - ");
				sockaddr_ip = (LPSOCKADDR) ptr->ai_addr;
				ipbufferlength = 46;
				iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL, ipstringbuffer, &ipbufferlength );
				if (iRetval)
					wprintf(L"WSAAddressToString failed with %u\n", WSAGetLastError() );
				else
					wprintf(L"%ws\n", ipstringbuffer);
					break;
			default:
				wprintf(L"Other %ld\n", ptr->ai_family);
				break;
			}
		}
		#ifdef __MINGW32__
		freeaddrinfo(result);
		#else
		// The older veriosn of freeaddrinfo is used that does not support Unicode.
		FreeAddrInfoW(result);
		#endif		

		WSACleanup();
	}
}

void group_enum(vector<wstring> &users, wchar_t *group)
{
		
		NET_API_STATUS res;

		// first, get the primary DC for this machine
		LPCWSTR lpDcName = NULL;
		res = NetGetDCName(NULL, NULL, (LPBYTE *) &lpDcName);
		if (res == NERR_Success){
			wprintf(L"\n[+] Primary DC: %ls\n", lpDcName);
		}
		else{
			// return if there was an error, since we won't be able
			// to retrieve any users
			wprintf(L"\n[-] Error: could not retrieve primary DC\n");
			return;
		}

		// double check to make sure we got a DC name
		if (!lpDcName){
			wprintf(L"[-] Error: could not retrieve primary DC\n");
			return;
		}

		wprintf(L"\nEnumerating members of domain group \"%ls\"\n", group);

		// query the DC for all users from the given group
		GROUP_USERS_INFO_0 *BufPtr, *p;
		DWORD er=0,tr=0,resume=0, t;
		res = NetGroupGetUsers(lpDcName,group,0,(LPBYTE *)&BufPtr,
								MAX_PREFERRED_LENGTH,&er,&tr,NULL);

		if(res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
		{
			p=BufPtr;
			for(t=1;t<=er;t++)
			{
				wprintf(L"[+] \"%ls\" user: %ls\n", group, p->grui0_name);
				users.push_back(wstring(p->grui0_name));
				p++;
			}
		}
		else if (res == NERR_GroupNotFound){
			wprintf(L"[-] Error: group name not found\n");
		}
		else
		{ 
			wprintf(L"[-] Error %d\n", res);
		}

		if (BufPtr != NULL){
			NetApiBufferFree(BufPtr);
		}
}

void share_enum(wchar_t *host, bool bCheckShareAccess)
{
	PSHARE_INFO_1 BufPtr,p;
	NET_API_STATUS res;
	DWORD er=0,tr=0,resume=0, t;

	printf("\nEnumerating Share Info\n");
	do
	{
		res = NetShareEnum (host, 1, (LPBYTE *) &BufPtr, MAX_PREFERRED_LENGTH, &er, &tr, &resume);
					
		if(res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
		{
			p=BufPtr;
			for(t=1;t<=er;t++)
			{
				wprintf(L"[+] %ls - Share : %-20s : %-30s\n", host, p->shi1_netname, p->shi1_remark);
				
				// skip IPC$, and see if we want to check access to this share
				if (_wcsicmp(p->shi1_netname, L"IPC$") && bCheckShareAccess){
					wchar_t path[255];
					swprintf(path, 255, L"\\\\%s\\%s", host, p->shi1_netname);

					if(CanAccessFolder(path, GENERIC_READ)){
						wprintf(L"[+] Read access to: %ls\n", path);
					}
					else{
						wprintf(L"[-] No access to:%ls\n", path);
					}
				}
				p++;
			}
			NetApiBufferFree(BufPtr);
		} 
		else
		{ 
			wprintf(L"[-] %ls - Share - Error: %ld\n", host, res);
		}  
	} while (res==ERROR_MORE_DATA);
}

void session_enum(vector<wstring> &users, wchar_t *host)
{
	LPSESSION_INFO_10 pBuf = NULL;
	LPSESSION_INFO_10 pTmpBuf = NULL;
	DWORD dwLevel = 10;
	DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
	DWORD dwEntriesRead = 0;
	DWORD dwTotalEntries = 0;
	DWORD dwResumeHandle = 0;
	DWORD i;
	DWORD dwTotalCount = 0;
	LPTSTR pszClientName = NULL;
	LPTSTR pszUserName = NULL;
	NET_API_STATUS nStatus;
	wchar_t *user = NULL;

	printf("\nEnumerating Session Info\n");

	do
	{
		nStatus = NetSessionEnum(host,
					pszClientName,
					pszUserName,
					dwLevel,
					(LPBYTE*)&pBuf,
					dwPrefMaxLen,
					&dwEntriesRead,
					&dwTotalEntries,
					&dwResumeHandle);

		if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA))
		{
			if ((pTmpBuf = pBuf) != NULL)
			{
				for (i = 0; (i < dwEntriesRead); i++)
				{
					assert(pTmpBuf != NULL);
					if (pTmpBuf == NULL)
					{
						fprintf(stderr, "An access violation has occurred\n");
						break;
					}

					wprintf(L"[+] %ws - Session - %s from %s - Active: %d - Idle: %d\n",
						host,
						pTmpBuf->sesi10_username,
						pTmpBuf->sesi10_cname,
						pTmpBuf->sesi10_time,
						pTmpBuf->sesi10_idle_time
						);

					// check if the user is in the target user list if one is specified
					for (vector<wstring>::iterator it = users.begin(); it != users.end(); ++it){
						user = const_cast<wchar_t *>(it->c_str());
						if (!_wcsicmp(user, (pTmpBuf->sesi10_username))) {
							wprintf(L"[+] %ws - Target user found - %s\n", host, pTmpBuf->sesi10_username);
						}
					}
					
					pTmpBuf++;
					dwTotalCount++;
				}
			}
		}
		else
		{
			wprintf(L"[-] %ls - Session - Error: %ld\n", host, nStatus);
		}

		if (pBuf != NULL)
		{
			NetApiBufferFree(pBuf);
			pBuf = NULL;
		}
	} while (nStatus == ERROR_MORE_DATA);
   
	if (pBuf != NULL)
	{
		NetApiBufferFree(pBuf);
	}
}

void loggedon_enum(vector<wstring> &users, wchar_t *host)
{
	LPWKSTA_USER_INFO_1 pBuf = NULL;
	LPWKSTA_USER_INFO_1 pTmpBuf;
	DWORD dwLevel = 1;
	DWORD dwEntriesRead = 0;
	DWORD dwTotalEntries = 0;
	DWORD dwResumeHandle = 0;
	DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
	DWORD z;
	DWORD dwTotalCount = 0;
	NET_API_STATUS nStatus;
	wchar_t *user = NULL;
	
	printf("\nEnumerating Logged-on Users\n");
	do
	{
		nStatus = NetWkstaUserEnum(host,
					dwLevel,
					(LPBYTE*)&pBuf,
					dwPrefMaxLen,
					&dwEntriesRead,
					&dwTotalEntries,
					&dwResumeHandle);

		if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA))
		{
			if ((pTmpBuf = pBuf) != NULL)
			{
				for (z = 0; (z < dwEntriesRead); z++)
				{
					assert(pTmpBuf != NULL);
					if (pTmpBuf == NULL)
					{
						fprintf(stderr, "An access violation has occurred\n");
						break;
					}
						   
					if (!wcschr((wchar_t*)(pTmpBuf)->wkui1_username, L'$'))
					{
						wprintf(L"[+] %ws - Logged-on - %s\\%s\n", host, pTmpBuf->wkui1_logon_domain, pTmpBuf->wkui1_username);

						// check if the user is in the target user list if one is specified
						for (vector<wstring>::iterator it = users.begin(); it != users.end(); ++it){
							user = const_cast<wchar_t *>(it->c_str());
							if (!_wcsicmp(user, (pTmpBuf->wkui1_username))) {
								wprintf(L"[+] %ws - Target user found - %s\\%s\n", host, pTmpBuf->wkui1_logon_domain, pTmpBuf->wkui1_username);
							}
						}

					}

					pTmpBuf++;
					dwTotalCount++;
				}
			}
			else
			{
				wprintf(L"[-] %ls - Logged-on - Error: %ld\n", host, nStatus);
			}
		}

	} while (nStatus == ERROR_MORE_DATA);

	if (pBuf != NULL)
	{
		NetApiBufferFree(pBuf);
		pBuf = NULL;
	}
}

// function shamelessly stolen from Aaron Ballman's code sample
// at http://blog.aaronballman.com/2011/08/how-to-check-access-rights/
bool CanAccessFolder( LPCTSTR folderName, DWORD genericAccessRights )
{
    bool bRet = false;
    DWORD length = 0;
    if (!::GetFileSecurity( folderName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION 
            | DACL_SECURITY_INFORMATION, NULL, NULL, &length ) && 
            ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) {
        PSECURITY_DESCRIPTOR security = static_cast< PSECURITY_DESCRIPTOR >( ::malloc( length ) );
        if (security && ::GetFileSecurity( folderName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
                            | DACL_SECURITY_INFORMATION, security, length, &length )) {
            HANDLE hToken = NULL;
            if (::OpenProcessToken( ::GetCurrentProcess(), TOKEN_IMPERSONATE | TOKEN_QUERY | 
                    TOKEN_DUPLICATE | STANDARD_RIGHTS_READ, &hToken )) {
                HANDLE hImpersonatedToken = NULL;
                if (::DuplicateToken( hToken, SecurityImpersonation, &hImpersonatedToken )) {
                    GENERIC_MAPPING mapping = { 0xFFFFFFFF };
                    PRIVILEGE_SET privileges = { 0 };
                    DWORD grantedAccess = 0, privilegesLength = sizeof( privileges );
                    BOOL result = FALSE;
 
                    mapping.GenericRead = FILE_GENERIC_READ;
                    mapping.GenericWrite = FILE_GENERIC_WRITE;
                    mapping.GenericExecute = FILE_GENERIC_EXECUTE;
                    mapping.GenericAll = FILE_ALL_ACCESS;
 
                    ::MapGenericMask( &genericAccessRights, &mapping );
                    if (::AccessCheck( security, hImpersonatedToken, genericAccessRights, 
                            &mapping, &privileges, &privilegesLength, &grantedAccess, &result )) {
                        bRet = (result == TRUE);
                    }
                    ::CloseHandle( hImpersonatedToken );
                }
                ::CloseHandle( hToken );
            }
            ::free( security );
        }
    }
 
    return bRet;
}