/* * $Header$ * * Copyright 2008 Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #include #include // for _snprintf #include "util.h" #include "secure.hxx" extern "C" { #include "cci_debugging.h" #include "ccutils.h" } void* malloc_alloc_p(size_t size) { return malloc(size); } void free_alloc_p(void *pptr) { void **real_pptr = (void**)pptr; if (*real_pptr) { free(*real_pptr); *real_pptr = 0; } } extern "C" DWORD alloc_textual_sid( PSID pSid, // binary Sid LPSTR *pTextualSid // buffer for Textual representaion of Sid ) { PSID_IDENTIFIER_AUTHORITY psia; DWORD dwSubAuthorities; DWORD dwSidRev = SID_REVISION; DWORD dwCounter; DWORD dwSidSize; *pTextualSid = 0; // // test if Sid passed in is valid // if(!IsValidSid(pSid)) return ERROR_INVALID_PARAMETER; // obtain SidIdentifierAuthority psia = GetSidIdentifierAuthority(pSid); // obtain sidsubauthority count dwSubAuthorities =* GetSidSubAuthorityCount(pSid); // // compute buffer length // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL // dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR); *pTextualSid = (LPSTR)malloc_alloc_p(dwSidSize); if (!*pTextualSid) return GetLastError(); LPSTR TextualSid = *pTextualSid; // // prepare S-SID_REVISION- // wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev ); // // prepare SidIdentifierAuthority // if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) ) { wsprintf(TextualSid + lstrlen(TextualSid), TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"), (USHORT)psia->Value[0], (USHORT)psia->Value[1], (USHORT)psia->Value[2], (USHORT)psia->Value[3], (USHORT)psia->Value[4], (USHORT)psia->Value[5]); } else { wsprintf(TextualSid + lstrlen(TextualSid), TEXT("%lu"), (ULONG)(psia->Value[5] ) + (ULONG)(psia->Value[4] << 8) + (ULONG)(psia->Value[3] << 16) + (ULONG)(psia->Value[2] << 24) ); } // // loop through SidSubAuthorities // for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++) { wsprintf(TextualSid + lstrlen(TextualSid), TEXT("-%lu"), *GetSidSubAuthority(pSid, dwCounter) ); } return 0; } DWORD alloc_token_user(HANDLE hToken, PTOKEN_USER *pptu) { DWORD status = 0; DWORD size = 0; *pptu = 0; GetTokenInformation(hToken, TokenUser, *pptu, 0, &size); if (size == 0) status = GetLastError(); if (!status) { if (!(*pptu = (PTOKEN_USER)malloc_alloc_p(size))) status = GetLastError(); } if (!status) { if (!GetTokenInformation(hToken, TokenUser, *pptu, size, &size)) status = GetLastError(); } if (status && *pptu) { free_alloc_p(pptu); } return status; } DWORD alloc_username( PSID Sid, LPSTR* pname, LPSTR* pdomain = 0 ) { DWORD status = 0; DWORD name_len = 0; DWORD domain_len = 0; SID_NAME_USE snu; LPSTR name = 0; LPSTR domain = 0; *pname = 0; if (pdomain) *pdomain = 0; LookupAccountSidA(NULL, Sid, 0, &name_len, 0, &domain_len, &snu); if ((name_len == 0) || (domain_len == 0)) status = GetLastError(); if (!status) { if (!(name = (LPSTR)malloc_alloc_p(name_len))) status = GetLastError(); } if (!status) { if (!(domain = (LPSTR)malloc_alloc_p(domain_len))) status = GetLastError(); } if (!status) { if (!LookupAccountSidA(NULL, Sid, name, &name_len, domain, &domain_len, &snu)) status = GetLastError(); } if (status) { if (name) free_alloc_p(&name); if (domain) free_alloc_p(&domain); } else { if (pdomain) { *pname = name; *pdomain = domain; } else { DWORD size = name_len + domain_len + 1; *pname = (LPSTR)malloc_alloc_p(size); if (!*pname) status = GetLastError(); else _snprintf(*pname, size, "%s\\%s", name, domain); } } return status; } DWORD get_authentication_id(HANDLE hToken, LUID* pAuthId) { TOKEN_STATISTICS ts; DWORD len; if (!GetTokenInformation(hToken, TokenStatistics, &ts, sizeof(ts), &len)) return GetLastError(); *pAuthId = ts.AuthenticationId; return 0; } DWORD alloc_name_9x( LPSTR* pname, LPSTR postfix ) { char prefix[] = "krbcc"; DWORD len = (sizeof(prefix) - 1) + 1 + strlen(postfix) + 1; *pname = (LPSTR)malloc_alloc_p(len); if (!*pname) return GetLastError(); _snprintf(*pname, len, "%s.%s", prefix, postfix); return 0; } DWORD alloc_name_NT(LPSTR* pname, LPSTR postfix) { DWORD status = 0; HANDLE hToken = 0; LUID auth_id; #ifdef _DEBUG PTOKEN_USER ptu = 0; LPSTR name = 0; LPSTR domain = 0; LPSTR sid = 0; #endif char prefix[] = "krbcc"; // Play it safe and say 3 characters are needed per 8 bits (byte). // Note that 20 characters are needed for a 64-bit number in // decimal (plus one for the string termination. // and include room for sessionId. char lid[3*sizeof(LUID)+1+5]; DWORD sessionId; DWORD len = 0; *pname = 0; status = SecureClient::Token(hToken); if (!status) { status = get_authentication_id(hToken, &auth_id); } if (!status) { if (!ProcessIdToSessionId(GetCurrentProcessId(), &sessionId)) sessionId = 0; } #ifdef _DEBUG if (!status) {status = alloc_token_user(hToken, &ptu);} if (!status) {status = alloc_username(ptu->User.Sid, &name, &domain);} if (!status) {status = alloc_textual_sid(ptu->User.Sid, &sid);} #endif if (!status) { _snprintf(lid, sizeof(lid), "%I64u.%u", auth_id, sessionId); lid[sizeof(lid)-1] = 0; // be safe len = (sizeof(prefix) - 1) + 1 + strlen(lid) + 1 + strlen(postfix) + 1; *pname = (LPSTR)malloc_alloc_p(len); if (!*pname) status = GetLastError(); } // // We used to allocate a name of the form: // "prefix.domain.name.sid.lid.postfix" (usually under 80 // characters, depending on username). However, XP thought this // was "invalid" (too long?) for some reason. // // Therefore, we now use "prefix.lid.postfix" // and for Terminal server we use "prefix.lid.sessionId.postfix" // if (!status) { _snprintf(*pname, len, "%s.%s.%s", prefix, lid, postfix); } #ifdef _DEBUG if (sid) free_alloc_p(&sid); if (name) free_alloc_p(&name); if (domain) free_alloc_p(&domain); if (ptu) free_alloc_p(&ptu); #endif if (hToken && hToken != INVALID_HANDLE_VALUE) CloseHandle(hToken); if (status && *pname) free_alloc_p(pname); return status; } extern "C" DWORD alloc_name(LPSTR* pname, LPSTR postfix, BOOL isNT) { return isNT ? alloc_name_NT(pname, postfix) : alloc_name_9x(pname, postfix); } extern "C" DWORD alloc_own_security_descriptor_NT(PSECURITY_DESCRIPTOR* ppsd) { DWORD status = 0; HANDLE hToken = 0; PTOKEN_USER ptu = 0; PSID pSid = 0; PACL pAcl = 0; DWORD size = 0; SECURITY_DESCRIPTOR sd; *ppsd = 0; if (!status) {status = SecureClient::Token(hToken);} // Get SID: if (!status) {status = alloc_token_user(hToken, &ptu);} if (!status) { size = GetLengthSid(ptu->User.Sid); pSid = (PSID) malloc_alloc_p(size); if (!pSid) status = GetLastError(); } if (!status) { if (!CopySid(size, pSid, ptu->User.Sid)) status = GetLastError(); } if (!status) { // Prepare ACL: size = sizeof(ACL); // Add an ACE: size += sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(pSid); pAcl = (PACL) malloc_alloc_p(size); if (!pAcl) status = GetLastError(); } if (!status) { if (!InitializeAcl(pAcl, size, ACL_REVISION)) status = GetLastError(); } if (!status) { if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, pSid)) status = GetLastError(); } if (!status) { // Prepare SD itself: if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) status = GetLastError(); } if (!status) { if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) status = GetLastError(); } if (!status) { if (!SetSecurityDescriptorOwner(&sd, pSid, FALSE)) status = GetLastError(); } if (!status) { if (!IsValidSecurityDescriptor(&sd)) status = ERROR_INVALID_PARAMETER; } if (!status) { // We now have a SD. Let's copy it. { // This should not succeed. Instead it should give us the size. BOOL ok = MakeSelfRelativeSD(&sd, 0, &size); } if (size == 0) status = GetLastError(); } if (!status) { *ppsd = (PSECURITY_DESCRIPTOR) malloc_alloc_p(size); if (!*ppsd) status = GetLastError(); } if (!status) { if (!MakeSelfRelativeSD(&sd, *ppsd, &size)) status = GetLastError(); } if (ptu) free_alloc_p(&ptu); if (pSid) free_alloc_p(&pSid); if (pAcl) free_alloc_p(&pAcl); if (hToken && hToken != INVALID_HANDLE_VALUE) CloseHandle(hToken); if (status && *ppsd) free_alloc_p(ppsd); return status; } DWORD alloc_module_file_name( char* module, char** pname ) { const DWORD max = 8192; DWORD status = 0; DWORD got = 0; DWORD size = 512; // use low number to test... HMODULE h = 0; BOOL ok = FALSE; char* name = 0; if (!pname) return ERROR_INVALID_PARAMETER; *pname = 0; h = GetModuleHandle(module); if (!h) return GetLastError(); // We assume size < max and size > 0 while (!status && !ok) { if (size > max) { // XXX - Assert? status = ERROR_INVALID_DATA; continue; } if (name) free_alloc_p(&name); name = (char*)malloc_alloc_p(size + 1); if (!name) { status = ERROR_NOT_ENOUGH_MEMORY; continue; } name[size] = 0; got = GetModuleFileName(h, name, size); if (!got) { status = GetLastError(); // sanity check: if (!status) { // XXX - print nasty message...assert? status = ERROR_INVALID_DATA; } continue; } // To know we're ok, we need to verify that what we got // was bigger than GetModuleSize thought it got. ok = got && (got < size) && !name[got]; size *= 2; } if (status && name) free_alloc_p(&name); else *pname = name; return status; } DWORD alloc_module_dir_name( char* module, char** pname ) { DWORD status = alloc_module_file_name(module, pname); if (!status) { char* name = *pname; char* p = name + strlen(name); while ((p >= name) && (*p != '\\') && (*p != '/')) p--; if (p < name) { free_alloc_p(pname); status = ERROR_INVALID_DATA; } else { *p = 0; } } return status; } DWORD alloc_module_dir_name_with_file( char* module, char* file, char** pname ) { DWORD status = alloc_module_dir_name(module, pname); if (!status) { char* name = *pname; size_t name_size = strlen(name); size_t size = name_size + 1 + strlen(file) + 1; char* result = (char*)malloc_alloc_p(size); if (!result) { status = ERROR_NOT_ENOUGH_MEMORY; free_alloc_p(pname); } else { strcpy(result, name); result[name_size] = '\\'; strcpy(result + name_size + 1, file); free_alloc_p(pname); *pname = result; } } return status; } DWORD alloc_cmdline_2_args(char* prog, char* arg1, char* arg2, char** pname) { DWORD status = 0; size_t size = strlen(prog) + strlen(arg1) + strlen(arg2) + 4; char* result = (char*)malloc_alloc_p(size); if (!result) { status = ERROR_NOT_ENOUGH_MEMORY; } else { strcpy(result, prog); strcat(result, " "); strcat(result, arg1); strcat(result, " "); strcat(result, arg2); *pname = result; } cci_debug_printf("%s made <%s>", __FUNCTION__, result); return status; }