t_tip1.gif (7229 bytes)

 
 


**!!****!!****!!****!!****!!****!!****!!****!!****!!**
 

NOTE: There are hidden characters in this html file for spacing and other purposes. Be wary about importing the code text here directly into your VBA module.

First the bad news and some very good advice:

Be prepared for locking yourself out of a database at least once and having to start over. 

Use a non-critical database as a test subject until your technique is flawless. Don't be satisfied with just one success on one test database.

Back up a copy of the default workgroup file SYSTEM.MDW.

Never use it to set up security.

When you get around to using and important database:

Back up an unsecured copy of the database in a safe place.

Do not trust my code implicitly. There may be a typo or somehow it could have been edited without my knowledge.

**!!****!!****!!****!!****!!****!!****!!****!!****!!**

This document contains the following:

Securing Access 2.0, 95, 97
Securing a back-end
Code to lock and unlock a secure database.

1. Securing Access 2.0, 95. 97:      Return to Top

You have read up on access security in "Access [2000], [97], [95], [20] Developers Handbook published by SYBEX. A great reference. Be sure to read up on security first as what follows is only an outline.

BACK UP YOUR DATABASE FIRST IN A SAFE PLACE.

BACK UP A COPY OF THE DEFAULT WORKGROUP FILE SYSTEM.MDW

Be prepared for locking yourself out of a database at least once and having to start over. I have done so. Use a non-critical database as a test subject.

Study the outline below.

Make a copy of a "virgin" SYSTEM.MDW file (workgroup file) and conveniently rename it. Log onto this renamed file using WRKGADM.EXE.  Open your test Access database as a member of this new workgroup. Your user name is now "Admin." and you belong to the Admins group. Anyone in the Admins group is "god" and has full permissions. unless you remove permissions from the Admins group. (An unwise thing to do unless you are very, very sure of what you are doing.)

Now use the menu to open the permissions dialog box. Note that there are two security dialog options on the Tools\Security menu. One dialog box is for setting permissions and ownership. The other is for managing users, groups, and passwords.

Now for the trick. You create a new user and assign the new user to the Admins group You will soon be that new user. You remove the default, automatic user "Admin" from the Admins group. What! Yes, anyone who logs on to an Access database without a password is assigned the user name "Admin." Surprise -- out of the box, Access is secured but the security is not active or transparent. When you log on to or create an Access database, you do so as the user "Admin" with a blank or no password whether you like it or not. So the first part of the trick is to remove the Admin from the Admins group. But Access insists there be one member in the Admins group. Hence, the new user you create and put there.

Now, since you are still the Admin, give the Admin a password. The current user can give himself a password. Now two users have full permissions to open the database. The Admin can still do so because "it" belongs to the "Users" group which we have not mentioned until now to keep matters simple, and the new user you have created who belongs the the Admins group and the Users group.

Close the test database and close access.

Reopen Access and your test database and presto, the security dialog box appears asking for your logon name and password. Enter the logon name of your new user. Your database should open. Return to the security dialog box for assigning passwords and give yourself a password.

Close the dialog box, your database , and Access

 Reopen Access and your test database. Enter your logon user name and password. your database should open.

Try opening the database with the user name "Admin" and the Admin's password.

 If you can't get back in, read more and try again. Remember, you only locked yourself out of a test, dummy database. Right?

Now for the second part of the trick. The nasty Users group. You can't delete this group and every user automatically belongs to it. Worse, this group has full permissions to everything in your database by default. Let's see -- the group will always exist and all users will always belong to it. BUT! you can remove all the permissions is possesses. If  it doesn't have any permissions, users who belong to it can't do a darn thing. We can render it a toothless tiger in two ways.

The easiest is to use the security wizard and secure the database. This wizard, in all Access versions up to 2002, will do several useful things. In Access 2000 - 2002, it does more useful things. The wizard will remover the Admin from the Admins group, but we have already done that. It will remove all permissions from the Users group. Yay!  It will make the current user (you disguised as the new user you have created) the owner of the database and all the objects in it. An important thing as you know from reading the Access Developer's Handbook. Right?

The harder way is to use the information you have learned from reading up on Access security and do all the things the wizard does yourself.

Close the database. The Admin can now open the database with its password but can't do anything as he belongs to the toothless tiger, the Users group. And, of course, only you will know the Admin's password. You can open the database with your password and do anything because you belong to the Admins group which has full permissions.

