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 */
SidToString(const SID * sid,char ** 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 
StringToSid(const char * str,SID * sid)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))
print_asc(const unsigned char * buf,int len)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 
dump_data(const unsigned char * buf1,int len)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 
calc_tmp_HKLM_SECURITY_SD(SECURITY_DESCRIPTOR * old_sd,SID * current_user_sid,SECURITY_DESCRIPTOR ** _old_parent_sd,SECURITY_DESCRIPTOR ** _old_child_sd,SECURITY_DESCRIPTOR ** _new_parent_sd,SECURITY_DESCRIPTOR ** _new_child_sd)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 
inherit_SD(HKEY parent_hk,char * current_key,BOOL reset,SECURITY_DESCRIPTOR * current_sd,SECURITY_DESCRIPTOR * child_sd)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 
replaceSIDBuffer(BYTE * buf,DWORD len,SID * oldDomainSid,SID * newDomainSid)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 
replaceSID(HKEY parent_hk,const char * parent_path,const char * current_key,SID * oldDomainSid,SID * newDomainSid)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 
main(int argc,char * argv[])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 }
1075