Пример #1
0
Файл: ftp.php Проект: rair/yacs
 /**
  * login
  *
  * The script checks provided name and password against remote server.
  *
  * This is done by transmitting the user name and the password
  * while opening a FTP session to the server.
  *
  * @param string the nickname of the user
  * @param string the submitted password
  * @return TRUE on succesful authentication, FALSE othewise
  */
 function login($name, $password)
 {
     global $context;
     // we need some parameters
     if (!isset($this->attributes['authenticator_parameters']) || !$this->attributes['authenticator_parameters']) {
         Logger::error(i18n::s('Please provide parameters to the authenticator.'));
         return FALSE;
     }
     // prepare network parameters
     $server = $this->attributes['authenticator_parameters'];
     if (strstr($server, ':')) {
         list($server, $port) = explode(':', $server, 2);
     } else {
         $port = 21;
     }
     // open network socket
     if (!($handle = Safe::fsockopen($server, $port))) {
         Logger::error(sprintf(i18n::s('Impossible to connect to %.'), $this->attributes['authenticator_parameters']));
         return FALSE;
     }
     // read welcome banner
     if (!($line = fgets($handle, 256)) || !strstr($line, '2')) {
         fclose($handle);
         Logger::error(sprintf(i18n::s('Invalid banner message from %s.'), $this->attributes['authenticator_parameters']));
         return FALSE;
     }
     // submit name
     fputs($handle, "USER {$username}\r\n");
     if (!($line = fgets($handle, 256)) || !strstr($line, '3')) {
         fclose($handle);
         Logger::error(sprintf(i18n::s('Impossible to submit name to %s.'), $this->attributes['authenticator_parameters']));
         return FALSE;
     }
     // submit password
     fputs($handle, "PASS {$password}\r\n");
     if (!($line = fgets($handle, 256)) || !strstr($line, '2')) {
         fclose($handle);
         Logger::error(sprintf(i18n::s('Impossible to submit password to %s.'), $this->attributes['authenticator_parameters']));
         return FALSE;
     }
     // close ftp session
     fputs($handle, "QUIT\r\n");
     fclose($handle);
     // this is a valid user
     return TRUE;
 }
Пример #2
0
 /**
  * attempt to use the trackback interface
  *
  * @param string some text, extracted from the target site, to extract the broker URL, if any
  * @param string the source address
  * @param string the target address from which the text has been extracted
  * @param string title of the source page
  * @param string excerpt of the source page
  * @param string blog name of the source page
  * @return TRUE if the target site has been pinged back, FALSE otherwise
  *
  * @link http://www.movabletype.org/docs/mttrackback.html TrackBack Technical Specification
  */
 public static function ping_as_trackback($text, $source, $target, $title = '', $excerpt = '', $blog_name = '')
 {
     global $context;
     // extract all rdf blocks
     preg_match_all('/<rdf:RDF(.*)<\\/rdf:RDF>/iUs', $text, $blocks);
     // nothing to do
     if (!@count($blocks[1])) {
         return FALSE;
     }
     // look for the broker
     $broker = array();
     foreach ($blocks[1] as $block) {
         // seek the trackback interface
         if (!preg_match('/(dc:identifier|about)="' . preg_quote($target, '/') . '/mi', $block)) {
             continue;
         }
         // extract the broker link
         if (preg_match('/trackback:ping="([^"]+)"/mi', $block, $broker)) {
             break;
         }
     }
     // trackback interface not supported at this page
     if (!isset($broker[1])) {
         return FALSE;
     }
     // parse the broker URL
     $items = @parse_url($broker[1]);
     // no host, assume it's us
     if (!($host = $items['host'])) {
         $host = $context['host_name'];
     }
     // no port, assume the standard
     if (!isset($items['port']) || !($port = $items['port'])) {
         $port = 80;
     }
     // outbound web is not authorized
     if (isset($context['without_outbound_http']) && $context['without_outbound_http'] == 'Y') {
         if (isset($context['debug_trackback']) && $context['debug_trackback'] == 'Y') {
             Logger::remember('links/links.php: Links::ping_as_trackback()', 'Outbound HTTP is not authorized.', 'debug');
         }
         return FALSE;
     }
     // connect to the server
     if (!($handle = Safe::fsockopen($host, $port, $errno, $errstr, 30))) {
         if (isset($context['debug_trackback']) && $context['debug_trackback'] == 'Y') {
             Logger::remember('links/links.php: Links::ping_as_trackback()', sprintf('Impossible to connect to %s.', $host . ':' . $port), 'debug');
         }
         return FALSE;
     }
     // ensure enough execution time
     Safe::set_time_limit(30);
     // build the path, including any query
     $path = $items['path'];
     if (isset($items['query']) && $items['query']) {
         $path .= '?' . $items['query'];
     }
     // encode the content
     $data = 'title=' . urlencode($title) . '&url=' . urlencode($source) . '&excerpt=' . urlencode($excerpt) . '&blog_name=' . urlencode($blog_name);
     $headers = 'Content-Type: application/x-www-form-urlencoded' . CRLF . 'Content-Length: ' . strlen($data) . CRLF;
     // actual trackback, through HTTP POST
     $request = "POST " . $path . " HTTP/1.0" . CRLF . 'Host: ' . $host . CRLF . "User-Agent: YACS (www.yacs.fr)" . CRLF . "Connection: close" . CRLF . $headers . CRLF . $data;
     // save the request if debug mode
     if (isset($context['debug_trackback']) && $context['debug_trackback'] == 'Y') {
         Logger::remember('links/links.php: Links::ping_as_trackback() request', str_replace("\r\n", "\n", $request), 'debug');
     }
     // submit the request
     fputs($handle, $request);
     // we are interested only in the very first bytes of the response
     $code = fread($handle, 15);
     fclose($handle);
     // save the response if debug mode
     if (isset($context['debug_trackback']) && $context['debug_trackback'] == 'Y') {
         Logger::remember('links/links.php: Links::ping_as_trackback() response', $code . '...', 'debug');
     }
     // check HTTP status
     if (!preg_match('/^HTTP\\/[0-9\\.]+ 200/', $code)) {
         return FALSE;
     }
     // successful trackback
     if (isset($context['debug_trackback']) && $context['debug_trackback'] == 'Y') {
         Logger::remember('links/links.php: Links::ping_as_trackback() success', $broker[1], 'debug');
     }
     return TRUE;
 }
