WinNT Passwords [Parte 2]
Death Knights Issue 2
by Cacaio
No tdk01, eu falei onde podem ser vistas em pleno texto as senhas do WinNT, e agora falarei sobre um pequeno utilitario que transforma a password database que estra no registro do NT (em HKEY_LOCAL_MACHINE\SECURITY\SAM\Domains\Account\Users) para um valido formato sbpasswd. Isso daqui pode ajudar alguns admnistradores de Samba que tem uma master password database em uma maquina WinNT e quer a colocar em sincronia com o arquuivo smbpassword no sei servidor UNIX/Samba. Fazendo isto as senhas nao aparecem mais como texto.
Este utilitario descarrega as entradas de password do NT no seguinte formato:
<user>:<id>:<lanman pw>:<NT pw>:comment:homedir:
Onde:
<user> e' o user name no WinNT
<id> e' o Relative ID (RID) do WinNT
<lanman pw> e' o lanman passwrod haso do usuario.
<NT pw> e' o WinNT (md4) password hash -\
Se o usuario nao tiver senha, aparecera
'NO PASSWORD*****'. Se a conta for invalida
ou desativada, terao 32 '*''s.
-NOTA-
O homedir nao pode conter o caractere ':', pos eles sao utilizados como separa- dores de campo no arquvo smbpasswd (sendo para UNIX), todos os caracteres ':' depois da letra do triva se tornarao '_'.
Como usar o pwdump
So uma sugestao: eu recomendo fazer isto nas suas maquinas NT e entao criar users UNIX (no /etc/passwd) com os mesmos dados da conta no UNIX e no NT RID.
Estas contas no /etc/passwd devem ter desativado a entrada de senhas, proibindo que usuarios NT loguem no UNIX via telnet. Isto nao vai proibir que usem o Samba como um servidor. O smbpasswod criado deve ser copado para $SAMBA/private/smbpasswd (onde $SAMBA e o diretorio base em que voce instalou o Samba. Para deixar que o samba sempre encripte as senhas de users, coloque o seguinte setting:
security = user encrypted passwords = yes
Isto no seu arquivo smb.conf. Fazendo isto o seu sistema estara apto para usufruir dos beneficios deste utilitario.
O utilitario pwdump.exe pode colocar um \\machine name como argumento, isso e' para que quando utilizado, faca o que deve na maquina remota ao inves da local, se tiver privilegios o suficiente, claro. Ele ira pegar o estilo do password database da maquina local.
Source
Para compilar o source, voce precisa da biblioteca DES. Ela pode ser obtida em:
ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/libdes-4.01.tar.gz
Para compilar voce pode usar qualquer compilador.
-------xX !!! CuT HeRe !!! !!! CuT HeRe !!! !!! CuT HeRe !!! Xx-------
/* file pwdump.c */
/*
* T H E
*
* $$P¯"˝$b ,gP¯"˝$b ,gP¯""˝$b ,gP¯$$$$$$$$˝$b ,g¯ ˝$b
* $$ $$ $$ $$ $$ $$ $$$$$$ $$ $$
* $$ $$ $$ "˝ $$ $$ $$$$ $$ $$
* $$ $$ $$P˝" ,p $$, ,$$ `$$' $$, ,$$
* $$ $$ gg $$ $$$$$$$$$ $$ $$$$$$$$$
* $$ $$ $$ $$ $$' `$$ $$ $$' `$$
* $$ $$ $$ $$ $$ $$ $$ $$ $$
* $$ $$ $$ $$ $$ $$ .$$. $$ $$
* T$, gP' T$, gP' $$ $$ $$$$ $$ $$
* $$P˝˝¯" $$P˝˝¯" "˝ ˝" $$$$ "˝ ˝"
* ˝
* K N i G H T S
*
* Visit our webpage at http://www.deathknights.com
*
*/
/*
* (C) Jeremy Allison 1997. All rights reserved.
*
* This program is free for commercial and non-commercial use.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* THIS SOFTWARE IS PROVIDED BY JEREMY ALLISON ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "des.h"
char *error_to_string(DWORD error)
{
char *msgbuf;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
(char *)&msgbuf,
0,
NULL
) == 0)
return 0;
return msgbuf;
}
/*
* Return a pointer to a string describing an os error.
* error_to_string returns a pointer to LocalAlloc'ed
* memory. Cache it and release when the next one is
* requested.
1000
*/
char *str_oserr(DWORD err)
{
static char *lastmsg = 0;
if(lastmsg)
LocalFree((HLOCAL)lastmsg);
lastmsg = error_to_string(err);
return lastmsg;
}
BOOL get_sid(const char *name, SID **ppsid)
{
SID_NAME_USE sid_use;
DWORD sid_size = 0;
DWORD dom_size = 0;
char *domain;
*ppsid = 0;
if(LookupAccountName(0, name, 0, &sid_size, 0, &dom_size, &sid_use) == 0) {
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
fprintf( stderr, "get_sid: LookupAccountName for size on name %s failed. Error was %s\n",
name, str_oserr(GetLastError()));
return FALSE;
}
}
*ppsid = (SID *)LocalAlloc( LMEM_FIXED, sid_size);
domain = (char *)LocalAlloc( LMEM_FIXED, dom_size);
if( *ppsid == 0 || domain == 0) {
fprintf( stderr, "get_sid: LocalAlloc failed. Error was %s\n",
str_oserr(GetLastError()));
if(*ppsid)
LocalFree((HLOCAL)*ppsid);
if(domain)
LocalFree((HLOCAL)domain);
*ppsid = 0;
return FALSE;
}
if(LookupAccountName(0, name, *ppsid, &sid_size, domain, &dom_size, &sid_use) == 0) {
fprintf( stderr,
"get_sid: LookupAccountName failed for name %s. Error was %s\n",
name, str_oserr(GetLastError()));
LocalFree((HLOCAL)*ppsid);
LocalFree((HLOCAL)domain);
*ppsid = 0;
return FALSE;
}
LocalFree((HLOCAL)domain);
return TRUE;
}
BOOL create_sd_from_list( SECURITY_DESCRIPTOR *sdout, int num, ...)
{
va_list ap;
SID **sids = 0;
char *name;
DWORD amask;
DWORD acl_size;
PACL pacl = 0;
int i;
if((sids = (SID **)calloc(1,sizeof(SID *)*num)) == 0) {
fprintf(stderr, "create_sd_from_list: calloc fail.\n");
return FALSE;
}
acl_size = num * (sizeof(ACL) +
sizeof(ACCESS_ALLOWED_ACE) +
sizeof(DWORD));
/* Pega todos os SID's */
va_start( ap, num);
for( i = 0; i < num; i++) {
name = va_arg( ap, char *);
amask = va_arg(ap, DWORD);
if(get_sid( name, &sids[i]) == FALSE)
goto cleanup;
acl_size += GetLengthSid(sids[i]);
}
va_end(ap);
if((pacl = (PACL)LocalAlloc( LMEM_FIXED, acl_size)) == 0) {
fprintf( stderr, "create_sd_from_list: LocalAlloc fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
if(InitializeSecurityDescriptor( sdout, SECURITY_DESCRIPTOR_REVISION) == FALSE) {
fprintf( stderr, "create_sd_from_list: InitializeSecurityDescriptor fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
if(InitializeAcl( pacl, acl_size, ACL_REVISION) == FALSE) {
fprintf( stderr, "create_sd_from_list: InitializeAcl fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
va_start(ap, num);
for( i = 0; i < num; i++) {
ACE_HEADER *ace_p;
name = va_arg( ap, char *);
amask = va_arg( ap, DWORD);
if(AddAccessAllowedAce( pacl, ACL_REVISION, amask, sids[i]) == FALSE) {
fprintf( stderr, "create_sd_from_list: AddAccessAllowedAce fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
/* Make sure the ACE is inheritable */
if(GetAce( pacl, 0, (LPVOID *)&ace_p) == FALSE) {
fprintf( stderr, "create_sd_from_list: GetAce fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
ace_p->AceFlags |= ( CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
}
/* Add the ACL into the sd. */
if(SetSecurityDescriptorDacl( sdout, TRUE, pa
1000
cl, FALSE) == FALSE) {
fprintf( stderr, "create_sd_from_list: SetSecurityDescriptorDacl fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
for( i = 0; i < num; i++)
if(sids[i] != 0)
LocalFree((HLOCAL)sids[i]);
free(sids);
return TRUE;
cleanup:
if(sids != 0) {
for( i = 0; i < num; i++)
if(sids[i] != 0)
LocalFree((HLOCAL)sids[i]);
free(sids);
}
if(pacl != 0)
LocalFree((HLOCAL)pacl);
return FALSE;
}
int set_userkeys_security( HKEY start, const char *path, SECURITY_DESCRIPTOR *psd,
HKEY *return_key)
{
HKEY key;
DWORD err;
char usersid[128];
DWORD indx = 0;
if((err = RegOpenKeyEx( start, path, 0, KEY_ENUMERATE_SUB_KEYS, &key)) !=
ERROR_SUCCESS) {
fprintf(stderr, "set_userkeys_security: Failed to open key %s to enumerate. \
Error was %s.\n",
path, str_oserr(err));
return -1;
}
do {
DWORD size;
FILETIME ft;
size = sizeof(usersid);
err = RegEnumKeyEx( key, indx, usersid, &size, 0, 0, 0, &ft);
if(err == ERROR_SUCCESS) {
HKEY subkey;
indx++;
if((err = RegOpenKeyEx( key, usersid, 0, WRITE_DAC, &subkey)) !=
ERROR_SUCCESS) {
fprintf(stderr, "set_userkeys_security: Failed to open key %s to set security. \
Error was %s.\n",
usersid, str_oserr(err));
RegCloseKey(key);
return -1;
}
if((err = RegSetKeySecurity( subkey, DACL_SECURITY_INFORMATION,
psd)) != ERROR_SUCCESS) {
fprintf(stderr, "set_userkeys_security: Failed to set security on key %s. \
Error was %s.\n",
usersid, str_oserr(err));
RegCloseKey(subkey);
RegCloseKey(key);
return -1;
}
RegCloseKey(subkey);
}
} while(err == ERROR_SUCCESS);
if(err != ERROR_NO_MORE_ITEMS) {
RegCloseKey(key);
return -1;
}
if(return_key == 0)
RegCloseKey(key);
else
*return_key = key;
return 0;
}
int restore_sam_tree_access( HKEY start )
{
char path[128];
char *p;
HKEY key;
DWORD err;
SECURITY_DESCRIPTOR sd;
DWORD admin_mask;
admin_mask = WRITE_DAC | READ_CONTROL;
if(create_sd_from_list( &sd, 2, "SYSTEM", GENERIC_ALL,
"Administrators", admin_mask) == FALSE)
return -1;
strcpy( path, "SECURITY\\SAM\\Domains\\Account\\Users");
/* Remove the security on the user keys first. */
if(set_userkeys_security( start, path, &sd, 0) != 0)
return -1;
/* now go up the path, restoring security */
do {
if((err = RegOpenKeyEx( start, path, 0, WRITE_DAC, &key)) !=
ERROR_SUCCESS) {
fprintf(stderr, "restore_sam_tree_access:Failed to open key %s to set \
security. Error was %s.\n",
path, str_oserr(err));
return -1;
}
if((err = RegSetKeySecurity( key, DACL_SECURITY_INFORMATION,
&sd)) != ERROR_SUCCESS) {
fprintf(stderr, "restore_sam_tree_access: Failed to set security on key %s. \
Error was %s.\n",
path, str_oserr(err));
RegCloseKey(key);
return -1;
}
RegCloseKey(key);
p = strrchr(path, '\\');
if( p != 0)
*p = 0;
} while( p != 0 );
return 0;
}
int set_sam_tree_access( HKEY start, HKEY *return_key)
{
char path[128];
char *p;
HKEY key;
DWORD err;
BOOL security_changed = FALSE;
SECURITY_DESCRIPTOR sd;
DWORD admin_mask;
BOOL finished = FALSE;
admin_mask = WRITE_DAC | READ_CONTROL | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS;
if(create_sd_fr
1000
om_list( &sd, 2, "SYSTEM", GENERIC_ALL,
"Administrators", admin_mask) == FALSE)
return -1;
strcpy( path, "SECURITY\\SAM\\Domains\\Account\\Users");
p = strchr(path, '\\');
do {
if( p != 0)
*p = 0;
else
finished = TRUE;
if((err = RegOpenKeyEx( start, path, 0, WRITE_DAC, &key)) !=
ERROR_SUCCESS) {
fprintf(stderr, "set_sam_tree_access:Failed to open key %s to set \
security. Error was %s.\n",
path, str_oserr(err));
return (security_changed ? -2: -1);
}
if((err = RegSetKeySecurity( key, DACL_SECURITY_INFORMATION,
&sd)) != ERROR_SUCCESS) {
fprintf(stderr, "set_sam_tree_access: Failed to set security on key %s. \
Error was %s.\n",
path, str_oserr(err));
RegCloseKey(key);
return (security_changed ? -2: -1);
}
security_changed = TRUE;
RegCloseKey(key);
if(p != 0) {
*p++ = '\\';
p = strchr(p, '\\');
}
} while( !finished );
if(set_userkeys_security( start, path, &sd, &key) != 0)
return -2;
if(return_key == 0)
RegCloseKey(key);
else
*return_key = key;
return 0;
}
int get_int( char *array )
{
return ((array[0]&0xff) + ((array[1]<<8)&0xff00) +
((array[2]<<16)&0xff0000) +
((array[3]<<24)&0xff000000));
}
void str_to_key(unsigned char *str,unsigned char *key)
{
void des_set_odd_parity(des_cblock *);
int i;
key[0] = str[0]>>1;
key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
key[7] = str[6]&0x7F;
for (i=0;i<8;i++) {
key[i] = (key[i]<<1);
}
des_set_odd_parity((des_cblock *)key);
}
void sid_to_key1(unsigned long sid,unsigned char deskey[8])
{
unsigned char s[7];
s[0] = (unsigned char)(sid & 0xFF);
s[1] = (unsigned char)((sid>>8) & 0xFF);
s[2] = (unsigned char)((sid>>16) & 0xFF);
s[3] = (unsigned char)((sid>>24) & 0xFF);
s[4] = s[0];
s[5] = s[1];
s[6] = s[2];
str_to_key(s,deskey);
}
void sid_to_key2(unsigned long sid,unsigned char deskey[8])
{
unsigned char s[7];
s[0] = (unsigned char)((sid>>24) & 0xFF);
s[1] = (unsigned char)(sid & 0xFF);
s[2] = (unsigned char)((sid>>8) & 0xFF);
s[3] = (unsigned char)((sid>>16) & 0xFF);
s[4] = s[0];
s[5] = s[1];
s[6] = s[2];
str_to_key(s,deskey);
}
int check_vp(char *vp, int vp_size, char **username, char **fullname,
char **comment, char **homedir,
char *lanman,int *got_lanman,
char *md4, int *got_md4,
DWORD rid
)
{
des_key_schedule ks1, ks2;
des_cblock deskey1, deskey2;
int username_offset = get_int(vp + 0xC);
int username_len = get_int(vp + 0x10);
int fullname_offset = get_int(vp + 0x18);
int fullname_len = get_int(vp + 0x1c);
int comment_offset = get_int(vp + 0x24);
int comment_len = get_int(vp + 0x28);
int homedir_offset = get_int(vp + 0x48);
int homedir_len = get_int(vp + 0x4c);
int pw_offset = get_int(vp + 0x9c);
*username = 0;
*fullname = 0;
*comment = 0;
*homedir = 0;
*got_lanman = 0;
*got_md4 = 0;
if(username_len < 0 || username_offset < 0 || comment_len < 0 ||
fullname_len < 0 || homedir_offset < 0 ||
comment_offset < 0 || pw_offset < 0)
return -1;
username_offset += 0xCC;
fullname_offset += 0xCC;
comment_offset += 0xCC;
homedir_offset += 0xCC;
pw_offset += 0xCC;
if((*username = (char *)malloc(username_len + 1)) == 0) {
fprintf(stderr, "check_vp: malloc fail for username.\n");
return -1;
}
if((*fullname = (char *)malloc(fullname_len + 1)) == 0)
1000
{
fprintf(stderr, "check_vp: malloc fail for username.\n");
free(*username);
*username = 0;
return -1;
}
if((*comment = (char *)malloc(comment_len + 1)) == 0) {
fprintf(stderr, "check_vp: malloc fail for comment.\n");
free(*username);
*username = 0;
free(*fullname);
*fullname = 0;
return -1;
}
if((*homedir = (char *)malloc(homedir_len + 1)) == 0) {
fprintf(stderr, "check_vp: malloc fail for homedir.\n");
free(*username);
*username = 0;
free(*fullname);
*fullname = 0;
free(*comment);
*comment = 0;
return -1;
}
wcstombs( *username, (wchar_t *)(vp + username_offset), username_len/sizeof(wchar_t));
(*username)[username_len/sizeof(wchar_t)] = 0;
wcstombs( *fullname, (wchar_t *)(vp + fullname_offset), fullname_len/sizeof(wchar_t));
(*fullname)[fullname_len/sizeof(wchar_t)] = 0;
wcstombs( *comment, (wchar_t *)(vp + comment_offset), comment_len/sizeof(wchar_t));
(*comment)[comment_len/sizeof(wchar_t)] = 0;
wcstombs( *homedir, (wchar_t *)(vp + homedir_offset), homedir_len/sizeof(wchar_t));
(*homedir)[homedir_len/sizeof(wchar_t)] = 0;
if(pw_offset >= vp_size) {
/* No password */
*got_lanman = 0;
*got_md4 = 0;
return 0;
}
if(pw_offset + 32 > vp_size) {
/* Account disabled ? */
*got_lanman = -1;
*got_md4 = -1;
return 0;
}
sid_to_key1(rid,(unsigned char *)deskey1);
des_set_key((des_cblock *)deskey1,ks1);
sid_to_key2(rid,(unsigned char *)deskey2);
des_set_key((des_cblock *)deskey2,ks2);
vp += pw_offset;
des_ecb_encrypt((des_cblock *)vp,
(des_cblock *)lanman, ks1, DES_DECRYPT);
des_ecb_encrypt((des_cblock *)(vp + 8),
(des_cblock *)&lanman[8], ks2, DES_DECRYPT);
vp += 16;
des_ecb_encrypt((des_cblock *)vp,
(des_cblock *)md4, ks1, DES_DECRYPT);
des_ecb_encrypt((des_cblock *)(vp + 8),
(des_cblock *)&md4[8], ks2, DES_DECRYPT);
*got_lanman = 1;
*got_md4 = 1;
return 0;
}
void print_hexval(char *val)
{
int i;
for(i = 0; i < 16; i++)
printf("%02X", (unsigned char)val[i]);
}
void strip_text( char *txt )
{
char *p;
for( p = strchr(txt, ':'); p ; p = strchr( p + 1, ':'))
*p = '_';
for( p = strchr(txt, '\n'); p ; p = strchr(p + 1, '\n'))
*p = '_';
for( p = strchr(txt, '\r'); p ; p = strchr(p + 1, '\r'))
*p = '_';
}
int printout_smb_entry( HKEY user, DWORD rid )
{
DWORD err;
DWORD type;
DWORD size = 0;
char *vp;
char lanman[16];
char md4_hash[16];
char *username;
char *fullname;
char *comment;
char *homedir;
int got_lanman;
int got_md4;
/* Find out how much space we need for the 'V' value. */
if((err = RegQueryValueEx( user, "V", 0, &type, 0, &size))
!= ERROR_SUCCESS) {
fprintf(stderr, "printout_smb_entry: Unable to determine size needed \
for user 'V' value. Error was %s.\n.", str_oserr(err));
return -1;
}
if((vp = (char *)malloc(size)) == 0) {
fprintf(stderr, "printout_smb_entry: malloc fail for user entry.\n");
return -1;
}
if((err = RegQueryValueEx( user, "V", 0, &type, (LPBYTE)vp, &size))
!= ERROR_SUCCESS) {
fprintf(stderr, "printout_smb_entry: Unable to read user 'V' value. \
Error was %s.\n.", str_oserr(err));
free(vp);
return -1;
}
/* Check heuristics */
if(check_vp(vp, size, &username, &fullname, &comment,
&homedir, lanman, &got_lanman,
md4_hash, &got_md4, rid) != 0) {
fprintf(stderr, "Failed to parse entry for RID %X\n", rid);
free(vp);
return 0;
}
/* Ensure username of comment
1000
don't have any nasty suprises
for us such as an embedded ':' or '\n' - see multiple UNIX
passwd field update security bugs for details... */
strip_text( username );
strip_text( fullname );
strip_text( comment );
strip_text( homedir );
printf("%s:%d:", username, rid);
if(got_lanman) {
if(got_lanman == -1) /* Conta desativada? */
printf("********************************");
else
print_hexval(lanman);
} else
printf("NO PASSWORD*********************");
printf(":");
if(got_md4) {
if(got_md4 == -1) /* Conta desativada? */
printf("********************************");
else
print_hexval(md4_hash);
} else
printf("NO PASSWORD*********************");
printf(":");
if(*fullname)
printf("%s", fullname);
if(*fullname && *comment)
printf(",");
if(*comment)
printf("%s", comment);
printf(":");
if(*homedir)
printf("%s", homedir);
printf(":\n");
free(username);
free(comment);
free(homedir);
free(vp);
return 0;
}
int enumerate_users( HKEY key)
{
DWORD indx = 0;
DWORD err;
DWORD rid;
char usersid[128];
do {
DWORD size;
FILETIME ft;
size = sizeof(usersid);
err = RegEnumKeyEx( key, indx, usersid, &size, 0, 0, 0, &ft);
if(err == ERROR_SUCCESS) {
HKEY subkey;
indx++;
if((err = RegOpenKeyEx( key, usersid, 0, KEY_QUERY_VALUE, &subkey)) !=
ERROR_SUCCESS) {
fprintf(stderr, "enumerate_users: Failed to open key %s to read value. \
Error was %s.\n",
usersid, str_oserr(err));
RegCloseKey(key);
return -1;
}
rid = strtoul(usersid, 0, 16);
if(rid != 0) {
if(printout_smb_entry( subkey, rid ) != 0) {
RegCloseKey(subkey);
return -1;
}
}
RegCloseKey(subkey);
}
} while(err == ERROR_SUCCESS);
if(err != ERROR_NO_MORE_ITEMS) {
RegCloseKey(key);
return -1;
}
return 0;
}
void usage(const char *arg0) {
fprintf(stderr, "Usage: %s <\\\\machine>\n", arg0);
exit(-1);
}
/*
* uso: \\machine
*/
int main(int argc, char **argv)
{
char username[128];
DWORD size;
HKEY start_key = HKEY_LOCAL_MACHINE;
HKEY users_key;
int err;
if(argc > 2)
usage(argv[0]);
size = sizeof(username);
if(GetUserName(username, &size)== FALSE) {
fprintf(stderr, "%s: GetUserName() failed. Error was %s.",
argv[0], str_oserr(GetLastError()));
return -1;
}
if(stricmp( "Administrator", username) != 0) {
fprintf(stderr, "%s: You must be running as user Administrator \
to run this program\n", argv[0]);
return -1;
}
if(argc == 2) {
if((err = RegConnectRegistry( argv[1], HKEY_LOCAL_MACHINE, &start_key)) !=
ERROR_SUCCESS) {
fprintf(stderr, "%s: Failed to connect to registry on remote computer %s.\
Error was %s.\n", argv[0], argv[1], str_oserr(err));
return -1;
}
}
if((err = set_sam_tree_access( start_key, &users_key)) != 0) {
if(err == -2)
restore_sam_tree_access( start_key);
return -1;
}
enumerate_users( users_key );
RegCloseKey(users_key);
restore_sam_tree_access( start_key );
if(start_key != HKEY_LOCAL_MACHINE)
RegCloseKey(start_key);
return 0;
}