Blob Blame History Raw
diff -U0 smbldap-tools-0.9.6/ChangeLog.svn36 smbldap-tools-0.9.6/ChangeLog
--- smbldap-tools-0.9.6/ChangeLog.svn36	2010-11-15 14:45:49.000000000 +0000
+++ smbldap-tools-0.9.6/ChangeLog	2011-03-07 13:09:28.736762330 +0000
@@ -1 +1,23 @@
-# $Id: ChangeLog 26 2010-11-15 14:28:01Z mm1 $
+# $Id: ChangeLog 34 2011-02-23 08:10:50Z fumiyas $
+
+2011-02-23 <fumiyas at OSS echnology, Inc. Japan>
+	* smbldap_tools.pm:
+	  - get_next_id: Use getgrgid() for GID number
+	  - read_parameter: Use lexically-scoped variable $line
+	    instead of global $_
+	  - read_user_human_readable: Use UTF-8 flaged string and
+	    \P{IsPrint} to check if an LDAP attribute has non-printable
+	    characters or not
+	* smbldap-populate: Fix wrong sambaGroupType values for local groups
+	* Replace bare "smbpasswd" with "$config{smbpasswd}"
+	* smbldap-useradd: Add -h (--no-dereference) option to the
+	  chown(1) command-line
+	* smbldap-useradd: Extend -Z (--attr) option to take multiple
+	  -Z options
+	* smbldap-usermod: Set sambaPwdLastSet to the current time
+	  if "-B 0" is used (for Samba 3.0.25 and later)
+	* smbldap-usermod: Extend -Z (--attr) option:
+	  - Take multiple -Z options
+	  - Append a value to a multi-value attribute by -Z +name=value
+	  - Remove a value from a multi-value attribute by -Z -name=value
+	  - Remove a attribte by -Z -name
diff -up smbldap-tools-0.9.6/configure.pl.svn36 smbldap-tools-0.9.6/configure.pl
--- smbldap-tools-0.9.6/configure.pl.svn36	2010-11-15 14:45:49.000000000 +0000
+++ smbldap-tools-0.9.6/configure.pl	2011-03-07 13:09:28.743763425 +0000
@@ -1,13 +1,13 @@
 #!/usr/bin/perl -w
 
-# $Id: configure.pl 26 2010-11-15 14:28:01Z mm1 $
+# $Id: configure.pl 36 2011-03-05 10:02:23Z mm1 $
 
-# This script can help you setting up the smbldap_conf.pl file. It will get all
-# the defaults value that are defined in the smb.conf configuration file. You 
+# This script can help you setting up the smbldap_conf.pl file. It will set all
+# the default values that are defined in the smb.conf configuration file. You 
 # should then start with this configuration file. You will also need the SID
-# for your samba domain: set up the controler domain before using this script.
+# for your samba domain: set up the domain controller before using this script.
 
-#  This code was developped by IDEALX (http://IDEALX.org/) and
+#  This code was developed by IDEALX (http://IDEALX.org/) and
 #  contributors (their names can be found in the CONTRIBUTORS file).
 #
 #                 Copyright (C) 2002 IDEALX
@@ -43,14 +43,14 @@ Before starting, check
  . if your samba controller is up and running.
  . if the domain SID is defined (you can get it with the 'net getlocalsid')
 
- . you can leave the configuration using the Crtl-c key combination
+ . you can leave the configuration using the Ctrl-c key combination
  . empty value can be set with the \".\" character\n";
 print "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n";
 
 # we first check if Samba is up and running
 my $test_smb=`pidof smbd`;
 chomp($test_smb);
-die "\nSamba need to be started first !\n" if ($test_smb eq "" || not defined $test_smb);
+die "\nSamba needs to be started first !\n" if ($test_smb eq "" || not defined $test_smb);
 
 print "Looking for configuration files...\n\n";
 my $smb_conf="";