Пример #3
0
Файл: link.php Проект: rair/yacs
 /**
  * validate a link
  *
  * This function submits a HTTP request to the target server to check that the page actually exists
  *
  * @param the link to validate
  * @return A date if Last-Modified has been provided, or TRUE if the link is reachable, FALSE otherwise
  */
 function validate($url)
 {
     global $context;
     // parse this url
     $items = @parse_url($url);
     // assume the link is correct if not http
     if ($items['scheme'] && $items['scheme'] != 'http') {
         return TRUE;
     }
     // no host, assume it's us
     if (!($host = $items['host'])) {
         $host = $context['host_name'];
     }
     // sometime parse_url() adds a '_'
     $host = rtrim($host, '_');
     // no port, assume the standard
     if (!($port = $items['port'])) {
         $port = 80;
     }
     // assume the link is correct when outbound web is not authorized
     if (isset($context['without_outbound_http']) && $context['without_outbound_http'] == 'Y') {
         return TRUE;
     }
     // open a network connection -- wait for up to 10 seconds for the TCP connection
     if (!($handle = Safe::fsockopen($host, $port, $errno, $errstr, 10))) {
         if ($context['with_debug'] == 'Y') {
             logger::remember('links/link.php: ' . $host . ':' . $port . ' is not reachable', $url, 'debug');
         }
         return FALSE;
     }
     // ensure enough execution time
     Safe::set_time_limit(30);
     // build the path
     $path = $items['path'];
     if (!$path) {
         $path = '/';
     }
     // sometime parse_url() adds a '_'
     $path = rtrim($path, '_');
     // include any query
     if ($items['query']) {
         $path .= '?' . $items['query'];
     }
     // send an HTTP request
     fputs($handle, 'HEAD ' . $path . " HTTP/1.0" . CRLF . 'Host: ' . $host . CRLF . "User-Agent: YACS (www.yacs.fr)" . CRLF . "Connection: close" . CRLF . CRLF);
     // we are interested into the header only
     $response = '';
     while (!feof($handle) && strlen($response) < 5242880) {
         // ask for Ethernet-sized chunks
         $chunk = fread($handle, 1500);
         // split on headers boundary
         $here = strpos($chunk, CRLF . CRLF);
         if ($here !== FALSE) {
             $chunk = substr($chunk, 0, $here);
             $response .= $chunk;
             break;
         }
         // gather header information
         $response .= $chunk;
     }
     fclose($handle);
     // split headers into lines
     $lines = explode(CRLF, $response);
     // ensure we have a valid HTTP status line
     if (!preg_match('/^HTTP\\/[0-9\\.]+ 20\\d /', $lines[0])) {
         if ($context['with_debug'] == 'Y') {
             logger::remember('links/link.php: bad status: ' . $lines[0], $url, 'debug');
         }
         return FALSE;
     }
     // scan lines for "Last-Modified" header
     foreach ($lines as $line) {
         if (preg_match('/^Last-Modified: (.*?)/', $line, $matches)) {
             // return the stamp for this link
             return date("Y-m-d H:i:s", strtotime($matches[1]));
         }
     }
     // no date, but the link has been validated anyway
     return TRUE;
 }
