#!/usr/bin/perl
-# $Id: sync-accounts,v 1.18 2002-07-14 17:04:59 ianmdlvl Exp $
+# This is part of sync-accounts, a tool for synchronising UN*X password data.
#
-# Copyright (C)1999-2000 Ian Jackson <ian@davenant.greenend.org.uk>
-# Copyright (C)2000-2001 nCipher Corporation Ltd
+# sync-accounts is
+# Copyright 1999-2000,2002 Ian Jackson <ian@davenant.greenend.org.uk>
+# Copyright 2000-2001 nCipher Corporation Ltd
#
-# This is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free
-# Software Foundation; either version 2, or (at your option) any later
-# version.
+# sync-accounts is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
#
-# This is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# for more details.
+# sync-accounts is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
#
# You should already have a copy of the GNU General Public License.
# If not, write to the Free Software Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
-# The config file consists of directives, one per line. Leading and
-# trailing whitespace, blank lines and lines starting # are ignored.
-#
-# Some config file directives apply globally and should appear first:
-#
-# lockpasswd link <suffix/filename>
-# lockgroup link <suffix/filename>
-# Specifies the lockfile suffix or pathname to use when editing
-# the passwd and group files. The value is a suffix if it does
-# not start with `/'. If set to /dev/null no locking is done.
-#
-# lockpasswd runvia <program>
-# lockgroup runvia <program>
-# Lock by reinvoking ourselves via a program as EDITOR.
-# (<program> would typically be vipw or vigr.)
-#
-# lockpasswd none
-# lockgroup none
-# Do not lock.
-#
-# logfile <filename>
-# Append log messages to <filename> instead of stdout.
-# Errors still go to stderr.
-#
-# localformat bsd|std
-# Specifies the local password file is in the relevant format:
-# `std' is the standard V7 password file (with a SysV- style
-# /etc/shadow if one is detected at run-time); `bsd' is the weird
-# BSD4.4 master.passwd format, and should be used only with
-# `lockpasswd runvia vipw'. The default is `std'.
-#
-# Some config file directives set options which may be different at
-# different points in the file. The most-recently-seen value is used
-# at each point:
-#
-# uidmin <min>
-# uidmax <max>
-# homebase <pathname>
-# When an account is to be created, a uid/gid will be chosen
-# which is one higher than the highest currently in use (except
-# that ids outside the range <min>-<max> are ignored and will
-# never be used). The default home directory location is
-# <pathname>/<username>.
-#
-# sameuid
-# nosameuid
-# Specifies whether uids are supposed to match. The default is
-# nosameuid. When sameuid is on, it is an error for the uid or
-# gid of a local account not to match the corresponding remote
-# account, and new local accounts will get the remote accounts'
-# ids.
-#
-# usergroups
-# nousergroups
-# defaultgid <gid>
-# Specifies whether local accounts are supposed to have
-# corresponding groups, or all be part of a particular group. If
-# usergroups is set, when a new account is created, the
-# corresponding per-user group will be created as well, and
-# per-user groups are created for existing accounts if necessary
-# (if account creation is enabled). If the gid or group name for
-# a per-user group is already taken for a different group name or
-# gid this will be logged, and processing of that account will be
-# inhibited, but it is not a fatal error. If defaultgid is used,
-# then newly-created accounts will be made a part of that group,
-# and the groups of existing accounts will be left alone. If
-# nousergroups is specified then no new accounts can be created,
-# and existing accounts' groups will be left alone. The default
-# is `usergroups'.
-#
-# createuser
-# createuser <commandname>
-# nocreateuser
-# Specifies whether accounts found on the remote host should be
-# created if necessary, and what command to run to do the
-# creation (eg, setup of home directory). The default is
-# nocreateuser. If createuser is specified without a commandname
-# then sync-accounts-createuser is used. The command is found on
-# the PATH if necessary. Either sameuid, or both uidmin and
-# uidmax, must be specified, if accounts are to be created.
-#
-# The command (which will be run with sh -c) must at least create
-# the new account's home directory. The passwd and group entries
-# will not have been set up. The following environment variables
-# will be set, giving details about the account to be created:
-# SYNCUSER_CREATE_USER
-# SYNCUSER_CREATE_UID
-# SYNCUSER_CREATE_GID
-# SYNCUSER_CREATE_COMMENT
-# SYNCUSER_CREATE_HOME
-# SYNCUSER_CREATE_SHELL
-# If it chooses, the script may modify the password entry which
-# will be added to the system, by outputting a replacement
-# password file entry. (The password field of that is ignored.)
-# If the script outputs a line which does not contain a : then
-# the account will not be created after all.
-#
-# group <glob-pattern>
-# nogroup <glob-pattern>
-# Specifies that the membership of the local groups specified
-# should be adjusted or not adjusted whenever account data for a
-# particular user is copied, so that the account will be a member
-# of the affected group locally iff it is a member of the same
-# group on the remote host. The most recently-encountered
-# glob-pattern for a particular group takes effect. The default
-# is `nogroups *'.
-#
-# defaultshell <pathname>
-# If, when creating an account, the remote account's shell is not
-# available on the local system, this value will be used. The
-# default is /bin/sh.
-#
-# Some config file directives are per-host, and should appear before
-# any directives which actually modify accounts:
-#
-# host <shorthostname>
-# Starts a host's section. This resets the per-host parameters
-# to the defaults. The shorthostname need not be the host's
-# official name in any sense. If sync-accounts is invoked with
-# host names on the command line they are compared with the
-# shorthostnames.
-#
-# getpasswd <command>
-# getgroup <command>
-# Commands to run on the local host to get the passwd, shadow and
-# group data for the host in question. getpasswd must be
-# specified if user data is to be transferred; getgroup must be
-# specified if group data is to be transferred.
-#
-# getshadow <command>
-# Specifies that shadow file data is to be used (by default,
-# password information is found from the output of getpasswd).
-# The command should emit shadow data in the format specified by
-# shadow(5) on Linux. getshadow should not be specified without
-# getpasswd.
-#
-# remoteformat std|bsd
-# Specifies the format of the output of `getpasswd'. `std' is
-# standard V7 passwd file format (optionally augmented by the use
-# of a shadow file fetched with getshadow). `bsd' is the weird
-# BSD4.4 master.passwd format (and getshadow should not normally
-# be used with `remoteformat bsd'). The default is `std'.
-#
-# Some configuration file directives specify that account data is to
-# transferred from the current host. They should appear as the last
-# thing(s) in a host section:
-#
-# user <username> [remote=<remoteusername>]
-# Specifies that account data should be copied for local user
-# <username> from the remote account <remoteusername> (assumed to
-# be the same as <username> if not specified). The account
-# password, comment field, and shell will be copied
-# unconditionally. If sameuid is specified the uid will be
-# checked.
-#
-# users <ruidmin>-<ruidmax>
-# Specifies that all remote users whose uid is in the given range
-# are to be copied to corresponding local user accounts.
-#
-# nouser <username>
-# Specifies that data for <username> is _not_ to be copied, even
-# if subsequent user or users directives suggest that it should
-# be.
-#
-# (A note is made when a `user', `users' or `nouser' directive is
-# encountered for a particular account, and no subsequent directives
-# for that account will take effect.)
-#
-# addhere
-# This directive has no effect on `sync-accounts'. However, it
-# is used as a placeholder by `grab-account': new accounts for
-# creation are inserted just before `addhere'.
-#
-# Finally, the config file must finish with:
-#
-# end
+# $Id: sync-accounts,v 1.22 2002-07-14 22:21:29 ianmdlvl Exp $
use POSIX;
open O,"$fn_use" or die "$fn_use ($fn_str): $!";
while (<O>) {
chomp;
- $record= [ split(/\:/,$_,-1) ];
- die "$fn_emsg:$.:wrong number of fields:\`$_'\n"
- unless @$record == $nfields;
+ if (m/^\#/ || !m/\S/) {
+ $record= $_;
+ } else {
+ $record= [ split(/\:/,$_,-1) ];
+ die "$fn_emsg:$.:wrong number of fields:\`$_'\n"
+ unless @$record == $nfields;
+ }
push @$ary_ref, $record;
}
close O or die "$fn_use ($fn_str): $!";
sub checkuid ($$) {
my ($useuid,$foruser) = @_;
for $e (@ownpasswd) {
+ next unless ref $e;
if ($e->[$PW_USER] ne $foruser && $e->[$PW_UID] == $useuid) {
diag("uid clash with $e->[$PW_USER] (uid $e->[$PW_UID])");
return 0;
$ugfound=0;
for $e (@owngroup) {
+ next unless ref $e;
$samename= $e->[$GR_GROUP] eq $lu;
$sameid= $e->[$GR_GID] eq $luid;
next unless $samename || $sameid;
if ($display) {
for $e (@ownpasswd) {
- next unless $e->[$PW_USER] eq $lu;
+ next unless ref $e && $e->[$PW_USER] eq $lu;
hosthead("from $ch_name");
print ($lu eq $ru ? " $lu" : " $lu($ru)") or die $!;
print "<DUPLICATE>" if $displaydone{$lu}++;
return;
}
- if (!grep($_->[$PW_USER] eq $lu, @ownpasswd)) {
+ if (!grep(ref $_ && $_->[$PW_USER] eq $lu, @ownpasswd)) {
if (!length $opt_createuser) { diag("account creation not enabled"); return; }
if ($no_act) { diag("-n specified; not creating account"); return; }
$useuid= $ch_uidmin;
for $e ($defaultgid==-1 ? (@ownpasswd, @owngroup) : (@ownpasswd)) {
+ next unless ref $e;
$tuid= $e->[$PW_UID]; next if $tuid<$useuid || $tuid>$ch_uidmax;
if ($tuid==$ch_uidmax) {
diag("uid (or gid?) $ch_uidmax used, cannot create users");
}
for $e (@ownpasswd) {
- next unless $e->[$PW_USER] eq $lu;
+ next unless ref $e && $e->[$PW_USER] eq $lu;
syncusergroup($lu,$e->[$PW_UID]) or return;
}
$rgid= $rempasswd{$ru}->[$REM_GID];
if ($opt_sameuid && checkuid($ruid,$lu)) {
for $e (@ownpasswd) {
- next unless $e->[$PW_USER] eq $lu;
+ next unless ref $e && $e->[$PW_USER] eq $lu;
$luid= $e->[$PW_UID]; $lgid= $e->[$PW_GID];
die "$diagstr: local uid $luid, remote uid $ruid\n" if $luid ne $ruid;
die "$diagstr: local gid $lgid, remote gid $rgid\n" if $lgid ne $rgid;
}
#print STDERR "syncuser($lu,$ru) exists $own_haveshadow\n";
- if ($own_haveshadow && grep($_->[$PW_USER] eq $lu, @ownshadow)) {
+ if ($own_haveshadow && grep(ref $_ && $_->[$PW_USER] eq $lu, @ownshadow)) {
#print STDERR "syncuser($lu,$ru) shadow $rempasswd{$ru}->[$REM_PW]\n";
copyfield('shadow',$lu,$SP_PW, $rempasswd{$ru}->[$REM_PW]);
} else {
if (!$nogroups) {
for $e (@owngroup) {
+ next unless ref $e;
$tgroup= $e->[$GR_GROUP];
#print STDERR "syncuser($lu,$ru) group $tgroup\n";
next unless &wantsyncgroup($tgroup);
}
sub finish () {
+ my ($record);
+
for $h (keys %wanthost) {
die "host $h not in config file\n" if $wanthost{$h};
}
if ($display) {
#print STDERR "\n\nfinish display=$display pw=$pw\n\n";
for $e (@ownpasswd) {
+ next unless ref $e;
$tu= $e->[$PW_USER];
$tuid= $e->[$PW_UID];
next if $displaydone{$tu};
$tpw= $e->[$PW_PW];
#print STDERR ">$tu|$tpw<\n";
for $e2 (@ownshadow) {
- next unless $e2->[$SP_USER] eq $tu;
+ next unless ref $e2 && $e2->[$SP_USER] eq $tu;
$tpw= $e2->[$SP_PW]; last;
}
$tpw= length($tpw)>=13 ? 1 : length($tpw) ? -1 : 0;
}
open NF,"> $newfile" or die "$newfile: $!";
for $e (@$data_ref) {
- print NF join(':',@$e),"\n" or die $!;
+ $record= ref $e ? join(':',@$e) : $e;
+ print NF $record,"\n" or die $!;
}
close NF or die $!;
system 'diff','-U0','--label',$realfile,$newfileinst,
while (<CF>) {
chomp;
- next if m/^\#/ || !m/\S/;
s/^\s*//; s/\s*$//;
+ next if m/^\#/ || !m/\S/;
finish() if m/^end$/;
if (m/^host\s+(\S+)$/) {
$ch_name= $1;