From 838ff633aa9a3d8f0add86e7e9c284c61f8fe385 Mon Sep 17 00:00:00 2001 From: dkgroot Date: Sat, 26 Jun 2021 23:19:53 +0000 Subject: [PATCH] Reverse the logic when detecting tftpserver existence and path - write a sentinel probe file to the known/possible distro tftp directories - try fetching it through tftp - if we manage to fetch the file, we have the correct path - remove sentinel probe file When creating directories in tftpboot directory we should not set write permissions, using 0755 instead. --- install.php | 51 ++++++++++++++++++----------- sccpManClasses/extconfigs.class.php | 4 +-- sccpManTraits/helperFunctions.php | 43 ++++++++++++------------ 3 files changed, 56 insertions(+), 42 deletions(-) diff --git a/install.php b/install.php index 2cc2026..b0fc79d 100644 --- a/install.php +++ b/install.php @@ -1,4 +1,4 @@ -ASget('ASTETCDIR'); - // TODO: add option to use external server - $remoteFile = "TestFileXXX111.txt"; // should not exist - $thisInstaller->tftp_put_test_file(); + $tftpRootPath = ""; + // TODO: add option to use external server + $remoteFileName = ".sccp_manager_installer_probe_sentinel_temp".mt_rand(0, 9999999); + $remoteFileContent = "# This is a test file created by Sccp_Manager. It can be deleted without impact"; $possibleFtpDirs = array('/srv', '/srv/tftp','/var/lib/tftp', '/tftpboot'); + + // write a couple of sentinels to different distro tftp locations in the filesystem foreach ($possibleFtpDirs as $dirToTest) { - if (file_exists("{$dirToTest}/{$remoteFile}")) { - $tftpRootPath = $dirToTest; - unlink("{$dirToTest}/{$remoteFile}"); - outn("
  • " . _("Found ftp root dir at {$dirToTest}") . "
  • "); - if ($settingsFromDb['tftp_path']['data'] != $tftpRootPath) { - $settingsToDb["tftp_path"] =array( 'keyword' => 'tftp_path', 'seq' => 2, 'type' => 0, 'data' => $tftpRootPath); - // Need to set the new value here to pass to extconfigs below - $settingsFromDb['tftp_path']['data'] = $tftpRootPath; + if (is_dir($dirToTest) && is_writable($dirToTest) && empty($tftpRootPath)) { + $tempFile = "${dirToTest}/{$remoteFileName}"; + $FH = fopen($tempFile, "w"); + if ($FH == null) { + continue; + } + fwrite($FH, $remoteFileContent); + fclose($FH); + + // try to pull the written file through tftp. + // this way we can determine if tftp server is active, and what it's + // source directory is. + if ($remoteFileContent == $thisInstaller->tftpReadTestFile($remoteFileName)) { + $tftpRootPath = $dirToTest; + outn("
  • " . _("Found ftp root dir at {$tftpRootPath}") . "
  • "); + if ($settingsFromDb['tftp_path']['data'] != $tftpRootPath) { + $settingsToDb["tftp_path"] = array( 'keyword' => 'tftp_path', 'seq' => 2, 'type' => 0, 'data' => $tftpRootPath); + // Need to set the new value here to pass to extconfigs below + $settingsFromDb['tftp_path']['data'] = $tftpRootPath; + } + } + // remove all sentinel file + if (file_exists($tempFile)) { + unlink($tempFile); } - break; } } - if (empty($tftpRootPath)) { die_freepbx(_("Either TFTP server is down or TFTP root is non standard. Please fix, refresh, and try again")); } - if (!is_writeable($tftpRootPath)) { - die_freepbx(_("{$tftpRootPath} is not writable by user asterisk. Please fix, refresh and try again")); - } - + $settingsToDb['asterisk_etc_path'] =array( 'keyword' => 'asterisk_etc_path', 'seq' => 20, 'type' => 0, 'data' => $confDir); foreach ($settingsToDb as $settingToSave) { @@ -933,7 +947,6 @@ function checkTftpServer() { die_freepbx(_("Error updating sccpsettings. $sql")); } } - return; } diff --git a/sccpManClasses/extconfigs.class.php b/sccpManClasses/extconfigs.class.php index c0b01fa..6e95fba 100644 --- a/sccpManClasses/extconfigs.class.php +++ b/sccpManClasses/extconfigs.class.php @@ -326,8 +326,8 @@ class extconfigs $base_config[$key] = $adv_config[$value]; // Save to sccpsettings $settingsToDb[$key] =array( 'keyword' => $key, 'seq' => 20, 'type' => 0, 'data' => $adv_config[$value]); - if (!file_exists($base_config[$key])) { - if (!mkdir($base_config[$key], 0777, true)) { + if (!is_dir($base_config[$key])) { + if (!mkdir($base_config[$key], 0755, true)) { die_freepbx(_('Error creating dir : ' . $base_config[$key])); } } diff --git a/sccpManTraits/helperFunctions.php b/sccpManTraits/helperFunctions.php index 7ff9ba5..dfa88ec 100644 --- a/sccpManTraits/helperFunctions.php +++ b/sccpManTraits/helperFunctions.php @@ -161,34 +161,35 @@ trait helperfunctions { return $result; } - public function tftp_put_test_file() + function tftpReadTestFile($remoteFileName) { // https://datatracker.ietf.org/doc/html/rfc1350 $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); - $host = "127.0.0.1"; // TODO: Should consider remote TFT Servers in future + if ($socket) { + $host = "127.0.0.1"; // TODO: Should consider remote TFT Servers in future + $port = 69; - // create the WRQ request packet - $packet = chr(0) . chr(2) . "TestFileXXX111.txt" . chr(0) . 'netascii' . chr(0); - // UDP is connectionless, so we just send it. - socket_sendto($socket, $packet, strlen($packet), MSG_EOR, $host, 69); + // create the RRQ request packet + $packet = chr(0) . chr(1) . $remoteFileName . chr(0) . 'netascii' . chr(0); + // UDP is connectionless, so we just send it. + socket_sendto($socket, $packet, strlen($packet), MSG_EOR, $host, $port); - $buffer = ''; - $port = ''; - $ret = ''; + $buffer = null; + $port = ""; + $ret = ""; - // Should now receive an ack packet - socket_recvfrom($socket, $buffer, 4, MSG_PEEK, $host, $port); + // fetch file content + $numbytes = socket_recvfrom($socket, $buffer, 84, MSG_WAITALL, $host, $port); + + // unpack the returned buffer and discard the first two bytes + $pkt = unpack("n2/a*data", $buffer); - // Then should send our data packet - $packet = chr(0) . chr(3) . chr(0) . chr(1) . 'This is a test file created by Sccp_Manager. It can be deleted without any impact'; - socket_sendto($socket, $packet, strlen($packet), MSG_EOR, $host, $port); - - // finally will recieve an ack packet - socket_recvfrom($socket, $buffer, 4, MSG_PEEK, $host, $port); - - socket_close($socket); - - return; + socket_close($socket); + if ($numbytes) { + return $pkt["data"]; + } + } + return false; } public function initVarfromXml() {