While logged onto the database as your new user, you can create new groups and new users, assigning the users to groups as desired. I frequently use the groups: Supers, Supports, and Readers. I assign Supers permission to read, insert, delete, and update tables and queries. I assign Supports a mix of these permissions, and I assign readers read only permissions. I do not assign any users any permissions at all. Users get their permissions by belonging to one of the groups. This strategy is easy to manage. Read up on Users and Groups. 

Note: If your database has make-table queries or code that changes the design of forms or reports at runtime, or code that creates new forms or reports at runtime, be sure to give the appropriate groups permissions to modify the form or report design and\or permissions for using new tables and queries. Read up on this topic also.

Note: If you do not give the groups you create administer permission, members in the group cannot import database objects from this database into a new one..

2. Securing a Back-End      Return to Top

Secure the front-end first using one of the above procedures.

Then, while logged on to your workgroup as the new user you have created, create an empty database. Import into it the database objects in your back-end. You become the owner of these objects and Admin loses ownership of these objects. Use the security dialog box for permissions to add and remove permissions for the objects in your back end. When done, only you will have administer permissions for these objects. Other users you previously created while securing the front-end will have a mix of desired permissions. But probably none will have the administer permission.

Now the front-end and the back-end belong to the same workgroup. You can open the front-end and link to the tables in your secure back-end. The table links in the front-end inherit the permissions  assigned to the matching tables in the back-end. To be dead certain, you can establish the permissions for the links too that match the permissions in the back end. However, if the link is broken and recreated,. the new link will  have full permissions. Some developers erroneously think that by securing the front-end only and setting permissions on the links, they are securing the back-end too, but that is not the case.

Finally, the code      Return to Top

The code is needed because you may want to cancel the shift key as a way to open the database by circumnavigating the autoexec macro. You may want to solidly hide the database window. You may want to include your own menus so users cannot print anything or get to some of the other functions on the standard toolbars. The code is dangerous because a mistake could permanently lock-up the database. So be sure to use the code on a test database with repeated successes before plunging in and using it on a mission critical database.

You should put the macro and the code in both the front-end and the back-end, if you have a back-end.

The code needs an autoexec macro to work. When you open an Access database, the first thing that fires is the autoexec macro. However, note that the autoexec macro in a back-end does not fire if you access the back end using links from a front-end. You actually have to open the database for the autoexec macro to fire.

The macro's name in the database window MUST BE "autoexec"

The action for the macro is "run code"

The function name is "OpenDb()"

You then create a new module and give it a suggestive name like "basOpenRun" and copy the following code into it:

This code locks and unlocks the database. Most of it is based on code found in the Microsoft VBA Help file and code found in the excellent Access Developers Handbook published by SYBEX. Buy it!

'===========================================================

Dim mblnSpecialKeysAllowed As Boolean 'Scope of constant is module-wide

'===========================================================

Function OpenDbADO()

On Error GoTo OpenDbADO_Err

' Note: Access 2000 on uses ADOX. This code will fail in earlier versions of Access.
' Note See directly below for the same function that works in Access 2.0, 95, and 97.

If IsUserMemberADOX("Admins") Then

' The function TestDBProperty() is listed later on.
' It checks to see if  the property is set to true or to false.
' Also note that the lines below only execute
' if the CurrentUser() is a member of the Admins group.

    If Not TestDBProperty("AllowSpecialKeys") Then
        If vbYes = MsgBox("Do you want to UnLock the database?", vbYesNo + vbQuestion + vbDefaultButton2) Then
            If UnLockDb() Then
                MsgBox "I will close the database" & vbLf & "so you can open it unlocked."
                Application.CloseCurrentDatabase
            End If
        End If
    Else
        If vbYes = MsgBox("Do you want to Lock the database?", vbYesNo + vbQuestion + vbDefaultButton2) Then
            If LockDB() Then
                MsgBox "I will close the database" & vbLf & "so you can open it locked."
                Application.CloseCurrentDatabase
            End If
        End If
    End If
End If

OpenDbADO_Exit:

Exit Function

OpenDbADO_Err:

' Insert your error trapping here.

Resume OpenDbADO_Exit

End Function

'===========================================================

Function OpenDbDAO()

On Error GoTo OpenDbADO_Err

' Note This function works in Access 2.0, 95, and 97.

If IsUserMemberDAO("Admins") Then

