3
# This code was developped by Jerome Tournier (jtournier@gmail.com) and
4
# contributors (their names can be found in the CONTRIBUTORS file).
6
# This was first contributed by IDEALX (http://www.opentrust.com/)
8
# This program is free software; you can redistribute it and/or
9
# modify it under the terms of the GNU General Public License
10
# as published by the Free Software Foundation; either version 2
11
# of the License, or (at your option) any later version.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
18
# You should have received a copy of the GNU General Public License
19
# along with this program; if not, write to the Free Software
20
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
23
# Purpose of smbldap-usermod : user (posix,shadow,samba) modification
27
use FindBin qw($RealBin);
38
Getopt::Long::Configure('bundling');
40
"A|sambaPwdCanChange=s" => \$Options{A},
41
"B|sambaPwdMustChange=s" => \$Options{B},
42
"C|sambaHomePath=s" => \$Options{C},
43
"D|sambaHomeDrive=s" => \$Options{D},
44
"E|sambaLogonScript=s" => \$Options{E},
45
"F|sambaProfilePath=s" => \$Options{F},
46
"G|group=s" => \$Options{G},
47
"H|sambaAcctFlags=s" => \$Options{H},
48
"I|sambaDisable" => \$Options{I},
49
"J|sambaEnable" => \$Options{J},
50
"L|shadowLock" => \$Options{L},
51
"M|mailAddresses=s" => \$Options{M},
52
"N|givenName=s" => \$Options{N},
53
"P=s" => \$Options{P},
54
"U|shadowUnlock" => \$Options{U},
55
"S|surname=s" => \$Options{S},
56
"T|mailToAddress=s" => \$Options{T},
57
"Z|attr=s" => \$Options{Z},
58
"a|addsambaSAMAccount" => \$Options{a},
59
"c|gecos=s" => \$Options{c},
60
"d|homedir=s" => \$Options{d},
61
"e|expire=s" => \$Options{e},
62
"sambaExpire=s" => \$Options{sambaExpire},
63
"g|gid=s" => \$Options{g},
64
"h|help" => \$Options{h},
65
"o|canBeNotUnique" => \$Options{o},
66
"r|rename=s" => \$Options{r},
67
"s|shell=s" => \$Options{s},
68
"shadowExpire=s" => \$Options{shadowExpire},
69
"shadowMax=s" => \$Options{shadowMax},
70
"shadowMin=s" => \$Options{shadowMin},
71
"shadowInactive=s" => \$Options{shadowInactive},
72
"shadowWarning=s" => \$Options{shadowWarning},
73
"u|uid=s" => \$Options{u}
76
#my $ok = getopts('A:B:C:D:E:F:H:IJM:N:S:PT:ame:f:u:g:G:d:l:r:s:c:ok:?h', \%Options);
78
if ( ( !$ok ) || ( @ARGV < 1 ) || ( $Options{'h'} ) ) {
80
print "Usage: $0 [options] username\n\n";
82
print "Available UNIX options are:\n";
83
print " -c|--gecos <gecos> gecos\n";
84
print " -d|--homedir <dir> home directory\n";
85
print " -r|--rename <username> username\n";
86
print " -u|--uid <uidNumber> uid\n";
87
print " -o|--canBeNotUnique uid can be non unique\n";
88
print " -g|--gid <gidNumber gid\n";
90
" -G|--group [+-]<grp1,...> supplementary groups (comma separated)\n";
91
print " -s|--shell <shell> shell\n";
92
print " -N|--givenName <name> given name (first name)\n";
93
print " -S|--surname <suname> surname (family name)\n";
94
print " -P ends by invoking smbldap-passwd\n";
95
print " -M|--mailAddresses <mail,> mailAddresses (comma seperated)\n";
97
" -T|--mailToAddress <mail,> mailToAddress (forward address) (comma seperated)\n";
99
" -e|--expire <date> Sets both shadow and samba expiration date: like \"YYYY-MM-DD(HH:MM:SS)\", or \"yYmMdD\" to extand y year,m months and d days\n";
101
" --shadowExpire <date/n> Shadow expiration date (like \"YYYY-MM-DD\") or 'n' days from today\n";
103
" --shadowMax <n> User must change the password, at least, every 'n' days\n";
105
" --shadowMin <n> user must wait 'n' days once the password has changed before changing it again\n";
107
" --shadowInactive <n> number of days of inactivity allowed for the specified user\n";
109
" --shadowWarning <n> User is warned that the password must be changed four days before the password expires\n";
110
print " -L|--shadowLock lock unix user's password\n";
111
print " -U|--shadowUnlock unlock unix user's password\n";
113
" -Z add custom attributes, as name=value pairs comma separated\n";
115
print "Available SAMBA options are:\n";
116
print " -a|--addsambaSAMAccount add sambaSAMAccount objectclass\n";
118
" --sambaExpire <date> expire date (\"YYYY-MM-DD HH:MM:SS\")\n";
120
" -A|--sambaPwdCanChange can change password ? 0 if no, 1 if yes\n";
122
" -B|--sambaPwdMustChange must change password ? 0 if no, 1 if yes\n";
124
" -C|--sambaHomePath <dir> sambaHomePath (SMB home share, like '\\\\PDC-SRV\\homes')\n";
126
" -D|--sambaHomeDrive <drive> sambaHomeDrive (letter associated with home share, like 'H:')\n";
128
" -E|--sambaLogonScript <script> sambaLogonScript (DOS script to execute on login)\n";
130
" -F|--sambaProfilePath <path> sambaProfilePath (profile directory, like '\\\\PDC-SRV\\profiles\\foo')\n";
132
" -H|--sambaAcctFlags <flags> sambaAcctFlags (samba account control bits like '[NDHTUMWSLKI]')\n";
134
" -I|--sambaDisable disable an user. Can't be used with -H or -J\n";
136
" -J|--sambaEnable enable an user. Can't be used with -H or -I\n";
137
print " -h|--help show this help message\n";
142
print "You must be root to modify an user\n";
146
# Read only first @ARGV
149
# Let's connect to the directory first
150
my $ldap_master = connect_ldap_master();
153
my $user_entry = read_user_entry($user);
154
if ( !defined($user_entry) ) {
155
print "$0: user $user doesn't exist\n";
159
my $samba = is_samba_user($user);
161
# get the dn of the user
162
my $dn = $user_entry->dn();
167
if ( defined( $tmp = $Options{'a'} ) ) {
169
print "Error: Account for user $user already _is_ a Samba account!\n",
174
# Let's connect to the directory first
175
my $winmagic = 2147483647;
176
my $valpwdcanchange = 0;
177
my $valpwdmustchange = $winmagic;
178
my $valpwdlastset = 0;
179
my $valacctflags = "[UX]";
180
my $user_entry = read_user_entry($user);
181
my $uidNumber = $user_entry->get_value('uidNumber');
182
my $userRid = 2 * $uidNumber + 1000;
185
my $modify = $ldap_master->modify(
188
add => [ objectClass => 'sambaSAMAccount' ],
189
add => [ sambaPwdLastSet => "$valpwdlastset" ],
190
add => [ sambaLogonTime => '0' ],
191
add => [ sambaLogoffTime => '2147483647' ],
192
add => [ sambaKickoffTime => '2147483647' ],
193
add => [ sambaPwdCanChange => "$valpwdcanchange" ],
194
add => [ sambaPwdMustChange => "$valpwdmustchange" ],
195
add => [ sambaSID => "$config{SID}-$userRid" ],
196
add => [ sambaAcctFlags => "$valacctflags" ],
199
if ( $modify->code ) {
200
warn "failed to modify entry: ", $modify->error;
204
# when adding samba attributes, try to set samba primary group as well.
206
read_group_entry_gid( $user_entry->get_value('gidNumber') );
208
# override group if new group id sould be set with this call as well
209
$group_entry = read_group_entry_gid( $Options{'g'} ) if $Options{'g'};
210
my $userGroupSID = $group_entry->get_value('sambaSID');
212
my $modify_grpSID = $ldap_master->modify( "$dn",
213
changes => [ add => [ sambaPrimaryGroupSID => "$userGroupSID" ], ]
216
if ( $modify_grpSID->code ) {
217
warn "failed to modify entry: ", $modify_grpSID->error;
221
else { # no reason to abort imho
223
"Warning: sambaPrimaryGroupSID could not be set beacuse group of user $user is not a mapped Domain group!\n",
224
"To get a list of groups mapped to Domain groups, use \"net groupmap list\" on a Domain member machine.\n";
227
# now it is a samba account. this flag is needed here if someone uses i. e. "-a -g newgroupid".
228
# if not set here, the sambaPrimaryGroupSID value would not be updated
238
if ( defined( $tmp = $Options{'u'} ) ) {
239
if ( !defined( $Options{'o'} ) ) {
240
$nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1";
241
if ( $nscd_status == 0 ) {
242
system "/etc/init.d/nscd stop > /dev/null 2>&1";
245
if ( getpwuid($tmp) ) {
246
if ( $nscd_status == 0 ) {
247
system "/etc/init.d/nscd start > /dev/null 2>&1";
250
print "$0: uid number $tmp exists\n";
253
if ( $nscd_status == 0 ) {
254
system "/etc/init.d/nscd start > /dev/null 2>&1";
258
push( @mods, 'uidNumber', $tmp );
259
$_userUidNumber = $tmp;
262
# as rid we use 2 * uid + 1000
263
my $_userRid = 2 * $_userUidNumber + 1000;
264
if ( defined( $Options{'x'} ) ) {
265
$_userRid = sprint( "%x", $_userRid );
267
push( @mods, 'sambaSID', $config{SID} . '-' . $_userRid );
275
if ( defined( $tmp = $Options{'g'} ) ) {
276
$_userGidNumber = parse_group($tmp);
277
if ( $_userGidNumber < 0 ) {
278
print "$0: group $tmp doesn't exist\n";
281
push( @mods, 'gidNumber', $_userGidNumber );
284
# as grouprid we use the sambaSID attribute's value of the group
285
my $group_entry = read_group_entry_gid($_userGidNumber);
286
my $_userGroupSID = $group_entry->get_value('sambaSID');
287
unless ($_userGroupSID) {
289
"Error: sambaPrimaryGroupSid could not be set (sambaSID for group $_userGidNumber does not exist)\n";
292
push( @mods, 'sambaPrimaryGroupSid', $_userGroupSID );
297
if ( defined( $tmp = $Options{'s'} ) ) {
298
push( @mods, 'loginShell' => $tmp );
301
if ( defined( $tmp = $Options{'c'} ) ) {
305
'description' => $tmp
309
if ( defined( $tmp = $Options{'d'} ) ) {
310
push( @mods, 'homeDirectory' => $tmp );
313
# RFC 2256 & RFC 2798
314
# sn: family name (option S) # RFC 2256: family name of a person.
315
# givenName: prenom (option N) # RFC 2256: part of a person's name which is not their surname nor middle name.
316
# cn: person's full name # RFC 2256: person's full name.
317
# displayName: perferably displayed name # RFC 2798: preferred name of a person to be used when displaying entries.
319
#givenname is the forename of a person (not famiy name) => http://en.wikipedia.org/wiki/Given_name
320
#surname (or sn) is the familiy name => http://en.wikipedia.org/wiki/Surname
321
# my surname (or sn): Tournier
322
# my givenname: Jerome
324
if ( defined( $tmp = $Options{'N'} ) ) {
325
push( @mods, 'givenName' => utf8Encode($tmp) );
328
if ( defined( $tmp = $Options{'S'} ) ) {
329
push( @mods, 'sn' => utf8Encode($tmp) );
333
if ( $Options{'N'} or $Options{'S'} or $Options{'a'} ) {
334
$Options{'N'} = $user_entry->get_value('givenName') unless $Options{'N'};
335
$Options{'S'} = $user_entry->get_value('sn') unless $Options{'S'};
337
# if givenName eq sn eq username (default of smbldap-useradd), cn and displayName would
338
# be "username username". So we just append surname if its not default
339
# (there may be the very very special case of an user where those three values _are_ equal)
340
$cn = "$Options{'N'}";
341
$cn .= " " . $Options{'S'}
342
unless ( $Options{'S'} eq $Options{'N'} and $Options{'N'} eq $user );
343
my $push_val = utf8Encode($cn);
344
push( @mods, 'cn' => $push_val );
346
# set displayName for Samba account
348
push( @mods, 'displayName' => $push_val );
352
if ( defined $Options{'e'} ) {
353
if ( !defined $Options{'shadowExpire'} ) {
354
$Options{'shadowExpire'} = $Options{'e'};
356
if ( !defined $Options{'sambaExpire'} ) {
357
$Options{'sambaExpire'} = $Options{'e'};
361
sub parse_date_to_unix {
364
if ( $date =~ /(\d\d\d\d)-(\d?\d)-(\d?\d)(\s+(\d?\d):(\d\d):(\d\d))?/ ) {
366
if ( defined $5 and defined $6 and defined $7 ) {
367
$localtime = timelocal( $7, $6, $5, $3, $2 - 1, $1 );
370
$localtime = timelocal( 0, 0, 2, $3, $2 - 1, $1 );
372
my $shadowExpire = int($localtime);
373
$shadowExpire = sprintf( "%d", $shadowExpire );
374
return $shadowExpire;
379
if ( $date =~ /(\d+)y/ ) {
380
$daysAdd += 365.3 * $1;
383
if ( $date =~ /(\d+)m/ ) {
384
$daysAdd += 30.4 * $1;
387
if ( $date =~ /(\d+)([^ym]{1}|$)/ ) {
391
if ( $daysAdd > 0 ) {
392
return int( time + ( $daysAdd * 24 * 3600 ) );
402
sub parse_date_to_unix_days {
404
return int( parse_date_to_unix($arg) / 86400 );
407
# Shadow password parameters
408
my $localtime = time() / 86400;
409
if ( defined $Options{'shadowExpire'} ) {
411
# Unix expiration password
412
my $tmp = $Options{'shadowExpire'};
415
# my $expire=`date --date='$tmp' +%s`;
417
# my $shadowExpire=int($expire/86400)+1;
418
# date syntax asked: YYYY-MM-DD
420
$tmp = parse_date_to_unix_days($tmp);
422
push( @mods, 'shadowExpire', $tmp );
425
print "Invalid format for '--shadowExpire' option.\n";
429
if ( defined $Options{'shadowWarning'} ) {
430
push( @mods, 'shadowWarning', $Options{shadowWarning} );
433
if ( defined $Options{'shadowMax'} ) {
434
push( @mods, 'shadowMax', $Options{shadowMax} );
437
if ( defined $Options{'shadowMin'} ) {
438
push( @mods, 'shadowMin', $Options{shadowMin} );
441
if ( defined $Options{'shadowInactive'} ) {
442
push( @mods, 'shadowInactive', $Options{shadowInactive} );
445
if ( defined $Options{'L'} ) {
447
# lock shadow account
448
$tmp = $user_entry->get_value('userPassword');
449
if ( !( $tmp =~ /!/ ) ) {
452
push( @mods, 'userPassword' => $tmp );
455
if ( defined $Options{'U'} ) {
457
# unlock shadow account
458
$tmp = $user_entry->get_value('userPassword');
462
push( @mods, 'userPassword' => $tmp );
466
if ( $tmp = $Options{'M'} ) {
468
# action si + or - for adding or deleting an entry
470
if ( $tmp =~ s/^([+-])+\s*// ) {
473
my @userMailLocal = &split_arg_comma($tmp);
475
foreach my $m (@userMailLocal) {
476
my $domain = $config{mailDomain};
477
if ( $m =~ /^(.+)@/ ) {
480
# mailLocalAddress contains only the first part
484
push( @mail, $m . ( $domain ? '@' . $domain : '' ) );
490
@old_mail = $user_entry->get_value('mail');
491
@old_MailLocal = $user_entry->get_value('mailLocalAddress');
492
if ( $action eq '+' ) {
493
@userMailLocal = &list_union( \@old_MailLocal, \@userMailLocal );
494
@mail = &list_union( \@old_mail, \@mail );
496
elsif ( $action eq '-' ) {
497
@userMailLocal = &list_minus( \@old_MailLocal, \@userMailLocal );
498
@mail = &list_minus( \@old_mail, \@mail );
501
push( @mods, 'mailLocalAddress', [@userMailLocal] );
502
push( @mods, 'mail' => [@mail] );
506
if ( $tmp = $Options{'T'} ) {
510
# action si + or - for adding or deleting an entry
511
if ( $tmp =~ s/^([+-])+\s*// ) {
514
my @userMailTo = &split_arg_comma($tmp);
516
@old = $user_entry->get_value('mailRoutingAddress');
518
if ( $action eq '+' ) {
519
@userMailTo = &list_union( \@old, \@userMailTo );
521
elsif ( $action eq '-' ) {
522
@userMailTo = &list_minus( \@old, \@userMailTo );
524
push( @mods, 'mailRoutingAddress', [@userMailTo] );
528
my @objectclass = $user_entry->get_value('objectClass');
529
if ( !grep ( $_ =~ /^inetLocalMailRecipient$/i, @objectclass ) ) {
531
'objectClass' => [ @objectclass, 'inetLocalMailRecipient' ] );
535
if ( defined( $tmp = $Options{'G'} ) ) {
537
if ( $tmp =~ s/^([+-])+\s*// ) {
540
if ( $action eq '-' ) {
542
# remove user from specified groups
543
foreach my $gname ( &split_arg_comma($tmp) ) {
544
group_remove_member( $gname, $user );
548
if ( $action ne '+' ) {
549
my @old = &find_groups_of($user);
551
# remove user from old groups
552
foreach my $gname (@old) {
553
if ( $gname ne "" ) {
554
group_remove_member( $gname, $user );
559
# add user to new groups
560
add_grouplist_user( $tmp, $user );
565
# A : sambaPwdCanChange
566
# B : sambaPwdMustChange
569
# E : sambaLogonScript
570
# F : sambaProfilePath
574
my $winmagic = 2147483647;
576
$samba = is_samba_user($user);
578
if ( defined( $tmp = $Options{'sambaExpire'} ) ) {
580
my $kickoffTime = parse_date_to_unix($tmp);
581
if ( $kickoffTime != -1 ) {
582
push( @mods, 'sambakickoffTime' => $kickoffTime );
585
print "Invalid format for '--sambaExpire' option (" . $tmp . ").\n";
589
print "User $user is not a samba user\n";
593
my $_sambaPwdCanChange;
594
if ( defined( $tmp = $Options{'A'} ) ) {
596
$attr = "sambaPwdCanChange";
598
$_sambaPwdCanChange = 0;
601
$_sambaPwdCanChange = $winmagic;
603
push( @mods, 'sambaPwdCanChange' => $_sambaPwdCanChange );
606
print "User $user is not a samba user\n";
610
my $_sambaPwdMustChange;
611
if ( defined( $tmp = $Options{'B'} ) ) {
614
$_sambaPwdMustChange = 0;
616
# To force a user to change his password:
617
# . the attribut sambaAcctFlags must not match the 'X' flag
619
my $flags = $user_entry->get_value('sambaAcctFlags');
620
if ( defined $flags and $flags =~ /X/ ) {
622
if ( $flags =~ /(\w+)/ ) {
626
$_sambaAcctFlags = "\[$letters\]";
627
push( @mods, 'sambaAcctFlags' => $_sambaAcctFlags );
629
push( @mods, 'sambaPwdLastSet' => '0' );
632
$_sambaPwdMustChange = $winmagic;
634
push( @mods, 'sambaPwdMustChange' => $_sambaPwdMustChange );
637
print "User $user is not a samba user\n";
641
if ( defined( $tmp = $Options{'C'} ) ) {
643
if ( $tmp eq "" and defined $user_entry->get_value('sambaHomePath') ) {
644
push( @dels, 'sambaHomePath' => [] );
646
elsif ( $tmp ne "" ) {
647
push( @mods, 'sambaHomePath' => $tmp );
651
print "User $user is not a samba user\n";
655
if ( defined( $tmp = $Options{'D'} ) ) {
657
if ( $tmp eq "" and defined $user_entry->get_value('sambaHomeDrive') ) {
658
push( @dels, 'sambaHomeDrive' => [] );
660
elsif ( $tmp ne "" ) {
661
$tmp = $tmp . ":" unless ( $tmp =~ /:/ );
662
push( @mods, 'sambaHomeDrive' => $tmp );
666
print "User $user is not a samba user\n";
670
if ( defined( $tmp = $Options{'E'} ) ) {
672
if ( $tmp eq "" and defined $user_entry->get_value('sambaLogonScript') )
674
push( @dels, 'sambaLogonScript' => [] );
676
elsif ( $tmp ne "" ) {
677
push( @mods, 'sambaLogonScript' => $tmp );
681
print "User $user is not a samba user\n";
685
if ( defined( $tmp = $Options{'F'} ) ) {
687
if ( $tmp eq "" and defined $user_entry->get_value('sambaProfilePath') )
689
push( @dels, 'sambaProfilePath' => [] );
691
elsif ( $tmp ne "" ) {
692
push( @mods, 'sambaProfilePath' => $tmp );
696
print "User $user is not a samba user\n";
702
( defined $Options{'H'} or defined $Options{'I'} or defined $Options{'J'} )
706
if ( defined( $tmp = $Options{'H'} ) ) {
708
#$tmp =~ s/\\/\\\\/g;
709
$_sambaAcctFlags = $tmp;
715
$flags = $user_entry->get_value('sambaAcctFlags');
717
if ( defined( $tmp = $Options{'I'} ) ) {
718
if ( !( $flags =~ /D/ ) ) {
720
if ( $flags =~ /(\w+)/ ) {
723
$_sambaAcctFlags = "\[D$letters\]";
726
elsif ( defined( $tmp = $Options{'J'} ) ) {
727
if ( $flags =~ /D/ ) {
729
if ( $flags =~ /(\w+)/ ) {
733
$_sambaAcctFlags = "\[$letters\]";
738
if ( $_sambaAcctFlags and "$_sambaAcctFlags" ne '' ) {
739
push( @mods, 'sambaAcctFlags' => $_sambaAcctFlags );
741
push( @mods, 'sambaPwdLastSet' => $date );
747
( defined $Options{'H'} or defined $Options{'I'} or defined $Options{'J'} )
750
print "User $user is not a samba user\n";
753
if ( defined( $tmp = $Options{'Z'} ) ) {
754
my @namval = split /,/, $tmp;
756
foreach my $pair (@namval) {
757
my ( $name, $value ) = split /=/, $pair;
758
next if ( !$name or !$value );
759
push( @mods, $name => $value );
766
my $modify = $ldap_master->modify( "$dn", 'replace' => {@mods} );
767
$modify->code && warn "failed to modify entry: ", $modify->error;
769
# we can delete only if @dels is not empty: we check the number of elements
770
my $nb_to_del = scalar(@dels);
771
if ( $nb_to_del != 0 ) {
772
$modify = $ldap_master->modify( "$dn", 'delete' => {@dels} );
774
# don't proceed on error
775
$modify->code && die "failed to modify entry: ", $modify->error;
779
$ldap_master->unbind;
781
# asked to rename the account. only do that if new rdn doesn't equal old one
782
if ( defined( my $new_user = $Options{'r'} ) and $Options{'r'} ne $user ) {
783
my $ldap_master = connect_ldap_master();
786
# read eventual new user entry
787
my $new_user_entry = read_user_entry($new_user);
788
if ( defined($new_user_entry) ) {
789
print "$0: user $new_user already exists, cannot rename\n";
793
# we check the real dn as it could be a user or computer account
794
$dn = $user_entry->dn;
796
my ( $account, $rdn ) = ( $dn =~ m/([^,])*,(.*)$/ );
797
if ( $account =~ m/(.*)\$/ ) {
799
# it's a computer account
801
my $modify = $ldap_master->moddn(
803
newrdn => "uid=$new_user",
805
newsuperior => "$rdn"
810
my $modify = $ldap_master->moddn(
812
newrdn => "uid=$new_user",
814
newsuperior => "$rdn"
817
$modify->code && die "failed to change dn: ", $modify->error;
819
# change cn, sn, displayName, givenName attributes
820
my $user_entry = read_user_entry($new_user);
821
my $dn = $user_entry->dn();
824
# If old sn is not old username (which would be the default) we assume that there is a surename that is correctly set
825
# so no change is required here. If they equal, we use the new username for new sn unless
826
# -S option is used (the sn value would have been set/updated before in that case).
827
push( @mods, 'sn' => $new_user )
828
unless ( $user_entry->get_value('sn')
829
and $user_entry->get_value('sn') ne $user or $Options{'S'} );
831
# If old givenName is not old username (which would be the default) we assume that there is a
832
# givenName correctly set so no change is required here. If they equal, we set givenName to the new username unless
833
# the -N option is used (the givenName would have been set/updated before in that case).
834
push( @mods, 'givenName' => $new_user )
835
unless ( $user_entry->get_value('givenName')
836
and $user_entry->get_value('givenName') ne $new_user or $Options{'N'} );
838
# common name, should be "fistname lastname". Same for displayName but only if $samba.
839
# Uses utf8Encode like processing of options -S and -N above. If old cn is old username
840
# (which would be the default) this field should be updated, unless -N _and_ -S is given.
841
# Then assume it has been set correctly with -N and -S before.
842
push( @mods, "cn" => $new_user )
843
unless ( $user_entry->get_value("cn")
844
and $user_entry->get_value("cn") ne utf8Encode($user)
845
or $Options{'N'} and $Options{'S'} );
846
push( @mods, "displayName" => $new_user )
848
or $user_entry->get_value("displayName")
849
and $user_entry->get_value("displayName") ne utf8Encode($user)
850
or $Options{'N'} and $Options{'S'} );
852
if ( @mods > 0 ) { # only change if there is something to change
854
$ldap_master->modify( "$dn", changes => [ 'replace' => [@mods] ] );
855
$modify->code && warn "failed to rename the user: ", $modify->error;
858
# changing username in groups
859
my @groups = &find_groups_of($user);
860
foreach my $gname (@groups) {
861
if ( $gname ne "" ) {
862
my $dn_line = get_group_dn($gname);
863
my $dn = get_dn_from_line("$dn_line");
864
print "updating group $gname\n";
865
$modify = $ldap_master->modify(
868
'delete' => [ memberUid => $user ],
869
'add' => [ memberUid => $new_user ]
873
&& warn "failed to update user's supplementary group $gname: ",
878
$ldap_master->unbind;
881
$nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1";
883
if ( $nscd_status == 0 ) {
884
system "/etc/init.d/nscd restart > /dev/null 2>&1";
887
if ( defined( $Options{'P'} ) ) {
888
exec "$RealBin/smbldap-passwd $user";
891
############################################################
895
smbldap-usermod - Modify a user account
899
smbldap-usermod [-c gecos] [-d home_dir] [-r login_name] [-u uid] [-g gid] [-o] [-G group[,...]] [-s shell] [-N first_name] [-S surname] [-P] [-M mail[,...]] [-T mail,[..]] [--shadowExpire date/n] [--shadowMax n] [--shadowMin n] [--shadowInactive n] [--shadowWarning n] [-L] [-U] [-a] [-e expiration_date/n] [--sambaExpire date/n] [-A canchange] [-B mustchange] [-C smbhome] [-D homedrive] [-E scriptpath] [-F profilepath] [-H acctflags] [-I] [-J] [-h] login
903
The smbldap-usermod command modifies the system account files to reflect the changes that are specified
909
The new value of the user's comment field (gecos). (Don't use this to modify displayName or cn. Use -N and -S options combined instead).
911
-d, --homedir home_dir
912
The user's new login directory.
914
-r, --rename new_user
915
Allow to rename a user. This option will update the dn attribute for the user. You can also update others attributes using the corresponding script options.
918
The numerical value of the user's ID. This value must be unique, unless the -o option is used. The value must be non negative. Any files which the user owns and which are located in the directory tree rooted at the user's home directory will have the file user ID changed automatically. Files outside of the user's home directory must be altered manually.
921
uidNumber can be non unique
923
-g, --gid initial_group
924
The group name or number of the user's new initial login group. The group name must exist. A group number must refer to an already existing group. The default group number is 1.
926
-G, --group [+-]group,[...]
927
A list of supplementary groups which the user is also a member of. Each group is separated from the next by a comma, with no intervening whitespace. The groups are subject to the same restrictions as the group given with the -g option. If the user is currently a member of a group which is not listed, the user will be removed from the group, unless the '+' or '-' caracter is used to add or remove groups to inital ones.
930
The name of the user's new login shell. Setting this field to blank causes the system to select the default
934
set the user's given name (attribute givenName). Additionally used to set the first name in displayName and cn.
937
Set the user's surname (attribute sn). Additionally used to set the last name in displayName and cn.
940
End by invoking smbldap-passwd to change the user password (both unix and samba passwords)
942
-M, --mailAddresses mail,[...]
943
mailAddresses (comma seperated)
945
-T, --mailToAddress mail,[...]
946
mailToAddress (forward address) (comma seperated)
948
--shadowExpire <YYYY-MM-DD/n>
949
Set the expiration date for the user password. This only affect unix account. The date may be specified as either YYYY-MM-DD or 'n' days from day. The 'n' syntax also supports the extended format (#y)(#m)(#d) for years, months, and days from today. One need not specify all three, so all of the following are examples of valid input: '5y4m2d' (5 years, 4 months, and 2 days), '5y' (5 years), '5y2d' (5 years and 2 days), and '3' (3 days). This option calls the internal 'timelocal' command to set calculate the number of seconds from Junary 1 1970 to the specified date.
952
User must change the password, at least, every 'n' days
955
User must wait 'n' days once the password has changed before changing it again
958
Number of days of inactivity allowed for the specified user
961
User is warned that the password must be changed four days before the password expires
964
Lock unix user's password. This puts a '!' in front of the encrypted password, effectively disabling the password.
967
Unlock unix user's password. This removes the '!' in front of the encrypted password.
971
-a, --addsambaSAMAccount
972
Add the sambaSAMAccount objectclass to the specified user account. This allow the user to become a samba user.
974
-e, --expire <YYYY-MM-DD(HH:MM:SS)/n>
975
Sets the expiration for both samba (--sambaExpire) and shadow (--shadowExpire).
977
--sambaExpire <YYYY-MM-DD HH:MM:SS/n>
978
Set the expiration date for the user account. This only affects the samba account. The date must be in the following format: YYYY-MM-DD HH:MM:SS. The n-days format of shadowExpire is also supported. This option uses the internal 'timelocal' command to set calculate the number of seconds from Junary 1 1970 to the specified date.
981
Creates rid and primaryGroupID in hex instead of decimal (for Samba 2.2.2 unpatched only - higher versions always use decimal)
983
-A, --sambaPwdCanChange
984
can change password ? 0 if no, 1 if yes
986
-B, --sambaPwdMustChange
987
must change password ? 0 if no, 1 if yes
989
-C, --sambaHomePath path
990
sambaHomePath (SMB home share, like '\\\\PDC-SRV\\homes')
992
-D, --sambaHomeDrive drive
993
sambaHomeDrive (letter associated with home share, like 'H:')
995
-E, --sambaLogonScript script
996
sambaLogonScript, relative to the [netlogon] share (DOS script to execute on login, like 'foo.bat')
998
-F, --sambaProfilePath path
999
sambaProfilePath (profile directory, like '\\\\PDC-SRV\\profiles\\foo')
1001
-H, --sambaAcctFlags flags
1002
sambaAcctFlags, spaces and trailing bracket are ignored (samba account control bits like '[NDHTUMWSLKI]')
1005
disable user. Can't be used with -H or -J
1008
enable user. Can't be used with -H or -I