view common/util.c @ 716:929c3db85eb7

Add central place to obtain current change count.
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 02 Jul 2014 16:09:19 +0200
parents 4ad764bfb39c
children 216a65d7fc4b
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU GPL (v>=2)
 * and comes with ABSOLUTELY NO WARRANTY!
 * See LICENSE.txt for details.
 */
#include "util.h"
#include "logging.h"
#include "strhelp.h"

#ifndef _WIN32
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>
#else
#include <windows.h>
#endif

#ifdef WIN32
char * get_install_dir()
{
  wchar_t wPath[MAX_PATH];
  char *utf8path = NULL;
  char *dirsep = NULL;

  if (!GetModuleFileNameW (NULL, wPath, MAX_PATH - 1)) 
    {
      PRINTLASTERROR ("Failed to obtain module file name. Path too long?");
      return NULL;
    }

  /* wPath might not be 0 terminated */
  wPath[MAX_PATH - 1] = '\0';

  utf8path = wchar_to_utf8 (wPath, wcsnlen(wPath, MAX_PATH));

  if (utf8path == NULL)
    {
      ERRORPRINTF ("Failed to convert module path to utf-8");
      return NULL;
    }

  /* Cut away the executable name */
  dirsep = strrchr(utf8path, '\\');
  if (dirsep == NULL)
    {
      ERRORPRINTF ("Failed to find directory seperator.");
      return NULL;
    }
  *dirsep = '\0';
  return utf8path;
}

static PSID
copy_sid(PSID from)
{
  if (!from)
    {
      return 0;
    }

  DWORD sidLength = GetLengthSid(from);
  PSID to = (PSID) xmalloc(sidLength);
  CopySid(sidLength, to, from);
  return to;
}


PSID
get_process_owner(HANDLE hProcess)
{
    HANDLE hToken = NULL;
    PSID sid;

    if (hProcess == NULL)
      {
        ERRORPRINTF ("invalid call to get_process_owner");
        return NULL;
      }

    OpenProcessToken(hProcess, TOKEN_READ, &hToken);
    if (hToken)
      {
        DWORD size = 0;
        PTOKEN_USER userStruct;

        // check how much space is needed
        GetTokenInformation(hToken, TokenUser, NULL, 0, &size);
        if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
          {
            userStruct = (PTOKEN_USER) xmalloc (size);
            GetTokenInformation(hToken, TokenUser, userStruct, size, &size);

            sid = copy_sid(userStruct->User.Sid);
            CloseHandle(hToken);
            xfree (userStruct);
            return sid;
          }
      }
    return NULL;
}
#endif

bool
is_elevated()
{
  bool ret = false;
#ifndef _WIN32
  ret = (geteuid() == 0);
#else
  HANDLE hToken = NULL;
  if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
    {
      DWORD elevation;
      DWORD cbSize = sizeof (DWORD);
      if (GetTokenInformation (hToken, TokenElevation, &elevation,
                               sizeof (TokenElevation), &cbSize))
        {
          ret = elevation;
        }
    }
  if (hToken)
    CloseHandle (hToken);
#endif
  return ret;
}

bool is_admin()
{
#ifndef _WIN32
  struct passwd *current_user = getpwuid (geteuid());
  int ngroups = 0,
      ret = 0,
      i = 0;
  gid_t * groups = NULL;

  if (current_user == NULL)
    {
      ERRORPRINTF ("Failed to obtain user information.");
      return false;
    }

  ret = getgrouplist (current_user->pw_name, current_user->pw_gid, NULL,
                      &ngroups);

  if (ret != -1 || ngroups <= 0)
    {
      ERRORPRINTF ("Unknown error in getgrouplist call");
      return false;
    }

  groups = xmalloc (((unsigned int)ngroups) * sizeof (gid_t));

  ret = getgrouplist (current_user->pw_name, current_user->pw_gid, groups,
                      &ngroups);

  if (ret != ngroups)
    {
      ERRORPRINTF ("Group length mismatch.");
      xfree (groups);
      return false;
    }

  for (i = 0; i < ngroups; i++)
    {
      struct group *gr = getgrgid (groups[i]);
      if (gr == NULL)
        {
          ERRORPRINTF ("Error in group enumeration");
          xfree (groups);
          return false;
        }
      if (strcmp("sudo", gr->gr_name) == 0)
        {
          DEBUGPRINTF ("User is in sudo group \n");
          xfree (groups);
          return true;
        }
    }

  DEBUGPRINTF ("User is not in sudo group");

  return false;
#else
  bool retval = false;
  BOOL in_admin_group = FALSE;
  HANDLE hToken = NULL;
  HANDLE hTokenToCheck = NULL;
  DWORD cbSize = 0;
  TOKEN_ELEVATION_TYPE elevation;
  BYTE admin_id[SECURITY_MAX_SID_SIZE];

  if (!OpenProcessToken(GetCurrentProcess(),
                        TOKEN_QUERY | TOKEN_DUPLICATE, &hToken))
    {
      PRINTLASTERROR ("Failed to duplicate process token.\n");
      return false;
    }

  if (!GetTokenInformation(hToken, TokenElevationType, &elevation,
                           sizeof(elevation), &cbSize))
    {
      PRINTLASTERROR ("Failed to get token information.\n");
      goto done;
    }

  /* If limited check the the linked token instead */
  if (TokenElevationTypeLimited == elevation)
    {
      if (!GetTokenInformation(hToken, TokenLinkedToken, &hTokenToCheck,
                               sizeof(hTokenToCheck), &cbSize))
        {
          PRINTLASTERROR ("Failed to get the linked token.\n");
          goto done;
        }
    }

  if (!hTokenToCheck) /* The linked token is already of the correct type */
    {
      if (!DuplicateToken(hToken, SecurityIdentification, &hTokenToCheck))
        {
          PRINTLASTERROR ("Failed to duplicate token for identification.\n");
          goto done;
        }
    }

  /* Do the sid dance for the adminSID */
  cbSize = sizeof(admin_id);
  if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &admin_id,
                          &cbSize))
    {
      PRINTLASTERROR ("Failed to get admin sid.\n");
      goto done;
    }

  /* The actual check */
  if (!CheckTokenMembership(hTokenToCheck, &admin_id, &in_admin_group))
    {
      PRINTLASTERROR ("Failed to check token membership.\n");
      goto done;
    }

  if (in_admin_group)
    {
      /* Winbool to standard bool */
      retval = true;
    }

done:
  if (hToken) CloseHandle(hToken);
  if (hTokenToCheck) CloseHandle(hTokenToCheck);

  return retval;
#endif
}

http://wald.intevation.org/projects/trustbridge/