' The function TestDBProperty() is listed later on.
' It checks to see if  the property is set to true or to false.
' Also note that the lines below only execute
' if the CurrentUser() is a member of the Admins group.

    If Not TestDBProperty("AllowSpecialKeys") Then
        If vbYes = MsgBox("Do you want to UnLock the database?", vbYesNo + vbQuestion + vbDefaultButton2) Then
            If UnLockDb() Then
                MsgBox "I will close the database" & vbLf & "so you can open it unlocked."
                Application.CloseCurrentDatabase
            End If
        End If
    Else
        If vbYes = MsgBox("Do you want to Lock the database?", vbYesNo + vbQuestion + vbDefaultButton2) Then
            If LockDB() Then
                MsgBox "I will close the database" & vbLf & "so you can open it locked."
                Application.CloseCurrentDatabase
            End If
        End If
    End If
End If

OpenDbADO_Exit:

Exit Function

OpenDbADO_Err:

' Insert your error trapping here.

Resume OpenDbADO_Exit

End Function

' ================================================================

' This function works in all versions of Access

Function LockDB() As Boolean

On Error GoTo LockDB_Err

' Note: These constants simply make the code below more readable.

Const DB_Text As Long = 10
Const DB_Boolean As Long = 1

' Note: You can optionally create your own menus and toolbars to replace the default ones
' The menu statements need to be remarked out until you create your own menus.

' Call ChangeProperty("StartupMenuBar", DB_Text, "Your users Menu ")
' Call ChangeProperty("StartupShortcutMenuBar", DB_Text, "Your users Shortcut Menu Bar")

Call ChangeProperty("StartupShowDBWindow", DB_Boolean, False)
Call ChangeProperty("StartupShowStatusBar", DB_Boolean, True)
Call ChangeProperty("AllowBuiltinToolbars", DB_Boolean, False)
Call ChangeProperty("AllowFullMenus", DB_Boolean, False)
Call ChangeProperty("AllowBreakIntoCode", DB_Boolean, False)
Call ChangeProperty("AllowSpecialKeys", DB_Boolean, False)
Call ChangeProperty("AllowBypassKey", DB_Boolean, False)
Call ChangeProperty("AllowShortcutMenus", DB_Boolean, False)
Call ChangeProperty("AllowToolbarChanges", DB_Boolean, False)

LockDB = True

LockDB_Exit:

Exit Function

LockDB_Err:

' Insert your error trapping here.

Resume LockDB_Exit

End Function

' ========================================================

' This function works in all versions of Access

Function UnLockDb() As Boolean

' Note: You can optionally create your own menus and toolbars to replace the default ones
' The menu statements need to be remarked out until you create your own menus.

' Call ChangeProperty("StartupMenuBar", DB_Text, "Admins Menu")
' Call ChangeProperty("StartupShortcutMenuBar", DB_Text, "Admins Menu Bar")

Call ChangeProperty("StartUpShowDBWindow", DB_Boolean, True)
Call ChangeProperty("StartupShowStatusBar", DB_Boolean, True)
Call ChangeProperty("AllowBuiltInToolbars", DB_Boolean, True)
Call ChangeProperty("AllowFullMenus", DB_Boolean, True)
Call ChangeProperty("AllowBreakIntoCode", DB_Boolean, True)
Call ChangeProperty("AllowSpecialKeys", DB_Boolean, True)
Call ChangeProperty("AllowBypassKey", DB_Boolean, True)
Call ChangeProperty("AllowToolbarChanges", DB_Boolean, True)
Call ChangeProperty("AllowShortcutMenus", DB_Boolean, True)

UnLockDb = True

UnLockDb_Exit:

Exit Function

UnLockDb_Err:

' Insert your error trapping here.

Resume UnLockDb_Exit

End Function

' ===========================================================

' This function works in all versions of Access

Function ChangeProperty(strProperty As String, varType As Variant, varValue As Variant) As Integer

On Error GoTo ChangeProperty_Err

Dim db As Object
Dim prp As Variant
Const PropertyNotfound = 3270

Set db = CurrentDb
On Error GoTo ChangeProperty_Err
db.Properties(strProperty) = varValue
ChangeProperty = True

ChangeProperty_Exit:

On Error Resume Next
Set db = Nothing
Err = 0
On Error GoTo 0
Exit Function

ChangeProperty_Err:

' Note: If your code generates an error because the property does not yet exist.
' the lines below create the property. A neat solution for which I am in debt to the
' authors of the Access 2000 Developers Handbook, Getz, Litwin, and Gilbert.

