profiles
[metze/samba/wip.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 "system/filesys.h"
24 #include "popt_common.h"
25 #include "../libcli/security/security.h"
26 <<<<<<< HEAD
27
28 /* GLOBAL VARIABLES */
29
30 struct dom_sid old_sid, new_sid;
31 int change = 0, new_val = 0;
32 int opt_verbose = False;
33
34 /********************************************************************
35 ********************************************************************/
36
37 static void verbose_output(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
38 static void verbose_output(const char *format, ...)
39 {
40         va_list args;
41         char *var = NULL;
42
43         if (!opt_verbose) {
44                 return;
45         }
46
47         va_start(args, format);
48         if ((vasprintf(&var, format, args)) == -1) {
49                 va_end(args);
50                 return;
51         }
52
53         fprintf(stdout, "%s", var);
54         va_end(args);
55         SAFE_FREE(var);
56 }
57
58 /********************************************************************
59 ********************************************************************/
60
61 static bool swap_sid_in_acl( struct security_descriptor *sd, struct dom_sid *s1, struct dom_sid *s2 )
62 {
63         struct security_acl *theacl;
64         int i;
65         bool update = False;
66
67         verbose_output("  Owner SID: %s\n", sid_string_tos(sd->owner_sid));
68         if ( dom_sid_equal( sd->owner_sid, s1 ) ) {
69                 sid_copy( sd->owner_sid, s2 );
70                 update = True;
71                 verbose_output("  New Owner SID: %s\n",
72                         sid_string_tos(sd->owner_sid));
73
74         }
75
76         verbose_output("  Group SID: %s\n", sid_string_tos(sd->group_sid));
77         if ( dom_sid_equal( sd->group_sid, s1 ) ) {
78                 sid_copy( sd->group_sid, s2 );
79                 update = True;
80                 verbose_output("  New Group SID: %s\n",
81                         sid_string_tos(sd->group_sid));
82         }
83
84         theacl = sd->dacl;
85         verbose_output("  DACL: %d entries:\n", theacl->num_aces);
86         for ( i=0; i<theacl->num_aces; i++ ) {
87                 verbose_output("    Trustee SID: %s\n",
88                         sid_string_tos(&theacl->aces[i].trustee));
89                 if ( dom_sid_equal( &theacl->aces[i].trustee, s1 ) ) {
90                         sid_copy( &theacl->aces[i].trustee, s2 );
91                         update = True;
92                         verbose_output("    New Trustee SID: %s\n",
93                                 sid_string_tos(&theacl->aces[i].trustee));
94                 }
95         }
96
97 #if 0
98         theacl = sd->sacl;
99         verbose_output("  SACL: %d entries: \n", theacl->num_aces);
100         for ( i=0; i<theacl->num_aces; i++ ) {
101                 verbose_output("    Trustee SID: %s\n",
102                         sid_string_tos(&theacl->aces[i].trustee));
103                 if ( dom_sid_equal( &theacl->aces[i].trustee, s1 ) ) {
104                         sid_copy( &theacl->aces[i].trustee, s2 );
105                         update = True;
106                         verbose_output("    New Trustee SID: %s\n",
107                                 sid_string_tos(&theacl->aces[i].trustee));
108                 }
109         }
110 #endif
111         return update;
112 }
113
114 /********************************************************************
115 ********************************************************************/
116
117 static bool copy_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk,
118                                 REGF_NK_REC *parent, REGF_FILE *outfile,
119                                 const char *parentpath  )
120 {
121         REGF_NK_REC *key, *subkey;
122         struct security_descriptor *new_sd;
123         struct regval_ctr *values;
124         struct regsubkey_ctr *subkeys;
125         int i;
126         char *path;
127         WERROR werr;
128
129         /* swap out the SIDs in the security descriptor */
130
131         if (nk->sec_desc->sec_desc == NULL) {
132                 fprintf(stderr, "Invalid (NULL) security descriptor!\n");
133                 return false;
134         }
135
136         new_sd = security_descriptor_copy(outfile->mem_ctx,
137                                           nk->sec_desc->sec_desc);
138         if (new_sd == NULL) {
139                 fprintf(stderr, "Failed to copy security descriptor!\n");
140                 return False;
141         }
142
143         verbose_output("ACL for %s%s%s\n", parentpath, parent ? "\\" : "", nk->keyname);
144         swap_sid_in_acl( new_sd, &old_sid, &new_sid );
145
146         werr = regsubkey_ctr_init(NULL, &subkeys);
147         if (!W_ERROR_IS_OK(werr)) {
148                 DEBUG(0,("copy_registry_tree: talloc() failure!\n"));
149                 return False;
150         }
151
152         werr = regval_ctr_init(subkeys, &values);
153         if (!W_ERROR_IS_OK(werr)) {
154                 TALLOC_FREE( subkeys );
155                 DEBUG(0,("copy_registry_tree: talloc() failure!\n"));
156                 return False;
157         }
158
159         /* copy values into the struct regval_ctr */
160
161         for ( i=0; i<nk->num_values; i++ ) {
162                 regval_ctr_addvalue( values, nk->values[i].valuename, nk->values[i].type,
163                         nk->values[i].data, (nk->values[i].data_size & ~VK_DATA_IN_OFFSET) );
164         }
165
166         /* copy subkeys into the struct regsubkey_ctr */
167
168         while ( (subkey = regfio_fetch_subkey( infile, nk )) ) {
169                 regsubkey_ctr_addkey( subkeys, subkey->keyname );
170         }
171
172         key = regfio_write_key( outfile, nk->keyname, values, subkeys, new_sd, parent );
173
174         /* write each one of the subkeys out */
175
176         path = talloc_asprintf(subkeys, "%s%s%s",
177                         parentpath, parent ? "\\" : "",nk->keyname);
178         if (!path) {
179                 TALLOC_FREE( subkeys );
180                 return false;
181         }
182
183         nk->subkey_index = 0;
184         while ((subkey = regfio_fetch_subkey(infile, nk))) {
185                 if (!copy_registry_tree( infile, subkey, key, outfile, path)) {
186                         TALLOC_FREE(subkeys);
187                         return false;
188                 }
189         }
190
191
192         verbose_output("[%s]\n", path);
193
194         /* values is a talloc()'d child of subkeys here so just throw it all away */
195         TALLOC_FREE(subkeys);
196
197         return True;
198 }
199 =======
200 #include "../librpc/gen_ndr/ndr_security.h"
201 >>>>>>> 1150460... profiles...
202
203 /*********************************************************************
204 *********************************************************************/
205
206 int main( int argc, const char *argv[] )
207 {
208         TALLOC_CTX *frame = talloc_stackframe();
209         int opt;
210         int change = 0, new_val = 0;
211         struct dom_sid old_sid, new_sid;
212         DATA_BLOB old_blob, new_blob;
213         enum ndr_err_code ndr_err;
214         char *orig_filename, *new_filename;
215         uint8_t *buf;
216         size_t len;
217         size_t ofs;
218         int opt_verbose = False;
219         struct poptOption long_options[] = {
220                 POPT_AUTOHELP
221                 { "change-sid", 'c', POPT_ARG_STRING, NULL, 'c', "Provides SID to change" },
222                 { "new-sid", 'n', POPT_ARG_STRING, NULL, 'n', "Provides SID to change to" },
223                 { "verbose", 'v', POPT_ARG_NONE, &opt_verbose, 'v', "Verbose output" },
224                 POPT_COMMON_SAMBA
225                 POPT_COMMON_VERSION
226                 POPT_TABLEEND
227         };
228         poptContext pc;
229
230         smb_init_locale();
231
232         /* setup logging options */
233
234         setup_logging( "profiles", DEBUG_STDERR);
235
236         pc = poptGetContext("profiles", argc, argv, long_options,
237                 POPT_CONTEXT_KEEP_FIRST);
238
239         poptSetOtherOptionHelp(pc, "<profilefile>");
240
241         ZERO_STRUCT(old_sid);
242         ZERO_STRUCT(new_sid);
243
244         /* Now, process the arguments */
245
246         while ((opt = poptGetNextOpt(pc)) != -1) {
247                 switch (opt) {
248                 case 'c':
249                         change = 1;
250                         if (!string_to_sid(&old_sid, poptGetOptArg(pc))) {
251                                 fprintf(stderr, "Argument to -c should be a SID in form of S-1-5-...\n");
252                                 poptPrintUsage(pc, stderr, 0);
253                                 exit(254);
254                         }
255                         break;
256
257                 case 'n':
258                         new_val = 1;
259                         if (!string_to_sid(&new_sid, poptGetOptArg(pc))) {
260                                 fprintf(stderr, "Argument to -n should be a SID in form of S-1-5-...\n");
261                                 poptPrintUsage(pc, stderr, 0);
262                                 exit(253);
263                         }
264                         break;
265
266                 }
267         }
268
269         poptGetArg(pc);
270
271         if (!poptPeekArg(pc)) {
272                 poptPrintUsage(pc, stderr, 0);
273                 exit(1);
274         }
275
276         if (!change || !new_val) {
277                 fprintf(stderr, "You must specify both -c and -n if one or the other is set!\n");
278                 poptPrintUsage(pc, stderr, 0);
279                 exit(252);
280         }
281
282         orig_filename = talloc_strdup(frame, poptPeekArg(pc));
283         if (!orig_filename) {
284                 exit(ENOMEM);
285         }
286         new_filename = talloc_asprintf(frame,
287                                         "%s.new",
288                                         orig_filename);
289         if (!new_filename) {
290                 exit(ENOMEM);
291         }
292
293         buf = (uint8_t *)file_load(orig_filename, &len, UINT32_MAX, frame);
294         if (buf == NULL) {
295                 fprintf( stderr, "Failed to open %s!\n", orig_filename );
296                 fprintf( stderr, "Error was (%s)\n", strerror(errno) );
297                 exit (1);
298         }
299
300         ndr_err = ndr_push_struct_blob(&old_blob, frame, &old_sid,
301                         (ndr_push_flags_fn_t) ndr_push_dom_sid);
302         SMB_ASSERT(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
303
304         ndr_err = ndr_push_struct_blob(&new_blob, frame, &new_sid,
305                         (ndr_push_flags_fn_t) ndr_push_dom_sid);
306         SMB_ASSERT(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
307
308         if (new_blob.length > old_blob.length) {
309                 fprintf(stderr, "New SID[%s][%u] is longer than old SID[%s][%u]]\n",
310                         sid_string_dbg(&new_sid), (unsigned)new_blob.length,
311                         sid_string_dbg(&old_sid), (unsigned)old_blob.length);
312                 exit (1);
313         }
314
315         if (new_blob.length < old_blob.length) {
316                 static const uint8_t pad[1024];
317                 size_t pad_len = old_blob.length - new_blob.length;
318                 SMB_ASSERT(pad_len <= sizeof(pad));
319                 data_blob_append(frame, &new_blob, pad, pad_len);
320         }
321
322         SMB_ASSERT(new_blob.length == old_blob.length);
323
324         for (ofs=0; ofs < len;) {
325                 uint8_t *p = &buf[ofs];
326                 size_t remaining = len - ofs;
327                 int cmp;
328
329                 if (remaining < old_blob.length) {
330                         break;
331                 }
332
333                 cmp = memcmp(p, old_blob.data, old_blob.length);
334                 if (cmp != 0) {
335                         ofs += 1;
336                         continue;
337                 }
338
339                 if (opt_verbose) {
340                         fprintf(stdout, "replace at ofs[%u]\n", (unsigned)ofs);
341                 }
342
343                 memcpy(p, new_blob.data, new_blob.length);
344                 ofs += new_blob.length;
345         }
346
347         file_save(new_filename, buf, len);
348
349         poptFreeContext(pc);
350
351         TALLOC_FREE(frame);
352         return 0;
353 }