Cover V02, I03
Figure 1
Figure 2
Figure 3
Figure 4
Listing 1
Listing 2


Two Handy AIX Tools: The Failed Login Report and lptran

Jeff Courington

AIX is a very distinctive implementation of UNIX, with its own strengths and weaknesses. In the course of administering an AIX system, I've developed a couple of tools that you might also find useful. The first is a failed login report generator, which allows you to track failed logins on the system. The second is lptran, a utility that allows you to move print jobs from one queue to another (a functionality mysteriously missing from AIX).

A Failed Login Report for AIX

Among other duties, system administrators must teach the basic skills needed to use the system. The first of these skills is logging into the system: first you enter your login name, then you enter your password. I thought this was a simple procedure until I looked at the failure records contained in AIX's /etc/security/failedlogin file.

Taking myself as an average user, I was suprised to find that over the last year and a half I had failed the login process 205 times. Remember that the failedlogin file can only track logins with correct login names and incorrect passwords. All other entries are assigned to the login UNKNOWN. I found that on my system the high number was 698. It then occurred to me that a report on failed logins could be a useful system administration tool. Such a tool would draw its data from the failedlogin file.

The failedlogin File

For successful logins, entries are made in the two system files /etc/utmp and /usr/adm/wtmp. The who command uses the /etc/utmp file to show the current users on the system, while the /usr/adm/wtmp file contains system accounting records for connections. If the login process fails, the file that gets updated is /etc/security/failedlogin.

