From a1f930ddbd4f43376829569441c7de4b920d9e02 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Apr 2013 14:02:09 +0200 Subject: [PATCH 1/3] samba-tool: add 'replace-binary-sid' command This is a replacement for the broken 'profiles' utility. Signed-off-by: Stefan Metzmacher --- python/samba/netcmd/main.py | 2 + python/samba/netcmd/replace_binary_sid.py | 111 +++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100755 python/samba/netcmd/replace_binary_sid.py diff --git a/python/samba/netcmd/main.py b/python/samba/netcmd/main.py index 5f788235..4246364 100644 --- a/python/samba/netcmd/main.py +++ b/python/samba/netcmd/main.py @@ -39,6 +39,7 @@ from samba.netcmd.time import cmd_time from samba.netcmd.user import cmd_user from samba.netcmd.vampire import cmd_vampire from samba.netcmd.processes import cmd_processes +from samba.netcmd.replace_binary_sid import cmd_replace_binary_sid class cmd_sambatool(SuperCommand): @@ -68,3 +69,4 @@ class cmd_sambatool(SuperCommand): subcommands["user"] = cmd_user() subcommands["vampire"] = cmd_vampire() subcommands["processes"] = cmd_processes() + subcommands["replace-binary-sid"] = cmd_replace_binary_sid() diff --git a/python/samba/netcmd/replace_binary_sid.py b/python/samba/netcmd/replace_binary_sid.py new file mode 100755 index 0000000..3640574 --- /dev/null +++ b/python/samba/netcmd/replace_binary_sid.py @@ -0,0 +1,111 @@ +# +# Copyright Stefan Metzmacher metze@samba.org 2013 +# +# 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; either version 3 of the License, or +# (at your option) any later version. +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# +# Tool to replace SID's in binary NDR format within a file. +# This can be used for NTUSER.dat files, when migrating +# roaming profiles to a new domain. +# + +import os +from samba.dcerpc import security +from samba.ndr import ndr_pack +import samba.getopt as options +from samba.netcmd import ( + Command, + CommandError, + Option + ) + +class cmd_replace_binary_sid(Command): + """Replace a binary (NDR) encoded SID in a file (e.g. NTUSER.dat).""" + + synopsis = "%prog [options]" + + takes_optiongroups = { + "versionopts": options.VersionOptions, + } + + takes_options = [ + Option("--verbose", dest="verbose", action="store_true") + ] + + takes_args = ["oldfile", "oldsid", "newfile", "newsid"] + + def run(self, old_file_path, old_sid_str, new_file_path, new_sid_str, + versionopts=None, verbose=False): + try: + old_sid = security.dom_sid(old_sid_str) + except Exception, err: + raise CommandError("oldsid[%s] invalid" % (old_sid_str)) + old_bin = ndr_pack(old_sid) + try: + new_sid = security.dom_sid(new_sid_str) + except Exception, err: + raise CommandError("newsid[%s] invalid" % (new_sid_str)) + new_bin = ndr_pack(new_sid) + + if old_file_path == new_file_path: + raise CommandError("old_file_path should not match new_file_path") + + if len(old_bin) != len(new_bin): + raise CommandError("The binary size of oldsid(%d) != newsid(%d)" \ + % (len(old_bin), len(new_bin))) + + blen = len(old_bin) + if blen < 24: + raise CommandError("The binary size of oldsid(%d) < 24" \ + % (len(old_bin))) + + try: + old_fd = os.open(old_file_path, os.O_RDONLY) + except Exception, err: + raise CommandError(err) + old_st = os.fstat(old_fd) + new_flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL + new_mode = old_st.st_mode + try: + new_fd = os.open(new_file_path, new_flags, new_mode) + except Exception, err: + raise CommandError(err) + old_file = os.fdopen(old_fd, 'r') + old_bytes = old_file.read() + old_file.close() + + new_bytes = "" + ofs = 0 + remaining = len(old_bytes) - ofs + while remaining >= blen: + if old_bytes[ofs:ofs+blen] == old_bin: + if verbose: + print "replacing at offset[%d]" % (ofs) + new_bytes += new_bin + ofs += blen + else: + new_bytes += old_bytes[ofs:ofs+1] + ofs += 1 + remaining = len(old_bytes) - ofs + + if remaining > 0: + new_bytes += old_bytes[ofs:ofs+remaining] + ofs += remaining + + new_file = os.fdopen(new_fd, 'w') + new_file.write(new_bytes) + new_file.close() + + return -- 1.7.9.5 From 3428a3868b1a7a718896f859cb45b6c2971b337a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Mar 2013 09:40:36 +0100 Subject: [PATCH 2/3] s3:utils/profiles: fix a compiler warning Signed-off-by: Stefan Metzmacher --- source3/utils/profiles.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/utils/profiles.c b/source3/utils/profiles.c index 30c6ad0..51e63d4 100644 --- a/source3/utils/profiles.c +++ b/source3/utils/profiles.c @@ -194,7 +194,7 @@ static bool copy_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk, /********************************************************************* *********************************************************************/ -int main( int argc, char *argv[] ) +int main(int argc, const char *argv[]) { TALLOC_CTX *frame = talloc_stackframe(); int opt; @@ -218,7 +218,7 @@ int main( int argc, char *argv[] ) setup_logging( "profiles", DEBUG_STDERR); - pc = poptGetContext("profiles", argc, (const char **)argv, long_options, + pc = poptGetContext("profiles", argc, argv, long_options, POPT_CONTEXT_KEEP_FIRST); poptSetOtherOptionHelp(pc, ""); -- 1.7.9.5 From 89e4ac59314961964522203a4370cb9c19f38e18 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Apr 2013 14:07:02 +0200 Subject: [PATCH 3/3] s3:utils/profiles: add --really-force option and warn about data corruption (bug #9629) While trying to fix the problem from bug #9629, I found that the profiles tool completely corrupts the new NTUSER.dat file, there're missing keys and values (regdiff show differences) and the resulting file is much smaller than the original file. Instead of trying to fix the security descriptors on registry level, it's much easier and safer to just replace the binary SID values within the NTUSER.dat file. We keep the profiles binary, so that admins get pointed to 'samba-tool replace-binary-sids'. Signed-off-by: Stefan Metzmacher --- source3/utils/profiles.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/source3/utils/profiles.c b/source3/utils/profiles.c index 51e63d4..1aad280 100644 --- a/source3/utils/profiles.c +++ b/source3/utils/profiles.c @@ -201,11 +201,16 @@ int main(int argc, const char *argv[]) REGF_FILE *infile, *outfile; REGF_NK_REC *nk; char *orig_filename, *new_filename; + enum { + OPT_REALLY_FORCE = 1000 + }; + bool really_force = false; struct poptOption long_options[] = { POPT_AUTOHELP { "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" }, { "verbose", 'v', POPT_ARG_NONE, &opt_verbose, 'v', "Verbose output" }, + { "really-force", 0, POPT_ARG_NONE, NULL, OPT_REALLY_FORCE, "ignore corruption warning" }, POPT_COMMON_SAMBA POPT_COMMON_VERSION POPT_TABLEEND @@ -245,6 +250,9 @@ int main(int argc, const char *argv[]) } break; + case OPT_REALLY_FORCE: + really_force = true; + break; } } @@ -255,6 +263,15 @@ int main(int argc, const char *argv[]) exit(1); } + if (!really_force) { + poptPrintUsage(pc, stderr, 0); + fprintf(stderr, "WARNING!!!\n"); + fprintf(stderr, "This tool has known bugs which corrupt the output file!\n"); + fprintf(stderr, "Better use 'samba-tool replace-binary-sid' to modify your NTUSER.dat\n"); + fprintf(stderr, "or use the --really-force option if you want corrupted data.\n"); + exit(252); + } + if ((!change && new_val) || (change && !new_val)) { fprintf(stderr, "You must specify both -c and -n if one or the other is set!\n"); poptPrintUsage(pc, stderr, 0); -- 1.7.9.5