NAME

AcctInfo.pm - Accessing and Manipulating Unix account information with Perl.


SYNOPSIS

In its simplest form:

    #!/usr/local/bin/perl -w

    use AcctInfo;

    my $acct = new AcctInfo;

    $acct->SetUser("root");
    $acct->cache;
    $acct->dump;
    exit;

That script would dump some info about the root account. The amount and quality of info would depend on how many features your operating system reports. By default, the cache() method tries to get as much info as possible and store it for easy access.

Example output from the program above:

  Username  : root
  Password  : H7axm7Qd0ezas
  UID       : 0
  GID       : 1
  Name      : 0000-Admin(0000)
  Home Dir  : /
  Shell     : /sbin/sh
  File Quota:
  File Usage:
  Disk Quota:
  Disk Usage:
  Exipration: none
  Exp Date  : Wed Dec 31 19:00:00 1969
  Change    : 10161
  Today     : 10216
  Today Date: Wed Dec 31 21:50:16 1969
  DaysLeft  : infinity
  Min       :
  Max       :
  Warn      :
  Inactive  :
  Flag      :
  MyStatus  :
  MyTime    :
  Forward   : "|/usr/local/bin/procmail"

Not all that interesting, but read on.


DESCRIPTION

AcctInfo attempts to abstract information about user accounts (usernames, passwords, shells, quotas, account expiration info, and so on) with a uniform interface. Ideally, one can develop account reporting and/or manipulation tools which use AcctInfo to gather information, and they'll run on any system that is supported by AcctInfo.pm. See NOTES for details.

Of course, if you develop a script to report on, say, account expiration dates, and you try to run it on a system that doesn't have any sense of account expiration, you will encounter trouble. So, your mileage may vary.

In this early version, the module is read-only by default. You shouldn't be able to damage anything by running it. That's mostly because the code for manipulating /etc/passwd and /etc/shadow is still experimental, and must be manually turned on. See NOTES for more information.


REQUIREMENTS

Perl 5.003 or newer is required. I strongly suggest newer.

