delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2011/10/04/13:54:42

X-Recipient: archive-cygwin AT delorie DOT com
X-Spam-Check-By: sourceware.org
Date: Tue, 4 Oct 2011 19:53:41 +0200
From: Corinna Vinschen <corinna-cygwin AT cygwin DOT com>
To: cygwin AT cygwin DOT com
Subject: Re: admin privileges when logging in by ssh?
Message-ID: <20111004175341.GA14345@calimero.vinschen.de>
Reply-To: cygwin AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
References: <rg0q679hpajl00ujv34jtmavsanhpb6n2t AT 4ax DOT com> <fb5s67hrbvq8lej86nqjhfp0et01fc6lsf AT 4ax DOT com> <20111004094440 DOT GB14728 AT calimero DOT vinschen DOT de> <0s9m87drlejguq5s9u6njre69spr5sd8o6 AT 4ax DOT com>
MIME-Version: 1.0
In-Reply-To: <0s9m87drlejguq5s9u6njre69spr5sd8o6@4ax.com>
User-Agent: Mutt/1.5.21 (2010-09-15)
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Unsubscribe: <mailto:cygwin-unsubscribe-archive-cygwin=delorie DOT com AT cygwin DOT com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

--Nq2Wo0NMKNjxTN9z
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline

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

--Nq2Wo0NMKNjxTN9z
Content-Type: text/plain; charset=utf-8
Content-Disposition: attachment; filename="gettokinfo.cc"

#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


--Nq2Wo0NMKNjxTN9z
Content-Type: text/plain; charset=us-ascii

--
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
--Nq2Wo0NMKNjxTN9z--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019