File: smbldap-migrate-unix-accounts

package info (click to toggle)
smbldap-tools 0.9.5-1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 844 kB
  • ctags: 325
  • sloc: perl: 4,690; makefile: 132; sh: 20
file content (371 lines) | stat: -rwxr-xr-x 11,640 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
#!/usr/bin/perl -w

# Created by P.Wieleba@iem.pw.edu.pl in 2004

use strict;
use Getopt::Std;
use FindBin;
use FindBin qw($RealBin);
use lib "$RealBin/";
use smbldap_tools;

# function declaration
sub migrate_user;
sub migrate_shadow_user;
sub get_user_entry;
sub exist_in_tab;
sub del_from_tab;
sub add_to_tab;
sub read_shadow_file;

# smbldap-migrate-unix-accounts (-? or -h for help)
#
#

my %Options;

my $ok = getopts('M:P:S:vn?hd:a', \%Options);

if ( (!$ok) || ($Options{'?'}) || ($Options{'h'}) || (!keys(%Options)) ) {
  print "Usage: $0 [-PSMvn?hda]\n";
  print "  -?|-h      show this help message\n";
  print "  -P file    import passwd file\n";
  print "  -S file    import shadow file\n";
  print "  -M file    import FreeBSD master.passwd\n";
  print "  -v         displays modified entries to STDOUT\n";
  print "  -n         do everything execpt updating LDAP\n";
  print "  -d obj_nam delete and add (not just update) existing entry in LDAP\n";
  print "  -a         adds sambaSamAccount objectClass\n";  
  exit (1);
}

my $INFILE = undef;
my %shadowUsers;

if ( $Options{'M'} ) {
  open($INFILE,$Options{'M'}) or
    die "I cannot open file: " . $Options{'M'} . "\n";
} elsif ( $Options{'P'} ) {
  open($INFILE,$Options{'P'}) or
    die "I cannot open file: " . $Options{'P'} . "\n";
  # if defined -S option also read shadow file
  if ( $Options{'S'} ) {
    %shadowUsers = read_shadow_file($Options{'S'});
    (%shadowUsers) or ( close($INFILE) and 
                        die "I cannot open file: " . $Options{'S'} . "\n" ); 
  }
} elsif ( $Options{'S'} ) {
  open($INFILE,$Options{'S'}) or
    die "I cannot open file: " . $Options{'S'} . "\n";
}

my $ldap_master=connect_ldap_master();

