1#!/usr/bin/perl  -w
2##
3## Convert an LDIF file containing sambaAccount entries
4## to the new sambaSamAccount objectclass
5##
6## Copyright Gerald (Jerry) Carter	2003
7##
8## Usage: convertSambaAccount --sid=<Domain SID> \
9##       --input=<input ldif> --output=<output ldif> \
10##       --changetype=[modify|add]
11##
12## You can generate an input ldif file using:
13## $ ldapsearch -LL -x -h ldapsrv -D cn=root,dc=company,dc=com \
14##   -b dc=copmany,dc=com > /tmp/samba3.alpha23.ldif
15##
16## Note the "-LL" so no additional comments are generated
17##
18
19
20use strict;
21use Net::LDAP::LDIF;
22use Getopt::Long;
23
24
25##############################################################################
26## local variables
27
28my ( $domain, $domsid, $changetype );
29my ( $ldif, $ldif2 );
30my ( $entry, @objclasses, $obj );
31my ( $is_samba_account, $is_samba_group );
32my ( %attr_map, %group_attr_map, $key );
33my ( @dels, $deletion, @adds, $addition );
34my ( $result, %options );
35
36
37##############################################################################
38## Print the option usage
39
40sub usage {
41
42	print "convertSambaAccount <options>\n";
43	print "Options:\n";
44	print "  --help         print this help message\n";
45	print "  --input        input LDIF filename\n";
46	print "  --output       output LDIF filename\n";
47	print "  --sid          domain SID\n";
48	print "  --changetype   [modify|add] (default is 'add')\n";
49}
50
51
52##############################################################################
53##                               MAIN DRIVER                                ##
54##############################################################################
55
56##
57## hashes to map old attribute names to new ones 
58##
59
60%attr_map = ( 
61	lmPassword	=> 'sambaLMPassword',
62	ntPassword	=> 'sambaNTPassword',
63	pwdLastSet	=> 'sambaPwdLastSet',
64	pwdMustChange	=> 'sambaPwdMustChange',
65	pwdCanChange	=> 'sambaPwdCanChange',
66	homeDrive	=> 'sambaHomeDrive',
67	smbHome		=> 'sambaHomePath',
68	scriptPath	=> 'sambaLogonScript',
69	profilePath	=> 'sambaProfilePath',
70	kickoffTime	=> 'sambaKickoffTime',
71	logonTime	=> 'sambaLogonTime',
72	logoffTime	=> 'sambaLogoffTime',
73	userWorkstations	=> 'sambaUserWorkstations',
74	domain		=> 'sambaDomainName',
75	acctFlags	=> 'sambaAcctFlags',
76);
77
78%group_attr_map = (
79	ntSid		=> 'sambaSID',
80	ntGroupType	=> 'sambaGroupType',
81);
82
83##
84## process command line args
85##
86
87$result = GetOptions(\%options,
88			"help", 
89			"input=s", 
90			"output=s", 
91			"sid=s",
92			"changetype=s");
93
94if (!$result && ($#ARGV != -1)) {
95	usage();
96	exit 1;
97}
98
99if ( defined($options{'help'}) ) {
100	usage();
101	exit 0;
102}
103
104
105if ( !defined( $options{'sid'} ) ) {
106	print "You must provide a domain sid\n";
107	exit 1;
108}
109
110$domsid = $options{'sid'};
111
112$changetype = 'add';
113if ( defined( $options{'changetype'} ) ) {
114	$changetype = $options{'changetype'};
115}
116
117##
118## open files
119##
120
121$ldif = Net::LDAP::LDIF->new ($options{'input'}, "r") or die $!;
122
123if ( "$changetype" eq "add" ) {
124	$ldif2 = Net::LDAP::LDIF->new ($options{'output'}, "w") or die $!;
125}
126elsif ( "$changetype" eq "modify" ) {
127	open( OUTPUT, ">$options{'output'}" ) or die $!;
128}
129else {
130	print "Bad changetype!\n";
131	exit 1;
132}
133
134##
135## process LDIF 
136##
137
138while ( !$ldif->eof ) {
139	undef ( $entry );
140	$entry = $ldif->read_entry();
141
142	## skip entry if we find an error
143	if ( $ldif->error() ) {
144		print "Error msg: ",$ldif->error(),"\n";
145		print "Error lines:\n",$ldif->error_lines(),"\n";
146		next;
147	}
148
149	##
150	## check to see if we have anything to do on this
151	## entry.  If not just write it out
152	##
153	@objclasses = $entry->get_value( "objectClass" );
154	undef ( $is_samba_account );
155	undef ( $is_samba_group );
156	@adds = ();
157	@dels = ();
158	foreach $obj ( @objclasses ) {
159		if ( "$obj" eq "sambaAccount" ) {
160			$is_samba_account = 1;
161		} elsif ( "$obj" eq "sambaGroupMapping" ) {
162			$is_samba_group = 1;
163		}
164	}
165
166	if ( defined ( $is_samba_account ) ) {
167		##
168		## start editing the sambaAccount
169		##
170
171		@dels = ( 'objectclass: sambaAccount', 'rid' );
172		@adds = ('objectclass: sambaSamAccount', "sambaSID: " .  ${domsid} . "-" . ${entry}->get_value( 'rid' ) );
173		$entry->delete( 'objectclass' => [ 'sambaAccount' ] );
174		$entry->add( 'objectclass' => 'sambaSamAccount' );
175
176		$entry->add( 'sambaSID' => $domsid."-".$entry->get_value( "rid" ) );
177		$entry->delete( 'rid' );
178	
179		if ( defined($entry->get_value( "primaryGroupID" )) ) {
180			push @adds, "sambaPrimaryGroupSID: " . $domsid."-".$entry->get_value( "primaryGroupID" );
181			push @dels, "primaryGroupID";
182			$entry->add( 'sambaPrimaryGroupSID' => $domsid."-".$entry->get_value( "primaryGroupID" ) );
183			$entry->delete( 'primaryGroupID' );
184		}
185	
186
187		foreach $key ( keys %attr_map ) {
188			if ( defined($entry->get_value($key)) ) {
189				push @adds, "$attr_map{$key}: " . $entry->get_value($key);
190				push @dels, "$key";
191				$entry->add( $attr_map{$key} => $entry->get_value($key) );
192				$entry->delete( $key );
193			}
194		}
195	} elsif ( defined ( $is_samba_group ) ) {
196		foreach $key ( keys %group_attr_map ) {
197			if ( defined($entry->get_value($key)) ) {
198				push @adds, "$group_attr_map{$key}: " . $entry->get_value($key);
199				push @dels, "$key";
200				$entry->add( $group_attr_map{$key} => $entry->get_value($key) );
201				$entry->delete( $key );
202			}
203		}
204	}
205	
206	## see if we should write full entries or only the changes
207	
208	if ( "$changetype" eq "add" ) {
209		$ldif2->write_entry( $entry );
210	}
211	else {
212		if ( defined ( $is_samba_account ) || defined ( $is_samba_group ) ){
213			if ( @adds + @dels > 0 ) {
214				print OUTPUT "dn: " . $entry->dn . "\n";
215				foreach $addition (@adds) {
216					$addition =~ /(^\w+):/;
217					print OUTPUT "add: " . $1  . "\n";
218					print OUTPUT "$addition\n-\n";
219				}
220				foreach $deletion (@dels) {
221					if ( $deletion =~ /^(\w+):\s(.*)/ ) {
222						print OUTPUT "delete: $1\n$1: $2\n-\n";
223					} else {
224						print OUTPUT "delete: $deletion\n-\n"
225					}
226				}
227				print OUTPUT "\n"
228			}
229		}
230	}
231}
232
233
234