Пример #4
0
Файл: call.php Проект: rair/yacs
 /**
  * get a list of remote resources
  *
  * This function performs a REST call against a web services that provides a RSS-encoded response.
  *
  * Minimum example:
  * [php]
  * $result = Call::list_resources($url);
  * if(!$result[0])
  *	echo $result[1]; // error message
  * else
  *	... // use call result from $result[1]
  * [/php]
  *
  * @param string the url to use
  * @param array the parameters to transmit
  * @return an array of which the first value indicates call success or failure
  *
  * @see search.php
  */
 public static function list_resources($url, $parameters = NULL)
 {
     global $context;
     // encode the request
     $data = '';
     foreach ($parameters as $label => $value) {
         if ($data) {
             $data .= '&';
         }
         $data .= urlencode($label) . '=' . urlencode($value);
     }
     $headers = '';
     $headers .= 'Content-Type: application/x-www-form-urlencoded' . CRLF;
     $headers .= 'Content-Length: ' . strlen($data) . CRLF;
     // parse the target URL
     $items = @parse_url($url);
     // no host, assume it's us
     if (!($host = $items['host'])) {
         $host = $context['host_name'];
     }
     // no port, assume the standard
     if (!isset($items['port']) || !($port = $items['port'])) {
         $port = 80;
     }
     // outbound web is not authorized
     if (isset($context['without_outbound_http']) && $context['without_outbound_http'] == 'Y') {
         return array(FALSE, 'Outbound HTTP is not authorized.');
     }
     // connect to the server
     if (!($handle = Safe::fsockopen($host, $port, $errno, $errstr, 30))) {
         return array(FALSE, sprintf('Impossible to connect to %s.', $host . ':' . $port));
     }
     // ensure enough execution time
     Safe::set_time_limit(30);
     // build the path, including any query
     $path = $items['path'];
     if ($items['query']) {
         $path .= '?' . $items['query'];
     }
     // build an HTTP request
     $request = "POST " . $path . " HTTP/1.0" . CRLF . 'Host: ' . $host . CRLF . "Accept-Encoding: gzip" . CRLF . "User-Agent: YACS (www.yacs.fr)" . CRLF . "Connection: close" . CRLF . $headers . CRLF . $data;
     // save the request if debug mode
     if ($context['debug_call'] == 'Y') {
         Logger::remember('services/call.php: Call::list_resources() request', str_replace("\r\n", "\n", $request), 'debug');
     }
     // submit the request
     fputs($handle, $request);
     // get everything by Ethernet-sized chunks
     $response = '';
     while (!feof($handle) && strlen($response) < 5242880) {
         $response .= fread($handle, 1500);
     }
     fclose($handle);
     // ensure we have a valid HTTP status line
     if (preg_match('/^HTTP/', $response) && !preg_match('/^HTTP\\/[0-9\\.]+ 200 /', $response)) {
         $lines = explode("\n", $response, 2);
         return array(FALSE, 'Unexpected HTTP status "' . $lines[0] . '"');
     }
     // separate headers from body
     list($headers, $content) = explode(CRLF . CRLF, $response, 2);
     // uncompress payload if necessary
     if (preg_match('/Content-Encoding: \\s*gzip/i', $headers)) {
         $content = gzinflate(substr($content, 10));
     }
     // save the response if debug mode
     if ($context['debug_call'] == 'Y') {
         Logger::remember('services/call.php: Call::list_resources() response', str_replace("\r\n", "\n", $headers . "\n\n" . $content), 'debug');
     }
     // we understand only text responses
     if (!preg_match('/^Content-Type: text/m', $headers)) {
         return array(FALSE, 'Impossible to process not-textual response');
     }
     // passthrough if not xml
     if (!preg_match('/^Content-Type: text\\/xml/m', $headers)) {
         return $content;
     }
     // select a codec handler
     include_once $context['path_to_root'] . 'services/codec.php';
     include_once $context['path_to_root'] . 'services/rss_codec.php';
     $codec = new RSS_Codec();
     if (!is_object($codec)) {
         return array(FALSE, 'Impossible to load codec RSS_Codec');
     }
     // decode the result
     return $codec->import_response($content, $headers, $parameters);
 }
