aheinecke@404: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik aheinecke@404: * Software engineering by Intevation GmbH aheinecke@404: * aheinecke@404: * This file is Free Software under the GNU GPL (v>=2) aheinecke@404: * and comes with ABSOLUTELY NO WARRANTY! aheinecke@404: * See LICENSE.txt for details. aheinecke@404: */ aheinecke@321: #include "util.h" aheinecke@505: #include "logging.h" andre@644: #include "strhelp.h" aheinecke@505: wilde@323: #ifndef _WIN32 wilde@323: #include wilde@323: #include andre@644: #include andre@644: #include andre@644: #include wilde@323: #else aheinecke@321: #include aheinecke@321: #endif aheinecke@321: andre@671: #ifdef WIN32 andre@675: char * get_install_dir() andre@675: { andre@675: wchar_t wPath[MAX_PATH]; andre@675: char *utf8path = NULL; andre@675: char *dirsep = NULL; andre@675: andre@675: if (!GetModuleFileNameW (NULL, wPath, MAX_PATH - 1)) andre@675: { andre@675: PRINTLASTERROR ("Failed to obtain module file name. Path too long?"); andre@675: return NULL; andre@675: } andre@675: andre@675: /* wPath might not be 0 terminated */ andre@675: wPath[MAX_PATH - 1] = '\0'; andre@675: andre@675: utf8path = wchar_to_utf8 (wPath, wcsnlen(wPath, MAX_PATH)); andre@675: andre@675: if (utf8path == NULL) andre@675: { andre@675: ERRORPRINTF ("Failed to convert module path to utf-8"); andre@675: return NULL; andre@675: } andre@675: andre@675: /* Cut away the executable name */ andre@675: dirsep = strrchr(utf8path, '\\'); andre@675: if (dirsep == NULL) andre@675: { andre@675: ERRORPRINTF ("Failed to find directory seperator."); andre@675: return NULL; andre@675: } andre@675: *dirsep = '\0'; andre@675: return utf8path; andre@675: } andre@675: andre@670: static PSID andre@670: copy_sid(PSID from) andre@670: { andre@670: if (!from) andre@670: { andre@670: return 0; andre@670: } andre@670: andre@670: DWORD sidLength = GetLengthSid(from); andre@670: PSID to = (PSID) xmalloc(sidLength); andre@670: CopySid(sidLength, to, from); andre@670: return to; andre@670: } andre@670: andre@670: andre@670: PSID andre@670: get_process_owner(HANDLE hProcess) andre@670: { andre@670: HANDLE hToken = NULL; andre@670: PSID sid; andre@670: andre@670: if (hProcess == NULL) andre@670: { andre@670: ERRORPRINTF ("invalid call to get_process_owner"); andre@670: return NULL; andre@670: } andre@670: andre@670: OpenProcessToken(hProcess, TOKEN_READ, &hToken); andre@670: if (hToken) andre@670: { andre@670: DWORD size = 0; andre@670: PTOKEN_USER userStruct; andre@670: andre@670: // check how much space is needed andre@670: GetTokenInformation(hToken, TokenUser, NULL, 0, &size); andre@670: if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) andre@670: { andre@670: userStruct = (PTOKEN_USER) xmalloc (size); andre@670: GetTokenInformation(hToken, TokenUser, userStruct, size, &size); andre@670: andre@670: sid = copy_sid(userStruct->User.Sid); andre@670: CloseHandle(hToken); andre@670: xfree (userStruct); andre@670: return sid; andre@670: } andre@670: } andre@670: return NULL; andre@670: } andre@671: #endif andre@670: aheinecke@321: bool wilde@323: is_elevated() wilde@323: { wilde@323: bool ret = false; wilde@323: #ifndef _WIN32 wilde@323: ret = (geteuid() == 0); wilde@323: #else wilde@323: HANDLE hToken = NULL; wilde@323: if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken)) wilde@323: { wilde@323: DWORD elevation; wilde@323: DWORD cbSize = sizeof (DWORD); wilde@323: if (GetTokenInformation (hToken, TokenElevation, &elevation, wilde@323: sizeof (TokenElevation), &cbSize)) wilde@323: { wilde@323: ret = elevation; wilde@323: } wilde@323: } wilde@323: if (hToken) wilde@323: CloseHandle (hToken); wilde@323: #endif wilde@323: return ret; wilde@323: } aheinecke@505: aheinecke@505: bool is_admin() aheinecke@505: { aheinecke@505: #ifndef _WIN32 andre@644: struct passwd *current_user = getpwuid (geteuid()); andre@644: int ngroups = 0, andre@644: ret = 0, andre@644: i = 0; andre@644: gid_t * groups = NULL; andre@644: andre@644: if (current_user == NULL) andre@644: { andre@644: ERRORPRINTF ("Failed to obtain user information."); andre@644: return false; andre@644: } andre@644: andre@644: ret = getgrouplist (current_user->pw_name, current_user->pw_gid, NULL, andre@644: &ngroups); andre@644: andre@644: if (ret != -1 || ngroups <= 0) andre@644: { andre@644: ERRORPRINTF ("Unknown error in getgrouplist call"); andre@644: return false; andre@644: } andre@644: andre@644: groups = xmalloc (((unsigned int)ngroups) * sizeof (gid_t)); andre@644: andre@644: ret = getgrouplist (current_user->pw_name, current_user->pw_gid, groups, andre@644: &ngroups); andre@644: andre@644: if (ret != ngroups) andre@644: { andre@644: ERRORPRINTF ("Group length mismatch."); andre@644: xfree (groups); andre@644: return false; andre@644: } andre@644: andre@644: for (i = 0; i < ngroups; i++) andre@644: { andre@644: struct group *gr = getgrgid (groups[i]); andre@644: if (gr == NULL) andre@644: { andre@644: ERRORPRINTF ("Error in group enumeration"); andre@644: xfree (groups); andre@644: return false; andre@644: } andre@644: if (strcmp("sudo", gr->gr_name) == 0) andre@644: { andre@644: DEBUGPRINTF ("User is in sudo group \n"); andre@644: xfree (groups); andre@644: return true; andre@644: } andre@644: } andre@644: andre@644: DEBUGPRINTF ("User is not in sudo group"); andre@644: aheinecke@505: return false; aheinecke@505: #else aheinecke@505: bool retval = false; aheinecke@505: BOOL in_admin_group = FALSE; aheinecke@505: HANDLE hToken = NULL; aheinecke@505: HANDLE hTokenToCheck = NULL; aheinecke@505: DWORD cbSize = 0; aheinecke@505: TOKEN_ELEVATION_TYPE elevation; aheinecke@505: BYTE admin_id[SECURITY_MAX_SID_SIZE]; aheinecke@505: aheinecke@505: if (!OpenProcessToken(GetCurrentProcess(), aheinecke@505: TOKEN_QUERY | TOKEN_DUPLICATE, &hToken)) aheinecke@505: { aheinecke@505: PRINTLASTERROR ("Failed to duplicate process token.\n"); aheinecke@505: return false; aheinecke@505: } aheinecke@505: aheinecke@505: if (!GetTokenInformation(hToken, TokenElevationType, &elevation, aheinecke@505: sizeof(elevation), &cbSize)) aheinecke@505: { aheinecke@505: PRINTLASTERROR ("Failed to get token information.\n"); aheinecke@505: goto done; aheinecke@505: } aheinecke@505: aheinecke@505: /* If limited check the the linked token instead */ aheinecke@505: if (TokenElevationTypeLimited == elevation) aheinecke@505: { aheinecke@505: if (!GetTokenInformation(hToken, TokenLinkedToken, &hTokenToCheck, aheinecke@505: sizeof(hTokenToCheck), &cbSize)) aheinecke@505: { aheinecke@505: PRINTLASTERROR ("Failed to get the linked token.\n"); aheinecke@505: goto done; aheinecke@505: } aheinecke@505: } aheinecke@505: aheinecke@505: if (!hTokenToCheck) /* The linked token is already of the correct type */ aheinecke@505: { aheinecke@505: if (!DuplicateToken(hToken, SecurityIdentification, &hTokenToCheck)) aheinecke@505: { aheinecke@505: PRINTLASTERROR ("Failed to duplicate token for identification.\n"); aheinecke@505: goto done; aheinecke@505: } aheinecke@505: } aheinecke@505: aheinecke@505: /* Do the sid dance for the adminSID */ aheinecke@505: cbSize = sizeof(admin_id); aheinecke@505: if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &admin_id, aheinecke@505: &cbSize)) aheinecke@505: { aheinecke@505: PRINTLASTERROR ("Failed to get admin sid.\n"); aheinecke@505: goto done; aheinecke@505: } aheinecke@505: aheinecke@505: /* The actual check */ aheinecke@505: if (!CheckTokenMembership(hTokenToCheck, &admin_id, &in_admin_group)) aheinecke@505: { aheinecke@505: PRINTLASTERROR ("Failed to check token membership.\n"); aheinecke@505: goto done; aheinecke@505: } aheinecke@505: aheinecke@505: if (in_admin_group) aheinecke@505: { aheinecke@505: /* Winbool to standard bool */ aheinecke@505: retval = true; aheinecke@505: } aheinecke@505: aheinecke@505: done: aheinecke@505: if (hToken) CloseHandle(hToken); aheinecke@505: if (hTokenToCheck) CloseHandle(hTokenToCheck); aheinecke@505: aheinecke@505: return retval; aheinecke@505: #endif aheinecke@505: } aheinecke@505: