/* * samusrgrp.c - SAM database, add or remove user in a group * * Command line utility, non-inreractive to add or remove a user to/from * a local group in the SAM database, list groups with memberships etc * * When run as: * samusrtogrp - add user to group * samusrfromgrp - remove user from a group * or as any other name, option of what to do must be specified * * Changes: * 2013 - aug: cleaned up for release, still some debug & strangeness left * 2013 - apr-may: add, remove, list working (more or less) * 2012 - oct: First version, never 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 samusrgrp_version[] = "samusrgrp 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; /* Print machine SID. Put into here since no better place for now */ void cmd_machinesid(void) { struct sid_binary sid; char *sidstr; if (sam_get_machine_sid(hive[H_SAM], (char *)&sid)) { sidstr = sam_sid_to_string(&sid); puts(sidstr); FREE(sidstr); } } /* Get and parse parameters for group changes */ int cmd_usrgrp(char *user, char *grp, int what, int human) { int numgrp; int rid = 0; char *resolveduser = NULL; char *resolvedgroup = NULL; char s[200]; numgrp = strtol(grp, NULL, 0); if ((H_SAM < 0) || (!user)) return(1); 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("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 */ resolveduser = sam_get_username(hive[H_SAM], rid); if (!resolveduser) return(1); /* Fails if RID does not exists */ resolvedgroup = sam_get_groupname(hive[H_SAM], numgrp); if (!resolvedgroup) return(1); /* Fails if GID does not exists */ if (human) printf("%s user <%s> with RID = %d (0x%0x) %s group <%s> with GID = %d (0x%x)\n", (what == 1 ? "Add" : "Remove"), resolveduser, rid, rid, (what == 1 ? "to" : "from"), resolvedgroup, numgrp, numgrp ); FREE(resolveduser); FREE(resolvedgroup); switch (what) { case 1: return(!sam_add_user_to_grp(hive[H_SAM] ,rid, numgrp)); break; case 2: return(!sam_remove_user_from_grp(hive[H_SAM] ,rid, numgrp)); break; } return(0); } void usage(void) { printf(" [-a|-r] -u -g \n" "Add or remove a (local) user to/from a group\n" "Mode:" " -a = add user to group\n" " -r = remove user from group\n" " -l = list groups\n" " -L = list groups and also their members\n" " -s = Print machine SID\n" "Parameters:\n" " can be given as a username or a RID in hex with 0x in front\n" " is the group number, in hex with 0x in front\n" " Example:\n" " -a -u theboss -g 0x220 -> add user named 'theboss' group hex 220 (administrators)\n" " -a -u 0x3ea -g 0x221 -> add user with RID (hex) 3ea group hex 221 (users)\n" " -r -u 0x3ff -g 0x220 -> remove user RID 0x3ff from grp 0x220\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" " Also, success if user already in (or not in if -r) the group\n" "Options:\n" " -H : Human readable output, else parsable\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" "Multi call binary, if program is named:\n" " samusrtogrp -- Assume -a mode: Add a user into a group\n" " samusrfromgrp -- Assume -r mode: Remove user from a group\n" ); } int main(int argc, char **argv) { extern int optind; extern char* optarg; int what = 0; int add = 0; int rem = 0; int mode = 0; int m = 0; int list = 0; int human = 0; int ret, wret, il; char *hivename; char c; char *usr = NULL; char *grp = NULL; char *options = "aru:g:vNEthlLHs"; if (!strcmp(argv[0],"samusrtogrp")) what = 1; if (!strcmp(argv[0],"samusrfromgrp")) what = 2; if (!strcmp(argv[0],"samgrplist")) what = 3; while((c=getopt(argc,argv,options)) > 0) { switch(c) { case 'a': add = 1; m++; break; /* Add user */ case 'r': rem = 2; m++; break; /* Remove user */ case 'l': list = 1; m++; break; /* List groups */ case 'L': list = 2; m++; break; /* List groups + members */ case 's': list = 3; m++; break; /* Print machine sid */ case 'u': usr = optarg; break; case 'g': grp = optarg; 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 ",samusrgrp_version,argv[0]); usage(); exit(0); break; default: printf("%s\n%s ",samusrgrp_version,argv[0]); usage(); exit(1); break; } } if (m == 0) { fprintf(stderr,"%s: ERROR: One of mode -a -r -l -L must be specified\n",argv[0]); printf("%s\n%s ",samusrgrp_version,argv[0]); usage(); exit(1); } if (m > 1) { fprintf(stderr,"%s: ERROR: Please select only one of modes -a -r -l -L\n",argv[0]); exit(1); } if (!list && (!usr || !grp || !*usr || !*grp) ) { fprintf(stderr,"%s: ERROR: Both -u and -g must be specified.\n",argv[0]); exit(1); } /* Implicit mode parameter overrides mode based on binary name */ if (add) what = 1; if (rem) what = 2; if (list) what = 3; // printf("add = %d, rem = %d, list = %d, what = %d\n",add,rem,list,what); /* 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: Registry hive does not look like SAM!\n" "%s: WARNING: Continuing anyway, may lead to strange messages/failures!\n",argv[0],argv[0]); H_SAM = 0; } /* Do logic */ if (list == 3) { cmd_machinesid(); ret = 0; } else { if (list) { sam_list_groups(hive[H_SAM], list - 1, human); ret = 0; } else { ret = cmd_usrgrp(usr, grp, what, human); if (!ret && human) printf("Success!\n"); } } /* 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); }