home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
c
/
cops_104.zip
/
cops_104
/
perl
/
pass.cache.pl
< prev
next >
Wrap
Perl Script
|
1992-03-10
|
11KB
|
445 lines
#
# Routines for reading and caching user and group information. These
# are used in multiple programs... it caches the info once, then hopefully
# won't be used again.
#
# Steve Romig, May 1991.
#
# Provides a bunch of routines and a bunch of arrays. Routines
# (and their usage):
#
# load_passwd_info($use_getent, $file_name)
#
# loads user information into the %uname* and %uid* arrays
# (see below).
#
# If $use_getent is non-zero:
# get the info via repeated 'getpwent' calls. This can be
# *slow* on some hosts, especially if they are running as a
# YP (NIS) client.
# If $use_getent is 0:
# if $file_name is "", then get the info from reading the
# results of "ypcat passwd" and from /etc/passwd. Otherwise,
# read the named file. The file should be in passwd(5)
# format.
#
# load_group_info($use_gentent, $file_name)
#
# is similar to load_passwd_info.
#
# Information is stored in several convenient associative arrays:
#
# %uname2shell Assoc array, indexed by user name, value is
# shell for that user name.
#
# %uname2dir Assoc array, indexed by user name, value is
# home directory for that user name.
#
# %uname2uid Assoc array, indexed by name, value is uid for
# that uid.
#
# %uname2passwd Assoc array, indexed by name, value is password
# for that user name.
#
# %uid2names Assoc array, indexed by uid, value is list of
# user names with that uid, in form "name name
# name...".
#
# %gid2members Assoc array, indexed by gid, value is list of
# group members in form "name name name..."
#
# %gname2gid Assoc array, indexed by group name, value is
# matching gid.
#
# %gid2names Assoc array, indexed by gid, value is the
# list of group names with that gid in form
# "name name name...".
#
# You can also use routines named the same as the arrays - pass the index
# as the arg, get back the value. If you use this, get{gr|pw}{uid|gid|nam}
# will be used to lookup entries that aren't found in the cache.
#
# To be done:
# probably ought to add routines to deal with full names.
# maybe there ought to be some anal-retentive checking of password
# and group entries.
# probably ought to cache get{pw|gr}{nam|uid|gid} lookups also.
# probably ought to avoid overwriting existing entries (eg, duplicate
# names in password file would collide in the tables that are
# indexed by name).
#
# Disclaimer:
# If you use YP and you use netgroup entries such as
# +@servers::::::
# +:*:::::/usr/local/utils/messages
# then loading the password file in with &load_passwd_info(0) will get
# you mostly correct YP stuff *except* that it won't do the password and
# shell substitutions as you'd expect. You might want to use
# &load_passwd_info(1) instead to use getpwent calls to do the lookups,
# which would be more correct.
#
package main;
$PASSWD = '/etc/passwd' unless defined $PASSWD;
require 'pathconf.pl';
%uname2shell = ();
%uname2dir = ();
%uname2uid = ();
%uname2passwd = ();
%uid2names = ();
%gid2members = ();
%gname2gid = ();
%gid2names = ();
$DOMAINNAME = "/bin/domainname" unless defined $DOMAINNAME;
$YPCAT = "/bin/ypcat" unless defined $YPCAT;
$yptmp = "./yptmp.$$";
$passwd_loaded = 0; # flags to use to avoid reloading everything
$group_loaded = 0; # unnecessarily...
#
# We provide routines for getting values from the data structures as well.
# These are named after the data structures they cache their data in. Note
# that they will all generate password and group file lookups via getpw*
# and getgr* if they can't find info in the cache, so they will work
# "right" even if load_passwd_info and load_group_info aren't called to
# preload the caches.
#
# I should point out, however, that if you don't call load_*_info to preload
# the cache, uid2names, gid2names and gid2members *will not* be complete, since
# you must read the entire password and group files to get a complete picture.
# This might be acceptable in some cases, so you can skip the load_*_info
# calls if you know what you are doing...
#
sub uname2shell {
local($key) = @_;
if (! defined($uname2shell{$key})) {
&add_pw_info(getpwnam($key));
}
return($uname2shell{$key});
}
sub uname2dir {
local($key) = @_;
local(@pw_info);
if (! defined($uname2dir{$key})) {
&add_pw_info(getpwnam($key));
}
return($uname2dir{$key});
}
sub uname2uid {
local($key) = @_;
local(@pw_info);
if (! defined($uname2uid{$key})) {
&add_pw_info(getpwnam($key));
}
return($uname2uid{$key});
}
sub uname2passwd {
local($key) = @_;
local(@pw_info);
if (! defined($uname2passwd{$key})) {
&add_pw_info(getpwnam($key));
}
return($uname2passwd{$key});
}
sub uid2names {
local($key) = @_;
local(@pw_info);
if (! defined($uid2names{$key})) {
&add_pw_info(getpwuid($key));
}
return($uid2names{$key});
}
sub gid2members {
local($key) = @_;
local(@gr_info);
if (! defined($gid2members{$key})) {
&add_gr_info(getgrgid($key));
}
return($gid2members{$key});
}
sub gname2gid {
local($key) = @_;
local(@gr_info);
if (! defined($gname2gid{$key})) {
&add_gr_info(getgrnam($key));
}
return($gname2gid{$key});
}
sub gid2names {
local($key) = @_;
local(@gr_info);
if (! defined($gid2names{$key})) {
&add_gr_info(getgrgid($key));
}
return($gid2names{$key});
}
#
# Update user information for the user named $name. We cache the password,
# uid, login group, home directory and shell.
#
sub add_pw_info {
local($name, $passwd, $uid, $gid) = @_;
local($dir, $shell);
#
# Ugh! argh...yech...sigh. If we use getpwent, we get back 9 elts,
# if we parse /etc/passwd directly we get 7. Pick off the last 2 and
# assume that they are the $directory and $shell.
#
$num = ( $#_ >= 7 ? 8 : 6 );
$dir = $_[$num - 1];
$shell = $_[$num] || '/bin/sh';
if ($name ne "") {
$uname2shell{$name} = $shell;
$uname2dir{$name} = $dir;
$uname2uid{$name} = $uid;
$uname2passwd{$name} = $passwd;
if ($gid ne "") {
# fixme: should probably check for duplicates...sigh
if (defined($gid2members{$gid})) {
$gid2members{$gid} .= " $name";
} else {
$gid2members{$gid} = $name;
}
}
if ($uid ne "") {
if (defined($uid2names{$uid})) {
$uid2names{$uid} .= " $name";
} else {
$uid2names{$uid} = $name;
}
}
}
}
#
# Update group information for the group named $name. We cache the gid
# and the list of group members.
#
sub add_gr_info {
local($name, $passwd, $gid, $members) = @_;
if ($name ne "") {
$gname2gid{$name} = $gid;
if ($gid ne "") {
if (defined($gid2names{$gid})) {
$gid2names{$gid} .= " $name";
} else {
$gid2names{$gid} = $name;
}
# fixme: should probably check for duplicates
$members = join(' ', split(/[, \t]+/, $members));
if (defined($gid2members{$gid})) {
$gid2members{$gid} .= " " . $members;
} else {
$gid2members{$gid} = $members;
}
}
}
}
#
# We need to suck in the entire group and password files so that we can
# make the %uid2names, %gid2members and %gid2names lists complete. Otherwise,
# we would just read the entries as needed with getpw* and cache the results.
# Sigh.
#
# There are several ways that we might find the info. If $use_getent is 1,
# then we just use getpwent and getgrent calls to read the info in.
#
# That isn't real efficient if you are using YP (especially on a YP client), so
# if $use_getent is 0, we can use ypcat to get a copy of the passwd and
# group maps in a fairly efficient manner. If we do this we have to also read
# the local /etc/{passwd,group} files to complete our information. If we aren't
# using YP, we just read the local pasword and group files.
#
sub load_passwd_info {
local($use_getent, $file_name) = @_;
local(@pw_info);
if ($passwd_loaded) {
return;
}
$passwd_loaded = 1;
if ($'GET_PASSWD) {
open(GFILE, "$'GET_PASSWD|") || die "can't $'GET_PASSWD";
while (<GFILE>) {
chop;
&add_pw_info(split(/:/));
}
close(GFILE);
}
else {
if ($use_getent) {
#
# Use getpwent to get the info from the system, and add_pw_info to
# cache it.
#
while (@pw_info = getpwent) {
&add_pw_info(@pw_info);
}
endpwent;
return;
} elsif ($file_name eq "") {
chop($has_yp = `$DOMAINNAME`);
if ($has_yp) {
#
# If we have YP (NIS), then use ypcat to get the stuff from the
# map.@
#
system("$YPCAT passwd > $yptmp 2> /dev/null");
if (-s $yptmp) {
open(FILE, "$YPCAT passwd|") ||
die "can't 'ypcat passwd'";
while (<FILE>) {
chop;
&add_pw_info(split(/:/));
}
}
close(FILE);
}
#
# We have to read /etc/passwd no matter what...
#
$file_name = "/etc/passwd";
}
open(FILE, $file_name) ||
die "can't open $file_name";
while (<FILE>) {
chop;
if ($_ !~ /^\+/) {
&add_pw_info(split(/:/));
}
# fixme: if the name matches +@name, then this is a wierd
# netgroup thing, and we aren't dealing with it right. might want
# to warn the poor user...suggest that he use the use_getent
# method instead.
}
}
close(FILE);
}
sub load_group_info {
local($use_getent, $file_name) = @_;
local(@gr_info);
if ($group_loaded) {
return;
}
$group_loaded = 1;
if ($use_getent) {
#
# Use getgrent to get the info from the system, and add_gr_info to
# cache it.
#
while ((@gr_info = getgrent()) != 0) {
&add_gr_info(@gr_info);
}
endgrent();
return();
} elsif ($file_name eq "") {
chop($has_yp = `$DOMAINNAME`);
if ($has_yp) {
#
# If we have YP (NIS), then use ypcat to get the stuff from the
# map.
#
system("$YPCAT passwd > $yptmp 2> /dev/null");
if (-s $yptmp) {
open(FILE, "$YPCAT group|") ||
die "can't 'ypcat group'";
while (<FILE>) {
chop;
&add_gr_info(split(/:/));
}
close(FILE);
}
}
#
# We have to read /etc/group no matter what...
#
$file_name = "/etc/group";
}
open(FILE, $file_name) ||
die "can't open $file_name";
while (<FILE>) {
chop;
if ($_ !~ /^\+/) {
&add_gr_info(split(/:/));
}
# fixme: if the name matches +@name, then this is a wierd
# netgroup thing, and we aren't dealing with it right. might want
# to warn the poor user...suggest that he use the use_getent
# method instead.
}
close(FILE);
}
# Load the password stuff -- Do NOT take this out!
&'load_passwd_info(0,$PASSWD);
unlink $yptmp;
1;