1 /* w32_account.c - Account related W32 functions.
2 Copyright (C) 2007-2009 g10 Code GmbH
3 Copyright (C) 1999-2005 Nullsoft, Inc.
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any
7 damages arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any
10 purpose, including commercial applications, and to alter it and
11 redistribute it freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must
14 not claim that you wrote the original software. If you use this
15 software in a product, an acknowledgment in the product
16 documentation would be appreciated but is not required.
17
18 2. Altered source versions must be plainly marked as such, and must
19 not be misrepresented as being the original software.
20
21 3. This notice may not be removed or altered from any source
22 distribution.
23
24 =======[ wk 2007-05-21 ]====
25 The code for get_group_name has been taken from NSIS 2.05, module
26 UserInfo.c. NSIS bears the above license and along with the
27 notice:
28 This license applies to everything in the NSIS package, except where
29 otherwise noted.
30 Thus we make this module available under the same license - note,
31 that this lincese is fully compatibe with the GNU GPL 2.0.
32 */
33
34
35
36
37 #include <stdlib.h>
38 #include <string.h>
39 #include <windows.h>
40 #include <sddl.h> // for ConvertSidToStringSid()
41
42 #include "w32lib.h"
43 #include "utils.h"
44
45 #ifndef DIM
46 #define DIM(v) (sizeof(v)/sizeof((v)[0]))
47 #endif
48
49
50 /* Return a malloced name of our user group. */
51 static char *
get_group_name(void)52 get_group_name (void)
53 {
54 HANDLE hThread;
55 TOKEN_GROUPS *ptg = NULL;
56 DWORD cbTokenGroups;
57 DWORD i, j;
58 SID_IDENTIFIER_AUTHORITY SystemSidAuthority = { SECURITY_NT_AUTHORITY };
59 char *group;
60 struct
61 {
62 DWORD auth_id;
63 char *name;
64 } groups[] =
65 {
66 /* Every user belongs to the users group, hence
67 users comes before guests */
68 {DOMAIN_ALIAS_RID_USERS, "User"},
69 {DOMAIN_ALIAS_RID_GUESTS, "Guest"},
70 {DOMAIN_ALIAS_RID_POWER_USERS, "Power"},
71 {DOMAIN_ALIAS_RID_ADMINS, "Admin"}
72 };
73
74
75 group = NULL;
76 if (GetVersion() & 0x80000000)
77 {
78 /* This is not NT; thus we are always Admin. */
79 group = "Admin";
80 }
81 else if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hThread)
82 || OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hThread))
83 {
84 /* With the token for the current thread or process in hand we
85 query the size of the associated group information. Note
86 that we expect an error because buffer has been passed as
87 NULL. cbTokenGroups will then tell use the required size. */
88 if (!GetTokenInformation (hThread, TokenGroups, NULL, 0, &cbTokenGroups)
89 && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
90 {
91 ptg = GlobalAlloc (GPTR, cbTokenGroups);
92 if (ptg)
93 {
94 if (GetTokenInformation ( hThread, TokenGroups, ptg,
95 cbTokenGroups, &cbTokenGroups))
96 {
97
98 /* Now iterate through the list of groups for this
99 access token looking for a match against the SID
100 we created above. */
101 for (i = 0; i < DIM (groups); i++)
102 {
103 PSID psid = 0;
104
105 AllocateAndInitializeSid (&SystemSidAuthority,
106 2,
107 SECURITY_BUILTIN_DOMAIN_RID,
108 groups[i].auth_id,
109 0, 0, 0, 0, 0, 0,
110 &psid);
111 if (!psid)
112 continue;
113 for (j = 0; j < ptg->GroupCount; j++)
114 if (EqualSid(ptg->Groups[j].Sid, psid))
115 group = groups[i].name;
116 FreeSid(psid);
117 }
118 }
119
120 GlobalFree(ptg);
121 }
122 }
123
124 CloseHandle(hThread);
125 }
126
127 return group? strdup (group):NULL;
128 }
129
130
131 /* Return true if we are an administrator. The chekc is done only
132 once so if the current user has been hadded to the Administrator
133 group the process needs to be rerstarted. */
134 int
w32_is_administrator(void)135 w32_is_administrator (void)
136 {
137 static int got_it;
138 static int is_admin;
139
140 if (!got_it)
141 {
142 char *name = get_group_name ();
143
144 if (name && !strcmp (name, "Admin"))
145 is_admin = 1;
146 got_it = 1;
147 free (name);
148 }
149
150 return is_admin;
151 }
152