admin privileges when logging in by ssh?

Corinna Vinschen corinna-cygwin@cygwin.com
Tue Oct 4 17:54:00 GMT 2011


On Oct  4 11:59, Andrew Schulman wrote:
> > On Sep 12 10:24, Andrew Schulman wrote:
> > > > When a user with administrative privileges logs in to sshd, it seems that the user is only granted
> > > > standard user privileges for that session.  Is there a way around that?  How can I get the admin
> > > > privileges for that session?
> > > 
> > > Winding this up:
> > > 
> > > Password authentication to sshd is all that's needed to be granted the account's admin privileges on
> > > login.  I was mistaken about UAC:  unlike at the console, when you log in by ssh, the account's
> > > admin privileges are granted at login, without needing any further authentication to UAC.
> > 
> > I'm quite puzzeled since password authentication should not be needed.
> > This should work with pubkey as well.  Please see
> > http://cygwin.com/cygwin-ug-net/ntsec.html#ntsec-setuid-overview for
> > a discussion how setuid works in Cygwin.
> > 
> > In all cases, password auth and passwordless auth, you should get a full
> > admin token.  In case of password auth and in the passwordless methods
> > 2 and 3, the OS returns a restricted token under UAC, but that token
> > has a reference to the full admin token attached.  Cygwin fetches this
> > token and uses that when switching the user context.  In the default
> > passwordless method 1, Cygwin creates a token from scratch, which also
> > has full admin rights.  However, this token has a couple of problems as
> > described in http://cygwin.com/cygwin-ug-net/ntsec.html#ntsec-nopasswd1
> > Probably that's what you stumble over.
> 
> Thanks for writing up that documentation of user context switching (I
> assume it was you who wrote it).  It's complex.

Sorry, but the Windows authentication stuff is complex.

> So IIUC, sshd by default uses method 1, creating a token from scratch.  So

Not sshd in the first place, but the underlying set(e)uid system call.

> when a user logs in with pubkey authentication, they won't have a logon
> session, which means their SID name may be misidentified by native Windows
> apps; and they won't have access to password-protected network shares.  But
> they should still have all of the privileges normally granted to their
> account.

Right.  And in contrast to the normal user token, the token hand-crafted
by Cygwin has all privileges enabled by default.  But it suffers from
the fact that there's no login session attached to it.  Don't ask.  This
part of the authentication mechanism I don't understand and afaics it's
not documented at all.

> I'm not able to test it right now, but what I observed before was that when
> a user with the SeBackupPrivilege and SeBackupPrivilege privileges logged
> in by password authentication, it could use those privileges (with rsync);
> but when it logged in by pubkey authentication, it couldn't.  So I agree
> that this is puzzling since it doesn't seem to square with the description
> above.  This is on Windows 7 Home Premium.

The OS shouldn't matter.

> I'll test this again when I can, to be sure what I observed is correct.  If
> you can suggest any diagnostic tools to help identify the available
> privileges, that would be helpful.

Does Windows 7 Home Premium come with a native whoami?  I'm only
running Ultimate, which has this tool:

  $ /cygdrive/c/Windows/System32/whoami /all

With method 1 you will see a wrong user name showing up, even though
the user SID is correct.

If you don't have a native whoami, I hacked some tool once which I
use all the time to do basically the same as the Windows whoami.
I attached the ugly source code, build with

  $ g++ -o gettokinfo gettokinfo.cc

and run from the session you want to check like this

  $ ./gettokinfo

if you don't want to see the privileges, or like this

  $ ./gettokinfo x

if you want to see them.


Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat
-------------- next part --------------
#include <stdio.h>
#include <unistd.h>
#define _WIN32_WINNT 0x0600
#include <windows.h>

int
error (const char *funcname)
{
  fprintf (stderr, "%s: %lu\n", funcname, GetLastError());
  return 1;
}

char *
convert_sid_to_string_sid (const PSID psid, char *sid_str)
{
  char t[32];
  DWORD i;

  if (!psid)
    return NULL;
  strcpy (sid_str, "S-1-");
  sprintf(t, "%u", GetSidIdentifierAuthority (psid)->Value[5]);
  strcat (sid_str, t);
  for (i = 0; i < *GetSidSubAuthorityCount (psid); ++i)
    {
      sprintf(t, "-%lu", *GetSidSubAuthority (psid, i));
      strcat (sid_str, t);
    }
  return sid_str;
}

