The netgroup membership module

Synopsis

Module Name:

pam_netgroups

Author:

Tom Payerle <payerle@umd.edu>

Maintainer:

Currently, the author (http://www.glue.umd.edu/~payerle/Software/PAM-Netgroups)

Management groups provided:

account

Cryptographically sensitive:

Security rating:

Clean code base:

Not rated by Linux PAM maintainer. Seems clean on modern linuxes.

On some older systems, receive several warnings during compile when NIS support enabled, believed to be deficiencies in libraries using. rpcsvc/ypclnt.h generates a warning for list ending in a comma. Files args.-c and nis.-c generate warnings when use NIS functions yp_get_default_domain and yp_match about discarding const'edness. I believe these are due to lax use of const'edness in the NIS function prototypes.

System dependencies:

If NIS support enabled, uses header files rpcsvc/ypclnt.h and rpcsvc/yp_prot.h. Functions in libc. Does not use function innetgr which is disabled in some libc distributions.

If HESIOD support enabled, requires libhesiod and libresolv, and the header file hesiod.h, which are part of standard MIT hesiod distribution.

Network aware:

Uses NIS and HESIOD maps, if enabled.

Overview of module

This module grants or denies access based on netgroup membership. It was written to restrict access to machines based on a list of users and/or HESIOD-based netgroups, but has been generalized where it was somewhat easy or useful to do so.

The item being compared to the list can be almost any standard PAM item, not just the username (although for ease of discussion, will generally refer to this item as the user). The concept of netgroup is not restricted to NIS netgroups, but actually any NIS or HESIOD map in addition to standard Unix groups. The NIS and HESIOD maps can be a list of users, etc. keyed on the name of the group, or a list of groups keyed on the username, etc.

Account Management component

Recognized arguments:

General options:
sense=allow|deny
file=filename
[onerr=succeed|fail]
[item=PAM_USER|PAM_RUSER|PAM_RHOST|PAM_TTY]
[version[=yes|no]|noversion]
[debug[=integer]|nodebug]
[extra_warnings[=yes|no]|noextra_warnings]

Map options:
[maptype=unix|NIS|hesiod]
[map=map_name]
[mapmode=bygroup|byuser|netgroup]
[domain=NIS domain]
[recursive[=yes|no]|norecursive]
[field_sep=comma|space|comma_or_space|space_or_comma|netgroup|none]

File input format options:
[comments[=yes|no|no_inline]|nocomments]
[pluschar[=yes|no|required]|nopluschar]
[defmode=include|exclude]
[nulluser[=yes|no]|nonulluser]

Description:

This module usually compares the requestee's username to a list of user and group names in a specified file, and grant or allow access depending on whether the username was found in the file. Normally, it will grant access if username is found in the file (sense=allow mode), but setting sense=deny reverses this. More generally, it will compare one of a number of PAM variables to the file, but for purposes of this discussion we will assume it is the username being compared.

The specified file is opened and read line by line, with each line presumed to contain a single username or groupname (excluding comments, and blank lines are ignored with a warning). The user or groupname may be preceded by a plus ('+') or minus ('-') character to indicate whether that user/group should be included or excluded from the list (see the flags pluschar and defmode). The module reads the file until the requestee's username matches a line in the file, or is in the group listed on the line. Usually, the line is in include mode, and the module allow or deny access according to the sense flag. If the line is in exclude mode, the module stops reading the input file and acts as if the username was not found in the file. If the nulluser flag is set, a bare plus or minus character will act as a wild card matching all users in include or exclude mode, respectively.

Groups are denoted with a leading ampersand ('&') character, and can check for membership in standard Unix groups, or NIS or HESIOD maps, according to the maptype flag. If the requestee's username is a member of the group, the module will behave as if it matched an username listed in the file, based on whether the line was in include or exclude mode and the value of the sense flag.

For Unix maptypes, it simply checks if the user has the group as its primary group or in its extended groupset. None of the other map related flags are used or allowed.

For NIS and HESIOD maps, the name of the map to use is specified with the map flag. The map can be keyed on the group name, returning a list of users in the group (mapmode=bygroup), in which case the username is considered a member of the netgroup if it is found in the returned list. Alternatively, the map can be keyed on usernames (mapmode=byuser), returning a list of groups the user belongs to, in which case the username is considered a member of the netgroup if the group name is found in the returned list. For NIS maps, you can also specify mapmode=netgroup, which mimics normal netgroup behavior, in which the map defaults to netgroup, keyed on the group name, and returning NIS netgroup triplets. Membership is established if the appropriate element of the triplet (user for PAM_USER or PAM_RUSER, or host for PAM_RHOST) matches the item in question.

The field_sep flag determines how to split the list returned from the map into distinct elements, whether at commas, spaces, or either (field_sep=comma, space, or comma_or_space, respectively. space_or_comma is a synonym for comma_or_space). The flag also can take the value netgroup when dealing with NIS netgroups to properly parse lists containing netgroup triplets.

The recursive flag can be set to allow netgroups within netgroups. It is by default on for NIS netgroups, in which case it treats any entry which is not a netgroup triplet as an included group on which to recurse. For other maps, it can be set, in which case it treats an entry in the returned list as a group to recurse into if it begins with an ampersand ('&'). The module will then do a lookup in the map with that new group as the key, and then check if the requestee's username (if mapmode is bygroup) or the group name in the file (if mapmode is byuser) is in the new list returned. Note that the enclosed group is used as the key for recursive lookups even in byuser map mode.

Detailed description of arguments

The module ignores case in the names of the flags, and when matching value strings to a list of allowed values.

Examples/suggested usage:

An example typical of the types of uses I see for this module is as follows. Consider a cluster of machines sharing a common user list with one host acting as the mail server (incoming and outgoing SMTP, IMAP, POP, etc.). You do not wish to allow all users login access to the mail server, but you don't wish to mess with the passwd file, etc., either. So you create a file /etc/restrict.login on the mail server, containing the lines:

# restrict.login file for mail server
+@admins
+@mailadmins
- #This line is not really needed
Then using a /etc/pam.d/login file like (note the account section):
#%PAM-1.0
auth required /lib/security/pam_pwdb.so shadow nullok
account required /lib/security/pam_netgroups.so file=/etc/restrict.login maptype=NIS nulluser sense=allow
account required /lib/security/pam_pwdb.so
password required /lib/security/pam_pwdb.so nullok use_authtok md5 shadow
session required /lib/security/pam_pwdb.so
(Note also that a number of lines not relevant to this discussion have been elided. The above is not recommended for use in a real system, it is merely an example of using the netgroups module.)

With the above configuration files, anyone trying to login to the mail server will first get the standard username/password stuff, but will not be allowed access unless the user is a member of one or both of the (standard NIS) netgroups admins or mailadmins.

If instead of standard NIS netgroups your system was using the hesiod map ngbygroup, with key admins returning the value tom, dick, harry and key mailadmins returning the value mary, helen, kevin, danny , peter, then replacing the pam_netgroups line in the above login file with:

account required /lib/security/pam_netgroups.so file=/etc/restrict.login maptype=hesiod map=ngbygroup mapmode=bygroup nulluser sense=allow
would allow users tom, dick, harry, mary, helen, kevin, danny, and peter to log in, but no one else.

If this is a large cluster with many users, it may be more efficient to invert the map for netgroup membership, and use instead the map ngbyuser, with keys for each user listing the groups they are in. E.g., the value for key mary might look like: users, imap_users, mailusers, mailadmins, itstaff, webadmins The corresponding line in the pam configuration file for the login service would be:

account required /lib/security/pam_netgroups.so file=/etc/restrict.login maptype=hesiod map=ngbyuser mapmode=byuser nulluser sense=allow
In this case, only users with either mailadmins or admins in their list of groups they belong to (i.e. the list returned when reading the entry in map ngbyuser keyed on their username) can log in.

If you wanted to restrict pop service to members of the mailusers group who are not also members of the imap_users group, you can use the following as a /etc/restrict.pop file:

#
# This is a sample restict.pop file
+@mailadmins #If this came after imap_users, then mailadmins who use imap
# would not be able to use pop
-@imap_users #imap_users can't use pop, only imap
+@mail_users # All mail users who aren't imap_users can use pop
Mailadmins are allowed to use pop, as are all mail_users who are not imap_users. An imap_user (not in mailadmins), would get matched at second line, but since that line is in exclude mode, they are treated as not in the file and denied access. If using standard NIS netgroups, the relevant line in the pam configuration for pop file would be:
account required /lib/security/pam_netgroups.so file=/etc/restrict.pop maptype=NIS sense=allow