// Drop admin privileges and exec() a command. #define WINVER 0x0500 #include #include #include #include #include #define SIDSTRUCT(name, auth, n, subauth...) \ static struct { \ BYTE Revision; \ BYTE SubAuthorityCount; \ SID_IDENTIFIER_AUTHORITY IdentifierAuthority; \ DWORD SubAuthority[n]; \ } name = {SID_REVISION, n, {auth}, {subauth}} static int pwinerror(const char * msg) { fprintf(stderr, "%s: %d\n", msg, (int)GetLastError()); return 1; } int main(int argc, char **argv) { int ac = 1; bool b_flag = false; if (ac < argc && !strcmp (argv[ac], "-b")) { b_flag = true; ac++; } if (ac >= argc || argv[ac][0] == '-') { printf ("Usage: %s [-b] COMMAND [ARG ...]\n" "Drop admin privileges and exec COMMAND\n" "\n" " -b keep SeBackupPrivilege\n", argv[0]); return 1; } // Get token HANDLE ptoken; if(!OpenProcessToken (GetCurrentProcess (), TOKEN_ALL_ACCESS, &ptoken)) return pwinerror("OpenProcessToken"); // Get privileges const int max_privs = 100; char priv_buf[sizeof (DWORD) + sizeof (LUID_AND_ATTRIBUTES) * max_privs]; TOKEN_PRIVILEGES * privs = (TOKEN_PRIVILEGES *)priv_buf; DWORD size = 0; if (!GetTokenInformation (ptoken, TokenPrivileges, privs, sizeof(priv_buf), &size)) return pwinerror ("GetTokenInformation"); // Collect luids of privileges to disable LUID_AND_ATTRIBUTES disable_privs[max_privs]; int num_disable_privs = 0; for (unsigned i = 0; i < privs->PrivilegeCount; i++) { char name[100]; size = sizeof(name); if (!LookupPrivilegeName (NULL, &privs->Privileges[i].Luid, name, &size)) return pwinerror ("LookupPrivilegeName"); if (!strcmp (name, SE_CHANGE_NOTIFY_NAME)) continue; if (!strcmp (name, SE_CREATE_GLOBAL_NAME)) continue; if (b_flag && !strcmp (name, SE_BACKUP_NAME)) continue; disable_privs[num_disable_privs].Luid = privs->Privileges[i].Luid; disable_privs[num_disable_privs].Attributes = 0; num_disable_privs++; } // Set SIDs to disable const int num_disable_sids = 1; SID_AND_ATTRIBUTES disable_sids[num_disable_sids]; SIDSTRUCT(admins, SECURITY_NT_AUTHORITY, 2, // S-1-5-32-544 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS); disable_sids[0].Sid = &admins; disable_sids[0].Attributes = 0; // Create restricted token HANDLE rtoken; if (!CreateRestrictedToken (ptoken, 0, num_disable_sids, disable_sids, num_disable_privs, disable_privs, 0, 0, &rtoken)) return pwinerror("CreateRestrictedToken"); CloseHandle (ptoken); // Change to restricted token if (cygwin_internal (CW_SET_EXTERNAL_TOKEN, rtoken, CW_TOKEN_RESTRICTED)) { perror ("cygwin_internal (CW_SET_EXTERNAL_TOKEN,...)"); return 1; } if (setuid (geteuid ())) { perror ("setuid"); return 1; } execvp (argv[ac], argv+ac); perror (argv[ac]); return 1; }