$request->DoResponse(403); } if (!$dav_resource->Exists() && !$dav_resource->HavePrivilegeTo('DAV::bind')) { $request->DoResponse(403); } if (!ini_get('open_basedir') && (isset($c->dbg['ALL']) || isset($c->dbg['put']) && $c->dbg['put'])) { $fh = fopen('/tmp/PUT.txt', 'w'); if ($fh) { fwrite($fh, $request->raw_post); fclose($fh); } } include_once 'caldav-PUT-functions.php'; controlRequestContainer($dav_resource->GetProperty('username'), $dav_resource->GetProperty('user_no'), $dav_resource->bound_from(), true); $lock_opener = $request->FailIfLocked(); if ($dav_resource->IsCollection()) { if ($dav_resource->IsPrincipal() || $dav_resource->IsBinding() || !isset($c->readonly_webdav_collections) || $c->readonly_webdav_collections == true) { $request->DoResponse(405); // Method not allowed return; } $appending = isset($_GET['mode']) && $_GET['mode'] == 'append'; /** * CalDAV does not define the result of a PUT on a collection. We treat that * as an import. The code is in caldav-PUT-functions.php */ import_collection($request->raw_post, $request->user_no, $request->path, true, $appending); $request->DoResponse(200); return; } $etag = md5($request->raw_post);
} if (!$dest->ContainerExists()) { $request->DoResponse(409, translate('Destination collection does not exist')); } if (!$request->overwrite && $dest->Exists()) { $request->DoResponse(412, translate('Not overwriting existing destination resource')); } if (isset($request->etag_none_match) && $request->etag_none_match != '*') { $request->DoResponse(412); /** request to move, but only if there is no source? WTF! */ } $src = new DAVResource($request->path); if (!$src->Exists()) { $request->DoResponse(412, translate('Source resource does not exist.')); } if ($src->IsCollection()) { switch ($dest->ContainerType()) { case 'calendar': case 'addressbook': case 'schedule-inbox': case 'schedule-outbox': $request->DoResponse(412, translate('Special collections may not contain a calendar or other special collection.')); } } else { if (isset($request->etag_if_match) && $request->etag_if_match != '' || isset($request->etag_none_match) && $request->etag_none_match != '') { /** * RFC2068, 14.25: * If none of the entity tags match, or if "*" is given and no current * entity exists, the server MUST NOT perform the requested method, and * MUST return a 412 (Precondition Failed) response. *
fclose($fh); } } $lock_opener = $request->FailIfLocked(); $dest = new DAVResource($request->path); $container = $dest->FetchParentContainer(); if (!$dest->Exists()) { if ($container->IsPrincipal()) { $request->PreconditionFailed(405, 'method-not-allowed', translate('A DAViCal principal collection may only contain collections')); } if (!$container->Exists()) { $request->PreconditionFailed(409, 'collection-must-exist', translate('The destination collection does not exist')); } $container->NeedPrivilege('DAV::bind'); } else { if ($dest->IsCollection()) { if (!isset($c->readonly_webdav_collections) || $c->readonly_webdav_collections) { $request->PreconditionFailed(405, 'method-not-allowed', translate('You may not PUT to a collection URL')); } $request->DoResponse(403, translate('PUT on a collection is only allowed for text/calendar content against a calendar collection')); } $dest->NeedPrivilege('DAV::write-content'); } if (isset($request->etag_none_match) && $request->etag_none_match != '*' && $dest->Exists()) { $request->PreconditionFailed(412, 'if-none-match', translate('A resource already exists at the destination.')); } if (isset($request->etag_if_match) && $request->etag_if_match != $dest->unique_tag()) { $request->PreconditionFailed(412, 'if-match', sprintf('Existing resource ETag of "%s" does not match "%s"', $dest->unique_tag(), $request->etag_if_match)); } $collection_id = $container->GetProperty('collection_id'); $qry = new AwlQuery();
/** * A slightly simpler version of write_resource which will make more sense for calling from * an external program. This makes assumptions that the collection and user do exist * and bypasses all checks for whether it is reasonable to write this here. * @param string $path The path to the resource being written * @param string $caldav_data The actual resource to be written * @param string $put_action_type INSERT or UPDATE depending on what we are to do * @return boolean True for success, false for failure. */ function simple_write_resource($path, $caldav_data, $put_action_type, $write_action_log = false) { global $session; /** * We pull the user_no & collection_id out of the collection table, based on the resource path */ $dav_resource = new DAVResource($path); $etag = md5($caldav_data); $collection_path = preg_replace('#/[^/]*$#', '/', $path); $collection = new DAVResource($collection_path); if ($collection->IsCollection() || $collection->IsSchedulingCollection()) { return write_resource($dav_resource, $caldav_data, $collection, $session->user_no, $etag, $put_action_type, false, $write_action_log); } return false; }
return $responses; } /** * Something that we can handle, at least roughly correctly. */ $responses = array(); if ($request->IsProxyRequest()) { $response = add_proxy_response($request->proxy_type, $request->principal->dav_name()); if (isset($response)) { $responses[] = $response; } } else { $resource = new DAVResource($request->path); if (!$resource->Exists()) { $request->PreconditionFailed(404, 'must-exist', translate('That resource is not present on this server.')); } $resource->NeedPrivilege('DAV::read'); if ($resource->IsCollection()) { dbg_error_log('PROPFIND', 'Getting collection contents: Depth %d, Path: %s', $request->depth, $resource->dav_name()); $responses[] = $resource->RenderAsXML($property_list, $reply); if ($request->depth > 0) { $responses = array_merge($responses, get_collection_contents($request->depth - 1, $resource)); } } elseif ($request->HavePrivilegeTo('DAV::read', false)) { $responses[] = $resource->RenderAsXML($property_list, $reply); } } $xmldoc = $reply->Render('multistatus', $responses); $etag = md5($xmldoc); header('ETag: "' . $etag . '"'); $request->DoResponse(207, $xmldoc, 'text/xml; charset="utf-8"');
if ($qry->Exec('BIND', __LINE__, __FILE__)) { $qry = new AwlQuery('SELECT bind_id from dav_binding where dav_name = :dav_name', array(':dav_name' => $destination_path)); if (!$qry->Exec('BIND', __LINE__, __FILE__) || $qry->rows() != 1 || !($row = $qry->Fetch())) { $request->DoResponse(500, translate('Database Error')); } fetch_external($row->bind_id, ''); $request->DoResponse(201); } else { $request->DoResponse(500, translate('Database Error')); } } else { $source = new DAVResource($href); if (!$source->Exists()) { $request->PreconditionFailed(403, 'DAV::bind-source-exists', translate('The BIND Request MUST identify an existing resource.')); } if ($source->IsPrincipal() || !$source->IsCollection()) { $request->PreconditionFailed(403, 'DAV::binding-allowed', translate('DAViCal only allows BIND requests for collections at present.')); } if ($source->IsBinding()) { $source = new DAVResource($source->bound_from()); } /* bind_id INT8 DEFAULT nextval('dav_id_seq') PRIMARY KEY, bound_source_id INT8 REFERENCES collection(collection_id) ON UPDATE CASCADE ON DELETE CASCADE, access_ticket_id TEXT REFERENCES access_ticket(ticket_id) ON UPDATE CASCADE ON DELETE SET NULL, parent_container TEXT NOT NULL, dav_name TEXT UNIQUE NOT NULL, dav_displayname TEXT, external_url TEXT, type TEXT */
* Not much for it but to process the incoming settings in a big loop, doing * the special-case stuff as needed and falling through to a default which * stuffs the property somewhere we will be able to retrieve it from later. */ $qry = new AwlQuery(); $qry->Begin(); $setcalendar = count($xmltree->GetPath('/DAV::propertyupdate/DAV::set/DAV::prop/DAV::resourcetype/urn:ietf:params:xml:ns:caldav:calendar')); foreach ($setprops as $k => $setting) { $tag = $setting->GetTag(); $content = $setting->RenderContent(); switch ($tag) { case 'DAV::displayname': /** * Can't set displayname on resources - only collections or principals */ if ($dav_resource->IsCollection() || $dav_resource->IsPrincipal()) { if ($dav_resource->IsBinding()) { $qry->QDo('UPDATE dav_binding SET dav_displayname = :displayname WHERE dav_name = :dav_name', array(':displayname' => $content, ':dav_name' => $dav_resource->dav_name())); } else { if ($dav_resource->IsPrincipal()) { $qry->QDo('UPDATE dav_principal SET fullname = :displayname, displayname = :displayname, modified = current_timestamp WHERE user_no = :user_no', array(':displayname' => $content, ':user_no' => $request->user_no)); } else { $qry->QDo('UPDATE collection SET dav_displayname = :displayname, modified = current_timestamp WHERE dav_name = :dav_name', array(':displayname' => $content, ':dav_name' => $dav_resource->dav_name())); } } $success[$tag] = 1; } else { $failure['set-' . $tag] = new XMLElement('propstat', array(new XMLElement('prop', new XMLElement($tag)), new XMLElement('status', 'HTTP/1.1 403 Forbidden'), new XMLElement('responsedescription', array(new XMLElement('error', new XMLElement('cannot-modify-protected-property')), translate("The displayname may only be set on collections, principals or bindings."))))); } break; case 'DAV::resourcetype':
(DAV:allowed-principal): The principals specified in the ACEs submitted in the ACL request MUST be allowed as principals for the resource. For example, a server where only authenticated principals can access resources would not allow the DAV:all or DAV:unauthenticated principals to be used in an ACE, since these would allow unauthenticated access to resources. */ $position = 0; $xmltree = BuildXMLTree($request->xml_tags, $position); $aces = $xmltree->GetPath("/DAV::acl/*"); $grantor = new DAVResource($request->path); if (!$grantor->Exists()) { $request->DoResponse(404); } if (!$grantor->IsCollection()) { $request->PreconditionFailed(403, 'not-supported-privilege', 'ACLs are only supported on Principals or Collections'); } $grantor->NeedPrivilege('write-acl'); $cache_delete_list = array(); $qry = new AwlQuery('BEGIN'); $qry->Exec('ACL', __LINE__, __FILE__); function process_ace($grantor, $by_principal, $by_collection, $ace) { global $cache_delete_list, $request; $elements = $ace->GetContent(); $principal_node = $elements[0]; $grant = $elements[1]; if ($principal_node->GetNSTag() != 'DAV::principal') { $request->MalformedRequest('ACL request must contain a principal, not ' . $principal->GetNSTag()); }