~ubuntu-branches/ubuntu/intrepid/samba/intrepid-updates

« back to all changes in this revision

Viewing changes to examples/LDAP/smbldap-tools-0.9.2/smbldap_tools.pm

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2008-06-02 09:01:46 UTC
  • mfrom: (0.25.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20080602090146-92ur4nx39ccg708r
Tags: 2:3.0.30-2ubuntu1
* Merge from debian unstable, remaining changes:
  * debian/patches/VERSION.patch
    - set SAMABA_VERSION_VENDOR_SUFFIX to Ubuntu
  * debian/smb.conf
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] shares, and a comment about
      "value users = %S to show users how to restrict access to 
      \\server\useranem to only username.
    - Add map to guest = Bad user, maps bad username to guest access.
      (LP: #32067)
  * debian/samba-common.postinst:
    - Fix upgrade from a first installation done with feisty, edgy, or dapper.
      (LP: #201059)
    - When populating the new sambashare group, it's not an error if the user
      simply doesn't exist; test for this case and the install continue 
      instead of aborting. (LP: #206036)
  * debian/smba-common.config:
    - do not change priority to HIGH if dhclient3 is installed
    - used priority medium instead of hight for the workgroup question
  * debian/winbind.files
    - insclude additional files
  * debian/patches/fix-documentation.patch:
    - fix typos in net(8) and smb.conf(5) man pages
  * debian/mksambapasswd.awk:
    - Don't add user with UID less than 1000 to smbpasswd.
  * debian/samba.init:
    - add 'status' option for LSB conformance.
  * Updated control version.
  * Dropped Changes:
    - Dropped debian/patches/fix-smbprinting-os2.patch. Accepted upstream.
    - Dropped debian/patches/fix-documentation.patch. Accepted upstream.
     

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/perl -w
2
 
use strict;
3
 
package smbldap_tools;
4
 
use Net::LDAP;
5
 
use Crypt::SmbHash;
6
 
use 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
 
 
34
 
my $smbldap_conf;
35
 
if (-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
 
 
41
 
my $smbldap_bind_conf;
42
 
if (-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
 
}
47
 
my $samba_conf;
48
 
if (-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
 
 
54
 
use vars       qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
55
 
use Exporter;
56
 
$VERSION = 1.00;
57
 
 
58
 
@ISA = qw(Exporter);
59
 
use 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
 
 
112
 
sub 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
 
 
118
 
sub 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
 
 
135
 
sub 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
 
 
144
 
sub 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
 
 
183
 
sub 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
 
  }
218
 
my %smbconf=read_smbconf();
219
 
 
220
 
sub 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
 
 
230
 
sub 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");
249
 
if ($config{usersdn} !~ m/,/ ) {$config{usersdn}=$config{usersdn}.",".$config{suffix};}
250
 
$config{groupsdn}=get_parameter("ldap group suffix","groupsdn");
251
 
if ($config{groupsdn} !~ m/,/ ) {$config{groupsdn}=$config{groupsdn}.",".$config{suffix};}
252
 
$config{computersdn}=get_parameter("ldap machine suffix","computersdn");
253
 
if ($config{computersdn} !~ m/,/ ) {$config{computersdn}=$config{computersdn}.",".$config{suffix};}
254
 
$config{idmapdn}=get_parameter("ldap idmap suffix","idmapdn");
255
 
if (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
260
 
if (!defined $config{sambaUnixIdPooldn}) {
261
 
        $config{sambaUnixIdPooldn}="sambaDomainName=$config{sambaDomain},$config{suffix}";
262
 
}
263
 
if (!defined $config{masterLDAP}) {
264
 
        $config{masterLDAP}="127.0.0.1";
265
 
}
266
 
if (!defined $config{masterPort}) {
267
 
        $config{masterPort}="389";
268
 
}
269
 
if (!defined $config{slaveLDAP}) {
270
 
        $config{slaveLDAP}="127.0.0.1";
271
 
}
272
 
if (!defined $config{slavePort}) {
273
 
        $config{slavePort}="389";
274
 
}
275
 
if (!defined $config{ldapTLS}) {
276
 
        $config{ldapTLS}="0";
277
 
}
278
 
 
279
 
sub 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
 
 
305
 
sub 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
 
 
345
 
sub 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
 
 
366
 
sub 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
 
 
388
 
sub 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)
416
 
sub 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
 
 
427
 
sub 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
 
 
438
 
sub 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
 
 
451
 
sub 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})
464
 
sub 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
478
 
sub 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"
528
 
sub 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)
537
 
sub 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)
566
 
sub add_samba_machine_smbpasswd
567
 
  {
568
 
    my $user = shift;
569
 
    system "smbpasswd -a -m $user";
570
 
    return 1;
571
 
  }
572
 
 
573
 
sub 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
 
 
603
 
sub 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
 
 
633
 
sub 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
 
 
641
 
sub 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
 
 
650
 
sub 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)
678
 
sub 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)
693
 
sub 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)
729
 
sub 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
762
 
sub 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
790
 
sub 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
805
 
sub 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 ########
833
 
sub 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
 
 
850
 
sub 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
 
 
874
 
sub 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
891
 
sub 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
909
 
sub 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
 
 
932
 
sub 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
 
 
959
 
sub 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
966
 
EOF
967
 
        ;
968
 
        close FILE;
969
 
        my $rc = $?;
970
 
        return $rc;
971
 
  }
972
 
 
973
 
sub 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
 
 
983
 
sub 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)
991
 
sub 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
 
 
1004
 
sub 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
 
 
1015
 
sub 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
 
 
1026
 
sub 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
 
 
1073
 
sub utf8Encode {
1074
 
  my $arg = shift; 
1075
 
 
1076
 
  return to_utf8(
1077
 
                                 -string=> $arg,
1078
 
                                 -charset => 'ISO-8859-1',
1079
 
                                );
1080
 
}
1081
 
 
1082
 
sub utf8Decode {
1083
 
  my $arg = shift;
1084
 
 
1085
 
  return from_utf8(
1086
 
                                   -string=> $arg,
1087
 
                                   -charset => 'ISO-8859-1',
1088
 
                                  );
1089
 
}   
1090
 
 
1091
 
1;
1092