2 * winsecur.c: implementation of winsecur.h.
10 #if !defined NO_SECURITY
12 #define WINSECUR_GLOBAL
15 /* Initialised once, then kept around to reuse forever */
16 static PSID worldsid, networksid, usersid;
21 static int attempted = FALSE;
22 static int successful;
23 static HMODULE advapi;
27 advapi = load_system32_dll("advapi32.dll");
28 successful = advapi &&
29 GET_WINDOWS_FUNCTION(advapi, GetSecurityInfo) &&
30 GET_WINDOWS_FUNCTION(advapi, SetSecurityInfo) &&
31 GET_WINDOWS_FUNCTION(advapi, OpenProcessToken) &&
32 GET_WINDOWS_FUNCTION(advapi, GetTokenInformation) &&
33 GET_WINDOWS_FUNCTION(advapi, InitializeSecurityDescriptor) &&
34 GET_WINDOWS_FUNCTION(advapi, SetSecurityDescriptorOwner) &&
35 GET_WINDOWS_FUNCTION(advapi, SetEntriesInAclA);
40 PSID get_user_sid(void)
42 HANDLE proc = NULL, tok = NULL;
43 TOKEN_USER *user = NULL;
45 PSID sid = NULL, ret = NULL;
53 if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE,
54 GetCurrentProcessId())) == NULL)
57 if (!p_OpenProcessToken(proc, TOKEN_QUERY, &tok))
60 if (!p_GetTokenInformation(tok, TokenUser, NULL, 0, &toklen) &&
61 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
64 if ((user = (TOKEN_USER *)LocalAlloc(LPTR, toklen)) == NULL)
67 if (!p_GetTokenInformation(tok, TokenUser, user, toklen, &toklen))
70 sidlen = GetLengthSid(user->User.Sid);
72 sid = (PSID)smalloc(sidlen);
74 if (!CopySid(sidlen, sid, user->User.Sid))
77 /* Success. Move sid into the return value slot, and null it out
78 * to stop the cleanup code freeing it. */
95 int getsids(char **error)
98 #pragma clang diagnostic push
99 #pragma clang diagnostic ignored "-Wmissing-braces"
101 SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY;
102 SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
104 #pragma clang diagnostic pop
112 if ((usersid = get_user_sid()) == NULL) {
113 *error = dupprintf("unable to construct SID for current user: %s",
114 win_strerror(GetLastError()));
120 if (!AllocateAndInitializeSid(&world_auth, 1, SECURITY_WORLD_RID,
121 0, 0, 0, 0, 0, 0, 0, &worldsid)) {
122 *error = dupprintf("unable to construct SID for world: %s",
123 win_strerror(GetLastError()));
129 if (!AllocateAndInitializeSid(&nt_auth, 1, SECURITY_NETWORK_RID,
130 0, 0, 0, 0, 0, 0, 0, &networksid)) {
131 *error = dupprintf("unable to construct SID for "
132 "local same-user access only: %s",
133 win_strerror(GetLastError()));
145 int make_private_security_descriptor(DWORD permissions,
146 PSECURITY_DESCRIPTOR *psd,
150 EXPLICIT_ACCESS ea[3];
162 memset(ea, 0, sizeof(ea));
163 ea[0].grfAccessPermissions = permissions;
164 ea[0].grfAccessMode = REVOKE_ACCESS;
165 ea[0].grfInheritance = NO_INHERITANCE;
166 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
167 ea[0].Trustee.ptstrName = (LPTSTR)worldsid;
168 ea[1].grfAccessPermissions = permissions;
169 ea[1].grfAccessMode = GRANT_ACCESS;
170 ea[1].grfInheritance = NO_INHERITANCE;
171 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
172 ea[1].Trustee.ptstrName = (LPTSTR)usersid;
173 ea[2].grfAccessPermissions = permissions;
174 ea[2].grfAccessMode = REVOKE_ACCESS;
175 ea[2].grfInheritance = NO_INHERITANCE;
176 ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
177 ea[2].Trustee.ptstrName = (LPTSTR)networksid;
179 acl_err = p_SetEntriesInAclA(3, ea, NULL, acl);
180 if (acl_err != ERROR_SUCCESS || *acl == NULL) {
181 *error = dupprintf("unable to construct ACL: %s",
182 win_strerror(acl_err));
186 *psd = (PSECURITY_DESCRIPTOR)
187 LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
189 *error = dupprintf("unable to allocate security descriptor: %s",
190 win_strerror(GetLastError()));
194 if (!InitializeSecurityDescriptor(*psd, SECURITY_DESCRIPTOR_REVISION)) {
195 *error = dupprintf("unable to initialise security descriptor: %s",
196 win_strerror(GetLastError()));
200 if (!SetSecurityDescriptorOwner(*psd, usersid, FALSE)) {
201 *error = dupprintf("unable to set owner in security descriptor: %s",
202 win_strerror(GetLastError()));
206 if (!SetSecurityDescriptorDacl(*psd, TRUE, *acl, FALSE)) {
207 *error = dupprintf("unable to set DACL in security descriptor: %s",
208 win_strerror(GetLastError()));
231 static int really_restrict_process_acl(char **error)
233 EXPLICIT_ACCESS ea[2];
238 static const DWORD nastyace=WRITE_DAC | WRITE_OWNER |
239 PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD |
241 PROCESS_SET_QUOTA | PROCESS_SET_INFORMATION |
242 PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE |
243 PROCESS_SUSPEND_RESUME;
248 memset(ea, 0, sizeof(ea));
251 ea[0].grfAccessPermissions = nastyace;
252 ea[0].grfAccessMode = DENY_ACCESS;
253 ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
254 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
255 ea[0].Trustee.ptstrName = (LPTSTR)worldsid;
258 ea[1].grfAccessPermissions = ~nastyace & 0x1fff;
259 ea[1].grfAccessMode = GRANT_ACCESS;
260 ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
261 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
262 ea[1].Trustee.ptstrName = (LPTSTR)usersid;
264 acl_err = p_SetEntriesInAclA(2, ea, NULL, &acl);
266 if (acl_err != ERROR_SUCCESS || acl == NULL) {
267 *error = dupprintf("unable to construct ACL: %s",
268 win_strerror(acl_err));
272 if (ERROR_SUCCESS != p_SetSecurityInfo
273 (GetCurrentProcess(), SE_KERNEL_OBJECT,
274 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
275 usersid, NULL, acl, NULL)) {
276 *error = dupprintf("Unable to set process ACL: %s",
277 win_strerror(GetLastError()));
293 #endif /* !defined NO_SECURITY */
296 * Lock down our process's ACL, to present an obstacle to malware
297 * trying to write into its memory. This can't be a full defence,
298 * because well timed malware could attack us before this code runs -
299 * even if it was unconditionally run at the very start of main(),
300 * which we wouldn't want to do anyway because it turns out in practie
301 * that interfering with other processes in this way has significant
302 * non-infringing uses on Windows (e.g. screen reader software).
304 * If we've been requested to do this and are unsuccessful, bomb out
305 * via modalfatalbox rather than continue in a less protected mode.
307 * This function is intentionally outside the #ifndef NO_SECURITY that
308 * covers the rest of this file, because when PuTTY is compiled
309 * without the ability to restrict its ACL, we don't want it to
310 * silently pretend to honour the instruction to do so.
312 void restrict_process_acl(void)
317 #if !defined NO_SECURITY
318 ret = really_restrict_process_acl(&error);
321 error = dupstr("ACL restrictions not compiled into this binary");
324 modalfatalbox("Could not restrict process ACL: %s", error);