mirror of
https://github.com/rescatux/chntpw
synced 2026-06-21 14:07:44 +00:00
256 lines
7.3 KiB
C
256 lines
7.3 KiB
C
/*
|
|
* sampasswd.c - SAM database, add or remove user in a group
|
|
*
|
|
* Command line utility, non-interactive to reset user password and/or
|
|
* account bits for a user in the SAM database
|
|
*
|
|
* Changes:
|
|
* 2013 - aug: cleaned up a bit for release, some debug still there
|
|
* 2013 - apr-may: reset one, all and first features
|
|
* 2012 - oct: First version, some code from earlier chntpw.c. Not released.
|
|
*
|
|
*****
|
|
*
|
|
* Copyright (c) 1997-2014 Petter Nordahl-Hagen.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* See file GPL.txt for the full license.
|
|
*
|
|
*****
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "ntreg.h"
|
|
#include "sam.h"
|
|
|
|
|
|
const char sampasswd_version[] = "sampasswd version 0.2 140201, (c) Petter N Hagen";
|
|
|
|
|
|
/* Global verbosity flag */
|
|
int gverbose = 0;
|
|
|
|
/* Array of loaded hives */
|
|
#define MAX_HIVES 10
|
|
struct hive *hive[MAX_HIVES+1];
|
|
int no_hives = 0;
|
|
|
|
int H_SAM = -1;
|
|
|
|
|
|
|
|
int do_reset(char *user, int inrid, int verb)
|
|
{
|
|
int rid = 0;
|
|
int ret;
|
|
char *resolvedname = NULL;
|
|
char s[200];
|
|
|
|
if ((H_SAM < 0) || (!user && !inrid) ) return(1);
|
|
|
|
if (inrid) {
|
|
rid = inrid;
|
|
} else {
|
|
if (*user == '0' && *(user+1) == 'x') sscanf(user,"%i",&rid);
|
|
}
|
|
|
|
if (!rid) { /* Look up username */
|
|
/* Extract the unnamed value out of the username-key, value is RID */
|
|
snprintf(s,180,"\\SAM\\Domains\\Account\\Users\\Names\\%s\\@",user);
|
|
rid = get_dword(hive[H_SAM],0,s, TPF_VK_EXACT|TPF_VK_SHORT);
|
|
if (rid == -1) {
|
|
printf("ERROR: User <%s> not found\n",user);
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
/* At this point we have a RID, so get the real username it maps to just to show it */
|
|
resolvedname = sam_get_username(hive[H_SAM], rid);
|
|
|
|
if (!resolvedname) return(1); /* RID lookup failed, no such user */
|
|
|
|
if (gverbose) printf("do_reset: Username: %s, RID = %d (0x%0x)\n",resolvedname,rid,rid);
|
|
|
|
ret = sam_reset_pw(hive[H_SAM], rid);
|
|
|
|
if (!ret && verb) printf("Password reset for user %s, RID = %d [0x%0x]\n",resolvedname,rid,rid);
|
|
|
|
FREE(resolvedname);
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
void usage(void)
|
|
{
|
|
printf(" [-r|-l] [-H] -u <user> <samhive>\n"
|
|
"Reset password or list users in SAM database\n"
|
|
"Mode:\n"
|
|
" -r = reset users password\n"
|
|
" -l = list users in sam\n"
|
|
"Parameters:\n"
|
|
" <user> can be given as a username or a RID in hex with 0x in front\n"
|
|
" Example:\n"
|
|
" -r -u theboss -> resets password of user named 'theboss' if found\n"
|
|
" -r -u 0x3ea -> resets password for user with RID 0x3ea (hex)\n"
|
|
" -r -a -> Reset password of all users in administrators group (0x220)\n"
|
|
" -r -f -> Reset password of admin user with lowest RID\n"
|
|
" not counting built-in admin (0x1f4) unless it is the only admin\n"
|
|
" Usernames with international characters usually fails to be found,\n"
|
|
" please use RID number instead\n"
|
|
" If success, there will be no output, and exit code is 0\n"
|
|
"Options:\n"
|
|
" -H : For list: Human readable listing (default is parsable table)\n"
|
|
" -H : For reset: Will output confirmation message if success\n"
|
|
" -N : No allocate mode, only allow edit of existing values with same size\n"
|
|
" -E : No expand mode, do not expand hive file (safe mode)\n"
|
|
" -t : Debug trace of allocated blocks\n"
|
|
" -v : Some more verbose messages/debug\n"
|
|
);
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
|
|
extern int optind;
|
|
extern char* optarg;
|
|
|
|
int what = 0;
|
|
int reset = 0;
|
|
int list = 0;
|
|
int mode = 0;
|
|
int human = 0;
|
|
int adm = 0;
|
|
int all = 0;
|
|
int first = 0;
|
|
int ret, wret, il;
|
|
char *hivename;
|
|
char c;
|
|
char *usr = NULL;
|
|
|
|
char *options = "rlHu:vNEthaf";
|
|
|
|
while((c=getopt(argc,argv,options)) > 0) {
|
|
switch(c) {
|
|
case 'r': reset = 1; break;
|
|
case 'l': list = 2; break;
|
|
case 'u': usr = optarg; break;
|
|
case 'a': all = 1; break;
|
|
case 'f': first = 1; break;
|
|
case 'H': human = 1; break;
|
|
case 'v': mode |= HMODE_VERBOSE; gverbose = 1; break;
|
|
case 'N': mode |= HMODE_NOALLOC; break;
|
|
case 'E': mode |= HMODE_NOEXPAND; break;
|
|
case 't': mode |= HMODE_TRACE; break;
|
|
case 'h': printf("%s\n%s ",sampasswd_version,argv[0]); usage(); exit(0); break;
|
|
default: printf("%s\n%s ",sampasswd_version,argv[0]); usage(); exit(1); break;
|
|
}
|
|
}
|
|
|
|
if (!reset && !list && !what) {
|
|
fprintf(stderr,"%s: ERROR: Mode -r or -l must be specified. -h for help\n",argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
#if 0 /* Should both be allowed at same time?? */
|
|
if (list && reset) {
|
|
fprintf(stderr,"%s: ERROR: Mode -r and -l impossible at the same time. -h for help\n",argv[0]);
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
if (reset && !all && !first && (!usr || !*usr)) {
|
|
fprintf(stderr,"%s: ERROR: Need a user for reset, -u must be specified.\n",argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
/* Load hives. Only first SAM hive will be used however */
|
|
|
|
hivename = argv[optind+no_hives];
|
|
if (!hivename || !*hivename) {
|
|
fprintf(stderr,"%s: ERROR: You must specify a SAM registry hive filename.\n",argv[0]);
|
|
exit(1);
|
|
}
|
|
do {
|
|
if (!(hive[no_hives] = openHive(hivename,
|
|
HMODE_RW|mode))) {
|
|
fprintf(stderr,"%s: ERROR: Unable to open/read registry hive, cannot continue\n",argv[0]);
|
|
exit(1);
|
|
}
|
|
switch(hive[no_hives]->type) {
|
|
case HTYPE_SAM: H_SAM = no_hives; break;
|
|
// case HTYPE_SOFTWARE: H_SOF = no_hives; break;
|
|
// case HTYPE_SYSTEM: H_SYS = no_hives; break;
|
|
// case HTYPE_SECURITY: H_SEC = no_hives; break;
|
|
}
|
|
no_hives++;
|
|
hivename = argv[optind+no_hives];
|
|
} while (hivename && *hivename && no_hives < MAX_HIVES);
|
|
|
|
if (H_SAM == -1) {
|
|
fprintf(stderr,"%s: WARNING: Hive file does not look like SAM, but continuing anyway in case detection was wrong\n"
|
|
"%s: WARNING: If it really is not a SAM file you will get strange errors or bad results\n",argv[0],argv[0]);
|
|
H_SAM = 0;
|
|
}
|
|
|
|
|
|
/* Do logic */
|
|
|
|
if (list) {
|
|
adm = sam_list_users(hive[H_SAM], human);
|
|
if (gverbose) printf(" sam_list_users found admin to be 0x%x\n",adm);
|
|
}
|
|
|
|
if (reset) {
|
|
if (all) {
|
|
ret = sam_reset_all_pw(hive[H_SAM], human);
|
|
if (ret) {
|
|
fprintf(stderr,"%s: ERROR: Failed reset password of ALL users\n",argv[0]);
|
|
}
|
|
} else if (first) {
|
|
adm = sam_list_users(hive[H_SAM], 2);
|
|
if (!adm) {
|
|
fprintf(stderr,"%s: ERROR: Unable to reset, no admin users found\n",argv[0]);
|
|
} else {
|
|
// printf("Resetting password of user with RID %x\n",adm);
|
|
ret = do_reset(usr, adm, human);
|
|
}
|
|
} else {
|
|
ret = do_reset(usr, 0, human);
|
|
if (ret) {
|
|
fprintf(stderr,"%s: ERROR: Failed reset password for %s\n",argv[0],usr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* write registry hive (if needed) */
|
|
|
|
wret = 0;
|
|
for (il = 0; il < no_hives; il++) {
|
|
// wret |= writeHive(hive[il]);
|
|
if (hive[il]->state & HMODE_DIDEXPAND)
|
|
fprintf(stderr," WARNING: Registry file %s was expanded! Experimental! Use at own risk!\n",hive[il]->filename);
|
|
while (no_hives > 0)
|
|
closeHive(hive[--no_hives]);
|
|
}
|
|
|
|
return(ret | wret);
|
|
}
|
|
|