e9c1b9de56b8279e674c2a2631ecc97436b995ff
[samba.git] / source3 / script / mysql_convert.pl
1 #!/usr/local/bin/perl
2
3 use Mysql;
4
5 $ACB_DISABLED=0x0001;
6 $ACB_HOMDIRREQ=0x0002;
7 $ACB_PWNOTREQ=0x0004;
8 $ACB_TEMPDUP=0x0008;
9 $ACB_NORMAL=0x0010;
10 $ACB_MNS=0x0020;
11 $ACB_DOMTRUST=0x0040;
12 $ACB_WSTRUST=0x0080;
13 $ACB_SVRTRUST=0x0100;
14 $ACB_PWNOEXP=0x0200;
15 $ACB_AUTOLOCK=0x0400;
16
17 sub getoptionval {
18         my ($option) = @_;
19
20         my ($value) = ($option =~ /^[^=]+=\s*(\S.*\S)/ );
21
22         return $value;
23 }
24
25 sub usage {
26
27 print <<EOUSAGE;
28 $0 [options]
29 options:
30    --infile=<filename>          # smbpasswd style file to read entries from
31    --outfile=<filename>         # file to dump results to, format depending
32                                 #   on --infile:
33                                 # With --infile: Dump mysql script queries
34                                 # Without --infile: Dump smbpasswd format
35                                 #                from reading mysql database
36    --host=<hostname>            # Mysql Server name (default: localhost)
37    --db=<database>              # Mysql Database name
38    --user=<user>                # Mysql User
39    --password[=<password>]      # Mysql password for --user
40    --table=<table>              # Mysql table
41    --create                     # Generate 'create table' query
42    --file=[trash|append]        # Action to take if --outfile file exists
43    --check                      # Do not alter or skip bad uids
44
45 EOUSAGE
46 exit 0;
47 }
48
49 sub getpass {
50         my($prompt)=@_;
51         my($ret);
52
53         print $prompt;
54         system "stty -echo";
55         chomp($ret=<STDIN>);
56         system "stty echo";
57         print "\n";
58         $ret;
59 }
60
61 sub next_entry {
62         my ($name,$uid,$lm,$nt,$f,$lct) = ();
63
64         $name="";
65         if ( not $infile ) {
66                 ($name,$uid,$lm,$nt,$f,$lct) = $mysqlquery->fetchrow();
67         }
68         else {
69                 my $line=<INFILE>;
70
71                 return () if ( not $line );
72
73                 chomp($line);
74
75                 next if ( $line !~ /^[^: ]+:\d+:/ );
76
77                 ($name,$uid,$lm,$nt,$f,$lct) = split(/:/,$line);
78
79                 if ( $lct =~ /^LCT-/ ) {
80                         # New Format smbpasswd file
81                         my $flags=0;
82
83                         $flags |= $ACB_PWNOTREQ if ( $f =~ /N/ );
84                         $flags |= $ACB_DISABLED if ( $f =~ /D/ );
85                         $flags |= $ACB_HOMDIRREQ if ( $f =~ /H/ );
86                         $flags |= $ACB_TEMPDUP if ( $f =~ /T/ );
87                         $flags |= $ACB_NORMAL if ( $f =~ /U/ );
88                         $flags |= $ACB_MNS if ( $f =~ /M/ );
89                         $flags |= $ACB_WSTRUST if ( $f =~ /W/ );
90                         $flags |= $ACB_SVRTRUST if ( $f =~ /S/ );
91                         $flags |= $ACB_AUTOLOCK if ( $f =~ /L/ );
92                         $flags |= $ACB_PWNOEXP if ( $f =~ /X/ );
93                         $flags |= $ACB_DOMTRUST if ( $f =~ /I/ );
94
95                         $f = $flags;
96
97                         $f = $ACB_NORMAL if ( not $f );
98
99                         $lct =~ s/LCT-//;
100                         $lct = (unpack("L",pack("H8",$lct)))[0];
101                 }
102                 else {
103                         # Old Format smbpasswd file
104                         $f = 0;
105                         $lct = time();
106                         if ( $lm =~ /^NO PASS/ ) {
107                                 $f |= $ACB_PWNOTREQ;
108                                 $lm = "";
109                                 $nt = "";
110                         }
111                         elsif ( $lm =~ /^XX/ ) {
112                                 $f |= $ACB_DISABLED;
113
114                                 $lm = "";
115                                 $nt = "";
116                         }
117
118                         if ( $name =~ /\$$/ ) {
119                                 $f |= $ACB_WSTRUST;
120                         }
121
122                         $f = $ACB_NORMAL if ( not $f );
123                 }
124         }
125         return () if ( not $name );
126         ($name,$uid,$lm,$nt,$f,$lct);
127 }
128
129 sub do_query {
130         my ( $query ) = @_;
131
132         chomp($query);
133         if ( $outfile ) {
134                 print OUTFILE "$query;\n";
135         }
136         else {
137                 if ( not $mysqldb->query($query) ) {
138                         print "$query: $Mysql::db_errstr\n";
139                 }
140         }
141 }
142
143 sub do_file {
144         my ($file,$name,$uid,$lm,$nt,$f,$lct)=@_;
145
146         my $strings = "";
147
148         $strings .= "N" if ( $f & $ACB_PWNOTREQ );
149         $strings .= "D" if ( $f & $ACB_DISABLED );
150         $strings .= "H" if ( $f & $ACB_HOMDIRREQ );
151         $strings .= "T" if ( $f & $ACB_TEMPDUP );
152         $strings .= "U" if ( $f & $ACB_NORMAL );
153         $strings .= "M" if ( $f & $ACB_MNS );
154         $strings .= "W" if ( $f & $ACB_WSTRUST );
155         $strings .= "S" if ( $f & $ACB_SVRTRUST );
156         $strings .= "L" if ( $f & $ACB_AUTOLOCK );
157         $strings .= "X" if ( $f & $ACB_PWNOEXP );
158         $strings .= "I" if ( $f & $ACB_DOMTRUST );
159
160         $f = sprintf( "[%-11s]", $strings );
161
162         $lct=uc("LCT-".(unpack("H8",pack("L","$lct")))[0]);
163
164         $lm = "X"x32 if ( not $lm );
165         $nt = "X"x32 if ( not $nt );
166
167         print $file "$name:$uid:$lm:$nt:$f:$lct\n";
168 }
169
170 $dbhost = "localhost";
171
172 for $option ( @ARGV ) {
173         if ( $option =~ /--outfile=/ ) {
174                 $outfile = getoptionval($option);
175         }
176         elsif ( $option =~ /--infile=/ ) {
177                 $infile = getoptionval($option);
178         }
179         elsif ( $option =~ /--db=/ ) {
180                 $dbname = getoptionval($option);
181         }
182         elsif ( $option =~ /--user=/ ) {
183                 $dbuser = getoptionval($option);
184         }
185         elsif ( $option =~ /--host=/ ) {
186                 $dbhost = getoptionval($option);
187         }
188         elsif ( $option =~ /--password/ ) {
189                 $dbpasswd = getoptionval($option);
190                 $need_password = "yes"
191         }
192         elsif ( $option =~ /--table=/ ) {
193                 $dbtable = getoptionval($option);
194         }
195         elsif ( $option =~ /--create/ ) {
196                 $create_table = "yes";
197         }
198         elsif ( $option =~ /--file=/ ) {
199                 $file_action = getoptionval($option);
200         }
201         elsif ( $option =~ /--check/ ) {
202                 $check = "yes";
203         }
204         else {
205                 print "Unknown option: $option\n";
206                 $unknown = "yes";
207         }
208 }
209
210 &usage if ( $unknown eq "yes" );
211
212 if ( ( not $infile ) && ( not $outfile ) && ( $create_table ne "yes" ) ) {
213         print "Need file to read from or write to\n";
214         &usage;
215 }
216 elsif ( $infile && $outfile ) {
217         if ( not $dbtable ) {
218                 print "Need --table to create queries\n";
219                 exit 1;
220         }
221
222         # Reading a smbpasswd file, dumping queries into an file which
223         # can be used for a mysql script
224         # --db* options are ignored.
225
226         $ignored = "";
227         $ignored .= " --db" if ( $dbname );
228         $ignored .= " --user" if ( $dbuser );
229         $ignored .= " --password" if ( $dbuser );
230
231         if ( $ignored ) {
232                 print "Ignoring options: $ignored\n";
233         }
234 }
235 elsif ( (not $dbname) || (not $dbtable) || (not $dbuser) ) {
236         print "Missing database particulars:\n";
237         print "  --db=??\n" if ( not $dbname );
238         print "  --user=??\n" if ( not $dbuser );
239         print "  --table=??\n" if ( not $dbtable );
240         &usage;
241 }
242 else {
243         if ( ($need_password eq "yes") && ( not $dbpasswd )) {
244                 $dbpasswd = getpass("Enter MySQL password for $dbuser: ");
245         }
246         $mysqldb = Connect Mysql($dbhost,$dbname,$dbuser,$dbpasswd);
247
248         if ( not $mysqldb ) {
249                 print "Cannot connect to database: $Mysql::db_errstr\n";
250                 exit 1;
251         }
252
253         if ( $outfile ) {
254                 $mysqlquery = $mysqldb->query("select unix_name,unix_uid,smb_passwd,smb_nt_passwd,acct_ctrl,pass_last_set_time from $dbtable");
255
256                 if ( not $mysqlquery ) {
257                         print "MySQL Query failed: $Mysql::db_errstr\n";
258                         exit 1;
259                 }
260         }
261 }
262
263 if ( $create_table eq "yes" ) {
264         $create_table_query=<<EOSQL;
265 create table $dbtable (
266 unix_name            char(20) not null,
267 unix_uid             int(10)  unsigned not null,
268 nt_name              char(20) not null,
269 user_rid             int(10)  unsigned not null,
270 smb_passwd           char(32),
271 smb_nt_passwd        char(32),
272 acct_ctrl            int(10) unsigned not null,
273 pass_last_set_time   int(10) unsigned not null,
274 unique (unix_name),
275 unique (unix_uid)
276 )
277 EOSQL
278         print "$create_table_query\n";
279 }
280 if ( $infile ) {
281         if ( not open(INFILE,$infile) ) {
282                 print "$infile: $!\n";
283                 exit 1;
284         }
285 }
286
287 if ( $outfile ) {
288         if ( ! -f $outfile ) {
289                 $open_string=">$outfile";
290         }
291         elsif ( not $file_action ) {
292                 print "File $outfile exists:\n";
293                 print "Please use --file=[trash|append] option to determine destiny of file\n";
294                 exit 1;
295         }
296         elsif ( $file_action eq "append" ) {
297                 $open_string = ">>$outfile";
298         }
299         else {
300                 $open_string = ">$outfile";
301         }
302
303         if ( not open(OUTFILE,$open_string) ) {
304                 print "$outfile: $!\n";
305                 exit 1;
306         }
307 }
308
309 do_query($create_table_query) if ( $create_table_query );
310
311 $linenum=1;
312 while (($name,$uid,$lm,$nt,$f,$lct)=next_entry()) {
313         
314         $| = 1;
315         print "\r$linenum ";
316         $linenum++;
317
318         $nuid = "";
319
320         $nuid = (getpwnam(lc($name)))[2];
321
322         if ( $check ) {
323                 if ( not $nuid ) {
324                         # print "Removing $name: Does not exist\n";
325                         push(@removed,[$name,$uid,$lm,$nt,$f,$lct]);
326                         next;
327                 }
328                 else {
329                         # print "Changing uid of $name\n";
330                         $uid = $nuid;
331                 }
332         }
333
334         if ( $infile ) {
335                 if ( $lm ) {
336                         $lm = "'$lm'";
337                 }
338                 else {
339                         $lm = "NULL";
340                 }
341                 if ( $nt ) {
342                         $nt = "'$nt'";
343                 }
344                 else {
345                         $nt = "NULL";
346                 }
347                 $rid=(4*$uid)+1000;
348                 do_query("insert into $dbtable (unix_name,unix_uid,smb_passwd,smb_nt_passwd,acct_ctrl,pass_last_set_time,nt_name,user_rid) values ('$name',$uid,$lm,$nt,$f,$lct,'$name',$rid)");
349         }
350         else {
351                 do_file(OUTFILE,$name,$uid,$lm,$nt,$f,$lct);
352         }
353 }
354
355 if ( @removed ) {
356         print "\n\nIgnored entries because usernames do not exist\n";
357         foreach $line ( @removed ) {
358                 do_file(STDOUT,@{ $line });
359         }
360 }
361
362 close (OUTFILE) if ( $outfile );
363 close (INFILE) if ( $infile );
364 print "\n";