97dbd4a4c61a13bfad128b86ce943f6a7edccead
[claws.git] / src / common / w32_account.c
1 /* w32_account.c - Account related W32 functions.
2    Copyright (C) 2007 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
40 #include "w32lib.h"
41
42 #ifndef DIM
43 #define DIM(v)  (sizeof(v)/sizeof((v)[0]))
44 #endif
45
46
47 /* Return a malloced name of our user group.  */
48 static char *
49 get_group_name (void)
50 {
51   HANDLE        hThread;
52   TOKEN_GROUPS  *ptg = NULL;
53   DWORD         cbTokenGroups;
54   DWORD         i, j;
55   SID_IDENTIFIER_AUTHORITY SystemSidAuthority = { SECURITY_NT_AUTHORITY };
56   char *group;
57   struct
58   {
59     DWORD auth_id;
60     char *name;
61   } groups[] = 
62     {
63       /* Every user belongs to the users group, hence
64          users comes before guests */
65       {DOMAIN_ALIAS_RID_USERS, "User"},
66       {DOMAIN_ALIAS_RID_GUESTS, "Guest"},
67       {DOMAIN_ALIAS_RID_POWER_USERS, "Power"},
68       {DOMAIN_ALIAS_RID_ADMINS, "Admin"}
69     };
70
71
72   group = NULL;
73   if (GetVersion() & 0x80000000) 
74     {
75       /* This is not NT; thus we are always Admin. */
76       group = "Admin";
77     }
78   else if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hThread) 
79            || OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hThread))
80     {
81       /* With the token for the current thread or process in hand we
82          query the size of the associated group information.  Note
83          that we expect an error because buffer has been passed as
84          NULL. cbTokenGroups will then tell use the required size.  */
85       if (!GetTokenInformation (hThread, TokenGroups, NULL, 0, &cbTokenGroups)
86           && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
87         {
88           ptg = GlobalAlloc (GPTR, cbTokenGroups);
89           if (ptg)
90             {
91               if (GetTokenInformation ( hThread, TokenGroups, ptg,
92                                         cbTokenGroups, &cbTokenGroups))
93                 {
94
95                   /* Now iterate through the list of groups for this
96                      access token looking for a match against the SID
97                      we created above. */
98                   for (i = 0; i < DIM (groups); i++)
99                     {
100                       PSID psid = 0;
101                       
102                       AllocateAndInitializeSid (&SystemSidAuthority,
103                                                 2,
104                                                 SECURITY_BUILTIN_DOMAIN_RID,
105                                                 groups[i].auth_id,
106                                                 0, 0, 0, 0, 0, 0,
107                                                 &psid);
108                       if (!psid) 
109                         continue;
110                       for (j = 0; j < ptg->GroupCount; j++)
111                         if (EqualSid(ptg->Groups[j].Sid, psid))
112                           group = groups[i].name;
113                       FreeSid(psid);
114                     }
115                 }
116               
117               GlobalFree(ptg);
118             }
119         }
120       
121       CloseHandle(hThread);
122     }
123
124   return group? strdup (group):NULL;
125 }
126
127
128 /* Return true if we are an administrator.  The chekc is done only
129    once so if the current user has been hadded to the Administrator
130    group the process needs to be rerstarted. */
131 int
132 w32_is_administrator (void)
133 {
134   static int got_it;
135   static int is_admin;
136
137   if (!got_it)
138     {
139       char *name = get_group_name ();
140
141       if (name && !strcmp (name, "Admin"))
142         is_admin = 1;
143       got_it = 1;
144       free (name);
145     }
146
147   return is_admin;
148 }
149