1#!/usr/bin/perl -w 2use strict; 3package smbldap_tools; 4use Net::LDAP; 5use Crypt::SmbHash; 6 7# $Id: smbldap_tools.pm,v 1.54 2005/01/29 15:00:54 jtournier Exp $ 8# 9# This code was developped by IDEALX (http://IDEALX.org/) and 10# contributors (their names can be found in the CONTRIBUTORS file). 11# 12# Copyright (C) 2001-2002 IDEALX 13# 14# This program is free software; you can redistribute it and/or 15# modify it under the terms of the GNU General Public License 16# as published by the Free Software Foundation; either version 2 17# of the License, or (at your option) any later version. 18# 19# This program is distributed in the hope that it will be useful, 20# but WITHOUT ANY WARRANTY; without even the implied warranty of 21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22# GNU General Public License for more details. 23# 24# You should have received a copy of the GNU General Public License 25# along with this program; if not, write to the Free Software 26# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 27# USA. 28 29 30# ugly funcs using global variables and spawning openldap clients 31 32my $smbldap_conf="/etc/opt/IDEALX/smbldap-tools/smbldap.conf"; 33my $smbldap_bind_conf="/etc/opt/IDEALX/smbldap-tools/smbldap_bind.conf"; 34use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 35use Exporter; 36$VERSION = 1.00; 37 38@ISA = qw(Exporter); 39use vars qw(%config $ldap); 40 41@EXPORT = qw( 42 get_user_dn 43 get_group_dn 44 is_group_member 45 is_samba_user 46 is_unix_user 47 is_user_valid 48 does_sid_exist 49 get_dn_from_line 50 add_posix_machine 51 add_samba_machine 52 add_samba_machine_smbpasswd 53 group_add_user 54 add_grouplist_user 55 disable_user 56 delete_user 57 group_add 58 group_del 59 get_homedir 60 read_user 61 read_user_entry 62 read_group 63 read_group_entry 64 read_group_entry_gid 65 find_groups_of 66 parse_group 67 group_remove_member 68 group_get_members 69 do_ldapadd 70 do_ldapmodify 71 get_user_dn2 72 connect_ldap_master 73 connect_ldap_slave 74 group_type_by_name 75 subst_configvar 76 read_config 77 read_parameter 78 subst_user 79 split_arg_comma 80 list_union 81 list_minus 82 get_next_id 83 print_banner 84 %config 85 ); 86 87sub print_banner 88 { 89 print STDERR "(c) IDEALX 2004 (http://www.idealx.com)- Licenced under GPL\n"; 90 } 91 92sub read_parameter 93 { 94 my $line=shift; 95 ## check for a param = value 96 if ($_=~/=/) { 97 my ($param,$val); 98 if ($_=~/"/) { 99 #my ($param,$val) = ($_=~/(.*)\s*=\s*"(.*)"/); 100 ($param,$val) = /\s*(.*?)\s*=\s*"(.*)"/; 101 } elsif ($_=~/'/) { 102 ($param,$val) = /\s*(.*?)\s*=\s*'(.*)'/; 103 } else { 104 ($param,$val) = /\s*(.*?)\s*=\s*(.*)/; 105 } 106 return ($param,$val); 107 } 108 } 109 110sub subst_configvar 111 { 112 my $value = shift; 113 my $vars = shift; 114 115 $value =~ s/\$\{([^}]+)\}/$vars->{$1} ? $vars->{$1} : $1/eg; 116 return $value; 117 } 118 119sub read_conf 120 { 121 my %conf; 122 open (CONFIGFILE, "$smbldap_conf") || die "Unable to open $smbldap_conf for reading !\n"; 123 while (<CONFIGFILE>) { 124 chomp($_); 125 ## throw away comments 126 next if ( /^\s*#/ || /^\s*$/ || /^\s*\;/); 127 ## check for a param = value 128 my ($parameter,$value)=read_parameter($_); 129 $value = &subst_configvar($value, \%conf); 130 $conf{$parameter}=$value; 131 } 132 close (CONFIGFILE); 133 134 if ($< == 0) { 135 open (CONFIGFILE, "$smbldap_bind_conf") || die "Unable to open $smbldap_bind_conf for reading !\n"; 136 while (<CONFIGFILE>) { 137 chomp($_); 138 ## throw away comments 139 next if ( /^\s*#/ || /^\s*$/ || /^\s*\;/); 140 ## check for a param = value 141 my ($parameter,$value)=read_parameter($_); 142 $value = &subst_configvar($value, \%conf); 143 $conf{$parameter}=$value; 144 } 145 close (CONFIGFILE); 146 } else { 147 $conf{slaveDN}=$conf{slavePw}=$conf{masterDN}=$conf{masterPw}=""; 148 } 149 150 return(%conf); 151 } 152 153# let's read the configurations file... 154%config=read_conf(); 155 156 157sub connect_ldap_master 158 { 159 # bind to a directory with dn and password 160 my $ldap_master = Net::LDAP->new( 161 "$config{masterLDAP}", 162 port => "$config{masterPort}", 163 version => 3, 164 timeout => 60, 165 # debug => 0xffff, 166 ) 167 or die "erreur LDAP: Can't contact master ldap server ($@)"; 168 if ($config{ldapTLS} == 1) { 169 $ldap_master->start_tls( 170 verify => "$config{verify}", 171 clientcert => "$config{clientcert}", 172 clientkey => "$config{clientkey}", 173 cafile => "$config{cafile}" 174 ); 175 } 176 $ldap_master->bind ( "$config{masterDN}", 177 password => "$config{masterPw}" 178 ); 179 $ldap=$ldap_master; 180 return($ldap_master); 181 } 182 183sub connect_ldap_slave 184 { 185 # bind to a directory with dn and password 186 my $conf_cert; 187 my $ldap_slave = Net::LDAP->new( 188 "$config{slaveLDAP}", 189 port => "$config{slavePort}", 190 version => 3, 191 timeout => 60, 192 # debug => 0xffff, 193 ) 194 or warn "erreur LDAP: Can't contact slave ldap server ($@)\n=>trying to contact the master server\n"; 195 if (!$ldap_slave) { 196 # connection to the slave failed: trying to contact the master ... 197 $ldap_slave = Net::LDAP->new( 198 "$config{masterLDAP}", 199 port => "$config{masterPort}", 200 version => 3, 201 timeout => 60, 202 # debug => 0xffff, 203 ) 204 or die "erreur LDAP: Can't contact master ldap server ($@)\n"; 205 } 206 if ($ldap_slave) { 207 if ($config{ldapTLS} == 1) { 208 $ldap_slave->start_tls( 209 verify => "$config{verify}", 210 clientcert => "$config{clientcert}", 211 clientkey => "$config{clientkey}", 212 cafile => "$config{cafile}" 213 ); 214 } 215 $ldap_slave->bind ( "$config{masterDN}", 216 password => "$config{masterPw}" 217 ); 218 $ldap=$ldap_slave; 219 return($ldap_slave); 220 } 221 } 222 223sub get_user_dn 224 { 225 my $user = shift; 226 my $dn=''; 227 my $mesg = $ldap->search ( base => $config{suffix}, 228 scope => $config{scope}, 229 filter => "(&(objectclass=posixAccount)(uid=$user))" 230 ); 231 $mesg->code && die $mesg->error; 232 foreach my $entry ($mesg->all_entries) { 233 $dn= $entry->dn; 234 } 235 chomp($dn); 236 if ($dn eq '') { 237 return undef; 238 } 239 $dn="dn: ".$dn; 240 return $dn; 241 } 242 243 244sub get_user_dn2 245 { 246 my $user = shift; 247 my $dn=''; 248 my $mesg = $ldap->search ( base => $config{suffix}, 249 scope => $config{scope}, 250 filter => "(&(objectclass=posixAccount)(uid=$user))" 251 ); 252 $mesg->code && warn "failed to perform search; ", $mesg->error; 253 254 foreach my $entry ($mesg->all_entries) { 255 $dn= $entry->dn; 256 } 257 chomp($dn); 258 if ($dn eq '') { 259 return (1,undef); 260 } 261 $dn="dn: ".$dn; 262 return (1,$dn); 263 } 264 265 266sub get_group_dn 267 { 268 my $group = shift; 269 my $dn=''; 270 my $filter; 271 if ($group =~ /^\d+$/) { 272 $filter="(&(objectclass=posixGroup)(|(cn=$group)(gidNumber=$group)))"; 273 } else { 274 $filter="(&(objectclass=posixGroup)(cn=$group))"; 275 } 276 my $mesg = $ldap->search ( base => $config{groupsdn}, 277 scope => $config{scope}, 278 filter => $filter 279 ); 280 $mesg->code && die $mesg->error; 281 foreach my $entry ($mesg->all_entries) { 282 $dn= $entry->dn; 283 } 284 chomp($dn); 285 if ($dn eq '') { 286 return undef; 287 } 288 $dn="dn: ".$dn; 289 return $dn; 290 } 291 292# return (success, dn) 293# bool = is_samba_user($username) 294sub is_samba_user 295 { 296 my $user = shift; 297 my $mesg = $ldap->search ( base => $config{suffix}, 298 scope => $config{scope}, 299 filter => "(&(objectClass=sambaSamAccount)(uid=$user))" 300 ); 301 $mesg->code && die $mesg->error; 302 return ($mesg->count ne 0); 303 } 304 305sub is_unix_user 306 { 307 my $user = shift; 308 my $mesg = $ldap->search ( base => $config{suffix}, 309 scope => $config{scope}, 310 filter => "(&(objectClass=posixAccount)(uid=$user))" 311 ); 312 $mesg->code && die $mesg->error; 313 return ($mesg->count ne 0); 314 } 315 316sub is_group_member 317 { 318 my $dn_group = shift; 319 my $user = shift; 320 my $mesg = $ldap->search ( base => $dn_group, 321 scope => 'base', 322 filter => "(&(memberUid=$user))" 323 ); 324 $mesg->code && die $mesg->error; 325 return ($mesg->count ne 0); 326 } 327 328# all entries = does_sid_exist($sid,$config{scope}) 329sub does_sid_exist 330 { 331 my $sid = shift; 332 my $dn_group=shift; 333 my $mesg = $ldap->search ( base => $dn_group, 334 scope => $config{scope}, 335 filter => "(sambaSID=$sid)" 336 #filter => "(&(objectClass=sambaSAMAccount|objectClass=sambaGroupMapping)(sambaSID=$sid))" 337 ); 338 $mesg->code && die $mesg->error; 339 return ($mesg); 340 } 341 342# try to bind with user dn and password to validate current password 343sub is_user_valid 344 { 345 my ($user, $dn, $pass) = @_; 346 my $userLdap = Net::LDAP->new($config{slaveLDAP}) or die "erreur LDAP"; 347 my $mesg= $userLdap->bind (dn => $dn, password => $pass ); 348 if ($mesg->code eq 0) { 349 $userLdap->unbind; 350 return 1; 351 } else { 352 if ($userLdap->bind()) { 353 $userLdap->unbind; 354 return 0; 355 } else { 356 print ("The LDAP directory is not available.\n Check the server, cables ..."); 357 $userLdap->unbind; 358 return 0; 359 } 360 die "Problem : contact your administrator"; 361 } 362 } 363 364 365# dn = get_dn_from_line ($dn_line) 366# helper to get "a=b,c=d" from "dn: a=b,c=d" 367sub get_dn_from_line 368 { 369 my $dn = shift; 370 $dn =~ s/^dn: //; 371 return $dn; 372 } 373 374 375# success = add_posix_machine($user, $uid, $gid) 376sub add_posix_machine 377 { 378 my ($user, $uid, $gid) = @_; 379 # bind to a directory with dn and password 380 my $add = $ldap->add ( "uid=$user,$config{computersdn}", 381 attr => [ 382 'objectclass' => ['top','inetOrgPerson', 'posixAccount'], 383 'cn' => "$user", 384 'sn' => "$user", 385 'uid' => "$user", 386 'uidNumber' => "$uid", 387 'gidNumber' => "$gid", 388 'homeDirectory' => '/dev/null', 389 'loginShell' => '/bin/false', 390 'description' => 'Computer', 391 'gecos' => 'Computer', 392 ] 393 ); 394 395 $add->code && warn "failed to add entry: ", $add->error ; 396 # take down the session 397 return 1; 398 } 399 400 401# success = add_samba_machine_smbpasswd($computername) 402sub add_samba_machine_smbpasswd 403 { 404 my $user = shift; 405 system "smbpasswd -a -m $user"; 406 return 1; 407 } 408 409sub add_samba_machine 410 { 411 my ($user, $uid) = @_; 412 my $sambaSID = 2 * $uid + 1000; 413 my $name = $user; 414 $name =~ s/.$//s; 415 416 my ($lmpassword,$ntpassword) = ntlmgen $name; 417 my $modify = $ldap->modify ( "uid=$user,$config{computersdn}", 418 changes => [ 419 replace => [objectClass => ['inetOrgPerson', 'posixAccount', 'sambaSAMAccount']], 420 add => [sambaPwdLastSet => '0'], 421 add => [sambaLogonTime => '0'], 422 add => [sambaLogoffTime => '2147483647'], 423 add => [sambaKickoffTime => '2147483647'], 424 add => [sambaPwdCanChange => '0'], 425 add => [sambaPwdMustChange => '0'], 426 add => [sambaAcctFlags => '[W ]'], 427 add => [sambaLMPassword => "$lmpassword"], 428 add => [sambaNTPassword => "$ntpassword"], 429 add => [sambaSID => "$config{SID}-$sambaSID"], 430 add => [sambaPrimaryGroupSID => "$config{SID}-0"] 431 ] 432 ); 433 434 $modify->code && die "failed to add entry: ", $modify->error ; 435 436 return 1; 437 } 438 439sub group_add_user 440 { 441 my ($group, $userid) = @_; 442 my $members=''; 443 my $dn_line = get_group_dn($group); 444 if (!defined(get_group_dn($group))) { 445 print "$0: group \"$group\" doesn't exist\n"; 446 exit (6); 447 } 448 if (!defined($dn_line)) { 449 return 1; 450 } 451 my $dn = get_dn_from_line("$dn_line"); 452 # on look if the user is already present in the group 453 my $is_member=is_group_member($dn,$userid); 454 if ($is_member == 1) { 455 print "User \"$userid\" already member of the group \"$group\".\n"; 456 } else { 457 # bind to a directory with dn and password 458 # It does not matter if the user already exist, Net::LDAP will add the user 459 # if he does not exist, and ignore him if his already in the directory. 460 my $modify = $ldap->modify ( "$dn", 461 changes => [ 462 add => [memberUid => $userid] 463 ] 464 ); 465 $modify->code && die "failed to modify entry: ", $modify->error ; 466 } 467 } 468 469sub group_del 470 { 471 my $group_dn=shift; 472 # bind to a directory with dn and password 473 my $modify = $ldap->delete ($group_dn); 474 $modify->code && die "failed to delete group : ", $modify->error ; 475 } 476 477sub add_grouplist_user 478 { 479 my ($grouplist, $user) = @_; 480 my @array = split(/,/, $grouplist); 481 foreach my $group (@array) { 482 group_add_user($group, $user); 483 } 484 } 485 486sub disable_user 487 { 488 my $user = shift; 489 my $dn_line; 490 my $dn = get_dn_from_line($dn_line); 491 492 if (!defined($dn_line = get_user_dn($user))) { 493 print "$0: user $user doesn't exist\n"; 494 exit (10); 495 } 496 my $modify = $ldap->modify ( "$dn", 497 changes => [ 498 replace => [userPassword => '{crypt}!x'] 499 ] 500 ); 501 $modify->code && die "failed to modify entry: ", $modify->error ; 502 503 if (is_samba_user($user)) { 504 my $modify = $ldap->modify ( "$dn", 505 changes => [ 506 replace => [sambaAcctFlags => '[D ]'] 507 ] 508 ); 509 $modify->code && die "failed to modify entry: ", $modify->error ; 510 } 511 } 512 513# delete_user($user) 514sub delete_user 515 { 516 my $user = shift; 517 my $dn_line; 518 519 if (!defined($dn_line = get_user_dn($user))) { 520 print "$0: user $user doesn't exist\n"; 521 exit (10); 522 } 523 524 my $dn = get_dn_from_line($dn_line); 525 my $modify = $ldap->delete($dn); 526 } 527 528# $gid = group_add($groupname, $group_gid, $force_using_existing_gid) 529sub group_add 530 { 531 my ($gname, $gid, $force) = @_; 532 my $nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1"; 533 if ($nscd_status == 0) { 534 system "/etc/init.d/nscd stop > /dev/null 2>&1"; 535 } 536 if (!defined($gid)) { 537 #while (defined(getgrgid($config{GID_START}))) { 538 # $config{GID_START}++; 539 #} 540 #$gid = $config{GID_START}; 541 $gid=get_next_id($config{groupsdn},"gidNumber"); 542 } else { 543 if (!defined($force)) { 544 if (defined(getgrgid($gid))) { 545 return undef; 546 } 547 } 548 } 549 if ($nscd_status == 0) { 550 system "/etc/init.d/nscd start > /dev/null 2>&1"; 551 } 552 my $modify = $ldap->add ( "cn=$gname,$config{groupsdn}", 553 attrs => [ 554 objectClass => 'posixGroup', 555 cn => "$gname", 556 gidNumber => "$gid" 557 ] 558 ); 559 560 $modify->code && die "failed to add entry: ", $modify->error ; 561 return $gid; 562 } 563 564# $homedir = get_homedir ($user) 565sub get_homedir 566 { 567 my $user = shift; 568 my $homeDir=''; 569 my $entry; 570 my $mesg = $ldap->search ( 571 base =>$config{usersdn}, 572 scope => $config{scope}, 573 filter => "(&(objectclass=posixAccount)(uid=$user))" 574 ); 575 $mesg->code && die $mesg->error; 576 577 my $nb=$mesg->count; 578 if ($nb > 1) { 579 print "Aborting: there are $nb existing user named $user\n"; 580 foreach $entry ($mesg->all_entries) { 581 my $dn=$entry->dn; 582 print " $dn\n"; 583 } 584 exit (4); 585 } else { 586 $entry = $mesg->shift_entry(); 587 $homeDir= $entry->get_value("homeDirectory"); 588 } 589 590 chomp $homeDir; 591 if ($homeDir eq '') { 592 return undef; 593 } 594 return $homeDir; 595 } 596 597# search for an user 598sub read_user 599 { 600 my $user = shift; 601 my $lines =''; 602 my $mesg = $ldap->search ( # perform a search 603 base => $config{suffix}, 604 scope => $config{scope}, 605 filter => "(&(objectclass=posixAccount)(uid=$user))" 606 ); 607 608 $mesg->code && die $mesg->error; 609 foreach my $entry ($mesg->all_entries) { 610 $lines.= "dn: " . $entry->dn."\n"; 611 foreach my $attr ($entry->attributes) { 612 { 613 $lines.= $attr.": ".join(',', $entry->get_value($attr))."\n"; 614 } 615 } 616 } 617 chomp $lines; 618 if ($lines eq '') { 619 return undef; 620 } 621 return $lines; 622 } 623 624# search for a user 625# return the attributes in an array 626sub read_user_entry 627 { 628 my $user = shift; 629 my $mesg = $ldap->search ( # perform a search 630 base => $config{suffix}, 631 scope => $config{scope}, 632 filter => "(&(objectclass=posixAccount)(uid=$user))" 633 ); 634 635 $mesg->code && die $mesg->error; 636 my $entry = $mesg->entry(); 637 return $entry; 638 } 639 640# search for a group 641sub read_group 642 { 643 my $user = shift; 644 my $lines =''; 645 my $mesg = $ldap->search ( # perform a search 646 base => $config{groupsdn}, 647 scope => $config{scope}, 648 filter => "(&(objectclass=posixGroup)(cn=$user))" 649 ); 650 651 $mesg->code && die $mesg->error; 652 foreach my $entry ($mesg->all_entries) { 653 $lines.= "dn: " . $entry->dn."\n"; 654 foreach my $attr ($entry->attributes) { 655 { 656 $lines.= $attr.": ".join(',', $entry->get_value($attr))."\n"; 657 } 658 } 659 } 660 chomp $lines; 661 if ($lines eq '') { 662 return undef; 663 } 664 return $lines; 665 } 666 667# find groups of a given user 668##### MODIFIE ######## 669sub find_groups_of { 670 my $user = shift; 671 my @groups = (); 672 my $mesg = $ldap->search ( # perform a search 673 base => $config{groupsdn}, 674 scope => $config{scope}, 675 filter => "(&(objectclass=posixGroup)(memberuid=$user))" 676 ); 677 $mesg->code && die $mesg->error; 678 679 my $entry; 680 while ($entry = $mesg->shift_entry()) { 681 push(@groups, scalar($entry->get_value('cn'))); 682 } 683 return (@groups); 684} 685 686sub read_group_entry { 687 my $group = shift; 688 my $entry; 689 my %res; 690 my $mesg = $ldap->search ( # perform a search 691 base => $config{groupsdn}, 692 scope => $config{scope}, 693 filter => "(&(objectclass=posixGroup)(cn=$group))" 694 ); 695 696 $mesg->code && die $mesg->error; 697 my $nb=$mesg->count; 698 if ($nb > 1) { 699 print "Error: $nb groups exist \"cn=$group\"\n"; 700 foreach $entry ($mesg->all_entries) { 701 my $dn=$entry->dn; print " $dn\n"; 702 } 703 exit 11; 704 } else { 705 $entry = $mesg->shift_entry(); 706 } 707 return $entry; 708} 709 710sub read_group_entry_gid { 711 my $group = shift; 712 my %res; 713 my $mesg = $ldap->search ( # perform a search 714 base => $config{groupsdn}, 715 scope => $config{scope}, 716 filter => "(&(objectclass=posixGroup)(gidNumber=$group))" 717 ); 718 719 $mesg->code && die $mesg->error; 720 my $entry = $mesg->shift_entry(); 721 return $entry; 722} 723 724# return the gidnumber for a group given as name or gid 725# -1 : bad group name 726# -2 : bad gidnumber 727sub parse_group 728 { 729 my $userGidNumber = shift; 730 if ($userGidNumber =~ /[^\d]/ ) { 731 my $gname = $userGidNumber; 732 my $gidnum = getgrnam($gname); 733 if ($gidnum !~ /\d+/) { 734 return -1; 735 } else { 736 $userGidNumber = $gidnum; 737 } 738 } elsif (!defined(getgrgid($userGidNumber))) { 739 return -2; 740 } 741 return $userGidNumber; 742 } 743 744# remove $user from $group 745sub group_remove_member 746 { 747 my ($group, $user) = @_; 748 my $members=''; 749 my $grp_line = get_group_dn($group); 750 if (!defined($grp_line)) { 751 return 0; 752 } 753 my $dn = get_dn_from_line($grp_line); 754 # we test if the user exist in the group 755 my $is_member=is_group_member($dn,$user); 756 if ($is_member == 1) { 757 # delete only the user from the group 758 my $modify = $ldap->modify ( "$dn", 759 changes => [ 760 delete => [memberUid => ["$user"]] 761 ] 762 ); 763 $modify->code && die "failed to delete entry: ", $modify->error ; 764 } 765 return 1; 766 } 767 768sub group_get_members 769 { 770 my ($group) = @_; 771 my $members; 772 my @resultat; 773 my $grp_line = get_group_dn($group); 774 if (!defined($grp_line)) { 775 return 0; 776 } 777 my $mesg = $ldap->search ( 778 base => $config{groupsdn}, 779 scope => $config{scope}, 780 filter => "(&(objectclass=posixgroup)(cn=$group))" 781 ); 782 $mesg->code && die $mesg->error; 783 foreach my $entry ($mesg->all_entries) { 784 foreach my $attr ($entry->attributes) { 785 if ($attr=~/\bmemberUid\b/) { 786 foreach my $ent ($entry->get_value($attr)) { 787 push (@resultat,$ent); 788 } 789 } 790 } 791 } 792 return @resultat; 793 } 794 795sub do_ldapmodify 796 { 797 my $ldif = shift; 798 my $FILE = "|$config{ldapmodify} -r >/dev/null"; 799 open (FILE, $FILE) || die "$!\n"; 800 print FILE <<EOF; 801$ldif 802EOF 803 ; 804 close FILE; 805 my $rc = $?; 806 return $rc; 807 } 808 809sub group_type_by_name { 810 my $type_name = shift; 811 my %groupmap = ( 812 'domain' => 2, 813 'local' => 4, 814 'builtin' => 5 815 ); 816 return $groupmap{$type_name}; 817} 818 819sub subst_user 820 { 821 my ($str, $username) = @_; 822 $str =~ s/%U/$username/ if ($str); 823 return($str); 824 } 825 826# all given mails are stored in a table (remove the comma separated) 827sub split_arg_comma { 828 my $arg = shift; 829 my @args; 830 if (defined($arg)) { 831 if ($arg eq '-') { 832 @args = ( ); 833 } else { 834 @args = split(/\s*,\s*/, $arg); 835 } 836 } 837 return (@args); 838} 839 840sub list_union { 841 my ($list1, $list2) = @_; 842 my @res = @$list1; 843 foreach my $e (@$list2) { 844 if (! grep($_ eq $e, @$list1)) { 845 push(@res, $e); 846 } 847 } 848 return @res; 849} 850 851sub list_minus { 852 my ($list1, $list2) = @_; 853 my @res = (); 854 foreach my $e (@$list1) { 855 if (! grep( $_ eq $e, @$list2 )) { 856 push(@res, $e); 857 } 858 } 859 return @res; 860} 861 862sub get_next_id($$) { 863 my $ldap_base_dn = shift; 864 my $attribute = shift; 865 my $tries = 0; 866 my $found=0; 867 my $next_uid_mesg; 868 my $nextuid; 869 if ($ldap_base_dn =~ m/$config{usersdn}/i) { 870 # when adding a new user, we'll check if the uidNumber available is not 871 # already used for a computer's account 872 $ldap_base_dn=$config{suffix} 873 } 874 do { 875 $next_uid_mesg = $ldap->search( 876 base => $config{sambaUnixIdPooldn}, 877 filter => "(objectClass=sambaUnixIdPool)", 878 scope => "base" 879 ); 880 $next_uid_mesg->code && die "Error looking for next uid"; 881 if ($next_uid_mesg->count != 1) { 882 die "Could not find base dn, to get next $attribute"; 883 } 884 my $entry = $next_uid_mesg->entry(0); 885 886 $nextuid = $entry->get_value($attribute); 887 my $modify=$ldap->modify( "$config{sambaUnixIdPooldn}", 888 changes => [ 889 replace => [ $attribute => $nextuid + 1 ] 890 ] 891 ); 892 $modify->code && die "Error: ", $modify->error; 893 # let's check if the id found is really free (in ou=Groups or ou=Users)... 894 my $check_uid_mesg = $ldap->search( 895 base => $ldap_base_dn, 896 filter => "($attribute=$nextuid)", 897 ); 898 $check_uid_mesg->code && die "Cannot confirm $attribute $nextuid is free"; 899 if ($check_uid_mesg->count == 0) { 900 $found=1; 901 return $nextuid; 902 } 903 $tries++; 904 print "Cannot confirm $attribute $nextuid is free: checking for the next one\n" 905 } while ($found != 1); 906 die "Could not allocate $attribute!"; 907} 908 909 910#$ldap->unbind; 911#$ldap->unbind; 912 9131; 914 915