• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/samba-3.0.25b/examples/LDAP/smbldap-tools-0.9.2/
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.1.1.1 2010-07-16 07:33:12 winniec 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
1093