[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: A possible way to have NT authentic against LDAP (RFI)



hi,

Lars Nordin wrote:
> 
> I don't know how well this would work but I've causally been looking around
> for a way to have Linux and NT boxes authentic against one data source.
> 
Same here.  I've been looking into this, off and on, for a month or two
now. 

(disclaimer: not an expert in any of the following technologies, I only
found out what ldap was about a month ago. So please forgive any newbie
mistakes : )

 I didn't like any of the NIS based solutions I found, I assume they all
inherit NIS's security holes(?, clear text etc. is that true?).

One ldap solution which looks like it *may* work is on centered around
"password filters".
http://msdn.microsoft.com/library/psdk/logauth/pswd_portal_9tph.htm . 
Has anyone implemented such a scheme yet?  A windows "password filter"
is a DLL that is called up by the system whenever and and more
importantly however the user changes their password.  This means that
the password can be changed in usrmgr or alt+ctl+del then "change
password" and the dll will be called all the same, (or that's what I got
from the reference : )  What we'd be interested in is this function...

NTSTATUS PasswordChangeNotify(
  PUNICODE_STRING UserName,
  ULONG RelativeId,
  PUNICODE_STRING NewPassword
);

The API states that this function will be called by the system, from our
DLL, with the user's name and password.  We can *conceptually* have this
function run an ldap query to update a foreign ldap server.  I'm
planning to implement this on windows 2k but the ASDI SDK (windoze's
ldap SDK) can be installed on win95 or NT4 (I believe).

On the unix-side, we can wrap the passwd command to do the same thing.

I would love to hear what everybody thinks of this (Even if it's to say
this idea sucks! : ).  Anybody worked with password filter's before?
(even if it's just to install one :) It's coming down to the wire and I
have to settle on an implementation soon. 

If anyone wants to persue (read *hack*) this, please feel free to
contact me.  I'll be looking at this scheme for at least the next few
days.

I've attached the sample code I found in microsoft documentation
(passwordnotify.c) and a minimal password filter which compiles but
doesn't work yet (ldap_passwordnotify.c).  (I may not be installing it
right I believe, any light on this would be appreciated greatly)  Also I
have no ldap code yet.

Thanks in advance for comments, pointers, criticisms.
Kervin
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <ntsecapi.h>

#define STATUS_SUCCESS (NTSTATUS)0

_declspec(dllexport) NTSTATUS NTAPI PasswordChangeNotify(PUNICODE_STRING UserName, ULONG RelativeId, PUNICODE_STRING Password)
{
	FILE *o;
    WCHAR String[ 256 ];

	o=fopen("w+", "passwdchgfile.txt");
    swprintf(String,
        L"Password for account %.*ls (rid 0x%x) changed to %.*ls\n",
        UserName->Length / sizeof(WCHAR),
        UserName->Buffer,
        RelativeId,
        Password->Length / sizeof(WCHAR),
        Password->Buffer
        );
     /*OutputDebugStringW( String );*/
	fprintf(o, "%s", String);
    ZeroMemory(String, sizeof(String));

    return STATUS_SUCCESS;
}