Пример #5
0
 /**
  * process all messages from one mailbox
  *
  * This is original code compliant to RFC 1939 for the authentication,
  * fetching and processing of messages queued in a POP3 mailbox.
  *
  * @param array of mailbox attributes ($server, $account, $password)
  * @return the number of processed messages
  */
 public static function process_queue($queue)
 {
     global $context;
     // useless if we don't have a valid database connection
     if (!$context['connection']) {
         return 0;
     }
     // make queue parameters available
     $context['mail_queue'] = $queue;
     // use queue parameters to connect to the server
     list($server, $account, $password, $allowed, $match, $section, $options, $hooks, $prefix, $suffix) = $queue;
     // no host, assume it's us
     if (!$server) {
         $server = $context['host_name'];
     }
     // assume the standard pop3 socket
     $port = 110;
     // use alternate port if required to do so
     if (preg_match('/^(.+):([0-9]+)$/', $server, $matches)) {
         $server = $matches[1];
         $port = intval($matches[2]);
     }
     // ensure that we can support tls communications
     if (isset($server) && !strncmp($server, 'ssl://', 6) && is_callable('extension_loaded') && !extension_loaded('openssl')) {
         Logger::remember('agents/messages.php: Load the OpenSSL extension to support secured transmissions to mail server ' . $server);
         return 0;
     }
     // open a network connection
     if (!($handle = Safe::fsockopen($server, $port, $errno, $errstr, 10))) {
         Logger::remember('agents/messages.php: ' . sprintf('Impossible to connect to %s', $server));
         return 0;
     }
     // ensure enough execution time
     Safe::set_time_limit(30);
     // get server banner
     if (($reply = fgets($handle)) === FALSE) {
         Logger::remember('agents/messages.php: Impossible to get banner of ' . $server);
         fclose($handle);
         return 0;
     }
     if ($context['debug_messages'] == 'Y') {
         Logger::remember('agents/messages.php: POP <-', rtrim($reply), 'debug');
     }
     // expecting an OK
     if (strncmp($reply, '+OK', 3)) {
         Logger::remember('agents/messages.php: Mail service is closed at ' . $server, rtrim($reply));
         fclose($handle);
         return 0;
     }
     // maybe the server accepts APOP
     $stamp = '';
     if (preg_match('/<.+@.+>/U', $reply, $matches)) {
         $stamp = $matches[0];
     }
     // we will go with APOP, only if explicitly allowed
     $authenticated = FALSE;
     if ($stamp && preg_match('/\\bwith_apop\\b/i', $options)) {
         // the digest
         if ($context['debug_messages'] == 'Y') {
             Logger::remember('agents/messages.php: POP stamp', $stamp . $password, 'debug');
         }
         $hash = md5($stamp . $password);
         // send user name and hash
         $request = 'APOP ' . $account . ' ' . $hash;
         fputs($handle, $request . CRLF);
         if ($context['debug_messages'] == 'Y') {
             Logger::remember('agents/messages.php: POP ->', $request, 'debug');
         }
         // expecting an OK
         if (($reply = fgets($handle)) === FALSE) {
             Logger::remember('agents/messages.php: No reply to APOP command at ' . $server);
             fclose($handle);
             return 0;
         }
         if ($context['debug_messages'] == 'Y') {
             Logger::remember('agents/messages.php: POP <-', rtrim($reply), 'debug');
         }
         if (strncmp($reply, '+OK', 3)) {
             Logger::remember('agents/messages.php: Impossible to authenticate account ' . $account . ' at ' . $server, rtrim($reply));
         } else {
             $authenticated = TRUE;
         }
     }
     // we will transmit the password in clear
     if (!$authenticated) {
         // send user name
         $request = 'USER ' . $account;
         fputs($handle, $request . CRLF);
         if ($context['debug_messages'] == 'Y') {
             Logger::remember('agents/messages.php: POP ->', $request, 'debug');
         }
         // expecting an OK
         if (($reply = fgets($handle)) === FALSE) {
             Logger::remember('agents/messages.php: No reply to USER command at ' . $server);
             fclose($handle);
             return 0;
         }
         if ($context['debug_messages'] == 'Y') {
             Logger::remember('agents/messages.php: POP <-', rtrim($reply), 'debug');
         }
         if (strncmp($reply, '+OK', 3)) {
             Logger::remember('agents/messages.php: Unknown account ' . $account . ' at ' . $server, rtrim($reply));
             fclose($handle);
             return 0;
         }
         // send password
         $request = 'PASS ' . $password;
         fputs($handle, $request . CRLF);
         if ($context['debug_messages'] == 'Y') {
             Logger::remember('agents/messages.php: POP ->', $request, 'debug');
         }
         // expecting an OK
         if (($reply = fgets($handle)) === FALSE) {
             Logger::remember('agents/messages.php: No reply to PASS command at ' . $server);
             fclose($handle);
             return 0;
         }
         if ($context['debug_messages'] == 'Y') {
             Logger::remember('agents/messages.php: POP <-', rtrim($reply), 'debug');
         }
         if (strncmp($reply, '+OK', 3)) {
             Logger::remember('agents/messages.php: Invalid password for account ' . $account . ' at ' . $server, rtrim($reply));
             fclose($handle);
             return 0;
         }
     }
     // ask for information
     $request = 'STAT';
     fputs($handle, $request . CRLF);
     if ($context['debug_messages'] == 'Y') {
         Logger::remember('agents/messages.php: POP ->', $request, 'debug');
     }
     // expecting an OK
     if (($reply = fgets($handle)) === FALSE) {
         Logger::remember('agents/messages.php: No reply to STAT command at ' . $server);
         fclose($handle);
         return 0;
     }
     if (strncmp($reply, '+OK', 3)) {
         Logger::remember('agents/messages.php: Rejected command STAT at ' . $server, 'reply="' . rtrim($reply) . '"');
         fclose($handle);
         return 0;
     }
     // evaluate queue size
     $tokens = explode(' ', $reply);
     if ($context['debug_messages'] == 'Y') {
         Logger::remember('agents/messages.php: POP <-', rtrim($reply), 'debug');
     }
     $queue_size = @$tokens[1];
     // nothing to do
     if (!$queue_size) {
         fclose($handle);
         return 0;
     }
     // limit the number of messages processed on each tick
     if ($queue_size > 10) {
         $queue_size = 10;
     }
     // process messages one by one
     for ($index = 1; $index <= $queue_size; $index++) {
         // ask for the message
         $request = 'RETR ' . $index;
         fputs($handle, $request . CRLF);
         if ($context['debug_messages'] == 'Y') {
             Logger::remember('agents/messages.php: POP ->', $request, 'debug');
         }
         // expecting an OK
         if (($reply = fgets($handle)) === FALSE) {
             Logger::remember('agents/messages.php: No reply to RETR command at ' . $server);
             fclose($handle);
             return $index - 1;
         }
         if (strncmp($reply, '+OK', 3)) {
             Logger::remember('agents/messages.php: Rejected command RETR at ' . $server, rtrim($reply));
             fclose($handle);
             return $index - 1;
         }
         // fetch one message at a time
         $message = '';
         while (!feof($handle)) {
             // ensure enough execution time
             Safe::set_time_limit(30);
             // get a chunk (up to ten 1500-byte Ethernet packets)
             $chunk = fread($handle, 16384);
             // look for message end
             if (preg_match("/(.*)\\.\r\n\$/s", $chunk, $matches)) {
                 $message .= $matches[1];
                 break;
             }
             // not yet at the end
             $message .= $chunk;
         }
         // suppress the message from the mailbox before entering into the database
         $request = 'DELE ' . $index;
         fputs($handle, $request . CRLF);
         if ($context['debug_messages'] == 'Y') {
             Logger::remember('agents/messages.php: POP ->', $request, 'debug');
         }
         // expecting an OK
         if (($reply = fgets($handle)) === FALSE) {
             Logger::remember('agents/messages.php: No reply to DELE command at ' . $server);
         } elseif (strncmp($reply, '+OK', 3)) {
             Logger::remember('agents/messages.php: Rejected command DELE at ' . $server, rtrim($reply));
         }
         // file the message if in debug mode
         if ($context['debug_messages'] == 'Y' && Safe::make_path('temporary/agents')) {
             Safe::file_put_contents('temporary/agents/' . uniqid('message_'), $message);
         }
         // process the message
         Messages::process_message($message);
     }
     // close the session to actually purge the queue
     $request = 'QUIT';
     fputs($handle, $request . CRLF);
     if ($context['debug_messages'] == 'Y') {
         Logger::remember('agents/messages.php: POP ->', $request, 'debug');
     }
     // expecting an OK
     if (($reply = fgets($handle)) === FALSE) {
         Logger::remember('agents/messages.php: No reply to QUIT command at ' . $server);
     } elseif (strncmp($reply, '+OK', 3)) {
         Logger::remember('agents/messages.php: Rejected command QUIT at ' . $server, rtrim($reply));
     }
     if ($queue_size > 0) {
         Logger::remember('agents/messages.php: ' . $queue_size . ' message(s) have been processed from ' . $server);
     }
     fclose($handle);
     return $queue_size;
 }
