From ebfeeb220e2fcd04d6fee000963bd47a655a0510 Mon Sep 17 00:00:00 2001 From: Rob Ostensen Date: Thu, 5 Jan 2012 21:24:02 -0600 Subject: [PATCH 1/6] add checks to prevent external binds from being created or updated if curl is missing, add check to setup page --- htdocs/setup.php | 10 +++++++++- inc/caldav-BIND.php | 6 ++++-- inc/external-fetch.php | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/htdocs/setup.php b/htdocs/setup.php index 7ba5b176..86604aa4 100644 --- a/htdocs/setup.php +++ b/htdocs/setup.php @@ -107,6 +107,13 @@ function check_magic_quotes_runtime() { return new CheckResult( (get_magic_quotes_runtime() == 0) ); } +function check_curl() { + global $phpinfo, $loaded_extensions; + + if (!function_exists('curl_init')) return new CheckResult(false); + return new CheckResult(isset($loaded_extensions['curl'])); +} + $loaded_extensions = array_flip(get_loaded_extensions()); @@ -255,7 +262,8 @@ function build_dependencies_table( ) { translate('Suhosin "server.strip" disabled') => 'check_suhosin_server_strip', translate('PHP Magic Quotes GPC off') => 'check_magic_quotes_gpc', translate('PHP Magic Quotes runtime off') => 'check_magic_quotes_runtime', - translate('PHP calendar extension available') => 'check_calendar' + translate('PHP calendar extension available') => 'check_calendar', + translate('PHP curl support') => 'check_curl' ); if ( isset($c->authenticate_hook) && isset($c->authenticate_hook['call']) && $c->authenticate_hook['call'] == 'LDAP_check') { diff --git a/inc/caldav-BIND.php b/inc/caldav-BIND.php index ed104aaf..d93a7fa9 100644 --- a/inc/caldav-BIND.php +++ b/inc/caldav-BIND.php @@ -47,8 +47,10 @@ if ( $destination->Exists() ) { $request->PreconditionFailed(403,'DAV::can-overwrite',translate('A resource already exists at the destination.')); } -if ( preg_match ( '{^https?://[A-Za-z][^/]*/.+$}', $href ) && ! stripos( $href, 'localhost' ) < 9 - && ! stripos( $href, '127.0.0.1' ) < 9 && ! stripos( $href, $_SERVER['SERVER_NAME'] ) < 9 && ! stripos( $href, $_SERVER['SERVER_ADDR'] ) < 9 ) { +// external binds shouldn't ever point back to ourselves but they should be a valid http[s] url +if ( preg_match ( '{^https?://([^/]+)(:[0-9]\+)?/.+$}', $href, $matches ) && + strcasecmp( $matches[0], 'localhost' ) !== 0 && strcasecmp( $matches[0], '127.0.0.1' ) !== 0 + && strcasecmp( $matches[0], $_SERVER['SERVER_NAME'] ) !== 0 && strcasecmp( $matches[0], $_SERVER['SERVER_ADDR'] ) !== 0 ) { require_once('external-fetch.php'); $qry = new AwlQuery( ); $qry->QDo('SELECT collection_id FROM collection WHERE dav_name = :dav_name ', array( ':dav_name' => '/.external/'. md5($href) )); diff --git a/inc/external-fetch.php b/inc/external-fetch.php index 8f32bee2..b5d5366d 100644 --- a/inc/external-fetch.php +++ b/inc/external-fetch.php @@ -13,6 +13,11 @@ function create_external ( $path,$is_calendar,$is_addressbook ) { global $request; + if ( ! function_exists ( "curl_init" ) ) { + dbg_error_log("external", "external resource cannot be fetched without curl, please install curl"); + $request->DoResponse( 503, translate('PHP5 curl support is required for external binds') ); + return ; + } $resourcetypes = ''; if ($is_calendar) $resourcetypes .= ''; $qry = new AwlQuery(); @@ -36,6 +41,11 @@ function create_external ( $path,$is_calendar,$is_addressbook ) function fetch_external ( $bind_id, $min_age ) { + if ( ! function_exists ( "curl_init" ) ) { + dbg_error_log("external", "external resource cannot be fetched without curl, please install curl"); + $request->DoResponse( 503, translate('PHP5 curl support is required for external binds') ); + return ; + } $sql = 'SELECT collection.*, collection.dav_name AS path, dav_binding.external_url AS external_url FROM dav_binding LEFT JOIN collection ON (collection.collection_id=bound_source_id) WHERE bind_id = :bind_id'; $params = array( ':bind_id' => $bind_id ); if ( strlen ( $min_age ) > 2 ) { @@ -83,6 +93,10 @@ function update_external ( $request ) global $c; if ( $c->external_refresh < 1 ) return ; + if ( ! function_exists ( "curl_init" ) ) { + dbg_error_log("external", "external resource cannot be fetched without curl, please install curl"); + return ; + } $sql = 'SELECT bind_id from dav_binding LEFT JOIN collection ON (collection.collection_id=bound_source_id) WHERE dav_binding.dav_name = :dav_name AND collection.modified + interval :interval < NOW()'; $qry = new AwlQuery( $sql, array ( ':dav_name' => $request->dav_name(), ':interval' => $c->external_refresh . ' minutes' ) ); dbg_error_log("external", "checking if external resource needs update"); From 6915ef3d49ea28d52f481a459538c98d5ad383ed Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Mon, 9 Jan 2012 23:32:50 +1300 Subject: [PATCH 2/6] Fix Principal::Create() for default_privileges. --- inc/Principal.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/inc/Principal.php b/inc/Principal.php index 46a43e58..0cae69ae 100644 --- a/inc/Principal.php +++ b/inc/Principal.php @@ -533,7 +533,10 @@ class Principal { foreach( self::updateableFields() AS $k ) { if ( !isset($field_values->{$k}) && !isset($this->{$k}) ) continue; if ( $inserting ) { - $param_names[] = ':'.$k; + if ($k == 'default_privileges') + $param_names[] = 'cast(:'.$k.' as text)::BIT(24)'; + else + $param_names[] = ':'.$k; $insert_fields[] = $k; } else { From 90a34a78ecd452a2df86e8ff68699466bddba79a Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 12 Jan 2012 10:26:53 +1300 Subject: [PATCH 3/6] Finally really fix that permissions issue in Principal. --- inc/Principal.php | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/inc/Principal.php b/inc/Principal.php index 0cae69ae..5e44ee33 100644 --- a/inc/Principal.php +++ b/inc/Principal.php @@ -532,23 +532,19 @@ class Principal { $sql_params = array(); foreach( self::updateableFields() AS $k ) { if ( !isset($field_values->{$k}) && !isset($this->{$k}) ) continue; + $param_name = ':'.$k; + $sql_params[$param_name] = (isset($field_values->{$k}) ? $field_values->{$k} : $this->{$k}); + if ( $k == 'default_privileges' ) { + $sql_params[$param_name] = sprintf('%024s',decbin($sql_params[$param_name])); + $param_name = 'cast('.$param_name.' as text)::BIT(24)'; + } if ( $inserting ) { - if ($k == 'default_privileges') - $param_names[] = 'cast(:'.$k.' as text)::BIT(24)'; - else - $param_names[] = ':'.$k; + $param_names[] = $param_name; $insert_fields[] = $k; } else { - if ($k == 'default_privileges') { - $update_list[] = $k.'=cast(:'.$k.' as text)::BIT(24)'; - } - else { - $update_list[] = $k.'=:'.$k; - } + $update_list[] = $k.'='.$param_name; } - - $sql_params[':'.$k] = (isset($field_values->{$k}) ? $field_values->{$k} : $this->{$k}); } if ( $inserting && isset(self::$db_mandatory_fields) ) { From 33effe2a7055341f33f0c4f3fa8ad1c46d3fd535 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 12 Jan 2012 13:59:34 +1300 Subject: [PATCH 4/6] Add a default for min_age. --- inc/external-fetch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/external-fetch.php b/inc/external-fetch.php index b5d5366d..d86483a6 100644 --- a/inc/external-fetch.php +++ b/inc/external-fetch.php @@ -39,7 +39,7 @@ function create_external ( $path,$is_calendar,$is_addressbook ) } } -function fetch_external ( $bind_id, $min_age ) +function fetch_external ( $bind_id, $min_age = '1 hour' ) { if ( ! function_exists ( "curl_init" ) ) { dbg_error_log("external", "external resource cannot be fetched without curl, please install curl"); From c48d19895eac3e7e8e37103af4e23a75e1bd466a Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 12 Jan 2012 14:01:44 +1300 Subject: [PATCH 5/6] Support use of HTTP_AUTHORIZATION in addition to AUTHORIZATION cgi. This is supplied by older versions of FastCGI. --- inc/HTTPAuthSession.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inc/HTTPAuthSession.php b/inc/HTTPAuthSession.php index 12cf9c07..d4c19efd 100644 --- a/inc/HTTPAuthSession.php +++ b/inc/HTTPAuthSession.php @@ -101,6 +101,8 @@ class HTTPAuthSession { /** * Get HTTP Auth to work with PHP+FastCGI */ + if ( !isset($_SERVER["AUTHORIZATION"]) && isset($_SERVER["HTTP_AUTHORIZATION"]) && !empty($_SERVER["HTTP_AUTHORIZATION"])) + $_SERVER["AUTHORIZATION"] = $_SERVER["HTTP_AUTHORIZATION"]; if (isset($_SERVER["AUTHORIZATION"]) && !empty($_SERVER["AUTHORIZATION"])) { list ($type, $cred) = split (" ", $_SERVER['AUTHORIZATION']); if ($type == 'Basic') { From b491d914ea7c9fafa1af937b7fab06f02c56af30 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 12 Jan 2012 18:44:28 +1300 Subject: [PATCH 6/6] Allow for silly programs that send content-type XML with a GET request. --- inc/CalDAVRequest.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index 46ef5799..20ac9e85 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -187,7 +187,7 @@ class CalDAVRequest $this->content_type = $matches[1]; } if ( isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 7 ) { - if ( $this->method == 'PROPFIND' || $this->method == 'REPORT' ) { + if ( $this->method == 'PROPFIND' || $this->method == 'REPORT' || $this->method == 'PROPPATCH' || $this->method == 'BIND' || $this->method == 'MKTICKET' || $this->method == 'ACL' ) { if ( !preg_match( '{^(text|application)/xml$}', $this->content_type ) ) { @dbg_error_log( "LOG request", 'Request is "%s" but client set content-type to "%s". Assuming they meant XML!', $request->method, $this->content_type ); @@ -198,6 +198,13 @@ class CalDAVRequest $this->CoerceContentType(); } } + else if ( !preg_match( '{^(text|application)/xml$}', $this->content_type ) ) { + if ( $this->method == 'GET' || $this->method == 'HEAD' || $this->method == 'OPTIONS' || $this->method == 'MKCALENDAR' || $this->method == 'MKCOL' ) { + @dbg_error_log( "LOG request", '%s Request specified %s content type but none is present. Assuming null content-type.', + $request->method, $this->content_type ); + $this->content_type = 'text/plain'; + } + } $this->user_agent = ((isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "Probably Mulberry")); /**