]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - windows/winsecur.c
Move SID-getting code into a separate function so it can be shared by
[PuTTY.git] / windows / winsecur.c
1 /*
2  * winsecur.c: implementation of winsecur.h.
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7
8 #include "putty.h"
9
10 #if !defined NO_SECURITY
11
12 #define WINSECUR_GLOBAL
13 #include "winsecur.h"
14
15 /* Initialised once, then kept around to reuse forever */
16 static PSID worldsid, networksid, usersid;
17
18
19 int got_advapi(void)
20 {
21     static int attempted = FALSE;
22     static int successful;
23     static HMODULE advapi;
24
25     if (!attempted) {
26         attempted = TRUE;
27         advapi = load_system32_dll("advapi32.dll");
28         successful = advapi &&
29             GET_WINDOWS_FUNCTION(advapi, GetSecurityInfo) &&
30             GET_WINDOWS_FUNCTION(advapi, OpenProcessToken) &&
31             GET_WINDOWS_FUNCTION(advapi, GetTokenInformation) &&
32             GET_WINDOWS_FUNCTION(advapi, InitializeSecurityDescriptor) &&
33             GET_WINDOWS_FUNCTION(advapi, SetSecurityDescriptorOwner) &&
34             GET_WINDOWS_FUNCTION(advapi, SetEntriesInAclA);
35     }
36     return successful;
37 }
38
39 int got_crypt(void)
40 {
41     static int attempted = FALSE;
42     static int successful;
43     static HMODULE crypt;
44
45     if (!attempted) {
46         attempted = TRUE;
47         crypt = load_system32_dll("crypt32.dll");
48         successful = crypt &&
49             GET_WINDOWS_FUNCTION(crypt, CryptProtectMemory);
50     }
51     return successful;
52 }
53
54 PSID get_user_sid(void)
55 {
56     HANDLE proc = NULL, tok = NULL;
57     TOKEN_USER *user = NULL;
58     DWORD toklen, sidlen;
59     PSID sid = NULL, ret = NULL;
60
61     if (!got_advapi())
62         goto cleanup;
63
64     if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE,
65                             GetCurrentProcessId())) == NULL)
66         goto cleanup;
67
68     if (!p_OpenProcessToken(proc, TOKEN_QUERY, &tok))
69         goto cleanup;
70
71     if (!p_GetTokenInformation(tok, TokenUser, NULL, 0, &toklen) &&
72         GetLastError() != ERROR_INSUFFICIENT_BUFFER)
73         goto cleanup;
74
75     if ((user = (TOKEN_USER *)LocalAlloc(LPTR, toklen)) == NULL)
76         goto cleanup;
77
78     if (!p_GetTokenInformation(tok, TokenUser, user, toklen, &toklen))
79         goto cleanup;
80
81     sidlen = GetLengthSid(user->User.Sid);
82
83     sid = (PSID)smalloc(sidlen);
84
85     if (!CopySid(sidlen, sid, user->User.Sid))
86         goto cleanup;
87
88     /* Success. Move sid into the return value slot, and null it out
89      * to stop the cleanup code freeing it. */
90     ret = sid;
91     sid = NULL;
92
93   cleanup:
94     if (proc != NULL)
95         CloseHandle(proc);
96     if (tok != NULL)
97         CloseHandle(tok);
98     if (user != NULL)
99         LocalFree(user);
100     if (sid != NULL)
101         sfree(sid);
102
103     return ret;
104 }
105
106 int getsids(char *error)
107 {
108     SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY;
109     SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
110     int ret;
111
112     error=NULL;
113
114     if (!usersid) {
115         if ((usersid = get_user_sid()) == NULL) {
116             error = dupprintf("unable to construct SID for current user: %s",
117                                win_strerror(GetLastError()));
118             goto cleanup;
119         }
120     }
121
122     if (!worldsid) {
123         if (!AllocateAndInitializeSid(&world_auth, 1, SECURITY_WORLD_RID,
124                                       0, 0, 0, 0, 0, 0, 0, &worldsid)) {
125             error = dupprintf("unable to construct SID for world: %s",
126                                win_strerror(GetLastError()));
127             goto cleanup;
128         }
129     }
130
131     if (!networksid) {
132         if (!AllocateAndInitializeSid(&nt_auth, 1, SECURITY_NETWORK_RID,
133                                       0, 0, 0, 0, 0, 0, 0, &networksid)) {
134             error = dupprintf("unable to construct SID for "
135                                "local same-user access only: %s",
136                                win_strerror(GetLastError()));
137             goto cleanup;
138         }
139     }
140
141     ret=TRUE;
142
143  cleanup:
144     if (ret) {
145       sfree(error);
146       error = NULL;
147     }
148     return ret;
149 }
150   
151
152 int make_private_security_descriptor(DWORD permissions,
153                                      PSECURITY_DESCRIPTOR *psd,
154                                      PACL *acl,
155                                      char **error)
156 {
157     SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY;
158     SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
159     EXPLICIT_ACCESS ea[3];
160     int acl_err;
161     int ret = FALSE;
162
163
164     *psd = NULL;
165     *acl = NULL;
166     *error = NULL;
167
168     if (!getsids(*error))
169       goto cleanup;
170
171     memset(ea, 0, sizeof(ea));
172     ea[0].grfAccessPermissions = permissions;
173     ea[0].grfAccessMode = REVOKE_ACCESS;
174     ea[0].grfInheritance = NO_INHERITANCE;
175     ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
176     ea[0].Trustee.ptstrName = (LPTSTR)worldsid;
177     ea[1].grfAccessPermissions = permissions;
178     ea[1].grfAccessMode = GRANT_ACCESS;
179     ea[1].grfInheritance = NO_INHERITANCE;
180     ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
181     ea[1].Trustee.ptstrName = (LPTSTR)usersid;
182     ea[2].grfAccessPermissions = permissions;
183     ea[2].grfAccessMode = REVOKE_ACCESS;
184     ea[2].grfInheritance = NO_INHERITANCE;
185     ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
186     ea[2].Trustee.ptstrName = (LPTSTR)networksid;
187
188     acl_err = p_SetEntriesInAclA(3, ea, NULL, acl);
189     if (acl_err != ERROR_SUCCESS || *acl == NULL) {
190         *error = dupprintf("unable to construct ACL: %s",
191                            win_strerror(acl_err));
192         goto cleanup;
193     }
194
195     *psd = (PSECURITY_DESCRIPTOR)
196         LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
197     if (!*psd) {
198         *error = dupprintf("unable to allocate security descriptor: %s",
199                            win_strerror(GetLastError()));
200         goto cleanup;
201     }
202
203     if (!InitializeSecurityDescriptor(*psd, SECURITY_DESCRIPTOR_REVISION)) {
204         *error = dupprintf("unable to initialise security descriptor: %s",
205                            win_strerror(GetLastError()));
206         goto cleanup;
207     }
208
209     if (!SetSecurityDescriptorOwner(*psd, usersid, FALSE)) {
210         *error = dupprintf("unable to set owner in security descriptor: %s",
211                            win_strerror(GetLastError()));
212         goto cleanup;
213     }
214
215     if (!SetSecurityDescriptorDacl(*psd, TRUE, *acl, FALSE)) {
216         *error = dupprintf("unable to set DACL in security descriptor: %s",
217                            win_strerror(GetLastError()));
218         goto cleanup;
219     }
220
221     ret = TRUE;
222
223   cleanup:
224     if (!ret) {
225         if (*psd) {
226             LocalFree(*psd);
227             *psd = NULL;
228         }
229         if (*acl) {
230             LocalFree(*acl);
231             *acl = NULL;
232         }
233     } else {
234         sfree(*error);
235         *error = NULL;
236     }
237     return ret;
238 }
239
240 int protectprocess(char *error)
241 {
242     SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY;
243     SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
244     EXPLICIT_ACCESS ea[2];
245     int acl_err;
246     int ret=FALSE;
247     PACL acl = NULL;
248
249     static const nastyace=WRITE_DAC | WRITE_OWNER |
250         PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD |
251         PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION |
252         PROCESS_SET_QUOTA | PROCESS_SET_INFORMATION |
253         PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE |
254         PROCESS_SUSPEND_RESUME;
255
256     if (!getsids(error))
257         goto cleanup;
258
259     memset(ea, 0, sizeof(ea));
260
261     /* Everyone: deny */
262     ea[0].grfAccessPermissions = nastyace;
263     ea[0].grfAccessMode = DENY_ACCESS;
264     ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
265     ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
266     ea[0].Trustee.ptstrName = (LPTSTR)worldsid;
267
268     /* User: user ace */
269     ea[1].grfAccessPermissions = ~nastyace & 0x1fff;
270     ea[1].grfAccessMode = GRANT_ACCESS;
271     ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
272     ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
273     ea[1].Trustee.ptstrName = (LPTSTR)usersid;
274
275     acl_err = p_SetEntriesInAclA(2, ea, NULL, &acl);
276
277     if (acl_err != ERROR_SUCCESS || acl == NULL) {
278         error = dupprintf("unable to construct ACL: %s",
279                           win_strerror(acl_err));
280         goto cleanup;
281     }
282
283     if (ERROR_SUCCESS !=
284         SetSecurityInfo(
285                         GetCurrentProcess(),
286                         SE_KERNEL_OBJECT,
287                         OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
288                         usersid,
289                         NULL,
290                         acl,
291                         NULL
292                         )) {
293         error=dupprintf("Unable to set process ACL: %s",
294                         win_strerror(GetLastError()));
295         goto cleanup;
296     }
297                       
298
299     ret=TRUE;
300     
301   cleanup:
302     if (!ret) {
303         if (acl) {
304             LocalFree(acl);
305             acl = NULL;
306         }
307     }
308     return ret;
309 }  
310 #endif /* !defined NO_SECURITY */