<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">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 &lt;adrian15sgd@gmail.com&gt;

--- 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) $&lt;
 
 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 &lt;stdio.h&gt;
+#include &lt;unistd.h&gt;
+#include &lt;stdlib.h&gt;
+#include &lt;string.h&gt;
+
+#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 &lt; 0) || (!user &amp;&amp; !inrid) ) return(1);
+
+  if (inrid) {
+    rid = inrid;
+  } else {
+    if (*user == '0' &amp;&amp; *(user+1) == 'x') sscanf(user,"%i",&amp;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 &lt;%s&gt; 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 &amp; 0x8000; /* ret != 0 means locked ; ret == 0 means unlocked */
+
+  if (!ret &amp;&amp; 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 &lt;user&gt; &lt;samhive&gt;\n"
+	 "Unlock user or list users in SAM database\n"
+         "Mode:\n"
+	 "   -U = Unlock user\n"
+         "   -l = list users in sam\n"
+         "Parameters:\n"
+         "   &lt;user&gt; can be given as a username or a RID in hex with 0x in front\n"
+         "   Example:\n"
+         "   -U -u theboss -&gt; Unlocks user named 'theboss' if found\n"
+         "   -U -u 0x3ea -&gt; Unlocks user with RID 0x3ea (hex)\n"
+	 "   -U -f -&gt; 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)) &gt; 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 &amp;&amp; !list &amp;&amp; !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 &amp;&amp; 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 &amp;&amp; !first &amp;&amp; (!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]-&gt;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 &amp;&amp; *hivename &amp;&amp; no_hives &lt; 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 &lt; no_hives; il++) {
+    wret |= writeHive(hive[il]);
+    if (hive[il]-&gt;state &amp; HMODE_DIDEXPAND)
+      fprintf(stderr," WARNING: Registry file %s was expanded! Experimental! Use at own risk!\n",hive[il]-&gt;filename);
+    while (no_hives &gt; 0)
+      closeHive(hive[--no_hives]);
+  }
+
+  return(ret | wret);
+}
+
</pre></body></html>