From 629fb744763135c1cc2e5b0e354784933ebe8cdc Mon Sep 17 00:00:00 2001 From: pdontthink Date: Sat, 6 Apr 2019 19:06:29 +0000 Subject: [PATCH] Add IMAP ID command (RFC2971), sent after every login - use by setting $imap_id_command_args in config/config_local.php (see notes in config/config_local.example.php for more details) git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@14814 7612ce4b-ef26-0410-bec9-ea0150e637f0 --- config/config_local.example.php | 28 ++++++++ doc/ChangeLog | 3 + functions/imap_general.php | 122 ++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) diff --git a/config/config_local.example.php b/config/config_local.example.php index 21c48edd..16bc47ce 100644 --- a/config/config_local.example.php +++ b/config/config_local.example.php @@ -146,4 +146,32 @@ * while using this setting, you must include the following * as part of this setting: * $head_tag_extra = '......'; + * + * $imap_id_command_args (array) causes the IMAP ID + * command (RFC 2971) to be sent after every login, + * identifying the client to the server. Each key in this + * array is an attibute to be sent in the ID command to + * the server. Values will be sent as-is except if the + * value is "###REMOTE ADDRESS###" (without quotes) in + * which case the current user's real IP address will be + * substituted. If "###X-FORWARDED-FOR###" is used and a + * "X-FORWARDED-FOR" header is present in the client request, + * the contents of that header are used (careful, this can + * be forged). If "###X-FORWARDED-FOR OR REMOTE ADDRESS###" + * is used, then the "X-FORWARDED-FOR" header is used if it + * is present in the request, otherwise, the client's + * connecting IP address is used. The following attributes + * will always be added unless they are specifically + * overridden with a blank value: + * name, vendor, support-url, version + * A parsed representation of server's response is made + * available to plugins as both a global and session variable + * named "imap_server_id_response" (a simple key/value array) + * unless response parsing is turned off by way of setting a + * variable in this file named + * $do_not_parse_imap_id_command_response to TRUE, in which + * case, the stored response will be the unparsed IMAP response. + * $imap_id_command_args = array('remote-host' => '###REMOTE ADDRESS###'); + * $do_not_parse_imap_id_command_response = FALSE; + * */ diff --git a/doc/ChangeLog b/doc/ChangeLog index 936ff672..42ffee71 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -426,6 +426,9 @@ Version 1.5.2 - SVN - Updated SVG handling, closing several related vulnerabilities (#2831) [CVE-2018-14950] [CVE-2018-14951] [CVE-2018-14952] [CVE-2018-14953] [CVE-2018-14954] [CVE-2018-14955] + - Added IMAP ID command (RFC2971), sent after every login - use + by setting $imap_id_command_args in config/config_local.php + (see notes in config/config_local.example.php for more details) Version 1.5.1 (branched on 2006-02-12) -------------------------------------- diff --git a/functions/imap_general.php b/functions/imap_general.php index 16f43fbd..08b9ab2a 100755 --- a/functions/imap_general.php +++ b/functions/imap_general.php @@ -1052,6 +1052,128 @@ function sqimap_login ($username, $password, $imap_server_address, exit; } + // Run ID command if configured - RFC 2971 + // + // Administrator must declare a configuration variable called + // $imap_id_command_args in config/config_local.php which must + // be an array, where each key is an attibute to be sent in the + // IMAP ID command to the server. Values will be sent as-is + // except if the value is "###REMOTE ADDRESS###" (without quotes) + // in which case the current user's real IP address will be + // substituted. If "###X-FORWARDED-FOR###" is used and a + // "X-FORWARDED-FOR" header is present in the client request, + // the contents of that header are used (careful, this can be + // forged). If "###X-FORWARDED-FOR OR REMOTE ADDRESS###" is + // used, then the "X-FORWARDED-FOR" header is used if it is + // present in the request, otherwise, the client's connecting + // IP address is used. The following attributes will always be + // added unless they are specifically overridden with a blank + // value: + // name, vendor, support-url, version + // A parsed representation of server's response is made available + // to plugins as both a global and session variable named + // "imap_server_id_response" (a simple key/value array) unless + // response parsing is turned off by way of setting a variable + // named $do_not_parse_imap_id_command_response in + // config/config_local.php to TRUE, in which case, the stored + // response will be the unparsed IMAP response. + // + global $imap_id_command_args, $do_not_parse_imap_id_command_response; + if (!empty($imap_id_command_args) && is_array($imap_id_command_args) + && sqimap_capability($imap_stream, 'ID')) { + + static $args = array(); + if (empty($args)) { + if (!isset($imap_id_command_args['name'])) + $imap_id_command_args['name'] = 'SquirrelMail'; + if (!isset($imap_id_command_args['vendor'])) + $imap_id_command_args['vendor'] = 'SquirrelMail Project Team'; + if (!isset($imap_id_command_args['support-url'])) + $imap_id_command_args['support-url'] = 'https://squirrelmail.org'; + if (!isset($imap_id_command_args['version'])) { + $imap_id_command_args['version'] = SM_VERSION; + } + foreach ($imap_id_command_args as $key => $value) { + $key = trim($key); + $value = trim($value); + if ($key === '' || $value === '') + continue; + if ($value === '###REMOTE ADDRESS###' && sqGetGlobalVar('REMOTE_ADDR', $remote_addr, SQ_SERVER)) + $value = $remote_addr; + else if ($value === '###X-FORWARDED-FOR###' && sqGetGlobalVar('HTTP_X_FORWARDED_FOR', $remote_addr, SQ_SERVER)) + $value = $remote_addr; + else if ($value === '###X-FORWARDED-FOR OR REMOTE ADDRESS###') { + if (sqGetGlobalVar('HTTP_X_FORWARDED_FOR', $remote_addr, SQ_SERVER)) + $value = $remote_addr; + else if (sqGetGlobalVar('REMOTE_ADDR', $remote_addr, SQ_SERVER)) + $value = $remote_addr; + } + else if ($value === '###REMOTE ADDRESS###' && sqGetGlobalVar('REMOTE_ADDR', $remote_addr, SQ_SERVER)) { + $value = $remote_addr; + } + $args[] = '"' . str_replace(array('"', '\\'), array('\\"', '\\\\'), $key) + . '" "' . str_replace(array('"', '\\'), array('\\"', '\\\\'), $value) . '"'; + } + } + $read_ary = sqimap_run_command($imap_stream, 'ID (' . implode(' ', $args) . ')', false, $response, $message); + if (!empty($read_ary) && is_array($read_ary)) { + global $imap_server_id_response; + if ($do_not_parse_imap_id_command_response) + $imap_server_id_response = $read_ary; + else + { + $imap_server_id_response = array(); + + // NOTE that this parser ignores closing ) sign, so + // technically some kind of malformed server + // response could cause extra junk to be included here + foreach ($read_ary as $info) + { + $parsed_info = explode('(', $info, 2); + if (!empty($parsed_info[1])) + { + // find opening quote for the next key name + while ($parsed_info = explode('"', $parsed_info[1], 2)) + { + if (empty($parsed_info[1])) + break; + else + { + // find closing quote for the key name + $pos = strpos($parsed_info[1], '"'); + if ($pos === FALSE) + break; + else + { + $key = substr($parsed_info[1], 0, $pos); + $parsed_info[1] = substr($parsed_info[1], $pos + 1); + + // find opening quote for the key's value + $parsed_info = explode('"', $parsed_info[1], 2); + if (empty($parsed_info[1])) + break; + else + { + // find closing quote for the key's value + $pos = strpos($parsed_info[1], '"'); + if ($pos === FALSE) + break; + else + { + $imap_server_id_response[$key] = substr($parsed_info[1], 0, $pos); + $parsed_info[1] = substr($parsed_info[1], $pos + 1); + } + } + } + } + } + } + } + } + sqsession_register($imap_server_id_response, 'imap_server_id_response'); + } + } + return $imap_stream; } -- 2.25.1