UINT MSIREG_OpenLocalManagedProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create) { WCHAR squished_pc[GUID_SIZE]; WCHAR keypath[0x200]; LPWSTR usersid; UINT r; TRACE("%s\n", debugstr_w(szProductCode)); if (!squash_guid(szProductCode, squished_pc)) return ERROR_FUNCTION_FAILED; TRACE("squished (%s)\n", debugstr_w(squished_pc)); r = get_user_sid(&usersid); if (r != ERROR_SUCCESS || !usersid) { ERR("Failed to retrieve user SID: %d\n", r); return r; } sprintfW(keypath, szInstaller_LocalManagedProd_fmt, usersid, squished_pc); LocalFree(usersid); if (create) return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key); return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key); }
// initialize the registry. setup default keys to use void os_init_registry_stuff(const char *company, const char *app, const char *version) { if (company) { strcpy_s(szCompanyName, company); } else { strcpy_s(szCompanyName, Osreg_company_name); } if (app) { strcpy_s(szAppName, app); } else { strcpy_s(szAppName, Osreg_app_name); } #ifdef WIN32 OSVERSIONINFO versionInfo; versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&versionInfo); // Windows Vista is 6.0 which is the first version requiring this if (versionInfo.dwMajorVersion >= 6) { userSIDValid = get_user_sid(userSID); } #endif Os_reg_inited = 1; }
UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, HKEY *key, BOOL create) { UINT rc; WCHAR squished_pc[GUID_SIZE]; WCHAR keypath[0x200]; LPWSTR usersid; TRACE("%s\n", debugstr_w(szProduct)); if (!squash_guid(szProduct, squished_pc)) return ERROR_FUNCTION_FAILED; TRACE("squished (%s)\n", debugstr_w(squished_pc)); rc = get_user_sid(&usersid); if (rc != ERROR_SUCCESS || !usersid) { ERR("Failed to retrieve user SID: %d\n", rc); return rc; } sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc); if (create) rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key); else rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key); LocalFree(usersid); return rc; }
bool getsids(char **error) { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-braces" #endif SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY; #ifdef __clang__ #pragma clang diagnostic pop #endif bool ret = false; *error = NULL; if (!usersid) { if ((usersid = get_user_sid()) == NULL) { *error = dupprintf("unable to construct SID for current user: %s", win_strerror(GetLastError())); goto cleanup; } } if (!worldsid) { if (!AllocateAndInitializeSid(&world_auth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldsid)) { *error = dupprintf("unable to construct SID for world: %s", win_strerror(GetLastError())); goto cleanup; } } if (!networksid) { if (!AllocateAndInitializeSid(&nt_auth, 1, SECURITY_NETWORK_RID, 0, 0, 0, 0, 0, 0, 0, &networksid)) { *error = dupprintf("unable to construct SID for " "local same-user access only: %s", win_strerror(GetLastError())); goto cleanup; } } ret = true; cleanup: return ret; }
UINT MSIREG_OpenCurrentUserInstallProps(LPCWSTR szProduct, HKEY *key, BOOL create) { UINT rc; LPWSTR usersid; rc = get_user_sid(&usersid); if (rc != ERROR_SUCCESS || !usersid) { ERR("Failed to retrieve user SID: %d\n", rc); return rc; } rc = MSIREG_OpenInstallProps(szProduct, usersid, key, create); LocalFree(usersid); return rc; }
int getsids(char *error) { SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY; int ret; error=NULL; if (!usersid) { if ((usersid = get_user_sid()) == NULL) { error = dupprintf("unable to construct SID for current user: %s", win_strerror(GetLastError())); goto cleanup; } } if (!worldsid) { if (!AllocateAndInitializeSid(&world_auth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldsid)) { error = dupprintf("unable to construct SID for world: %s", win_strerror(GetLastError())); goto cleanup; } } if (!networksid) { if (!AllocateAndInitializeSid(&nt_auth, 1, SECURITY_NETWORK_RID, 0, 0, 0, 0, 0, 0, 0, &networksid)) { error = dupprintf("unable to construct SID for " "local same-user access only: %s", win_strerror(GetLastError())); goto cleanup; } } ret=TRUE; cleanup: if (ret) { sfree(error); error = NULL; } return ret; }
UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent) { UINT rc; WCHAR comp[GUID_SIZE]; WCHAR keypath[0x200]; LPWSTR usersid; TRACE("%s\n", debugstr_w(szComponent)); if (!squash_guid(szComponent, comp)) return ERROR_FUNCTION_FAILED; TRACE("squished (%s)\n", debugstr_w(comp)); rc = get_user_sid(&usersid); if (rc != ERROR_SUCCESS || !usersid) { ERR("Failed to retrieve user SID: %d\n", rc); return rc; } sprintfW(keypath, szUserDataComp_fmt, usersid, comp); LocalFree(usersid); return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath); }
/* * Create an access check structure, the format depends on the version parameter. * If broken is specified then we create a stucture that isn't conform to the * specification. * * If the structure can't be created then NULL is returned. */ static DATA_BLOB *create_access_check(struct torture_context *tctx, struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const char *user, bool broken, uint32_t version) { TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); DATA_BLOB *blob = talloc_zero(mem_ctx, DATA_BLOB); enum ndr_err_code ndr_err; const struct dom_sid *sid = get_user_sid(tctx, p, tmp_ctx, user); if (sid == NULL) { return NULL; } if (version == 2) { struct bkrp_access_check_v2 access_struct; struct sha sctx; uint8_t nonce[32]; ZERO_STRUCT(access_struct); generate_random_buffer(nonce, sizeof(nonce)); access_struct.nonce_len = sizeof(nonce); access_struct.nonce = nonce; access_struct.sid = *sid; ndr_err = ndr_push_struct_blob(blob, blob, &access_struct, (ndr_push_flags_fn_t)ndr_push_bkrp_access_check_v2); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return NULL; } /* * We pushed the whole structure including a null hash * but the hash need to be calculated only up to the hash field * so we reduce the size of what has to be calculated */ SHA1_Init(&sctx); SHA1_Update(&sctx, blob->data, blob->length - sizeof(access_struct.hash)); SHA1_Final(blob->data + blob->length - sizeof(access_struct.hash), &sctx); /* Altering the SHA */ if (broken) { blob->data[blob->length - 1]++; } } if (version == 3) { struct bkrp_access_check_v3 access_struct; struct hc_sha512state sctx; uint8_t nonce[32]; ZERO_STRUCT(access_struct); generate_random_buffer(nonce, sizeof(nonce)); access_struct.nonce_len = sizeof(nonce); access_struct.nonce = nonce; access_struct.sid = *sid; ndr_err = ndr_push_struct_blob(blob, blob, &access_struct, (ndr_push_flags_fn_t)ndr_push_bkrp_access_check_v3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return NULL; } /*We pushed the whole structure including a null hash * but the hash need to be calculated only up to the hash field * so we reduce the size of what has to be calculated */ SHA512_Init(&sctx); SHA512_Update(&sctx, blob->data, blob->length - sizeof(access_struct.hash)); SHA512_Final(blob->data + blob->length - sizeof(access_struct.hash), &sctx); /* Altering the SHA */ if (broken) { blob->data[blob->length -1]++; } } talloc_free(tmp_ctx); return blob; }
agent_pending_query *agent_query( strbuf *query, void **out, int *outlen, void (*callback)(void *, void *, int), void *callback_ctx) { HWND hwnd; char *mapname; HANDLE filemap; unsigned char *p, *ret; int id, retlen; COPYDATASTRUCT cds; SECURITY_ATTRIBUTES sa, *psa; PSECURITY_DESCRIPTOR psd = NULL; PSID usersid = NULL; *out = NULL; *outlen = 0; if (query->len > AGENT_MAX_MSGLEN) return NULL; /* query too large */ hwnd = FindWindow("Pageant", "Pageant"); if (!hwnd) return NULL; /* *out == NULL, so failure */ mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId()); psa = NULL; #ifndef NO_SECURITY if (got_advapi()) { /* * Make the file mapping we create for communication with * Pageant owned by the user SID rather than the default. This * should make communication between processes with slightly * different contexts more reliable: in particular, command * prompts launched as administrator should still be able to * run PSFTPs which refer back to the owning user's * unprivileged Pageant. */ usersid = get_user_sid(); if (usersid) { psd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (psd) { if (p_InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION) && p_SetSecurityDescriptorOwner(psd, usersid, false)) { sa.nLength = sizeof(sa); sa.bInheritHandle = true; sa.lpSecurityDescriptor = psd; psa = &sa; } else { LocalFree(psd); psd = NULL; } } } } #endif /* NO_SECURITY */ filemap = CreateFileMapping(INVALID_HANDLE_VALUE, psa, PAGE_READWRITE, 0, AGENT_MAX_MSGLEN, mapname); if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) { sfree(mapname); return NULL; /* *out == NULL, so failure */ } p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); strbuf_finalise_agent_query(query); memcpy(p, query->s, query->len); cds.dwData = AGENT_COPYDATA_ID; cds.cbData = 1 + strlen(mapname); cds.lpData = mapname; /* * The user either passed a null callback (indicating that the * query is required to be synchronous) or CreateThread failed. * Either way, we need a synchronous request. */ id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds); if (id > 0) { retlen = 4 + GET_32BIT_MSB_FIRST(p); ret = snewn(retlen, unsigned char); if (ret) { memcpy(ret, p, retlen); *out = ret; *outlen = retlen; } }
Socket new_named_pipe_client(const char *pipename, Plug plug) { HANDLE pipehandle; PSID usersid, pipeowner; PSECURITY_DESCRIPTOR psd; char *err; Socket ret; assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0); assert(strchr(pipename + 9, '\\') == NULL); while (1) { pipehandle = CreateFile(pipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (pipehandle != INVALID_HANDLE_VALUE) break; if (GetLastError() != ERROR_PIPE_BUSY) { err = dupprintf("Unable to open named pipe '%s': %s", pipename, win_strerror(GetLastError())); ret = new_error_socket(err, plug); sfree(err); return ret; } /* * If we got ERROR_PIPE_BUSY, wait for the server to * create a new pipe instance. (Since the server is * expected to be winnps.c, which will do that immediately * after a previous connection is accepted, that shouldn't * take excessively long.) */ if (!WaitNamedPipe(pipename, NMPWAIT_USE_DEFAULT_WAIT)) { err = dupprintf("Error waiting for named pipe '%s': %s", pipename, win_strerror(GetLastError())); ret = new_error_socket(err, plug); sfree(err); return ret; } } if ((usersid = get_user_sid()) == NULL) { CloseHandle(pipehandle); err = dupprintf("Unable to get user SID"); ret = new_error_socket(err, plug); sfree(err); return ret; } if (p_GetSecurityInfo(pipehandle, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION, &pipeowner, NULL, NULL, NULL, &psd) != ERROR_SUCCESS) { err = dupprintf("Unable to get named pipe security information: %s", win_strerror(GetLastError())); ret = new_error_socket(err, plug); sfree(err); CloseHandle(pipehandle); return ret; } if (!EqualSid(pipeowner, usersid)) { err = dupprintf("Owner of named pipe '%s' is not us", pipename); ret = new_error_socket(err, plug); sfree(err); CloseHandle(pipehandle); LocalFree(psd); return ret; } LocalFree(psd); return make_handle_socket(pipehandle, pipehandle, NULL, plug, TRUE); }
/* Move a file handle to recycle bin * The pathname must be a valid NT file name generated using filename_to_nt_pathname() */ static NTSTATUS move_to_recycle_bin(HANDLE handle, WCHAR *pathname) { IO_STATUS_BLOCK status_block; NTSTATUS status; /* TODO: Handle the case when recycle bin does not exist (according to cygwin) */ /* TODO: Handle when the file is inside recycle bin */ WCHAR recyclepath[512]; UNICODE_STRING recycle; RtlInitEmptyUnicodeString(&recycle, recyclepath, sizeof(recyclepath)); /* Root directory, should look like "\??\C:\", 7 characters */ UNICODE_STRING root; RtlInitCountedUnicodeString(&root, pathname, sizeof(WCHAR) * 7); RtlAppendUnicodeStringToString(&recycle, &root); RtlAppendUnicodeToString(&recycle, L"$Recycle.Bin\\"); WCHAR renamepath[512]; UNICODE_STRING rename; RtlInitEmptyUnicodeString(&rename, renamepath, sizeof(renamepath)); RtlAppendUnicodeStringToString(&rename, &recycle); /* Append user sid */ { WCHAR buf[256]; UNICODE_STRING sid; RtlInitEmptyUnicodeString(&sid, buf, sizeof(buf)); RtlConvertSidToUnicodeString(&sid, get_user_sid(), FALSE); RtlAppendUnicodeStringToString(&rename, &sid); RtlAppendUnicodeToString(&rename, L"\\"); } /* Generate an unique file name by append file id and a hash of the pathname, * To allow unlinking multiple hard links of the same file */ RtlAppendUnicodeToString(&rename, L".flinux"); /* Append file id */ { FILE_INTERNAL_INFORMATION info; status = NtQueryInformationFile(handle, &status_block, &info, sizeof(info), FileInternalInformation); if (!NT_SUCCESS(status)) { log_error("NtQueryInformationFile(FileInternalInformation) failed, status: %x", status); return status; } RtlAppendInt64ToString(info.IndexNumber.QuadPart, 16, &rename); RtlAppendUnicodeToString(&rename, L"_"); } /* Append file path hash */ { UNICODE_STRING path; RtlInitUnicodeString(&path, pathname); ULONG hash; RtlHashUnicodeString(&path, FALSE, HASH_STRING_ALGORITHM_DEFAULT, &hash); RtlAppendIntegerToString(hash, 16, &rename); } /* Rename file */ char buf[512]; FILE_RENAME_INFORMATION *info = (FILE_RENAME_INFORMATION *)buf; info->ReplaceIfExists = FALSE; info->RootDirectory = NULL; info->FileNameLength = rename.Length; memcpy(info->FileName, rename.Buffer, rename.Length); status = NtSetInformationFile(handle, &status_block, info, sizeof(*info) + info->FileNameLength, FileRenameInformation); if (!NT_SUCCESS(status)) { log_error("NtSetInformationFile(FileRenameInformation) failed, status: %x", status); return status; } return STATUS_SUCCESS; }
int make_private_security_descriptor(DWORD permissions, PSECURITY_DESCRIPTOR *psd, PACL *acl, char **error) { SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY; EXPLICIT_ACCESS ea[3]; int acl_err; int ret = FALSE; /* Initialised once, then kept around to reuse forever */ static PSID worldsid, networksid, usersid; *psd = NULL; *acl = NULL; *error = NULL; if (!got_advapi()) { *error = dupprintf("unable to load advapi32.dll"); goto cleanup; } if (!usersid) { if ((usersid = get_user_sid()) == NULL) { *error = dupprintf("unable to construct SID for current user: %s", win_strerror(GetLastError())); goto cleanup; } } if (!worldsid) { if (!AllocateAndInitializeSid(&world_auth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldsid)) { *error = dupprintf("unable to construct SID for world: %s", win_strerror(GetLastError())); goto cleanup; } } if (!networksid) { if (!AllocateAndInitializeSid(&nt_auth, 1, SECURITY_NETWORK_RID, 0, 0, 0, 0, 0, 0, 0, &networksid)) { *error = dupprintf("unable to construct SID for " "local same-user access only: %s", win_strerror(GetLastError())); goto cleanup; } } memset(ea, 0, sizeof(ea)); ea[0].grfAccessPermissions = permissions; ea[0].grfAccessMode = REVOKE_ACCESS; ea[0].grfInheritance = NO_INHERITANCE; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.ptstrName = (LPTSTR)worldsid; ea[1].grfAccessPermissions = permissions; ea[1].grfAccessMode = GRANT_ACCESS; ea[1].grfInheritance = NO_INHERITANCE; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.ptstrName = (LPTSTR)usersid; ea[2].grfAccessPermissions = permissions; ea[2].grfAccessMode = REVOKE_ACCESS; ea[2].grfInheritance = NO_INHERITANCE; ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[2].Trustee.ptstrName = (LPTSTR)networksid; acl_err = p_SetEntriesInAclA(3, ea, NULL, acl); if (acl_err != ERROR_SUCCESS || *acl == NULL) { *error = dupprintf("unable to construct ACL: %s", win_strerror(acl_err)); goto cleanup; } *psd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (!*psd) { *error = dupprintf("unable to allocate security descriptor: %s", win_strerror(GetLastError())); goto cleanup; } if (!InitializeSecurityDescriptor(*psd, SECURITY_DESCRIPTOR_REVISION)) { *error = dupprintf("unable to initialise security descriptor: %s", win_strerror(GetLastError())); goto cleanup; } if (!SetSecurityDescriptorDacl(*psd, TRUE, *acl, FALSE)) { *error = dupprintf("unable to set DACL in security descriptor: %s", win_strerror(GetLastError())); goto cleanup; } ret = TRUE; cleanup: if (!ret) { if (*psd) { LocalFree(*psd); *psd = NULL; } if (*acl) { LocalFree(*acl); *acl = NULL; } } else { sfree(*error); *error = NULL; } return ret; }