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