PATCH: krb5-1.2.4 Set security on file cache in NT/2000

PATCH: krb5-1.2.4 Set security on file cache in NT/2000

Post by Alistair Mack » Wed, 24 Apr 2002 01:21:12



All,

The following patch affords NTFS security on a file cache should you
choose to use one (to get Oracle 8 to talk to MIT in NT, file caching
is the only way). The way it's set up now sets read/write access to
the owner of the process creating the cache file (ie by running Leash
or kinit) and the world group "Everyone" delete access so that if
another user logs in, the existing cache may be deleted and hence
overwritten. Leash complains a little about the fact that it can't
read the file (permission denied), but as mentioned, it will still get
deleted and a new one created. You can play with the permissions for
owner and everyone by changing the #define's
OWNER_CCACHE_ACCESS_RIGHTS and WORLD_CCACHE_ACCESS_RIGHTS near the top
of the file to other valid values from winnt.h

Replace src/lib/krb5/ccache/file/fcc_init.c with the following and
rebuild the DLL's

===== fcc_init.c BEGIN ====

/*
 * lib/krb5/ccache/file/fcc_init.c
 *
 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization
contemplating
 *   export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity
pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T.
software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without
express
 * or implied warranty.
 *
 *
 * This file contains the source code for krb5_fcc_initialize.
 */

#include <errno.h>
#include "fcc.h"

#ifdef _WIN32

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

/*
 * Set NT operating system security on new ccache file
 *
 * Will attempt to set RW permission for the current user, and delete
 * permission for "Everyone". Since ccache filenames in Windows are
not
 * by default created with some identifier for the current uid(),
 * somebody else logging on at the workstation needs to be able to
 * delete the ccache to initialse their own
 */

/*
 * Adapted from Microsoft KB articles
 * "HOWTO: Add an Access-Allowed ACE to a File (Q102102)" and
 * "HOWTO: Retrieve Current User and Domain Names on Windows NT,
Windows 2000, or Windows XP (Q111544)"
 * and the MSDN reference on "well known" SIDs
 *
 * The two KB artices were combined to get a routine that gets the SID
 * of the current user (running this process), create a NULL DACL
 * and add an access allowed ACE to this DACL giving RW access to this
user
 * only + another ACE affording delete to everyone else.
 */

/*
 * Must use Windows mem manager to ensure security structs are DWORD
aligned
 */

#define myheapalloc(x) (HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
x))
#define myheapfree(x)  (HeapFree(GetProcessHeap(), 0, x))

/* File access rights for the owner of the ccache */
#define OWNER_CCACHE_ACCESS_RIGHTS (GENERIC_READ | GENERIC_WRITE)

/*
 *  ..and for the rest of the world. If a fixed name ccfile is used
 * (ie not using USERNAME from environment or some such), the rest of
the
 * world must be able to overwrite an existing ccache when they kinit
 */

#define WORLD_CCACHE_ACCESS_RIGHTS (DELETE)

int
set_windows_security (char *lpszFileName)
{
  /*
   * Values for errno, I've best guessed. Suggestions anyone?
   */

  // SID variables.
  HANDLE hToken = NULL;
  PTOKEN_USER ptiUser = NULL;
  DWORD cbti = 0;
  SID_IDENTIFIER_AUTHORITY sia = SECURITY_WORLD_SID_AUTHORITY;
  PSID pSidEveryone = NULL;

  // New SD variables.
  SECURITY_DESCRIPTOR newSD;

  // ACL variables.
  ACL_SIZE_INFORMATION AclInfo;

  // New ACL variables.
  PACL pNewACL = NULL;
  DWORD cbNewACL = 0;

  // Assume function will fail.
  int retval = -1;

  SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;

  //
  // STEP 1: Get SID of the account this process is running as.
  //

  // Get the calling thread's access token.
  if (!OpenThreadToken (GetCurrentThread (), TOKEN_QUERY, TRUE,
&hToken))
    {

      if (GetLastError () != ERROR_NO_TOKEN)
        goto cleanup;

      // Retry against process token if no thread token exists.
      if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY,
&hToken))
        goto cleanup;
    }

  // Obtain the size of the user information in the token.
  if (GetTokenInformation (hToken, TokenUser, NULL, 0, &cbti))
    {
      // Call should have failed due to zero-length buffer.
      // ie we don't expect to get here!
      goto cleanup;
    }
  else
    {

      // Call should have failed due to zero-length buffer.
      if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
        goto cleanup;
    }

  // Allocate buffer for user information in the token.
  ptiUser = (PTOKEN_USER) myheapalloc (cbti);
  if (!ptiUser)
    goto cleanup;

  // Retrieve the user information from the token.
  if (!GetTokenInformation (hToken, TokenUser, ptiUser, cbti, &cbti))
    goto cleanup;

  //
  // Create a "well known" SID for the group "Everyone"
  //

  if (!AllocateAndInitializeSid
      (&sia, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0,
&pSidEveryone))
    {
      errno = ENOMEM;
      goto cleanup;
    }

  //
  // Initialize new SD.
  //
  if (!InitializeSecurityDescriptor (&newSD,
SECURITY_DESCRIPTOR_REVISION))
    {
      errno = EINVAL;
      goto cleanup;
    }
  //
  // Get size information for DACL.
  //
  AclInfo.AceCount = 0;         // Assume NULL DACL.
  AclInfo.AclBytesFree = 0;
  AclInfo.AclBytesInUse = sizeof (ACL);

  //
  // Compute size needed for the new ACL.
  // We're adding two ACEs to it
  //
  cbNewACL = sizeof (ACL) + (2 * sizeof (ACCESS_ALLOWED_ACE)) +
