#!/usr/bin/perl -w # # smb2lmhost.pl # # Author: Heiko Teichmeier # Glauchau/Sa., Germany # E-Mail: heiko@tei-lin-net.de # Web: www.tei-lin-net.de # # Date: 2004-03-14 # Version: 0.1.5 # License: GPL # # Description: # ------------ # A perl script which allows you collect the windows machine names # with the corresponding IP adress (IPv4 only) using # the 'smbstatus' command. # It should write these pairs to the file "lmhosts", because other # scripts are functional only if the machine-name/IP mapping # works fine. # # Based on the script "smb-wall.pl" by Keith Farrar # # #============================================================================= # # Modified by # Heiko Teichmeier # 2003-11-19 v. 0.0.1 # 2003-11-20 v. 0.1.1 # # 2004-02-25 v. 0.1.2 (with help by Peter Reinhart, correct my bad english, thanks to him) # 2004-03-06 v. 0.1.3 # 2004-03-14 v. 0.1.4 (set the script under GPL-Licence) # 2004-03-14 v. 0.1.5 (modify the script to sort the machine-/ip-pairs) # use strict; my $VERSION = "0.1.5"; #=== definitions of your environment === # # location and name of the lmhost-file my $lm_file = "/etc/samba/lmhosts"; # location and name of safety-copy of the original lmhost-file my $lm_backup = "/etc/samba/lmhosts.orig"; # location and name of the temporarily changed lmhost-file my $lm_tmp = "/etc/samba/lmhosts.tmp"; my $lm_tmp_m = "/etc/samba/lmhosts.tmp_m"; my $lm_tmp_i = "/etc/samba/lmhosts.tmp_i"; my $lm_tmp1 = "/etc/samba/lmhosts.tmp1"; my $lm_tmp2 = "/etc/samba/lmhosts.tmp2"; my $lm_tmp3 = "/etc/samba/lmhosts.tmp3"; # write to the 'lmhosts' file - yes=1, no=0 or nothing my $lm_write = 1; # write the message-header to the lmhosts-file - yes=1, no=0 or nothing my $write_msg = 1; # create the 'lmhosts' file if not existing - yes=1, no=0 or nothing my $lm_create = 1; my $dat = localtime(time); # a message to write to the begin of the lmhosts-file to let the user know # how the file hase been created # the user should know, that a bad user, who use a faked IP adress, would through this # script automatically push to the 'lmhosts' file! my $lm_msg = "# \n"; $lm_msg .= "# This 'lmhosts' file whas automatically generated by\n"; $lm_msg .= "# the $0-Script\n"; $lm_msg .= "# +---------------------------+\n"; $lm_msg .= "# last run on: \| $dat \n"; $lm_msg .= "# +---------------------------+\n"; $lm_msg .= "# The Windows name/IP adress pairs are based on calls from\n"; $lm_msg .= "# the 'smbstatus' script\n"; $lm_msg .= "# \n"; # read the name-IP-pairs from the original lmhosts-file to insert in the # new created file - collecting machine-/ip-pairs over a long time, all old # pairs are inserted in the new lmhost-file too my $lm_read_old = 1; my $smbstatus = "/usr/bin/smbstatus"; my $proid = 0; my $mach_name = ""; my $mach_ip = ""; # here you can set a criterium to sort the machine/ip-pairs; # "ip" sort by ip-adresses # "name" sort by machine-names # as default we use the ip-adress sorting my $sort_crit = "ip"; # #=== end of definitions ================ my (%machines,@clients,@message,$client,@mach_names,@proc_ids); my ($strn_tmp,$strn_1,$strn_2); my (@pairs_m,@pairs_i,@sort_pairs_m,@sort_pairs_i,@save_rows,@sort_pairs); my (@sort_pairs_mt,@sort_pairs_it,@str_tmp); my $count = 0; my $lm_miss = 0; # test - does the "lmhosts" file already exist? if (! -e $lm_file) { print "File \'$lm_file\' not found!\n"; $lm_miss = "1"; if (not ($lm_create eq 1)) { print "\'$lm_file\' creation not wish!\n"; print "See options in the script!\n\n"; exit 1; } } else { open(RDFILE, "<$lm_file") || die "Open of \$lm_file failed!.\n$!\n"; while() { my $inp = $_; $count++; # saving the rows of the file to the array '@save_rows' my $anz = push(@save_rows,$inp); # rows select - no comments, no space or NULL rows # leere und Kommentar-Zeilen ueberspringen next if $inp =~ /^\#/; next if $inp =~ /^$/; next if $inp =~ /^ /; next unless $inp =~ /^[0-9]+/; my @data = split(' ', $inp, 2); # do not accept this line if it consists of less then two fields next unless $data[1]; my $key = $data[0]; my $value = $data[1]; # delete the last char - is the newline-char chomp $value; $machines{$key} = $value; } close(RDFILE); } # save the rows of the $lm_file to the $lm_backup-file open(WRFILE, ">$lm_backup") || die "Open of \$lm_backup failed!.\n$!\n"; while(@save_rows) { my $row = shift(@save_rows); printf WRFILE $row; } close(WRFILE); # call 'smbstatus' to look for Windows client name/IP adress pairs open(PCLIST, "$smbstatus |") || die "$smbstatus failed!.\n$!\n"; while() { last if /^Locked files:/; my @arr = split(" ", $_, 6); # do not accept this line if it consists of less than six fields next unless $arr[5]; # Reads out and saves PID # PID auslesen und speichern $proid = $arr[3]; push(@proc_ids, $proid); $client = $arr[4]; next unless $client =~ /[^.]/; # expect 'dot' in a client name next if grep($_ eq $client, @clients); # we only want this name once push (@clients,$client); # Reads and stores machine name/IP adress raw my $mach_ip_raw = $arr[5]; my @ip_arr = split(" ", $mach_ip_raw, 6); my $mach_ip_raw1= $ip_arr[0]; # store length of the string "machine-ip", to # cut the "(" and ")" my $len = length $mach_ip_raw1; my $mach_ip = substr($mach_ip_raw1, 1, $len-2); $machines{$mach_ip}=$client; } if ($lm_miss) { $machines{"127.0.0.1"}="localhost"; } close(PCLIST); # write the key pairs from the hash %machines as strings to various arrays foreach my $key (keys %machines) { $strn_1 = "$key|$machines{$key}"; @pairs_i = (@pairs_i,$strn_1); $strn_2 = "$machines{$key}|$key"; @pairs_m = (@pairs_m,$strn_2); } @sort_pairs_mt = sort @pairs_m; @sort_pairs_it = sort @pairs_i; $strn_tmp = ""; while(@sort_pairs_mt) { $strn_tmp = shift(@sort_pairs_mt); @str_tmp = split(/\|/,$strn_tmp); $strn_tmp = "$str_tmp[1]\t$str_tmp[0]"; @sort_pairs_m = (@sort_pairs_m,$strn_tmp); } $strn_tmp = ""; while(@sort_pairs_it) { $strn_tmp = shift(@sort_pairs_it); @str_tmp = split(/\|/, $strn_tmp); $strn_tmp = "$str_tmp[0]\t$str_tmp[1]"; @sort_pairs_i = (@sort_pairs_i,$strn_tmp); } # write NULL string and then the array @sort_pairs to $lm_file open(WRFILE, ">$lm_file") || die "Open of \$lm_file failed!.\n$!\n"; printf WRFILE ""; if ($write_msg) { printf WRFILE "$lm_msg"; } # set the array "@sort_pairs" to the selected one if ($sort_crit eq "name") {@sort_pairs = @sort_pairs_m;} elsif ($sort_crit eq "ip") {@sort_pairs = @sort_pairs_i;} else {@sort_pairs = @sort_pairs_i;} while(@sort_pairs) { my $row = shift(@sort_pairs); printf WRFILE "$row\n"; } close(WRFILE); exit 0;