2015-11-29 17:30:52 +08:00
#ifndef CONFIG
#define CONFIG "config.h"
#endif // CONFIG
#include CONFIG
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
2016-10-14 13:28:23 +08:00
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
2015-11-29 17:30:52 +08:00
#include "vlmcs.h"
2016-10-08 13:35:48 +08:00
#if _MSC_VER
#include <Shlwapi.h>
#endif
2015-11-29 17:30:52 +08:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
2016-10-08 13:35:48 +08:00
#if _MSC_VER
#include "wingetopt.h"
#else
2015-11-29 17:30:52 +08:00
#include <getopt.h>
2016-10-08 13:35:48 +08:00
#endif
2015-11-29 17:30:52 +08:00
#include <sys/types.h>
#include <sys/stat.h>
2016-10-08 13:35:48 +08:00
#ifndef _MSC_VER
2015-11-29 17:30:52 +08:00
#include <unistd.h>
2016-10-08 13:35:48 +08:00
#endif
2015-11-29 17:30:52 +08:00
#ifndef _WIN32
#include <sys/ioctl.h>
#include <termios.h>
#else // _WIN32
#endif // _WIN32
#include "endian.h"
#include "shared_globals.h"
#include "output.h"
#ifndef USE_MSRPC
#include "network.h"
#include "rpc.h"
#else // USE_MSRPC
#include "msrpc-client.h"
#endif // USE_MSRPC
#include "kms.h"
#include "helpers.h"
#include "dns_srv.h"
#define VLMCS_OPTION_GRAB_INI 1
#define VLMCS_OPTION_NO_GRAB_INI 2
2016-08-15 18:35:59 +08:00
#ifndef IS_LIBRARY
2015-11-29 17:30:52 +08:00
// Function Prototypes
static void CreateRequestBase ( REQUEST * Request );
// KMS Parameters
2016-06-06 10:36:00 +08:00
#ifndef NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
static int_fast8_t verbose = FALSE ;
2016-06-06 10:36:00 +08:00
#endif
2015-11-29 17:30:52 +08:00
static int_fast8_t VMInfo = FALSE ;
static int_fast8_t dnsnames = TRUE ;
static int FixedRequests = 0 ;
2016-08-15 18:35:59 +08:00
static DWORD LicenseStatus = 0x02 ;
2015-11-29 17:30:52 +08:00
static const char * CMID = NULL ;
static const char * CMID_prev = NULL ;
static const char * WorkstationName = NULL ;
static int BindingExpiration = 43200 ; //30 days
static const char * RemoteAddr ;
static int_fast8_t ReconnectForEachRequest = FALSE ;
2016-10-14 13:28:23 +08:00
#ifndef USE_MSRPC
2015-11-29 17:30:52 +08:00
static int AddressFamily = AF_UNSPEC ;
2016-10-14 13:28:23 +08:00
#else
static int AddressFamily = 0 ;
#endif // USE_MSRPC
2015-11-29 17:30:52 +08:00
static int_fast8_t incompatibleOptions = 0 ;
static const char * fn_ini_client = NULL ;
2016-12-02 15:56:18 +08:00
//static int_fast16_t kmsVersionMinor = 0;
2020-03-30 01:21:09 -04:00
//static const char* ePidGroup[] = { "Windows", "Office2010", "Office2013", "Office2016" };
2016-12-02 15:56:18 +08:00
static int32_t ActiveProductIndex = 0 ;
static int32_t NCountPolicy = 0 ;
static GUID AppGuid , KmsGuid , SkuGuid ;
static uint16_t MinorVersion = 0 ;
static uint16_t MajorVersion ;
2015-11-29 17:30:52 +08:00
#ifndef NO_DNS
static int_fast8_t NoSrvRecordPriority = FALSE ;
#endif // NO_DNS
2020-03-30 01:21:09 -04:00
//typedef char iniFileEpidLines[4][256];
2015-11-29 17:30:52 +08:00
typedef struct
{
const char * first [ 16 ];
const char * second [ 16 ];
const char * tld [ 22 ];
} DnsNames ;
// Some names for the DNS name random generator
static DnsNames ClientDnsNames =
{
{ "www" , "ftp" , "kms" , "hack-me" , "smtp" , "ns1" , "mx1" , "ns1" , "pop3" , "imap" , "mail" , "dns" , "headquarter" , "we-love" , "_vlmcs._tcp" , "ceo-laptop" },
{ ".microsoft" , ".apple" , ".amazon" , ".samsung" , ".adobe" , ".google" , ".yahoo" , ".facebook" , ".ubuntu" , ".oracle" , ".borland" , ".htc" , ".acer" , ".windows" , ".linux" , ".sony" },
{ ".com" , ".net" , ".org" , ".cn" , ".co.uk" , ".de" , ".com.tw" , ".us" , ".fr" , ".it" , ".me" , ".info" , ".biz" , ".co.jp" , ".ua" , ".at" , ".es" , ".pro" , ".by" , ".ru" , ".pl" , ".kr" }
};
// Request Count Control Variables
static int RequestsToGo = 1 ;
static BOOL firstRequestSent = FALSE ;
static void string2UuidOrExit ( const char * const restrict input , GUID * const restrict guid )
{
2016-12-02 15:56:18 +08:00
if ( strlen ( input ) != GUID_STRING_LENGTH || ! string2UuidLE ( input , guid ))
2015-11-29 17:30:52 +08:00
{
errorout ( "Fatal: Command line contains an invalid GUID. \n " );
2016-10-24 21:32:24 +08:00
exit ( VLMCSD_EINVAL );
2015-11-29 17:30:52 +08:00
}
}
#ifndef NO_HELP
__noreturn static void clientUsage ( const char * const programName )
{
errorout (
"vlmcs %s \n\n "
# ifndef NO_DNS
2016-10-14 13:28:23 +08:00
"Usage: %s [options] [ <host>[:<port>] | .<domain> | - ] [options] \n\n "
2015-11-29 17:30:52 +08:00
# else // DNS
2016-10-14 13:28:23 +08:00
"Usage: %s [options] [<host>[:<port>]] [options] \n\n "
2015-11-29 17:30:52 +08:00
# endif // DNS
"Options: \n\n "
2016-06-06 10:36:00 +08:00
# ifndef NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
" -v Be verbose \n "
2016-06-06 10:36:00 +08:00
# endif
2015-11-29 17:30:52 +08:00
" -l <app> \n "
" -4 Force V4 protocol \n "
" -5 Force V5 protocol \n "
" -6 Force V6 protocol \n "
# ifndef USE_MSRPC
" -i <IpVersion> Use IP protocol (4 or 6) \n "
# endif // USE_MSRPC
2016-12-02 15:56:18 +08:00
# ifndef NO_EXTERNAL_DATA
" -j <file> Load external KMS data file <file> \n "
# endif // NO_EXTERNAL_DATA
2015-11-29 17:30:52 +08:00
" -e Show some valid examples \n "
" -x Show valid Apps \n "
2016-06-06 10:36:00 +08:00
" -d no DNS names, use Netbios names (no effect if -w is used) \n "
" -V show version information and exit \n\n "
2015-11-29 17:30:52 +08:00
"Advanced options: \n\n "
" -a <AppGUID> Use custom Application GUID \n "
" -s <ActGUID> Use custom Activation Configuration GUID \n "
" -k <KmsGUID> Use custom KMS GUID \n "
" -c <ClientGUID> Use custom Client GUID. Default: Use random \n "
" -o <PreviousClientGUID> Use custom Prevoius Client GUID. Default: ZeroGUID \n "
2016-08-15 18:35:59 +08:00
" -K <ProtocolVersion> Use a specific (possibly invalid) protocol version \n "
2015-11-29 17:30:52 +08:00
" -w <Workstation> Use custom workstation name. Default: Use random \n "
" -r <RequiredClientCount> Fake required clients \n "
" -n <Requests> Fixed # of requests (Default: Enough to charge) \n "
" -m Pretend to be a virtual machine \n "
" -G <file> Get ePID/HwId data and write to <file>. Can't be used with -l, -4, -5, -6, -a, -s, -k, -r and -n \n "
# ifndef USE_MSRPC
" -T Use a new TCP connection for each request. \n "
" -N <0|1> disable or enable NDR64. Default: 1 \n "
" -B <0|1> disable or enable RPC bind time feature negotiation. Default: 1 \n "
# endif // USE_MSRPC
" -t <LicenseStatus> Use specfic license status (0 <= T <= 6) \n "
" -g <BindingExpiration> Use a specfic binding expiration time in minutes. Default 43200 \n "
# ifndef NO_DNS
" -P Ignore priority and weight in DNS SRV records \n "
# endif // NO_DNS
# ifndef USE_MSRPC
" -p Don't use multiplexed RPC bind \n "
# endif // USE_MSRPC
" \n "
"<port>: \t\t TCP port name of the KMS to use. Default 1688. \n "
"<host>: \t\t host name of the KMS to use. Default 127.0.0.1 \n "
# ifndef NO_DNS
".<domain>: \t find KMS server in <domain> via DNS \n "
# endif // NO_DNS
"<app>: \t\t (Type %s -x to see a list of valid apps) \n\n " ,
Version , programName , programName
);
2016-10-24 21:32:24 +08:00
exit ( VLMCSD_EINVAL );
2015-11-29 17:30:52 +08:00
}
__pure static int getLineWidth ( void )
{
2016-10-14 13:28:23 +08:00
#ifdef TERMINAL_FIXED_WIDTH // For Toolchains that to not have winsize
2015-11-29 17:30:52 +08:00
return TERMINAL_FIXED_WIDTH ;
2016-10-14 13:28:23 +08:00
#else // Can determine width of terminal
#ifndef _WIN32
2015-11-29 17:30:52 +08:00
struct winsize w ;
2016-10-14 13:28:23 +08:00
if ( ioctl ( STDOUT_FILENO , TIOCGWINSZ , & w ))
2015-11-29 17:30:52 +08:00
{
return 80 ; // Return this if stdout is not a tty
}
return w . ws_col ;
2016-10-14 13:28:23 +08:00
#else // _WIN32
2015-11-29 17:30:52 +08:00
CONSOLE_SCREEN_BUFFER_INFO csbiInfo ;
HANDLE hStdout = GetStdHandle ( STD_OUTPUT_HANDLE );
if ( ! GetConsoleScreenBufferInfo ( hStdout , & csbiInfo ))
{
return 80 ; // Return this if stdout is not a Console
}
return csbiInfo . srWindow . Right - csbiInfo . srWindow . Left ;
2016-10-14 13:28:23 +08:00
#endif // WIN32
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
#endif // Can determine width of terminal
2015-11-29 17:30:52 +08:00
}
__noreturn static void showProducts ( PRINTFUNC p )
{
int cols = getLineWidth ();
int itemsPerLine ;
uint8_t i ;
2016-12-02 15:56:18 +08:00
int32_t index ;
2015-11-29 17:30:52 +08:00
uint_fast8_t longestString = 0 ;
2016-12-02 15:56:18 +08:00
int32_t k , items = KmsData -> SkuItemCount ;
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
p ( "You may use these product names or numbers: \n\n " );
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
for ( index = 0 ; index < KmsData -> SkuItemCount ; index ++ )
2015-11-29 17:30:52 +08:00
{
2016-12-02 15:56:18 +08:00
uint_fast8_t len = ( uint_fast8_t ) strlen ( KmsData -> SkuItemList [ index ]. Name );
if ( len > longestString ) longestString = len ;
2015-11-29 17:30:52 +08:00
}
itemsPerLine = cols / ( longestString + 10 );
if ( ! itemsPerLine ) itemsPerLine = 1 ;
uint8_t lines = items / itemsPerLine ;
if ( items % itemsPerLine ) lines ++ ;
for ( i = 0 ; i < lines ; i ++ )
{
for ( k = 0 ; k < itemsPerLine ; k ++ )
{
uint8_t j ;
2016-12-02 15:56:18 +08:00
index = k * lines + i ;
2015-11-29 17:30:52 +08:00
if ( index >= items ) break ;
2016-12-02 15:56:18 +08:00
p ( "%3u = %s" , index + 1 , KmsData -> SkuItemList [ index ]. Name );
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
for ( j = 0 ; j < longestString + 4 - strlen ( KmsData -> SkuItemList [ index ]. Name ); j ++ )
2015-11-29 17:30:52 +08:00
{
p ( " " );
}
}
p ( " \n " );
}
p ( " \n " );
exit ( 0 );
}
__noreturn static void examples ( const char * const programName )
{
printf (
2016-12-02 15:56:18 +08:00
" \n Request activation for Office 2013 using V4 protocol from 192.168.1.5:1688 \n "
" \t %s -l \" Office 2013 Professional \" -4 192.168.1.5 \n "
" \t %s -l \" Office 2013 Professional \" -4 192.168.1.5:1688 \n\n "
2015-11-29 17:30:52 +08:00
"Request activation for Windows Server 2012 using V4 protocol from localhost:1688 \n "
2016-12-02 15:56:18 +08:00
" \t %s -4 -l \" Windows Server 2012 \" -k 8665cb71-468c-4aa3-a337-cb9bc9d5eaac \n "
" \t %s -4 -l \" Windows Server 2012 \"\n "
" \t %s -4 -l \" Windows Server 2012 \" [::1]:1688 \n "
" \t %s -4 -l \" Windows Server 2012 \" 127.0.0.2:1688 \n\n "
2015-11-29 17:30:52 +08:00
"Send 100,000 requests to localhost:1688 \n "
2016-12-02 15:56:18 +08:00
" \t %s -n 100000 \n\n "
2015-11-29 17:30:52 +08:00
"Request Activation for Windows 8 from 10.0.0.1:4711 and pretend to be Steve Ballmer \n "
2016-12-02 15:56:18 +08:00
" \t %s -l \" Windows 8 Professional \" -w steveb1.redmond.microsoft.com 10.0.0.1:4711 \n\n " ,
2015-11-29 17:30:52 +08:00
programName , programName , programName , programName , programName , programName , programName , programName
);
exit ( 0 );
}
2016-12-02 15:56:18 +08:00
#else // NO_HELP
__noreturn static void clientUsage ( const char * const programName )
{
errorout ( "Incorrect parameter specified. \n " );
exit ( VLMCSD_EINVAL );
}
#endif // NO_HELP
2016-08-15 18:35:59 +08:00
static void parseProtocolVersion ( void )
{
char * endptr_major , * endptr_minor , * period = strchr ( optarg , ( int ) '.' );
if ( ! period )
{
errorout ( "Fatal: Protocol version must be in the format #.# \n " );
2016-10-24 21:32:24 +08:00
exit ( VLMCSD_EINVAL );
2016-08-15 18:35:59 +08:00
}
long major = strtol ( optarg , & endptr_major , 10 );
long minor = strtol ( period + 1 , & endptr_minor , 10 );
if (( * endptr_major && * endptr_major != '.' ) || * endptr_minor || * optarg == '.' || ! period [ 1 ])
{
errorout ( "Fatal: Protocol version must be in the format #.# \n " );
2016-10-24 21:32:24 +08:00
exit ( VLMCSD_EINVAL );
2016-08-15 18:35:59 +08:00
}
if ( major < 0 || major > 0xffff || minor < 0 || minor > 0xffff )
{
errorout ( "Fatal: Major and minor protocol version number must be between 0 and 65535 \n " );
2016-10-24 21:32:24 +08:00
exit ( VLMCSD_EINVAL );
2016-08-15 18:35:59 +08:00
}
2016-12-02 15:56:18 +08:00
MajorVersion = ( uint16_t ) major ;
MinorVersion = ( uint16_t ) minor ;
2016-08-15 18:35:59 +08:00
}
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
static int32_t findLicensePackByName ( const char * const name )
2015-11-29 17:30:52 +08:00
{
2016-12-02 15:56:18 +08:00
int32_t i ;
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
for ( i = KmsData -> SkuItemCount - 1 ; i >= 0 ; i -- )
2015-11-29 17:30:52 +08:00
{
2016-12-02 15:56:18 +08:00
if ( ! strcasecmp ( name , KmsData -> SkuItemList [ i ]. Name )) return i ;
2015-11-29 17:30:52 +08:00
}
2016-12-02 15:56:18 +08:00
return i ;
}
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
static const char * const client_optstring = "+N:B:i:j:l:a:s:k:c:w:r:n:t:g:G:o:K:pPTv456mexdV" ;
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
//We handle only "-j". Many other options do not run without a loaded database
static void parseCommandLinePass0 ( const int argc , CARGV argv )
{
int o ;
optReset ();
2016-10-14 13:28:23 +08:00
2016-12-02 15:56:18 +08:00
for ( opterr = 0 ; ( o = getopt ( argc , ( char * const * ) argv , client_optstring )) > 0 ; ) switch ( o )
2016-10-14 13:28:23 +08:00
{
2016-12-02 15:56:18 +08:00
# ifndef NO_EXTERNAL_DATA
case 'j' : // Set "License Pack" and protocol version (e.g. Windows8, Office2013v5, ...)
fn_data = optarg ;
# ifndef NO_INTERNAL_DATA
ExplicitDataLoad = TRUE ;
# endif // NO_INTERNAL_DATA
break ;
# endif // NO_EXTERNAL_DATA
2016-10-14 13:28:23 +08:00
2016-12-02 15:56:18 +08:00
default :
break ;
2016-10-14 13:28:23 +08:00
}
2015-11-29 17:30:52 +08:00
}
//First pass. We handle only "-l". Since -a -k -s -4 -5 and -6 are exceptions to -l, we process -l first
static void parseCommandLinePass1 ( const int argc , CARGV argv )
{
int o ;
optReset ();
2016-10-14 13:28:23 +08:00
for ( opterr = 0 ; ( o = getopt ( argc , ( char * const * ) argv , client_optstring )) > 0 ; ) switch ( o )
2015-11-29 17:30:52 +08:00
{
2016-10-14 13:28:23 +08:00
case 'l' : // Set "License Pack" and protocol version (e.g. Windows8, Office2013v5, ...)
2016-12-02 15:56:18 +08:00
if ( stringToInt ( optarg , 1 , KmsData -> SkuItemCount , ( unsigned int * ) & ActiveProductIndex ))
{
ActiveProductIndex -- ;
break ;
}
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
ActiveProductIndex = findLicensePackByName ( optarg );
if ( ActiveProductIndex < 0 )
2016-10-14 13:28:23 +08:00
{
errorout ( "Invalid client application. \" %s \" is not valid for -l. \n\n " , optarg );
#ifndef NO_HELP
showProducts ( & errorout );
#endif // !NO_HELP
}
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
default :
break ;
2015-11-29 17:30:52 +08:00
}
2016-12-02 15:56:18 +08:00
int32_t kmsIndex = KmsData -> SkuItemList [ ActiveProductIndex ]. KmsIndex ;
int32_t appIndex = KmsData -> SkuItemList [ ActiveProductIndex ]. AppIndex ;
MajorVersion = ( uint16_t ) KmsData -> SkuItemList [ ActiveProductIndex ]. ProtocolVersion ;
NCountPolicy = ( uint32_t ) KmsData -> SkuItemList [ ActiveProductIndex ]. NCountPolicy ;
memcpy ( & SkuGuid , & KmsData -> SkuItemList [ ActiveProductIndex ]. Guid , sizeof ( GUID ));
memcpy ( & KmsGuid , & KmsData -> KmsItemList [ kmsIndex ]. Guid , sizeof ( GUID ));
memcpy ( & AppGuid , & KmsData -> AppItemList [ appIndex ]. Guid , sizeof ( GUID ));
2015-11-29 17:30:52 +08:00
}
// Second Pass. Handle all options except "-l"
static void parseCommandLinePass2 ( const char * const programName , const int argc , CARGV argv )
{
int o ;
optReset ();
2016-10-14 13:28:23 +08:00
for ( opterr = 0 ; ( o = getopt ( argc , ( char * const * ) argv , client_optstring )) > 0 ; ) switch ( o )
2015-11-29 17:30:52 +08:00
{
2016-10-14 13:28:23 +08:00
#ifndef NO_HELP
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
case 'j' :
break ;
2016-10-14 13:28:23 +08:00
case 'e' : // Show examples
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
examples ( programName );
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'x' : // Show Apps
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
showProducts ( & printf );
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
#endif // NO_HELP
2015-11-29 17:30:52 +08:00
# ifndef NO_DNS
2016-10-14 13:28:23 +08:00
case 'P' :
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
NoSrvRecordPriority = TRUE ;
break ;
2015-11-29 17:30:52 +08:00
# endif // NO_DNS
2016-10-14 13:28:23 +08:00
case 'G' :
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
incompatibleOptions |= VLMCS_OPTION_GRAB_INI ;
fn_ini_client = optarg ;
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
# ifndef USE_MSRPC
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'N' :
2016-10-24 21:32:24 +08:00
if ( ! getArgumentBool ( & UseClientRpcNDR64 , optarg )) clientUsage ( programName );
2016-10-14 13:28:23 +08:00
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'B' :
2016-10-24 21:32:24 +08:00
if ( ! getArgumentBool ( & UseClientRpcBTFN , optarg )) clientUsage ( programName );
2016-10-14 13:28:23 +08:00
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'i' :
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
switch ( getOptionArgumentInt (( char ) o , 4 , 6 ))
{
case 4 :
AddressFamily = AF_INET ;
break ;
case 6 :
AddressFamily = AF_INET6 ;
break ;
default :
errorout ( "IPv5 does not exist. \n " );
2016-10-24 21:32:24 +08:00
exit ( VLMCSD_EINVAL );
2016-10-14 13:28:23 +08:00
}
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'p' : // Multiplexed RPC
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
UseMultiplexedRpc = FALSE ;
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
# endif // USE_MSRPC
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'n' : // Fixed number of Requests (regardless, whether they are required)
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI ;
FixedRequests = getOptionArgumentInt (( char ) o , 1 , INT_MAX );
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'r' : // Fake minimum required client count
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI ;
2016-12-02 15:56:18 +08:00
NCountPolicy = getOptionArgumentInt (( char ) o , 0 , INT_MAX );
2016-10-14 13:28:23 +08:00
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'c' : // use a specific client GUID
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
// If using a constant Client ID, send only one request unless /N= explicitly specified
if ( ! FixedRequests ) FixedRequests = 1 ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
CMID = optarg ;
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'o' : // use a specific previous client GUID
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
CMID_prev = optarg ;
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'a' : // Set specific App Id
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI ;
2016-12-02 15:56:18 +08:00
string2UuidOrExit ( optarg , & AppGuid );
2016-10-14 13:28:23 +08:00
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'g' : // Set custom "grace" time in minutes (default 30 days)
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
BindingExpiration = getOptionArgumentInt (( char ) o , 0 , INT_MAX );
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 's' : // Set specfic SKU ID
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI ;
2016-12-02 15:56:18 +08:00
string2UuidOrExit ( optarg , & SkuGuid );
2016-10-14 13:28:23 +08:00
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'k' : // Set specific KMS ID
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI ;
2016-12-02 15:56:18 +08:00
string2UuidOrExit ( optarg , & KmsGuid );
2016-10-14 13:28:23 +08:00
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case '4' : // Force V4 protocol
case '5' : // Force V5 protocol
case '6' : // Force V5 protocol
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI ;
2016-12-02 15:56:18 +08:00
MajorVersion = o - 0x30 ;
MinorVersion = 0 ;
2016-10-14 13:28:23 +08:00
break ;
2016-08-15 18:35:59 +08:00
2016-10-14 13:28:23 +08:00
case 'K' : // Use specific protocol (may be invalid)
2016-08-15 18:35:59 +08:00
2016-10-14 13:28:23 +08:00
parseProtocolVersion ();
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'd' : // Don't use DNS names
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
dnsnames = FALSE ;
break ;
2015-11-29 17:30:52 +08:00
2016-06-06 10:36:00 +08:00
# ifndef NO_VERBOSE_LOG
2016-10-14 13:28:23 +08:00
case 'v' : // Be verbose
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
verbose = TRUE ;
break ;
2015-11-29 17:30:52 +08:00
2016-06-06 10:36:00 +08:00
# endif // NO_VERBOSE_LOG
2016-10-14 13:28:23 +08:00
case 'm' : // Pretend to be a virtual machine
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
VMInfo = TRUE ;
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 'w' : // WorkstationName (max. 63 chars)
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
WorkstationName = optarg ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
if ( strlen ( WorkstationName ) > 63 )
{
errorout ( " \007 WARNING! Truncating workstation name to 63 characters (%s). \n " , WorkstationName );
}
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
case 't' :
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
LicenseStatus = getOptionArgumentInt (( char ) o , 0 , 0x7fffffff );
if (( unsigned int ) LicenseStatus > 6 ) errorout ( "Warning: Correct license status is 0 <= license status <= 6. \n " );
break ;
2015-11-29 17:30:52 +08:00
# ifndef USE_MSRPC
2016-10-14 13:28:23 +08:00
case 'T' :
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
ReconnectForEachRequest = TRUE ;
break ;
2015-11-29 17:30:52 +08:00
# endif // USE_MSRPC
2016-10-14 13:28:23 +08:00
case 'l' :
incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI ;
break ;
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
# ifndef NO_VERSION_INFORMATION
2016-06-06 10:36:00 +08:00
2016-10-14 13:28:23 +08:00
case 'V' :
2016-06-06 10:36:00 +08:00
# if defined(__s390__) && !defined(__zarch__) && !defined(__s390x__)
2016-10-14 13:28:23 +08:00
printf ( "vlmcs %s %i-bit \n " , Version , sizeof ( void * ) == 4 ? 31 : ( int ) sizeof ( void * ) << 3 );
2016-06-06 10:36:00 +08:00
# else
2016-10-14 13:28:23 +08:00
printf ( "vlmcs %s %i-bit \n " , Version , ( int ) sizeof ( void * ) << 3 );
2016-06-06 10:36:00 +08:00
# endif // defined(__s390__) && !defined(__zarch__) && !defined(__s390x__)
2016-10-14 13:28:23 +08:00
printPlatform ();
printCommonFlags ();
printClientFlags ();
exit ( 0 );
2016-06-06 10:36:00 +08:00
# endif // NO_VERSION_INFORMATION
2016-10-14 13:28:23 +08:00
default :
clientUsage ( programName );
2015-11-29 17:30:52 +08:00
}
if (( incompatibleOptions & ( VLMCS_OPTION_NO_GRAB_INI | VLMCS_OPTION_GRAB_INI )) == ( VLMCS_OPTION_NO_GRAB_INI | VLMCS_OPTION_GRAB_INI ))
clientUsage ( programName );
}
2016-12-02 15:56:18 +08:00
///*
// * Compares 2 GUIDs where one is host-endian and the other is little-endian (network byte order)
// */
//int_fast8_t IsEqualGuidLEHE(const GUID* const guid1, const GUID* const guid2)
//{
// GUID tempGuid;
// LEGUID(&tempGuid, guid2);
// return IsEqualGUID(guid1, &tempGuid);
//}
2015-11-29 17:30:52 +08:00
#ifndef USE_MSRPC
static void checkRpcLevel ( const REQUEST * request , RESPONSE * response )
{
if ( ! RpcFlags . HasNDR32 )
errorout ( " \n WARNING: Server's RPC protocol does not support NDR32. \n " );
2016-10-24 21:32:24 +08:00
if ( UseClientRpcBTFN && UseClientRpcNDR64 && RpcFlags . HasNDR64 && ! RpcFlags . HasBTFN )
2015-11-29 17:30:52 +08:00
errorout ( " \n WARNING: Server's RPC protocol has NDR64 but no BTFN. \n " );
2016-12-02 15:56:18 +08:00
//# ifndef NO_BASIC_PRODUCT_LIST
// if (!IsEqualGuidLEHE(&request->KMSID, &ProductList[15].guid) && UseClientRpcBTFN && !RpcFlags.HasBTFN)
// errorout("\nWARNING: A server with pre-Vista RPC activated a product other than Office 2010.\n");
//# endif // NO_BASIC_PRODUCT_LIST
2015-11-29 17:30:52 +08:00
}
#endif // USE_MSRPC
static void displayResponse ( const RESPONSE_RESULT result , const REQUEST * request , RESPONSE * response , BYTE * hwid )
{
fflush ( stdout );
if ( ! result . RpcOK ) errorout ( " \n\007 ERROR: Non-Zero RPC result code. \n " );
if ( ! result . DecryptSuccess ) errorout ( " \n\007 ERROR: Decryption of V5/V6 response failed. \n " );
if ( ! result . IVsOK ) errorout ( " \n\007 ERROR: AES CBC initialization vectors (IVs) of request and response do not match. \n " );
if ( ! result . PidLengthOK ) errorout ( " \n\007 ERROR: The length of the PID is not valid. \n " );
if ( ! result . HashOK ) errorout ( " \n\007 ERROR: Computed hash does not match hash in response. \n " );
if ( ! result . ClientMachineIDOK ) errorout ( " \n\007 ERROR: Client machine GUIDs of request and response do not match. \n " );
if ( ! result . TimeStampOK ) errorout ( " \n\007 ERROR: Time stamps of request and response do not match. \n " );
if ( ! result . VersionOK ) errorout ( " \n\007 ERROR: Protocol versions of request and response do not match. \n " );
if ( ! result . HmacSha256OK ) errorout ( " \n\007 ERROR: Keyed-Hash Message Authentication Code (HMAC) is incorrect. \n " );
2016-08-15 18:35:59 +08:00
if ( ! result . IVnotSuspicious ) errorout ( " \n WARNING: The KMS server is an emulator because the response uses an IV following KMSv5 rules in KMSv6 protocol. \n " );
2015-11-29 17:30:52 +08:00
if ( result . effectiveResponseSize != result . correctResponseSize )
{
errorout ( " \n\007 WARNING: Size of RPC payload (KMS Message) should be %u but is %u." , result . correctResponseSize , result . effectiveResponseSize );
}
# ifndef USE_MSRPC
checkRpcLevel ( request , response );
# endif // USE_MSRPC
if ( ! result . DecryptSuccess ) return ; // Makes no sense to display anything
char ePID [ 3 * PID_BUFFER_SIZE ];
if ( ! ucs2_to_utf8 ( response -> KmsPID , ePID , PID_BUFFER_SIZE , 3 * PID_BUFFER_SIZE ))
{
memset ( ePID + 3 * PID_BUFFER_SIZE - 3 , 0 , 3 );
}
// Read KMSPID from Response
2016-06-06 10:36:00 +08:00
# ifndef NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
if ( ! verbose )
2016-06-06 10:36:00 +08:00
# endif // NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
{
printf ( " -> %s" , ePID );
if ( LE16 ( response -> MajorVer ) > 5 )
{
# ifndef _WIN32
printf ( " (%016llX)" , ( unsigned long long ) BE64 ( * ( uint64_t * ) hwid ));
# else // _WIN32
printf ( " (%016I64X)" , ( unsigned long long ) BE64 ( * ( uint64_t * ) hwid ));
# endif // _WIN32
2016-12-02 15:56:18 +08:00
}
2015-11-29 17:30:52 +08:00
printf ( " \n " );
2016-12-02 15:56:18 +08:00
}
2016-06-06 10:36:00 +08:00
# ifndef NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
else
{
printf (
2016-10-14 13:28:23 +08:00
" \n\n Response from KMS server \n ======================== \n\n "
"Size of KMS Response : %u (0x%x) \n " , result . effectiveResponseSize , result . effectiveResponseSize
2015-11-29 17:30:52 +08:00
);
logResponseVerbose ( ePID , hwid , response , & printf );
printf ( " \n " );
}
2016-06-06 10:36:00 +08:00
# endif // NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
}
static void connectRpc ( RpcCtx * s )
{
# ifdef NO_DNS
2016-10-24 21:32:24 +08:00
RpcDiag_t rpcDiag ;
2015-11-29 17:30:52 +08:00
* s = connectToAddress ( RemoteAddr , AddressFamily , FALSE );
if ( * s == INVALID_RPCCTX )
{
errorout ( "Fatal: Could not connect to %s \n " , RemoteAddr );
2016-10-24 21:32:24 +08:00
exit ( SOCKET_ECONNABORTED );
2015-11-29 17:30:52 +08:00
}
if ( verbose )
printf ( " \n Performing RPC bind ... \n " );
2016-10-24 21:32:24 +08:00
RpcStatus status ;
if (( status = rpcBindClient ( * s , verbose , & rpcDiag )))
2015-11-29 17:30:52 +08:00
{
errorout ( "Fatal: Could not bind RPC \n " );
2016-10-24 21:32:24 +08:00
exit ( status );
2015-11-29 17:30:52 +08:00
}
if ( verbose ) printf ( "... successful \n " );
# else // DNS
static kms_server_dns_ptr * serverlist = NULL ;
static int numServers = 0 ;
//static int_fast8_t ServerListAlreadyPrinted = FALSE;
int i ;
if ( ! strcmp ( RemoteAddr , "-" ) || * RemoteAddr == '.' ) // Get KMS server via DNS SRV record
{
if ( ! serverlist )
numServers = getKmsServerList ( & serverlist , RemoteAddr );
if ( numServers < 1 )
{
errorout ( "Fatal: No KMS servers found \n " );
2016-10-24 21:32:24 +08:00
exit ( SOCKET_ECONNABORTED );
2015-11-29 17:30:52 +08:00
}
if ( ! NoSrvRecordPriority ) sortSrvRecords ( serverlist , numServers );
2016-06-06 10:36:00 +08:00
# ifndef NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
if ( verbose /*&& !ServerListAlreadyPrinted*/ )
{
for ( i = 0 ; i < numServers ; i ++ )
{
printf (
2016-10-14 13:28:23 +08:00
"Found %-40s (priority: %hu, weight: %hu, randomized weight: %i) \n " ,
serverlist [ i ] -> serverName ,
serverlist [ i ] -> priority , serverlist [ i ] -> weight ,
NoSrvRecordPriority ? 0 : serverlist [ i ] -> random_weight
2015-11-29 17:30:52 +08:00
);
}
printf ( " \n " );
//ServerListAlreadyPrinted = TRUE;
}
2016-06-06 10:36:00 +08:00
# endif // NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
}
else // Just use the server supplied on the command line
{
if ( ! serverlist )
{
serverlist = ( kms_server_dns_ptr * ) vlmcsd_malloc ( sizeof ( kms_server_dns_ptr ));
* serverlist = ( kms_server_dns_ptr ) vlmcsd_malloc ( sizeof ( kms_server_dns_t ));
numServers = 1 ;
strncpy (( * serverlist ) -> serverName , RemoteAddr , sizeof (( * serverlist ) -> serverName ));
}
}
for ( i = 0 ; i < numServers ; i ++ )
{
* s = connectToAddress ( serverlist [ i ] -> serverName , AddressFamily , ( * RemoteAddr == '.' || * RemoteAddr == '-' ));
if ( * s == INVALID_RPCCTX ) continue ;
2016-10-24 21:32:24 +08:00
RpcDiag_t rpcDiag ;
2015-11-29 17:30:52 +08:00
2016-06-06 10:36:00 +08:00
# ifndef NO_VERBOSE_LOG
if ( verbose ) printf ( " \n Performing RPC bind ... \n " );
2015-11-29 17:30:52 +08:00
2016-10-24 21:32:24 +08:00
if ( rpcBindClient ( * s , verbose , & rpcDiag ))
2016-06-06 10:36:00 +08:00
# else
2016-10-24 21:32:24 +08:00
if ( rpcBindClient ( * s , FALSE , & rpcDiag ))
2016-06-06 10:36:00 +08:00
# endif
2015-11-29 17:30:52 +08:00
{
errorout ( "Warning: Could not bind RPC \n " );
continue ;
}
2016-06-06 10:36:00 +08:00
# ifndef NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
if ( verbose ) printf ( "... successful \n " );
2016-06-06 10:36:00 +08:00
# endif
2015-11-29 17:30:52 +08:00
return ;
}
errorout ( "Fatal: Could not connect to any KMS server \n " );
2016-10-24 21:32:24 +08:00
exit ( SOCKET_ECONNABORTED );
2015-11-29 17:30:52 +08:00
# endif // DNS
}
2016-08-15 18:35:59 +08:00
#endif // IS_LIBRARY
2015-11-29 17:30:52 +08:00
2016-08-15 18:35:59 +08:00
int SendActivationRequest ( const RpcCtx sock , RESPONSE * baseResponse , REQUEST * baseRequest , RESPONSE_RESULT * result , BYTE * const hwid )
2015-11-29 17:30:52 +08:00
{
size_t requestSize , responseSize ;
BYTE * request , * response ;
int status ;
result -> mask = 0 ;
2016-08-15 18:35:59 +08:00
if ( LE16 ( baseRequest -> MajorVer ) < 5 )
2015-11-29 17:30:52 +08:00
request = CreateRequestV4 ( & requestSize , baseRequest );
else
request = CreateRequestV6 ( & requestSize , baseRequest );
2016-12-11 12:25:30 +08:00
if ( ! (( status = rpcSendRequest ( sock , request , requestSize , & response , & responseSize ))))
2015-11-29 17:30:52 +08:00
{
if ( LE16 ((( RESPONSE * )( response )) -> MajorVer ) == 4 )
{
RESPONSE_V4 response_v4 ;
2016-10-08 13:35:48 +08:00
* result = DecryptResponseV4 ( & response_v4 , ( const int ) responseSize , response , request );
2015-11-29 17:30:52 +08:00
memcpy ( baseResponse , & response_v4 . ResponseBase , sizeof ( RESPONSE ));
}
else
{
RESPONSE_V6 response_v6 ;
2016-10-08 13:35:48 +08:00
* result = DecryptResponseV6 ( & response_v6 , ( int ) responseSize , response , request , hwid );
2015-11-29 17:30:52 +08:00
memcpy ( baseResponse , & response_v6 . ResponseBase , sizeof ( RESPONSE ));
}
result -> RpcOK = TRUE ;
}
if ( response ) free ( response );
free ( request );
return status ;
}
2016-08-15 18:35:59 +08:00
#ifndef IS_LIBRARY
2015-11-29 17:30:52 +08:00
static int sendRequest ( RpcCtx * const s , REQUEST * const request , RESPONSE * const response , hwid_t hwid , RESPONSE_RESULT * const result )
{
CreateRequestBase ( request );
2016-10-14 13:28:23 +08:00
if ( * s == INVALID_RPCCTX )
2015-11-29 17:30:52 +08:00
connectRpc ( s );
else
{
// Check for lame KMS emulators that close the socket after each request
int_fast8_t disconnected = isDisconnected ( * s );
if ( disconnected )
errorout ( " \n Warning: Server closed RPC connection (probably non-multitasked KMS emulator) \n " );
if ( ReconnectForEachRequest || disconnected )
{
closeRpc ( * s );
connectRpc ( s );
}
}
2016-12-02 15:56:18 +08:00
printf ( "Sending activation request (KMS V%u) " , MajorVersion );
2015-11-29 17:30:52 +08:00
fflush ( stdout );
return SendActivationRequest ( * s , response , request , result , hwid );
}
static void displayRequestError ( RpcCtx * const s , const int status , const int currentRequest , const int totalRequests )
{
errorout ( " \n Error 0x%08X while sending request %u of %u \n " , status , currentRequest , RequestsToGo + totalRequests );
2016-10-14 13:28:23 +08:00
switch ( status )
2015-11-29 17:30:52 +08:00
{
case 0xC004F042 : // not licensed
2016-12-02 15:56:18 +08:00
errorout ( "The KMS server has declined to activate the requested product \n " );
2015-11-29 17:30:52 +08:00
break ;
case 0x8007000D : // e.g. v6 protocol on a v5 server
2016-12-02 15:56:18 +08:00
errorout ( "The KMS host you are using is unable to handle your product. It only supports legacy versions \n " );
break ;
case 0xC004F06C :
errorout ( "The time stamp differs too much from the KMS server time \n " );
break ;
case 0xC004D104 :
errorout ( "The security processor reported that invalid data was used \n " );
2015-11-29 17:30:52 +08:00
break ;
case 1 :
errorout ( "An RPC protocol error has occured \n " );
closeRpc ( * s );
connectRpc ( s );
break ;
default :
2016-12-02 15:56:18 +08:00
# if _WIN32
errorout ( "%s \n " , win_strerror ( status ));
# endif // _WIN32
2015-11-29 17:30:52 +08:00
break ;
}
}
static void newIniBackupFile ( const char * const restrict fname )
{
FILE * restrict f = fopen ( fname , "wb" );
if ( ! f )
{
2016-10-24 21:32:24 +08:00
int error = errno ;
errorout ( "Fatal: Cannot create %s: %s \n " , fname , strerror ( error ));
exit ( error );
2015-11-29 17:30:52 +08:00
}
if ( fclose ( f ))
{
2016-10-24 21:32:24 +08:00
int error = errno ;
errorout ( "Fatal: Cannot write to %s: %s \n " , fname , strerror ( error ));
2016-10-08 13:35:48 +08:00
vlmcsd_unlink ( fname );
2016-10-24 21:32:24 +08:00
exit ( error );
2015-11-29 17:30:52 +08:00
}
}
2020-03-30 01:21:09 -04:00
static void updateIniFile ( char *** restrict lines )
2015-11-29 17:30:52 +08:00
{
2020-03-30 01:21:09 -04:00
int_fast8_t * lineWritten = ( int_fast8_t * ) malloc ( KmsData -> CsvlkCount * sizeof ( int_fast8_t ));
2016-10-08 13:35:48 +08:00
# if !_MSC_VER
2015-11-29 17:30:52 +08:00
struct stat statbuf ;
2016-10-08 13:35:48 +08:00
# endif
2015-11-29 17:30:52 +08:00
uint_fast8_t i ;
int_fast8_t iniFileExistedBefore = TRUE ;
unsigned int lineNumber ;
2020-03-30 01:21:09 -04:00
memset ( lineWritten , FALSE , KmsData -> CsvlkCount * sizeof ( int_fast8_t ));
2015-11-29 17:30:52 +08:00
char * restrict fn_bak = ( char * ) vlmcsd_malloc ( strlen ( fn_ini_client ) + 2 );
strcpy ( fn_bak , fn_ini_client );
strcat ( fn_bak , "~" );
2016-10-08 13:35:48 +08:00
# if _MSC_VER
if ( ! PathFileExists ( fn_ini_client ))
{
iniFileExistedBefore = FALSE ;
newIniBackupFile ( fn_bak );
}
# else
2015-11-29 17:30:52 +08:00
if ( stat ( fn_ini_client , & statbuf ))
{
if ( errno != ENOENT )
{
2016-10-24 21:32:24 +08:00
int error = errno ;
errorout ( "Fatal: %s: %s \n " , fn_ini_client , strerror ( error ));
exit ( error );
2015-11-29 17:30:52 +08:00
}
else
{
iniFileExistedBefore = FALSE ;
newIniBackupFile ( fn_bak );
}
}
2016-10-08 13:35:48 +08:00
# endif
2015-11-29 17:30:52 +08:00
else
{
2016-10-08 13:35:48 +08:00
vlmcsd_unlink ( fn_bak ); // Required for Windows. Most Unix systems don't need it.
2015-11-29 17:30:52 +08:00
if ( rename ( fn_ini_client , fn_bak ))
{
2020-03-30 01:21:09 -04:00
const int error = errno ;
2016-10-24 21:32:24 +08:00
errorout ( "Fatal: Cannot create %s: %s \n " , fn_bak , strerror ( error ));
exit ( error );
2015-11-29 17:30:52 +08:00
}
}
printf ( " \n %s file %s \n " , iniFileExistedBefore ? "Updating" : "Creating" , fn_ini_client );
FILE * restrict in , * restrict out ;
in = fopen ( fn_bak , "rb" );
if ( ! in )
{
2020-03-30 01:21:09 -04:00
const int error = errno ;
2016-10-24 21:32:24 +08:00
errorout ( "Fatal: Cannot open %s: %s \n " , fn_bak , strerror ( error ));
exit ( error );
2015-11-29 17:30:52 +08:00
}
out = fopen ( fn_ini_client , "wb" );
if ( ! out )
{
2020-03-30 01:21:09 -04:00
const int error = errno ;
2016-10-24 21:32:24 +08:00
errorout ( "Fatal: Cannot create %s: %s \n " , fn_ini_client , strerror ( error ));
exit ( error );
2015-11-29 17:30:52 +08:00
}
char sourceLine [ 256 ];
for ( lineNumber = 1 ; fgets ( sourceLine , sizeof ( sourceLine ), in ); lineNumber ++ )
{
2020-03-30 01:21:09 -04:00
for ( i = 0 ; i < KmsData -> CsvlkCount ; i ++ )
2015-11-29 17:30:52 +08:00
{
2020-03-30 01:21:09 -04:00
if ( * ( * lines )[ i ] && ! strncasecmp ( sourceLine , ( * lines )[ i ], strlen ( getNextString (( KmsData -> CsvlkData [ i ]. EPid )))))
2015-11-29 17:30:52 +08:00
{
if ( lineWritten [ i ]) break ;
fprintf ( out , "%s" , ( * lines )[ i ]);
printf ( "line %2i: %s" , lineNumber , ( * lines )[ i ]);
lineWritten [ i ] = TRUE ;
break ;
}
}
2020-03-30 01:21:09 -04:00
if ( i >= KmsData -> CsvlkCount )
2015-11-29 17:30:52 +08:00
{
fprintf ( out , "%s" , sourceLine );
}
}
if ( ferror ( in ))
{
2016-10-24 21:32:24 +08:00
int error = errno ;
errorout ( "Fatal: Cannot read from %s: %s \n " , fn_bak , strerror ( error ));
exit ( error );
2015-11-29 17:30:52 +08:00
}
fclose ( in );
2020-03-30 01:21:09 -04:00
for ( i = 0 ; i < KmsData -> CsvlkCount ; i ++ )
2015-11-29 17:30:52 +08:00
{
if ( ! lineWritten [ i ] && * ( * lines )[ i ])
{
fprintf ( out , "%s" , ( * lines )[ i ]);
printf ( "line %2i: %s" , lineNumber + i , ( * lines )[ i ]);
}
}
if ( fclose ( out ))
{
2020-03-30 01:21:09 -04:00
const int error = errno ;
2016-10-24 21:32:24 +08:00
errorout ( "Fatal: Cannot write to %s: %s \n " , fn_ini_client , strerror ( error ));
exit ( error );
2015-11-29 17:30:52 +08:00
}
2016-10-08 13:35:48 +08:00
if ( ! iniFileExistedBefore ) vlmcsd_unlink ( fn_bak );
2015-11-29 17:30:52 +08:00
free ( fn_bak );
}
2016-10-08 13:35:48 +08:00
2015-11-29 17:30:52 +08:00
static void grabServerData ()
{
RpcCtx s = INVALID_RPCCTX ;
2016-10-14 13:28:23 +08:00
WORD MajorVer = 6 ;
2020-03-30 01:21:09 -04:00
int32_t i ;
int32_t j ;
char ** lines = ( char ** ) vlmcsd_malloc ( KmsData -> CsvlkCount * sizeof ( char * ));
GUID * kmsGuids = ( GUID * ) vlmcsd_malloc ( KmsData -> CsvlkCount * sizeof ( GUID ));
2016-12-02 15:56:18 +08:00
2020-03-30 01:21:09 -04:00
for ( i = 0 ; i < KmsData -> CsvlkCount ; i ++ )
2016-12-02 15:56:18 +08:00
{
2020-03-30 01:21:09 -04:00
lines [ i ] = ( char * ) vlmcsd_malloc ( 256 );
* lines [ i ] = 0 ;
for ( j = 0 ; j < KmsData -> KmsItemCount ; j ++ )
{
if ( KmsData -> KmsItemList [ j ]. EPidIndex == i )
{
kmsGuids [ i ] = KmsData -> KmsItemList [ j ]. Guid ;
break ;
}
}
}
2016-12-02 15:56:18 +08:00
2015-11-29 17:30:52 +08:00
RESPONSE response ;
RESPONSE_RESULT result ;
REQUEST request ;
hwid_t hwid ;
int status ;
size_t len ;
2020-03-30 01:21:09 -04:00
for ( i = 0 ; i < KmsData -> CsvlkCount && MajorVer > 3 ; i ++ )
2016-10-14 13:28:23 +08:00
{
2020-03-30 01:21:09 -04:00
const int32_t kmsIndex = getProductIndex ( & kmsGuids [ i ], KmsData -> KmsItemList , KmsData -> KmsItemCount , NULL , NULL );
2016-12-02 15:56:18 +08:00
if ( kmsIndex < 0 )
{
2020-03-30 01:21:09 -04:00
errorout ( "Warning: KMS GUID not in database. \n " );
2016-12-02 15:56:18 +08:00
continue ;
}
ActiveProductIndex = ~ 0 ;
2020-03-30 01:21:09 -04:00
for ( j = KmsData -> SkuItemCount - 1 ; j >= 0 ; j -- )
2016-12-02 15:56:18 +08:00
{
if ( KmsData -> SkuItemList [ j ]. KmsIndex == kmsIndex )
{
ActiveProductIndex = j ;
break ;
}
}
if ( ActiveProductIndex == ~ 0 )
{
2020-03-30 01:21:09 -04:00
errorout ( "Warning: KMS GUID not in database. \n " );
2016-12-02 15:56:18 +08:00
continue ;
}
2020-03-30 01:21:09 -04:00
const int32_t appIndex = KmsData -> SkuItemList [ ActiveProductIndex ]. AppIndex ;
2016-12-02 15:56:18 +08:00
NCountPolicy = ( uint32_t ) KmsData -> SkuItemList [ ActiveProductIndex ]. NCountPolicy ;
memcpy ( & SkuGuid , & KmsData -> SkuItemList [ ActiveProductIndex ]. Guid , sizeof ( GUID ));
memcpy ( & KmsGuid , & KmsData -> KmsItemList [ kmsIndex ]. Guid , sizeof ( GUID ));
memcpy ( & AppGuid , & KmsData -> AppItemList [ appIndex ]. Guid , sizeof ( GUID ));
MajorVersion = ( uint16_t ) MajorVer ;
2016-10-14 13:28:23 +08:00
status = sendRequest ( & s , & request , & response , hwid , & result );
2020-03-30 01:21:09 -04:00
printf ( "%-11s" , getNextString ( KmsData -> CsvlkData [ i ]. EPid ));
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
if ( status )
{
displayRequestError ( & s , status , i + 7 - MajorVer , 9 - MajorVer );
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
if ( status == 1 ) break ;
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
if (( status & 0xF0000000 ) == 0x80000000 )
{
MajorVer -- ;
i -- ;
}
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
continue ;
}
2015-11-29 17:30:52 +08:00
2020-03-30 01:21:09 -04:00
printf ( "%i of %i" , ( int )( i + 7 - MajorVer ), ( int )( KmsData -> CsvlkCount + 6 - MajorVer ));
2016-10-14 13:28:23 +08:00
displayResponse ( result , & request , & response , hwid );
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
char ePID [ 3 * PID_BUFFER_SIZE ];
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
if ( ! ucs2_to_utf8 ( response . KmsPID , ePID , PID_BUFFER_SIZE , 3 * PID_BUFFER_SIZE ))
{
memset ( ePID + 3 * PID_BUFFER_SIZE - 3 , 0 , 3 );
}
2015-11-29 17:30:52 +08:00
2020-03-30 01:21:09 -04:00
vlmcsd_snprintf ( lines [ i ], 255 - strlen ( lines [ i ]), "%s = %s" , getNextString ( KmsData -> CsvlkData [ i ]. EPid ), ePID );
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
if ( response . MajorVer > 5 )
{
len = strlen ( lines [ i ]);
2020-03-30 01:21:09 -04:00
vlmcsd_snprintf ( lines [ i ] + len , 255 - len , " / %02X %02X %02X %02X %02X %02X %02X %02X" , hwid [ 0 ], hwid [ 1 ], hwid [ 2 ], hwid [ 3 ], hwid [ 4 ], hwid [ 5 ], hwid [ 6 ], hwid [ 7 ]);
2016-10-14 13:28:23 +08:00
}
2015-11-29 17:30:52 +08:00
len = strlen ( lines [ i ]);
2020-03-30 01:21:09 -04:00
vlmcsd_snprintf ( lines [ i ] + len , 255 - len , " \n " );
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
}
2015-11-29 17:30:52 +08:00
if ( strcmp ( fn_ini_client , "-" ))
{
updateIniFile ( & lines );
}
else
{
printf ( " \n " );
2020-03-30 01:21:09 -04:00
for ( i = 0 ; i < KmsData -> CsvlkCount ; i ++ ) printf ( "%s" , lines [ i ]);
2015-11-29 17:30:52 +08:00
}
}
2016-10-08 13:35:48 +08:00
int client_main ( int argc , CARGV argv )
2015-11-29 17:30:52 +08:00
{
2016-10-14 13:28:23 +08:00
#if defined(_WIN32) && !defined(USE_MSRPC)
2015-11-29 17:30:52 +08:00
// Windows Sockets must be initialized
2020-03-30 01:21:09 -04:00
WSADATA wsaData ;
2015-11-29 17:30:52 +08:00
int error ;
2020-03-30 01:21:09 -04:00
if (( error = WSAStartup ( 0x0202 , & wsaData )))
2015-11-29 17:30:52 +08:00
{
2016-12-02 15:56:18 +08:00
errorout ( "Fatal: Could not initialize Windows sockets (Error: %d). \n " , error );
2015-11-29 17:30:52 +08:00
return error ;
}
2016-10-14 13:28:23 +08:00
#endif // _WIN32
2015-11-29 17:30:52 +08:00
2016-10-14 13:28:23 +08:00
#ifdef _NTSERVICE
2015-11-29 17:30:52 +08:00
// We are not a service
IsNTService = FALSE ;
2016-10-14 13:28:23 +08:00
#endif // _NTSERVICE
2015-11-29 17:30:52 +08:00
randomNumberInit ();
2016-12-02 15:56:18 +08:00
//# ifndef NO_EXTERNAL_DATA
// ExplicitDataLoad = TRUE;
//# endif // NO_EXTERNAL_DATA
parseCommandLinePass0 ( argc , argv );
2015-11-29 17:30:52 +08:00
int_fast8_t useDefaultHost = FALSE ;
if ( optind < argc )
RemoteAddr = argv [ optind ];
else
useDefaultHost = TRUE ;
2020-03-30 01:21:09 -04:00
const int hostportarg = optind ;
2015-11-29 17:30:52 +08:00
if ( optind < argc - 1 )
{
2016-12-02 15:56:18 +08:00
parseCommandLinePass0 ( argc - hostportarg , argv + hostportarg );
2015-11-29 17:30:52 +08:00
if ( optind < argc - hostportarg )
clientUsage ( argv [ 0 ]);
}
2016-12-02 15:56:18 +08:00
loadKmsData ();
if ( ! KmsData -> AppItemCount || ! KmsData -> SkuItemCount || ! KmsData -> KmsItemCount )
{
errorout ( "Fatal: Incomplete KMS data file \n " );
exit ( VLMCSD_EINVAL );
}
parseCommandLinePass1 ( argc , argv );
if ( optind < argc - 1 )
{
parseCommandLinePass1 ( argc - hostportarg , argv + hostportarg );
}
2015-11-29 17:30:52 +08:00
parseCommandLinePass2 ( argv [ 0 ], argc , argv );
if ( optind < argc - 1 )
parseCommandLinePass2 ( argv [ 0 ], argc - hostportarg , argv + hostportarg );
if ( useDefaultHost )
2016-10-14 13:28:23 +08:00
{
# ifndef USE_MSRPC
2015-11-29 17:30:52 +08:00
RemoteAddr = AddressFamily == AF_INET6 ? "::1" : "127.0.0.1" ;
2016-10-14 13:28:23 +08:00
# else
RemoteAddr = "127.0.0.1" ;
# endif
}
2015-11-29 17:30:52 +08:00
if ( fn_ini_client != NULL )
grabServerData ();
else
{
int requests ;
RpcCtx s = INVALID_RPCCTX ;
2016-12-02 15:56:18 +08:00
for ( requests = 0 , RequestsToGo = NCountPolicy == 1 ? 1 : NCountPolicy - 1 ; RequestsToGo ; requests ++ )
2015-11-29 17:30:52 +08:00
{
RESPONSE response ;
REQUEST request ;
RESPONSE_RESULT result ;
hwid_t hwid ;
int status = sendRequest ( & s , & request , & response , hwid , & result );
if ( FixedRequests ) RequestsToGo = FixedRequests - requests - 1 ;
if ( status )
{
displayRequestError ( & s , status , requests + 1 , RequestsToGo + requests + 1 );
if ( ! FixedRequests ) RequestsToGo = 0 ;
}
else
{
if ( ! FixedRequests )
{
2016-12-02 15:56:18 +08:00
if ( firstRequestSent && NCountPolicy - ( int ) response . Count >= RequestsToGo )
2015-11-29 17:30:52 +08:00
{
errorout ( " \n The KMS server does not increment it's active clients. Aborting... \n " );
RequestsToGo = 0 ;
}
else
{
2016-12-02 15:56:18 +08:00
RequestsToGo = NCountPolicy - response . Count ;
2015-11-29 17:30:52 +08:00
if ( RequestsToGo < 0 ) RequestsToGo = 0 ;
}
}
fflush ( stderr );
printf ( "%i of %i " , requests + 1 , RequestsToGo + requests + 1 );
displayResponse ( result , & request , & response , hwid );
firstRequestSent = TRUE ;
}
}
}
return 0 ;
}
// Create Base KMS Client Request
static void CreateRequestBase ( REQUEST * Request )
{
2016-12-02 15:56:18 +08:00
Request -> MinorVer = LE16 ( MinorVersion );
Request -> MajorVer = LE16 ( MajorVersion );
2015-11-29 17:30:52 +08:00
Request -> VMInfo = LE32 ( VMInfo );
Request -> LicenseStatus = LE32 ( LicenseStatus );
Request -> BindingExpiration = LE32 ( BindingExpiration );
2016-12-02 15:56:18 +08:00
Request -> N_Policy = LE32 ( NCountPolicy );
memcpy ( & Request -> ActID , & SkuGuid , sizeof ( GUID ));
memcpy ( & Request -> KMSID , & KmsGuid , sizeof ( GUID ));
memcpy ( & Request -> AppID , & AppGuid , sizeof ( GUID ));
2015-11-29 17:30:52 +08:00
getUnixTimeAsFileTime ( & Request -> ClientTime );
{
if ( CMID )
{
2016-12-02 15:56:18 +08:00
string2UuidOrExit ( CMID , & Request -> CMID );
2015-11-29 17:30:52 +08:00
}
else
{
get16RandomBytes ( & Request -> CMID );
// Set reserved UUID bits
Request -> CMID . Data4 [ 0 ] &= 0x3F ;
Request -> CMID . Data4 [ 0 ] |= 0x80 ;
// Set UUID type 4 (random UUID)
Request -> CMID . Data3 &= LE16 ( 0xfff );
Request -> CMID . Data3 |= LE16 ( 0x4000 );
}
if ( CMID_prev )
{
2016-12-02 15:56:18 +08:00
string2UuidOrExit ( CMID_prev , & Request -> CMID_prev );
2015-11-29 17:30:52 +08:00
}
else
{
memset ( & Request -> CMID_prev , 0 , sizeof ( Request -> CMID_prev ));
}
}
static const char alphanum [] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /*"abcdefghijklmnopqrstuvwxyz" */ ;
if ( WorkstationName )
{
utf8_to_ucs2 ( Request -> WorkstationName , WorkstationName , WORKSTATION_NAME_BUFFER , WORKSTATION_NAME_BUFFER * 3 );
}
else if ( dnsnames )
{
int len , len2 ;
2016-12-02 15:56:18 +08:00
unsigned int index = rand () % vlmcsd_countof ( ClientDnsNames . first );
2016-10-08 13:35:48 +08:00
len = ( int ) utf8_to_ucs2 ( Request -> WorkstationName , ClientDnsNames . first [ index ], WORKSTATION_NAME_BUFFER , WORKSTATION_NAME_BUFFER * 3 );
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
index = rand () % vlmcsd_countof ( ClientDnsNames . second );
2016-10-08 13:35:48 +08:00
len2 = ( int ) utf8_to_ucs2 ( Request -> WorkstationName + len , ClientDnsNames . second [ index ], WORKSTATION_NAME_BUFFER , WORKSTATION_NAME_BUFFER * 3 );
2015-11-29 17:30:52 +08:00
2016-12-02 15:56:18 +08:00
index = rand () % vlmcsd_countof ( ClientDnsNames . tld );
2015-11-29 17:30:52 +08:00
utf8_to_ucs2 ( Request -> WorkstationName + len + len2 , ClientDnsNames . tld [ index ], WORKSTATION_NAME_BUFFER , WORKSTATION_NAME_BUFFER * 3 );
}
else
{
unsigned int size = ( rand () % 14 ) + 1 ;
const unsigned char * dummy ;
unsigned int i ;
for ( i = 0 ; i < size ; i ++ )
{
Request -> WorkstationName [ i ] = utf8_to_ucs2_char (( unsigned char * ) alphanum + ( rand () % ( sizeof ( alphanum ) - 1 )), & dummy );
}
Request -> WorkstationName [ size ] = 0 ;
}
2016-06-06 10:36:00 +08:00
# ifndef NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
if ( verbose )
{
printf ( " \n Request Parameters \n ================== \n\n " );
logRequestVerbose ( Request , & printf );
printf ( " \n " );
}
2016-06-06 10:36:00 +08:00
# endif // NO_VERBOSE_LOG
2015-11-29 17:30:52 +08:00
}
2016-11-16 12:12:36 +08:00
#if _MSC_VER && !defined(_DEBUG)&& !MULTI_CALL_BINARY
int __stdcall WinStartUp ( void )
{
WCHAR ** szArgList ;
int argc ;
szArgList = CommandLineToArgvW ( GetCommandLineW (), & argc );
int i ;
char ** argv = ( char ** ) vlmcsd_malloc ( sizeof ( char * ) * argc );
for ( i = 0 ; i < argc ; i ++ )
{
int size = WideCharToMultiByte ( CP_UTF8 , 0 , szArgList [ i ], - 1 , argv [ i ], 0 , NULL , NULL );
argv [ i ] = ( char * ) vlmcsd_malloc ( size );
WideCharToMultiByte ( CP_UTF8 , 0 , szArgList [ i ], - 1 , argv [ i ], size , NULL , NULL );
}
exit ( client_main ( argc , argv ));
}
#endif // _MSC_VER && !defined(_DEBUG)&& !MULTI_CALL_BINARY
2016-08-15 18:35:59 +08:00
#endif // IS_LIBRARY