[Samba-it] samba+ldap passwd

Marco Gaiarin gaio at sv.lnf.it
Tue Mar 16 02:29:37 MDT 2010


Mandi! Paolo Ghidini
  In chel di` si favelave...

> E' una cosa corretta o sono superflui e basta settare solo la scadenza
> della password? qualcuno utilizza un'altro sistema?

Le strade sono essenzialmente tre:

1) non usi come provider degli account (nss) e del contesto pam 'account'
 LDAP, ma winbind

2) usi LDAP come provider nss, ma usi winbind nel contesto pam
 'auth' solo per l'autenticazione.

3) usi LDAP sia come nss che come provider pam per 'account', e ti
 costruisci uno script che periodicamente 'sincronizza' le scadenza da
samba a posix.


Personalmente a me non piace 1), ma perchè non mi piace tenermi dietro
tutte le chincaglierie che winbind fa. Sono del partito anti-winbind,
questa lista lo sa, il problema è che ogni tanto non mi ricordo più
perchè... ;)

la soluzione 2 sarebbe un ottimo compromesso se winbind fosse usabile
nel contesto 'account', ma devi usare auth, un po' rigidino...

Io uso la soluzione 3, e se si tratta di un client aggiungo anche
winbind nel contesto pam 'password' che permette di cambiare la
password da linux.
Allego script.

-- 
dott. Marco Gaiarin				    GNUPG Key ID: 240A3D66
  Associazione ``La Nostra Famiglia''                http://www.sv.lnf.it/
  Polo FVG  -  Via della Bontà, 7 - 33078  -  San Vito al Tagliamento (PN)
  marco.gaiarin(at)sv.lnf.it	  tel +39-0434-842711  fax +39-0434-842797

		Dona il 5 PER MILLE a LA NOSTRA FAMIGLIA!
	   http://www.lanostrafamiglia.it/chi_siamo/5xmille.php
	(cf 00307430132, categoria ONLUS oppure RICERCA SANITARIA)
-------------- next part --------------
#!/usr/bin/perl -w

#  This code was developped by Marco Gaiarin <gaio at linux.it>
#  taking ideas and code from smbldap-tools script by IDEALX
#  (http://IDEALX.org/) and
#
#                 Copyright (C) 2006 Marco Gaiarin
#                 Copyright (C) 2001-2002 IDEALX
#
#  This program 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
#  of the License, or (at your option) any later version.
#
#  This program 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 have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
#  USA.

# Purpose of smbldap-userexpire: expire user (posix,shadow,samba) after some
#				 inactivity time

# CHANGELOG
#
# (Thu Jul 20 16:12:39 CEST 2006)
#  + added -P options, rename all POSIX options
#  + considering the case sambaLogonTime < sambaPwdLastSet


use strict;
use smbldap_tools;

#####################

use Getopt::Std;
my %Options;

# getting some info from config file
#
my $pwdage = 90;
if (defined $config{defaultMaxPasswordAge}) {
  $pwdage = $config{defaultMaxPasswordAge};
}
my $acctage = 180;
my $pxpwdage = 210;
my $pxacctage = 360;
my $pxwarndays = 7;
 

my $ok = getopts('vdfsp:a:P:A:W:h?', \%Options);
if ( (!$ok) || (@ARGV < 1) || ($Options{'?'}) || ($Options{'h'}) ) {
  print_banner;
  print "Usage: $0 [-vdfs?h] [-p days] [-a days] [-P days] [-A days] [-W days] username\n";
  print "Available options are:\n";
  print "  -v    verbose mode\n";
  print "  -d    dry-run (do all the checks but just not update)\n";
  print "  -f    fix broken/impossible value\n";
  print "  -s    fix also POSIX/shadow account information\n";
  print "  -p    password age, default $pwdage (in days)\n";
  print "  -a    account age, default $acctage (in days)\n";
  print "  -P    POSIX password age, default $pxpwdage (in days)\n";
  print "  -A    POSIX account age, default $pxacctage (in days)\n";
  print "  -W    POSIX warning days before expiring, default $pxwarndays (in days)\n";
  print "  -?|-h show this help message\n";
  exit (1);
}

if ($< != 0) {
  print "You must be root to modify an user\n";
  exit (1);
}
# Read only first @ARGV
my $user = $ARGV[0];

# Let's connect to the directory first
my $ldap_master=connect_ldap_master();

# Read user data
my $user_entry = read_user_entry($user);
if (!defined($user_entry)) {
  if ($Options{'v'}) {
    print "$0: user $user doesn't exist\n";
  }
  exit (1);
}
my $dn = $user_entry->dn();

# no samba? no party!
if ( ! grep ($_ =~ /^sambaSamAccount$/i, $user_entry->get_value('objectClass'))) {
  if ($Options{'v'}) {
    print "$0: user $user doesn't have samba data, nothing to do.\n";
  }
  exit(1);
}

# some vars...
my @mods;
my $tmp;
my constant $max = 2147483647;
my $retval = 0;
my $curdate = time;

# reapup account ages on commandline...
if (defined($tmp = $Options{'p'})) {
  $pwdage = int($tmp);
}
if (defined($tmp = $Options{'a'})) {
  $acctage = int($tmp);
}
if (defined($tmp = $Options{'P'})) {
  $pxpwdage = int($tmp);
}
if (defined($tmp = $Options{'A'})) {
  $pxacctage = int($tmp);
}
if (defined($tmp = $Options{'W'})) {
  $pxwarndays = int($tmp);
}

# Eventually adding missing shadowAccount OC
if ( ($Options{'s'}) && (! grep ($_ =~ /^shadowAccount$/i, $user_entry->get_value('objectClass'))) ) {
  my @objectclass = $user_entry->get_value('objectClass');
  push(@mods, 'objectClass' => [ @objectclass, 'shadowAccount' ]);
  if ($Options{'v'}) {
    print "$0: user $user shadowAccount ObjectClass missing added\n";
  }
}

# Password expiration are handled automatically by samba, here we do only
# some check... note that we use a theresold value of one day for password
# expiration...
my $pls = $user_entry->get_value('sambaPwdLastSet');
my $pmc = $user_entry->get_value('sambaPwdMustChange');
if (! defined($pmc) ) {
  $pmc = 0;
}
my $af = $user_entry->get_value('sambaAcctFlags');
if ($Options{'f'}) {
  if ( $pls > $curdate ) {
    $pls = $curdate;  
    if ($Options{'v'}) {
      print "$0: user $user sambaPwdLastSet invalid, resetting to $pls\n";
    }
    push(@mods, 'sambaPwdLastSet' => $pls);
  }

  if ( $pmc > $curdate + (($pwdage+1)*24*60*60) ) {
    $pmc = $curdate;
    if ($Options{'v'}) {
      print "$0: user $user sambaPwdMustChange too high, resetting to $pmc\n";
    }
    push(@mods, 'sambaPwdMustChange' => $pmc);
  }

  if ( $af =~ /X/ ) {
    if ($Options{'v'}) {
      print "$0: user $user sambaAcctFlags 'X' enabled, resetting it\n";
    }
    $af =~ s/X//;
    push(@mods, 'sambaAcctFlags' => $af);
  }
}


# account expiration/disabling...
my $lot = $user_entry->get_value('sambaLogonTime');
if (! defined($lot) ) {
  $lot = 0;
}
if ( $lot < $pls ) {
  # strange, this user have a logon time smaller than last pwd set, could
  # be a real UNIX guy that use smbpasswd by hand?
  # anyway we consider this an access...
  if ($Options{'v'}) {
    print "$0: user $user sambaPwdLastSet considered as an access\n";
  }
  $lot = $pls;
  push(@mods, 'sambaLogonTime' => $lot);
}
if ( ($lot < $curdate - ($acctage*24*60*60)) && ($af !~ /D/) ) {
  if ($Options{'v'}) {
    print "$0: user $user sambaLogonTime too low, disabling account\n";
  }
  $af =~ s/U/DU/;
  push(@mods, 'sambaAcctFlags' => $af);
  $retval = 2;

  # if we are using shadow, this could be excessive, but better do this
  # then risk to have and open access lying around...
  my $up = $user_entry->get_value('userPassword');
  if ( ($Options{'s'}) && ($lot < $curdate - ($pxacctage*24*60*60)) && ($up !~ /^{crypt}x$/) ) {
    if ($Options{'v'}) {
      print "$0: user $user sambaLogonTime really too low, disabling POSIX account\n";
    }
    $up = "{crypt}x";
    push(@mods, 'userPassword' => $up);
  }
}

# poking POSIX shadow data...
if ( $Options{'s'} ) {
  my $lc = $user_entry->get_value('shadowLastChange');
  if ( ! defined($lc) ) {
    $lc = 0;
  }
  my $slc = int ($pls/(24*60*60));
  if ( $lc != $slc ) {
    if ($Options{'v'}) {
      print "$0: user $user setting up shadow data\n";
    }
    push(@mods, 'shadowLastChange' => $slc);
    push(@mods, 'shadowMin' => 0);
    push(@mods, 'shadowMax' => $pxpwdage);
    push(@mods, 'shadowWarning' => $pxwarndays);
    push(@mods, 'shadowInactive' => ($pxacctage - $pxpwdage) );
  }
}

# apply changes
if ( (@mods) && (! $Options{'d'}) ) {
  my $modify = $ldap_master->modify ( "$dn",
				    'replace' => { @mods }
				  );
  $modify->code && warn "failed to modify entry: ", $modify->error ;
}

# take down session
$ldap_master->unbind;

# need to tackle with nscd...
if ( (@mods) && (! $Options{'d'}) ) {
  my $nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1";
  if ($nscd_status == 0) {
    system "/etc/init.d/nscd restart > /dev/null 2>&1";
  }
} 

# we exit with a well-known exit status, so if we change something
# important we can warn users...
exit($retval);

############################################################

=head1 NAME

smbldap-userexpire - Expire user account based on last access time

=head1 SYNOPSIS

smbldap-userexpire [-v] [-d] [-f] [-s] [-p days] [-a days] [-x days] login

=head1 DESCRIPTION

The  smbldap-userexpire  command  check for account access timestamp, and update account info accordingly, typically disabling account if not used by some time.

-v
 Verbose mode, print any action taken

-d
 Dry-run, actually compute all needed modification but not apply them; usually used in conjunction with -v

-f
 Fix broken/impossible data, that can prevent an account to expire

-s
 Fix also POSIX/shadow data; note that LDAP shadow data can not be used, so this script also set the POSIX password invalid

-p days
 Password age in days (also use defaultMaxPasswordAge in smbldap.conf)

-a days
 Samba Account age in days

-P days
 POSIX password age in days

-A days
 POSIX Account age in days

-W days
 POSIX warning days before expiring; in PAM-enabled environment, the POSIX layer will warn users that password are expiring


=head1 RETURN VALUES

This script return 0 if all goes well, 1 if something goes wrong and 2 if all goes well and a Samba account was disabled.

This is intended so you can catch return value, and do something (send an email, ...) to user. For the same reason Samba account age <> POSIX account age, with the latter better to be highest then the former.

=head1 SEE ALSO

       smbldap-usermod(1) smbldap-useraccess(1) chage(1)

=cut

#'


More information about the samba-it mailing list