If Err = PropertyNotfound Then ' Property not found.
    Set prp = db.CreateProperty(strProperty, varType, varValue)
    db.Properties.Append prp
    Resume Next
Else

' insert normal error trapping here

End IF

End Function

' ===================================================

' This function works in all versions of Access
' if you use the correct Dim statement for creating the database object variable

Function TestDBProperty(strProperty As String)

On Error GoTo TestDBProperty_Err

' Note: the next Dim statement works in Access 2000
' without any reference to the DAO 3.6 library.

Dim db As Object

' Note: In pre-2000 versions of Access, you can use the statement
' Dim db as Database

Dim prpNew As Property
Dim strMsg As String
Const PropertyNotFoundError = 3270

Set db = CurrentDb()

' If the property exists and is set to True, TestDBProperty = True.
' If the property does not exist or is set to False, TestDBProperty remains False.

TestDBProperty = db.Properties(strProperty)

TestDBProperty_Exit:

On Error Resume Next
Set db = Nothing
Err = 0
On Error GoTo 0
Exit Function

TestDBProperty_Err:

If Err = PropertyNotFoundError Then       ' Err equals 3270, property not found.
    strMsg = "Property tested does not yet exist." & vbLf & vbLf
    strMsg = strMsg & "You will be asked if you want to unlock the database." & vbLf & vbLf
    strMsg = strMsg & "Click YES." & vbLf & vbLf
    strMsg = strMsg & "The property will then be created." & vbLf
    strMsg = strMsg & "The database will announce it is closing." & vbLf & vbLf
    strMsg = strMsg & "When you reopen the database," & vbLf
     strMsg = strMsg & "it will be set up for locking and unlocking."
    MsgBox strMsg, vbOKOnly + vbInformation
Else

' Insert you normal error trapping here.

End If
Resume TestDBProperty_Exit

End Function

' ===================================================

Function IsUserMemberADOX(pGroup As String, Optional pUser As Variant) As Boolean

' Note: This code only works in Access 2000 on as it uses ADO and ADOX.
'          
See down below for the code for prior versions of Access that use DAO
'          You may need to set a reference to MSADOX.dill
'          While having a VBA module open, click on Tools\References.
'           Look in the list for "Microsoft ADO Ext 2.5 for DDL and Security"
'           Make sure it is checked. The usual path is
'           C:\Program Files\Common Files\System\ADO\msadox.dll
' Note: You should review the Optional argument for user-defined functions

On Error GoTo IsUserMemberADOX_Err

Dim cat As ADOX.Catalog
Dim cnn as ADODB.Connection
Dim strGroup As String
Dim varUser As Variant

strGroup = pGroup
varUser = pUser

cat.ActiveConnection = cnn
Set cat = New ADOX.Catalog
If IsMissing(varUser) Then
    varUser = CurrentUser()
End If

IsUserMemberADOX = (cat.Groups(strGroup).Users(varUser).Name = varUser)

IsUserMemberADOX_Exit:

On Error Resume Next
Set cat = Nothing
Set cnn = Nothing
Err = 0
On Error GoTo 0
Exit Function

IsUserMemberADOX_Err:

' Insert your error trapping here.

Resume IsUserMemberADOX_Exit

End Function

' ===================================================

Function IsUserMemberDAO(strGroup As String, Optional varUser As Variant) As Boolean

' This function works in pre-2000 versions of Access

On Error GoTo IsUserMemberDAO_Err

Dim wrk As Workspace
Dim usr As User
Dim grp As Group
Dim varGroup As Variant

Set wrk = DBEngine.Workspaces(0)

wrk.Users.Refresh
wrk.Groups.Refresh

If IsMissing(varUser) Then
    varUser = CurrentUser()
End if
Set usr = wrk.Users(varUser)
Set grp = wrk.Groups(strGroup)
varGroup = usr.Groups(strGroup).Name

If Not IsEmpty(varGroup) Then
    IsUserMemberDAO = True
End If

IsUserMemberDAO_Exit:

On Error Resume Next
Set wrk = Nothing
Set usr = Nothing
Set grp= Nothing
Err = 0
On Error GoTo 0
Exit Function

IsUserMemberDAO_Err:

' Insert your error trapping here

Resume IsUserMemberDAO_Exit

End Function

.    
Tales  Tips Menu
Tales Company
Home Home
Contact Us Contact Us