#include #include #include #pragma hdrstop #define MAXLEN 256 #define CHUNK 32 struct Session { char *client; // client machine char *user; // user name DWORD time; // idle since (seconds) }; struct SessionList { int nReserved; int nUsed; // number of elements Session *s; // points to array of Session structs containing the info we want }; // we do all our declares ourselves. To learn why, check out // http://www.mvps.org/network/nt95.html // ----- cut here ----- NT declarations #define NET_API_STATUS DWORD #define NET_API_FUNCTION __stdcall typedef NET_API_STATUS (NET_API_FUNCTION *NetSessionEnum_NT)( LPWSTR servername, LPWSTR UncClientName, LPWSTR username, DWORD level, LPBYTE *bufptr, DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries, LPDWORD resume_handle ); typedef NET_API_STATUS (NET_API_FUNCTION *NetApiBufferFree_NT)( LPVOID Buffer ); struct SESSION_INFO_10_NT { LPWSTR sesi10_cname; LPWSTR sesi10_username; DWORD sesi10_time; DWORD sesi10_idle_time; }; // ----- cut here ----- 95 declarations #define API_FUNCTION DECLSPEC_IMPORT API_RET_TYPE APIENTRY typedef __declspec(dllimport) DWORD (__stdcall *NetSessionEnum_95)( const char FAR *pszServer, short sLevel, char FAR *pbBuffer, unsigned short cbBuffer, unsigned short FAR *pcEntriesRead, unsigned short FAR *pcTotalAvail ); #pragma pack(push, 1) struct session_info_0_95 { char FAR *sesi0_cname; }; struct session_info_10_95 { char FAR *sesi10_cname; char FAR *sesi10_username; unsigned long sesi10_time; unsigned long sesi10_idle_time; }; struct session_info_50_95 { char FAR *sesi50_cname; char FAR *sesi50_username; unsigned long sesi50_key; unsigned short sesi50_num_conns; unsigned short sesi50_num_opens; unsigned long sesi50_time; unsigned long sesi50_idle_time; unsigned char sesi50_protocol; unsigned char pad1; }; #pragma pack(pop) // ----- cut here ----- End of OS-specific declarations void FillSessionList95( const char *server, SessionList& sl ) { char *buf; int bufsize, level, successLevel; session_info_10_95 *cur10; session_info_50_95 *cur50; NetSessionEnum_95 pNSE; HINSTANCE hDLL; DWORD rc, i; WORD read, total; hDLL = LoadLibrary( "svrapi.dll" ); if ( hDLL == NULL ) { printf( "LoadLibrary( \"svrapi.dll\" ): gle = %lu\n", GetLastError() ); exit( 1 ); } pNSE = (NetSessionEnum_95) GetProcAddress( hDLL, "NetSessionEnum" ); if ( pNSE == NULL ) { printf( "GetProcAddress( \"svrapi.dll\" ): gle = %lu\n", GetLastError() ); exit( 1 ); } buf = NULL; successLevel = 90; // try levels 10 and 50 in this order, until we don't get a level error for ( rc = ERROR_INVALID_LEVEL, level = 10; rc == ERROR_INVALID_LEVEL && level <= 50; level += 40 ) { bufsize = 1024; do { printf( "Trying: level %d, bufsize = %d bytes\n", level, bufsize ); free( buf ); buf = (char *) malloc( bufsize ); // NOTE: pre-Jul98 Platform SDKs had bugs in the headers // and required a cast for the first three args (to char*). rc = pNSE( server, level, buf, bufsize, &read, &total ); // printf( "rc = %ld; server = %s, level = %d, buf = %p, bufsize = %d, read = %d, total = %d\n", // (int) rc, server, level, buf, bufsize, (int) read, (int) total ); if ( rc == 0 ) successLevel = level; bufsize += 1024; } while ( bufsize < 65536 && ( rc == ERROR_MORE_DATA || rc == ERROR_INVALID_PARAMETER ) ); } if ( rc != ERROR_SUCCESS ) { printf( "NSE() returned %lu\n", rc ); exit( 1 ); } // belts and braces if ( successLevel != 10 && successLevel != 50 ) { printf( "why is successLevel == %d?\n", successLevel ); exit( 1 ); } if ( (DWORD) ( sl.nReserved - sl.nUsed ) < read ) { // make some room in the list sl.s = (Session *) realloc( sl.s, ( sl.nReserved + max( CHUNK, read ) ) * sizeof sl.s[0] ); if ( sl.s == NULL ) { printf( "Unable to get memory for %d additional sessions.\n", max( CHUNK, read ) ); exit( 1 ); } sl.nReserved += max( CHUNK, read ); } switch ( successLevel ) { case 10: for ( i = 0, cur10 = (session_info_10_95 *) buf; i < read; ++ i, ++ cur10 ) { memset( &sl.s[sl.nUsed], '\0', sizeof sl.s[sl.nUsed] ); if ( cur10->sesi10_cname != NULL ) sl.s[sl.nUsed].client = strdup( cur10->sesi10_cname ); if ( cur10->sesi10_username != NULL ) sl.s[sl.nUsed].user = strdup( cur10->sesi10_username ); sl.s[sl.nUsed].time = cur10->sesi10_time; ++ sl.nUsed; } break; case 50: for ( i = 0, cur50 = (session_info_50_95 *) buf; i < read; ++ i, ++ cur50 ) { memset( &sl.s[sl.nUsed], '\0', sizeof sl.s[sl.nUsed] ); if ( cur50->sesi50_cname != NULL ) sl.s[sl.nUsed].client = strdup( cur50->sesi50_cname ); if ( cur50->sesi50_username != NULL ) sl.s[sl.nUsed].user = strdup( cur50->sesi50_username ); sl.s[sl.nUsed].time = cur50->sesi50_time; ++ sl.nUsed; } break; default: printf( "why is successLevel == %d, and why didn't the " "earlier \"if\" catch it?\n", successLevel ); exit( 1 ); break; } FreeLibrary( hDLL ); free( buf ); } void FillSessionListNT( const char *server, const char *client, const char *user, SessionList& sl ) { SESSION_INFO_10_NT *buf; SESSION_INFO_10_NT *cur; DWORD read, total, resumeh, rc, i; char tt[MAXLEN]; wchar_t *wserver = NULL, *wclient = NULL, *wuser = NULL; NetSessionEnum_NT pNSE = NULL; NetApiBufferFree_NT pNABF = NULL; HINSTANCE hDLL; hDLL = LoadLibrary( "netapi32.dll" ); if ( hDLL == NULL ) { printf( "LoadLibrary( \"netapi32.dll\" ): gle = %lu\n", GetLastError() ); exit( 1 ); } pNSE = (NetSessionEnum_NT) GetProcAddress( hDLL, "NetSessionEnum" ); pNABF = (NetApiBufferFree_NT) GetProcAddress( hDLL, "NetApiBufferFree" ); if ( pNSE == NULL || pNABF == NULL ) { printf( "GetProcAddress( \"netapi32.dll\" ) returned NULL\n" ); exit( 1 ); } if ( server != NULL ) { wserver = (wchar_t *) malloc( ( strlen( server ) + 10 ) * 2 ); mbstowcs( wserver, server, -1 ); } if ( client != NULL ) { wclient = (wchar_t *) malloc( ( strlen( client ) + 10 ) * 2 ); mbstowcs( wclient, client, -1 ); } if ( user != NULL ) { wuser = (wchar_t *) malloc( ( strlen( user ) + 10 ) * 2 ); mbstowcs( wuser, user, -1 ); } resumeh = 0; do { buf = NULL; // NOTE: pre-Jul98 Platform SDKs had bugs in the headers // and required a cast for the first three args (to char*). rc = pNSE( wserver, wclient, wuser, 10, (BYTE **) &buf, 2048, &read, &total, &resumeh ); if ( rc != ERROR_MORE_DATA && rc != ERROR_SUCCESS ) break; if ( (DWORD) ( sl.nReserved - sl.nUsed ) < read ) { // make some room in the list sl.s = (Session *) realloc( sl.s, ( sl.nReserved + max( CHUNK, read ) ) * sizeof sl.s[0] ); if ( sl.s == NULL ) { printf( "Unable to get memory for %d additional sessions.\n", max( CHUNK, read ) ); exit( 1 ); } sl.nReserved += max( CHUNK, read ); } printf( "\ngot %lu entries out of %lu\n", read, total ); for ( i = 0, cur = buf; i < read; ++ i, ++ cur ) { memset( &sl.s[sl.nUsed], '\0', sizeof sl.s[sl.nUsed] ); if ( cur->sesi10_cname != NULL ) { wcstombs( tt, cur->sesi10_cname, MAXLEN ); sl.s[sl.nUsed].client = strdup( tt ); } if ( cur->sesi10_username != NULL ) { wcstombs( tt, cur->sesi10_username, MAXLEN ); sl.s[sl.nUsed].user = strdup( tt ); } sl.s[sl.nUsed].time = cur->sesi10_time; ++ sl.nUsed; } if ( buf != NULL ) pNABF( buf ); } while ( rc == ERROR_MORE_DATA ); FreeLibrary( hDLL ); if ( rc != ERROR_SUCCESS ) printf( "NSE() returned %lu\n", rc ); free( wserver ); free( wclient ); free( wuser); } void ShowSessionList( const char *server, const char *client, const char *user ) { OSVERSIONINFO ovi = { sizeof ovi }; SessionList sl = { 0, 0, NULL }; int i; GetVersionEx( &ovi ); switch ( ovi.dwPlatformId ) { case VER_PLATFORM_WIN32_WINDOWS: FillSessionList95( server, sl ); break; case VER_PLATFORM_WIN32_NT: FillSessionListNT( server, client, user, sl ); break; default: puts( "Sorry, but this sample requires Windows 9x or NT." ); exit( 1 ); } printf( "%-30.30s %-30.30s %-8.8s\n", "Client", "User", "Idle sec" ); printf( "%-30.30s %-30.30s %-8.8s\n", "------------------------------", "------------------------------", "--------" ); for ( i = 0; i < sl.nUsed; ++ i ) { printf( "%-30.30s %-30.30s %02d:%02d:%02d\n", sl.s[i].client == NULL? "": sl.s[i].client, sl.s[i].user == NULL? "": sl.s[i].user, sl.s[i].time / 3600, ( sl.s[i].time % 3600 ) / 60, sl.s[i].time % 60 ); free( sl.s[i].client ); free( sl.s[i].user ); } free( sl.s ); } int main( int argc, char *argv[] ) { const char *server = NULL, *user = NULL, *client = NULL; int errors = 0, i; bool haveServer = false, haveUser = false, haveClient = false; if ( argc > 7 ) { usage: puts( "\nnsesse2 [-s \\\\server] [-c \\\\computername|-u username]\n" ); puts( "\\\\server -- machine to check, with backslashes, please." ); puts( " Default: local machine.\n" ); puts( "\\\\computername -- only list sessions from this computer." ); puts( " Default: all computers.\n" ); puts( "username -- only list sessions logged in as username." ); puts( " Default: all users.\n" ); puts( "You can use -c, or -u, or neither -- but not both together." ); puts( "On Win9X, both -c and -u will be ignored." ); return 1; } for ( i = 1; i < argc; ++ i ) { if ( *argv[i] != '-' && *argv[1] != '/' ) { printf( "\"%s\": switches must start with a dash or a slash.\n", argv[i] ); ++ errors; continue; } switch ( argv[i][1] ) { case '?': goto usage; case 's': if ( i == argc - 1 ) // no further args? { printf( "\"%s\" requires the server name as an argument.\n", argv[i] ); ++ errors; break; } if ( haveServer ) { printf( "\"%s\" can only be used once.\n", argv[i] ); ++ errors; ++ i; // skip what probably is another server name break; } ++ i; // advance arg index to account for server name server = argv[i]; haveServer = true; break; case 'c': if ( i == argc - 1 ) // no further args? { printf( "\"%s\" requires the client name as an argument.\n", argv[i] ); ++ errors; break; } if ( haveClient ) { printf( "\"%s\" can only be used once.\n", argv[i] ); ++ i; ++ errors; break; } ++ i; client = argv[i]; haveClient = true; if ( client[0] != '\\' || client[1] != '\\' ) { printf( "\"%s\" should start with a double backslash \"\\\\\".\n", client ); ++ errors; } break; case 'u': if ( i == argc - 1 ) // no further args? { printf( "\"%s\" requires the user name as an argument.\n", argv[i] ); ++ errors; break; } if ( haveUser ) { printf( "\"%s\" can only be used once.\n", argv[i] ); ++ i; ++ errors; break; } ++ i; user = argv[i]; haveUser = true; break; default: printf( "\"%s\" is not a valid switch, sorry.\n", argv[i] ); ++ errors; break; } } if ( errors ) { printf( "\n%d command line errors. Pass GO, do not collect $200.\n\n", errors ); goto usage; } ShowSessionList( server, client, user ); return i; }