advapi = load_system32_dll("advapi32.dll");
successful = advapi &&
GET_WINDOWS_FUNCTION(advapi, GetSecurityInfo) &&
+ GET_WINDOWS_FUNCTION(advapi, SetSecurityInfo) &&
GET_WINDOWS_FUNCTION(advapi, OpenProcessToken) &&
GET_WINDOWS_FUNCTION(advapi, GetTokenInformation) &&
GET_WINDOWS_FUNCTION(advapi, InitializeSecurityDescriptor) &&
DWORD toklen, sidlen;
PSID sid = NULL, ret = NULL;
+ if (usersid)
+ return usersid;
+
if (!got_advapi())
goto cleanup;
/* Success. Move sid into the return value slot, and null it out
* to stop the cleanup code freeing it. */
- ret = sid;
+ ret = usersid = sid;
sid = NULL;
cleanup:
return ret;
}
-int getsids(char *error)
+int getsids(char **error)
{
- SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY;
- SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
- int ret;
+ SID_IDENTIFIER_AUTHORITY world_auth = { SECURITY_WORLD_SID_AUTHORITY };
+ SID_IDENTIFIER_AUTHORITY nt_auth = { SECURITY_NT_AUTHORITY };
+ int ret = FALSE;
- error=NULL;
+ *error = NULL;
if (!usersid) {
if ((usersid = get_user_sid()) == NULL) {
- error = dupprintf("unable to construct SID for current user: %s",
+ *error = dupprintf("unable to construct SID for current user: %s",
win_strerror(GetLastError()));
goto cleanup;
}
if (!worldsid) {
if (!AllocateAndInitializeSid(&world_auth, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &worldsid)) {
- error = dupprintf("unable to construct SID for world: %s",
+ *error = dupprintf("unable to construct SID for world: %s",
win_strerror(GetLastError()));
goto cleanup;
}
if (!networksid) {
if (!AllocateAndInitializeSid(&nt_auth, 1, SECURITY_NETWORK_RID,
0, 0, 0, 0, 0, 0, 0, &networksid)) {
- error = dupprintf("unable to construct SID for "
+ *error = dupprintf("unable to construct SID for "
"local same-user access only: %s",
win_strerror(GetLastError()));
goto cleanup;
}
}
- ret=TRUE;
+ ret = TRUE;
cleanup:
- if (ret) {
- sfree(error);
- error = NULL;
- }
return ret;
}
PACL *acl,
char **error)
{
- SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY;
- SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
EXPLICIT_ACCESS ea[3];
int acl_err;
int ret = FALSE;
*acl = NULL;
*error = NULL;
- if (!getsids(*error))
+ if (!getsids(error))
goto cleanup;
memset(ea, 0, sizeof(ea));
return ret;
}
-int setprocessacl(char *error)
+static int really_restrict_process_acl(char **error)
{
- SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY;
- SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
EXPLICIT_ACCESS ea[2];
int acl_err;
int ret=FALSE;
PACL acl = NULL;
- static const nastyace=WRITE_DAC | WRITE_OWNER |
+ static const DWORD nastyace=WRITE_DAC | WRITE_OWNER |
PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD |
- PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION |
+ PROCESS_DUP_HANDLE |
PROCESS_SET_QUOTA | PROCESS_SET_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE |
PROCESS_SUSPEND_RESUME;
acl_err = p_SetEntriesInAclA(2, ea, NULL, &acl);
if (acl_err != ERROR_SUCCESS || acl == NULL) {
- error = dupprintf("unable to construct ACL: %s",
- win_strerror(acl_err));
+ *error = dupprintf("unable to construct ACL: %s",
+ win_strerror(acl_err));
goto cleanup;
}
- if (ERROR_SUCCESS !=
- SetSecurityInfo(
- GetCurrentProcess(),
- SE_KERNEL_OBJECT,
- OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
- usersid,
- NULL,
- acl,
- NULL
- )) {
- error=dupprintf("Unable to set process ACL: %s",
- win_strerror(GetLastError()));
+ if (ERROR_SUCCESS != p_SetSecurityInfo
+ (GetCurrentProcess(), SE_KERNEL_OBJECT,
+ OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+ usersid, NULL, acl, NULL)) {
+ *error = dupprintf("Unable to set process ACL: %s",
+ win_strerror(GetLastError()));
goto cleanup;
}
}
}
return ret;
-}
+}
#endif /* !defined NO_SECURITY */
+
+/*
+ * Lock down our process's ACL, to present an obstacle to malware
+ * trying to write into its memory. This can't be a full defence,
+ * because well timed malware could attack us before this code runs -
+ * even if it was unconditionally run at the very start of main(),
+ * which we wouldn't want to do anyway because it turns out in practie
+ * that interfering with other processes in this way has significant
+ * non-infringing uses on Windows (e.g. screen reader software).
+ *
+ * If we've been requested to do this and are unsuccessful, bomb out
+ * via modalfatalbox rather than continue in a less protected mode.
+ *
+ * This function is intentionally outside the #ifndef NO_SECURITY that
+ * covers the rest of this file, because when PuTTY is compiled
+ * without the ability to restrict its ACL, we don't want it to
+ * silently pretend to honour the instruction to do so.
+ */
+void restrict_process_acl(void)
+{
+ char *error = NULL;
+ int ret;
+
+#if !defined NO_SECURITY
+ ret = really_restrict_process_acl(&error);
+#else
+ ret = FALSE;
+ error = dupstr("ACL restrictions not compiled into this binary");
+#endif
+ if (!ret)
+ modalfatalbox("Could not restrict process ACL: %s", error);
+}