_declspec(dllexport) BOOL NTAPI InitializeChangeNotify(void)
{
	return TRUE;
}

  


   /*++

   Copyright (c) 1995, 1996  Microsoft Corporation

   Module Name:

       pswdntfy.c

   Abstract:

       This module illustrates how to implement password change
       notification and password filtering in Windows NT 4.0.

       Password change notification is useful for synchronization of
       non-Windows NT account databases.

       Password change filtering is useful for enforcing quality or
       strength of passwords in an Windows NT account database.

       This sample illustrates one approach to enforcing additional
       password quality.

   Author:

       Scott Field (sfield)    14-May-96

   --*/

   #include <windows.h>
   #include "ntsecapi.h" // \mstools\samples\win32\winnt\security\include\

   #ifndef STATUS_SUCCESS
   #define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)
   #endif

   NTSTATUS
   NTAPI
   PasswordChangeNotify(
       PUNICODE_STRING UserName,
       ULONG RelativeId,
       PUNICODE_STRING Password
       )
   /*++

   Routine Description:

       This (optional) routine is notified of a password change.

   Arguments:

       UserName - Name of user whose password changed

       RelativeId - RID of the user whose password changed

       NewPassword - Cleartext new password for the user

   Return Value:

       STATUS_SUCCESS only - errors from packages are ignored.

   --*/
   {

   #ifdef DEBUG
       WCHAR String[ 256 ];

       swprintf(String,
           L"Password for account %.*ls (rid 0x%x) changed to %.*ls\n",
           UserName->Length / sizeof(WCHAR),
           UserName->Buffer,
           RelativeId,
           Password->Length / sizeof(WCHAR),
           Password->Buffer
           );

       OutputDebugStringW( String );

       ZeroMemory(String, sizeof(String));
   #endif

       return STATUS_SUCCESS;
   }

   BOOL
   NTAPI
   PasswordFilter(
       PUNICODE_STRING UserName,
       PUNICODE_STRING FullName,
       PUNICODE_STRING Password,
       BOOL SetOperation
       )
   /*++

   Routine Description:

       This (optional) routine is notified of a password change.

   Arguments:

       UserName - Name of user whose password changed

       FullName - Full name of the user whose password changed

       NewPassword - Cleartext new password for the user

       SetOperation - TRUE if the password was SET rather than CHANGED

   Return Value:

       TRUE if the specified Password is suitable (complex, long, etc).
        The system will continue to evaluate the password update request
        through any other installed password change packages.

       FALSE if the specified Password is unsuitable. The password change
        on the specified account will fail.

   --*/
   {
       BOOL bComplex = FALSE; // assume the password in not complex enough
       DWORD cchPassword;
       PWORD CharType;
       DWORD i;
       DWORD dwNum = 0;
       DWORD dwUpper = 0;
       DWORD dwLower = 0;

       //
       // check if the password is complex enough for our liking by
       // checking that at least two of the four character types are
       // present.
       //

       CharType = HeapAlloc(GetProcessHeap(), 0, Password->Length);
       if(CharType == NULL) return FALSE;

       cchPassword = Password->Length / sizeof(WCHAR);

       if(GetStringTypeW(
           CT_CTYPE1,
           Password->Buffer,
           cchPassword,
           CharType
           )) {

           for(i = 0 ; i < cchPassword ; i++) {

               //
               // keep track of what type of characters we have encountered
               //

               if(CharType[i] & C1_DIGIT) {
                   dwNum = 1;
                   continue;
               }

               if(CharType[i] & C1_UPPER) {
                   dwUpper = 1;
                   continue;
               }

               if(CharType[i] & C1_LOWER) {
                   dwLower = 1;
                   continue;
               }

               if(!(CharType[i] & (C1_ALPHA | C1_DIGIT) )) {

                   //
                   // any other character types make the password complex
                   //

                   dwNum = 2;

                   break;
               }
           } // for

           //
           // Indicate whether we encountered enough password complexity
           //

           if( (dwNum + dwUpper + dwLower) >= 2 )
               bComplex = TRUE;

           ZeroMemory( CharType, Password->Length );
       } // if

       HeapFree(GetProcessHeap(), 0, CharType);

       return bComplex;
   }

   BOOL
   NTAPI
   InitializeChangeNotify(
       void
       )
   /*++

   Routine Description:

       This (optional) routine is called when the password change package
       is loaded.

   Arguments:

   Return Value:

       TRUE if initialization succeeded.

       FALSE if initialization failed. This DLL will be unloaded by the
        system.

   --*/
   {

   #ifdef DEBUG
       OutputDebugString( TEXT("Initialize Change Notify called!\n") );
   #endif

       //
       // initialize any critical sections associated with password change
       // events, etc.
       //

       return TRUE;
   }

   /********

   pswdntfy.def
   ------------

   LIBRARY pswdntfy

   EXPORTS
       InitializeChangeNotify
       PasswordChangeNotify
       PasswordFilter

   ********/