/*
Samba Unix/Linux SMB client utility profiles.c
Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com
+ Copyright (C) 2003 Jelmer Vernooij (conversion to popt)
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 "regf"-Block
================
-"regf" is obviosly the abbreviation for "Registry file". "regf" is the
+"regf" is obviously the abbreviation for "Registry file". "regf" is the
signature of the header-block which is always 4kb in size, although only
the first 64 bytes seem to be used and a checksum is calculated over
the first 0x200 bytes only!
0x0002 ExpandSZ: string with "%var%" expanding (UNICODE!)
0x0003 RegBin: raw-binary value
0x0004 RegDWord: Dword
-0x0007 RegMultiSZ: multiple strings, seperated with 0
+0x0007 RegMultiSZ: multiple strings, separated with 0
(UNICODE!)
The "lf"-record
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <sys/mman.h>
typedef unsigned int DWORD;
typedef unsigned short WORD;
#define OFF(f) (0x1000 + (f) + 4)
+static void print_sid(DOM_SID *sid);
+
+int verbose = 1;
+DOM_SID old_sid, new_sid;
+int change = 0, new = 0;
+
/* Compare two SIDs for equality */
-int compare_sid(DOM_SID *s1, DOM_SID *s2)
+static int my_sid_equal(DOM_SID *s1, DOM_SID *s2)
{
int sa1, sa2;
if (sa1 != sa2) return 0;
- return !bcmp((char *)&s1->id_auth, (char *)&s2->id_auth,
+ return !memcmp((char *)&s1->id_auth, (char *)&s2->id_auth,
6 + sa1 * 4);
}
+/*
+ * Quick and dirty to read a SID in S-1-5-21-x-y-z-rid format and
+ * construct a DOM_SID
+ */
+static int get_sid(DOM_SID *sid, const unsigned char *sid_str)
+{
+ int i = 0, auth;
+ const unsigned char *lstr;
+
+ if (strncmp(sid_str, "S-1-5", 5)) {
+ fprintf(stderr, "Does not conform to S-1-5...: %s\n", sid_str);
+ return 0;
+ }
+
+ /* We only allow strings of form S-1-5... */
+
+ sid->sid_rev_num = 1;
+ sid->id_auth[5] = 5;
+
+ lstr = sid_str + 5;
+
+ while (1) {
+ if (!lstr || !lstr[0] || sscanf(lstr, "-%u", &auth) == 0) {
+ if (i < 4) {
+ fprintf(stderr, "Not of form -d-d...: %s, %u\n", lstr, i);
+ return 0;
+ }
+ sid->num_auths=i;
+ print_sid(sid);
+ return 1;
+ }
+
+ SIVAL(&sid->sub_auths[i], 0, auth);
+ i++;
+ lstr = (const unsigned char *)strchr(lstr + 1, '-');
+ }
+
+ return 1;
+}
+
+#if 0
+
/*
* Replace SID1, component by component with SID2
* Assumes will never be called with unequal length SIDS
* so only touches 21-x-y-z-rid portion
+ * This routine does not need to deal with endianism as
+ * long as the incoming SIDs are both in the same (LE) format.
*/
-void change_sid(DOM_SID *s1, DOM_SID *s2)
+static void change_sid(DOM_SID *s1, DOM_SID *s2)
{
int i;
}
}
-void print_sid(DOM_SID *sid)
+#endif
+
+static void print_sid(DOM_SID *sid)
{
int i, comps = sid->num_auths;
fprintf(stdout, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
for (i = 0; i < comps; i++) {
- fprintf(stdout, "-%u", sid->sub_auths[i]);
+ fprintf(stdout, "-%u", IVAL(&sid->sub_auths[i],0));
}
fprintf(stdout, "\n");
}
-void print_acl(ACL *acl, char *prefix)
+static void process_sid(DOM_SID *sid, DOM_SID *o_sid, DOM_SID *n_sid)
+{
+ int i;
+ if (my_sid_equal(sid, o_sid)) {
+
+ for (i=0; i<sid->num_auths; i++) {
+ sid->sub_auths[i] = n_sid->sub_auths[i];
+
+ }
+
+ }
+
+}
+
+static void process_acl(ACL *acl, const char *prefix)
{
int ace_cnt, i;
ACE *ace;
- ace_cnt = acl->num_aces;
+ ace_cnt = IVAL(&acl->num_aces, 0);
ace = (ACE *)&acl->aces;
- fprintf(stdout, "%sACEs: %u\n", prefix, ace_cnt);
+ if (verbose) fprintf(stdout, "%sACEs: %u\n", prefix, ace_cnt);
for (i=0; i<ace_cnt; i++) {
- fprintf(stdout, "%s Perms: %08X, SID: ", prefix, ace->perms);
+ if (verbose) fprintf(stdout, "%s Perms: %08X, SID: ", prefix,
+ IVAL(&ace->perms, 0));
+ if (change)
+ process_sid(&ace->trustee, &old_sid, &new_sid);
print_sid(&ace->trustee);
- ace = (ACE *)((char *)ace + ace->length);
+ ace = (ACE *)((char *)ace + SVAL(&ace->length, 0));
}
}
-void usage(void)
-{
- fprintf(stderr, "usage: profiles [-c <OLD-SID> -n <NEW-SID>] <profilefile>\n");
- fprintf(stderr, "Version: %s\n", VERSION);
- fprintf(stderr, "\n\t-c S-1-5-21-z-y-x-oldrid provides SID to change");
- fprintf(stderr, "\n\t-n S-1-5-21-a-b-c-newrid provides SID to change to");
- fprintf(stderr, "\n\t\tBoth must be present if the other is.");
- fprintf(stderr, "\n\t\tIf neither present, just report the SIDs found\n");
-}
-
-DOM_SID old_sid, new_sid;
-
int main(int argc, char *argv[])
{
- int i, fd, aces, start = 0;
- int verbose = 0;
- int process_sids = 0;
- void *base;
+ int opt;
+ int fd, start = 0;
+ char *base;
struct stat sbuf;
- fstring sid_str;
REGF_HDR *regf_hdr;
HBIN_HDR *hbin_hdr;
NK_HDR *nk_hdr;
SK_HDR *sk_hdr;
- WORD first_sk_off, sk_off;
+ DWORD first_sk_off, sk_off;
MY_SEC_DESC *sec_desc;
int *ptr;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Sets verbose mode" },
+ { "change-sid", 'c', POPT_ARG_STRING, NULL, 'c', "Provides SID to change" },
+ { "new-sid", 'n', POPT_ARG_STRING, NULL, 'n', "Provides SID to change to" },
+ { 0, 0, 0, 0 }
+ };
- if (argc < 2) {
- usage();
- exit(1);
- }
+ poptContext pc;
+
+ pc = poptGetContext("profiles", argc, (const char **)argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ poptSetOtherOptionHelp(pc, "<profilefile>");
/*
* Now, process the arguments
*/
- fd = open(argv[1], O_RDWR, 0000);
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'c':
+ change = 1;
+ if (!get_sid(&old_sid, poptGetOptArg(pc))) {
+ fprintf(stderr, "Argument to -c should be a SID in form of S-1-5-...\n");
+ poptPrintUsage(pc, stderr, 0);
+ exit(254);
+ }
+ break;
+
+ case 'n':
+ new = 1;
+ if (!get_sid(&new_sid, poptGetOptArg(pc))) {
+ fprintf(stderr, "Argument to -n should be a SID in form of S-1-5-...\n");
+ poptPrintUsage(pc, stderr, 0);
+ exit(253);
+ }
+
+ break;
+
+ case 'v':
+ verbose++;
+ break;
+ }
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+
+ if ((!change & new) || (change & !new)) {
+ fprintf(stderr, "You must specify both -c and -n if one or the other is set!\n");
+ poptPrintUsage(pc, stderr, 0);
+ exit(252);
+ }
+
+ poptGetArg(pc); /* To get argv[0] */
+
+ fd = open(poptPeekArg(pc), O_RDWR, 0000);
if (fd < 0) {
- fprintf(stderr, "Could not open %s: %s\n", argv[1],
+ fprintf(stderr, "Could not open %s: %s\n", poptPeekArg(pc),
strerror(errno));
exit(2);
}
if (fstat(fd, &sbuf) < 0) {
- fprintf(stderr, "Could not stat file %s, %s\n", argv[1],
+ fprintf(stderr, "Could not stat file %s, %s\n", poptPeekArg(pc),
strerror(errno));
exit(3);
}
* dealing with the records. We are interested in the sk record
*/
start = 0;
- base = mmap(&start, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+#ifdef HAVE_MMAP
+ base = mmap(&start, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+#else
+ base = (char *)-1;
+ errno = ENOSYS;
+#endif
if ((int)base == -1) {
- fprintf(stderr, "Could not mmap file: %s, %s\n", argv[1],
+ fprintf(stderr, "Could not mmap file: %s, %s\n", poptPeekArg(pc),
strerror(errno));
exit(4);
}
+ /*
+ * In what follows, and in places above, in order to work on both LE and
+ * BE platforms, we have to use the Samba macros to extract SHORT, LONG
+ * and associated UNSIGNED quantities from the data in the mmap'd file.
+ * NOTE, however, that we do not need to do anything with memory
+ * addresses that we construct from pointers in our address space.
+ * For example,
+ *
+ * sec_desc = (MY_SEC_DESC *)&(sk_hdr->sec_desc[0]);
+ *
+ * is simply taking the address of a structure we already have the address
+ * of in our address space, while, the fields within it, will have to
+ * be accessed with the macros:
+ *
+ * owner_sid = (DOM_SID *)(&sk_hdr->sec_desc[0] +
+ * IVAL(&sec_desc->owner_off, 0));
+ *
+ * Which is pulling out an offset and adding it to an existing pointer.
+ *
+ */
+
regf_hdr = (REGF_HDR *)base;
- if (verbose) fprintf(stdout, "Registry file size: %u\n", sbuf.st_size);
+ if (verbose) fprintf(stdout, "Registry file size: %u\n", (unsigned int)sbuf.st_size);
- if (regf_hdr->REGF_ID != REG_REGF_ID) {
- fprintf(stderr, "Incorrect Registry file (doesn't have header ID): %s\n", argv[1]);
+ if (IVAL(®f_hdr->REGF_ID, 0) != REG_REGF_ID) {
+ fprintf(stderr, "Incorrect Registry file (doesn't have header ID): %s\n", poptPeekArg(pc));
exit(5);
}
if (verbose) fprintf(stdout, "First Key Off: %u, Data Block Size: %u\n",
- regf_hdr->first_key, regf_hdr->dblk_size);
+ IVAL(®f_hdr->first_key, 0),
+ IVAL(®f_hdr->dblk_size, 0));
- hbin_hdr = (HBIN_HDR *)(base + 0x1000);
+ hbin_hdr = (HBIN_HDR *)(base + 0x1000); /* No need for Endian stuff */
/*
* This should be the hbin_hdr
*/
- if (hbin_hdr->HBIN_ID != REG_HBIN_ID) {
- fprintf(stderr, "Incorrect hbin hdr: %s\n", argv[1]);
+ if (IVAL(&hbin_hdr->HBIN_ID, 0) != REG_HBIN_ID) {
+ fprintf(stderr, "Incorrect hbin hdr: %s\n", poptPeekArg(pc));
exit(6);
}
if (verbose) fprintf(stdout, "Next Off: %u, Prev Off: %u\n",
- hbin_hdr->next_off, hbin_hdr->prev_off);
+ IVAL(&hbin_hdr->next_off, 0),
+ IVAL(&hbin_hdr->prev_off, 0));
- nk_hdr = (NK_HDR *)(base + 0x1000 + regf_hdr->first_key + 4);
+ nk_hdr = (NK_HDR *)(base + 0x1000 + IVAL(®f_hdr->first_key, 0) + 4);
- if (nk_hdr->NK_ID != REG_NK_ID) {
- fprintf(stderr, "Incorrect NK Header: %s\n", argv[1]);
+ if (SVAL(&nk_hdr->NK_ID, 0) != REG_NK_ID) {
+ fprintf(stderr, "Incorrect NK Header: %s\n", poptPeekArg(pc));
exit(7);
}
+ sk_off = first_sk_off = IVAL(&nk_hdr->sk_off, 0);
if (verbose) {
- fprintf(stdout, "Type: %0x\n", nk_hdr->type);
- fprintf(stdout, "SK Off : %o\n", (0x1000 + nk_hdr->sk_off + 4));
+ fprintf(stdout, "Type: %0x\n", SVAL(&nk_hdr->type, 0));
+ fprintf(stdout, "SK Off : %o\n", (0x1000 + sk_off + 4));
}
- sk_hdr = (SK_HDR *)(base + 0x1000 + nk_hdr->sk_off + 4);
- sk_off = first_sk_off = nk_hdr->sk_off;
+ sk_hdr = (SK_HDR *)(base + 0x1000 + sk_off + 4);
do {
DOM_SID *owner_sid, *group_sid;
ACL *sacl, *dacl;
- if (sk_hdr->SK_ID != REG_SK_ID) {
+ if (SVAL(&sk_hdr->SK_ID, 0) != REG_SK_ID) {
fprintf(stderr, "Incorrect SK Header format: %08X\n",
- (0x1000 + nk_hdr->sk_off + 4));
+ (0x1000 + sk_off + 4));
exit(8);
}
ptr = (int *)sk_hdr;
if (verbose) fprintf(stdout, "Off: %08X, Refs: %u, Size: %u\n",
- sk_off, sk_hdr->ref_cnt, sk_hdr->rec_size);
+ sk_off, IVAL(&sk_hdr->ref_cnt, 0),
+ IVAL(&sk_hdr->rec_size, 0));
sec_desc = (MY_SEC_DESC *)&(sk_hdr->sec_desc[0]);
- owner_sid = (DOM_SID *)(&sk_hdr->sec_desc[0] + sec_desc->owner_off);
- group_sid = (DOM_SID *)(&sk_hdr->sec_desc[0] + sec_desc->group_off);
- sacl = (ACL *)(&sk_hdr->sec_desc[0] + sec_desc->sacl_off);
- dacl = (ACL *)(&sk_hdr->sec_desc[0] + sec_desc->dacl_off);
- fprintf(stdout, " Owner SID: "); print_sid(owner_sid);
- fprintf(stdout, " Group SID: "); print_sid(group_sid);
+ owner_sid = (DOM_SID *)(&sk_hdr->sec_desc[0] +
+ IVAL(&sec_desc->owner_off, 0));
+ group_sid = (DOM_SID *)(&sk_hdr->sec_desc[0] +
+ IVAL(&sec_desc->group_off, 0));
+ sacl = (ACL *)(&sk_hdr->sec_desc[0] +
+ IVAL(&sec_desc->sacl_off, 0));
+ dacl = (ACL *)(&sk_hdr->sec_desc[0] +
+ IVAL(&sec_desc->dacl_off, 0));
+ if (verbose)fprintf(stdout, " Owner SID: ");
+ if (change) process_sid(owner_sid, &old_sid, &new_sid);
+ if (verbose) print_sid(owner_sid);
+ if (verbose) fprintf(stdout, " Group SID: ");
+ if (change) process_sid(group_sid, &old_sid, &new_sid);
+ if (verbose) print_sid(group_sid);
fprintf(stdout, " SACL: ");
- if (!sec_desc->sacl_off)
- fprintf(stdout, "NONE\n");
+ if (!sec_desc->sacl_off) { /* LE zero == BE zero */
+ if (verbose) fprintf(stdout, "NONE\n");
+ }
else
- print_acl(sacl, " ");
- fprintf(stdout, " DACL: ");
- if (!sec_desc->dacl_off)
- fprintf(stdout, "NONE\n");
+ process_acl(sacl, " ");
+ if (verbose) fprintf(stdout, " DACL: ");
+ if (!sec_desc->dacl_off) {
+ if (verbose) fprintf(stdout, "NONE\n");
+ }
else
- print_acl(dacl, " ");
- sk_off = sk_hdr->prev_off;
- sk_hdr = (SK_HDR *)(base + OFF(sk_hdr->prev_off));
+ process_acl(dacl, " ");
+ sk_off = IVAL(&sk_hdr->prev_off, 0);
+ sk_hdr = (SK_HDR *)(base + OFF(IVAL(&sk_hdr->prev_off, 0)));
} while (sk_off != first_sk_off);
-}
+#ifdef HAVE_MMAP
+ munmap(base, sbuf.st_size);
+#endif
+
+ poptFreeContext(pc);
+ close(fd);
+ return 0;
+}