while ( my $line=<$INFILE> ) {
  chop($line);
  next if ( $line =~ /^\s*$/ ); # whitespace
  next if ( $line =~ /^#/ );
  next if ( $line =~ /^\+/ );
  my $entry = undef;
  if ($Options{'M'}) {
    my($user,$pwd,$uid,$gid,$class,$change,$expire,$gecos,$homedir,$shell) = split(/:/,$line);
    # if user is not in LDAP new entry will be created
    $entry = get_user_entry($ldap_master,$user);
    $entry = migrate_user($entry,$user,$pwd,$uid,$gid,$gecos,$homedir,$shell);
    # for master.passwd file (nss_ldap)
    if ($entry) {
      my @objectClass = $entry->get_value( 'objectClass' );
      $entry->replace( 'objectClass' => [add_to_tab(\@objectClass,'shadowAccount')] );
    }
  } elsif ($Options{'P'}) {
    my($user,$pwd,$uid,$gid,$gecos,$homedir,$shell) = split(/:/,$line);
    # if user is not in LDAP new entry will be created
    $entry = get_user_entry($ldap_master,$user);
    $entry = migrate_user($entry,$user,$pwd,$uid,$gid,$gecos,$homedir,$shell,undef);
		
    # should I delete next functionality
    # add shadow entries if also -S defined
    if ($Options{'S'} and $shadowUsers{$user}) {
      my($user,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag) = split(/:/,$shadowUsers{$user});
      $entry = migrate_shadow_user($entry,$user,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag);
    }
  } elsif ($Options{'S'}) {
    my($user,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag)=split(/:/,$line);
    # if user is not in LDAP new entry will be created
    $entry = get_user_entry($ldap_master,$user);
    $entry = migrate_shadow_user($entry,$user,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag);
  }

  if ($entry) {
    # objectClass $Options{'d'} will be removed
    # from entry if it exists
    if ($Options{'d'}) {
      my @objectClass = $entry->get_value( 'objectClass' );
      $entry->replace( 'objectClass' => [del_from_tab(\@objectClass,$Options{'d'})] );
      #$entry->delete( 'objectClass' => [ $Options{'d'} ] );
    }
    # if used "-a" and sambaSamAccount doesn't exist.
    if ( $Options{'a'} and !exist_in_tab([$entry->get_value('objectClass')],'sambaSamAccount') ) {
      my @objectClass = $entry->get_value( 'objectClass' );
      $entry->replace( 'objectclass' => [add_to_tab(\@objectClass,'sambaSamAccount')] );
			
      # the below part comes from smbldap-useradd and
      # maybe it should be replaced by a new subroutine.
      my $userUidNumber = $entry->get_value('uidNumber');
      # as rid we use 2 * uid + 1000
      my $userRid = 2 * $userUidNumber + 1000;
      # let's test if this SID already exist
      my $user_sid = "$config{SID}-$userRid";
      my $test_exist_sid = does_sid_exist($user_sid,$config{usersdn});
      if ($test_exist_sid->count == 1) {
	print "User SID already owned by\n";
				# there should not exist more than one entry, but ...
	foreach my $entry ($test_exist_sid->all_entries) {
	  my $dn= $entry->dn;
	  chomp($dn);
	  print "$dn\n";
	}
      } else {
	$entry->replace( 'sambaSID' => $user_sid );
      }
    }
    if ($Options{'v'}) {
      $entry->dump();
    }
    if (!$Options{'n'}) {
      my $mesg;
      if ( $Options{'d'} ) {
				# delete entry from LDAP if it exists
	$mesg = $ldap_master->search( base => $entry->dn(),
				      scope => 'sub',
				      filter => '(objectClass=*)'
				    );
	if ( $mesg->count() == 1 ) {
	  $mesg = $ldap_master->delete($entry->dn());
	  if ($mesg->is_error()) {
	    print "Error: " . $mesg->error() . "\n";
	  }
	  $entry->changetype('add');
	}
      }
      $mesg = $entry->update($ldap_master);
      if ($mesg->is_error()) {
	print "Error: " . $mesg->error() . "\n";
      }
    }
  }
}

$INFILE and close($INFILE);
# take down the session
$ldap_master and $ldap_master->unbind;

# returns updated $entry
sub migrate_user
  {
    my($entry,$user,$pwd,$uid,$gid,$gecos,$homedir,$shell) = @_;
    my($name,$office,$wphone,$hphone)=split(/,/,$gecos);
    my($cn);
	
    # posixAccount MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
    my @objectClass = $entry->get_value( 'objectClass' );
    @objectClass = add_to_tab(\@objectClass,'posixAccount');
    @objectClass = add_to_tab(\@objectClass,'inetOrgPerson');
    $entry->replace( 'objectClass' => \@objectClass );

    $entry->replace( 'uid' => $user );
    if ($name) {
      $cn = $name;
    } else {
      $cn = $user;
    }
    $entry->replace( 'cn' => $cn );
    # perhaps I should delete it
    if ( exist_in_tab(\@objectClass,'inetOrgPerson') ) {
      # 'sn' is required by person objectClass from core.schema
      my @tmp = split(/\s+/,$cn);
      my $sn = $tmp[$#tmp];
      $entry->replace( 'sn' => $sn );
      # perhaps 'telephoneNumber' 'roomNumber' 'homePhone' 
      # and 'givenName' also should be modified ???????
    }
    ($pwd)       and $entry->replace( 'userPassword'  => "{crypt}" . $pwd );
    ($uid ne "") and $entry->replace( 'uidNumber'     => $uid );
    ($gid ne "") and $entry->replace( 'gidNumber'     => $gid );
    ($gecos)     and $entry->replace( 'gecos'         => $gecos );
    ($homedir)   and $entry->replace( 'homeDirectory' => $homedir );
    ($shell)     and $entry->replace( 'loginShell'    => $shell );

    return $entry;
  }

# returns updated $entry
sub migrate_shadow_user
  {
    my($entry,$user,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag) = @_;
	
    # shadowAccount MUST uid
    my @objectClass = $entry->get_value( 'objectClass' );
    # if the entry doesn't exist, it needs structural objectclass
    (@objectClass) or push(@objectClass,'account');
    $entry->replace( 'objectClass' => [add_to_tab(\@objectClass,'shadowAccount')] );
	
    $entry->replace( 'uid' => $user );
    ($pwd)      and $entry->replace( 'userPassword'     => "{crypt}" . $pwd );
    ($lastchg)  and $entry->replace( 'shadowLastChange' => $lastchg );
    ($min)      and $entry->replace( 'shadowMin'        => $min );
    ($max)      and $entry->replace( 'shadowMax'        => $max );
    ($warn)     and $entry->replace( 'shadowWarning'    => $warn );
    ($inactive) and $entry->replace( 'shadowInactive'   => $inactive );
    ($expire)   and $entry->replace( 'shadowExpire'     => $expire );
    ($flag)     and $entry->replace( 'shadowFlag'       => $flag );
	
    return $entry;
  }

# creates a _new_entry_ if user doesn't exist in ldap
# else return's ldap user entry
sub get_user_entry
  {
    my($ldap_master,$user) = @_;
	
    # do not use read_user_entry()
    my $mesg = $ldap_master->search( base => $config{usersdn},
				     scope => 'one',
				     filter => "(uid=$user)"
				   );
    my $entry;
    if ( $mesg->count() != 1 ) {
      $entry = Net::LDAP::Entry->new();
      $entry->dn("uid=$user,$config{usersdn}");
    } else {
      $entry = $mesg->entry(0); # ????
    }
    return $entry;
  }

# Check if a $text element exists in @table
# eg. exist_in_tab(\@table,$text);
sub exist_in_tab
  {
    my($ref_tab,$text) = @_;
    my @tab = @$ref_tab;

    foreach my $elem (@tab) {
      if ( lc($elem) eq lc($text) ) {
	return 1;
      }
    }
    return 0;
  }

# Delete $text element from @table
# eg. del_from_tab(\@table,$text);
sub del_from_tab
  {
    my($ref_tab,$text) = @_;
    my @tab = @$ref_tab;
    my @new_tab;
		
    foreach my $elem (@tab) {
      if ( lc($elem) ne lc($text) ) {
	push(@new_tab,$elem);
      }
    }
    return @new_tab;
  }

# Add $text to tab if it doesn't exist there
sub add_to_tab
  {
    my($ref_tab,$text) = @_;
    my @tab = @$ref_tab;
	
    if ( !exist_in_tab(\@tab,$text) ) {
      push(@tab,$text);
    }
    return @tab;
  }

# reads shadow file entries and places them in a hash
sub read_shadow_file
  {
    my($shadow) = @_;

    my $shadowUser;
    my %shadowUsers;
    open(SHADOW,$shadow) or
      return ;
    while (my $line=<SHADOW>) {
      chop($line);
      next if ( $line =~ /^\s*$/ ); # whitespace
      next if ( $line =~ /^#/ );
      ($shadowUser) = split(/:/, $line);
      $shadowUsers{$shadowUser} = $line;
    }
    close(SHADOW);
    return %shadowUsers;
  }

########################################

=head1 NAME

smbldap-migrate-unix-accounts - Migrate unix accounts to LDAP

=head1 SYNOPSIS

smbldap-migrate-unix-accounts [-P file] [-S file] [-M file] [-n] [-v]
[-h] [-?] [-d]

=head1 DESCRIPTION

This command processes one file as defined by option and
creates new or changes existing ldap user entry.
New attributes are added, and existing are changed.
None of the existing attributes is deleted.

-P passwd_file
       Processes passwd_file and uptades LDAP. Creates new ldap user
       entry or just adds posixAccount objectclass and corresponding
       attributes to the ldap user entry or just uptades their values.

-S shadow_file
       Reads shadow_file and uptades LDAP. Creates new ldap user
       entry or just adds shadowAccount objectclass and corresponding
       attributes to the ldap user entry or just uptades their values.

-M master.passwd_file
       Reads master.passwd_file and uptades LDAP. Creates new ldap user
       entry or just adds shadowAccount and posixAccount objectclass
       and corresponding attributes to the ldap user entry or just 
       uptades their values.

-h     show the help message

-?     the same as -h

-v     displayes modified entries to STDOUT

-n     do everything execpt updating LDAP. It is useful when used
       with -v switch.

-d objeClass_name
       In spite of just updating existing user entry, the entry will be 
       deleted from LDAP and a new one will be added.
       It is essential to use this option if you update users in LDAP
       and want to change their structural objectClass. 
       Use it in the example schema:
       There are no users in LDAP, and you migrate samba first.
       # pdbedit -e ldapsam:ldap://localhost
       # smbldap-migrate-passwd -P passwd -d 'account'

-a     adds sambaSamAccount objectClass and generates sambaSID attribute

=cut

#'

# The End