build: reduce printf() calls in generated build_options.c
[samba.git] / testprogs / win32 / prepare_dcpromo / prepare_dcpromo.c
1 /*
2    Copyright (C) Stefan Metzmacher <metze@samba.org> 2010
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.
16    Published to the public domain
17  */
18
19 /*
20  * This tool can set the DOMAIN-SID and nextRid counter in
21  * the local SAM on windows servers (tested with w2k8r2)
22  *
23  * dcpromo will use this values for the ad domain it creates.
24  *
25  * This might be useful for upgrades from a Samba3 domain.
26  */
27
28 #include <windows.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32
33 /* Convert a binary SID to a character string */
34 static DWORD SidToString(const SID *sid,
35                          char **string)
36 {
37         DWORD id_auth;
38         int i, ofs, maxlen;
39         char *result;
40
41         if (!sid) {
42                 return ERROR_INVALID_SID;
43         }
44
45         maxlen = sid->SubAuthorityCount * 11 + 25;
46
47         result = (char *)malloc(maxlen);
48         if (result == NULL) {
49                 return ERROR_NOT_ENOUGH_MEMORY;
50         }
51
52         /*
53          * BIG NOTE: this function only does SIDS where the identauth is not
54          * >= ^32 in a range of 2^48.
55          */
56
57         id_auth = sid->IdentifierAuthority.Value[5] +
58                 (sid->IdentifierAuthority.Value[4] << 8) +
59                 (sid->IdentifierAuthority.Value[3] << 16) +
60                 (sid->IdentifierAuthority.Value[2] << 24);
61
62         ofs = snprintf(result, maxlen, "S-%u-%lu",
63                        (unsigned int)sid->Revision, (unsigned long)id_auth);
64
65         for (i = 0; i < sid->SubAuthorityCount; i++) {
66                 ofs += snprintf(result + ofs, maxlen - ofs, "-%lu",
67                                 (unsigned long)sid->SubAuthority[i]);
68         }
69
70         *string = result;
71         return ERROR_SUCCESS;
72 }
73
74 static DWORD StringToSid(const char *str,
75                          SID *sid)
76 {
77         const char *p;
78         char *q;
79         DWORD x;
80
81         if (!sid) {
82                 return ERROR_INVALID_PARAMETER;
83         }
84
85         /* Sanity check for either "S-" or "s-" */
86
87         if (!str
88             || (str[0]!='S' && str[0]!='s')
89             || (str[1]!='-'))
90         {
91                 return ERROR_INVALID_PARAMETER;
92         }
93
94         /* Get the SID revision number */
95
96         p = str+2;
97         x = (DWORD)strtol(p, &q, 10);
98         if (x==0 || !q || *q!='-') {
99                 return ERROR_INVALID_SID;
100         }
101         sid->Revision = (BYTE)x;
102
103         /* Next the Identifier Authority.  This is stored in big-endian
104            in a 6 byte array. */
105
106         p = q+1;
107         x = (DWORD)strtol(p, &q, 10);
108         if (!q || *q!='-') {
109                 return ERROR_INVALID_SID;
110         }
111         sid->IdentifierAuthority.Value[5] = (x & 0x000000ff);
112         sid->IdentifierAuthority.Value[4] = (x & 0x0000ff00) >> 8;
113         sid->IdentifierAuthority.Value[3] = (x & 0x00ff0000) >> 16;
114         sid->IdentifierAuthority.Value[2] = (x & 0xff000000) >> 24;
115         sid->IdentifierAuthority.Value[1] = 0;
116         sid->IdentifierAuthority.Value[0] = 0;
117
118         /* now read the the subauthorities */
119
120         p = q +1;
121         sid->SubAuthorityCount = 0;
122         while (sid->SubAuthorityCount < 6) {
123                 x=(DWORD)strtoul(p, &q, 10);
124                 if (p == q)
125                         break;
126                 if (q == NULL) {
127                         return ERROR_INVALID_SID;
128                 }
129                 sid->SubAuthority[sid->SubAuthorityCount++] = x;
130
131                 if ((*q!='-') || (*q=='\0'))
132                         break;
133                 p = q + 1;
134         }
135
136         /* IF we ended early, then the SID could not be converted */
137
138         if (q && *q!='\0') {
139                 return ERROR_INVALID_SID;
140         }
141
142         return ERROR_SUCCESS;
143 }
144
145 #define MIN(a,b) ((a)<(b)?(a):(b))
146 static void print_asc(const unsigned char *buf,int len)
147 {
148         int i;
149         for (i=0;i<len;i++)
150                 printf("%c", isprint(buf[i])?buf[i]:'.');
151 }
152
153 static void dump_data(const unsigned char *buf1,int len)
154 {
155         const unsigned char *buf = (const unsigned char *)buf1;
156         int i=0;
157         if (len<=0) return;
158
159         printf("[%03X] ",i);
160         for (i=0;i<len;) {
161                 printf("%02X ",(int)buf[i]);
162                 i++;
163                 if (i%8 == 0) printf(" ");
164                 if (i%16 == 0) {
165                         print_asc(&buf[i-16],8); printf(" ");
166                         print_asc(&buf[i-8],8); printf("\n");
167                         if (i<len) printf("[%03X] ",i);
168                 }
169         }
170         if (i%16) {
171                 int n;
172                 n = 16 - (i%16);
173                 printf(" ");
174                 if (n>8) printf(" ");
175                 while (n--) printf("   ");
176                 n = MIN(8,i%16);
177                 print_asc(&buf[i-(i%16)],n); printf( " " );
178                 n = (i%16) - n;
179                 if (n>0) print_asc(&buf[i-n],n);
180                 printf("\n");
181         }
182 }
183
184 static DWORD calc_tmp_HKLM_SECURITY_SD(SECURITY_DESCRIPTOR *old_sd,
185                                        SID *current_user_sid,
186                                        SECURITY_DESCRIPTOR **_old_parent_sd,
187                                        SECURITY_DESCRIPTOR **_old_child_sd,
188                                        SECURITY_DESCRIPTOR **_new_parent_sd,
189                                        SECURITY_DESCRIPTOR **_new_child_sd)
190 {
191         LONG status;
192         DWORD cbSecurityDescriptor = 0;
193         SECURITY_DESCRIPTOR *old_parent_sd = NULL;
194         SECURITY_DESCRIPTOR *old_child_sd = NULL;
195         SECURITY_DESCRIPTOR *new_parent_sd = NULL;
196         SECURITY_DESCRIPTOR *new_child_sd = NULL;
197         BOOL ok;
198         ACL *old_Dacl = NULL;
199         ACL *new_Dacl = NULL;
200         ACL_SIZE_INFORMATION dacl_info;
201         DWORD i = 0;
202         SECURITY_DESCRIPTOR *AbsoluteSD = NULL;
203         DWORD dwAbsoluteSDSize = 0;
204         DWORD dwRelativeSDSize = 0;
205         DWORD dwDaclSize = 0;
206         ACL *Sacl = NULL;
207         DWORD dwSaclSize = 0;
208         SID *Owner = NULL;
209         DWORD dwOwnerSize = 0;
210         SID *PrimaryGroup = NULL;
211         DWORD dwPrimaryGroupSize = 0;
212         ACCESS_ALLOWED_ACE *ace = NULL;
213
214         ok = MakeAbsoluteSD(old_sd,
215                             NULL,
216                             &dwAbsoluteSDSize,
217                             NULL,
218                             &dwDaclSize,
219                             NULL,
220                             &dwSaclSize,
221                             NULL,
222                             &dwOwnerSize,
223                             NULL,
224                             &dwPrimaryGroupSize);
225         if (!ok) {
226                 status = GetLastError();
227         }
228         if (status != ERROR_INSUFFICIENT_BUFFER) {
229                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
230                 return status;
231         }
232
233         AbsoluteSD = (SECURITY_DESCRIPTOR *)malloc(dwAbsoluteSDSize+1024);
234         if (AbsoluteSD == NULL) {
235                 printf("LINE:%u: Error: no memory\n", __LINE__);
236                 return ERROR_NOT_ENOUGH_MEMORY;
237         }
238         old_Dacl = (ACL *)malloc(dwDaclSize + 1024);
239         if (old_Dacl == NULL) {
240                 printf("LINE:%u: Error: no memory\n", __LINE__);
241                 return ERROR_NOT_ENOUGH_MEMORY;
242         }
243         Sacl = (ACL *)malloc(dwSaclSize);
244         if (Sacl == NULL) {
245                 printf("LINE:%u: Error: no memory\n", __LINE__);
246                 return ERROR_NOT_ENOUGH_MEMORY;
247         }
248         Owner = (SID *)malloc(dwOwnerSize);
249         if (Owner == NULL) {
250                 printf("LINE:%u: Error: no memory\n", __LINE__);
251                 return ERROR_NOT_ENOUGH_MEMORY;
252         }
253         PrimaryGroup = (SID *)malloc(dwPrimaryGroupSize);
254         if (PrimaryGroup == NULL) {
255                 printf("LINE:%u: Error: no memory\n", __LINE__);
256                 return ERROR_NOT_ENOUGH_MEMORY;
257         }
258
259         ok = MakeAbsoluteSD(old_sd,
260                             AbsoluteSD,
261                             &dwAbsoluteSDSize,
262                             old_Dacl,
263                             &dwDaclSize,
264                             Sacl,
265                             &dwSaclSize,
266                             Owner,
267                             &dwOwnerSize,
268                             PrimaryGroup,
269                             &dwPrimaryGroupSize);
270         if (!ok) {
271                 status = GetLastError();
272                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
273                 return status;
274         }
275
276         AbsoluteSD->Control |= SE_DACL_AUTO_INHERITED | SE_DACL_AUTO_INHERIT_REQ | SE_DACL_PROTECTED;
277         dwRelativeSDSize = 0;
278         ok = MakeSelfRelativeSD(AbsoluteSD,
279                                 NULL,
280                                 &dwRelativeSDSize);
281         if (!ok) {
282                 status = GetLastError();
283         }
284         if (status != ERROR_INSUFFICIENT_BUFFER) {
285                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
286                 return ERROR_NOT_ENOUGH_MEMORY;
287         }
288
289         old_parent_sd = (SECURITY_DESCRIPTOR *)malloc(dwRelativeSDSize);
290         if (old_parent_sd == NULL) {
291                 printf("LINE:%u: Error: no memory\n", __LINE__);
292                 return ERROR_NOT_ENOUGH_MEMORY;
293         }
294
295         ok = MakeSelfRelativeSD(AbsoluteSD,
296                                 old_parent_sd,
297                                 &dwRelativeSDSize);
298         if (!ok) {
299                 status = GetLastError();
300                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
301                 return status;
302         }
303
304         ok = GetAclInformation(old_Dacl,
305                                &dacl_info,
306                                sizeof(dacl_info),
307                                AclSizeInformation);
308         if (!ok) {
309                 status = GetLastError();
310                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
311                 return status;
312         }
313
314         new_Dacl = (ACL *)calloc(dacl_info.AclBytesInUse + 1024, 1);
315         if (new_Dacl == NULL) {
316                 printf("LINE:%u: Error: no memory\n", __LINE__);
317                 return ERROR_NOT_ENOUGH_MEMORY;
318         }
319
320         InitializeAcl(new_Dacl, dacl_info.AclBytesInUse + 1024, ACL_REVISION);
321
322         ok = AddAccessAllowedAce(new_Dacl, ACL_REVISION,
323                                  KEY_ALL_ACCESS, current_user_sid);
324         if (!ok) {
325                 status = GetLastError();
326                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
327                 return status;
328         }
329
330         ok = GetAce(new_Dacl, 0, (LPVOID *)&ace);
331         if (!ok) {
332                 status = GetLastError();
333                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
334                 return status;
335         }
336
337         ace->Header.AceFlags |= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
338
339         for (i=0; i < dacl_info.AceCount; i++) {
340                 ok = GetAce(old_Dacl, i, (LPVOID *)&ace);
341                 if (!ok) {
342                         status = GetLastError();
343                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
344                         return status;
345                 }
346
347                 ok = AddAce(new_Dacl, ACL_REVISION, MAXDWORD,
348                             ace, ace->Header.AceSize);
349                 if (!ok) {
350                         status = GetLastError();
351                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
352                         return status;
353                 }
354         }
355
356         AbsoluteSD->Dacl = new_Dacl;
357         dwRelativeSDSize = 0;
358         ok = MakeSelfRelativeSD(AbsoluteSD,
359                                 NULL,
360                                 &dwRelativeSDSize);
361         if (!ok) {
362                 status = GetLastError();
363         }
364         if (status != ERROR_INSUFFICIENT_BUFFER) {
365                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
366                 return ERROR_NOT_ENOUGH_MEMORY;
367         }
368
369         new_parent_sd = (SECURITY_DESCRIPTOR *)malloc(dwRelativeSDSize);
370         if (new_parent_sd == NULL) {
371                 printf("LINE:%u: Error: no memory\n", __LINE__);
372                 return ERROR_NOT_ENOUGH_MEMORY;
373         }
374
375         ok = MakeSelfRelativeSD(AbsoluteSD,
376                                 new_parent_sd,
377                                 &dwRelativeSDSize);
378         if (!ok) {
379                 status = GetLastError();
380                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
381                 return status;
382         }
383
384         for (i=0; i < dacl_info.AceCount; i++) {
385                 ok = GetAce(old_Dacl, i, (LPVOID *)&ace);
386                 if (!ok) {
387                         status = GetLastError();
388                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
389                         return status;
390                 }
391
392                 ace->Header.AceFlags |= INHERITED_ACE;
393         }
394
395         AbsoluteSD->Control &= ~SE_DACL_PROTECTED;
396         AbsoluteSD->Dacl = old_Dacl;
397         dwRelativeSDSize = 0;
398         ok = MakeSelfRelativeSD(AbsoluteSD,
399                                 NULL,
400                                 &dwRelativeSDSize);
401         if (!ok) {
402                 status = GetLastError();
403         }
404         if (status != ERROR_INSUFFICIENT_BUFFER) {
405                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
406                 return ERROR_NOT_ENOUGH_MEMORY;
407         }
408
409         old_child_sd = (SECURITY_DESCRIPTOR *)malloc(dwRelativeSDSize);
410         if (old_child_sd == NULL) {
411                 printf("LINE:%u: Error: no memory\n", __LINE__);
412                 return ERROR_NOT_ENOUGH_MEMORY;
413         }
414
415         ok = MakeSelfRelativeSD(AbsoluteSD,
416                                 old_child_sd,
417                                 &dwRelativeSDSize);
418         if (!ok) {
419                 status = GetLastError();
420                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
421                 return status;
422         }
423
424         for (i=0; i < dacl_info.AceCount + 1; i++) {
425                 ok = GetAce(new_Dacl, i, (LPVOID *)&ace);
426                 if (!ok) {
427                         status = GetLastError();
428                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
429                         return status;
430                 }
431
432                 ace->Header.AceFlags |= INHERITED_ACE;
433         }
434
435         AbsoluteSD->Dacl = new_Dacl;
436         dwRelativeSDSize = 0;
437         ok = MakeSelfRelativeSD(AbsoluteSD,
438                                 NULL,
439                                 &dwRelativeSDSize);
440         if (!ok) {
441                 status = GetLastError();
442         }
443         if (status != ERROR_INSUFFICIENT_BUFFER) {
444                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
445                 return ERROR_NOT_ENOUGH_MEMORY;
446         }
447
448         new_child_sd = (SECURITY_DESCRIPTOR *)malloc(dwRelativeSDSize);
449         if (new_child_sd == NULL) {
450                 printf("LINE:%u: Error: no memory\n", __LINE__);
451                 return ERROR_NOT_ENOUGH_MEMORY;
452         }
453
454         ok = MakeSelfRelativeSD(AbsoluteSD,
455                                 new_child_sd,
456                                 &dwRelativeSDSize);
457         if (!ok) {
458                 status = GetLastError();
459                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
460                 return status;
461         }
462
463         *_old_parent_sd = old_parent_sd;
464         *_old_child_sd = old_child_sd;
465         *_new_parent_sd = new_parent_sd;
466         *_new_child_sd = new_child_sd;
467         return ERROR_SUCCESS;
468 }
469
470 static DWORD inherit_SD(HKEY parent_hk,
471                         char *current_key,
472                         BOOL reset,
473                         SECURITY_DESCRIPTOR *current_sd,
474                         SECURITY_DESCRIPTOR *child_sd)
475 {
476         DWORD status;
477         DWORD i = 0;
478         HKEY current_hk;
479
480         if (!reset) {
481                 status = RegOpenKeyEx(parent_hk,
482                                       current_key,
483                                       0, /* options */
484                                       WRITE_DAC, /* samDesired */
485                                       &current_hk);
486                 if (status != ERROR_SUCCESS) {
487                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
488                         return status;
489                 }
490
491                 status = RegSetKeySecurity(current_hk,
492                                            DACL_SECURITY_INFORMATION |
493                                            PROTECTED_DACL_SECURITY_INFORMATION |
494                                            UNPROTECTED_DACL_SECURITY_INFORMATION |
495                                            UNPROTECTED_SACL_SECURITY_INFORMATION,
496                                            current_sd /* pSecurityDescriptor */
497                                            );
498                 if (status != ERROR_SUCCESS) {
499                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
500                         return status;
501                 }
502
503                 RegCloseKey(current_hk);
504         }
505
506         status = RegOpenKeyEx(parent_hk,
507                               current_key,
508                               0, /* options */
509                               KEY_ENUMERATE_SUB_KEYS, /* samDesired */
510                               &current_hk);
511         if (status != ERROR_SUCCESS) {
512                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
513                 return status;
514         }
515
516         for (i=0; ; i++) {
517                 char subkey[10240];
518                 HKEY hk_child;
519
520                 memset(subkey, 0, sizeof(subkey));
521                 status = RegEnumKey(current_hk, i, subkey, sizeof(subkey));
522                 if (status == ERROR_NO_MORE_ITEMS) {
523                         break;
524                 }
525                 if (status != ERROR_SUCCESS) {
526                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
527                         return status;
528                 }
529
530 #if 0
531                 printf("subkey: %s\n", subkey);
532 #endif
533
534                 status = inherit_SD(current_hk, subkey, reset,
535                                     child_sd, child_sd);
536                 if (status != ERROR_SUCCESS) {
537                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
538                         return status;
539                 }
540         }
541
542         RegCloseKey(current_hk);
543
544         if (reset) {
545                 status = RegOpenKeyEx(parent_hk,
546                                       current_key,
547                                       0, /* options */
548                                       WRITE_DAC, /* samDesired */
549                                       &current_hk);
550                 if (status != ERROR_SUCCESS) {
551                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
552                         return status;
553                 }
554
555                 status = RegSetKeySecurity(current_hk,
556                                            DACL_SECURITY_INFORMATION |
557                                            PROTECTED_DACL_SECURITY_INFORMATION |
558                                            UNPROTECTED_DACL_SECURITY_INFORMATION |
559                                            UNPROTECTED_SACL_SECURITY_INFORMATION,
560                                            current_sd /* pSecurityDescriptor */
561                                            );
562                 if (status != ERROR_SUCCESS) {
563                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
564                         return status;
565                 }
566
567                 RegCloseKey(current_hk);
568         }
569
570         return ERROR_SUCCESS;
571 }
572
573 static DWORD replaceSIDBuffer(BYTE *buf, DWORD len,
574                               SID *oldDomainSid,
575                               SID *newDomainSid)
576 {
577         DWORD ret = 0;
578         BYTE *oldb = ((BYTE *)oldDomainSid)+2;
579         BYTE *newb = ((BYTE *)newDomainSid)+2;
580         int cmp;
581
582 #if 0
583         printf("replaceSIDBuffer: %u\n", len);
584         dump_data(buf, len);
585 #endif
586
587         if (len < 24) {
588                 return 0;
589         }
590
591         if (buf[0] != SID_REVISION) {
592                 return 0;
593         }
594
595         switch (buf[1]) {
596         case 4:
597                 ret = 24;
598                 break;
599         case 5:
600                 if (len < 28) {
601                         return 0;
602                 }
603                 ret = 28;
604                 break;
605         default:
606                 return 0;
607         }
608
609 #if 0
610         printf("oldb:\n");
611         dump_data(oldb, 22);
612 #endif
613         cmp = memcmp(&buf[2], oldb, 22);
614         if (cmp != 0) {
615                 return 0;
616         }
617
618         memcpy(&buf[2], newb, 22);
619
620         return ret;
621 }
622
623 static DWORD replaceSID(HKEY parent_hk,
624                         const char *parent_path,
625                         const char *current_key,
626                         SID *oldDomainSid,
627                         SID *newDomainSid)
628 {
629         DWORD status;
630         DWORD i = 0;
631         HKEY current_hk;
632         char current_path[10240];
633
634         snprintf(current_path, sizeof(current_path), "%s\\%s",
635                  parent_path, current_key);
636
637         status = RegOpenKeyEx(parent_hk,
638                               current_key,
639                               0, /* options */
640                               KEY_ALL_ACCESS, /* samDesired */
641                               &current_hk);
642         if (status != ERROR_SUCCESS) {
643                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
644                 return status;
645         }
646
647         for (i=0; ; i++) {
648                 char subkey[10240];
649                 HKEY hk_child;
650
651                 memset(subkey, 0, sizeof(subkey));
652                 status = RegEnumKey(current_hk, i, subkey, sizeof(subkey));
653                 if (status == ERROR_NO_MORE_ITEMS) {
654                         break;
655                 }
656                 if (status != ERROR_SUCCESS) {
657                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
658                         return status;
659                 }
660
661 #if 0
662                 printf("subkey: %s\n", subkey);
663 #endif
664
665                 status = replaceSID(current_hk, current_path, subkey,
666                                     oldDomainSid, newDomainSid);
667                 if (status != ERROR_SUCCESS) {
668                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
669                         return status;
670                 }
671         }
672
673         for (i=0; ; i++) {
674                 char valueName[10240];
675                 DWORD cbValueName;
676                 DWORD valueType = 0;
677                 BYTE *valueData = NULL;
678                 DWORD cbValueData = 0;
679                 DWORD ofs = 0;
680                 BOOL modified = FALSE;
681
682                 memset(valueName, 0, sizeof(valueName));
683                 cbValueName = sizeof(valueName)-1;
684                 status = RegEnumValue(current_hk, i,
685                                       valueName, &cbValueName,
686                                       NULL, NULL,
687                                       NULL, &cbValueData);
688                 if (status == ERROR_NO_MORE_ITEMS) {
689                         break;
690                 }
691                 if (status != ERROR_SUCCESS) {
692                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
693                         return status;
694                 }
695
696                 valueData = (BYTE *)malloc(cbValueData);
697                 if (valueData == NULL) {
698                         printf("LINE:%u: Error: no memory\n", __LINE__);
699                         return ERROR_NOT_ENOUGH_MEMORY;
700                 }
701
702                 cbValueName = sizeof(valueName)-1;
703                 status = RegEnumValue(current_hk, i,
704                                       valueName, &cbValueName,
705                                       NULL, &valueType,
706                                       valueData, &cbValueData);
707                 if (status != ERROR_SUCCESS) {
708                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
709                         return status;
710                 }
711
712                 if (valueType != REG_BINARY) {
713                         free(valueData);
714                         continue;
715                 }
716
717                 for (ofs=0; ofs < cbValueData;) {
718                         DWORD len;
719
720                         len = replaceSIDBuffer(valueData + ofs,
721                                                cbValueData - ofs,
722                                                oldDomainSid,
723                                                newDomainSid);
724                         if (len == 0) {
725                                 ofs += 4;
726                                 continue;
727                         }
728
729 #if 0
730                         printf("%s value[%u]:%s modified ofs:%u (0x%X) len:%u\n",
731                                 current_path, i, valueName, ofs, ofs, len);
732 #endif
733
734                         ofs += len;
735                         modified = TRUE;
736                 }
737
738                 if (!modified) {
739                         free(valueData);
740                         continue;
741                 }
742
743                 printf("%s value[%u]:%s replacing data\n",
744                         current_path, i, valueName);
745                 status = RegSetValueEx(current_hk,
746                                        valueName,
747                                        0,
748                                        valueType,
749                                        valueData,
750                                        cbValueData);
751                 if (status != ERROR_SUCCESS) {
752                         printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
753                         return status;
754                 }
755
756                 free(valueData);
757         }
758
759         RegCloseKey(current_hk);
760
761         return ERROR_SUCCESS;
762 }
763
764 int main(int argc, char *argv[])
765 {
766         LONG status;
767         HANDLE tokenHandle = NULL;
768         TOKEN_USER *tokenUser = NULL;
769         DWORD cbTokenUser = 0;
770         HKEY hklm;
771         HKEY hk_security;
772         HKEY hk_account_domain;
773         DWORD cbSecurityDescriptor = 0;
774         SECURITY_DESCRIPTOR *security_old_sd = NULL;
775         SECURITY_DESCRIPTOR *security_parent_old_sd = NULL;
776         SECURITY_DESCRIPTOR *security_child_old_sd = NULL;
777         SECURITY_DESCRIPTOR *security_parent_new_sd = NULL;
778         SECURITY_DESCRIPTOR *security_child_new_sd = NULL;
779         SID *currentUserSid = NULL;
780         char *currentUserSidString = NULL;
781         BOOL ok;
782         DWORD cbTmp = 0;
783         BYTE *AccountDomainF = NULL;
784         DWORD cbAccountDomainF = 0;
785         DWORD AccountDomainFType = 0;
786         DWORD *nextRid = NULL;
787         DWORD oldNextRid = 0;
788         DWORD newNextRid = 0;
789         BYTE *AccountDomainV = NULL;
790         DWORD cbAccountDomainV = 0;
791         SID *oldDomainSid = NULL;
792         char *oldDomainSidString = NULL;
793         SID *newDomainSid = NULL;
794         const char *newDomainSidString = NULL;
795
796         if (argc < 2 || argc > 3) {
797                 printf("Usage: %s <DOMAINSID> [<NEXTRID>]\n", argv[0]);
798                 return -1;
799         }
800
801         newDomainSidString = argv[1];
802
803         newDomainSid = (SID *)malloc(24);
804         if (newDomainSid == NULL) {
805                 printf("LINE:%u: Error: no memory\n", __LINE__);
806                 return -1;
807         }
808
809         status = StringToSid(newDomainSidString, newDomainSid);
810         if (status != ERROR_SUCCESS) {
811                 printf("Failed to parse DOMAINSID[%s]: Error: %d (0x%X)\n",
812                         newDomainSidString, status, status);
813                 return -1;
814         }
815         if (newDomainSid->SubAuthorityCount != 4) {
816                 printf("DOMAINSID[%s]: Invalid SubAuthorityCount[%u] should be 4\n",
817                         newDomainSidString, newDomainSid->SubAuthorityCount);
818                 return -1;
819         }
820
821         if (argc == 3) {
822                 char *q = NULL;
823                 newNextRid = (DWORD)strtoul(argv[2], &q, 10);
824                 if (newNextRid == 0 || newNextRid == 0xFFFFFFFF || !q || *q!='\0') {
825                         printf("Invalid newNextRid[%s]\n", argv[2]);
826                         return -1;
827                 }
828                 if (newNextRid < 1000) {
829                         printf("newNextRid[%u] < 1000\n", newNextRid);
830                         return -1;
831                 }
832         }
833
834         ok = OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &tokenHandle);
835         if (!ok) {
836                 status = GetLastError();
837                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
838                 return status;
839         }
840
841         ok = GetTokenInformation(tokenHandle, TokenUser,
842                                  NULL, 0, &cbTokenUser);
843         if (!ok) {
844                 status = GetLastError();
845         }
846         if (status != ERROR_INSUFFICIENT_BUFFER) {
847                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
848                 return status;
849         }
850
851         tokenUser = (TOKEN_USER *)malloc(cbTokenUser);
852         if (tokenUser == NULL) {
853                 printf("LINE:%u: Error: no memory\n", __LINE__);
854                 return -1;
855         }
856
857         ok = GetTokenInformation(tokenHandle, TokenUser,
858                                  tokenUser, cbTokenUser, &cbTokenUser);
859         if (!ok) {
860                 status = GetLastError();
861                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
862                 return status;
863         }
864
865         currentUserSid = tokenUser->User.Sid;
866
867         status = SidToString(currentUserSid, &currentUserSidString);
868         if (status != ERROR_SUCCESS) {
869                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
870                 return -1;
871         }
872
873         status = RegConnectRegistry(NULL, HKEY_LOCAL_MACHINE, &hklm);
874         if (status != ERROR_SUCCESS) {
875                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
876                 return -1;
877         }
878
879         status = RegOpenKeyEx(hklm, "SECURITY",
880                               0, /* options */
881                               READ_CONTROL, /* samDesired */
882                               &hk_security);
883         if (status != ERROR_SUCCESS) {
884                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
885                 return -1;
886         }
887
888         status = RegGetKeySecurity(hk_security,
889                                    OWNER_SECURITY_INFORMATION |
890                                    GROUP_SECURITY_INFORMATION |
891                                    DACL_SECURITY_INFORMATION |
892                                    PROTECTED_DACL_SECURITY_INFORMATION |
893                                    UNPROTECTED_DACL_SECURITY_INFORMATION |
894                                    UNPROTECTED_SACL_SECURITY_INFORMATION,
895                                    NULL, /* pSecurityDescriptor */
896                                    &cbSecurityDescriptor /* lpcbSecurityDescriptor */
897                                    );
898         if (status != ERROR_INSUFFICIENT_BUFFER) {
899                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
900                 return -1;
901         }
902
903         security_old_sd = (SECURITY_DESCRIPTOR *)malloc(cbSecurityDescriptor);
904         if (security_old_sd == NULL) {
905                 printf("LINE:%u: Error: no memory\n", __LINE__);
906                 return -1;
907         }
908
909         status = RegGetKeySecurity(hk_security,
910                                    OWNER_SECURITY_INFORMATION |
911                                    GROUP_SECURITY_INFORMATION |
912                                    DACL_SECURITY_INFORMATION |
913                                    PROTECTED_DACL_SECURITY_INFORMATION |
914                                    UNPROTECTED_DACL_SECURITY_INFORMATION |
915                                    UNPROTECTED_SACL_SECURITY_INFORMATION,
916                                    security_old_sd, /* pSecurityDescriptor */
917                                    &cbSecurityDescriptor /* lpcbSecurityDescriptor */
918                                    );
919         if (status != ERROR_SUCCESS) {
920                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
921                 return -1;
922         }
923
924         RegCloseKey(hk_security);
925
926         printf("currentUserSid: %s\n", currentUserSidString);
927
928         status = calc_tmp_HKLM_SECURITY_SD(security_old_sd,
929                                            currentUserSid,
930                                            &security_parent_old_sd,
931                                            &security_child_old_sd,
932                                            &security_parent_new_sd,
933                                            &security_child_new_sd);
934         if (status != ERROR_SUCCESS) {
935                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
936                 return -1;
937         }
938
939         printf("Grant full access to HKLM\\SECURITY\n");
940         status = inherit_SD(hklm, "SECURITY", FALSE,
941                             security_parent_new_sd, security_child_new_sd);
942         if (status != ERROR_SUCCESS) {
943                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
944                 return -1;
945         }
946
947         status = RegOpenKeyEx(hklm, "SECURITY\\SAM\\Domains\\Account",
948                               0, /* options */
949                               KEY_ALL_ACCESS, /* samDesired */
950                               &hk_account_domain);
951         if (status != ERROR_SUCCESS) {
952                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
953                 return -1;
954         }
955
956         status = RegQueryValueEx(hk_account_domain,
957                                  "F", NULL, NULL,
958                                  NULL,
959                                  &cbAccountDomainF);
960         if (status != ERROR_SUCCESS) {
961                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
962                 return -1;
963         }
964
965         AccountDomainF = (BYTE *)malloc(cbAccountDomainF);
966         if (AccountDomainF == NULL) {
967                 printf("LINE:%u: Error: no memory\n", __LINE__);
968                 return -1;
969         }
970
971         status = RegQueryValueEx(hk_account_domain,
972                                  "F", NULL, NULL,
973                                  AccountDomainF,
974                                  &cbAccountDomainF);
975         if (status != ERROR_SUCCESS) {
976                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
977                 return -1;
978         }
979
980         nextRid = (DWORD *)((BYTE *)AccountDomainF + 0x48);
981         oldNextRid = *nextRid;
982         if (newNextRid == 0) {
983                 newNextRid = oldNextRid;
984         }
985         printf("AccountDomainF: %u bytes\n", cbAccountDomainF);
986
987         status = RegQueryValueEx(hk_account_domain,
988                                  "V", NULL, NULL,
989                                  NULL,
990                                  &cbAccountDomainV);
991         if (status != ERROR_SUCCESS) {
992                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
993                 return -1;
994         }
995
996         AccountDomainV = (BYTE *)malloc(cbAccountDomainV);
997         if (AccountDomainV == NULL) {
998                 printf("LINE:%u: Error: no memory\n", __LINE__);
999                 return -1;
1000         }
1001
1002         status = RegQueryValueEx(hk_account_domain,
1003                                  "V", NULL, NULL,
1004                                  AccountDomainV,
1005                                  &cbAccountDomainV);
1006         if (status != ERROR_SUCCESS) {
1007                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
1008                 return -1;
1009         }
1010
1011         printf("AccountDomainV: %u bytes\n", cbAccountDomainV);
1012         oldDomainSid = (SID *)((BYTE *)AccountDomainV + (cbAccountDomainV - 24));
1013
1014         status = SidToString(oldDomainSid, &oldDomainSidString);
1015         if (status != ERROR_SUCCESS) {
1016                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
1017                 return -1;
1018         }
1019
1020         printf("Old Domain:%s, NextRid: %u (0x%08X)\n",
1021                 oldDomainSidString, oldNextRid, oldNextRid);
1022         printf("New Domain:%s, NextRid: %u (0x%08X)\n",
1023                 newDomainSidString, newNextRid, newNextRid);
1024
1025         status = replaceSID(hklm, "HKLM", "SECURITY\\SAM\\Domains",
1026                             oldDomainSid, newDomainSid);
1027         if (status != ERROR_SUCCESS) {
1028                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
1029                 goto failed;
1030         }
1031
1032         status = RegQueryValueEx(hk_account_domain,
1033                                  "F", NULL, &AccountDomainFType,
1034                                  AccountDomainF,
1035                                  &cbAccountDomainF);
1036         if (status != ERROR_SUCCESS) {
1037                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
1038                 return -1;
1039         }
1040         nextRid = (DWORD *)((BYTE *)AccountDomainF + 0x48);
1041         *nextRid = newNextRid;
1042
1043         printf("AccountDomainF replacing data (nextRid)\n");
1044         status = RegSetValueEx(hk_account_domain,
1045                                "F",
1046                                0,
1047                                AccountDomainFType,
1048                                AccountDomainF,
1049                                cbAccountDomainF);
1050         if (status != ERROR_SUCCESS) {
1051                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
1052                 return status;
1053         }
1054
1055         printf("Withdraw full access to HKLM\\SECURITY\n");
1056         status = inherit_SD(hklm, "SECURITY", TRUE,
1057                             security_parent_old_sd, security_child_old_sd);
1058         if (status != ERROR_SUCCESS) {
1059                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
1060                 return -1;
1061         }
1062         printf("DONE!\n");
1063         return 0;
1064 failed:
1065         printf("Withdraw full access to HKLM\\SECURITY\n");
1066         status = inherit_SD(hklm, "SECURITY", TRUE,
1067                             security_parent_old_sd, security_child_old_sd);
1068         if (status != ERROR_SUCCESS) {
1069                 printf("LINE:%u: Error: %d (0x%X)\n", __LINE__, status, status);
1070                 return -1;
1071         }
1072         printf("FAILED!\n");
1073         return 0;
1074 }