The failedlogin file records the failed login attempts in sequential order. The AIX manual, Elements Of AIX Security: R3.1 (Doc # GG42-3622-1), warns that this file should not be edited. To recover disk space, however, it can be deleted to allow the system to recreate it. The utmp.h header file defines the structure for the utmp record as shown in Figure 1.

Figure 2 shows the special values the ut_line variable can have if it is accounting for something other than a login, while Figure 3 lists the possible values for ut_type.

The utmp structure contains three other structures: ut_exit, ut_time, and ut_termio. The ut_exit structure contains the process termination status and the exit status. These fields tell something about why and how the process was completed. The ut_time structure records the login time of the process. The ut_termio structure records the initial terminal settings as shown by the stty -a command.

Although some of these entries are not very relevant for a failedlogin file, they are included so that the record will match the entries in the /etc/utmp file, which keeps the current user information. AIX users are probably familiar with the bug in the who program that shows ghost users on the system (a pseudo-terminal looks like it is logged in even though it really is not). By searching through the /etc/utmp file and only showing logins with the ut_type equal to USER_PROCESS, you can get a real list of who is on the system.

Program Implementation

The program in Listing 1 creates a report from the failedlogin file. Lines 27-30 check to see if the user wants the help for the flogin program to be printed. If not, the program checks to see whether the report should cover all users or a specific user. The meat of the program is in the print_users procedure, which first opens the failedlogin file at line 65. It checks user_name against the string NOBODY on line 69 to see if the report should print the user name as a header. It uses this same test on line 74 to decide whether to print all of the entries or to check the entry against user_name string. Line 71 uses fread to get records from the failedlogin file. Since the records are stored using the structure utmp each read is for a record the size of this structure. The while loop consists of various tests that must be performed to generate the final report. Lines 76 and 81 convert the ut_time variable by using the localtime and asctime functions. The ut_time variable is stored in seconds since the epoch. The localtime function call converts this into a tm structure, which asctime then converts to the format that we expect from the date command. Lines 84 and 85 finish the loop and print the number of failed logins. Line 86 prints a form feed, Octal 14, so that the printer will stay in alignment and return the number of users counted.

When I run the report, I usually use a small shell script to format the printout by user:

lsuser -a ALL|cut -f1 -d" "|xargs \
-i% flogin -u %

Figure 4 shows sample output from the program.

Security Benefits

The failed login report can be useful for system security. If you have a modem on the system, you can use the report to find out if someone has been trying to log into the system via the modem. Since the /usr/adm/wtmp file only contains successful logins, the accounting reports will not show failed attempts at breaking into the system. And it is usually only a matter of time before these failed attempts become successful.

I think you will be surprised at the uses for this report. At the very least, it offers another view of what is available to a system administrator on AIX.

lptran: A Transfer Command for the LP Spooler on AIX

A major shortcoming of IBM's version of the LP spooler on AIX is the lack of a command that lets you easily transfer a job from one queue to another. Many third-party spooler packages offer this feature, but that usually means using their spooler rather than the LP spooler. Other versions of UNIX do provide transfer commands: on SCO UNIX, for example, lpmove moves a print job from one queue to another. This command can move either a single print job to another queue or all print jobs from one queue to another.

I developed the lptran command (Listing 2) to provide the transfer functionality that the normal AIX LP spooler lacks. The command can copy a printout from one queue to another queue, but cannot transfer all of the print jobs from one queue to another, as lpmove does. This feature would be simple to add but is not part of this program. The lptran command also does not delete the old print job; again, this would be a simple modification.

Explanation of the AIX LP Spooler

In AIX 3.2 the LP spooler header files are in the directory /var/spool/lpd/qdir, while in AIX 3.1 they are in the directory /usr/lpd/qdir. The layout of the spooler header file is very cryptic. Rather than try to explain the entire layout, I focus here only on the parts the application needs.

The first line in the file holds the number of the print job. The middle of the file contains information about the state of the user's environment when the print job was queued. Also included in this section are the queue name, the title of the print job, the name of the person who submitted the job, and the host name of the system. The last section of this file contains the names of the actual files to be printed (these can be either copies of the files in the spool directory or the full path names of the actual files). Do not try to manually edit this file; if you do, the lp spooler will reject it.

Program Explanation

Since the program builds a linked list to hold the entries from the /var/spool/lpd/qdir directory, the first step is to set up a structure to hold these. I defined the structure t_type to hold the file name and the link to the next structure. I set the length of the name to 255 because this is MAX_PATH on AIX.

The first procedure, get_files(), opens the directory using the dirent functions and builds a linked list of the entries. It skips the first two entries (. and ..), then returns a pointer to the first member of the list.

Using the list built by get_files, the procedure find_job_number() reads the first line from each of the files and checks it against the job number that the user entered. This procedure return a NULL pointer if the job number is not found; otherwise, it returns a pointer to the correct entry.

The procedure read_and_transfer() opens the header files and skips past the unused information. It then reads each string from the file, checking to see if it is a regular file and if the path name is less than MAX_PATH. It then adds that string to the transfer string. I allocated only 4096 bytes for the transfer string. In most cases this should be more than enough, but if you need more, simply increase this number.

The last procedure, is_file(), simply checks to see if a file is a regular file. It returns TRUE if the file is regular; otherwise, it returns FALSE.

I could have skipped the building of the linked list and simply opened each file by combining get_files() and find_job_number(), but I decided to leave this this structure in place so that I could easily implement the second part of the SCO lpmove command at a later time.

Command Syntax

To compile for AIX 3.1:

cc -DAIX31 -olptran lptran.c

To compile for AIX 3.2:

cc -DAIX32 -olptran lptran.c

To use:

lptran <job_number> <queue>


If you are using the AIX LP spooler, I am sure you have encountered the need for this command. You've probably also wondered, as I have, why IBM has not implemented the command in some form. I hope our version will help you fill the hole in the AIX LP spooler.

About the Author

Jeff Courington has worked on various forms of UNIX over the past 8 years, including AIX, SCO, HP/UX, and SVR3 variants from Silicon Valley Software and Versyss Corporation. He presently has a network of 11 IBM RS/6000s and various HP/UX machines connected over the wide area with TCP/IP through the use of Cisco routers. Jeff graduated from Virginia Polytechnical Institute and State University with a BS in Computer Science. He is currently working on his MS in Computer Science at Virginia Commonwealth University and can be reached from the Internet at!aix!jeff.