f6f500a2aaef74912e0803a80997aae05f6ec344
[kai/samba.git] / source3 / utils / profiles.c
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "popt_common.h"
24 #include "registry/reg_objects.h"
25 #include "regfio.h"
26
27 /* GLOBAL VARIABLES */
28
29 struct dom_sid old_sid, new_sid;
30 int change = 0, new_val = 0;
31 int opt_verbose = False;
32
33 /********************************************************************
34 ********************************************************************/
35
36 static void verbose_output(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
37 static void verbose_output(const char *format, ...)
38 {
39         va_list args;
40         char *var = NULL;
41
42         if (!opt_verbose) {
43                 return;
44         }
45
46         va_start(args, format);
47         if ((vasprintf(&var, format, args)) == -1) {
48                 va_end(args);
49                 return;
50         }
51
52         fprintf(stdout, "%s", var);
53         va_end(args);
54         SAFE_FREE(var);
55 }
56
57 /********************************************************************
58 ********************************************************************/
59
60 static bool swap_sid_in_acl( struct security_descriptor *sd, struct dom_sid *s1, struct dom_sid *s2 )
61 {
62         struct security_acl *theacl;
63         int i;
64         bool update = False;
65
66         verbose_output("  Owner SID: %s\n", sid_string_tos(sd->owner_sid));
67         if ( sid_equal( sd->owner_sid, s1 ) ) {
68                 sid_copy( sd->owner_sid, s2 );
69                 update = True;
70                 verbose_output("  New Owner SID: %s\n",
71                         sid_string_tos(sd->owner_sid));
72
73         }
74
75         verbose_output("  Group SID: %s\n", sid_string_tos(sd->group_sid));
76         if ( sid_equal( sd->group_sid, s1 ) ) {
77                 sid_copy( sd->group_sid, s2 );
78                 update = True;
79                 verbose_output("  New Group SID: %s\n",
80                         sid_string_tos(sd->group_sid));
81         }
82
83         theacl = sd->dacl;
84         verbose_output("  DACL: %d entries:\n", theacl->num_aces);
85         for ( i=0; i<theacl->num_aces; i++ ) {
86                 verbose_output("    Trustee SID: %s\n",
87                         sid_string_tos(&theacl->aces[i].trustee));
88                 if ( sid_equal( &theacl->aces[i].trustee, s1 ) ) {
89                         sid_copy( &theacl->aces[i].trustee, s2 );
90                         update = True;
91                         verbose_output("    New Trustee SID: %s\n",
92                                 sid_string_tos(&theacl->aces[i].trustee));
93                 }
94         }
95
96 #if 0
97         theacl = sd->sacl;
98         verbose_output("  SACL: %d entries: \n", theacl->num_aces);
99         for ( i=0; i<theacl->num_aces; i++ ) {
100                 verbose_output("    Trustee SID: %s\n",
101                         sid_string_tos(&theacl->aces[i].trustee));
102                 if ( sid_equal( &theacl->aces[i].trustee, s1 ) ) {
103                         sid_copy( &theacl->aces[i].trustee, s2 );
104                         update = True;
105                         verbose_output("    New Trustee SID: %s\n",
106                                 sid_string_tos(&theacl->aces[i].trustee));
107                 }
108         }
109 #endif
110         return update;
111 }
112
113 /********************************************************************
114 ********************************************************************/
115
116 static bool copy_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk,
117                                 REGF_NK_REC *parent, REGF_FILE *outfile,
118                                 const char *parentpath  )
119 {
120         REGF_NK_REC *key, *subkey;
121         struct security_descriptor *new_sd;
122         struct regval_ctr *values;
123         struct regsubkey_ctr *subkeys;
124         int i;
125         char *path;
126         WERROR werr;
127
128         /* swap out the SIDs in the security descriptor */
129
130         if ( !(new_sd = dup_sec_desc( outfile->mem_ctx, nk->sec_desc->sec_desc )) ) {
131                 fprintf( stderr, "Failed to copy security descriptor!\n" );
132                 return False;
133         }
134
135         verbose_output("ACL for %s%s%s\n", parentpath, parent ? "\\" : "", nk->keyname);
136         swap_sid_in_acl( new_sd, &old_sid, &new_sid );
137
138         werr = regsubkey_ctr_init(NULL, &subkeys);
139         if (!W_ERROR_IS_OK(werr)) {
140                 DEBUG(0,("copy_registry_tree: talloc() failure!\n"));
141                 return False;
142         }
143
144         werr = regval_ctr_init(subkeys, &values);
145         if (!W_ERROR_IS_OK(werr)) {
146                 TALLOC_FREE( subkeys );
147                 DEBUG(0,("copy_registry_tree: talloc() failure!\n"));
148                 return False;
149         }
150
151         /* copy values into the struct regval_ctr */
152
153         for ( i=0; i<nk->num_values; i++ ) {
154                 regval_ctr_addvalue( values, nk->values[i].valuename, nk->values[i].type,
155                         nk->values[i].data, (nk->values[i].data_size & ~VK_DATA_IN_OFFSET) );
156         }
157
158         /* copy subkeys into the struct regsubkey_ctr */
159
160         while ( (subkey = regfio_fetch_subkey( infile, nk )) ) {
161                 regsubkey_ctr_addkey( subkeys, subkey->keyname );
162         }
163
164         key = regfio_write_key( outfile, nk->keyname, values, subkeys, new_sd, parent );
165
166         /* write each one of the subkeys out */
167
168         path = talloc_asprintf(subkeys, "%s%s%s",
169                         parentpath, parent ? "\\" : "",nk->keyname);
170         if (!path) {
171                 TALLOC_FREE( subkeys );
172                 return false;
173         }
174
175         nk->subkey_index = 0;
176         while ((subkey = regfio_fetch_subkey(infile, nk))) {
177                 if (!copy_registry_tree( infile, subkey, key, outfile, path)) {
178                         TALLOC_FREE(subkeys);
179                         return false;
180                 }
181         }
182
183         /* values is a talloc()'d child of subkeys here so just throw it all away */
184
185         TALLOC_FREE( subkeys );
186
187         verbose_output("[%s]\n", path);
188
189         return True;
190 }
191
192 /*********************************************************************
193 *********************************************************************/
194
195 int main( int argc, char *argv[] )
196 {
197         TALLOC_CTX *frame = talloc_stackframe();
198         int opt;
199         REGF_FILE *infile, *outfile;
200         REGF_NK_REC *nk;
201         char *orig_filename, *new_filename;
202         struct poptOption long_options[] = {
203                 POPT_AUTOHELP
204                 { "change-sid", 'c', POPT_ARG_STRING, NULL, 'c', "Provides SID to change" },
205                 { "new-sid", 'n', POPT_ARG_STRING, NULL, 'n', "Provides SID to change to" },
206                 { "verbose", 'v', POPT_ARG_NONE, &opt_verbose, 'v', "Verbose output" },
207                 POPT_COMMON_SAMBA
208                 POPT_COMMON_VERSION
209                 POPT_TABLEEND
210         };
211         poptContext pc;
212
213         load_case_tables();
214
215         /* setup logging options */
216
217         setup_logging( "profiles", True );
218         dbf = x_stderr;
219         x_setbuf( x_stderr, NULL );
220
221         pc = poptGetContext("profiles", argc, (const char **)argv, long_options,
222                 POPT_CONTEXT_KEEP_FIRST);
223
224         poptSetOtherOptionHelp(pc, "<profilefile>");
225
226         /* Now, process the arguments */
227
228         while ((opt = poptGetNextOpt(pc)) != -1) {
229                 switch (opt) {
230                 case 'c':
231                         change = 1;
232                         if (!string_to_sid(&old_sid, poptGetOptArg(pc))) {
233                                 fprintf(stderr, "Argument to -c should be a SID in form of S-1-5-...\n");
234                                 poptPrintUsage(pc, stderr, 0);
235                                 exit(254);
236                         }
237                         break;
238
239                 case 'n':
240                         new_val = 1;
241                         if (!string_to_sid(&new_sid, poptGetOptArg(pc))) {
242                                 fprintf(stderr, "Argument to -n should be a SID in form of S-1-5-...\n");
243                                 poptPrintUsage(pc, stderr, 0);
244                                 exit(253);
245                         }
246                         break;
247
248                 }
249         }
250
251         poptGetArg(pc);
252
253         if (!poptPeekArg(pc)) {
254                 poptPrintUsage(pc, stderr, 0);
255                 exit(1);
256         }
257
258         if ((!change && new_val) || (change && !new_val)) {
259                 fprintf(stderr, "You must specify both -c and -n if one or the other is set!\n");
260                 poptPrintUsage(pc, stderr, 0);
261                 exit(252);
262         }
263
264         orig_filename = talloc_strdup(frame, poptPeekArg(pc));
265         if (!orig_filename) {
266                 exit(ENOMEM);
267         }
268         new_filename = talloc_asprintf(frame,
269                                         "%s.new",
270                                         orig_filename);
271         if (!new_filename) {
272                 exit(ENOMEM);
273         }
274
275         if (!(infile = regfio_open( orig_filename, O_RDONLY, 0))) {
276                 fprintf( stderr, "Failed to open %s!\n", orig_filename );
277                 fprintf( stderr, "Error was (%s)\n", strerror(errno) );
278                 exit (1);
279         }
280
281         if ( !(outfile = regfio_open( new_filename, (O_RDWR|O_CREAT|O_TRUNC), (S_IREAD|S_IWRITE) )) ) {
282                 fprintf( stderr, "Failed to open new file %s!\n", new_filename );
283                 fprintf( stderr, "Error was (%s)\n", strerror(errno) );
284                 exit (1);
285         }
286
287         /* actually do the update now */
288
289         if ((nk = regfio_rootkey( infile )) == NULL) {
290                 fprintf(stderr, "Could not get rootkey\n");
291                 exit(3);
292         }
293
294         if (!copy_registry_tree( infile, nk, NULL, outfile, "")) {
295                 fprintf(stderr, "Failed to write updated registry file!\n");
296                 exit(2);
297         }
298
299         /* cleanup */
300
301         regfio_close(infile);
302         regfio_close(outfile);
303
304         poptFreeContext(pc);
305
306         TALLOC_FREE(frame);
307         return 0;
308 }