@@ -67,11 +67,11 @@ if ($config_smb ne "") {
 
 my $conf_dir;
 if (-d "/etc/opt/IDEALX/smbldap-tools") {
-	$conf_dir="/etc/opt/IDEALX/smbldap-tools/";
+	$conf_dir="/etc/opt/IDEALX/smbldap-tools";
 } elsif (-d "/etc/smbldap-tools") {
-	$conf_dir="/etc/smbldap-tools/";
+	$conf_dir="/etc/smbldap-tools";
 } else {
-	$conf_dir="/etc/opt/IDEALX/smbldap-tools/";
+	$conf_dir="/etc/opt/IDEALX/smbldap-tools";
 }
 
 print "\nThe default directory in which the smbldap configuration files are stored is shown.\n";
@@ -83,13 +83,13 @@ if ($conf_dir_tmp ne "") {
   $conf_dir=$conf_dir_tmp;
 }
 
-$conf_dir=~s/(\w)$/$1\//;
+$conf_dir=~s/\/*$//;
 if (! -d $conf_dir) {
 	mkdir "$conf_dir";
 }
 
-my $smbldap_conf="$conf_dir"."smbldap.conf";
-my $smbldap_bind_conf="$conf_dir"."smbldap_bind.conf";
+my $smbldap_conf="$conf_dir"."/smbldap.conf";
+my $smbldap_bind_conf="$conf_dir"."/smbldap_bind.conf";
 
 
 
@@ -141,8 +141,8 @@ print "Let's start configuring the smbld
 #   }
 # . if no value is found in smb.conf for the keys, this value is proposed
 # . the 'insist' variable: if set to 1, then the script will always call for a value
-#   for the parameter. In other words, there's not default value, and it can't be set
-#   to a null caracter string.
+#   for the parameter. In other words, there's no default value, and it can't be set
+#   to an empty string.
 
 sub read_entry
   {
@@ -193,10 +193,10 @@ sub read_entry
     return $value;
   }
 
-print ". workgroup name: name of the domain Samba act as a PDC\n";
+print ". workgroup name: name of the domain Samba acts as a PDC for\n";
 my $workgroup=read_entry("  workgroup name","workgroup","",0);
 
-print ". netbios name: netbios name of the samba controler\n";
+print ". netbios name: netbios name of the samba controller\n";
 my $netbios_name=read_entry("  netbios name","netbiosname","",0);
 
 print ". logon drive: local path to which the home directory will be connected (for NT Workstations). Ex: 'H:'\n";
@@ -207,7 +207,7 @@ my $logonhome=read_entry("  logon home (
 #$logonhome=~s/\\/\\\\/g;
 
 print ". logon path: directory where roaming profiles are stored. Ex:'\\\\$netbios_name\\profiles\\\%U'\n";
-my $logonpath=read_entry("  logon path (press the \".\" character if you don't want roaming profile)","logonpath","\\\\$netbios_name\\profiles\\\%U",0);
+my $logonpath=read_entry("  logon path (press the \".\" character if you don't want roaming profiles)","logonpath","\\\\$netbios_name\\profiles\\\%U",0);
 #$logonpath=~s/\\/\\\\/g;
 
 my $userHome=read_entry(". home directory prefix (use %U as username)","","/home/\%U",0);
@@ -237,12 +237,11 @@ my $sambaUnixIdPooldn=read_entry("  samb
 my ($trash1,$server);
 if (defined $config{passdbbackend}) {
   ($trash1,$server)=($config{passdbbackend}=~m/(.*)ldap:\/\/(.*)/);
-} else {
-  $server="127.0.0.1";
 }
+$server="127.0.0.1" unless defined($server);
 $server=~s/\///;
 my $ldapmasterserver;
-print ". ldap master server: IP adress or DNS name of the master (writable) ldap server\n";
+print ". ldap master server: IP address or DNS name of the master (writable) ldap server\n";
 $ldapmasterserver=read_entry("  ldap master server","",$server,0);
 my $ldapmasterport;
 if (defined $config{ldapport}) {
@@ -257,7 +256,7 @@ print "\n";
 system "stty echo";
 
 # parameters for the slave ldap server
-print ". ldap slave server: IP adress or DNS name of the slave ldap server: can also be the master one\n";
+print ". ldap slave server: IP address or DNS name of the slave ldap server: can also be the master one\n";
 my $ldap_slave_server=read_entry("  ldap slave server","","$server",0);
 my $ldap_slave_port;
 if (defined $config{ldapport}) {
@@ -307,16 +306,13 @@ my $userLoginShell=read_entry(". default
 
 my $skeletonDir=read_entry(". default skeleton directory","","/etc/skel",0);
 
-my $mailDomain=read_entry(". default domain name to append to mail adress", "","",0);
+my $mailDomain=read_entry(". default domain name to append to mail address", "","",0);
 
 print "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n";
 my $template_smbldap="
-# \$Source: /opt/cvs/samba/smbldap-tools/configure.pl,v $
-# \$Id: configure.pl 26 2010-11-15 14:28:01Z mm1 $
-#
 # smbldap-tools.conf : Q & D configuration file for smbldap-tools
 
-#  This code was developped by IDEALX (http://IDEALX.org/) and
+#  This code was developed by IDEALX (http://IDEALX.org/) and
 #  contributors (their names can be found in the CONTRIBUTORS file).
 #
 #                 Copyright (C) 2001-2002 IDEALX
@@ -524,12 +520,12 @@ mailDomain=\"$mailDomain\"
 #
 ##############################################################################
 
-# Allows not to use smbpasswd (if with_smbpasswd="0" in smbldap.conf) but
+# Allows not to use smbpasswd (if with_smbpasswd=\"0\" in smbldap.conf) but
 # prefer Crypt::SmbHash library
 with_smbpasswd=\"0\"
 smbpasswd=\"/usr/bin/smbpasswd\"
 
-# Allows not to use slappasswd (if with_slappasswd="0" in smbldap.conf)
+# Allows not to use slappasswd (if with_slappasswd=\"0\" in smbldap.conf)
 # but prefer Crypt:: libraries
 with_slappasswd=\"0\"
 slappasswd=\"/usr/sbin/slappasswd\"
@@ -542,7 +538,7 @@ my $template_smbldap_bind="
 ############################
 # Credential Configuration #
 ############################
-# Notes: you can specify two differents configuration if you use a
+# Note: you can specify two different configurations if you use a
 # master ldap for writing access and a slave ldap server for reading access
 # By default, we will use the same DN (so it will work for standard Samba
 # release)
diff -up smbldap-tools-0.9.6/CONTRIBUTORS.svn36 smbldap-tools-0.9.6/CONTRIBUTORS
--- smbldap-tools-0.9.6/CONTRIBUTORS.svn36	2010-11-15 14:45:49.000000000 +0000
+++ smbldap-tools-0.9.6/CONTRIBUTORS	2011-03-07 13:09:28.743763425 +0000
@@ -1,4 +1,4 @@
-# $Id: CONTRIBUTORS 26 2010-11-15 14:28:01Z mm1 $
+# $Id: CONTRIBUTORS 36 2011-03-05 10:02:23Z mm1 $
 #
 ## Authors, developers and contributors of SMBLDAP-TOOLS
 
@@ -9,6 +9,7 @@ or maintain parts of the code tree:
  . David Le Corfec <dlc@freesurf.fr>
  . Olivier Lemaire <olivier.lemaire@IDEALX.com>
  . Martin Matuška <mm@FreeBSD.org>
+ . SATOH Fumiyasu <fumiyas at OSS Technology, Inc., Japan>
 
 Many thanks for bug reports and patches:
  . Bruce Benda
@@ -37,5 +38,5 @@ Many thanks for bug reports and patches:
 	bug report for smbldap-populate
  . Christophe DUBREUIL <christophe.dubreuil@laposte.net>
 	Net::LDAP support in smbldap_tools.pm
- . Paul Horwath <paul@city-fan.org>
+ . Paul Howarth <paul@city-fan.org>
 	various style, spelling and other bugfixes
diff -up smbldap-tools-0.9.6/smbldap_bind.conf.svn36 smbldap-tools-0.9.6/smbldap_bind.conf
--- smbldap-tools-0.9.6/smbldap_bind.conf.svn36	2010-11-15 14:45:49.000000000 +0000
+++ smbldap-tools-0.9.6/smbldap_bind.conf	2011-03-07 13:09:28.744763582 +0000
@@ -1,4 +1,4 @@
-# $Id: smbldap_bind.conf 26 2010-11-15 14:28:01Z mm1 $
+# $Id: smbldap_bind.conf 35 2011-02-23 09:07:36Z fumiyas $
 #
 ############################
 # Credential Configuration #
@@ -7,7 +7,7 @@
 # master ldap for writing access and a slave ldap server for reading access
 # By default, we will use the same DN (so it will work for standard Samba
 # release)
-slaveDN="cn=Manager,dc=iallanis,dc=info"
+slaveDN="cn=Manager,dc=example,dc=com"
 slavePw="secret"
-masterDN="cn=Manager,dc=iallanis,dc=info"
+masterDN="cn=Manager,dc=example,dc=com"
 masterPw="secret"
diff -up smbldap-tools-0.9.6/smbldap.conf.svn36 smbldap-tools-0.9.6/smbldap.conf
--- smbldap-tools-0.9.6/smbldap.conf.svn36	2010-11-15 14:45:49.000000000 +0000
+++ smbldap-tools-0.9.6/smbldap.conf	2011-03-07 13:09:28.745763738 +0000
@@ -1,4 +1,4 @@
-# $Id: smbldap.conf 26 2010-11-15 14:28:01Z mm1 $
+# $Id: smbldap.conf 35 2011-02-23 09:07:36Z fumiyas $
 #
 # smbldap-tools.conf : Q & D configuration file for smbldap-tools
 
@@ -57,7 +57,7 @@ sambaDomain="DOMSMB"
 # Slave LDAP server
 # Ex: slaveLDAP=127.0.0.1
 # If not defined, parameter is set to "127.0.0.1"
-slaveLDAP="ldap.iallanis.info"
+slaveLDAP="ldap.example.com"
 
 # Slave LDAP port
 # If not defined, parameter is set to "389"
@@ -66,7 +66,7 @@ slavePort="389"
 # Master LDAP server: needed for write operations
 # Ex: masterLDAP=127.0.0.1
 # If not defined, parameter is set to "127.0.0.1"
-masterLDAP="ldap.iallanis.info"
+masterLDAP="ldap.example.com"
 
 # Master LDAP port
 # If not defined, parameter is set to "389"
@@ -95,15 +95,15 @@ cafile="/etc/smbldap-tools/ca.pem"
 
 # certificate to use to connect to the ldap server
 # see "man Net::LDAP" in start_tls section for more details
-clientcert="/etc/smbldap-tools/smbldap-tools.iallanis.info.pem"
+clientcert="/etc/smbldap-tools/smbldap-tools.example.com.pem"
 
 # key certificate to use to connect to the ldap server
 # see "man Net::LDAP" in start_tls section for more details
-clientkey="/etc/smbldap-tools/smbldap-tools.iallanis.info.key"
+clientkey="/etc/smbldap-tools/smbldap-tools.example.com.key"
 
 # LDAP Suffix
 # Ex: suffix=dc=IDEALX,dc=ORG
-suffix="dc=iallanis,dc=info"
+suffix="dc=example,dc=com"
 
 # Where are stored Users
 # Ex: usersdn="ou=Users,dc=IDEALX,dc=ORG"
@@ -209,7 +209,7 @@ userScript="logon.bat"
 # Domain appended to the users "mail"-attribute
 # when smbldap-useradd -M is used
 # Ex: mailDomain="idealx.com"
-mailDomain="iallanis.info"
+mailDomain="example.com"
 
 ##############################################################################
 #
diff -up smbldap-tools-0.9.6/smbldap-populate.svn36 smbldap-tools-0.9.6/smbldap-populate
--- smbldap-tools-0.9.6/smbldap-populate.svn36	2010-11-15 14:45:49.000000000 +0000
+++ smbldap-tools-0.9.6/smbldap-populate	2011-03-07 13:09:28.746763893 +0000
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 
-# $Id: smbldap-populate 26 2010-11-15 14:28:01Z mm1 $
+# $Id: smbldap-populate 28 2011-02-23 00:43:34Z fumiyas $
 
 #  This code was developped by Jerome Tournier (jtournier@gmail.com) and
 #  contributors (their names can be found in the CONTRIBUTORS file).
@@ -339,7 +339,7 @@ gidNumber: 544
 cn: Administrators
 description: Netbios Domain Members can fully administer the computer/sambaDomainName
 sambaSID: S-1-5-32-544
-sambaGroupType: 5
+sambaGroupType: 4
 displayName: Administrators
 
 #dn: cn=Users,$config{groupsdn}
@@ -350,7 +350,7 @@ displayName: Administrators
 #cn: Users
 #description: Netbios Domain Ordinary users
 #sambaSID: S-1-5-32-545
-#sambaGroupType: 5
+#sambaGroupType: 4
 #displayName: users
 
 #dn: cn=Guests,$config{groupsdn}
@@ -362,7 +362,7 @@ displayName: Administrators
 #memberUid: $guestName
 #description: Netbios Domain Users granted guest access to the computer/sambaDomainName
 #sambaSID: S-1-5-32-546
-#sambaGroupType: 5
+#sambaGroupType: 4
 #displayName: Guests
 
 #dn: cn=Power Users,$config{groupsdn}
@@ -373,7 +373,7 @@ displayName: Administrators
 #cn: Power Users
 #description: Netbios Domain Members can share directories and printers
 #sambaSID: S-1-5-32-547
-#sambaGroupType: 5
+#sambaGroupType: 4
 #displayName: Power Users
 
 dn: cn=Account Operators,$config{groupsdn}
@@ -384,7 +384,7 @@ gidNumber: 548
 cn: Account Operators
 description: Netbios Domain Users to manipulate users accounts
 sambaSID: S-1-5-32-548
-sambaGroupType: 5
+sambaGroupType: 4
 displayName: Account Operators
 
 #dn: cn=System Operators,$config{groupsdn}
@@ -395,7 +395,7 @@ displayName: Account Operators
 #cn: System Operators
 #description: Netbios Domain System Operators
 #sambaSID: S-1-5-32-549
-#sambaGroupType: 5
+#sambaGroupType: 4
 #displayName: System Operators
 
 dn: cn=Print Operators,$config{groupsdn}
@@ -406,7 +406,7 @@ gidNumber: 550
 cn: Print Operators
 description: Netbios Domain Print Operators
 sambaSID: S-1-5-32-550
-sambaGroupType: 5
+sambaGroupType: 4
 displayName: Print Operators
 
 dn: cn=Backup Operators,$config{groupsdn}
@@ -417,7 +417,7 @@ gidNumber: 551
 cn: Backup Operators
 description: Netbios Domain Members can bypass file security to back up files
 sambaSID: S-1-5-32-551
-sambaGroupType: 5
+sambaGroupType: 4
 displayName: Backup Operators
 
 dn: cn=Replicators,$config{groupsdn}
@@ -428,7 +428,7 @@ gidNumber: 552
 cn: Replicators
 description: Netbios Domain Supports file replication in a sambaDomainName
 sambaSID: S-1-5-32-552
-sambaGroupType: 5
+sambaGroupType: 4
 displayName: Replicators
 
 ";
diff -up smbldap-tools-0.9.6/smbldap_tools.pm.svn36 smbldap-tools-0.9.6/smbldap_tools.pm
--- smbldap-tools-0.9.6/smbldap_tools.pm.svn36	2010-11-15 14:45:49.000000000 +0000
+++ smbldap-tools-0.9.6/smbldap_tools.pm	2011-03-07 13:09:28.747764049 +0000
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 
-# $Id: smbldap_tools.pm 26 2010-11-15 14:28:01Z mm1 $
+# $Id: smbldap_tools.pm 32 2011-02-23 01:32:15Z fumiyas $
 
 #  This code was developped by Jerome Tournier (jtournier@gmail.com) and
 #  contributors (their names can be found in the CONTRIBUTORS file).
@@ -25,6 +25,7 @@
 use strict;
 
 package smbldap_tools;
+use Encode;
 use Net::LDAP;
 use Crypt::SmbHash;
 use Unicode::MapUTF8 qw(to_utf8 from_utf8);
@@ -121,16 +122,16 @@ sub print_banner {
 sub read_parameter {
     my $line = shift;
     ## check for a param = value
-    if ( $_ =~ /=/ ) {
+    if ( $line =~ /=/ ) {
         my ( $param, $val );
-        if ( $_ =~ /\s*.*?\s*=\s*".*"/ ) {
-            ( $param, $val ) = /\s*(.*?)\s*=\s*"(.*)"/;
+        if ( $line =~ /\s*(.*?)\s*=\s*"(.*)"/ ) {
+            ( $param, $val ) = ($1, $2);
         }
-        elsif ( $_ =~ /\s*.*?\s*=\s*'.*'/ ) {
-            ( $param, $val ) = /\s*(.*?)\s*=\s*'(.*)'/;
+        elsif ( $line =~ /\s*(.*?)\s*=\s*'(.*)'/ ) {
+            ( $param, $val ) = ($1, $2);
         }
         else {
-            ( $param, $val ) = /\s*(.*?)\s*=\s*(.*)/;
+            ( $param, $val ) = $line =~ /\s*(.*?)\s*=\s*(.*)/;
         }
         return ( $param, $val );
     }
@@ -624,7 +625,7 @@ sub add_posix_machine {
 # success = add_samba_machine_smbpasswd($computername)
 sub add_samba_machine_smbpasswd {
     my $user = shift;
-    system "smbpasswd -a -m $user";
+    system "$config{smbpasswd} -a -m $user";
     return 1;
 }
 
@@ -828,9 +829,10 @@ sub read_user {
         $lines .= "dn: " . $entry->dn . "\n";
         foreach my $attr ( $entry->attributes ) {
             my @vals = $entry->get_value($attr);
-#            foreach my $val (@vals) {
-#                $val = "**UNPRINTABLE**" if ( $val =~ /[^[:print:]]/ );
-#            }
+#	    my $val_utf8 = eval {
+#		Encode::decode_utf8($val, Encode::FB_CROAK);
+#	    };
+#	    $val = "**UNPRINTABLE**" if ($@ || $val_utf8 =~ /\P{IsPrint}/);
             $lines .= $attr . ": " . join( ',', @vals ) . "\n";
         }
     }
@@ -857,7 +859,10 @@ sub read_user_human_readable {
         foreach my $attr ( $entry->attributes ) {
             my @vals = $entry->get_value($attr);
             foreach my $val (@vals) {
-                $val = "**UNPRINTABLE**" if ( $val =~ /[^[:print:]]/ );
+		my $val_utf8 = eval {
+		    Encode::decode_utf8($val, Encode::FB_CROAK);
+		};
+		$val = "**UNPRINTABLE**" if ($@ || $val_utf8 =~ /\P{IsPrint}/);
             }
             if (   $attr eq "sambaPwdLastSet"
                 or $attr eq "sambaPwdCanChange"
@@ -1209,7 +1214,8 @@ sub get_next_id($$) {
         if ( $check_uid_mesg->count == 0 ) {
 
    # now, look if the id or gid is not already used in /etc/passwd or /etc/group
-            if ( !getpwuid($nextuid) ) {
+            if ($attribute =~ /^uid/i && !getpwuid($nextuid) ||
+	        $attribute =~ /^gid/i && !getgrgid($nextuid) ) {
                 $found = 1;
                 return $nextuid;
             }
diff -up smbldap-tools-0.9.6/smbldap-useradd.svn36 smbldap-tools-0.9.6/smbldap-useradd
--- smbldap-tools-0.9.6/smbldap-useradd.svn36	2010-11-15 14:45:49.000000000 +0000
+++ smbldap-tools-0.9.6/smbldap-useradd	2011-03-07 13:09:28.748764206 +0000
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 
-# $Id: smbldap-useradd 26 2010-11-15 14:28:01Z mm1 $
+# $Id: smbldap-useradd 34 2011-02-23 08:10:50Z fumiyas $
 
 #  This code was developed by Jerome Tournier (jtournier@gmail.com) and
 #  contributors (their names can be found in the CONTRIBUTORS file).
@@ -33,13 +33,47 @@ use smbldap_tools;
 use Crypt::SmbHash;
 #####################
 
-use Getopt::Std;
+use Getopt::Long;
 my %Options;
 
-my $ok =
-  getopts( 'abc:d:g:ik:mno:s:t:u:wA:B:C:D:E:F:G:H:M:N:O:PS:T:WX:Z:?', \%Options );
+Getopt::Long::Configure('bundling');
+my $ok = GetOptions(
+    "A|sambaPwdCanChange=s"  => \$Options{A},
+    "B|sambaPwdMustChange=s" => \$Options{B},
+    "C|sambaHomePath=s"      => \$Options{C},
+    "D|sambaHomeDrive=s"     => \$Options{D},
+    "E|sambaLogonScript=s"   => \$Options{E},
+    "F|sambaProfilePath=s"   => \$Options{F},
+    "G|group=s"              => \$Options{G},
+    "H|sambaAcctFlags=s"     => \$Options{H},
+    "M|mailAddresses=s"      => \$Options{M},
+    "N|givenName=s"          => \$Options{N},
+    "O|mailLocalAddress=s"   => \$Options{O},
+    "P"                      => \$Options{P},
+    "S|surname=s"            => \$Options{S},
+    "T|mailToAddress=s"      => \$Options{T},
+    "W"                      => \$Options{W},
+    "X|inputEncoding=s"      => \$Options{X},
+    "Z|attr=s@"              => \$Options{Z},
+    "a|addsambaSAMAccount"   => \$Options{a},
+    "b|aix"                  => \$Options{b},
+    "c|gecos=s"              => \$Options{c},
+    "d|homedir=s"            => \$Options{d},
+    "g|gid=s"                => \$Options{g},
+    "h|?|help"               => \$Options{h},
+    "i"                      => \$Options{i},
+    "k=s"                    => \$Options{k},
+    "m"                      => \$Options{m},
+    "n"                      => \$Options{n},
+    "o|ou=s"                 => \$Options{o},
+    "p=s"                    => \$Options{p},
+    "s|shell=s"              => \$Options{s},
+    "t=s"                    => \$Options{t},
+    "u|uid=s"                => \$Options{u},
+    "w"                      => \$Options{w},
+);
 
-if ( ( !$ok ) || ( @ARGV < 1 ) || ( $Options{'?'} ) ) {
+if ( ( !$ok ) || ( @ARGV < 1 ) || ( $Options{'h'} ) ) {
     print_banner;
     print "Usage: $0 [-abcdgikmnostuwABCDEFGHMNOPSTWXZ?] username\n";
     print "  -a	is a Windows User (otherwise, Posix stuff only)\n";
@@ -79,7 +113,7 @@ if ( ( !$ok ) || ( @ARGV < 1 ) || ( $Opt
     print "  -T	mailToAddress (forward address) (comma separated)\n";
     print "  -X	input encoding for givenname and surname (default UTF-8)\n";
     print "  -Z	set custom LDAP attributes, name=value pairs comma separated\n";
-    print "  -?	show this help message\n";
+    print "  -h	show this help message\n";
     exit(1);
 }
 
@@ -482,7 +516,7 @@ if ( defined( $tmp = $Options{'m'} ) ) {
                 system "mkdir $userHomeDirectory 2>/dev/null";
             }
             system
-"chown -R $userUidNumber:$userGidNumber $userHomeDirectory 2>/dev/null";
+"chown -hR $userUidNumber:$userGidNumber $userHomeDirectory 2>/dev/null";
             if ( defined $config{userHomeDirectoryMode} ) {
                 system
 "chmod $config{userHomeDirectoryMode} $userHomeDirectory 2>/dev/null";
@@ -521,17 +555,26 @@ if (@userMailTo) {
 }
 
 # Custom modification - MPK
-if ( $Options{'Z'} ) {
-    my @namval = split /,/, $Options{'Z'};
-    if (@namval) {
-        foreach my $pair (@namval) {
-            my ( $name, $value ) = split /=/, $pair;
-            next if ( !$name or !$value );
-            push( @adds, $name => $value );
-        }
+if ( defined( $tmp = $Options{'Z'} ) ) {
+    my %adds;
+    for my $pair ( map { split /,/ } @{$Options{'Z'}} ) {
+	my ( $name, $value ) = split( /[=:]/, $pair, 2 );
+	$name = lc( $name );
+	push( @{$adds{$name}}, $value );
+    }
+
+    while ( my ($name, $value) = each( %adds ) ) {
+	push( @adds, $name => $value );
     }
 }
 
+if (@adds) {
+    my $modify =
+      $ldap_master->modify( "uid=$userName,$config{usersdn}", add => {@adds} );
+
+    $modify->code && die "failed to add entry: ", $modify->error;
+}
+
 # Add Samba user infos
 if ( defined( $Options{'a'} ) ) {
     if ( !$config{with_smbpasswd} ) {
@@ -588,7 +631,7 @@ if ( defined( $Options{'a'} ) ) {
 
     }
     else {
-        my $FILE = "|smbpasswd -s -a $userName >/dev/null";
+        my $FILE = "|$config{smbpasswd} -s -a $userName >/dev/null";
         open( FILE, $FILE ) || die "$!\n";
         print FILE <<EOF;
 x
@@ -616,6 +659,8 @@ EOF
     $tmp = defined( $Options{'F'} ) ? $Options{'F'} : $config{userProfile};
     my $valprofilepath = &subst_user( $tmp, $userName );
 
+    my @adds = ();
+
     if ($valhomedrive) {
         push( @adds, 'sambaHomeDrive' => $valhomedrive );
     }
diff -up smbldap-tools-0.9.6/smbldap-usermod.svn36 smbldap-tools-0.9.6/smbldap-usermod
--- smbldap-tools-0.9.6/smbldap-usermod.svn36	2010-11-15 14:45:49.000000000 +0000
+++ smbldap-tools-0.9.6/smbldap-usermod	2011-03-07 13:09:28.749764363 +0000
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 
-# $Id: smbldap-usermod 26 2010-11-15 14:28:01Z mm1 $
+# $Id: smbldap-usermod 34 2011-02-23 08:10:50Z fumiyas $
 
 #  This code was developped by Jerome Tournier (jtournier@gmail.com) and
 #  contributors (their names can be found in the CONTRIBUTORS file).
@@ -32,7 +32,6 @@ use smbldap_tools;
 use Time::Local;
 #####################
 
-use Getopt::Std;
 use Getopt::Long;
 my %Options;
 my $nscd_status;
@@ -53,19 +52,19 @@ my $ok = GetOptions(
     "M|mail=s"               => \$Options{M},
     "N|givenName=s"          => \$Options{N},
     "O|mailLocalAddress=s"   => \$Options{O},
-    "P=s"                    => \$Options{P},
+    "P"                      => \$Options{P},
     "U|shadowUnlock"         => \$Options{U},
     "S|surname=s"            => \$Options{S},
     "T|mailToAddress=s"      => \$Options{T},
     "X|inputEncoding=s"      => \$Options{X},
-    "Z|attr=s"               => \$Options{Z},
+    "Z|attr=s@"              => \$Options{Z},
     "a|addsambaSAMAccount"   => \$Options{a},
     "c|gecos=s"              => \$Options{c},
     "d|homedir=s"            => \$Options{d},
     "e|expire=s"             => \$Options{e},
     "sambaExpire=s"          => \$Options{sambaExpire},
     "g|gid=s"                => \$Options{g},
-    "h|help"                 => \$Options{h},
+    "h|?|help"               => \$Options{h},
     "o|canBeNotUnique"       => \$Options{o},
     "r|rename=s"             => \$Options{r},
     "s|shell=s"              => \$Options{s},
@@ -77,8 +76,6 @@ my $ok = GetOptions(
     "u|uid=s"                => \$Options{u}
 );
 
-#my $ok = getopts('A:B:C:D:E:F:H:IJM:N:O:S:PT:X:Z:ame:f:u:g:G:d:l:r:s:c:ok:?h', \%Options);
-
 if ( ( !$ok ) || ( @ARGV < 1 ) || ( $Options{'h'} ) ) {
     print_banner;
     print "Usage: $0 [options] username\n\n";
@@ -632,12 +629,9 @@ if ( defined( $tmp = $Options{'A'} ) ) {
     }
 }
 
-my $_sambaPwdMustChange;
 if ( defined( $tmp = $Options{'B'} ) ) {
     if ( $samba == 1 ) {
         if ( $tmp != 0 ) {
-            $_sambaPwdMustChange = 0;
-
             # To force a user to change his password:
             # . the attribut sambaAcctFlags must not match the 'X' flag
             my $_sambaAcctFlags;
@@ -651,12 +645,13 @@ if ( defined( $tmp = $Options{'B'} ) ) {
                 $_sambaAcctFlags = "\[$letters\]";
                 push( @mods, 'sambaAcctFlags' => $_sambaAcctFlags );
             }
-            push( @mods, 'sambaPwdLastSet' => '0' );
+	    push(@mods, 'sambaPwdLastSet' => 0);
+	    push(@mods, 'sambaPwdMustChange' => 0);
         }
         else {
-            $_sambaPwdMustChange = $winmagic;
+	    push(@mods, 'sambaPwdLastSet' => time);
+	    push(@mods, 'sambaPwdMustChange' => $winmagic);
         }
-        push( @mods, 'sambaPwdMustChange' => $_sambaPwdMustChange );
     }
     else {
         print "User $user is not a samba user\n";
@@ -776,15 +771,31 @@ elsif ( !$samba == 1
 }
 
 if ( defined( $tmp = $Options{'Z'} ) ) {
-    my @namval = split /,/, $tmp;
-    if (@namval) {
-        foreach my $pair (@namval) {
-            my ( $name, $value ) = split /=/, $pair;
-            next if ( !$name or !$value );
-            push( @mods, $name => $value );
-        }
+    my %mods;
+    for my $pair ( map { split /,/ } @{$Options{'Z'}} ) {
+	my ( $name, $value ) = split( /[=:]/, $pair, 2 );
+	$name = lc( $name );
+	if ( defined($value) ) {
+	    if ( $name =~ s/^([\+\-])// ) {
+		my $action = $1;
+		my @value_old = $mods{$name}
+		    ? @{$mods{$name}}
+		    : $user_entry->get_value($name);
+		my @value = ($action eq '+')
+		    ? list_union( \@value_old, [$value] )
+		    : list_minus( \@value_old, [$value] );
+		$mods{$name} = \@value;
+	    } else {
+		push( @{$mods{$name}}, $value );
+	    }
+	} elsif ( $name =~ s/^-// ) {
+	    $mods{$name} = [];
+	}
     }
 
+    while ( my ($name, $value) = each( %mods ) ) {
+	push( @mods, $name => $value );
+    }
 }
 
 # apply changes