1/* 2 Samba Unix/Linux SMB client utility profiles.c 3 4 Copyright (C) Richard Sharpe, <rsharpe@richardsharpe.com> 2002 5 Copyright (C) Jelmer Vernooij (conversion to popt) 2003 6 Copyright (C) Gerald (Jerry) Carter 2005 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22 23#include "includes.h" 24#include "regfio.h" 25 26/* GLOBAL VARIABLES */ 27 28DOM_SID old_sid, new_sid; 29int change = 0, new_val = 0; 30BOOL opt_verbose = False; 31 32/******************************************************************** 33********************************************************************/ 34 35static void verbose_output(const char *format, ...) PRINTF_ATTRIBUTE(1,2); 36static void verbose_output(const char *format, ...) 37{ 38 va_list args; 39 char *var = NULL; 40 41 if (!opt_verbose) { 42 return; 43 } 44 45 va_start(args, format); 46 if ((vasprintf(&var, format, args)) == -1) { 47 va_end(args); 48 return; 49 } 50 51 fprintf(stdout, var); 52 va_end(args); 53 SAFE_FREE(var); 54} 55 56/******************************************************************** 57********************************************************************/ 58 59static BOOL swap_sid_in_acl( SEC_DESC *sd, DOM_SID *s1, DOM_SID *s2 ) 60{ 61 SEC_ACL *acl; 62 int i; 63 BOOL update = False; 64 65 verbose_output(" Owner SID: %s\n", sid_string_static(sd->owner_sid)); 66 if ( sid_equal( sd->owner_sid, s1 ) ) { 67 sid_copy( sd->owner_sid, s2 ); 68 update = True; 69 verbose_output(" New Owner SID: %s\n", 70 sid_string_static(sd->owner_sid)); 71 72 } 73 74 verbose_output(" Group SID: %s\n", sid_string_static(sd->group_sid)); 75 if ( sid_equal( sd->group_sid, s1 ) ) { 76 sid_copy( sd->group_sid, s2 ); 77 update = True; 78 verbose_output(" New Group SID: %s\n", 79 sid_string_static(sd->group_sid)); 80 } 81 82 acl = sd->dacl; 83 verbose_output(" DACL: %d entries:\n", acl->num_aces); 84 for ( i=0; i<acl->num_aces; i++ ) { 85 verbose_output(" Trustee SID: %s\n", 86 sid_string_static(&acl->aces[i].trustee)); 87 if ( sid_equal( &acl->aces[i].trustee, s1 ) ) { 88 sid_copy( &acl->aces[i].trustee, s2 ); 89 update = True; 90 verbose_output(" New Trustee SID: %s\n", 91 sid_string_static(&acl->aces[i].trustee)); 92 } 93 } 94 95#if 0 96 acl = sd->sacl; 97 verbose_output(" SACL: %d entries: \n", acl->num_aces); 98 for ( i=0; i<acl->num_aces; i++ ) { 99 verbose_output(" Trustee SID: %s\n", 100 sid_string_static(&acl->aces[i].trustee)); 101 if ( sid_equal( &acl->aces[i].trustee, s1 ) ) { 102 sid_copy( &acl->aces[i].trustee, s2 ); 103 update = True; 104 verbose_output(" New Trustee SID: %s\n", 105 sid_string_static(&acl->aces[i].trustee)); 106 } 107 } 108#endif 109 return update; 110} 111 112/******************************************************************** 113********************************************************************/ 114 115static BOOL copy_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk, 116 REGF_NK_REC *parent, REGF_FILE *outfile, 117 const char *parentpath ) 118{ 119 REGF_NK_REC *key, *subkey; 120 SEC_DESC *new_sd; 121 REGVAL_CTR *values; 122 REGSUBKEY_CTR *subkeys; 123 int i; 124 pstring path; 125 126 /* swap out the SIDs in the security descriptor */ 127 128 if ( !(new_sd = dup_sec_desc( outfile->mem_ctx, nk->sec_desc->sec_desc )) ) { 129 fprintf( stderr, "Failed to copy security descriptor!\n" ); 130 return False; 131 } 132 133 verbose_output("ACL for %s%s%s\n", parentpath, parent ? "\\" : "", nk->keyname); 134 swap_sid_in_acl( new_sd, &old_sid, &new_sid ); 135 136 if ( !(subkeys = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR )) ) { 137 DEBUG(0,("copy_registry_tree: talloc() failure!\n")); 138 return False; 139 } 140 141 if ( !(values = TALLOC_ZERO_P( subkeys, REGVAL_CTR )) ) { 142 DEBUG(0,("copy_registry_tree: talloc() failure!\n")); 143 return False; 144 } 145 146 /* copy values into the REGVAL_CTR */ 147 148 for ( i=0; i<nk->num_values; i++ ) { 149 regval_ctr_addvalue( values, nk->values[i].valuename, nk->values[i].type, 150 (const char *)nk->values[i].data, (nk->values[i].data_size & ~VK_DATA_IN_OFFSET) ); 151 } 152 153 /* copy subkeys into the REGSUBKEY_CTR */ 154 155 while ( (subkey = regfio_fetch_subkey( infile, nk )) ) { 156 regsubkey_ctr_addkey( subkeys, subkey->keyname ); 157 } 158 159 key = regfio_write_key( outfile, nk->keyname, values, subkeys, new_sd, parent ); 160 161 /* write each one of the subkeys out */ 162 163 pstr_sprintf( path, "%s%s%s", parentpath, parent ? "\\" : "", nk->keyname ); 164 165 nk->subkey_index = 0; 166 while ( (subkey = regfio_fetch_subkey( infile, nk )) ) { 167 if ( !copy_registry_tree( infile, subkey, key, outfile, path ) ) 168 return False; 169 } 170 171 /* values is a talloc()'d child of subkeys here so just throw it all away */ 172 173 TALLOC_FREE( subkeys ); 174 175 verbose_output("[%s]\n", path); 176 177 return True; 178} 179 180/********************************************************************* 181*********************************************************************/ 182 183int main( int argc, char *argv[] ) 184{ 185 int opt; 186 REGF_FILE *infile, *outfile; 187 REGF_NK_REC *nk; 188 pstring orig_filename, new_filename; 189 struct poptOption long_options[] = { 190 POPT_AUTOHELP 191 { "change-sid", 'c', POPT_ARG_STRING, NULL, 'c', "Provides SID to change" }, 192 { "new-sid", 'n', POPT_ARG_STRING, NULL, 'n', "Provides SID to change to" }, 193 { "verbose", 'v', POPT_ARG_NONE, &opt_verbose, 'v', "Verbose output" }, 194 POPT_COMMON_SAMBA 195 POPT_COMMON_VERSION 196 POPT_TABLEEND 197 }; 198 poptContext pc; 199 200 load_case_tables(); 201 202 /* setup logging options */ 203 204 setup_logging( "profiles", True ); 205 dbf = x_stderr; 206 x_setbuf( x_stderr, NULL ); 207 208 pc = poptGetContext("profiles", argc, (const char **)argv, long_options, 209 POPT_CONTEXT_KEEP_FIRST); 210 211 poptSetOtherOptionHelp(pc, "<profilefile>"); 212 213 /* Now, process the arguments */ 214 215 while ((opt = poptGetNextOpt(pc)) != -1) { 216 switch (opt) { 217 case 'c': 218 change = 1; 219 if (!string_to_sid(&old_sid, poptGetOptArg(pc))) { 220 fprintf(stderr, "Argument to -c should be a SID in form of S-1-5-...\n"); 221 poptPrintUsage(pc, stderr, 0); 222 exit(254); 223 } 224 break; 225 226 case 'n': 227 new_val = 1; 228 if (!string_to_sid(&new_sid, poptGetOptArg(pc))) { 229 fprintf(stderr, "Argument to -n should be a SID in form of S-1-5-...\n"); 230 poptPrintUsage(pc, stderr, 0); 231 exit(253); 232 } 233 break; 234 235 } 236 } 237 238 poptGetArg(pc); 239 240 if (!poptPeekArg(pc)) { 241 poptPrintUsage(pc, stderr, 0); 242 exit(1); 243 } 244 245 if ((!change && new_val) || (change && !new_val)) { 246 fprintf(stderr, "You must specify both -c and -n if one or the other is set!\n"); 247 poptPrintUsage(pc, stderr, 0); 248 exit(252); 249 } 250 251 pstrcpy( orig_filename, poptPeekArg(pc) ); 252 pstr_sprintf( new_filename, "%s.new", orig_filename ); 253 254 if ( !(infile = regfio_open( orig_filename, O_RDONLY, 0 )) ) { 255 fprintf( stderr, "Failed to open %s!\n", orig_filename ); 256 fprintf( stderr, "Error was (%s)\n", strerror(errno) ); 257 exit (1); 258 } 259 260 if ( !(outfile = regfio_open( new_filename, (O_RDWR|O_CREAT|O_TRUNC), (S_IREAD|S_IWRITE) )) ) { 261 fprintf( stderr, "Failed to open new file %s!\n", new_filename ); 262 fprintf( stderr, "Error was (%s)\n", strerror(errno) ); 263 exit (1); 264 } 265 266 /* actually do the update now */ 267 268 if ((nk = regfio_rootkey( infile )) == NULL) { 269 fprintf(stderr, "Could not get rootkey\n"); 270 exit(3); 271 } 272 273 if ( !copy_registry_tree( infile, nk, NULL, outfile, "" ) ) { 274 fprintf(stderr, "Failed to write updated registry file!\n"); 275 exit(2); 276 } 277 278 /* cleanup */ 279 280 regfio_close( infile ); 281 regfio_close( outfile ); 282 283 poptFreeContext(pc); 284 285 return( 0 ); 286} 287