Carp.pm is required (it's standard in Perl 5.003 and up, anyway).

Root access to the system on which you want to use this library may be necessary. Without root access, you will only have access to a subset of the information that would normally be available. Specifically, you cannot read the shadow password file (if there is one) or the disk quotas without it.

You MUST read the README file which is included in the distribtuion. It may contain information which ammends, corrects, or otherwise impacts what you will read in the remainder of the documentation.


USAGE

This module was designed for flexability. There are many ways to access most of the information stored in an AcctInfo object. You can either use the built-in Access Functions or read the Variables directly. (You're not actually reading them directly, but it appears so as far as your program is concerned.)


Installation

You should read the README file to make sure you've installed the module properly. It should be a familiar process like:

 % perl Makefile.PL
 % make
 % make test
 % make install


Access Functions

The following functions are defined in the AcctInfo module. Most of them are public, meaning that you're supposed to use them. Some are private, meaning that you're not supposed to use them -- but I won't stop you. Assume that functions are public unless otherwise documented.

As a convention, you may notice that most accessor functions begin with ``Get'' and most functions which change or set things begin with ``Set''. Of course, there are exceptions.

These are listed in no particular order. I should probably either group them by logical function or alphabetize them.

AUTOLOAD()
The autoload routine is what gives you access to AcctInfo's variables as explained in the Variables section below.

new()
The new routine is used to create a new instance of AcctInfo.

Example: my $acct = new AcctInfo;

debug()
debug() toggles debugging messages. By default, debugging is turned off. Turn it on if you are developing AcctInfo or having trouble with it.

debug() understands all of the folloing:

        Enable       Disable
        ------       -------
          1             0
        'yes'         'no'
        'on'          'off'

If you contact me for help, I'll likely ask you for some debugging output.

Example: $acct->debug;

cache()
cache() attempts to gather as much info about the current account as possible. You must have set the username via a call to SetUser() before calling cache().

cache() should give you a performance boost. You should be aware that cache() may be called automatically by some methods.

Example: $acct->cache;

reset()
reset() will clear all of the current object's internal data structures. Rather than creating lots of AcctInfo objects and using each only once, you may want to recycle them by calling reset() and then cache() after you've done a SetUser(). It depends on your needs.

Example: $acct->reset; $acct->SetUser("jzawodn"); $acct->cache;

dump()
dump() exists for debugging purposes. When invoked, the current object will print out all the current account info in a simple format.

Example: $acct->dump;

Commit()
Commit() must be called if you change any user attributes and want to make them really happen. Generally, you'll need to call Commit() after using any of the Set* functions (except SetUser()).

Commit() is generally smart enough to only bother updating files that require updating. For example, if you change a user's .forward using SetForward(), Commit() won't bother to re-write /etc/passwd and/or /etc/shadow, since those files don't care about mail forwarding.

Example: $acct->SetForward("/dev/null"); $acct->Commit();

SetUser()
SetUser() is what you call to tell the current instance of AccInfo which account you'd like to do stuff with. Just pass a username. If the account does not exist, it will return a false value.

Example: $acct->SetUser("root)";

GetAllUsers()
GetAllUsers() returns a list of all the usernames. They are in the order that your system returns them, which will either mean (a) the order they appear in /etc/passwd, or (b) the semi-random order from NIS/Yellow Pages. If you only want ``real'' users, see GetNonSystemUsers().

Example: my @users = $acct->GetAllUsers;

GetNonSystemUsers()
GetNonSystemUsers works just like GetAllUsers() except that it tries to exclude ``system'' users like root, sys, diag, lp, and so on. If it doesn't guess quite right, you might want to tweak the $hiUid and $loUid variables to suit your system. Essentially, it will only return the usernames for accounts whose uids fall between $loUid and $hiUid.

The default values for loUid and hiUid are 100 and 60,000 respectively.

Example: my @realusers = $acct->GetNonSystemUsers;

GetRealName()
GetRealName does just what you'd expect. It returns the ``real name'' of the current user. It simply grabs the user's gcos field. This means that you may get more that you bargin for if you're not careful. Some systems store other stuff in the gcos field (like phone numbers so that you can finger someone to get their phone number). If your system is like that, you may want to split on /,/ or something similar to get the info you are looking for.

If there is demand, I can implement some of that processing in this module.

See also: passwd

Example: print "$acct->Uname is really $acct->GetRealName";

SetRealName()
SetRealName is like GetRealNAme(), except that you're changing the user's 'real name' (gcos field).

Example: $acct ->-SetUser("porky"); $acct->cache; $acct->SetRealName("Porky the Pig");)

GetShell()
Returns the shell for the current user.

Example: print "Your shell is $acct->GetShell";

GetUid()
Returns the uid of the current user.

Example: print "Your uid is $acct->GetUid";

GetGid()
Returns the gid of the current user.

Example: print "Your primary gid is $acct->GetGid";

GetHomeDir()
Returns the home directory of the current user.

Example: my $homedir = $acct->GetHomeDir;

VerifyPassword()
Pass a guess of the password for the current user, and VerifyPassword will return true if it is correct, false otherwise.

Example: if ($acct->VerifyPassword("PaSsWoRd!")) { print "You guessed it!\n"; }

GetPassword()
Get's the current user's [encrypted] password. If you want to verify a password, just use VerifyPassword() and be done with it. If you want to do something else with the password, like extract the salt, use this function.

Example: my $encpasswd = $acct->GetPassword;

GetLastChange()
Returns the ``last change'' field from the shadow password file. This is the date when the user's password was last changed.

Example: my $lastchange = $acct->GetLastChange;

GetMin()
Returns the ``min'' field from the shadow password file.

GetMax()
Returns the ``max'' field from the shadow password file.

GetWarn()
Returns the ``warn'' field from the shadow password file.

GetInactive()
Returns the ``inactive'' field from the shadow password file.

GetExpire()
Returns the ``expire'' field from the shadow password file.

GetFlag()
Returns the ``flag'' field from the shadow password file.

ParsePWent()
PRIVATE

Used to parse the entries in the password file.

ParseSHent()
PRIVATE

Used to parse the entries in the shadow password file.

getpwnams()
PRIVATE

A version of getpwnam() that works on the shadow password file.

GetDaysLeft()
Returns the number of days before the current account will expire.

Example: print "You have $acct->GetDaysLeft days left.";

GetExpireDate()
Returns the expiration date for the current account.

Example: print "Your account is set to exipire on $acct->GetExpireDate";

GetForward()
Returns the contents of the user's .forward file (if one exists).

Example: print "Your mail is forwarded to $acct->GetFoward";

SetForward($foo)
Set's the user's .forward file to $foo.

Example: $acct->SetForward("/dev/null");

HasShadow()
Returns true if the system has a shadow password file. False if not.

Example: if($acct->HasShadow) { print "Yeay! You have a shadow password file.\n"; }

ChopDec()
PRIVATE

Used to chop decimals off of numbers after division.


Variables

There may be cases in which you don't feel like calling any of the AcctInfo functions for getting data. It just so happens that you can access many of AcctInfo's internal vairables by name, thanks to the autoload feture. Following is a quick list of those varibles, what they represent, and what functions are used to access and/or set them.

All of these are accessed like $acct->variable where variable comes from the list below.

    Variable      Description
    ========      ===========
    Uname         username
    Uid           uid
    Gid           gid
    Passwd        Encrypted passwordn
    Homedir       Home directory
    Name          real name
    Shell         shell
    Fquota        file quota
    Fusage        file usage
    Dquota        disk quota
    Dusage        disk usage
    Change        last change
    Expire        when the account expires (numeric)
    ExpireDate    date when the account expires
    Today         what today is (for comparing Expire)
    TodayDate     what today is (for comparing with ExpireDate)
    DaysLeft      how many days the user has left (Expire - Today)
    Min           the min field from /etc/shadow
    Max           the max field from /etc/shadow
    Warn          the warn field from /etc/shadow
    Inactive      the inactive field from /etc/shadow
    Flag          the flag field from /etc/shadow
    Forward       the contents of the user's .forward file (if exists)

You should always free to browse the source and try to figure it out own your own. I didn't try to hide anything (much).


NOTES

  1. Two global variables were recently added. They are $PARANOID and $EXPERIMENTAL.

    $PARANOID
    Set to 1 (true) by default.

    This controls how many sanity/safety checks occur when critical files are being updated. For the puposes of this discussion, critical files are /etc/passwd and /etc/shadow. That may change to include more files/features in the future.

    Any feedback on this measure is greatly appreciated.

    $EXPERIMENTAL
    Set to 0 (false) by default.

    This controls weather or not AcctInfo will let you do things which are currently considered experimental. The exact meaning of ``experimental'' will change in subsequent releases as the code sees more testing and has proven itself a bit.

    In this release, the following items are experimental:

    Updating /etc/passwd when Commit() is called.

    I plan to come up with a more useful way of setting these, without the need to actually modify AcctInfo.pm. See the Wishlist file for more details.

  2. This has been tested on Solaris 2.5.x and 2.6.x as well as Linux (Red Hat) 4.x.

  3. Quota support is currently being developed--it doesn't work yet.


CREDITS

Thanks to Rajeev Atluri <rajeev@cookie.gadzoox.com> for testing the code and pointing out documentaion problems.

Thanks to Eric Johansson <esj@harvee.billerica.ma.us> for some ideas about the Get/Set/Commit implementation. Eric may be working on a FreeBSD version as well.


AUTHOR

Jeremy D. Zawodny, <jzawodn@wcnet.org>