4
# Comments on usage from the email we received:
5
# I showed a friend the following script. He said I should submit it for
6
# inclusion in openldap, because it might useful for others.
8
# The attached perl script, when used like
10
# ldapsearch | ldiftopasswd
14
# 1. create /etc/passwd, /etc/shadow, /etc/group, and /etc/gshadow
16
# 2. append /etc/passwd.top, /etc/shadow.top, /etc/group.top, and /etc/gshadow.top to respective files.
18
# 3. use data from ldap to create the files (note: gshadow isn't really
19
# supported, because I don't use it, nor could I find any
20
# documentation. Adding support for other files should be easy).
22
# (of course you need access to all fields including the password field
23
# for this, so use correct parameters to ldapsearch).
25
# This could be useful for instance on laptop computers where you don't
26
# want to run a slave slapd server for some reason (perhaps memory
28
# ----------------------------------------
34
my $passwdfile="/etc/passwd";
35
my $shadowfile="/etc/shadow";
36
my $groupfile="/etc/group";
37
my $gshadowfile="/etc/gshadow";
40
'--passwd=s',\$passwdfile,
41
'--shadow=s',\$shadowfile,
42
'--group=s',\$groupfile,
43
'--gshadow=s',\$gshadowfile,
45
) or die "Bad options\n";
47
if ($help or $#ARGV != -1) {
48
print STDERR "usage: $0 [etcfile=filename] [--help]\n";
54
my $outhandle = new IO::File;
55
$outhandle->open(">$file") or die "Cannot open $file for writing";
57
open(TMP,"<$file.top") or die "cannot open $file.top for reading";
58
while (<TMP>) { $outhandle->print($_); }
59
close(TMP) or die "cannot close $file for reading";
64
my $PASSWD = start_file($passwdfile);
65
my $SHADOW = start_file($shadowfile);
66
my $GROUP = start_file($groupfile);
67
my $GSHADOW = start_file($gshadowfile);
76
$record->{"uidNumber"},":",
77
$record->{"gidNumber"},":",
78
$record->{"gecos"},":",
79
$record->{"homeDirectory"},":",
80
$record->{"loginShell"},"\n");
82
if (defined($record->{"userPassword"}) &&
83
$record->{"userPassword"} =~ /^{(crypt)}(.*)$/)
84
{ $userPassword = $2; }
89
$record->{"shadowLastChange"} || "10706",":",
90
$record->{"shadowMin"} || "0",":",
91
$record->{"shadowMax"} || "99999",":",
92
$record->{"shadowWarning"} || "7",":",
93
$record->{"shadowInactive"} || "",":",
94
$record->{"shadowExpire"} || "",":",
100
my $userPassword="*";
103
if (defined($record->{"memberUid"})) {
104
$members = join(",",@{$record->{"memberUid"}});
110
$record->{"gidNumber"},":",
113
if (defined($record->{"userPassword"}) &&
114
$record->{"userPassword"} =~ /^{(crypt)}(.*)$/)
115
{ $userPassword = $2; }
119
# $record->{"cn"},":",
142
elsif (/^objectClass: posixAccount$/) {
145
elsif (/^objectClass: posixGroup$/) {
148
elsif (/^(uid|uidNumber|gidNumber|gecos|homeDirectory|loginShell): (.*)$/) {
149
if (!defined($record{$1})) { $record{$1} = $2; }
151
elsif (/^(userPassword|shadowLastChange|shadowMin|shadowMax|shadowWarning|shadowInactive|shadowExpire): (.*)$/) {
152
if (!defined($record{$1})) { $record{$1} = $2; }
154
elsif (/^(cn): (.*)$/) {
155
if (!defined($record{$1})) { $record{$1} = $2; }
157
elsif (/^(uniqueMember): (.*)$/) {
158
push @{$record{$1}},$2;
159
if ($2 =~ /uid=([a-zA-Z]*),/) {
160
push @{$record{"memberUid"}},$1;
163
elsif (/^(memberUid): (.*)$/) {
164
push @{$record{$1}},$2;
166
elsif (/^(userPassword):: (.*)$/) {
167
$record{$1} = decode_base64($2);
171
$PASSWD->close or die "Cannot close $passwdfile for writing";
172
$SHADOW->close or die "Cannot close $shadowfile for writing";
173
$GROUP->close or die "Cannot close $groupfile for writing";
174
$GSHADOW->close or die "Cannot close $gshadowfile for writing";