Пример #6
0
 /**
  * scan a file for viruses
  *
  * This function connects to ClamAV daemon, if possible, to scan the referred file.
  *
  * @param string absolute path of the file to scan
  * @return string 'Y' if the file has been infected, '?' if clamav is not available, or 'N' if no virus has been found
  */
 public static function has_virus($file)
 {
     global $context;
     // file scanning must be configured
     if (!isset($context['clamav_check']) || $context['clamav_check'] === 'N') {
         return 'N';
     }
     // we can't connect to clamav daemon
     $server = 'localhost';
     if (!($handle = Safe::fsockopen($server, 3310, $errno, $errstr, 1))) {
         if ($context['with_debug'] == 'Y') {
             Logger::remember('files/files.php: Unable to connect to CLAMAV daemon', '', 'debug');
         }
         return '?';
     }
     // ensure enough execution time
     Safe::set_time_limit(30);
     // scan uploaded file
     $request = 'SCAN ' . $file;
     fputs($handle, $request . CRLF);
     if ($context['with_debug'] == 'Y') {
         Logger::remember('files/files.php: CLAMAV ->', $request, 'debug');
     }
     // expecting an OK
     if (($reply = fgets($handle)) === FALSE) {
         Logger::remember('files/files.php: No reply to SCAN command at ' . $server);
         fclose($handle);
         return '?';
     }
     if ($context['with_debug'] == 'Y') {
         Logger::remember('files/files.php: CLAMAV <-', $reply, 'debug');
     }
     // file has been infected!
     if (!stripos($reply, ': ok')) {
         Logger::remember('files/files.php: Infected upload by ' . Surfer::get_name());
         fclose($handle);
         return 'Y';
     }
     // everything is ok
     fclose($handle);
     return 'N';
 }
