| 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 |  | 
|---|
| 20 | use strict; | 
|---|
| 21 | use Net::LDAP::LDIF; | 
|---|
| 22 | use Getopt::Long; | 
|---|
| 23 |  | 
|---|
| 24 |  | 
|---|
| 25 | ############################################################################## | 
|---|
| 26 | ## local variables | 
|---|
| 27 |  | 
|---|
| 28 | my ( $domain, $domsid, $changetype ); | 
|---|
| 29 | my ( $ldif, $ldif2 ); | 
|---|
| 30 | my ( $entry, @objclasses, $obj ); | 
|---|
| 31 | my ( $is_samba_account, $is_samba_group ); | 
|---|
| 32 | my ( %attr_map, %group_attr_map, $key ); | 
|---|
| 33 | my ( @dels, $deletion, @adds, $addition ); | 
|---|
| 34 | my ( $result, %options ); | 
|---|
| 35 |  | 
|---|
| 36 |  | 
|---|
| 37 | ############################################################################## | 
|---|
| 38 | ## Print the option usage | 
|---|
| 39 |  | 
|---|
| 40 | sub 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 |  | 
|---|
| 94 | if (!$result && ($#ARGV != -1)) { | 
|---|
| 95 | usage(); | 
|---|
| 96 | exit 1; | 
|---|
| 97 | } | 
|---|
| 98 |  | 
|---|
| 99 | if ( defined($options{'help'}) ) { | 
|---|
| 100 | usage(); | 
|---|
| 101 | exit 0; | 
|---|
| 102 | } | 
|---|
| 103 |  | 
|---|
| 104 |  | 
|---|
| 105 | if ( !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'; | 
|---|
| 113 | if ( 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 |  | 
|---|
| 123 | if ( "$changetype" eq "add" ) { | 
|---|
| 124 | $ldif2 = Net::LDAP::LDIF->new ($options{'output'}, "w") or die $!; | 
|---|
| 125 | } | 
|---|
| 126 | elsif ( "$changetype" eq "modify" ) { | 
|---|
| 127 | open( OUTPUT, ">$options{'output'}" ) or die $!; | 
|---|
| 128 | } | 
|---|
| 129 | else { | 
|---|
| 130 | print "Bad changetype!\n"; | 
|---|
| 131 | exit 1; | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | ## | 
|---|
| 135 | ## process LDIF | 
|---|
| 136 | ## | 
|---|
| 137 |  | 
|---|
| 138 | while ( !$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 |  | 
|---|