1 /* 2 * $Header$ 3 * 4 * Copyright 2008 Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 #include <windows.h> 28 #include <stdio.h> // for _snprintf 29 #include <malloc.h> 30 #include <stdlib.h> 31 32 extern "C" { 33 #include "cci_debugging.h" 34 #include "ccutils.h" 35 } 36 37 #include "util.h" 38 #include "secure.hxx" 39 40 41 void* malloc_alloc_p(size_t size) { 42 return malloc(size); 43 } 44 45 void free_alloc_p(void *pptr) { 46 void **real_pptr = (void**)pptr; 47 if (*real_pptr) { 48 free(*real_pptr); 49 *real_pptr = 0; 50 } 51 } 52 53 extern "C" DWORD alloc_textual_sid( 54 PSID pSid, // binary Sid 55 LPSTR *pTextualSid // buffer for Textual representation of Sid 56 ) { 57 PSID_IDENTIFIER_AUTHORITY psia; 58 DWORD dwSubAuthorities; 59 DWORD dwSidRev = SID_REVISION; 60 DWORD dwCounter; 61 DWORD dwSidSize; 62 63 *pTextualSid = 0; 64 65 // 66 // test if Sid passed in is valid 67 // 68 if(!IsValidSid(pSid)) return ERROR_INVALID_PARAMETER; 69 70 // obtain SidIdentifierAuthority 71 psia = GetSidIdentifierAuthority(pSid); 72 73 // obtain sidsubauthority count 74 dwSubAuthorities =* GetSidSubAuthorityCount(pSid); 75 76 // 77 // compute buffer length 78 // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL 79 // 80 dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR); 81 *pTextualSid = (LPSTR)malloc_alloc_p(dwSidSize); 82 if (!*pTextualSid) 83 return GetLastError(); 84 85 LPSTR TextualSid = *pTextualSid; 86 87 // 88 // prepare S-SID_REVISION- 89 // 90 wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev ); 91 92 // 93 // prepare SidIdentifierAuthority 94 // 95 if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) ) 96 { 97 wsprintf(TextualSid + lstrlen(TextualSid), 98 TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"), 99 (USHORT)psia->Value[0], 100 (USHORT)psia->Value[1], 101 (USHORT)psia->Value[2], 102 (USHORT)psia->Value[3], 103 (USHORT)psia->Value[4], 104 (USHORT)psia->Value[5]); 105 } 106 else 107 { 108 wsprintf(TextualSid + lstrlen(TextualSid), TEXT("%lu"), 109 (ULONG)(psia->Value[5] ) + 110 (ULONG)(psia->Value[4] << 8) + 111 (ULONG)(psia->Value[3] << 16) + 112 (ULONG)(psia->Value[2] << 24) ); 113 } 114 115 // 116 // loop through SidSubAuthorities 117 // 118 for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++) 119 { 120 wsprintf(TextualSid + lstrlen(TextualSid), TEXT("-%lu"), 121 *GetSidSubAuthority(pSid, dwCounter) ); 122 } 123 return 0; 124 } 125 126 DWORD alloc_token_user(HANDLE hToken, PTOKEN_USER *pptu) { 127 DWORD status = 0; 128 DWORD size = 0; 129 *pptu = 0; 130 131 GetTokenInformation(hToken, TokenUser, *pptu, 0, &size); 132 if (size == 0) status = GetLastError(); 133 134 if (!status) { 135 if (!(*pptu = (PTOKEN_USER)malloc_alloc_p(size))) 136 status = GetLastError(); 137 } 138 139 if (!status) { 140 if (!GetTokenInformation(hToken, TokenUser, *pptu, size, &size)) 141 status = GetLastError(); 142 } 143 144 if (status && *pptu) { 145 free_alloc_p(pptu); 146 } 147 return status; 148 } 149 150 DWORD 151 alloc_username( 152 PSID Sid, 153 LPSTR* pname, 154 LPSTR* pdomain = 0 155 ) 156 { 157 DWORD status = 0; 158 DWORD name_len = 0; 159 DWORD domain_len = 0; 160 SID_NAME_USE snu; 161 LPSTR name = 0; 162 LPSTR domain = 0; 163 164 *pname = 0; 165 if (pdomain) *pdomain = 0; 166 167 LookupAccountSidA(NULL, Sid, 0, &name_len, 0, &domain_len, &snu); 168 if ((name_len == 0) || (domain_len == 0)) status = GetLastError(); 169 170 if (!status) { 171 if (!(name = (LPSTR)malloc_alloc_p(name_len))) status = GetLastError(); 172 } 173 174 if (!status) { 175 if (!(domain = (LPSTR)malloc_alloc_p(domain_len))) status = GetLastError(); 176 } 177 178 if (!status) { 179 if (!LookupAccountSidA(NULL, Sid, name, &name_len, domain, &domain_len, &snu)) status = GetLastError(); 180 } 181 182 if (status) { 183 if (name) free_alloc_p(&name); 184 if (domain) free_alloc_p(&domain); 185 } 186 else { 187 if (pdomain) { 188 *pname = name; 189 *pdomain = domain; 190 } 191 else { 192 DWORD size = name_len + domain_len + 1; 193 *pname = (LPSTR)malloc_alloc_p(size); 194 if (!*pname) status = GetLastError(); 195 else _snprintf(*pname, size, "%s\\%s", name, domain); 196 } 197 } 198 return status; 199 } 200 201 DWORD get_authentication_id(HANDLE hToken, LUID* pAuthId) { 202 TOKEN_STATISTICS ts; 203 DWORD len; 204 205 if (!GetTokenInformation(hToken, TokenStatistics, &ts, sizeof(ts), &len)) 206 return GetLastError(); 207 *pAuthId = ts.AuthenticationId; 208 return 0; 209 } 210 211 DWORD 212 alloc_name_9x( 213 LPSTR* pname, 214 LPSTR postfix 215 ) 216 { 217 char prefix[] = "krbcc"; 218 DWORD len = (sizeof(prefix) - 1) + 1 + strlen(postfix) + 1; 219 220 *pname = (LPSTR)malloc_alloc_p(len); 221 if (!*pname) return GetLastError(); 222 _snprintf(*pname, len, "%s.%s", prefix, postfix); 223 return 0; 224 } 225 226 DWORD alloc_name_NT(LPSTR* pname, LPSTR postfix) { 227 DWORD status = 0; 228 HANDLE hToken = 0; 229 LUID auth_id; 230 #ifdef _DEBUG 231 PTOKEN_USER ptu = 0; 232 LPSTR name = 0; 233 LPSTR domain = 0; 234 LPSTR sid = 0; 235 #endif 236 char prefix[] = "krbcc"; 237 // Play it safe and say 3 characters are needed per 8 bits (byte). 238 // Note that 20 characters are needed for a 64-bit number in 239 // decimal (plus one for the string termination. 240 // and include room for sessionId. 241 char lid[3*sizeof(LUID)+1+5]; 242 DWORD sessionId; 243 DWORD len = 0; 244 245 *pname = 0; 246 247 status = SecureClient::Token(hToken); 248 249 if (!status) { 250 status = get_authentication_id(hToken, &auth_id); 251 } 252 253 if (!status) { 254 if (!ProcessIdToSessionId(GetCurrentProcessId(), &sessionId)) 255 sessionId = 0; 256 } 257 258 #ifdef _DEBUG 259 if (!status) {status = alloc_token_user(hToken, &ptu);} 260 if (!status) {status = alloc_username(ptu->User.Sid, &name, &domain);} 261 if (!status) {status = alloc_textual_sid(ptu->User.Sid, &sid);} 262 #endif 263 264 if (!status) { 265 _snprintf(lid, sizeof(lid), "%I64u.%u", auth_id, sessionId); 266 lid[sizeof(lid)-1] = 0; // be safe 267 268 len = (sizeof(prefix) - 1) + 1 + strlen(lid) + 1 + strlen(postfix) + 1; 269 *pname = (LPSTR)malloc_alloc_p(len); 270 if (!*pname) status = GetLastError(); 271 } 272 273 // 274 // We used to allocate a name of the form: 275 // "prefix.domain.name.sid.lid.postfix" (usually under 80 276 // characters, depending on username). However, XP thought this 277 // was "invalid" (too long?) for some reason. 278 // 279 // Therefore, we now use "prefix.lid.postfix" 280 // and for Terminal server we use "prefix.lid.sessionId.postfix" 281 // 282 283 if (!status) { 284 _snprintf(*pname, len, "%s.%s.%s", prefix, lid, postfix); 285 } 286 287 #ifdef _DEBUG 288 if (sid) 289 free_alloc_p(&sid); 290 if (name) 291 free_alloc_p(&name); 292 if (domain) 293 free_alloc_p(&domain); 294 if (ptu) 295 free_alloc_p(&ptu); 296 #endif 297 if (hToken && hToken != INVALID_HANDLE_VALUE) 298 CloseHandle(hToken); 299 if (status && *pname) 300 free_alloc_p(pname); 301 return status; 302 } 303 304 extern "C" DWORD alloc_name(LPSTR* pname, LPSTR postfix, BOOL isNT) { 305 return isNT ? alloc_name_NT(pname, postfix) : 306 alloc_name_9x(pname, postfix); 307 } 308 309 extern "C" DWORD alloc_own_security_descriptor_NT(PSECURITY_DESCRIPTOR* ppsd) { 310 DWORD status = 0; 311 HANDLE hToken = 0; 312 PTOKEN_USER ptu = 0; 313 PSID pSid = 0; 314 PACL pAcl = 0; 315 DWORD size = 0; 316 SECURITY_DESCRIPTOR sd; 317 318 *ppsd = 0; 319 320 if (!status) {status = SecureClient::Token(hToken);} 321 322 // Get SID: 323 if (!status) {status = alloc_token_user(hToken, &ptu);} 324 325 if (!status) { 326 size = GetLengthSid(ptu->User.Sid); 327 pSid = (PSID) malloc_alloc_p(size); 328 if (!pSid) status = GetLastError(); 329 } 330 if (!status) { 331 if (!CopySid(size, pSid, ptu->User.Sid)) status = GetLastError(); 332 } 333 334 if (!status) { 335 // Prepare ACL: 336 size = sizeof(ACL); 337 // Add an ACE: 338 size += sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(pSid); 339 pAcl = (PACL) malloc_alloc_p(size); 340 if (!pAcl) status = GetLastError(); 341 } 342 343 if (!status) { 344 if (!InitializeAcl(pAcl, size, ACL_REVISION)) status = GetLastError(); 345 } 346 347 if (!status) { 348 if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, pSid)) status = GetLastError(); 349 } 350 351 if (!status) { 352 // Prepare SD itself: 353 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) status = GetLastError(); 354 } 355 356 if (!status) { 357 if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) status = GetLastError(); 358 } 359 360 if (!status) { 361 if (!SetSecurityDescriptorOwner(&sd, pSid, FALSE)) status = GetLastError(); 362 } 363 364 if (!status) { 365 if (!IsValidSecurityDescriptor(&sd)) status = ERROR_INVALID_PARAMETER; 366 } 367 368 if (!status) { 369 // We now have a SD. Let's copy it. 370 { 371 // This should not succeed. Instead it should give us the size. 372 BOOL ok = MakeSelfRelativeSD(&sd, 0, &size); 373 } 374 if (size == 0) status = GetLastError(); 375 } 376 377 if (!status) { 378 *ppsd = (PSECURITY_DESCRIPTOR) malloc_alloc_p(size); 379 if (!*ppsd) status = GetLastError(); 380 } 381 382 if (!status) { 383 if (!MakeSelfRelativeSD(&sd, *ppsd, &size)) status = GetLastError(); 384 } 385 386 if (ptu) free_alloc_p(&ptu); 387 if (pSid) free_alloc_p(&pSid); 388 if (pAcl) free_alloc_p(&pAcl); 389 if (hToken && hToken != INVALID_HANDLE_VALUE) CloseHandle(hToken); 390 if (status && *ppsd) free_alloc_p(ppsd); 391 return status; 392 } 393 394 DWORD 395 alloc_module_file_name( 396 char* module, 397 char** pname 398 ) 399 { 400 const DWORD max = 8192; 401 DWORD status = 0; 402 DWORD got = 0; 403 DWORD size = 512; // use low number to test... 404 HMODULE h = 0; 405 BOOL ok = FALSE; 406 char* name = 0; 407 408 if (!pname) 409 return ERROR_INVALID_PARAMETER; 410 *pname = 0; 411 412 h = GetModuleHandle(module); 413 414 if (!h) return GetLastError(); 415 416 // We assume size < max and size > 0 417 while (!status && !ok) { 418 if (size > max) { 419 // XXX - Assert? 420 status = ERROR_INVALID_DATA; 421 continue; 422 } 423 if (name) free_alloc_p(&name); 424 name = (char*)malloc_alloc_p(size + 1); 425 if (!name) { 426 status = ERROR_NOT_ENOUGH_MEMORY; 427 continue; 428 } 429 name[size] = 0; 430 got = GetModuleFileName(h, name, size); 431 if (!got) { 432 status = GetLastError(); 433 // sanity check: 434 if (!status) { 435 // XXX - print nasty message...assert? 436 status = ERROR_INVALID_DATA; 437 } 438 continue; 439 } 440 // To know we're ok, we need to verify that what we got 441 // was bigger than GetModuleSize thought it got. 442 ok = got && (got < size) && !name[got]; 443 size *= 2; 444 } 445 if (status && name) 446 free_alloc_p(&name); 447 else 448 *pname = name; 449 return status; 450 } 451 452 DWORD 453 alloc_module_dir_name( 454 char* module, 455 char** pname 456 ) 457 { 458 DWORD status = alloc_module_file_name(module, pname); 459 if (!status) { 460 char* name = *pname; 461 char* p = name + strlen(name); 462 while ((p >= name) && (*p != '\\') && (*p != '/')) p--; 463 if (p < name) { 464 free_alloc_p(pname); 465 status = ERROR_INVALID_DATA; 466 } else { 467 *p = 0; 468 } 469 } 470 return status; 471 } 472 473 DWORD 474 alloc_module_dir_name_with_file( 475 char* module, 476 char* file, 477 char** pname 478 ) 479 { 480 DWORD status = alloc_module_dir_name(module, pname); 481 if (!status) { 482 char* name = *pname; 483 size_t name_size = strlen(name); 484 size_t size = name_size + 1 + strlen(file) + 1; 485 char* result = (char*)malloc_alloc_p(size); 486 if (!result) { 487 status = ERROR_NOT_ENOUGH_MEMORY; 488 free_alloc_p(pname); 489 } else { 490 strcpy(result, name); 491 result[name_size] = '\\'; 492 strcpy(result + name_size + 1, file); 493 free_alloc_p(pname); 494 *pname = result; 495 } 496 } 497 return status; 498 } 499 500 DWORD alloc_cmdline_2_args(char* prog, 501 char* arg1, 502 char* arg2, 503 char** pname) { 504 DWORD status = 0; 505 size_t size = strlen(prog) + strlen(arg1) + strlen(arg2) + 4; 506 char* result = (char*)malloc_alloc_p(size); 507 if (!result) { 508 status = ERROR_NOT_ENOUGH_MEMORY; 509 } 510 else { 511 strcpy(result, prog); 512 strcat(result, " "); 513 strcat(result, arg1); 514 strcat(result, " "); 515 strcat(result, arg2); 516 *pname = result; 517 } 518 cci_debug_printf("%s made <%s>", __FUNCTION__, result); 519 return status; 520 } 521