Пример #7
0
Файл: http.php Проект: rair/yacs
 /**
  * login
  *
  * The script checks provided name and password against remote server.
  *
  * This is done by posting the user name and the password
  * to the web server.
  *
  * @param string the nickname of the user
  * @param string the submitted password
  * @return TRUE on succesful authentication, FALSE othewise
  */
 function login($name, $password)
 {
     global $context;
     // we need some parameters
     if (!isset($this->attributes['authenticator_parameters']) || !$this->attributes['authenticator_parameters']) {
         Logger::error(i18n::s('Please provide parameters to the authenticator.'));
         return FALSE;
     }
     // extract parameters
     $parameters = explode(" ", $this->attributes['authenticator_parameters']);
     // ensure a minimum number of parameters
     if (count($parameters) != 3) {
         Logger::error(i18n::s('Provide expected parameters to the REST POST authenticator.'));
         return FALSE;
     }
     // parse URL format
     if (!($url = $parameters[0])) {
         Logger::error(i18n::s('Wrong format of the URL target for the HTTP authenticator.'));
         return FALSE;
     }
     // prepare raw POST payload
     $payload = urlencode($parameters[1]) . "=" . urlencode($name) . "&" . urlencode($parameters[2]) . "=" . urlencode($password);
     // submit credentials to the authenticating server
     include_once $context['path_to_root'] . 'services/call.php';
     // build an HTTP request
     $request = "POST " . $url . " HTTP/1.0" . CRLF . 'Host: ' . $host . CRLF . "Accept-Encoding: gzip" . CRLF . "User-Agent: YACS (www.yacs.fr)" . CRLF . "Connection: close" . CRLF . "Content-Type: application/x-www-form-urlencoded" . CRLF . "Content-Length: " . strlen($payload) . CRLF . CRLF . $payload;
     // parse the target URL
     $items = @parse_url($url);
     // no host, assume it's us
     if (!isset($items['host']) || !($host = $items['host'])) {
         $host = $context['host_name'];
     }
     // no port, assume the standard
     if (!isset($items['port']) || !($port = $items['port'])) {
         $port = 80;
     }
     // outbound web is not authorized
     if (isset($context['without_outbound_http']) && $context['without_outbound_http'] == 'Y') {
         Logger::error(i18n::s('Outbound HTTP is not authorized.'));
         return FALSE;
     }
     // connect to the server
     if (!($handle = Safe::fsockopen($host, $port, $errno, $errstr, 30))) {
         Logger::error(sprintf(i18n::s('Impossible to connect to %.'), $items['host'] . ':' . $items['port']));
         return FALSE;
     }
     // ensure enough execution time
     Safe::set_time_limit(30);
     // build the path, including any query
     $path = $items['path'];
     if (!$path) {
         $path = '/';
     }
     if (isset($items['query']) && $items['query']) {
         $path .= '?' . $items['query'];
     }
     // submit the request
     fputs($handle, $request);
     // get everything by Ethernet-sized chunks
     $response = '';
     while (!feof($handle) && strlen($response) < 5242880) {
         $response .= fread($handle, 1500);
     }
     fclose($handle);
     // ensure we have a valid HTTP status line
     if (preg_match('/^HTTP\\/[0-9\\.]+ 200 /', $response)) {
         return TRUE;
     }
     // failed authentication
     return FALSE;
 }
