NTSTATUS FspToolGetSidFromName(PWSTR Name, PSID *PSid) { PSID Sid; WCHAR Domn[256]; DWORD SidSize, DomnSize; SID_NAME_USE Use; SidSize = 0; DomnSize = sizeof Domn / sizeof Domn[0]; if (LookupAccountNameW(0, Name, 0, &SidSize, Domn, &DomnSize, &Use)) return STATUS_INVALID_PARAMETER; if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) return FspNtStatusFromWin32(GetLastError()); Sid = MemAlloc(SidSize); if (0 == Sid) return STATUS_INSUFFICIENT_RESOURCES; DomnSize = sizeof Domn / sizeof Domn[0]; if (!LookupAccountNameW(0, Name, Sid, &SidSize, Domn, &DomnSize, &Use)) { MemFree(Sid); return FspNtStatusFromWin32(GetLastError()); } *PSid = Sid; return STATUS_SUCCESS; }
// Security ID (SID) Lookup HRESULT TCUserAccount::GetSID(LPCWSTR szUserName, PSID* ppSID, LPWSTR* ppszDomain) { // Not supported under Windows9x if (IsWin9x()) return S_FALSE; // Initialize the [out] parameters if (ppSID) *ppSID = NULL; if (ppszDomain) *ppszDomain = NULL; // Skip past "\" or ".\", if the specified name begins with that if (L'\\' == szUserName[0]) szUserName += 1; else if (L'.' == szUserName[0] && L'\\' == szUserName[1]) szUserName += 2; // Get the needed size of the buffers SID_NAME_USE eUse; DWORD cbSID = 0, cchDomain = 0; if (!LookupAccountNameW(NULL, szUserName, NULL, &cbSID, NULL, &cchDomain, &eUse)) { DWORD dwLastError = GetLastError(); if (ERROR_INSUFFICIENT_BUFFER != dwLastError) return HRESULT_FROM_WIN32(dwLastError); } // Allocate domain name buffer on the task allocation, since we return it DWORD cbDomain = cchDomain * sizeof(WCHAR); TCCoTaskPtr<WCHAR*> spszDomain = (WCHAR*)CoTaskMemAlloc(cbDomain); if (spszDomain.IsNull()) return E_OUTOFMEMORY; // Allocate the SID buffer on the task allocator, since we return it TCCoTaskPtr<PSID> spSID = (PSID)CoTaskMemAlloc(cbSID); if (spSID.IsNull()) return E_OUTOFMEMORY; // Lookup the account name if (!LookupAccountNameW(NULL, szUserName, spSID, &cbSID, spszDomain, &cchDomain, &eUse)) return HRESULT_FROM_WIN32(GetLastError()); // Copy the SID to the [out] parameter if (ppSID) *ppSID = spSID.Detach(); // Copy the domain string to the [out] parameter if (ppszDomain) *ppszDomain = spszDomain.Detach(); // Indicate success return S_OK; }
static int GetSidW(PSID *psid, const wchar_t *user) { wchar_t *refDomain = NULL; DWORD refDomainSize = 0; DWORD sidSize = 0; SID_NAME_USE peUse; int exitCode = 1; /* * Retrieve SID's size */ LookupAccountNameW(NULL, user, NULL, &sidSize, NULL, &refDomainSize, &peUse); FAIL(GetLastError() != ERROR_INSUFFICIENT_BUFFER); /* * Allocate buffer and retrieve SID */ *psid = (PSID) LocalAlloc(LPTR, sidSize); refDomain = (wchar_t *) LocalAlloc(LPTR, refDomainSize * sizeof(wchar_t)); FAIL(LookupAccountNameW(NULL, user, *psid, &sidSize, refDomain, &refDomainSize, &peUse) == FALSE); exitCode = 0; fail: /* * We don't need reference domain. */ if (refDomain) { LocalFree(refDomain); } if (exitCode != 0) { debug("ERROR. Cannot retrieve SID (%u).", GetLastError()); } return exitCode; }
// https://ru.wikipedia.org/wiki/DACL BOOL GetSidByName(WCHAR* wchUserName, PSID* lpSid, DWORD* dwSidLength) { DWORD dwLengthOfDomainName = 0; // длина имени домена LPTSTR lpDomainName = NULL; // указатель на имя домена SID_NAME_USE typeOfSid; // тип учетной записи DWORD LastError; if (!LookupAccountNameW(NULL, wchUserName, NULL, dwSidLength, NULL, &dwLengthOfDomainName, &typeOfSid)) { LastError = GetLastError(); if (LastError == ERROR_INSUFFICIENT_BUFFER) { *lpSid = (SID*)malloc(*dwSidLength); lpDomainName = (LPTSTR)malloc(dwLengthOfDomainName * sizeof(WCHAR)); if (!LookupAccountNameW(NULL, wchUserName, *lpSid, dwSidLength, lpDomainName, &dwLengthOfDomainName, &typeOfSid)) { free(*lpSid); free(lpDomainName); DebugOut("LookupAccountNameW[2](..., %S,...) failed! (LastError=0x%x)\n", wchUserName, GetLastError()); return FALSE; } } else { DebugOut("LookupAccountNameW[1](..., %S,...) failed! (LastError=0x%x)\n", wchUserName, LastError); return FALSE; } } free(lpDomainName); return TRUE; }
void TestLookupNameW( LPWSTR Name ) { // // LookupAccountNameW test // BOOL Bool; DWORD cbSid = 0; UCHAR Sid[BUFFER_SIZE]; SID_NAME_USE peUse = SidTypeUser; DWORD cbReferencedDomainName = 0; WCHAR ReferencedDomainName[BUFFER_SIZE]; printf(" LookupW call . . . . . . . . . . . . . . . . . "); Bool = LookupAccountNameW( NULL, Name, Sid, &cbSid, ReferencedDomainName, &cbReferencedDomainName, &peUse ); // // Expect failure here // if ( !Bool && GetLastError() != ERROR_INSUFFICIENT_BUFFER ) { printf("** FAILED **\n"); printf(" First call.\n"); printf(" Status: %d\n", GetLastError()); printf(" Sid Length: %d\n", cbSid); printf(" Domain Name Length: %d\n", cbReferencedDomainName); } else { Bool = LookupAccountNameW( NULL, Name, Sid, &cbSid, ReferencedDomainName, &cbReferencedDomainName, &peUse ); if ( !Bool ) { printf("** FAILED **\n"); printf(" Second call.\n"); printf(" Status: %d\n", GetLastError()); printf(" Sid Length: %d\n", cbSid); printf(" Domain Name Length: %d\n", cbReferencedDomainName); } else { printf("Succeeded\n"); printf(" Sid Length: %d\n", cbSid); printf(" Sid: "); DisplayAccountSid( Sid ); printf("\n"); printf(" Domain Name Length: %d\n", cbReferencedDomainName); printf(" Domain Name: *"); DumpWCharString( ReferencedDomainName ); printf("*\n"); printf(" Use: "); DisplayUse( peUse ); printf("\n\n"); } } }
int __cdecl wmain( int argc, wchar_t *argv[] ) { LPWSTR DirectoryToShare; LPWSTR Sharename; LPWSTR Username; LPWSTR Server; PSID pSid = NULL; DWORD cbSid; WCHAR RefDomain[DNLEN + 1]; DWORD cchDomain = DNLEN + 1; SID_NAME_USE peUse; SECURITY_DESCRIPTOR sd; PACL pDacl = NULL; DWORD dwAclSize; SHARE_INFO_502 si502; NET_API_STATUS nas; BOOL bSuccess = FALSE; // assume this function fails if(argc < 4) { printf("Usage: %ls <directory> <sharename> <user/group> [\\\\Server]\n", argv[0]); printf(" directory is fullpath of directory to share\n"); printf(" sharename is name of share on server\n"); printf(" user/group is an WinNT user/groupname (REDMOND\\sfield, Administrators, etc)\n"); printf(" optional Server is the name of the computer to create the share on\n"); printf("\nExample: %ls c:\\public public Everyone\n", argv[0]); printf("c:\\public shared as public granting Everyone full access\n"); printf("\nExample: %ls c:\\private cool$ REDMOND\\sfield \\\\WINBASE\n", argv[0]); printf("c:\\private on \\\\WINBASE shared as cool$ (hidden) granting REDMOND\\sfield access\n"); return RTN_USAGE; } // // since the commandline was Unicode, just provide pointers to // the relevant items // DirectoryToShare = argv[1]; Sharename = argv[2]; Username = argv[3]; if( argc > 4 ) { Server = argv[4]; } else { Server = NULL; // local machine } // // initial allocation attempt for Sid // #define SID_SIZE 96 cbSid = SID_SIZE; pSid = (PSID)HeapAlloc(GetProcessHeap(), 0, cbSid); if(pSid == NULL) { printf("HeapAlloc error!\n"); return RTN_ERROR; } // // get the Sid associated with the supplied user/group name // force Unicode API since we always pass Unicode string // if(!LookupAccountNameW( NULL, // default lookup logic Username, // user/group of interest from commandline pSid, // Sid buffer &cbSid, // size of Sid RefDomain, // Domain account found on (unused) &cchDomain, // size of domain in chars &peUse )) { // // if the buffer wasn't large enough, try again // if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { PSID psidTemp; psidTemp = (PSID)HeapReAlloc(GetProcessHeap(), 0, pSid, cbSid); if(psidTemp == NULL) { printf("HeapReAlloc error!\n"); goto cleanup; } else { pSid = psidTemp; } cchDomain = DNLEN + 1; if(!LookupAccountNameW( NULL, // default lookup logic Username, // user/group of interest from commandline pSid, // Sid buffer &cbSid, // size of Sid RefDomain, // Domain account found on (unused) &cchDomain, // size of domain in chars &peUse )) { printf("LookupAccountName error! (rc=%lu)\n", GetLastError()); goto cleanup; } } else { printf("LookupAccountName error! (rc=%lu)\n", GetLastError()); goto cleanup; } } // // compute size of new acl // dwAclSize = sizeof(ACL) + 1 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) + GetLengthSid(pSid) ; // // allocate storage for Acl // pDacl = (PACL)HeapAlloc(GetProcessHeap(), 0, dwAclSize); if(pDacl == NULL) goto cleanup; if(!InitializeAcl(pDacl, dwAclSize, ACL_REVISION)) goto cleanup; // // grant GENERIC_ALL (Full Control) access // if(!AddAccessAllowedAce( pDacl, ACL_REVISION, GENERIC_ALL, pSid )) goto cleanup; if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) goto cleanup; if(!SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE)) { fprintf(stderr, "SetSecurityDescriptorDacl error! (rc=%lu)\n", GetLastError()); goto cleanup; } // // setup share info structure // si502.shi502_netname = (LMSTR) Sharename; si502.shi502_type = STYPE_DISKTREE; si502.shi502_remark = NULL; si502.shi502_permissions = 0; si502.shi502_max_uses = SHI_USES_UNLIMITED; si502.shi502_current_uses = 0; si502.shi502_path = (LMSTR) DirectoryToShare; si502.shi502_passwd = NULL; si502.shi502_reserved = 0; si502.shi502_security_descriptor = &sd; nas = NetShareAdd( (LMSTR) Server, // share is on local machine 502, // info-level (LPBYTE)&si502, // info-buffer NULL // don't bother with parm ); if(nas != NO_ERROR) { printf("NetShareAdd error! (rc=%lu)\n", nas); goto cleanup; } bSuccess = TRUE; // indicate success cleanup: // // free allocated resources // if(pDacl != NULL) HeapFree(GetProcessHeap(), 0, pDacl); if(pSid != NULL) HeapFree(GetProcessHeap(), 0, pSid); if(!bSuccess) { return RTN_ERROR; } return RTN_OK; }
Private(const QString &name, PSID sid_ = 0) : userInfo(0), sid(NULL) { LPBYTE servername; NET_API_STATUS status = NetGetAnyDCName(0, 0, &servername); if (status != NERR_Success) { servername = NULL; } if (NetUserGetInfo((LPCWSTR) servername, (LPCWSTR) name.utf16(), 11, (LPBYTE *) &userInfo) != NERR_Success) { goto error; } if (servername) { NetApiBufferFree(servername); servername = 0; } if (!sid_) { DWORD size = 0; SID_NAME_USE nameuse; DWORD cchReferencedDomainName = 0; WCHAR* referencedDomainName = NULL; // the following line definitely fails: // both the sizes for sid and for referencedDomainName are Null // the needed sizes are set in size and cchReferencedDomainName LookupAccountNameW(NULL, (LPCWSTR) name.utf16(), sid, &size, referencedDomainName, &cchReferencedDomainName, &nameuse); sid = (PSID) new SID[size + 1]; referencedDomainName = new WCHAR[cchReferencedDomainName + 1]; if (!LookupAccountNameW(NULL, (LPCWSTR) name.utf16(), sid, &size, referencedDomainName, &cchReferencedDomainName, &nameuse)) { delete[] referencedDomainName; goto error; } // if you want to see both the DomainName and the sid of the user // uncomment the following lines /* LPWSTR sidstring; ConvertSidToStringSidW(sid, &sidstring); qDebug() << QString("\\\\") + QString::fromUtf16(reinterpret_cast<ushort*>(referencedDomainName)) + \ "\\" + name + "(" + QString::fromUtf16(reinterpret_cast<ushort*>(sidstring)) + ")"; LocalFree(sidstring);*/ delete[] referencedDomainName; } else { if (!IsValidSid(sid_)) goto error; DWORD sidlength = GetLengthSid(sid_); sid = (PSID) new BYTE[sidlength]; if (!CopySid(sidlength, sid, sid_)) goto error; } return; error: delete[] sid; sid = 0; if (userInfo) { NetApiBufferFree(userInfo); userInfo = 0; } if (servername) { NetApiBufferFree(servername); servername = 0; } }
static void enum_groups (domlist_t *mach, const char *sep, DWORD id_offset, char *disp_groupname, int print_current) { WCHAR machine[INTERNET_MAX_HOST_NAME_LENGTH + 1]; GROUP_INFO_2 *buffer; DWORD entriesread = 0; DWORD totalentries = 0; DWORD_PTR resume_handle = 0; WCHAR gname[GNLEN + 1]; DWORD rc; int ret = mbstowcs (machine, mach->str, INTERNET_MAX_HOST_NAME_LENGTH + 1); if (ret < 1 || ret >= INTERNET_MAX_HOST_NAME_LENGTH + 1) { fprintf (stderr, "%s: Invalid machine name '%s'. Skipping...\n", program_invocation_short_name, mach->str); return; } do { DWORD i; if (disp_groupname != NULL) { mbstowcs (gname, disp_groupname, GNLEN + 1); rc = NetGroupGetInfo (machine, (LPWSTR) & gname, 2, (void *) &buffer); entriesread=1; /* Avoid annoying error messages just because the group hasn't been found. */ if (rc == NERR_GroupNotFound) return; } else rc = NetGroupEnum (machine, 2, (void *) & buffer, MAX_PREFERRED_LENGTH, &entriesread, &totalentries, &resume_handle); switch (rc) { case ERROR_ACCESS_DENIED: print_win_error (rc); return; case ERROR_MORE_DATA: case ERROR_SUCCESS: break; default: print_win_error (rc); return; } for (i = 0; i < entriesread; i++) { WCHAR domain_name[MAX_DOMAIN_NAME_LEN + 1]; DWORD domname_len = MAX_DOMAIN_NAME_LEN + 1; char psid_buffer[MAX_SID_LEN]; PSID psid = (PSID) psid_buffer; DWORD sid_length = MAX_SID_LEN; SID_NAME_USE acc_type; int gid = buffer[i].grpi2_group_id; if (!LookupAccountNameW (machine, buffer[i].grpi2_name, psid, &sid_length, domain_name, &domname_len, &acc_type)) { print_win_error (GetLastError ()); fprintf(stderr, " (%ls)\n", buffer[i].grpi2_name); continue; } else if (acc_type == SidTypeDomain) { WCHAR domname[MAX_DOMAIN_NAME_LEN + GNLEN + 2]; wcscpy (domname, machine); wcscat (domname, L"\\"); wcscat (domname, buffer[i].grpi2_name); sid_length = MAX_SID_LEN; domname_len = MAX_DOMAIN_NAME_LEN + 1; if (!LookupAccountNameW (machine, domname, psid, &sid_length, domain_name, &domname_len, &acc_type)) { print_win_error (GetLastError ()); fprintf(stderr, " (%ls)\n", domname); continue; } } if (!print_current) /* fall through */; else if (EqualSid (curr_pgrp.psid, psid)) got_curr_pgrp = TRUE; printf ("%ls%s%ls:%s:%" PRIu32 ":\n", mach->with_dom ? domain_name : L"", mach->with_dom ? sep : "", buffer[i].grpi2_name, put_sid (psid), (unsigned int) (id_offset + gid)); } NetApiBufferFree (buffer); } while (rc == ERROR_MORE_DATA); }
static int enum_local_groups (domlist_t *mach, const char *sep, DWORD id_offset, char *disp_groupname, int print_builtin, int print_current) { WCHAR machine[INTERNET_MAX_HOST_NAME_LENGTH + 1]; LOCALGROUP_INFO_0 *buffer; DWORD entriesread = 0; DWORD totalentries = 0; DWORD_PTR resume_handle = 0; WCHAR gname[GNLEN + 1]; DWORD rc; int ret = mbstowcs (machine, mach->str, INTERNET_MAX_HOST_NAME_LENGTH + 1); if (ret < 1 || ret >= INTERNET_MAX_HOST_NAME_LENGTH + 1) { fprintf (stderr, "%s: Invalid machine name '%s'. Skipping...\n", program_invocation_short_name, mach->str); return 1; } do { DWORD i; if (disp_groupname) { mbstowcs (gname, disp_groupname, GNLEN + 1); rc = NetLocalGroupGetInfo (machine, gname, 0, (void *) &buffer); if (rc == ERROR_SUCCESS) entriesread = 1; /* Allow further searching for the group and avoid annoying error messages just because the group is not a local group or the group hasn't been found. */ else if (rc == ERROR_NO_SUCH_ALIAS || rc == NERR_GroupNotFound) return 0; } else rc = NetLocalGroupEnum (machine, 0, (void *) &buffer, MAX_PREFERRED_LENGTH, &entriesread, &totalentries, &resume_handle); switch (rc) { case ERROR_ACCESS_DENIED: print_win_error (rc); return 1; case ERROR_MORE_DATA: case ERROR_SUCCESS: break; default: print_win_error (rc); return 1; } for (i = 0; i < entriesread; i++) { WCHAR domain_name[MAX_DOMAIN_NAME_LEN + 1]; DWORD domname_len = MAX_DOMAIN_NAME_LEN + 1; char psid_buffer[MAX_SID_LEN]; PSID psid = (PSID) psid_buffer; DWORD sid_length = MAX_SID_LEN; DWORD gid; SID_NAME_USE acc_type; PDBGSID pdsid; BOOL is_builtin = FALSE; if (!LookupAccountNameW (machine, buffer[i].lgrpi0_name, psid, &sid_length, domain_name, &domname_len, &acc_type)) { print_win_error (GetLastError ()); fprintf (stderr, " (%ls)\n", buffer[i].lgrpi0_name); continue; } else if (acc_type == SidTypeDomain) { WCHAR domname[MAX_DOMAIN_NAME_LEN + GNLEN + 2]; wcscpy (domname, domain_name); wcscat (domname, L"\\"); wcscat (domname, buffer[i].lgrpi0_name); sid_length = MAX_SID_LEN; domname_len = MAX_DOMAIN_NAME_LEN + 1; if (!LookupAccountNameW (machine, domname, psid, &sid_length, domain_name, &domname_len, &acc_type)) { print_win_error (GetLastError ()); fprintf(stderr, " (%ls)\n", domname); continue; } } /* Store all local SIDs with prefix "S-1-5-32-" and check if it has been printed already. This allows to get all builtin groups exactly once and not once per domain. */ pdsid = (PDBGSID) psid; if (pdsid->IdentifierAuthority.Value[5] == sid_nt_auth.Value[5] && pdsid->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID) { int b; if (!print_builtin) goto skip_group; is_builtin = TRUE; if (builtin_sid_cnt) for (b = 0; b < builtin_sid_cnt; b++) if (EqualSid (&builtin_sid_list[b], psid)) goto skip_group; if (builtin_sid_cnt < MAX_BUILTIN_SIDS) CopySid (sizeof (DBGSID), &builtin_sid_list[builtin_sid_cnt++], psid); } if (!print_current) /* fall through */; else if (EqualSid (curr_pgrp.psid, psid)) got_curr_pgrp = TRUE; gid = *GetSidSubAuthority (psid, *GetSidSubAuthorityCount(psid) - 1); printf ("%ls%s%ls:%s:%" PRIu32 ":\n", mach->with_dom && !is_builtin ? domain_name : L"", mach->with_dom || is_builtin ? sep : "", buffer[i].lgrpi0_name, put_sid (psid), (unsigned int) (gid + (is_builtin ? 0 : id_offset))); skip_group: ; } NetApiBufferFree (buffer); } while (rc == ERROR_MORE_DATA); /* Return 1 if the single group we're looking for has been found here to avoid calling enum_groups for the same group, thus avoiding a spurious error message "group name could not be found" in enum_groups. */ return disp_groupname && entriesread ? 1 : 0; }
static void enum_unix_groups (domlist_t *mach, const char *sep, DWORD id_offset, char *unix_grp_list) { WCHAR machine[INTERNET_MAX_HOST_NAME_LENGTH + 1]; SID_IDENTIFIER_AUTHORITY auth = { { 0, 0, 0, 0, 0, 22 } }; char *gstr, *grp_list; WCHAR grp[GNLEN + sizeof ("Unix Group\\") + 1]; WCHAR dom[MAX_DOMAIN_NAME_LEN + 1]; DWORD glen, dlen, sidlen; PSID psid; char psid_buffer[MAX_SID_LEN]; SID_NAME_USE acc_type; int ret = mbstowcs (machine, mach->str, INTERNET_MAX_HOST_NAME_LENGTH + 1); if (ret < 1 || ret >= INTERNET_MAX_HOST_NAME_LENGTH + 1) { fprintf (stderr, "%s: Invalid machine name '%s'. Skipping...\n", program_invocation_short_name, mach->str); return; } if (!AllocateAndInitializeSid (&auth, 2, 2, 0, 0, 0, 0, 0, 0, 0, &psid)) return; if (!(grp_list = strdup (unix_grp_list))) { FreeSid (psid); return; } for (gstr = strtok (grp_list, ","); gstr; gstr = strtok (NULL, ",")) { if (!isdigit ((unsigned char) gstr[0]) && gstr[0] != '-') { PWCHAR p = wcpcpy (grp, L"Unix Group\\"); ret = mbstowcs (p, gstr, GNLEN + 1); if (ret < 1 || ret >= GNLEN + 1) fprintf (stderr, "%s: Invalid group name '%s'. Skipping...\n", program_invocation_short_name, gstr); else if (LookupAccountNameW (machine, grp, psid = (PSID) psid_buffer, (sidlen = MAX_SID_LEN, &sidlen), dom, (dlen = MAX_DOMAIN_NAME_LEN + 1, &dlen), &acc_type)) printf ("%s%s%ls:%s:%" PRIu32 ":\n", mach->with_dom ? "Unix_Group" : "", mach->with_dom ? sep : "", p, put_sid (psid), (unsigned int) (id_offset + *GetSidSubAuthority (psid, *GetSidSubAuthorityCount(psid) - 1))); } else { DWORD start, stop; char *p = gstr; if (*p == '-') start = 0; else start = strtol (p, &p, 10); if (!*p) stop = start; else if (*p++ != '-' || !isdigit ((unsigned char) *p) || (stop = strtol (p, &p, 10)) < start || *p) { fprintf (stderr, "%s: Malformed unix group list entry '%s'. " "Skipping...\n", program_invocation_short_name, gstr); continue; } for (; start <= stop; ++ start) { *GetSidSubAuthority (psid, *GetSidSubAuthorityCount(psid) - 1) = start; if (LookupAccountSidW (machine, psid, grp, (glen = GNLEN + 1, &glen), dom, (dlen = MAX_DOMAIN_NAME_LEN + 1, &dlen), &acc_type) && !iswdigit (grp[0])) printf ("%s%s%ls:%s:%" PRIu32 ":\n", mach->with_dom ? "Unix_Group" : "", mach->with_dom ? sep : "", grp, put_sid (psid), (unsigned int) (id_offset + start)); } } } free (grp_list); FreeSid (psid); }
static int collect_access_rights(probe_ctx *ctx, WCHAR *security_principle, bool include_group, bool resolve_group) { char *security_principle_str = oscap_windows_wstr_to_str(security_principle); LSA_OBJECT_ATTRIBUTES object_attributes; ZeroMemory(&object_attributes, sizeof(LSA_OBJECT_ATTRIBUTES)); LSA_HANDLE lsa_policy_handle; NTSTATUS status = LsaOpenPolicy(NULL, &object_attributes, POLICY_LOOKUP_NAMES, &lsa_policy_handle); if (status != STATUS_SUCCESS) { DWORD err = LsaNtStatusToWinError(status); char *error_message = oscap_windows_error_message(err); dD("LsaOpenPolicy failed for principle '%s': %s", security_principle_str, error_message); free(error_message); free(security_principle_str); return 1; } /* Convert the value of the security_principle element to a SID. */ DWORD sid_len = 0; DWORD domain_name_len = 0; SID_NAME_USE sid_type; LookupAccountNameW(NULL, security_principle, NULL, &sid_len, NULL, &domain_name_len, &sid_type); SID *sid = malloc(sid_len); WCHAR *domain_name = malloc(domain_name_len * sizeof(WCHAR)); if (!LookupAccountNameW(NULL, security_principle, sid, &sid_len, domain_name, &domain_name_len, &sid_type)) { DWORD err = GetLastError(); char *error_message = oscap_windows_error_message(err); dD("LookupAccountNameW failed for '%s': %s", security_principle_str, error_message); free(error_message); free(security_principle_str); free(sid); free(domain_name); return 1; } /* Is it a group? */ if (sid_type == SidTypeGroup || sid_type == SidTypeWellKnownGroup || sid_type == SidTypeAlias) { if (resolve_group) { struct oscap_list *group_members_list = oscap_list_new(); get_local_group_members(security_principle, group_members_list); get_global_group_members(security_principle, group_members_list); struct oscap_iterator *group_members_it = oscap_iterator_new(group_members_list); while (oscap_iterator_has_more(group_members_it)) { WCHAR *group_member = oscap_iterator_next(group_members_it); collect_access_rights(ctx, group_member, include_group, resolve_group); } oscap_iterator_free(group_members_it); oscap_list_free(group_members_list, free); } if (!include_group) { free(sid); free(domain_name); free(security_principle_str); return 0; } } /* Users and groups can inherit their privileges from their parents */ struct oscap_list *every_rights_sources = oscap_list_new(); oscap_list_add(every_rights_sources, wcsdup(security_principle)); get_user_local_groups(security_principle, every_rights_sources); get_user_global_groups(security_principle, every_rights_sources); /* Iterate over the items */ bool privileges_enabled[OVAL_PRIVILEGES_COUNT] = { false }; struct oscap_iterator *it = oscap_iterator_new(every_rights_sources); while (oscap_iterator_has_more(it)) { WCHAR *account_name = oscap_iterator_next(it); DWORD account_sid_len = 0; DWORD account_domain_name_len = 0; SID_NAME_USE account_sid_type; LookupAccountNameW(NULL, account_name, NULL, &account_sid_len, NULL, &account_domain_name_len, &account_sid_type); SID *account_sid = malloc(account_sid_len); WCHAR *account_domain_name = malloc(account_domain_name_len * sizeof(WCHAR)); if (!LookupAccountNameW(NULL, account_name, account_sid, &account_sid_len, account_domain_name, &account_domain_name_len, &account_sid_type)) { free(account_sid); free(account_domain_name); DWORD err = GetLastError(); char *error_message = oscap_windows_error_message(err); dD("LookupAccountNameW failed for '%s': %s", security_principle_str, error_message); free(error_message); free(security_principle_str); return 1; } LSA_UNICODE_STRING *granted_rights = NULL; ULONG granted_rights_count = 0; status = LsaEnumerateAccountRights(lsa_policy_handle, account_sid, &granted_rights, &granted_rights_count); if (status != STATUS_SUCCESS) { free(account_sid); free(account_domain_name); DWORD err = LsaNtStatusToWinError(status); char *error_message = oscap_windows_error_message(err); dD("LsaEnumerateAccountRights failed for '%s': %s", security_principle_str, error_message); free(error_message); /* We should not exit here, because when LsaEnumerateAccountRights * failed it can mean that the entity simply doesn't have any specific * privileges, it only inhertis privileges form its parent group(s). */ continue; } for (int i = 0; i < OVAL_PRIVILEGES_COUNT; i++) { if (!privileges_enabled[i]) { for (ULONG j = 0; j < granted_rights_count; j++) { if (wcscmp(granted_rights[j].Buffer, privileges_texts[i]) == 0) { privileges_enabled[i] = true; break; } } } } LsaFreeMemory(granted_rights); free(account_sid); free(account_domain_name); } oscap_iterator_free(it); oscap_list_free(every_rights_sources, free); /* Collect the OVAL item */ SEXP_t *item = probe_item_create(OVAL_WINDOWS_ACCESS_TOKEN, NULL, "security_principle", OVAL_DATATYPE_STRING, strdup(security_principle_str), NULL); for (int i = 0; i < OVAL_PRIVILEGES_COUNT; i++) { char *privilege_name = oscap_windows_wstr_to_str(privileges_texts[i]); /* Convert the element name to lowercase */ for (char *p = privilege_name; *p; p++) { *p = tolower(*p); } SEXP_t *privilege_value = SEXP_number_newb(privileges_enabled[i]); probe_item_ent_add(item, privilege_name, NULL, privilege_value); free(privilege_name); SEXP_free(privilege_value); } probe_item_collect(ctx, item); free(security_principle_str); return 0; }
// Calling function is responsible for freeing ppszSID using LocalAlloc HRESULT WpcuSidStringFromUserName(PCWSTR pcszUserName, PWSTR* ppszSID) { HRESULT hr = E_INVALIDARG; if (pcszUserName && ppszSID) { DWORD cbSID = 0, cchDomain = 0; SID_NAME_USE SidNameUse; // Call twice, first with null SID buffer. Retrieves required buffer // size for domain name LookupAccountNameW(NULL, pcszUserName, NULL, &cbSID, NULL, &cchDomain, &SidNameUse); if (!cbSID || !cchDomain) { hr = E_FAIL; } else { WCHAR* pszDomain = NULL; // Allocate properly sized buffer (with termination character) // for domain name pszDomain = new WCHAR[cchDomain]; if (!pszDomain) { hr = E_OUTOFMEMORY; } else { // Allocate properly sized buffer (with termination character) // for PSID PSID pSID = static_cast<PSID> (new BYTE[cbSID]); //(LocalAlloc (LMEM_FIXED, cbSID)); if (!pSID) { hr = E_OUTOFMEMORY; } else { // Second call with buffers allocated and sizes set if (!LookupAccountName(NULL, pcszUserName, pSID, &cbSID, pszDomain, &cchDomain, &SidNameUse)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { // Convert PSID to SID string if (!ConvertSidToStringSidW(pSID, ppszSID)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { hr = S_OK; } } delete[] pSID; // (LocalFree (pSID); } delete[] pszDomain; } } } return (hr); }