NAME
Sys::Export::Unix::UserDB - Abstractions for Unix passwd/group/shadow files
SYNOPSIS
use Sys::Export::Unix::UserDB;
# Load from filesystem
my $source_db = Sys::Export::Unix::UserDB->new;
$source_db->load('/path/to/source/etc');
# Create destination database and import some users/groups
my $dest_db = Sys::Export::Unix::UserDB->new(
auto_import => $source_db,
users => [qw( root daemon postgres nobody )],
groups => [qw( root wheel daemon video audio )],
);
# Add new users and groups
$dest_db->add_group('newgroup', gid => 1001);
$dest_db->add_user('newuser', uid => 1001, groups => [qw( audio video newgroup )]);
# Save to files
$dest_db->save('/path/to/dest/etc', format => 'Linux');
DESCRIPTION
This module provides abstractions for working with Unix 'passwd' databases, consisting of the /etc/passwd
and /etc/group
files, as well as platform-specific extensions like /etc/shadow
. (currently only Linux is supported, but BSD /etc/master.passwd
wouldn't be hard to add support for)
The goal of this object is to extract user/group information from one system image and merge it into another, with proper conflict detection and UID/GID management. It can also import users and groups from the host via getpwnam
/getgrnam
.
CONSTRUCTORS
new
$udb= Sys::Export::Unix::UserDB->new(%options);
- auto_import
-
The "auto_import" attribute, which can be another UserDB, or any "true" value meaning to import from the host.
- valid_name_regex
-
Affects the result of "is_valid_name", unless overridden in a subclass
- users
-
Hashref of
{ username => \%user_attrs }
of users to be added. An arrayref of usernames can be used if you setauto_import
, in which case each name will be imported (but must exist in the auto_import source). THis can also be an arrayref of User objects. - groups
-
Hashref of
{ groupname => \%group_attrs }
of groups to be added. An arrayref of group names can be used if you setauto_import
. It can also be an arrayref of Group objects.
ATTRIBUTES
users
A hashref of username => $user_obj
.
uids
A convenience hashref uid => $first_user_obj_having_uid
.
groups
A hashref of groupname => $group_obj
.
gids
A convenience hashref gid => $first_group_obj_having_gid
.
auto_import
This setting causes "user" (or "group") with an unknown name or ID to attempt to import the user/group rather than returning false. If the import fails, the "user" / "group" methods return false as normal.
If the value of this attribute is an instance of Sys::Export::Unix::UserDB, it imports from that other user database. If the value is a simple true scalar, it imports from the host via getpwnam etc. See "import_user" for a description of how imports work.
METHODS
clone
my $cloned_db = $userdb->clone;
Creates a deep clone of the entire UserDB object.
is_valid_name
Return true if a name is valid for users/groups of a UserDB. By default this uses a fairly permissive regular expression, and future versions may become more permissive. You can override it with something more specific to your system by passing valid_name_regex => qr/.../
to the constructor. You could also override this method in a subclass.
load
$userdb->load($path);
Given a path like /example/etc
, reads passwd, group, and (if readable) shadow files from that directory. Future versions may also support master.passwd
for BSD support.
save
$userdb->save($path_or_hashref);
If given a path, saves passwd, group, and shadow files to that directory. If given a hashref, saves the file contents into scalars named 'passwd', 'group', 'shadow'.
import_user
$user= $userdb->import_user($name); # attrs from getpwnam
$user= $userdb->import_user($user_obj); # from another userdb
$user= $userdb->import_user($name, %attrs); # like add_user, but "DWIM"
Imports a user into this UserDB. This differs from "add_user" in that it will attempt to re-number foreign UID/GIDs that conflcit with UID/GIDs that already exist in this UserDB. UID/GID under 1000 are considered "service accounts" and remapping will choose a new number on the same side of that divider as the old number. You should specify a name rather than GID for the user's primary group. If the group name is the same as the user name, this will create a group with GID equal to the UID.
Note: the behavior of this function is subject to change if I can find better ways to Do What I Mean for an import. If you want perfect backward compatibility, you should add the users and groups directly with the add_*
functions.
Returns the newly created user object, or dies.
import_group
$group= $userdb->import_group($name); # attrs from getgrnam
$group= $userdb->import_group($group_obj); # from another userdb
$group= $userdb->import_group($name, %attrs); # like add_group, but "DWIM"
Imports a group into this UserDB. This differs from "add_group" in that it will attempt to re-number foreign GIDs that conflcit with GIDs that already exist in this UserDB. GIDs under 1000 are considered "service accounts" and remapping will choose a new number on the same side of that divider as the old number.
Returns the newly created group object, or dies.
add_user
$user= $userdb->add_user($name_or_user_obj, %attrs);
Creates a new user. If the first parameter is a User object, clones it. Otherwise creates a new user with the given name. Duplicate names throw an exception, but duplicate UIDs only warn.
Returns the newly created user object, or dies.
add_group
$group= $userdb->add_group($name_or_group_obj, %attrs);
Creates a new group. If the first parameter is a Group object, clones it. Otherwise creates a new group with the given name. Duplicate names throw an exception, but duplicate UIDs only warn.
Returns the newly created group object, or dies.
user
$user = $userdb->user($name_or_uid);
Returns a user by name or UID if it exists, undef
otherwise. If "auto_import" is enabled, this may first attempt to import the requested UID/name.
has_user
Like "user" but returns a boolean and doesn't attempt to auto_import
.
group
$group = $userdb->group($name_or_uid);
Returns a group by name or GID if it exists, undef
otherwise. If "auto_import" is enabled, this may first attempt to import the requested GID/name.
has_group
Like "group" but returns a boolean and doesn't attempt to auto_import
.
USER OBJECTS
The user entries in the UserDB are represented as mostly-writeable objects. These deviate from the normal fields of /etc/passwd by having a group
attribute instead of gid
. The gid
is resolved during export using the UserDB's group list. Also, the supplemental groups are stored on the user object instead of as a list of members on the group object. There are also attributes for the fields of the shadow file.
You may declare arbitrary attributes, but you get a warning if they aren't known. This allows future compatibility with formats other than Linux.
User Attributes
This object supports accessors for arbitrary attributes via AUTOLOAD, but the following are pre-defined. Using an unknown attribute accessor generates a warning, which you can suppress by adding keys to the set of %Sys::Export::Unix::UserDB::User::known_attrs
.
- name
-
Required
- uid
-
Required
- group
-
Required, and should be a name rather than a GID.
- groups
-
A set (hashref) of supplemental group names, but you may assign using an arrayref for convenience.
- comment
-
General user information, usually full name
- gecos
-
More specific type of comment which should be composed of Full Name, Ofice Location, Work Tel. and Home Tel. User-editable, so structure is not enforced.
- dir
-
Home directory path
- shell
-
Login shell, or program to run on login
- passwd
-
The hashed password. This field is written to the
shadow
file. If a shadow file entry is required (for this or other shadow fields) then thepasswd
file field is written asx
, else*
. - expire
-
Unix time when account will expire (converted to epoch seconds if the field was stored as days)
- pw_last_change
-
Unix time of last password change (converted to epoch seconds if the field was stored as days)
- pw_min_age
-
Min days before password can be changed
- pw_max_age
-
Max days before password must be changed
- pw_warn_days
-
Days before max when warning is given to user
- pw_inactive_days
-
Days after max when user can still log in and immediately change password
User Methods
- new
- clone
- add_group
- remove_group
GROUP OBJECTS
While the /etc/group file normally stores a list of users belonging to a group, this UserDB implementation stores a set of groups on the user object, so the group object is rather empty.
Group Attributes:
This object supports accessors for arbitrary attributes via AUTOLOAD, but the following are pre-defined. Using an unknown attribute accessor generates a warning, which you can suppress by adding keys to the set of %Sys::Export::Unix::UserDB::Group::known_attrs
.
- name
-
Group name
- gid
-
Group ID
- passwd
-
Group password, which should never be used anyway. Leave this
undef
or'*'
.
Group Methods:
- new
- clone
VERSION
version 0.003
AUTHOR
Michael Conrad <mike@nrdvana.net>
COPYRIGHT AND LICENSE
This software is copyright (c) 2025 by Michael Conrad.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.