source: npl/fileserver/smb-ldap-tool/modified/smbldap-passwd @ 26ffad7

Last change on this file since 26ffad7 was c5c522c, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

initial commit, transferred from cleaned syn3 svn tree

  • Property mode set to 100755
File size: 10.2 KB
RevLine 
[c5c522c]1#!/usr/bin/perl -w
2
3# LDAP to unix password sync script for samba
4# $Id: smbldap-passwd 5895 2012-09-28 10:17:48Z edwin $
5
6#  This code was developped by IDEALX (http://IDEALX.org/) and
7#  contributors (their names can be found in the CONTRIBUTORS file).
8#
9#                 Copyright (C) 2001-2002 IDEALX
10#
11#  This program is free software; you can redistribute it and/or
12#  modify it under the terms of the GNU General Public License
13#  as published by the Free Software Foundation; either version 2
14#  of the License, or (at your option) any later version.
15#
16#  This program is distributed in the hope that it will be useful,
17#  but WITHOUT ANY WARRANTY; without even the implied warranty of
18#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19#  GNU General Public License for more details.
20#
21#  You should have received a copy of the GNU General Public License
22#  along with this program; if not, write to the Free Software
23#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
24#  USA.
25
26#  Purpose :
27#       . ldap-unix passwd sync for SAMBA>2.2.2 + LDAP
28#       . may also replace /bin/passwd
29
30# untaint environment
31$ENV{'PATH'}= '/bin:/usr/bin';
32$ENV{'SHELL'}= '/bin/sh';
33delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
34
35use strict;
36use FindBin;
37use FindBin qw($RealBin);
38use lib "$RealBin/";
39use smbldap_tools;
40
41use Crypt::SmbHash;
42use Digest::MD5 qw(md5);
43use Digest::SHA1 qw(sha1);
44use MIME::Base64 qw(encode_base64);
45
46# function declaration
47sub make_hash;
48sub make_salt;
49
50my $user= undef;
51my $oldpass= undef;
52
53my $arg;
54my $update_samba_passwd= 1;
55my $update_unix_passwd= 1;
56my $quiet=0;
57
58foreach $arg (@ARGV) {
59  if ( substr( $arg, 0, 1 ) eq '-' ) {
60    if ( $arg eq '-h' || $arg eq '-?' || $arg eq '--help' ) {
61      print_banner;
62      print "Usage: $0 [options] [username]\n";
63      print "  -h, -?, --help show this help message\n";
64      print "  -s             update only samba password\n";
65      print "  -u             update only UNIX password\n";
66      exit (6);
67    } elsif ($arg eq '-s') {
68      $update_samba_passwd= 1; $update_unix_passwd= 0;
69    } elsif ($arg eq '-u') {
70      $update_samba_passwd= 0; $update_unix_passwd= 1;
71    } elsif ($arg eq '-q'){
72      $quiet=1;
73    }
74  } else {
75    if ( $< != 0 ) {
76      die "Only root can specify username\n";
77    }
78    $user= $arg; last;
79  }
80}
81
82if (!defined($user)) {
83  $user = getpwuid($<);         # $user=$ENV{"USER"};
84}
85
86# check if $user variable is not tainted
87# [TODO] create proper user mask
88$user =~ /^([-\@\ \w.]+\$?)$/ and $user = $1 or
89  die "$0: username '$user' is tainted\n";
90
91
92my ($dn,$ldap_master);
93# First, connecting to the directory
94if ($< != 0) {
95  # non-root user
96  if (!defined($oldpass)) {
97    # prompt for password
98    print "Identity validation...\nenter your UNIX password: ";
99    system "/bin/stty -echo" if (-t STDIN);
100    chomp($oldpass=<STDIN>);
101    system "/bin/stty echo" if (-t STDIN);
102    print "\n";
103
104    $config{masterDN}="uid=$user,$config{usersdn}";
105    $config{masterPw}="$oldpass";
106    $ldap_master=connect_ldap_master();
107    $dn=$config{masterDN};
108    if (!is_user_valid($user, $dn, $oldpass)) {
109      print "Authentication failure\n";
110      exit (10);
111    }
112  }
113} else {
114  # root user
115  $ldap_master=connect_ldap_master();
116  # test existence of user in LDAP
117  my $dn_line;
118  if (!defined($dn_line = get_user_dn($user))) {
119    print "$0: user $user doesn't exist\n";
120    exit (10);
121  }
122  $dn = get_dn_from_line($dn_line);
123}
124
125my $samba = is_samba_user($user);
126
127# Printing verbose message
128if ( $samba and $update_samba_passwd ) {
129  if ( $update_unix_passwd ) {
130    if (!$quiet)
131    {
132      print "Changing UNIX and samba passwords for $user\n";
133    }
134  } else {
135    print "Changing samba password for $user\n";
136  }
137} else {
138  if ( $update_unix_passwd ) {
139    print "Changing UNIX password for $user\n";
140  } else {
141    die "Internal error";
142  }
143}
144
145# prompt for new password
146
147my $pass;
148my $pass2;
149
150if (!$quiet)
151{
152  print "New password: ";
153  system "/bin/stty -echo" if (-t STDIN);
154  chomp($pass=<STDIN>);
155  system "/bin/stty echo" if (-t STDIN);
156  print "\n";
157
158  print "Retype new password: ";
159  system "/bin/stty -echo" if (-t STDIN);
160  chomp($pass2=<STDIN>);
161  system "/bin/stty echo" if (-t STDIN);
162  print "\n";
163}
164else{
165  chomp($pass=<STDIN>);
166  $pass2=$pass;
167}
168
169if ($pass ne $pass2) {
170  print "New passwords don't match!\n";
171  exit (10);
172}
173
174# Prepare '$hash_password' for 'userPassword'
175my $hash_password;
176# Generate password hash
177if ($config{with_slappasswd}) {
178  # checking if password is tainted: nothing is changed!!!!
179  # essential for perl 5.8
180  ($pass =~ /^(.*)$/ and $pass=$1) or
181    die "$0: user password is tainted\n";
182
183  # use slappasswd to generate hash
184  if ( $config{hash_encrypt} eq "CRYPT" && defined($config{crypt_salt_format}) ) {
185    open BUF, "-|" or
186      exec "$config{slappasswd}",
187        "-h","{$config{hash_encrypt}}",
188          "-c","$config{crypt_salt_format}",
189            "-s","$pass";
190    $hash_password = <BUF>;
191    close BUF;
192  } else {
193    open(BUF, "-|") or
194      exec "$config{slappasswd}",
195        "-h","{$config{hash_encrypt}}",
196          "-s","$pass";
197    $hash_password = <BUF>;
198    close BUF;
199  }
200} else {
201  # use perl libraries to generate hash
202  $hash_password = make_hash($pass,$config{hash_encrypt},$config{crypt_salt_format});
203}
204# check if a hash was generated, otherwise die
205defined($hash_password) or
206  die "I cannot generate the proper hash!\n";
207chomp($hash_password);
208
209# First, connecting to the directory
210if ($< != 0) {
211  # if we are not root, we close the connection to re-open it as a normal user
212  $ldap_master->unbind;
213  $config{masterDN}="uid=$user,$config{usersdn}";
214  $config{masterPw}="$oldpass";
215  $ldap_master=connect_ldap_master();
216}
217
218# only modify smb passwords if smb user
219if ( $samba and $update_samba_passwd ) {
220  if (!$config{with_smbpasswd}) {
221    # generate LanManager and NT clear text passwords
222    my ($sambaLMPassword,$sambaNTPassword) = ntlmgen $pass;
223    # the sambaPwdLastSet must be updating
224    my $date=time;
225    my @mods;
226    push(@mods, 'sambaLMPassword' => $sambaLMPassword);
227    push(@mods, 'sambaNTPassword' => $sambaNTPassword);
228    push(@mods, 'sambaPwdLastSet' => $date);
229    if (defined $config{defaultMaxPasswordAge}) {
230      my $new_sambaPwdMustChange=$date+$config{defaultMaxPasswordAge}*24*60*60;
231      push(@mods, 'sambaPwdMustChange' => $new_sambaPwdMustChange);
232      if ($< ==0) {
233        push(@mods, 'sambaAcctFlags' => '[U]');
234      }
235    }
236    # Let's change nt/lm passwords
237    my $modify = $ldap_master->modify ( "$dn",
238                                        'replace' => { @mods }
239                                      );
240    $modify->code && warn "failed to modify entry: ", $modify->error ;
241
242  } else {
243    if ($< != 0) {
244      my $FILE="|$config{smbpasswd} -s >/dev/null";
245      open (FILE, $FILE) || die "$!\n";
246      print FILE <<EOF;
247$oldpass
248$pass
249$pass
250EOF
251      ;
252      close FILE;
253    } else {
254      open FILE,"|-" or
255        exec "$config{smbpasswd}","$user","-s";
256      local $SIG{PIPE} = sub {die "buffer pipe terminated" };
257      print FILE <<EOF;
258$pass
259$pass
260EOF
261      ;
262      close FILE;
263    }
264  }
265}
266
267# Update 'userPassword' field
268if ( $update_unix_passwd ) {
269  my $modify = $ldap_master->modify ( "$dn",
270                                      changes => [
271                                                  replace => [userPassword => "$hash_password"]
272                                                 ]
273                                    );
274  $modify->code && warn "Unable to change password: ", $modify->error ;
275}
276
277# take down session
278$ldap_master->unbind;
279
280exit 0;
281
282# Generates hash to be one of the following RFC 2307 schemes:
283# CRYPT,  MD5,  SMD5,  SHA, SSHA,  and  CLEARTEXT
284# SSHA is default
285# '%s' is a default crypt_salt_format
286# A substitute for slappasswd tool
287sub make_hash
288  {
289    my $hash_encrypt;
290    my $crypt_salt_format;
291
292    my $clear_pass=$_[0] or return undef;
293    $hash_encrypt='{' . $_[1] . '}' or $hash_encrypt = "{SSHA}";
294    $crypt_salt_format=$_[2] or $crypt_salt_format = '%s';
295
296    my $hash_pass;
297    if ($hash_encrypt eq "{CRYPT}" && defined($crypt_salt_format)) {
298      # Generate CRYPT hash
299      # for unix md5crypt $crypt_salt_format = '$1$%.8s'
300      my $salt = sprintf($crypt_salt_format,make_salt());
301      $hash_pass = "{CRYPT}" . crypt($clear_pass,$salt);
302
303    } elsif ($hash_encrypt eq "{MD5}") {
304      # Generate MD5 hash
305      $hash_pass = "{MD5}" . encode_base64( md5($clear_pass),'' );
306
307    } elsif ($hash_encrypt eq "{SMD5}") {
308      # Generate SMD5 hash (MD5 with salt)
309      my $salt = make_salt(4);
310      $hash_pass = "{SMD5}" . encode_base64( md5($clear_pass . $salt) . $salt,'');
311
312    } elsif ($hash_encrypt eq "{SHA}") {
313      # Generate SHA1 hash
314      $hash_pass = "{SHA}" . encode_base64( sha1($clear_pass),'' );
315
316    } elsif ($hash_encrypt eq "{SSHA}") {
317      # Generate SSHA hash (SHA1 with salt)
318      my $salt = make_salt(4);
319      $hash_pass = "{SSHA}" . encode_base64( sha1($clear_pass . $salt) . $salt,'' );
320
321    } elsif ($hash_encrypt eq "{CLEARTEXT}") {
322      $hash_pass=$clear_pass;
323
324    } else {
325      $hash_pass=undef;
326    }
327    return $hash_pass;
328  }
329
330# Generates salt
331# Similar to Crypt::Salt module from CPAN
332sub make_salt
333  {
334    my $length=32;
335    $length = $_[0] if exists($_[0]);
336 
337    my @tab = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
338    return join "",@tab[map {rand 64} (1..$length)];
339  }
340
341# - The End
342
343=head1 NAME
344
345smbldap-passwd - change user password
346
347=head1 SYNOPSIS
348
349smbldap-passwd [-?|--help|-s|-u] [name]
350
351=head1 DESCRIPTION
352
353smbldap-passwd changes passwords for user accounts. A normal user may only change the password for their own account, the super user may change the password for any account.
354
355If option -s specified then changed only samba password.
356If options -u specified then changed only UNIX password.
357With no options then changed both - UNIX and samba passwords.
358
359Password Changes
360 The user is first prompted for their old password, if one is present. This password is then tested against the stored password by binding to the server. The user has only one chance to enter the correct passwword. The super user is permitted to bypass this step so that forgotten passwords may be changed.
361 The user is then prompted for a replacement password. As a general guideline, passwords should consist of 6 to 8 characters including one or more from each of following sets:
362
363Lower case alphabetics
364
365Upper case alphabetics
366
367Digits 0 thru 9
368
369Punctuation marks
370
371Password will prompt again and compare the second entry against the first. Both entries are require to match in order for the password to be changed.
372
373=head1 SEE ALSO
374
375       passwd(1)
376
377=cut
378
379#'
Note: See TracBrowser for help on using the repository browser.