Skip to content

Commit f79a084

Browse files
committed
implement GetProcessPrivileges()
It's the first step towards IsSymlinkCreationAllowed().
1 parent a10c2fe commit f79a084

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

Win32.pm

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,25 @@ information about what you can do with this address has been lost in
12331233
the mist of time. Use the Win32::API module instead of this deprecated
12341234
function.
12351235
1236+
=item Win32::GetProcessPrivileges([PID])
1237+
1238+
Returns a reference to a hash holding the information about the privileges
1239+
held by the specified process. The keys are privilege names, and the values
1240+
are booleans indicating whether a given privilege is currently enabled or not.
1241+
1242+
If the optional PID parameter is omitted, the function queries the current
1243+
process.
1244+
1245+
Example return value:
1246+
1247+
{
1248+
SeTimeZonePrivilege => 0,
1249+
SeShutdownPrivilege => 0,
1250+
SeUndockPrivilege => 0,
1251+
SeIncreaseWorkingSetPrivilege => 0,
1252+
SeChangeNotifyPrivilege => 1
1253+
}
1254+
12361255
=item Win32::GetProductInfo(OSMAJOR, OSMINOR, SPMAJOR, SPMINOR)
12371256
12381257
Retrieves the product type for the operating system on the local

Win32.xs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,92 @@ XS(w32_SetConsoleOutputCP)
15571557
XSRETURN_IV(SetConsoleOutputCP((int)SvIV(ST(0))));
15581558
}
15591559

1560+
XS(w32_GetProcessPrivileges)
1561+
{
1562+
dXSARGS;
1563+
BOOL ret;
1564+
HV *priv_hv;
1565+
HANDLE proc_handle, token;
1566+
char *priv_name = NULL;
1567+
TOKEN_PRIVILEGES *privs = NULL;
1568+
DWORD i, pid, priv_name_len = 100, privs_len = 300;
1569+
1570+
if (items > 1)
1571+
Perl_croak(aTHX_ "usage: Win32::GetProcessPrivileges([$pid])");
1572+
1573+
if (items == 0) {
1574+
EXTEND(SP, 1);
1575+
pid = GetCurrentProcessId();
1576+
}
1577+
else {
1578+
pid = (DWORD)SvUV(ST(0));
1579+
}
1580+
1581+
proc_handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
1582+
1583+
if (!proc_handle)
1584+
XSRETURN_NO;
1585+
1586+
ret = OpenProcessToken(proc_handle, TOKEN_QUERY, &token);
1587+
CloseHandle(proc_handle);
1588+
1589+
if (!ret)
1590+
XSRETURN_NO;
1591+
1592+
do {
1593+
Renewc(privs, privs_len, char, TOKEN_PRIVILEGES);
1594+
ret = GetTokenInformation(
1595+
token, TokenPrivileges, privs, privs_len, &privs_len
1596+
);
1597+
} while (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
1598+
1599+
CloseHandle(token);
1600+
1601+
if (!ret) {
1602+
Safefree(privs);
1603+
XSRETURN_NO;
1604+
}
1605+
1606+
priv_hv = newHV();
1607+
New(0, priv_name, priv_name_len, char);
1608+
1609+
for (i = 0; i < privs->PrivilegeCount; ++i) {
1610+
DWORD ret_len = 0;
1611+
LUID_AND_ATTRIBUTES *priv = &privs->Privileges[i];
1612+
BOOL is_enabled = !!(priv->Attributes & SE_PRIVILEGE_ENABLED);
1613+
1614+
if (priv->Attributes & SE_PRIVILEGE_REMOVED)
1615+
continue;
1616+
1617+
do {
1618+
ret_len = priv_name_len;
1619+
ret = LookupPrivilegeNameA(
1620+
NULL, &priv->Luid, priv_name, &ret_len
1621+
);
1622+
1623+
if (ret_len > priv_name_len) {
1624+
priv_name_len = ret_len + 1;
1625+
Renew(priv_name, priv_name_len, char);
1626+
}
1627+
} while (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
1628+
1629+
if (!ret) {
1630+
SvREFCNT_dec((SV*)priv_hv);
1631+
Safefree(privs);
1632+
Safefree(priv_name);
1633+
XSRETURN_NO;
1634+
}
1635+
1636+
hv_store(priv_hv, priv_name, ret_len, newSViv(is_enabled), 0);
1637+
}
1638+
1639+
Safefree(privs);
1640+
Safefree(priv_name);
1641+
1642+
ST(0) = sv_2mortal(newRV_noinc((SV*)priv_hv));
1643+
XSRETURN(1);
1644+
}
1645+
15601646
MODULE = Win32 PACKAGE = Win32
15611647

15621648
PROTOTYPES: DISABLE
@@ -1626,6 +1712,7 @@ BOOT:
16261712
newXS("Win32::GetOEMCP", w32_GetOEMCP, file);
16271713
newXS("Win32::SetConsoleCP", w32_SetConsoleCP, file);
16281714
newXS("Win32::SetConsoleOutputCP", w32_SetConsoleOutputCP, file);
1715+
newXS("Win32::GetProcessPrivileges", w32_GetProcessPrivileges, file);
16291716
#ifdef __CYGWIN__
16301717
newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
16311718
#endif

t/Privileges.t

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use strict;
2+
use warnings;
3+
4+
use Test;
5+
use Win32;
6+
7+
plan tests => 4;
8+
9+
ok(ref(Win32::GetProcessPrivileges) eq 'HASH');
10+
ok(ref(Win32::GetProcessPrivileges(Win32::GetCurrentProcessId())) eq 'HASH');
11+
12+
# All Windows PIDs are divisible by 4. It's an undocumented implementation
13+
# detail, but it means it's extremely unlikely that the PID below is valid.
14+
ok(!Win32::GetProcessPrivileges(3423237));
15+
16+
my $whoami = `whoami /priv 2>&1`;
17+
my $skip = ($? == -1 || $? >> 8) ? '"whoami" command is missing' : 0;
18+
19+
skip($skip, sub{
20+
my $privs = Win32::GetProcessPrivileges();
21+
22+
while ($whoami =~ /^(Se\w+)/mg) {
23+
return 0 unless exists $privs->{$1};
24+
}
25+
26+
return 1;
27+
});

0 commit comments

Comments
 (0)