GetLengthSid (ptiUser->User.Sid) + GetLengthSid (pSidEveryone) - (2 *
sizeof (DWORD));        // ACE struct allows for first DWORD of contained
SID.

  //
  // Allocate memory for new ACL.
  //
  pNewACL = (PACL) myheapalloc (cbNewACL);
  if (!pNewACL)
    {
      errno = ENOMEM;
      goto cleanup;
    }

  //
  // Initialize the new ACL.
  //
  if (!InitializeAcl (pNewACL, cbNewACL, ACL_REVISION2))
    {
      errno = EINVAL;
      goto cleanup;
    }

  //
  // Add the access-allowed ACE for the current user to the new DACL.
  //

  if (!AddAccessAllowedAce
      (pNewACL, ACL_REVISION2, OWNER_CCACHE_ACCESS_RIGHTS,
ptiUser->User.Sid))
    {
      errno = EINVAL;
      goto cleanup;
    }

  //
  // Add access-allowed ACE for eveyone.
  //
  if (!AddAccessAllowedAce
      (pNewACL, ACL_REVISION2, WORLD_CCACHE_ACCESS_RIGHTS,
pSidEveryone))
    {
      errno = EINVAL;
      goto cleanup;
    }

  //
  // Set the new DACL to the new SD.
  //
  if (!SetSecurityDescriptorDacl (&newSD, TRUE, pNewACL, FALSE))
    {
      errno = EINVAL;
      goto cleanup;
    }
  //
  // Set the new SD to the File.
  //
  if (!SetFileSecurity (lpszFileName, secInfo, &newSD))
    {
      if (GetLastError () == ERROR_ACCESS_DENIED)
        errno = EACCES;
      else
        errno = EINVAL;

      goto cleanup;
    }

  retval = 0;

cleanup:

  //
  // Free allocated memory
  //

  if (hToken)
    CloseHandle (hToken);

  if (ptiUser)
    myheapfree (ptiUser);

  if (pSidEveryone)
    FreeSid (pSidEveryone);

  if (pNewACL)
    myheapfree (pNewACL);

  return retval;

}

#endif

/*
 * Modifies:
 * id
 *
 * Effects:
 * Creates/refreshes the file cred cache id.  If the cache exists, its
 * contents are destroyed.
 *
 * Errors:
 * system errors
 * permission errors
 */
krb5_error_code KRB5_CALLCONV
krb5_fcc_initialize (context, id, princ)
     krb5_context context;
     krb5_ccache id;
     krb5_principal princ;
{
  krb5_error_code kret = 0;
  int reti = 0;

  MAYBE_OPEN (context, id, FCC_OPEN_AND_ERASE);

#ifdef _WIN32
  reti = set_windows_security (((krb5_fcc_data *)
id->data)->filename);
#else
#ifndef HAVE_FCHMOD
#ifdef HAVE_CHMOD
  reti = chmod (((krb5_fcc_data *) id->data)->filename, S_IREAD |
S_IWRITE);
#endif
#else
  reti = fchmod (((krb5_fcc_data *) id->data)->fd, S_IREAD |
S_IWRITE);
#endif
#endif /* _WIN32 */

  if (reti == -1)
    {
      kret = krb5_fcc_interpret (context, errno);
      MAYBE_CLOSE (context, id, kret);
      return kret;
    }
  kret = krb5_fcc_store_principal (context, id, princ);

  MAYBE_CLOSE (context, id, kret);
  krb5_change_cache ();
  return kret;

}

===== fcc_init.c END ====

Enjoy!

 
 
 

PATCH: krb5-1.2.4 Set security on file cache in NT/2000

Post by Danilo Almeid » Wed, 24 Apr 2002 03:52:56


Thanks for the patch.  I have not yet had a chance to look at it
closely, but I do have one important questions:  Have you tried this on
Win9x?  Does it do the right thing on Win9x?

- Danilo

________________________________________________

http://mailman.mit.edu/mailman/listinfo/kerberos

 
 
 

PATCH: krb5-1.2.4 Set security on file cache in NT/2000

Post by Alistair Mack » Wed, 24 Apr 2002 18:34:50


I shouldn't think so. File system security can only be set on NTFS
volumes. AFAIK the security API's are present in Win9x, but do nothing
and probably return an error. There should perhaps be a version check
at the beginning (by calling GetVersion()) which causes the function
to do nothing and return if it is 9x

Alistair.


> Thanks for the patch.  I have not yet had a chance to look at it
> closely, but I do have one important questions:  Have you tried this on
> Win9x?  Does it do the right thing on Win9x?

> - Danilo

> ________________________________________________

> http://mailman.mit.edu/mailman/listinfo/kerberos

 
 
 

1. problems with krb5-1.2.2, Linux 2.4.x, gcc 2.95.3, glibc-2.2.3

I am trying to compile and install MIT kerberos 5-1.2.2 on a new
Slackware linux box.

My configure options are:
--enable-shared --with-krb4

Everything compiles okay.  However, when I try to run any of the
applications, I get the following error:

error while loading shared libraries: /usr/local/lib/libkrb5.so.3: \
undefined symbol: stat

How do I fix this?

Thank you,
Ashok Aiyar

2. iPAQ 3850, Navman 3000 GPS sleeve and Destinator software

3. need help installing krb5-1.0.5 on Solaris 2.4

4. US-FL-RPG400 / AS400 PROGRAMMER

5. krb5-1.2.4-beta1 compile

6. LHA && LHARC

7. krb5-1.2.4 is released

8. ZTerm 0.8

9. New cygwin patches for krb5-1.3-alpha2 and krb5-current (snapshot)

10. krb5 on Solaris 2.4

11. login.krb5 on Solaris 2.4

12. krb5-b4 telnet on solaris 2.4

13. Windows 2000 security patch - 16megs