/* * 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 #include #include #include #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 \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" " 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); }