Description: Add samunlock binary The samunlock binary lets you unlock or list users. This command is suited for scripts and can be run also interactively Obtained from: https://github.com/rescatux/chntpw/ Forwarded: no Origin: other Author: Adrian Gibanel Lopez --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ LIBS=$(shell libgcrypt-config --libs) -all: chntpw cpnt reged samusrgrp sampasswd +all: chntpw cpnt reged samusrgrp sampasswd samunlock chntpw: chntpw.o ntreg.o edlib.o libsam.o $(CC) $(CFLAGS) -o chntpw chntpw.o ntreg.o edlib.o libsam.o $(LIBS) @@ -41,6 +41,11 @@ sampasswd.static: sampasswd.o ntreg.o libsam.o $(CC) -static $(CFLAGS) -o sampasswd.static sampasswd.o ntreg.o libsam.o +samunlock: samunlock.o ntreg.o libsam.o + $(CC) $(CFLAGS) -o samunlock samunlock.o ntreg.o libsam.o + +samunlock.static: samunlock.o ntreg.o libsam.o + $(CC) -static $(CFLAGS) -o samunlock.static samunlock.o ntreg.o libsam.o #ts: ts.o ntreg.o @@ -52,5 +57,5 @@ $(CC) -c $(CFLAGS) $< clean: - rm -f *.o chntpw cpnt reged samusrgrp sampasswd *~ + rm -f *.o chntpw cpnt reged samusrgrp sampasswd samunlock *~ --- /dev/null +++ b/samunlock.c @@ -0,0 +1,248 @@ +/* + * samunlock.c - SAM database, Unlock user + * + * Command line utility, non-interactive to unlock a user + * in the SAM database + * + * Changes: + * 2014 - oct: First version, some code from earlier sampasswd.c. + * + ***** + * + * Copyright (c) 2014 Adrian Gibanel + * + * 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 +#include +#include +#include + +#include "ntreg.h" +#include "sam.h" + + +const char samunlock_version[] = "samunlock version 0.1 141018, (c) Adrian Gibanel"; + + +/* 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_unlock(char *user, int inrid, int verb) +{ + int rid = 0; + int ret; + char *resolvedname = NULL; + char s[200]; + unsigned short acb; + + 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_unlock: Username: %s, RID = %d (0x%0x)\n",resolvedname,rid,rid); + + acb = sam_handle_accountbits(hive[H_SAM], rid,2); + + ret = acb & 0x8000; /* ret != 0 means locked ; ret == 0 means unlocked */ + + if (!ret && verb) printf("Unlock user %s, RID = %d [0x%0x]\n",resolvedname,rid,rid); + + FREE(resolvedname); + return(ret); + +} + + + +void usage(void) +{ + printf(" [-U|-l] [-H] -u \n" + "Unlock user or list users in SAM database\n" + "Mode:\n" + " -U = Unlock user\n" + " -l = list users in sam\n" + "Parameters:\n" + " can be given as a username or a RID in hex with 0x in front\n" + " Example:\n" + " -U -u theboss -> Unlocks user named 'theboss' if found\n" + " -U -u 0x3ea -> Unlocks user with RID 0x3ea (hex)\n" + " -U -f -> Unlocks 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 unlock: 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 unlock = 0; + int list = 0; + int mode = 0; + int human = 0; + int adm = 0; + int first = 0; + int ret, wret, il; + char *hivename; + char c; + char *usr = NULL; + + char *options = "UlHu:vNEthaf"; + + while((c=getopt(argc,argv,options)) > 0) { + switch(c) { + case 'U': unlock = 1; break; + case 'l': list = 2; break; + case 'u': usr = optarg; 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 ",samunlock_version,argv[0]); usage(); exit(0); break; + default: printf("%s\n%s ",samunlock_version,argv[0]); usage(); exit(1); break; + } + } + + if (!unlock && !list && !what) { + fprintf(stderr,"%s: ERROR: Mode -U or -l must be specified. -h for help\n",argv[0]); + exit(1); + } + +#if 0 /* Should both be allowed at same time?? */ + if (list && unlock) { + fprintf(stderr,"%s: ERROR: Mode -U and -l impossible at the same time. -h for help\n",argv[0]); + exit(1); + } +#endif + + if (unlock && !first && (!usr || !*usr)) { + fprintf(stderr,"%s: ERROR: Need a user for unlock, -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 (unlock) { + if (first) { + adm = sam_list_users(hive[H_SAM], 2); + if (!adm) { + fprintf(stderr,"%s: ERROR: Unable to unlock, no admin users found\n",argv[0]); + } else { + // printf("Resetting password of user with RID %x\n",adm); + ret = do_unlock(usr, adm, human); + } + } else { + ret = do_unlock(usr, 0, human); + if (ret) { + fprintf(stderr,"%s: ERROR: Failed to unlock %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); +} +