Files
2014-10-18 22:25:05 +02:00

293 lines
8.3 KiB
C

/*
* 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 <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#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 <user> -g <groupid> <samhive>\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"
" <user> can be given as a username or a RID in hex with 0x in front\n"
" <group> 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);
}