Use a script to perform a security audit
Many network administrators devise a highly organized permission structure based on user groups for their NTFS file systems. Over time, permissions on shared files and folders can become unmanageable, especially if users frequently request temporary access to different folders within the shared folder structure. Administrators often end up assigning individual permissions for such users directly on the folders because none of the existing groups match the users' restrictions.
At the time, such assignments aren't a problem as long as the administrators carefully apply the permissions and keep the security and integrity of the folders intact. However, problems can arise months or years later when a major restructuring of the organization requires the administrator to audit and clean up the groups and security rights for these shared folders.
Where do you begin if, as part of a security audit, you're requested to report the files and folders to which each user and group has access? Wouldn't it be great if you could snap your fingers and get that information in an instant? Unfortunately, it's not that simple, but you can write a script to perform a security audit. To write such a script, you need to use showacls.exe and net.exe.
Showacls.exe is a useful but often overlooked command-line utility in the Microsoft Windows 2000 Server Resource Kit and Microsoft Windows NT Server 4.0 Resource Kit. This utility lets you display the access rights for files and folders on NTFS partitions, including access permissions for users. You simply follow the command syntax
showacls.exe path \[/s\]
where path is the full path to the file or folder for which you want to display the access rights (e.g., F:\myshare\data). If you use the optional /s switch, the utility displays the access permissions for the specified directory and all its subdirectories.
At first glance, you might think that you can use this command alone for the audit. However, you still need to know all the groups to which each user belongs because showacls.exe isn't aware of an account's group membership and might not report the files and folders to which those groups have access. You would then need to manually search each file or folder to determine whether that user and the groups to which the user belongs have access to it. Although Showacls is helpful, the audit remains primarily a manual task. However, you can creatively use this utility to obtain useful information programmatically, as I show you later.
Net.exe comes with Win2K, NT, and other Windows OSs. This utility offers many commands that let you manage various network components, such as shares, sessions, services, and user accounts. Most network administrators use this utility to map and unmap drive letters to network shares. However, you can also use the utility's Net User command to obtain the groups to which a user belongs. You follow the syntax
Net User user \[/domain\]
where user is the user account and /domain is a switch that designates the specified account as a domain account rather than a local account. This Net User command outputs most of the account information, including all the groups to which the user belongs, for the specified user account. However, before you can use the group information, you need to parse the output and extract the group names. The code in Listing 1 does just that. Because an asterisk (*) separates the groups in the Net User command's output, the code uses an asterisk as a delimiter. The code then strips away trailing spaces and writes the groups, one on each line, to a temporary file (i.e., %Temp%\getaccess.$$$).
Showacls.exe and net.exe provide a foundation for the script GetAccess.cmd. This script produces a text file that lists all the files and folders to which the specified user or group has access in the specified directory and all its subdirectories. When you launch the script, you must provide three parameters: the username or group name for which you're performing the audit (username_or_groupname), the path to the directory you want to scan (path_to_scan), and the name of the output file (outputfile). You can include the optional /d switch if you want to audit only folders and not files. You can also include the optional /verbose switch if you want the console to display what the script is doing when it runs. Thus, the command that launches the script has the syntax
GetAccess.cmd username_or_groupname path_to_scan outputfile \[/d\] \[/verbose\]
The script's logic is simple. It operates as follows:
- The script deletes the output file if it already exists. To accomplish this task, the script uses the command
- The script prepares the switches for the Dir command. As Listing 2 shows, the dirflag variable defines the switches according to the parameters you provide when you launch the script. The /s switch tells the Dir command to show all contents, including subdirectories, and the /b switch tells the Dir command to provide the output in bare format (i.e., without header or summary information). If you specified the /d parameter when you launched the script, the script adds the /ad switch to signify that you want to display directories only.
- The script stores the specified username or group name and two built-in group names (i.e., Everyone and Authenticated User) in a temporary file (%temp%\
getaccess.$$$). The script later uses the names in this file in conjunction with showacls.exe to determine whether the user or group specified has access to a file or folder.
- When the specified account is a user account, the script appends to the temporary file the groups to which the user belongs. The code in Listing 1, which I've already discussed, accomplishes this task.
- The script obtains the names of files and folders (or folders only if you included the /d switch) in the specified directory. The script uses the dirflag variable it set earlier in conjunction with the For and Dir commands to obtain these names:
- The :checkaccess and :hasaccess modules constitute the most important part of the script because they identify the files and folders to which the user or group has access. Although the code is important, it's straightforward, as Listing 4 shows.
- The script doesn't determine whether the specified account exists in your domain. The script only determines whether the specified account is a user account. If the specified account isn't a user account, the script assumes it's a group account. Thus, if you misspell a user account, the script assumes that the account is a group account. So, make sure that you enter all account names correctly on the command line.
- The script works for accounts only in your domain. (Net.exe imposes this limitation.)
- Depending on the naming convention in your organization, the script might mistakenly output a match if one account name is a truncated version of another account name. For example, if MyGroup21 has access to a file and you're looking for MyGroup2, the script will show MyGroup21 as a match. To get around this problem, you can use the Findstr command with the /x switch instead of the Find command. However, if you choose to replace the Find command with the FindStr command in the script, when you specify a group account name as a parameter, you must make sure that the name exactly matches (including case) the group name in the Microsoft Management Console (MMC) Active Directory Users and Computers snap-in (Win2K) or in User Manager for Domains (NT).
- The script can be extremely slow, especially when you audit a large folder structure against an account that belongs to many groups. The process is slow because for each account in the temporary file, the script must run showacls.exe against each folder that the Dir command returns. For example, suppose that 1000 subfolders are in the folder you're auditing and the temporary file contains five accounts (i.e., Everyone, Authenticated User, the specified user, and two additional groups to which the user belongs). The script must execute the :hasaccess module 5000 times (1000 subfolders * 5 accounts).
If Exist %outputfile% Del %outputfile% /q
The script uses the filefolder variable to properly output the status information on screen. This information tells you whether the script is processing files and folders or just folders.
As Listing 3 shows, the script uses the Net User command to determine whether the specified account is a user account or group account. If the Net User command doesn't return an error, the specified account is a user account; otherwise, the specified account is considered a group account. If the specified account is a user account, the script proceeds to Step 4. If the specified account is a group account, the script jumps to Step 5.
For /f "tokens=*" %%i in ('Dir %dirflag% %path_to_scan%') Do Call :checkaccess "%%i"
The For command tells the script to take each line in the Dir command's output, store that line in the %i variable, and run the code in the :checkaccess module against that line.
After the script passes the name of the file or folder to the :checkaccess module, the module stores the name in a variable named target. The :checkaccess module then loops through each account in the temporary file and runs the :hasaccess module against it. The :hasaccess module compares the Showacls command's output for the current file or folder against the current account in the temporary file by filtering the output through two Find commands.
If either Find command returns an exit code of 0, a match is present. When a match occurs, the script sends that file or folder name to the output file and the console screen.
I've executed GetAccess.cmd in both Win2K and NT environments. You can download the script from Windows & .NET Magazine's Web site (http://www.winnetmag.com, InstantDoc ID 38942). To use this script, you must have show-acls.exe installed in the same folder from which you launch the script or in a folder that's part of your path environment. GetAccess.cmd has certain limitations:
An Effortless Audit
GetAccess.cmd provides an inexpensive solution to an auditing problem that many network administrators face. Although the script has a few limitations, the alternative—manually checking the permissions of each file and folder—is a lot less desirable.