1<?php 2/** 3 * @copyright Copyright (c) 2016, ownCloud, Inc. 4 * 5 * @author Brice Maron <brice@bmaron.net> 6 * @author Christopher Schäpers <kondou@ts.unde.re> 7 * @author Christoph Wurst <christoph@winzerhof-wurst.at> 8 * @author Georg Ehrke <oc.list@georgehrke.com> 9 * @author Joas Schilling <coding@schilljs.com> 10 * @author Jörn Friedrich Dreyer <jfd@butonic.de> 11 * @author Lukas Reschke <lukas@statuscode.ch> 12 * @author Morris Jobke <hey@morrisjobke.de> 13 * @author Robin Appelman <robin@icewind.nl> 14 * @author Robin McCorkell <robin@mccorkell.me.uk> 15 * @author Roeland Jago Douma <roeland@famdouma.nl> 16 * @author Thomas Müller <thomas.mueller@tmit.eu> 17 * @author Vincent Petry <vincent@nextcloud.com> 18 * 19 * @license AGPL-3.0 20 * 21 * This code is free software: you can redistribute it and/or modify 22 * it under the terms of the GNU Affero General Public License, version 3, 23 * as published by the Free Software Foundation. 24 * 25 * This program is distributed in the hope that it will be useful, 26 * but WITHOUT ANY WARRANTY; without even the implied warranty of 27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 * GNU Affero General Public License for more details. 29 * 30 * You should have received a copy of the GNU Affero General Public License, version 3, 31 * along with this program. If not, see <http://www.gnu.org/licenses/> 32 * 33 */ 34require_once __DIR__ . '/lib/versioncheck.php'; 35 36use OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin; 37use Sabre\DAV\Exception\ServiceUnavailable; 38use Sabre\DAV\Server; 39 40/** 41 * Class RemoteException 42 * Dummy exception class to be use locally to identify certain conditions 43 * Will not be logged to avoid DoS 44 */ 45class RemoteException extends Exception { 46} 47 48/** 49 * @param Exception|Error $e 50 */ 51function handleException($e) { 52 $request = \OC::$server->getRequest(); 53 // in case the request content type is text/xml - we assume it's a WebDAV request 54 $isXmlContentType = strpos($request->getHeader('Content-Type'), 'text/xml'); 55 if ($isXmlContentType === 0) { 56 // fire up a simple server to properly process the exception 57 $server = new Server(); 58 if (!($e instanceof RemoteException)) { 59 // we shall not log on RemoteException 60 $server->addPlugin(new ExceptionLoggerPlugin('webdav', \OC::$server->getLogger())); 61 } 62 $server->on('beforeMethod:*', function () use ($e) { 63 if ($e instanceof RemoteException) { 64 switch ($e->getCode()) { 65 case 503: 66 throw new ServiceUnavailable($e->getMessage()); 67 case 404: 68 throw new \Sabre\DAV\Exception\NotFound($e->getMessage()); 69 } 70 } 71 $class = get_class($e); 72 $msg = $e->getMessage(); 73 throw new ServiceUnavailable("$class: $msg"); 74 }); 75 $server->exec(); 76 } else { 77 $statusCode = 500; 78 if ($e instanceof \OC\ServiceUnavailableException) { 79 $statusCode = 503; 80 } 81 if ($e instanceof RemoteException) { 82 // we shall not log on RemoteException 83 OC_Template::printErrorPage($e->getMessage(), '', $e->getCode()); 84 } else { 85 \OC::$server->getLogger()->logException($e, ['app' => 'remote']); 86 OC_Template::printExceptionErrorPage($e, $statusCode); 87 } 88 } 89} 90 91/** 92 * @param $service 93 * @return string 94 */ 95function resolveService($service) { 96 $services = [ 97 'webdav' => 'dav/appinfo/v1/webdav.php', 98 'dav' => 'dav/appinfo/v2/remote.php', 99 'caldav' => 'dav/appinfo/v1/caldav.php', 100 'calendar' => 'dav/appinfo/v1/caldav.php', 101 'carddav' => 'dav/appinfo/v1/carddav.php', 102 'contacts' => 'dav/appinfo/v1/carddav.php', 103 'files' => 'dav/appinfo/v1/webdav.php', 104 'direct' => 'dav/appinfo/v2/direct.php', 105 ]; 106 if (isset($services[$service])) { 107 return $services[$service]; 108 } 109 110 return \OC::$server->getConfig()->getAppValue('core', 'remote_' . $service); 111} 112 113try { 114 require_once __DIR__ . '/lib/base.php'; 115 116 // All resources served via the DAV endpoint should have the strictest possible 117 // policy. Exempted from this is the SabreDAV browser plugin which overwrites 118 // this policy with a softer one if debug mode is enabled. 119 header("Content-Security-Policy: default-src 'none';"); 120 121 if (\OCP\Util::needUpgrade()) { 122 // since the behavior of apps or remotes are unpredictable during 123 // an upgrade, return a 503 directly 124 throw new RemoteException('Service unavailable', 503); 125 } 126 127 $request = \OC::$server->getRequest(); 128 $pathInfo = $request->getPathInfo(); 129 if ($pathInfo === false || $pathInfo === '') { 130 throw new RemoteException('Path not found', 404); 131 } 132 if (!$pos = strpos($pathInfo, '/', 1)) { 133 $pos = strlen($pathInfo); 134 } 135 $service = substr($pathInfo, 1, $pos - 1); 136 137 $file = resolveService($service); 138 139 if (is_null($file)) { 140 throw new RemoteException('Path not found', 404); 141 } 142 143 $file = ltrim($file, '/'); 144 145 $parts = explode('/', $file, 2); 146 $app = $parts[0]; 147 148 // Load all required applications 149 \OC::$REQUESTEDAPP = $app; 150 OC_App::loadApps(['authentication']); 151 OC_App::loadApps(['filesystem', 'logging']); 152 153 switch ($app) { 154 case 'core': 155 $file = OC::$SERVERROOT .'/'. $file; 156 break; 157 default: 158 if (!\OC::$server->getAppManager()->isInstalled($app)) { 159 throw new RemoteException('App not installed: ' . $app); 160 } 161 OC_App::loadApp($app); 162 $file = OC_App::getAppPath($app) .'/'. $parts[1]; 163 break; 164 } 165 $baseuri = OC::$WEBROOT . '/remote.php/'.$service.'/'; 166 require_once $file; 167} catch (Exception $ex) { 168 handleException($ex); 169} catch (Error $e) { 170 handleException($e); 171} 172