/*************************************************************************** smb4kscanner.cpp - The network scan core class of Smb4K. ------------------- begin : Sam Mai 31 2003 copyright : (C) 2003-2007 by Alexander Reinholdt email : dustpuppy@users.berlios.de ***************************************************************************/ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ // TQt includes #include #include #include // KDE includes #include #include #include #include // system includes #include // Application specific includes. #include "smb4kscanner.h" #include "smb4kscanner_p.h" #include "smb4kauthinfo.h" #include "smb4kerror.h" #include "smb4tdeglobal.h" #include "smb4ksambaoptionshandler.h" #include "smb4kpasswordhandler.h" #include "smb4knetworkitems.h" #include "smb4ksettings.h" using namespace Smb4TDEGlobal; static bool created_workgroups_list = false; static bool created_hosts_list = false; Smb4KScanner::Smb4KScanner( TQValueList *workgroups, TQValueList *hosts, TQObject *parent, const char *name ) : TQObject( parent, name ), m_workgroups_list( workgroups ), m_hosts_list( hosts ) { m_priv = new Smb4KScannerPrivate; if ( !m_workgroups_list ) { created_workgroups_list = true; m_workgroups_list = new TQValueList; } else { // The list was passed to the constructor from outside. } if ( !m_hosts_list ) { created_hosts_list = true; m_hosts_list = new TQValueList; } else { // The list was passed to the constructor from outside. } m_proc = new TDEProcess( this, "ScannerMainProcess" ); m_proc->setUseShell( true ); m_working = false; m_queue.setAutoDelete( true ); connect( m_proc, TQ_SIGNAL( receivedStdout( TDEProcess *, char *, int ) ), this, TQ_SLOT( slotReceivedStdout( TDEProcess *, char *, int ) ) ); connect( m_proc, TQ_SIGNAL( processExited( TDEProcess* ) ), this, TQ_SLOT( slotProcessExited( TDEProcess * ) ) ); connect( m_proc, TQ_SIGNAL( receivedStderr( TDEProcess *, char *, int ) ), this, TQ_SLOT( slotReceivedStderr( TDEProcess *, char *, int ) ) ); } Smb4KScanner::~Smb4KScanner() { abort(); // Delete the list of workgroups, if necessary: if ( created_workgroups_list ) { for ( TQValueList::Iterator it = m_workgroups_list->begin(); it != m_workgroups_list->end(); ++it ) { delete *it; } m_workgroups_list->clear(); delete m_workgroups_list; } else { // The list of workgroups is handled outside of this class. } // Delete the list of hosts, if necessary: if ( created_hosts_list ) { for ( TQValueList::Iterator it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it ) { delete *it; } m_hosts_list->clear(); delete m_hosts_list; } else { // The list of hosts is handled outside of this class. } delete m_priv; } void Smb4KScanner::init() { m_timer_id = startTimer( TIMER_INTERVAL ); rescan(); } void Smb4KScanner::rescan() { m_queue.enqueue( new TQString( TQString( "%1:" ).arg( Init ) ) ); } /**************************************************************************** Scans for workgroup members. (public part) ****************************************************************************/ void Smb4KScanner::getWorkgroupMembers( const TQString &workgroup, const TQString &master, const TQString &ip ) { m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4" ).arg( Hosts ).arg( workgroup, master, ip ) ) ); } /**************************************************************************** Scans for shares on a selected host. (public part) ****************************************************************************/ void Smb4KScanner::getShares( const TQString &workgroup, const TQString &host, const TQString &ip, const TQString &protocol ) { m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4:%5" ).arg( Shares ).arg( workgroup, host, ip ).arg( protocol ) ) ); } /**************************************************************************** Gets more info on a selected host. (public part) ****************************************************************************/ void Smb4KScanner::getInfo( const TQString &workgroup, const TQString &host, const TQString &ip ) { Smb4KHostItem *item = getHost( host, workgroup ); if ( item && item->infoChecked() ) { emit info( item ); return; } else { // Avoid several queueing up: item->setInfoChecked( true ); } m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4" ).arg( Info ).arg( workgroup, host, ip ) ) ); } /**************************************************************************** Searches for a host. (public part) ****************************************************************************/ void Smb4KScanner::search( const TQString &host ) { // Check whether we already have this host in // the list: Smb4KHostItem *item = getHost( host ); if ( item ) { emit searchResult( item ); return; } m_queue.enqueue( new TQString( TQString( "%1:%2" ).arg( Search ).arg( host ) ) ); } /**************************************************************************** Aborts any process that is running. ****************************************************************************/ void Smb4KScanner::abort() { m_queue.clear(); if ( m_proc->isRunning() ) { m_proc->kill(); } } /**************************************************************************** This function retrieves the initial browse list ****************************************************************************/ void Smb4KScanner::scanNetwork() { abort(); TQString command; // Look up the workgroups/domains and their master browsers. // At the moment we have three methods: // (1) Smb4KSettings::EnumBrowseList::LookupDomains: This method is // the most reliable one. It uses nmblookup and will only find // *active* workgroup master browsers and thus active domains. // (2) Smb4KSettings::EnumBrowseList::QueryCurrentMaster: This // method will query the current master browser of the local // workgroup/domain. This method is not as reliable as the first // one, because you might get wrong (i. e. outdated) master // browsers for the workgroups or even empty workgroups. // (3) Smb4KSettings::EnumBrowseList::QueryCustomMaster: This method // is similar to the second one, but the user has defined a fixed // host name or IP address. // (4) Smb4KSettings::EnumBrowseList::ScanBroadcastAreas: Scan the // user given broadcast addresses for active hosts (IP scan) switch ( Smb4KSettings::browseList() ) { case Smb4KSettings::EnumBrowseList::LookupDomains: { command.append( "nmblookup -M " ); command.append( optionsHandler()->nmblookupOptions() ); command.append( " -- - | grep '<01>' | awk '{print $1}'" ); command.append( !optionsHandler()->winsServer().isEmpty() ? TQString( " | xargs nmblookup -R -U %1 -A " ).arg( optionsHandler()->winsServer() ) : " | xargs nmblookup -A " ); command.append( optionsHandler()->nmblookupOptions() ); *m_proc << command; startProcess( Workgroups ); break; } case Smb4KSettings::EnumBrowseList::QueryCurrentMaster: { command.append( "net " ); command.append( optionsHandler()->netOptions( Smb4KSambaOptionsHandler::LookupMaster, Smb4KSettings::domainName() ) ); command.append( " -U % | xargs net " ); command.append( optionsHandler()->netOptions( Smb4KSambaOptionsHandler::Domain, TQString() ) ); command.append( " -U % -S" ); *m_proc << command; startProcess( QueryHost ); break; } case Smb4KSettings::EnumBrowseList::QueryCustomMaster: { command.append( "net " ); command.append( optionsHandler()->netOptions( Smb4KSambaOptionsHandler::LookupHost, Smb4KSettings::customMasterBrowser() ) ); command.append( " -U % -S "+TDEProcess::quote( Smb4KSettings::customMasterBrowser() ) ); command.append( " | xargs net " ); command.append( optionsHandler()->netOptions( Smb4KSambaOptionsHandler::Domain, TQString() ) ); command.append( " -U % -S "+TDEProcess::quote( Smb4KSettings::customMasterBrowser() )+" -I " ); *m_proc << command; startProcess( QueryHost ); break; } case Smb4KSettings::EnumBrowseList::ScanBroadcastAreas: { // Get the broadcast addresses that are to be scanned: TQStringList addresses = TQStringList::split( ",", Smb4KSettings::broadcastAreas(), false ); // Build the command: for ( TQStringList::ConstIterator it = addresses.begin(); it != addresses.end(); ++it ) { if ( !(*it).isEmpty() ) { command.append( "nmblookup " ); // We want all globally defined options for nmblookup, except // the broadcast address, because that is needed for the IP // scan: command.append( optionsHandler()->nmblookupOptions( false ) ); command.append( " -B "+*it+" -- '*' " ); command.append( "| sed -e /querying/d | awk '{print $1}' " ); command.append( "| xargs nmblookup " ); // This time we want to have the globally defined broadcast // address: command.append( optionsHandler()->nmblookupOptions() ); // Include the WINS server: command.append( !optionsHandler()->winsServer().isEmpty() ? " -R -U "+optionsHandler()->winsServer()+" " : "" ); command.append( " -A" ); command.append( " ; " ); continue; } else { continue; } } // Get rid of the last 3 characters (" ; "): command.truncate( command.length() - 3 ); *m_proc << command; startProcess( IPScan ); break; } default: { break; } } } /**************************************************************************** Scans for workgroup members. (private part) ****************************************************************************/ void Smb4KScanner::scanForWorkgroupMembers( const TQString &workgroup, const TQString &master, const TQString &ip ) { m_priv->setWorkgroup( workgroup ); m_priv->setHost( master ); m_priv->setIP( ip ); TQString command; if ( !ip.isEmpty() ) { command.append( "net "+optionsHandler()->netOptions( Smb4KSambaOptionsHandler::ServerDomain, TQString() ) ); command.append( " -I "+ip ); command.append( " -w "+TDEProcess::quote( workgroup ) ); command.append( " -S "+TDEProcess::quote( master ) ); Smb4KAuthInfo authInfo( workgroup, master, TQString() ); (void) passwordHandler()->readAuth( &authInfo ); if ( !authInfo.user().isEmpty() ) { command.append( TQString( " -U %1" ).arg( TDEProcess::quote( authInfo.user() ) ) ); if ( !authInfo.password().isEmpty() ) { m_proc->setEnvironment( "PASSWD", authInfo.password() ); } } else { command.append( " -U %" ); } } else { command.append( "net "+optionsHandler()->netOptions( Smb4KSambaOptionsHandler::LookupHost, TDEProcess::quote( master ) ) ); command.append( " -S "+TDEProcess::quote( master )+" -w "+TDEProcess::quote( workgroup )+" -U % " ); // FIXME: Maybe we need to know the shell if the user does not use a // sh-compatible one...? command.append( "| xargs -IIPADDR " ); command.append( getenv( "SHELL" ) ); command.append( " -c 'echo \"*** "+master+": IPADDR ***\" && " ); command.append( "net "+optionsHandler()->netOptions( Smb4KSambaOptionsHandler::ServerDomain, TQString() ) ); command.append( " -I IPADDR" ); command.append( " -w "+TDEProcess::quote( workgroup ) ); command.append( " -S "+TDEProcess::quote( master ) ); Smb4KAuthInfo authInfo( workgroup, master, TQString() ); (void) passwordHandler()->readAuth( &authInfo ); if ( !authInfo.user().isEmpty() ) { command.append( TQString( " -U %1'" ).arg( TDEProcess::quote( authInfo.user() ) ) ); if ( !authInfo.password().isEmpty() ) { m_proc->setEnvironment( "PASSWD", authInfo.password() ); } } else { command.append( " -U %'" ); } } *m_proc << command; startProcess( Hosts ); } /**************************************************************************** Scans for shares on a selected host. (private part) ****************************************************************************/ void Smb4KScanner::scanForShares( const TQString &workgroup, const TQString &host, const TQString &ip, const TQString &protocol ) { m_priv->setWorkgroup( workgroup ); m_priv->setHost( host ); m_priv->setIP( ip ); Smb4KAuthInfo *auth = passwordHandler()->readAuth( new Smb4KAuthInfo( workgroup, host, TQString() ) ); TQString command; command = TQString( "net %1 -w %2 -S %3" ).arg( optionsHandler()->netOptions( Smb4KSambaOptionsHandler::Share, host, protocol ) ).arg( TDEProcess::quote( workgroup ), TDEProcess::quote( host ) ); if ( !ip.isEmpty() ) { command.append( TQString( " -I %1" ).arg( TDEProcess::quote( ip ) ) ); } if ( !auth->user().isEmpty() ) { command.append( TQString( " -U %1" ).arg( TDEProcess::quote( auth->user() ) ) ); if ( !auth->password().isEmpty() ) { m_proc->setEnvironment( "PASSWD", auth->password() ); } } else { command.append( " -U guest%" ); } delete auth; *m_proc << command; startProcess( Shares ); } /**************************************************************************** Gets more info on a selected host. (private part) ****************************************************************************/ void Smb4KScanner::scanForInfo( const TQString &workgroup, const TQString &host, const TQString &ip ) { m_priv->setWorkgroup( workgroup ); m_priv->setHost( host ); m_priv->setIP( ip ); TQString smbclient_options = optionsHandler()->smbclientOptions(); TQString command = TQString( "smbclient -d1 -U guest% -W %1 -L %2" ).arg( TDEProcess::quote( workgroup ) ).arg( TDEProcess::quote( host ) ); if ( !ip.isEmpty() ) { command.append( TQString( " -I %1" ).arg( TDEProcess::quote( ip ) ) ); } if ( !smbclient_options.stripWhiteSpace().isEmpty() ) { command.append( smbclient_options ); } *m_proc << command; startProcess( Info ); } /**************************************************************************** Searches for a host. (private part) ****************************************************************************/ void Smb4KScanner::searchForHost( const TQString &host ) { // We need this because smbclient won't return the host name. KNetwork::KIpAddress ip_address = KNetwork::KIpAddress( host ); if ( Smb4KSettings::searchMethod() == Smb4KSettings::EnumSearchMethod::Smbclient && (ip_address.isIPv4Addr() || ip_address.isIPv6Addr()) ) { Smb4KError::error( ERROR_IP_CANNOT_BE_USED ); m_working = false; emit state( SCANNER_STOP ); return; } m_priv->setHost( host ); TQString wins = optionsHandler()->winsServer(); TQString nmblookup_options = optionsHandler()->nmblookupOptions(); TQString smbclient_options = optionsHandler()->smbclientOptions(); TQString command; switch ( Smb4KSettings::searchMethod() ) { case Smb4KSettings::EnumSearchMethod::Nmblookup: { command = TQString( "nmblookup" ); if ( !nmblookup_options.stripWhiteSpace().isEmpty() ) { command.append( nmblookup_options ); } if ( host.contains( '.', true ) != 3 ) { if ( !wins.isEmpty() ) { command.append( TQString( " -R -U %1 %2 -S | grep '<00>' | sed -e 's/<00>.*//'" ).arg( wins ).arg( m_priv->host() ) ); } else { command.append( TQString( " %1 -S | grep '<00>' | sed -e 's/<00>.*//'" ).arg( m_priv->host() ) ); } } else { if ( !wins.isEmpty() ) { command.append( TQString( " -R -U %1 %2 -A | grep '<00>' | sed -e 's/<00>.*//'" ).arg( wins ).arg( m_priv->host() ) ); } else { command.append( TQString( " %1 -A | grep '<00>' | sed -e 's/<00>.*//'" ).arg( m_priv->host() ) ); } } break; } case Smb4KSettings::EnumSearchMethod::Smbclient: { command = TQString( "smbclient -d2 -U % -L %1" ).arg( m_priv->host() ); if ( !smbclient_options.stripWhiteSpace().isEmpty() ) { command.append( smbclient_options ); } break; } default: { // Something went wrong. Stop here. return; } } *m_proc << command; startProcess( Search ); } /**************************************************************************** Starts the process of the scanner. ****************************************************************************/ void Smb4KScanner::startProcess( int state ) { m_state = state; m_buffer = TQString(); if ( state != Info ) { TQApplication::setOverrideCursor( waitCursor ); } m_proc->start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); } /**************************************************************************** End the process and tell, what to do with the data. ****************************************************************************/ void Smb4KScanner::endProcess() { switch ( m_state ) { case Workgroups: case QueryHost: processWorkgroups(); break; case IPScan: processIPScan(); break; case Hosts: processWorkgroupMembers(); break; case Shares: processShares(); break; case Info: processInfo(); break; case Search: processSearch(); break; default: break; } m_state = Idle; m_priv->clearData(); TQApplication::restoreOverrideCursor(); m_proc->clearArguments(); m_working = false; emit state( SCANNER_STOP ); } /**************************************************************************** Process the list of workgroups. ****************************************************************************/ void Smb4KScanner::processWorkgroups() { TQStringList list = TQStringList::split( '\n', m_buffer, false ); for ( TQValueList::Iterator it = m_workgroups_list->begin(); it != m_workgroups_list->end(); ++it ) { delete *it; } for ( TQValueList::Iterator it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it ) { delete *it; } m_workgroups_list->clear(); m_hosts_list->clear(); if ( m_state == Workgroups ) { TQString workgroup, master, ip; for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) { if ( (*it).stripWhiteSpace().startsWith( "Looking" ) ) { ip = (*it).section( "of", 1, 1 ).stripWhiteSpace(); continue; } else if ( (*it).contains( "<00>" ) != 0 && (*it).contains( "" ) == 0 ) { if ( workgroup.isEmpty() && master.isEmpty() && !ip.isEmpty() ) { master = (*it).section( "<00>", 0, 0 ).stripWhiteSpace(); } continue; } else if ( (*it).contains( "<00>" ) != 0 && (*it).contains( "" ) != 0 ) { if ( workgroup.isEmpty() && !master.isEmpty() && !ip.isEmpty() ) { workgroup = (*it).left( (*it).find( "<00>" ) ).stripWhiteSpace(); m_workgroups_list->append( new Smb4KWorkgroupItem( workgroup, master, ip ) ); Smb4KHostItem *master_item = new Smb4KHostItem( workgroup, master, TQString(), ip ); master_item->setMaster( true ); m_hosts_list->append( master_item ); workgroup = TQString(); master = TQString(); ip = TQString(); } continue; } } } else if ( m_state == QueryHost ) { bool process = false; for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) { TQString line = (*it).stripWhiteSpace(); if ( line.startsWith( "-------------" ) ) { process = true; continue; } if ( process && !line.isEmpty() ) { TQString workgroup = line.section( " ", 0, 0 ).stripWhiteSpace(); TQString master = line.section( " ", 1, -1 ).stripWhiteSpace(); m_workgroups_list->append( new Smb4KWorkgroupItem( workgroup, master, TQString() ) ); Smb4KHostItem *master_item = new Smb4KHostItem( workgroup, master ); master_item->setMaster( true ); m_hosts_list->append( master_item ); continue; } else { continue; } } } lookupIPAddresses(); emit workgroups( *m_workgroups_list ); emit hostListChanged(); } /**************************************************************************** Process the data from the IP range scan ****************************************************************************/ void Smb4KScanner::processIPScan() { TQStringList list = TQStringList::split( '\n', m_buffer, true ); for ( TQValueList::Iterator it = m_workgroups_list->begin(); it != m_workgroups_list->end(); ++it ) { delete *it; } for ( TQValueList::Iterator it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it ) { delete *it; } m_workgroups_list->clear(); m_hosts_list->clear(); // Process the data: for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if ( (*it).startsWith( "Looking up status of" ) ) { TQString workgroup, host, ip; bool master = false; // Get the IP address of this host. ip = (*it).section( "of", 1, 1 ).stripWhiteSpace(); // Loop through the data: for ( TQStringList::ConstIterator i = it; i != list.end(); ++i ) { if ( (*i).contains( " <00> " ) != 0 ) { if ( (*i).contains( " " ) != 0 ) { workgroup = (*i).section( "<00>", 0, 0 ).stripWhiteSpace(); } else { host = (*i).section( "<00>", 0, 0 ).stripWhiteSpace(); } continue; } else if ( (*i).contains( "__MSBROWSE__" ) != 0 && (*i).contains( " <01> " ) != 0 ) { master = true; continue; } else if ( (*i).contains( "MAC Address" ) != 0 || (*i).stripWhiteSpace().isEmpty() ) { it = i; break; } else { continue; } } if ( !workgroup.isEmpty() ) { Smb4KWorkgroupItem *workgroup_item = getWorkgroup( workgroup ); if ( workgroup_item ) { if ( master ) { workgroup_item->setMaster( host, ip ); } else { // Do nothing } } else { if ( master ) { m_workgroups_list->append( new Smb4KWorkgroupItem( workgroup, host, ip ) ); } else { m_workgroups_list->append( new Smb4KWorkgroupItem( workgroup, TQString(), TQString() ) ); } } Smb4KHostItem *host_item = new Smb4KHostItem( workgroup, host, TQString(), ip ); host_item->setMaster( master ); m_hosts_list->append( host_item ); } else { // Do nothing } } else { continue; } } // No extra lookup of IP addresses is needed since // we searched for IP addresses. :) emit workgroups( *m_workgroups_list ); emit members( m_priv->workgroup(), *m_hosts_list ); emit hostListChanged(); } /**************************************************************************** Process the member list of a workgroup. ****************************************************************************/ void Smb4KScanner::processWorkgroupMembers() { TQStringList list = TQStringList::split( '\n', m_buffer, false ); switch ( Smb4KSettings::browseList() ) { case Smb4KSettings::EnumBrowseList::LookupDomains: case Smb4KSettings::EnumBrowseList::QueryCurrentMaster: case Smb4KSettings::EnumBrowseList::QueryCustomMaster: { if ( m_buffer.contains( "NT_STATUS_ACCESS_DENIED" ) != 0 || m_buffer.contains( "NT_STATUS_LOGON_FAILURE" ) != 0 || m_buffer.contains( "The username or password was not correct" ) != 0 ) { // Authentication failed: emit failed(); if ( passwordHandler()->askpass( m_priv->workgroup(), m_priv->host(), TQString(), Smb4KPasswordHandler::AccessDenied, kapp->mainWidget() ? kapp->mainWidget() : 0, "AskPass" ) ) { m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4" ).arg( Hosts ).arg( m_priv->workgroup(), m_priv->host(), m_priv->ip() ) ) ); } return; } else if ( m_buffer.contains( "Could not connect to server" ) != 0 || m_buffer.contains( "Unable to find a suitable server" ) != 0 || m_buffer.contains( "Invalid ip address specified" ) != 0 ) { // If the IP address is empty, the shell output contains // the IP address. Remove it, because it will confuse // the user: if ( m_priv->ip().isEmpty() ) { list.remove( list.first() ); } // Notify the rest of the program, that something went wrong. emit failed(); // Notify the user: Smb4KError::error( ERROR_GETTING_MEMBERS, TQString(), list.join( "\n" ) ); return; } else { // Do nothing } TQValueList hosts; bool process = false; for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) { TQString line = (*it).stripWhiteSpace(); if ( !process ) { // Find the IP address in case we did not know it at the beginning // of the scan process and put it into m_priv.ip(): if ( m_priv->ip().isEmpty() && line.startsWith( "***" ) && line.endsWith( "***" ) ) { m_priv->setIP( line.section( ":", 1, 1 ).section( "***", 0, 0 ).stripWhiteSpace() ); continue; } // Find the line after that we will have to process the output // to get the servers belonging to this workgroup: if ( line.startsWith( "-------------" ) ) { process = true; continue; } continue; } else { if ( !line.isEmpty() ) { TQString host, comment; if ( line.contains( " " ) == 0 ) { host = line; } else { host = line.section( " ", 0, 0 ).stripWhiteSpace(); comment = line.section( " ", 1, -1 ).stripWhiteSpace(); } Smb4KHostItem *item = new Smb4KHostItem( m_priv->workgroup(), host, comment ); if ( TQString::compare( item->name(), m_priv->host() ) == 0 ) { // The item is identical to the master browser! Give the // respective workgroup item the IP address of the master // if it is not already present. Smb4KWorkgroupItem *workgroupItem = getWorkgroup( m_priv->workgroup() ); if ( workgroupItem && workgroupItem->masterIP().isEmpty() ) { workgroupItem->setMasterIP( m_priv->ip() ); } // Set the IP address for new item (we only know it at this point, // because this is the workgroup master): item->setIPAddress( m_priv->ip() ); // Set it to be the master: item->setMaster( true ); } hosts.append( item ); continue; } else { continue; } } } // If the list is empty, put the master in. if ( hosts.isEmpty() ) { Smb4KHostItem *item = new Smb4KHostItem( m_priv->workgroup(), m_priv->host() ); item->setMaster( true ); hosts.append( item ); } emit members( m_priv->workgroup(), hosts ); // Now put the hosts in m_hosts_list: for ( TQValueList::Iterator it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it ) { if ( TQString::compare( (*it)->workgroup(), m_priv->workgroup() ) == 0 ) { bool found = false; for ( TQValueList::Iterator i = hosts.begin(); i != hosts.end(); ++i ) { if ( *i && TQString::compare( (*i)->name(), (*it)->name() ) == 0 ) { found = true; // The only thing that might be missing is the comment. (*it)->setComment( (*i)->comment() ); delete *i; *i = NULL; break; } else { continue; } } if ( !found ) { delete *it; *it = NULL; } } else { continue; } } m_hosts_list->remove( NULL ); hosts.remove( NULL ); // Append the list: *m_hosts_list += hosts; // Lookup IP addresses. lookupIPAddresses(); break; } case Smb4KSettings::EnumBrowseList::ScanBroadcastAreas: { if ( m_buffer.contains( "NT_STATUS_ACCESS_DENIED" ) != 0 || m_buffer.contains( "NT_STATUS_LOGON_FAILURE" ) != 0 || m_buffer.contains( "The username or password was not correct" ) != 0 ) { // Authentication failed: emit failed(); if ( passwordHandler()->askpass( m_priv->workgroup(), m_priv->host(), TQString(), Smb4KPasswordHandler::AccessDenied, kapp->mainWidget() ? kapp->mainWidget() : 0, "AskPass" ) ) { m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4" ).arg( Hosts ).arg( m_priv->workgroup(), m_priv->host(), m_priv->ip() ) ) ); } return; } else if ( m_buffer.contains( "Could not connect to server" ) != 0 || m_buffer.contains( "Unable to find a suitable server" ) != 0 || m_buffer.contains( "Invalid ip address specified" ) != 0 ) { // We are in IP scan mode, so we can ignore the error and emit // what we already have: emit members( m_priv->workgroup(), *m_hosts_list ); emit hostListChanged(); return; } // We will not remove any host from the list in IP scan mode, // but we will add additional infomation, if available. bool process = false; for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if ( (*it).stripWhiteSpace().startsWith( "-------------" ) ) { process = true; continue; } if ( process && !(*it).stripWhiteSpace().isEmpty() ) { TQString line = (*it).stripWhiteSpace(); // Extract host name and comment: TQString host, comment; if ( line.contains( " " ) == 0 ) { host = line; } else { host = line.section( " ", 0, 0 ).stripWhiteSpace(); comment = line.section( " ", 1, -1 ).stripWhiteSpace(); } // Now add the comment to the host item or do nothing if // no comment was found: if ( !comment.isEmpty() ) { Smb4KHostItem *item = getHost( host, m_priv->workgroup() ); if ( item ) { item->setComment( comment ); } continue; } else { continue; } } } emit members( m_priv->workgroup(), *m_hosts_list ); break; } default: { break; } } emit hostListChanged(); } /**************************************************************************** Process the share list of a host. ****************************************************************************/ void Smb4KScanner::processShares() { // Error handling if ( m_buffer.contains( "The username or password was not correct.", true ) != 0 || m_buffer.contains( "NT_STATUS_ACCOUNT_DISABLED" ) != 0 /* Active Directory error */ ) { // Authentication failed: emit failed(); if ( passwordHandler()->askpass( m_priv->workgroup(), m_priv->host(), TQString(), Smb4KPasswordHandler::AccessDenied, kapp->mainWidget() ? kapp->mainWidget() : 0, "AskPass" ) ) { m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4:%5" ).arg( Shares ).arg( m_priv->workgroup(), m_priv->host(), m_priv->ip(), TQString() ) ) ); } return; } else if ( m_buffer.contains( "could not obtain sid for domain", true ) != 0 ) { // FIXME: Does this error only occur when we scan a server that is // only capable of the RAP protocol or also under other conditions? m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4:%5" ).arg( Shares ).arg( m_priv->workgroup(), m_priv->host(), m_priv->ip(), "rap" ) ) ); m_priv->retry = true; return; } else if ( (m_buffer.contains( "Could not connect to server", true ) != 0 && m_buffer.contains( "The username or password was not correct.", true ) == 0) || m_buffer.contains( "Unable to find a suitable server" ) != 0 ) { // We could not get the list of shares: emit failed(); // Notify the user: Smb4KError::error( ERROR_GETTING_SHARES, TQString(), m_buffer ); return; } TQStringList list = TQStringList::split( '\n', m_buffer, false ); TQValueList share_list; bool process = false; for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if ( (*it).startsWith( "---" ) ) { process = true; } if ( process ) { TQString name, type, comment; if ( (*it).contains( " Disk ", true ) != 0 ) { name = (*it).section( " Disk ", 0, 0 ).stripWhiteSpace(); type = "Disk"; comment = (*it).section( " Disk ", 1, 1 ).stripWhiteSpace(); } else if ( (*it).contains( " Print ", true ) != 0 ) { name = (*it).section( " Print ", 0, 0 ).stripWhiteSpace(); type = "Printer"; comment = (*it).section( " Print ", 1, 1 ).stripWhiteSpace(); } else if ( (*it).contains( " IPC ", true ) != 0 ) { name = (*it).section( " IPC ", 0, 0 ).stripWhiteSpace(); type = "IPC"; comment = (*it).section( " IPC ", 1, 1 ).stripWhiteSpace(); } else { continue; } share_list.append( new Smb4KShareItem( m_priv->workgroup(), m_priv->host(), name, type, comment ) ); } else { continue; } } emit shares( m_priv->host(), share_list ); } /**************************************************************************** Process the search data. ****************************************************************************/ void Smb4KScanner::processSearch() { // NOTE: We do not emit Smb4KScanner::failed() here, because // errors are handled in a different way by the search dialog. // Stop right here if the user searched for illegal // strings like #, ', () etc. if ( m_buffer.contains( "Usage:", true ) != 0 || m_buffer.contains( "/bin/sh:", true ) != 0 ) { emit searchResult( new Smb4KHostItem() ); return; } TQStringList data = TQStringList::split( '\n', m_buffer.stripWhiteSpace(), false ); switch ( Smb4KSettings::searchMethod() ) { case Smb4KSettings::EnumSearchMethod::Nmblookup: { if ( !data.isEmpty() ) { // The last entry in the list is the workgroup: TQString workgroup = data.last().stripWhiteSpace(); TQString host, ip; if ( m_priv->host().contains( ".", true ) != 3 ) { // The IP address is in the first entry: ip = data.first().stripWhiteSpace().section( " ", 0, 0 ); // The host. host = m_priv->host().upper(); } else { ip = m_priv->host(); host = data[0].stripWhiteSpace(); } emit searchResult( new Smb4KHostItem( workgroup, host, TQString(), ip ) ); } else { emit searchResult( new Smb4KHostItem() ); } break; } case Smb4KSettings::EnumSearchMethod::Smbclient: { if ( data.count() > 1 && !data[1].isEmpty() ) { if ( m_buffer.contains( TQString( "Connection to %1 failed" ).arg( m_priv->host() ) ) != 0 ) { emit searchResult( new Smb4KHostItem() ); } else { TQString workgroup = data.grep( "Domain" ).first().section( "Domain=[", 1, 1 ).section( "]", 0, 0 ); TQString ip = data.grep( "Got a positive name query" ).first().section( "(", 1, 1 ).section( ")", 0, 0 ).stripWhiteSpace(); emit searchResult( new Smb4KHostItem( workgroup, m_priv->host().upper(), TQString(), ip ) ); } } else { emit searchResult( new Smb4KHostItem() ); } break; } default: { break; } } } /**************************************************************************** Process the information about a host. ****************************************************************************/ void Smb4KScanner::processInfo() { if ( m_proc->normalExit() ) { TQStringList list = TQStringList::split( '\n', m_buffer, false ); Smb4KHostItem *host = getHost( m_priv->host(), m_priv->workgroup() ); if ( host ) { for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if ( (*it).stripWhiteSpace().startsWith( "Domain" ) || (*it).stripWhiteSpace().startsWith( "OS" ) ) { // The OS string. host->setOSString( (*it).section( "OS=[", 1, 1 ).section( "]", 0, 0 ).stripWhiteSpace() ); // The Server string. host->setServerString( (*it).section( "Server=[", 1, 1 ).section( "]", 0, 0 ).stripWhiteSpace() ); break; } else if ( (*it).contains( "Connection to", true ) != 0 ) { // The lookup of the info failed: emit failed(); break; } } emit info( host ); } } else { // In case the process was aborted, we need to enable checking // again: Smb4KHostItem *host = getHost( m_priv->host(), m_priv->workgroup() ); if ( host ) { host->setInfoChecked( false ); } } } /**************************************************************************** Get a workgroup item out of the workgroup list. ****************************************************************************/ Smb4KWorkgroupItem *Smb4KScanner::getWorkgroup( const TQString &workgroup ) { TQValueListIterator it; for ( it = m_workgroups_list->begin(); it != m_workgroups_list->end(); ++it ) { if ( TQString::compare( (*it)->name(), workgroup ) == 0 ) { break; } else { continue; } } return it == m_workgroups_list->end() ? NULL : *it; } /**************************************************************************** Get a workgroup item out of the workgroup list. ****************************************************************************/ Smb4KHostItem *Smb4KScanner::getHost( const TQString &name, const TQString &workgroup ) { TQValueListIterator it; for ( it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it ) { if ( !workgroup.stripWhiteSpace().isEmpty() && TQString::compare( (*it)->workgroup().upper(), workgroup.upper() ) != 0 ) { continue; } if ( TQString::compare( (*it)->name().upper(), name.upper() ) == 0 ) { break; } else { continue; } } return it == m_hosts_list->end() ? NULL : *it; } /**************************************************************************** Add a host to the host list ****************************************************************************/ void Smb4KScanner::insertHost( Smb4KHostItem *host ) { if ( host && !getHost( host->name(), host->workgroup() ) ) { // Use the copy constructor here, so that we do not run into // trouble when/if host is deleted. Smb4KHostItem *host_item = new Smb4KHostItem( *host ); m_hosts_list->append( host_item ); // Check if the workgroup is already known. If not, create a new Smb4KWorkgroupItem, // declare the host a pseudo master and add the workgroup to the list. if ( !getWorkgroup( host_item->workgroup() ) ) { Smb4KWorkgroupItem *workgroup_item = new Smb4KWorkgroupItem( host_item->workgroup(), host_item->name(), host_item->ip() ); workgroup_item->setPseudoMaster(); host_item->setMaster( true ); // pseudo master appendWorkgroup( workgroup_item ); } // Lookup at least the IP address of this host, if necessary: if ( host_item->ip().isEmpty() ) { lookupIPAddresses(); } emit hostAdded( host_item ); emit hostListChanged(); } } /**************************************************************************** Appends an item to the list of workgroups. ****************************************************************************/ void Smb4KScanner::appendWorkgroup( Smb4KWorkgroupItem *item ) { if ( !getWorkgroup( item->name() ) ) { m_workgroups_list->append( item ); emit workgroups( *m_workgroups_list ); } } void Smb4KScanner::timerEvent( TQTimerEvent * ) { // Look for the thing to do (next). // At this point, the topmost item will not be // dequeued. This will be done below. int todo = Idle; TQString *head = NULL; if ( (head = m_queue.head()) != 0 ) { todo = head->section( ":", 0, 0 ).toInt(); } if ( !m_working && !m_queue.isEmpty() ) { // Start processing with dequeueing the item: TQString *item = m_queue.dequeue(); // Tell the program, that the scanner is running. m_working = true; switch ( todo ) { case Init: { emit state( SCANNER_INIT ); scanNetwork(); break; } case Hosts: { emit state( SCANNER_OPENING_WORKGROUP ); scanForWorkgroupMembers( item->section( ":", 1, 1 ), item->section( ":", 2, 2 ), item->section( ":", 3, 3 ) ); break; } case Shares: { if ( !m_priv->retry ) { emit state( SCANNER_OPENING_HOST ); } else { emit state( SCANNER_RETRYING_OPENING_HOST ); m_priv->retry = false; } scanForShares( item->section( ":", 1, 1 ), item->section( ":", 2, 2 ), item->section( ":", 3, 3 ), item->section( ":", 4, 4 ) ); break; } case Info: { emit state( SCANNER_RETRIEVING_INFO ); scanForInfo( item->section( ":", 1, 1 ), item->section( ":", 2, 2 ), item->section( ":", 3, 3 ) ); break; } case Search: { emit state( SCANNER_SEARCHING ); searchForHost( item->section( ":", 1, 1 ) ); break; } default: break; } delete item; } } ///////////////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATIONS ///////////////////////////////////////////////////////////////////////////// /**************************************************************************** Internal slots. ****************************************************************************/ void Smb4KScanner::slotReceivedStdout( TDEProcess *, char *buf, int len ) { m_buffer.append( TQString::fromLocal8Bit( buf, len ) ); } void Smb4KScanner::slotProcessExited( TDEProcess * ) { endProcess(); } void Smb4KScanner::slotReceivedStderr( TDEProcess *, char *buf, int len ) { m_buffer.append( TQString::fromLocal8Bit( buf, len ) ); } /*************************************************************************** * * * Lookup for IP addresses * * * ***************************************************************************/ /**************************************************************************** Start the scanning for IP addresses ****************************************************************************/ void Smb4KScanner::lookupIPAddresses() { bool start = false; TQString command = TQString(); for ( TQValueList::ConstIterator it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it ) { if ( (*it)->ip().stripWhiteSpace().isEmpty() && !(*it)->ipAddressChecked() ) { if ( !start ) { start = true; } (*it)->setIPAddressChecked( true ); command.append( "nmblookup" ); command.append( optionsHandler()->nmblookupOptions() ); command.append( optionsHandler()->winsServer().isEmpty() ? "" : " -R -U "+TDEProcess::quote( optionsHandler()->winsServer() ) ); command.append( " -- "+TDEProcess::quote( (*it)->name() )+" | grep '<00>'" ); command.append( " ; " ); continue; } else { continue; } } command.truncate( command.length() - 3 ); if ( start ) { TDEProcess *proc = new TDEProcess( this ); proc->setUseShell( true ); connect( proc, TQ_SIGNAL( receivedStdout( TDEProcess *, char *, int ) ), this, TQ_SLOT( slotReceivedIPAddresses( TDEProcess *, char *, int ) ) ); connect( proc, TQ_SIGNAL( processExited( TDEProcess * ) ), this, TQ_SLOT( slotIPAddressProcessExited( TDEProcess * ) ) ); *proc << command; proc->start( TDEProcess::NotifyOnExit, TDEProcess::Stdout ); } } /**************************************************************************** Processes IP addresses if data occurrs on stdout. ****************************************************************************/ void Smb4KScanner::slotReceivedIPAddresses( TDEProcess *, char *buf, int len ) { // WARNING: Do not implement error handling here!!! TQString buffer = TQString::fromLocal8Bit( buf, len ); if ( !buffer.stripWhiteSpace().isEmpty() ) { TQString ip = buffer.stripWhiteSpace().section( " ", 0, 0 ).stripWhiteSpace(); TQString host = buffer.stripWhiteSpace().section( " ", 1, 1 ).section( "<00>", 0, 0 ).stripWhiteSpace(); if ( !host.isEmpty() && !ip.isEmpty() ) { Smb4KHostItem *item = getHost( host ); if ( item ) { item->setIPAddress( ip ); if ( item->isMaster() ) { Smb4KWorkgroupItem *workgroup = getWorkgroup( item->workgroup() ); if ( workgroup ) { workgroup->setMasterIP( ip ); } } emit ipAddress( item ); } } } } /**************************************************************************** End IP address scan. ****************************************************************************/ void Smb4KScanner::slotIPAddressProcessExited( TDEProcess *p ) { delete p; } #include "smb4kscanner.moc"