Пример #8
0
 /**
  * connect to the mail server
  *
  * This function opens a network connection to the server, authenticate if required to do so,
  * and set $context['mail_handle'] to be used for actual transmissions.
  *
  * If parameter $context['mail_variant'] is set to 'smtp', a SMTP connection is
  * established with the computer specified in $context['mail_server']. If some credentials
  * are provided in $context['mail_account'] and $context['mail_password'], they are
  * transmitted to the server as per protocol extension. CRAM-MD5, LOGIN and PLAIN authentication
  * schemes have been implemented.
  *
  * @link http://tools.ietf.org/rfc/rfc2104.txt HMAC
  * @link http://www.fehcom.de/qmail/smtpauth.html
  *
  * If parameter $context['mail_variant'] is set to 'pop3', and if credentials have been
  * set in $context['mail_account'] and in $context['mail_password'], a POP3 connection
  * is made to the mail server just to authenticate, and then a SMTP connection
  * is established to actually transmit messages. If a secured communication has been
  * configured for SMTP, then a secured POP3 communication is performed on port 995. Else
  * a vanilla POP3 transaction is done on regular port 110.
  *
  * For any other value of $context['mail_variant'], or if the parameter is not set,
  * the function relies on the PHP mail() function to do the job. If the parameter
  * $context['mail_server'] is set, it overloads php.ini settings. Therefore you can change
  * the SMTP server used for transmission without the needs to edit the php.ini file.
  *
  * The parameter $context['mail_server'] can call for SSL/TLS support, or use a specific
  * port number, as in the following examples:
  *
  * [snippet]
  * ssl://mail.server.com
  * mail.server.com:234
  * [/snippet]
  *
  * @return mixed the socket handle itself, of FALSE on error
  *
  * @see control/configure.php
  */
 private static function connect()
 {
     global $context;
     // we already have an open handle
     if (isset($context['mail_handle'])) {
         return $context['mail_handle'];
     }
     // email services have to be activated
     if (!isset($context['with_email']) || $context['with_email'] != 'Y') {
         Logger::error(i18n::s('E-mail has not been enabled on this system.'));
         return FALSE;
     }
     // define target smtp server
     $port = 25;
     if (isset($context['mail_server'])) {
         $server = $context['mail_server'];
         // use alternate port if required to do so
         if (preg_match('/^(.+):([0-9]+)$/', $server, $matches)) {
             $server = $matches[1];
             $port = intval($matches[2]);
         }
     }
     // ensure that we can support tls communications
     if (isset($server) && !strncmp($server, 'ssl://', 6) && is_callable('extension_loaded') && !extension_loaded('openssl')) {
         logger::remember('shared/mailer.php: Load the OpenSSL extension to support secured transmissions to mail server ' . $server);
         return FALSE;
     }
     // go for POP authentication
     if (isset($server) && isset($context['mail_variant']) && $context['mail_variant'] == 'pop3') {
         // authenticate to a pop3 server
         if (isset($context['mail_account']) && isset($context['mail_password'])) {
             // select which port to use
             if (strncmp($server, 'ssl://', 6)) {
                 $pop3_port = 110;
             } else {
                 $pop3_port = 995;
             }
             // open a network connection
             if (!($handle = Safe::fsockopen($server, $pop3_port, $errno, $errstr, 10))) {
                 if ($context['debug_mail'] == 'Y') {
                     Logger::remember('shared/mailer.php: fsockopen:', $errstr . ' (' . $errno . ')', 'debug');
                 }
                 Logger::remember('shared/mailer.php: ' . sprintf('Impossible to connect to %s', $server . ':' . $pop3_port));
                 return FALSE;
             }
             // ensure enough execution time
             Safe::set_time_limit(30);
             // get server banner
             if (($reply = fgets($handle)) === FALSE) {
                 Logger::remember('shared/mailer.php: Impossible to get banner of ' . $server);
                 fclose($handle);
                 return FALSE;
             }
             if ($context['debug_mail'] == 'Y') {
                 Logger::remember('shared/mailer.php: POP <-', $reply, 'debug');
             }
             // expecting an OK
             if (strncmp($reply, '+OK', 3)) {
                 Logger::remember('shared/mailer.php: Mail service is closed at ' . $server, $reply);
                 fclose($handle);
                 return FALSE;
             }
             // send user name
             $request = 'USER ' . $context['mail_account'];
             fputs($handle, $request . CRLF);
             if ($context['debug_mail'] == 'Y') {
                 Logger::remember('shared/mailer.php: POP ->', $request, 'debug');
             }
             // expecting an OK
             if (($reply = fgets($handle)) === FALSE) {
                 Logger::remember('shared/mailer.php: No reply to USER command at ' . $server);
                 fclose($handle);
                 return FALSE;
             }
             if ($context['debug_mail'] == 'Y') {
                 Logger::remember('shared/mailer.php: POP <-', $reply, 'debug');
             }
             if (strncmp($reply, '+OK', 3)) {
                 Logger::remember('shared/mailer.php: Unknown account ' . $context['mail_account'] . ' at ' . $server, $reply);
                 fclose($handle);
                 return FALSE;
             }
             // send password
             $request = 'PASS ' . $context['mail_password'];
             fputs($handle, $request . CRLF);
             if ($context['debug_mail'] == 'Y') {
                 Logger::remember('shared/mailer.php: POP ->', $request, 'debug');
             }
             // expecting an OK
             if (($reply = fgets($handle)) === FALSE) {
                 Logger::remember('shared/mailer.php: No reply to PASS command at ' . $server);
                 fclose($handle);
                 return FALSE;
             }
             if ($context['debug_mail'] == 'Y') {
                 Logger::remember('shared/mailer.php: POP <-', $reply, 'debug');
             }
             if (strncmp($reply, '+OK', 3)) {
                 Logger::remember('shared/mailer.php: Invalid password for account ' . $account . ' at ' . $server, $reply);
                 fclose($handle);
                 return FALSE;
             }
             // we just wanted to authenticate
             fclose($handle);
         }
     }
     // we manage directly the SMTP transaction
     if (isset($server) && isset($context['mail_variant']) && ($context['mail_variant'] == 'pop3' || $context['mail_variant'] == 'smtp')) {
         // open a network connection
         if (!($handle = Safe::fsockopen($server, $port, $errno, $errstr, 10))) {
             if ($context['debug_mail'] == 'Y') {
                 Logger::remember('shared/mailer.php: fsockopen:', $errstr . ' (' . $errno . ')', 'debug');
             }
             Logger::remember('shared/mailer.php: ' . sprintf('Impossible to connect to %s', $server . ':' . $port));
             return FALSE;
         }
         // ensure enough execution time
         Safe::set_time_limit(30);
         // get server banner
         if (($response = Mailer::parse_response($handle, 220)) === FALSE) {
             Logger::remember('shared/mailer.php: Impossible to get banner of ' . $server);
             fclose($handle);
             return FALSE;
         }
         // provide our logical name
         if (strpos($response, 'ESMTP')) {
             $request = 'EHLO ' . $context['host_name'];
         } else {
             $request = 'HELO ' . $context['host_name'];
         }
         fputs($handle, $request . CRLF);
         if ($context['debug_mail'] == 'Y') {
             Logger::remember('shared/mailer.php: SMTP ->', $request, 'debug');
         }
         // expecting a welcome message
         if (($response = Mailer::parse_response($handle, 250)) === FALSE) {
             Logger::remember('shared/mailer.php: Command EHLO has been rejected at ' . $server);
             fclose($handle);
             return FALSE;
         }
         // authenticate as per SMTP protocol extension
         if (isset($context['mail_account']) && isset($context['mail_password']) && preg_match('/^AUTH (.+)$/m', $response, $matches)) {
             // CRAM-MD5 -- the preferred method
             if (strpos($matches[1], 'CRAM-MD5') !== FALSE) {
                 // get the challenge
                 $request = 'AUTH CRAM-MD5';
                 fputs($handle, $request . CRLF);
                 if ($context['debug_mail'] == 'Y') {
                     Logger::remember('shared/mailer.php: SMTP ->', $request, 'debug');
                 }
                 if (($response = Mailer::parse_response($handle, 334)) === FALSE) {
                     Logger::remember('shared/mailer.php: Command AUTH has been rejected at ' . $server);
                     fclose($handle);
                     return FALSE;
                 }
                 $challenge = base64_decode($response);
                 // from password to a 64 bytes block
                 if (strlen($context['mail_password']) < 64) {
                     $key = str_pad($context['mail_password'], 64, chr(0));
                 } elseif (strlen($context['mail_password']) > 64) {
                     $key = str_pad(pack('H32', md5($context['mail_password'])), 64, chr(0));
                 } else {
                     $key = $context['mail_password'];
                 }
                 // compute HMAC-MD5
                 $inner = $key ^ str_repeat(chr(0x36), 64);
                 $outer = $key ^ str_repeat(chr(0x5c), 64);
                 $digest = md5($outer . pack('H32', md5($inner . $challenge)));
                 // answer the challenge
                 $request = base64_encode($context['mail_account'] . ' ' . $digest);
                 fputs($handle, $request . CRLF);
                 if ($context['debug_mail'] == 'Y') {
                     Logger::remember('shared/mailer.php: SMTP ->', $request, 'debug');
                 }
                 // LOGIN
             } elseif (strpos($matches[1], 'LOGIN') !== FALSE) {
                 $request = 'AUTH LOGIN';
                 fputs($handle, $request . CRLF);
                 if ($context['debug_mail'] == 'Y') {
                     Logger::remember('shared/mailer.php: SMTP ->', $request, 'debug');
                 }
                 if (Mailer::parse_response($handle, 334) === FALSE) {
                     Logger::remember('shared/mailer.php: Command AUTH has been rejected at ' . $server);
                     fclose($handle);
                     return FALSE;
                 }
                 $request = base64_encode($context['mail_account']);
                 fputs($handle, $request . CRLF);
                 if ($context['debug_mail'] == 'Y') {
                     Logger::remember('shared/mailer.php: SMTP ->', $request, 'debug');
                 }
                 if (Mailer::parse_response($handle, 334) === FALSE) {
                     Logger::remember('shared/mailer.php: Command AUTH has been rejected at ' . $server);
                     fclose($handle);
                     return FALSE;
                 }
                 $request = base64_encode($context['mail_password']);
                 fputs($handle, $request . CRLF);
                 if ($context['debug_mail'] == 'Y') {
                     Logger::remember('shared/mailer.php: SMTP ->', $request, 'debug');
                 }
                 // PLAIN
             } elseif (strpos($matches[1], 'PLAIN') !== FALSE) {
                 $request = 'AUTH PLAIN ' . base64_encode("" . $context['mail_account'] . "" . $context['mail_password']);
                 fputs($handle, $request . CRLF);
                 if ($context['debug_mail'] == 'Y') {
                     Logger::remember('shared/mailer.php: SMTP ->', $request, 'debug');
                 }
             }
             // expecting an OK
             if (Mailer::parse_response($handle, 235) === FALSE) {
                 Logger::remember('shared/mailer.php: Command AUTH has been rejected at ' . $server);
                 fclose($handle);
                 return FALSE;
             }
         }
         // ready to submit messages
         $context['mail_handle'] = $handle;
         return $handle;
         // rely on system settings and PHP
     } elseif (is_callable('mail')) {
         // set the SMTP server
         if ($server) {
             Safe::ini_set('SMTP', $server);
         }
         // set the SMTP sender
         if (isset($context['mail_from']) && $context['mail_from']) {
             Safe::ini_set('sendmail_from', $context['mail_from']);
         }
         // ready to submit messages
         $context['mail_handle'] = TRUE;
         return TRUE;
     }
     // no SMTP configuration
     return FALSE;
 }