HANDLE tok;
char buf[4096];
DWORD size;

PVOID
gti (TOKEN_INFORMATION_CLASS type)
{
  if (GetTokenInformation (tok, type, buf, 4096, &size))
    return (PVOID) buf;
  return NULL;
}

PVOID
hgti (HANDLE token, TOKEN_INFORMATION_CLASS type)
{
  if (GetTokenInformation (token, type, buf, 4096, &size))
    return (PVOID) buf;
  return NULL;
}

void
print_acl (PACL acl)
{
  printf ("\n");
  if (! acl)
    printf ("empty\n");
  else for (DWORD i = 0; i < acl->AceCount; ++i)
    {
      ACCESS_ALLOWED_ACE *ace;

      if (!GetAce (acl, i, (PVOID *) &ace))
	continue;
      switch (ace->Header.AceType)
	{
	case ACCESS_ALLOWED_ACE_TYPE:
	  printf ("  allow ");
	  break;
	case ACCESS_DENIED_ACE_TYPE:
	  printf ("  deny  ");
	  break;
	default:
	  printf ("  unknown\n");
	  continue;
	}
      if (ace->Mask & (FILE_READ_DATA|GENERIC_READ))
	printf ("read ");
      if (ace->Mask & (FILE_WRITE_DATA|GENERIC_WRITE))
	printf ("write ");
      if (ace->Mask & (FILE_EXECUTE|GENERIC_EXECUTE))
	printf ("exec ");
      if (ace->Mask & GENERIC_ALL)
	printf ("all ");
      if (ace->Mask & MAXIMUM_ALLOWED)
	printf ("max ");
      PSID sid = (PSID) &ace->SidStart;
      char ssid[256];
      printf ("%lx %s\n", ace->Mask,
			  convert_sid_to_string_sid (sid, ssid));
    }
}

void
print_default_dacl ()
{
  TOKEN_DEFAULT_DACL *dacl = (TOKEN_DEFAULT_DACL *) gti (TokenDefaultDacl);

  printf ("DefaultDacl: ");
  if (dacl)
    print_acl (dacl->DefaultDacl);
  else
    printf ("unreadable\n");
}

void
print_my_proc_dacl ()
{
  long buf[1024];
  PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) buf;
  DWORD len;

  printf ("ProcessDacl: ");
  if (GetKernelObjectSecurity (GetCurrentProcess (), DACL_SECURITY_INFORMATION,
			       sd, sizeof buf, &len))
    {
      PACL acl;
      BOOL present, def;

      GetSecurityDescriptorDacl (sd, &present, &acl, &def);
      if (present)
	print_acl (acl);
      else
      	printf ("unavailable\n");
    }
  else
    printf ("unreadable (%lu)\n", GetLastError ());
}

#ifndef SE_GROUP_INTEGRITY
#define SE_GROUP_INTEGRITY                 (0x00000020L)
#define SE_GROUP_INTEGRITY_ENABLED         (0x00000040L)
#endif

void
print_groups (TOKEN_INFORMATION_CLASS what, const char *disp_what)
{
  TOKEN_GROUPS *groups = (TOKEN_GROUPS *) gti (what);

  printf ("%s: ", disp_what);
  if (groups)
    {
      printf ("\n");
      for (DWORD i = 0; i < groups->GroupCount; ++i)
        {
          char ssid[256];
          printf ("  %s ",
                  convert_sid_to_string_sid (groups->Groups[i].Sid, ssid));
          if (groups->Groups[i].Attributes & SE_GROUP_ENABLED)
            printf ("enabled ");
          if (groups->Groups[i].Attributes & SE_GROUP_ENABLED_BY_DEFAULT)
            printf ("default ");
          if (groups->Groups[i].Attributes & SE_GROUP_LOGON_ID)
            printf ("logon_id ");
          if (groups->Groups[i].Attributes & SE_GROUP_MANDATORY)
            printf ("mandatory ");
          if (groups->Groups[i].Attributes & SE_GROUP_OWNER)
            printf ("owner ");
          if (groups->Groups[i].Attributes & SE_GROUP_RESOURCE)
            printf ("resource ");
          if (groups->Groups[i].Attributes & SE_GROUP_USE_FOR_DENY_ONLY)
            printf ("deny_only ");
          if (groups->Groups[i].Attributes & SE_GROUP_INTEGRITY)
            printf ("integrity ");
          if (groups->Groups[i].Attributes & SE_GROUP_INTEGRITY_ENABLED)
            printf ("integrit-enabled ");
          printf ("\n");
        }
    }
  else
    printf ("unreadable\n");
}

