asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search










Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Programming a Visual Basic Component to Change NLTM Passwords
By Bill Craun
Rating: 3.9 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

    Introduction

    Several intriguing Microsoft technologies can be integrated to create a simple Windows Distributed Internetwork Application Architecture (DNA) application. Windows DNA technologies can be used to develop highly sophisticated, distributed, cooperating component-based solutions that use the integrated services provided by the Windows platform. DNA applications exist in a multitier environment of client/presentation services, application services, and data services. The DNA components corresponding to each tier include:

    Client/Presentation Services

    • HTML /DHTML
    • Component Object Model (COM)
    • Scripting
    • Win32 API

    Application Services

    • COM+ / Microsoft Transaction Server (MTS)
    • Internet Information Server (IIS)
    • Microsoft Message Queue Server (MSMQ)
    • Active Server Pages (ASP)

    Data Services

    • Universal Data Access
    • ADO
    • OLE-DB
    For a more in-depth discussion of Windows DNA please refer to the Microsoft White Paper at http://www.microsoft.com/dna/overview/dnawp.asp

    The application we will develop in this article is a browser-based Windows NT domain account password-changing utility that runs as a component in an MTS package on IIS and is accessible via the Internet. While IIS 4.0 provides native account password-changing functionality through the use of .htr files and an Internet Server API (ISAPI) extension, it does not provide for easy modification and does not run as an MTS component by default. The application we will develop demonstrates an extensible framework that could be easily enhanced to provide additional account-maintenance functionality specific to your individual requirements. You will also want to gain additional expertise developing Windows DNA applications, and sometimes the best way is to do it the old-fashioned way; roll your own.

    WARNING
    The application in this article will modify NT domain account passwords. Until you fully understand how the code works, you should only run it on a test machine in a domain where security will not be jeopardized by random password changes.

    Audience

    The target audience for this article is for Visual Basic and ASP developers looking to enhance their COM skills by building scalable, distributed Internet client-server applications involving IIS and MTS. The article assumes that you are familiar with the concepts of COM programming and ASP development. The emphasis will be on the overall application framework and not on advanced VB component development or ASP scripting. The article will step you through creating an MTS package and installing the component we will create. This is a very trivial task so don’t worry. The article does assume that you know how to create and configure a new Web site using IIS/PWS. This is required to run the ASP page that will call upon our component to perform the password change. Alternately, you can place the page in an existing site with no problems. It’s up to you. However, if the steps required to create a basic Web site are unclear, please refer to the IIS online documentation for further instructions on how to create a Web site.

    You will undoubtedly, as I have, find many additional improvements to this application and will find that enhancements are extremely easy to implement using a component-based approach. Let’s get started building our Windows DNA application.

    Here an Object, There an Object, Everywhere an Object

    Let’s begin by providing a brief explanation of the application’s functionality. The application is based on a single ActiveX Dynamic Link Library (DLL) installed as a component in an MTS package (for our simple application, MTS and IIS will be co-located on the same server).The DLL’s single class module is instantiated (called) from an ASP page when a user navigates to the page and submits the required form data. The component also encapsulates the Active Directory Services Interface (ADSI), specifically the NTLM provider, required to perform NT domain account-management functions, such as changing user passwords (more information on ADSI can be found on the 15Seconds.com site at http://www.15seconds.com/Issue/980304.htm and http://www.15seconds.com/Issue/980316.htm . The component also dynamically generates and returns HTML responses to the user’s browser. This functionality, encapsulating ASP to create HTML/DHTML, is very similar to the new Web Class server-side components introduced with Visual Basic 6.0.

    In addition, Windows NT event logging is performed by the component. Using a few basic Win32 APIs, the NetBIOS name of the domain controller is determined, and the Application event log for this machine is written to. This provides an audit trail of all attempted password-change operations performed by the component.

    There are many benefits for creating server-side components to encapsulate business logic and/or data-access functionality. First of all, components created using the powerful Visual Basic development environment can be used to extend IIS in virtually limitless ways. Not only can VB match all of the capabilities exposed by ASP, but can also integrate other server-side COM libraries to provide developers with unlimited opportunities and affords more robust scalability than ASP. ASP execution speed is greatly accelerated due to the in-process nature in which components run within IIS. By using compiled DLLs, your ASP code is effectively encrypted and provides a mechanism for protecting your intellectual property from prying eyes. Dependable versioning can be also be employed via a component-based architecture. Clearly, the next generation of distributed Internet client-server development will involve server-side components responsible for dynamic HTML/DHTML generation. Using components to wrap the ASP object helps the developer to create browser-independent code quickly and easily.

    Assemble Your Toolbox

    Aside from NT, Visual Basic (VB), and your favorite HTML editor, all of the required DNA technologies required for this application are available in the Windows NT 4.0 Option Pack, which you can download for free from http://www.microsoft.com/ntserver/nts/downloads/recommended/NT4OptPk/default.asp . We will need the following: Application Development Tools

    • VB 5.0 or 6.0 to create the ActiveX DLL server component
    • HTML editor to create the ASP form

    Server-Side Applications/Components

    • NT Server/Workstation 4.0
    • IIS 4.0 or Personal Web Server (PWS)
    • MTS 2.0
    • ADSI 2.0, specifically the NTLM provider
    • ASP

    Client-Side Applications/Components

    • 32-bit operating system (Win9x or NT Server/Workstation 4.0)
    • JavaScript capable browser

    Creating the DNA Application

    The application consists of one ActiveX DLL and one ASP page. Let’s begin with the ActiveX DLL.

    1. Open VB and start a new ActiveX DLL project.
    2. Rename the default project "Project1" to "aciChangePassword."
    3. Rename the default class module "Class1" to "Main."

      Figure 1

    4. Set its instancing properties to "5 -- MultiUse."

      Figure 1

    5. Set the Threading Model to "Apartment Threaded."

      Figure 1

    6. Set a reference to the Microsoft Active DS Type Library (activeds.tlb).
    7. Set a reference to the Microsoft Transaction Server Type Library (mtxas.dll).

      Figure 1

    8. Set other desired project properties, and save the project. When prompted for the individual file names, name the Class "Main.cls" and name the Project "aciChangePassword.vbp."
    9. Open the code window for Main and include the following code in the General declarations section.
      
      
      Option Explicit
      
      ' declare MTS object context variable
      Dim objCtx As ObjectContext
      
      ' declare the IIS intrinsic object variables
      Dim objApplication As Object
      Dim objRequest As Object
      Dim objResponse As Object
      Dim objServer As Object
      Dim objSession As Object
      
      
      
      These are the variable declarations for the IIS intrinsic objects that will be used to capture and maintain the object context for each client session. The object context is a reference passed from IIS/MTS to the DLL and allows us to maintain state information for each client session. The object context is also the mechanism that we will use to "talk with" IIS/MTS and will be used to generate the client-side HTML that is returned to the browser. The IIS intrinsic objects correspond directly to the ASP methods and properties that are exposed by the ASP object model (asp.dll). In order for HTML to be dynamically created and returned to a browser, the Response object is required, exactly like an ASP page. We will only be concerned with the Response object in this article, but all declarations are included for clarity.
    10. Next, we need to declare the Win32 APIs required to support NT event logging. Whenever an attempt is made to change a user password, this is interesting, and as NT administrators, we would like to know about it. What actually happens is the NetBIOS machine name of the Primary Domain Controller (PDC) is determined and a request is sent to this machine to create an entry in its Application Event log. All attempts performed via the component, success or failure, are logged.
      
      
      ' API declares for PDC event logging
      Private Declare Function RegisterEventSource _ 
      Lib "advapi32.dll" Alias "RegisterEventSourceA" _
      (ByVal lpUNCServerName As String, ByVal lpSourceName As String) As Long
      
      Private Declare Function DeregisterEventSource _
      Lib "advapi32.dll" (ByVal hEventLog As Long) As Long
      
      Private Declare Function ReportEvent _
      Lib "advapi32.dll" Alias "ReportEventA" _
      (ByVal hEventLog As Long, ByVal wType As Integer, _ 
      ByVal wCategory As Integer, ByVal dwEventID As Long, _
      ByVal lpUserSid As Any, ByVal wNumStrings As Integer,_
      ByVal dwDataSize As Long, plpStrings As Long, lpRawData _ 
      As Any) As Boolean
      
      Private Declare Function GetLastError Lib "kernel32" () As Long
      
      Private Declare Sub CopyMemory _
      Lib "kernel32" Alias "RtlMoveMemory"_
      (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)
      
      Private Declare Function GlobalAlloc _
      Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
      
      Private Declare Function GlobalFree _
      Lib "kernel32" (ByVal hMem As Long) As Long
      
      Private Declare Function NetGetDCName _
      Lib "netapi32.dll" (ServerName As Long, domainname _
      As Byte, bufptr As Long) As Long
      
      Private Declare Sub lstrcpyW Lib "kernel32" _
      (dest As Any, ByVal src As Any)
      
      Private Declare Function NetApiBufferFree& Lib "netapi32" (ByVal Buffer As Long)
      
      ' constant declares for PDC event logging
      Private Const EVENTLOG_ERROR_TYPE = 1
      Private Const EVENTLOG_INFORMATION_TYPE = 4
      
      
      
      Add this code to the general declarations section of the code module. Note the constant declarations. These indicate what types of event-log entries we will be creating. In our case, we only want to create informational and error event-log entries. Informational entries will be shown in the event log with the blue, informational icon. Error entries are shown with the red, stop sign icon.
    11. Add a new Public Sub called SetPassword in the code window and include the following code. This is the code that actually performs the password change. As you can see, this sub accepts four arguments: pstrUser, pstrOldPassword, pstrNewPassword, and pstrConfirmPassword. These are the parameters that are passed from the ASP page (we will develop later in the article), and these parameters are required to change an NT domain account password. The reason that the parameters are passed as arguments to the sub, instead of being declared as properties in the component, is a function of performance and efficiency. Whenever a property of a component running on a remote server is set, a trip across the network must be made to accomplish this. Let’s assume that I’ve declared each of these arguments as properties in the component, instead of declaring them as simple string arguments to the SetPassword Sub. In order to have the variables populated with values, I would have to explicitly assign their value in the ASP page, which would require four separate (4) calls to the component. Imagine if my component runs on a server located in some other continent. All of these calls require some amount of bandwidth, and in large-scale environments, with hundreds or even thousands of components running simultaneously, LAN/WAN performance can be severely impacted by these unnecessary calls. Instead, where possible, arguments from ASP pages should be passed in the call to the method or subroutine. This only requires one call to the component and, therefore, one trip across the network to the server running the component. This is much more efficient and maximizes available bandwidth by eliminating unnecessary LAN/WAN traffic.
      
      
      ' change the user's password
      
      Public Sub SetPassword(ByVal pstrUser As String, _
      	ByVal pstrOldPassword As String, ByVal pstrNewPassword _
      	As String, ByVal pstrConfirmPassword As String)
      
          Dim adsUser As IADsUser
          Dim strDialogText As String
          
          On Error GoTo ChangePasswordErrorHandler
          
          ' set MTS object references
          Call GetObjectReferences
          
          If pstrUser <> vbNullString Then
          
              If (Not (pstrOldPassword = vbNullString)) And _
      			(Not (pstrNewPassword = vbNullString)) Then
              
                  If (Not (pstrNewPassword <> pstrConfirmPassword)) Then
              
                      ' set the ADSI provider to WindowsNT
      				' (my NT domain is ateam, substitute your domain here)
                      Set adsUser = GetObject("WinNT://ateam/" & pstrUser & ",user")
              
                      ' call the ADSI ChangePassword method with the
      				' form supplied user/password values
                      adsUser.ChangePassword pstrOldPassword, pstrNewPassword
              
                      ' log the update to the PDC
                      Call LogNTEvent("Password change for user " & pstrUser &_
      					 " successful.", EVENTLOG_INFORMATION_TYPE, 1001)
                      
                      ' generate the alert dialog HTML
                      strDialogText = """Password change for user " & pstrUser &_
      					" successful."""
                      Call CreateAlertMarkup(strDialogText)
                      
                  Else
                  
                      ' generate the alert dialog HTML
                      strDialogText = """New/Confirm passwords are different."""
                      Call CreateAlertMarkup(strDialogText)
                      
                  End If
                  
              Else
                  
                  ' generate the alert dialog HTML
                  strDialogText = """A value for Old/New passwords is required."""
                  Call CreateAlertMarkup(strDialogText)
              
              End If
          
          End If
          
          Set adsUser = Nothing
          
          ' commit the transaction and release object references
          objCtx.SetComplete
          
          ' release MTS object references
          Call ReleaseObjectReferences
          
      Exit Sub
      
      '**********
      
      ChangePasswordErrorHandler:
      
          ' log the failed attempt
          Call LogNTEvent("Attempted password change for user " & pstrUser &_
      		" failed", EVENTLOG_ERROR_TYPE, 1003)
          
          ' generate the alert dialog HTML with PASSFILT.DLL simulated error message
          strDialogText = """Password for user " & pstrUser & " could not be changed.\n\n"
          strDialogText = strDialogText & "1. Your password cannot " &_
      		"be the same as any of your previous 5 passwords.\n"
          strDialogText = strDialogText & "2. Passwords must be 8-14 " &_
      		"characters in length.\n"
          strDialogText = strDialogText & "3. Passwords must also contain " &_
      		"characters from at least (3) of the following (4) classes:\n"
          strDialogText = strDialogText & "      - English uppercase letters (A-Z)\n"
          strDialogText = strDialogText & "      - English lowercase letters (a-z)\n"
          strDialogText = strDialogText & "      - Westernized Arabic numerals (0-9)\n"
          strDialogText = strDialogText & "      - Nonalphanumeric special" &_
      		" characters (such as punctuation symbols)\n"
          strDialogText = strDialogText & "4. Passwords may not contain " &_
      		"your user name or any part of your full name."""
          Call CreateAlertMarkup(strDialogText)
          
          ' abort the transaction and release object references
          objCtx.SetAbort
          
          ' release MTS object references
          Call ReleaseObjectReferences
          
      End Sub
      
      
      

    SetPassword Code

    Many interesting things occur in SetPassword. Let’s step through it to provide an overview of how the code works.

    A call is made to SetPassword when an ASP form (we will create this page later) is submitted. Four arguments are passed that correspond to form data typed by the user. The arguments include the user name, the user’s current password, the user’s new password, and the user’s confirmed new password.

    An error handler is declared so that any error generated from the class will be trapped. The error handler stores an error message indicating that the attempted password change was unsuccessful. On my domain, I have implemented PASSFILT.DLL, which forces new passwords to contain at least 6 characters, have mixed case, and contain numbers and/or symbols. This is also known as a strong password policy. PASSFILT.DLL is activated through a registry setting on PDCs and BDCs. More about this can be found in the Microsoft Knowledge Base article Q161990. The dialog text produced by our class is very similar to the dialog text produced when an unsuccessful attempt to change a user’s password is made with a strong password policy.

    Next, because we want to use ADSI to change the user’s password, we need to declare a variable (adsUser) to hold a reference the ADSI User object (IADsUser).

    
    
    Dim adsUser As IADsUser
    
    
    
    The variable adsUser can then be used to obtain a reference to a specific user in the NT domain account database, or SAM, as it’s most commonly referred. Possessing a reference to the User object allows us to use ADSI to programmatically perform any account-maintenance operation, including password changes, for the user, which are typically done using a GUI-based NT account-management tool such as User Manager for Domains. For example, we can also create and delete users.

    A call is made to GetObjectReferences, which establishes the MTS Object Context, allowing us to wrap the entire execution of our SetPassword Sub in an MTS transaction. GetObjectReferences also creates the IIS intrinsic objects required for ASP functionality within our DLL . The code for this sub is discussed in a later step. For now, just understand that we will be using an MTS transaction to notify MTS of success or failure for the entire password-change operation. We will set the stage for our transaction in this sub. After returning control from GetObjectReferences, we will have the ability to create an MTS transaction when we are ready.

    After we have verified that the arguments passed from the ASP form meet simple validation criteria (i.e., all arguments not NULL), we obtain a reference to the NT domain account we want to modify with the following line of code.

    
    
    Set adsUser = GetObject("WinNT://ateam/" & pstrUser & ",user")
    
    
    
    The GetObject method of ADSI is used to retrieve objects from a particular directory store, which is specified as an argument. In Active Directory parlance, the term provider is used to identify the target directory store. In this case, we want to obtain a user from the NT SAM so we will need to specify the NTLM provider (WinNT://). Other ADSI providers exist for Lightweight Directory Access Protocol (LDAP://) and for the IIS metabase (IIS://). You will also need to substitute your NT domain name in place of “ateam.” The last GetObject argument “user” tells ADSI that we will be retrieving a user account object from the SAM. After this line of code has executed, adsUser will hold a reference to the NT account passed as an argument from the ASP form in pstrUser.

    We are now ready to change the user password. All we need to do is to call the ADSI ChangePassword method for the user object adsUser. We will need to supply two string parameters to ChangePassword: strOldPassword and strNewPassword. These correspond to the user’s current password (strOldPassword) and the user’s desired new password (strNewPassword). Both arguments are supplied by the user from the ASP form. Assuming our error handler has not been triggered, an attempt will be made via ADSI to change the user’s password.

    At this point, to document success or failure of the attempted password change, a call is made to the LogNTEvent Sub and an Application Event log entry is made on the PDC.

    Components can be designed to explicitly support MTS transactions, or they can be written without regard to them. By supporting MTS transactions, your components achieve greater stability and scalability because you are providing MTS with additional information about your execution state and are provided with an additional layer of control.

    We will be using an MTS transaction in our component to control the password-change process. Assuming ADSI was successful, we notify MTS that our transaction has completed and give MTS the go-ahead to commit any work we may have performed up to this point. We make MTS aware of this with the following line:

    
    
    objCtx.SetComplete
    
    
    
    Alternately, we would need to notify MTS of failure, which aborts the currently running transaction with the following line:
    
    
    objCtx.SetAbort
    
    
    
    You will notice that this is how we abort a transaction when the error handler is triggered. What you should remember about a transaction is that it is defined as an atomic unit of work that, as a whole, either succeeds or fails; no in-between states exist.
    1. Add a Private Function named GetPrimaryDCName to the code module. This function accepts one string argument, pstrMachineName, which is really the name of the NT domain where the PDC you want to target resides.
      
      
      ' returns the PDC machine name
      Private Function GetPrimaryDCName(pstrMachineName As String) As String
      
          Dim DCName As String
          Dim DCNPtr As Long
          Dim DNArray() As Byte
          Dim DCNArray(100) As Byte
          Dim result As Long
          Dim strDialogText As String
          
          ' find the PDC
          DNArray = pstrMachineName & vbNullChar
          result = NetGetDCName(0&, DNArray(0), DCNPtr)
          
          If result <> 0 Then
          
               ' generate the alert dialog HTML
               strDialogText = """Domain controller for " & pstrMachineName & " not found."""
               Call CreateAlertMarkup(strDialogText)
               
              Exit Function
             
          End If
          
          lstrcpyW DCNArray(0), DCNPtr
          result = NetApiBufferFree(DCNPtr)
          DCName = DCNArray()
          GetPrimaryDCName = Left(DCName, InStr(DCName, Chr(0)) - 1)
         
      End Function
      
      
      
      The name of your NT domain where the account exists will be passed to this sub.
    2. Add a Private Sub named LogNTEvent to the code module. This code in this sub logs a message to the Application Event log of the PDC. It accepts the following arguments: sString, iLogType, and iEventID. These arguments correspond to the message text you want displayed in the event log, the type of event-log entry (Information, Warning, Error), and a numeric ID to identify the log-entry error type. Add the following code to the sub:
      
      
      ' log to the PDC Application event log
      Private Sub LogNTEvent(sString As String, iLogType As Integer, iEventID As Long)
          
          Dim bRC As Boolean
          Dim iNumStrings As Integer
          Dim hEventLog As Long
          Dim hMsgs As Long
          Dim cbStringSize As Long
          Dim strPDC As String
          Dim strDialogText As String
          
         '** substitue your domain name here ** 
      strPDC = GetPrimaryDCName("ateam")
      
          hEventLog = RegisterEventSource(strPDC, "aciChangePassword.dll")
          cbStringSize = Len(sString) + 1
          hMsgs = GlobalAlloc(&H40, cbStringSize)
          CopyMemory ByVal hMsgs, ByVal sString, cbStringSize
          iNumStrings = 1
          
          If ReportEvent(hEventLog, iLogType, 0, iEventID, 0&, iNumStrings, cbStringSize, hMsgs, hMsgs) = 0 Then
               ' generate the alert dialog HTML
              strDialogText = """Unexpected error: """ & GetLastError()
              Call CreateAlertMarkup(strDialogText)
          End If
          
          Call GlobalFree(hMsgs)
          DeregisterEventSource (hEventLog)
        
      End Sub
      
      
      
      Note the following line in the sub:
      
      
      strPDC = GetPrimaryDCName("ateam"). 
      
      
      
      You will need to substitute the name of your NT domain in place of “ateam.” You must surround the domain name with double quotes.
    3. Add a Private Sub called CreateAlertMarkup to the code window. This sub is responsible for building the HTML string that will be returned to the client browser in the form of a JavaScript alert dialog. JavaScript is used because, for the most part, it is browser-agnostic. You will notice that this is where we depend upon the IIS intrinsic Response object to return HTML directly to the user’s browser. Because we already have a reference to the user’s browser session via the IIS/MTS Object Context, we are assured of sending the appropriate dialog to the correct user. The sub accepts one string argument, pstrDialogText, which represents the string to be displayed in the JavaScript alert in the user’s browser. Add the following code to the new sub:
      
      
      ' generate JavaScript alert dialog HTML
      Private Sub CreateAlertMarkup(pstrDialogText As String)
      
          Dim strScriptingLanguage As String
          
          strScriptingLanguage = """JavaScript"""
          
          objResponse.Write vbCrLf
          objResponse.Write ("<SCRIPT LANGUAGE=" & strScriptingLanguage & ">") & vbCrLf
          objResponse.Write ("<!--") & vbCrLf
          objResponse.Write ("{") & vbCrLf
          objResponse.Write vbTab & ("window.alert(" & pstrDialogText & ");") & vbCrLf
          objResponse.Write ("}") & vbCrLf
          objResponse.Write ("-->") & vbCrLf
          objResponse.Write ("</SCRIPT>") & vbCrLf
          
      End Sub
      
      
      
    4. Add a new Private Sub named GetObjectReferences to the code module. GetObjectReferences is used to create references to the MTS ObjectContext. The MTS ObjectContext, remember, is the manner in which we will keep track and maintain separation of all running instances of the component. We would not want to get any running sessions confused because we could wind up sending the wrong HTML to the wrong browser, or worse yet, in a high-volume database environment, performing transactions (update, insert, delete, etc.) against the wrong executing sessions. Obviously, the results could be disastrous.
      
      
      Private Sub GetObjectReferences()
      
      ' get MTS object context
      Set objCtx = GetObjectContext
          
      ' get IIS intrinsic object references
      Set objApplication = objCtx.Item("Application")
      Set objRequest = objCtx.Item("Request")
      Set objResponse = objCtx.Item("Response")
      Set objServer = objCtx.Item("Server")
      Set objSession = objCtx.Item("Session")
          
      End Sub
      
      
      
      Notice that after we obtain a reference to the MTS Object Context, we then set a reference to each of the IIS intrinsic objects (Application, Request, Response, Server, and Session). As was stated earlier in the article, in order for our component to dynamically generate the HTML returned to the user’s browser, the Response object is all that’s required, but, in order to provide clarity, all objects’ references are declared. More advanced applications typically involve all of the intrinsics.
    5. At some point during execution, we have either successfully changed a user password or we have failed due to some error. Either way, we would like to end the execution of the component and transfer control back to the calling application, in this case, an ASP page. In order to prevent crashing the IIS server as a result of executing our component repeatedly, we need to perform some housekeeping after each execution of our component. What we really need to do is to explicitly destroy the references to all of the MTS/IIS objects we have created in memory on the IIS/MTS server. In order to reclaim the memory, we simply set each object reference variable equal to the VB keyword “Nothing.” All memory used by our variables will be released and becomes available for other processes running on the server. Add another Private Sub named ReleaseObjectReferences to the code module. This code will perform the necessary steps to release the memory allocated to the application’s object references. Add the following code to the new sub.
      
      
      ' release all MTS object references
      Private Sub ReleaseObjectReferences()
      
          Set objCtx = Nothing
          Set objApplication = Nothing
          Set objRequest = Nothing
          Set objResponse = Nothing
          Set objServer = Nothing
          Set objSession = Nothing
      
      End Sub
      
      
      
    6. We now have all the code required to create our DLL. Using VB, compile the DLL. Your DLL should be called aciChangePassword.dll. After compilation has completed, we are ready to install the component in an MTS package, but first we need to resolve one issue. Because VB has registered the component for us already with the path information pointing to the directory where you compiled aciChangePassword.dll, we need to remove this reference from the registry. To do this, type the following at the command line:
      
      
      regsvr32 -u aciChangePassword.dll <path where aciChangePassword.dll was compiled>
      
      
      
      You should receive a dialog indicating that aciChangePassword.dll was successfully unregistered. At this point, we can register the component via MTS.
    7. Decide what IIS/MTS machine you would like your component to be installed on, and copy the DLL into its \winnt\system32 directory.

      Open up the MTS Explorer Microsoft Management Console (MMC) snap-in, and double-click the My Computer folder or the name of the server where you copied the component to. Right-click the Packages Installed folder and select New -> Package. At the next dialog, select the option Create an empty package. Name the package aciChangePassword, and click Next. Select the user identity to run this package, and select Finish. Note, that if you choose a standard NT user account, they will need to be logged on the server when the component is run, or you will receive cryptic errors and the component cannot be instantiated. Instead, you should choose a service account. This will ensure that your component can be instantiated at all times.

      Your new package will be created. We will now install the aciChangePassword.dll component in this package.

      Figure 1

      Double-click on the Packages Installed folder to expand the list of installed packages. Double-click the aciChangePassword package folder to expand it. Select the Components folder and right-click. Select New -> Component. When the next dialog appears, select Install new component(s).

      Figure 1

      Figure 1

      Click Add Files, and browse to the location of your aciChangePassword.dll component (\winnt\system32) and select it. The information for the component should now appear in this dialog. Select the Details checkbox and make sure that the following appears in the Components found list box (Component-Main; Properties-MTX; Interfaces-found), and click Finish. You should see a spherical black icon with a green X representing the aciChangePassword component. The component will now be registered with MTS and will run under control of MTS when instantiated by another application. One more thing we need to do to our component is make MTS aware that our component will support transactions. We do this by right-clicking on the aciChangePassword component in our package, select Properties, and click the Transactions tab. Select Supports transactions. Accept the change by clicking OK.

      Depending on your individual MTS configuration, that should be all that is required to register your component. Execution permissions for components can be assigned on a user-by-user basis through the use of MTS Roles. Role-based security is beyond the scope of this article. Please refer to the MTS online documentation for a discussion of role-based component security.

    Are We There, Yet?

    We have accomplished a lot, thus far. Let’s take a step back to see exactly where we are and where we have to go. At this point, we have created and compiled an ActiveX DLL that will change a user’s password via ADSI using an MTS transaction. We have also created an MTS package for our component and installed it via the MTS Explorer.

    In order for users to browse to your Web site and change their password, we need some way to call our component. We will create a simple ASP page to accomplish this. The page will contain the HTML form used for parameter entry and will also contain the code necessary to call upon our component’s exposed password-change functionality.

    Create the ASP Page

    Open your favorite HTML editor, and add the following code to a new file. Save the file as setpass.asp.

    
    
    <head>
    <%
    
      ' declare variables
      Dim objReference
      Dim strUser
      Dim strOldPassword
      Dim strNewPassword
      Dim strConfirmNewPassword  
    
      ' obtain form values
      strUser = Request.Form("txtUser")
      strOldPassword = Request.Form("txtOldPassword")
      strNewPassword = Request.Form("txtNewPassword")
      strConfirmNewPassword = Request.Form("txtConfirmNewPassword")
      
      ' create object
      Set objReference = Server.CreateObject("aciChangePassword.Main")
    
      ' change the password
      Call objReference.SetPassword(strUser,strOldPassword,strNewPassword,strConfirmNewPassword)
    
      ' release object reference    
      Set objReference = Nothing
    
    %>
    <title>NT Domain Password Change</title>
    </head>
    
    <body bgcolor="#ffffff">
    
    <p><h2><font color=black face=Arial>NT Domain Password Change</font></h2></p>
    
    <form method="post" name="frmChangePassword" action="setpass.asp">
        <table width=325 border="0">
        	<tr>
    		<td colSpan=2><b>
    <font size=+1 face=Arial color=black>
    User:
    </font>
    </b>
    </td>
    		<td>
    <input type=text size=20 name="txtUser"></td>
        	</tr>
        	<tr>
    		<td colSpan=2><b>
    <font size=+1 color=black face=Arial>
    Password:
    </font>
    </b>
    </td>
    		<td><font>
    <input type="password" name="txtOldPassword">
    </font></td>
        	</tr>
        	<tr>
            	<td colSpan=2>
    <b>
    <font size=+1 color=black face=Arial>
    New Password:
    </font>
    </b>
    </td>
            	<td>
    <font>
    <input type="password" name="txtNewPassword">
    </font>
    </td>
        	</tr>
        	<tr>
            	<td colSpan=2><b>
    <font size=+1 color=black face=Arial>
    Confirm Password:
    </font></b></td>
            	<td>
    <input type="password" name="txtConfirmNewPassword">
    </font></td>
    	</tr>
        	<tr>
            	<td colSpan=3></td>
        	</tr>
        	<tr>
            	<td colSpan=3>
    <div align=center>
    <font color=black face=Arial>
    <INPUT  id=txtChangePassword name=txtChangePassword
    style="font-FAMILY: ; HEIGHT: 24px; WIDTH: 149px" type=submit value="Change Password">
    </div>
    </font>
    </td>
        	</tr>
        </table>
    </form>
    </body>
    </html>
    
    
    
    When the Change Password button is clicked, the form action specifies that the setpass.asp page is targeted.
    
    
    <form method="post" name="frmChangePassword" action="setpass.asp">
    
    
    
    Targeting the setpass.asp page will cause the ASP script between the tags to be executed.

    The page is a basic form with four textbox elements: user name, current password, new password, and confirmed new password. Each form element has a unique name, and the ASP Request.Form method can be used to retrieve the values entered in each textbox.

    
    
    strUser = Request.Form("txtUser")
    strOldPassword = Request.Form("txtOldPassword")
    strNewPassword = Request.Form("txtNewPassword")
    strConfirmNewPassword = Request.Form("txtConfirmNewPassword")
    
    
    
    Each form parameter is stored in a variable that will be used in the argument list when the SetPassword method of our component is called. Before we can call our component, we must create an instance of the class we want to use. The following line performs this operation:
    
    
    Set objReference = Server.CreateObject("aciChangePassword.Main")
    
    
    
    Remember, the project name was aciChangePassword and the class name was Main. This will now enable us to call the SetPassword method when we are ready.

    At this point, we have everything we need and all four arguments required by the SetPassword method should contain the appropriate form data entered by the user.

    
    
    objReference.SetPassword(strUser,strOldPassword,strNewPassword,strConfirmNewPassword)
    
    
    
    After we have made the call to change the password, we need to release the reference to the component.
    
    
    Set objReference = Nothing
    
    
    
    Okay, now we know how the ASP form works. Let’s set up the Web server and test our component.

    Oh, the Webs We Weave

    No special Web-server configuration is necessary to run the application. Since there is only a single HTML form with no other dependencies, you can host it in any virtual directory on your Web server. Copy setpass.asp into the desired directory, and you should be ready to go. You should make sure that script permission is specified for the directory where you host the ASP page, otherwise the ASP code cannot be executed.

    The Passwords They Are a Changin’

    We’re ready to test. Open up the MTS Explorer so we can see our component’s activation/deactivation. Navigate to the aciChangePassword package, and open the folder. Next, open the components folder for this package so that you can see the black ball with the green X representing the aciChangePassword.Main class of the component. When the component’s Main class is instantiated via the Web page, you should see the ball rotate. The icon will stop rotating when the component has completed execution, which will be when we tell MTS we’re finished via the .SetComplete or .SetAbort methods of the ObjectContext (objCtx). Due to fast execution speeds, you may not always see the icon rotate.

    Open your browser and navigate to the location of the setpass.asp page. The simple form should be displayed and you can enter the appropriate information for a change-password request. Enter an existing domain account name, its current password, the new password, and the confirmed new password, and click the Change Password button.

    Watch the icon in MTS for activity. It should spin briefly. In your browser, you will receive a dialog box indicating the success or failure of the operation. The icon should be stopped at this point.

    Verify in the NT Application Event log of the PDC that the component logged the attempt.

    Figure 1

    If you see that the password change was successful (blue, information icon), log into the domain using the new password. This will be absolute proof to you that the password was changed (was there ever any doubt?).

    Conclusion

    The Microsoft Windows DNA framework can be used to build highly scalable, distributed, cooperating component-based Internet applications. We can consider our password-change application a small-scale DNA implementation. By using MTS and IIS for application services and the browser for presentation services, the password-change component provides distributed functionality for Internet users. Dynamic generation of HTML was demonstrated through the use of the MTS/IIS intrinsic objects. ASP functionality can be wrapped and extended using the ASP object model and ASP ScriptingContext, or by using the IIS intrinsic objects and MTS ObjectContext. Either way, developers have a powerful set of tools and technologies to begin developing next-generation Internet application solutions.

    About the Author

    Bill Craun is a senior consultant with Ambassador Consulting, Inc. in Indianapolis. Bill, both an MCSE and MCSD, enjoys building cutting-edge Windows DNA solutions. He e is currently immersed in computer telephony integration (CTI) application development and deployment. His e-mail address is bcraun@ibm.net.

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Supporting Products/Tools
    AspEncrypt
    Built around the Microsoft CryptoAPI, AspEncrypt helps you harness all major encryption and hashing algorithms such as DES, Triple-DES, RC2, RC4, RSA, MD5 and SHA1 in just a few lines of code. The component can be used in tandem with AspEmail to send encrypted and signed mail in the industry-standard S/MIME format, or with AspUpload to encrypt files as they are being uploaded. AspEncrypt can also be used to issue and manage X.509 digital certificates.
    [Top]
    AspPDF
    AspPDF is an ASP/ASP.NET component which enables generation and management of documents in PDF format. Features include advanced text formatting, font embedding, form fill-in, images, tables, content and page extraction, document stitching, encryption, digital signatures, and more.
    [Top]
    Other Articles
    Apr 27, 2004 - Develop and Customize Web Parts with Custom Tool Parts
    Tool Parts provide an interface for Web Part properties well beyond the capabilities of the default property pane. In this article Gayan Peiris shows how to customize Web Parts with custom Tool Parts.
    [Read This Article]  [Top]
    Apr 7, 2004 - Reusable Components in ASP.NET 2.0, Object Binding and Precompilation
    This article demonstrates how to create a reusable component in ASP.NET 2.0 and then consume it from an ASP.NET page. Also learn how the ObjectDataSource control can be used to directly bind the output of an object to the controls in an ASP.NET page and how precompilation can be used to increase the performance of the Web application and catch compilation errors.
    [Read This Article]  [Top]
    Mar 31, 2004 - Build a Managed BHO and Plug into the Browser
    Browser Helper Objects (BHOs) are COM components that communicate with Internet Explorer to enrich the browsing experience. Michele Leroux Bustamante returns to the world of COM to show you how to build a managed BHO with the help of the .NET Framework's COM interoperability features.
    [Read This Article]  [Top]
    Feb 18, 2004 - Customizing SharePoint Web Parts with Custom Properties
    In addition to creating custom Web Parts for SharePoint Portal Server, developers can actually create their own custom properties to further enhance Web Part appearance and behavior. Gayan Peiris explains the process and provides all the necessary code.
    [Read This Article]  [Top]
    Sep 26, 2003 - Accessing Shared Resources Using ASP.NET
    Accessing shared resources is a challenge for many ASP.NET developers. Tony Arslan explains how a simple serviced component can solve this infamous problem.
    [Read This Article]  [Top]
    Oct 2, 2002 - Function Pointers and COM
    Using callbacks and function pointers in VB can be risky and complicated. Ben Garcia explains his work-around for the function pointer issue he encountered while creating the VB version of his SNMP component.
    [Read This Article]  [Top]
    Sep 4, 2002 - Creating an SNMP Component - Part 2
    In part two of this intriguing article series, Ben Garcia shows how to build an updated and improved SNMP component in VC++ AND VB, and he briefly explains why limitations in VB make VC++ a better language for developing this type of application.
    [Read This Article]  [Top]
    Jul 23, 2002 - Creating an SNMP Component
    Ben Garcia sheds some light on the Simple Network Management Protocol (SNMP). First he provides a history of SNMP, then he dives right into its architecture. Finally, he shows how to build a COM component that communicates with SNMP-enabled devices.
    [Read This Article]  [Top]
    Jun 26, 2002 - Accessing Caller ID from the Web - Part 1
    Paul Apostolos begins his series on using Web services and the MSComm32.OCX component to access caller id information from a Web page. In part 1, learn how to write the Visual Basic program that runs on the server and updates a database with incoming callers.
    [Read This Article]  [Top]
    Nov 20, 2001 - Creating a Server Component with VB - Redesigned - Part 2
    Doug Dean explains different methods of retrieving and manipulating data from a database in a VB DLL so that it is ready to be rendered in a browser.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry



    JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers