source: branches/samba-3.0/examples/LDAP/smbldap-tools-0.9.2/smbldap_tools.pm

Last change on this file was 1, checked in by Paul Smedley, 18 years ago

Initial code import

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