void
print_impersonation_level ()
{
  SECURITY_IMPERSONATION_LEVEL *imp =
        (SECURITY_IMPERSONATION_LEVEL *) gti (TokenImpersonationLevel);

  printf ("Impersonation Level: ");
  if (imp)
    switch (*imp)
      {
      case SecurityAnonymous:
        printf ("SecurityAnonymous\n");
        break;
      case SecurityIdentification:
        printf ("SecurityIdentification\n");
        break;
      case SecurityImpersonation:
        printf ("SecurityImpersonation\n");
        break;
      case SecurityDelegation:
        printf ("SecurityDelegation\n");
      default:
        printf ("unknown: %d\n", *imp);
      }
  else
    printf ("Primary Token\n");
}

void
print_owner ()
{
  TOKEN_OWNER *owner = (TOKEN_OWNER *) gti (TokenOwner);
  char ssid[256];

  printf ("Owner: ");
  if (owner)
    printf ("%s\n", convert_sid_to_string_sid (owner->Owner, ssid));
  else
    printf ("unreadable\n");
}

void
print_primary_group ()
{
  TOKEN_PRIMARY_GROUP *primary_group =
        (TOKEN_PRIMARY_GROUP *) gti (TokenPrimaryGroup);
  char ssid[256];

  printf ("Primary Group: ");
  if (primary_group)
    printf ("%s\n",
            convert_sid_to_string_sid (primary_group->PrimaryGroup, ssid));
  else
    printf ("unreadable\n");
}

void
print_privileges ()
{
  TOKEN_PRIVILEGES *privs = (TOKEN_PRIVILEGES *) gti (TokenPrivileges);

  printf ("Privileges: ");
  if (privs)
    {
      printf ("\n");
      for (DWORD i = 0; i < privs->PrivilegeCount; ++i)
        {
          DWORD siz;
          char privbuf[256];
          if (LookupPrivilegeName (NULL, &privs->Privileges[i].Luid,
                                   privbuf, (siz = 256, &siz)))
            {
              printf ("  %s ", privbuf);
              char dispbuf[256];
              DWORD lang_id;
              if (LookupPrivilegeDisplayName (NULL, privbuf, dispbuf,
                                              (siz = 256, &siz), &lang_id))
                printf ("\"%s\" ", dispbuf);
            }
          else
            printf ("unreadable: %lu %lu ", privs->Privileges[i].Luid.HighPart,
					    privs->Privileges[i].Luid.LowPart);
          if (privs->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
            printf ("enabled ");
          if (privs->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT)
            printf ("default ");
          if (privs->Privileges[i].Attributes & SE_PRIVILEGE_USED_FOR_ACCESS)
            printf ("access ");
          printf ("\n");
        }
    }
  else
    printf ("unreadable\n");
}

void
print_source ()
{
  TOKEN_SOURCE *source = (TOKEN_SOURCE *) gti (TokenSource);

  printf ("Source: ");
  if (source)
    printf ("%8.8s %ld %lu\n", source->SourceName,
                               source->SourceIdentifier.HighPart,
                               source->SourceIdentifier.LowPart);
  else
    printf ("unreadable\n");
}

void print_type ()
{
  TOKEN_TYPE *type = (TOKEN_TYPE *) gti (TokenType);

  printf ("Type: ");
  if (type)
    {
      if (*type == TokenPrimary)
        printf ("Primary\n");
      else if (*type == TokenImpersonation)
        printf ("Impersonation\n");
      else
        printf ("Unknown\n");
    }
  else
    printf ("unreadable\n");
}

void
print_user ()
{
  TOKEN_USER *user = (TOKEN_USER *) gti (TokenUser);
  char ssid[256];

  printf ("User: ");
  if (user)
    printf ("%s\n", convert_sid_to_string_sid (user->User.Sid, ssid));
  else
    printf ("unreadable\n");
}
void
print_token_statistics ()
{
  TOKEN_STATISTICS *stats = (TOKEN_STATISTICS *) gti (TokenStatistics);

  printf ("Statistics: ");
  if (stats)
    {
      printf ("TokenId: %lu %lu\n", stats->TokenId.HighPart,
				    stats->TokenId.LowPart);
      printf ("AuthenticationId: %lu %lu\n", stats->AuthenticationId.HighPart,
					     stats->AuthenticationId.LowPart);
      printf ("ExpirationTime: %lx%lx\n", stats->ExpirationTime.HighPart,
					  stats->ExpirationTime.LowPart);
      printf ("TokenType: ");
      if (stats->TokenType == TokenPrimary)
        printf ("Primary\n");
      else if (stats->TokenType == TokenImpersonation)
        printf ("Impersonation\n");
      else
        printf ("Unknown: %d\n", stats->TokenType);
      printf ("ImpersonationLevel: ");
      switch (stats->ImpersonationLevel)
	{
	case SecurityAnonymous:
	  printf ("SecurityAnonymous\n");
	  break;
	case SecurityIdentification:
	  printf ("SecurityIdentification\n");
	  break;
	case SecurityImpersonation:
	  printf ("SecurityImpersonation\n");
	  break;
	case SecurityDelegation:
	  printf ("SecurityDelegation\n");
	default:
	  printf ("unknown: %d\n", stats->ImpersonationLevel);
	}
      printf ("DynamicCharged: %lu\n", stats->DynamicCharged);
      printf ("DynamicAvailable: %lu\n", stats->DynamicAvailable);
      printf ("GroupCount: %lu\n", stats->GroupCount);
      printf ("PrivilegeCount: %lu\n", stats->PrivilegeCount);
      printf ("ModifiedId: %lu %lu\n", stats->ModifiedId.HighPart,
				    stats->ModifiedId.LowPart);
    }
  else
    printf ("unreadable\n");
}

void
print_security_descriptor (HANDLE token, const char *disp_what)
{
  char sd_buf[4096];
  DWORD lret = 0;
  PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) sd_buf;

  printf ("%s SecurityDescriptor: ", disp_what);
  if (!GetKernelObjectSecurity (token,
			        OWNER_SECURITY_INFORMATION
			        | GROUP_SECURITY_INFORMATION
			        | DACL_SECURITY_INFORMATION,
			        sd, 4096, &lret))
    {
      printf ("unreadable, ");
      if (lret > 4096)
        printf ("Security descriptor should be %lu bytes\n", lret);
      else
	printf ("GetKernelObjectSecurity ging nich: %lu\n", GetLastError ());
      return;
    }

  char ssid[256];
  PSID sid;
  BOOL dummy;

  if (!GetSecurityDescriptorOwner (sd, &sid, &dummy))
    printf ("\n  GetSecurityDescriptorOwner %lu", GetLastError ());
  else
    printf ("\n  Owner: %s", convert_sid_to_string_sid (sid, ssid));

  if (!GetSecurityDescriptorGroup (sd, &sid, &dummy))
    printf ("\n  GetSecurityDescriptorGroup %lu", GetLastError ());
  else
    printf ("\n  Group: %s", convert_sid_to_string_sid (sid, ssid));

  PACL acl;
  BOOL acl_exists;
        
  if (!GetSecurityDescriptorDacl (sd, &acl_exists, &acl, &dummy))
    printf ("\n  GetSecurityDescriptorDacl %lu\n", GetLastError ());
  else
    print_acl (acl);
}

void
print_token_info (HANDLE token, BOOL with_privs)
{
  tok = token;
  print_type ();
  print_impersonation_level ();
  print_source ();
  print_owner ();
  print_user ();
  print_primary_group ();
  print_groups (TokenGroups, "Groups");
  print_default_dacl ();
  print_my_proc_dacl ();
  print_security_descriptor (token, "Token");
  print_token_statistics ();
  if (with_privs)
    print_privileges ();
  print_groups (TokenRestrictedSids, "RestrictedSids");
}

#ifndef NTCT

int
main (int argc, char **argv)
{
  HANDLE token;
  HANDLE proc = GetCurrentProcess ();

  if (argc > 1 && argv[1][0] == '-')
    {
      proc = OpenProcess (MAXIMUM_ALLOWED, FALSE, atoi (argv[1] + 1));
      if (!proc)
	return error ("OpenProcess");
      --argc;
    }
  if (!OpenProcessToken (proc,
                         MAXIMUM_ALLOWED, //TOKEN_QUERY|TOKEN_QUERY_SOURCE,
                         &token))
    return error ("OpenProcessToken");
  print_token_info (token, argc > 1);
  print_security_descriptor (proc, "Process");
  return 0;
}

#endif

-------------- next part --------------
--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple


More information about the Cygwin mailing list