Overview

Packages

  • awl
    • caldav-client-v2
    • RRule
  • davical
    • authentication
      • drivers
    • caldav
    • DAViCalSession
    • DAVTicket
    • external-bind
    • feed
    • HTTPAuthSession
    • iSchedule
    • iSchedule-POST
    • logging
    • metrics
    • Principal
    • propfind
    • PublicSession
    • Request
    • Resource
    • tzservice
  • None
  • PHP

Functions

  • add_failure
  • check_for_expansion
  • component_to_xml
  • controlRequestContainer
  • delete_collection
  • deliverItipCancel
  • display_status
  • do_scheduling_for_delete
  • do_scheduling_reply
  • do_scheduling_requests
  • doImipMessage
  • doItipAttendeeReply
  • doItipOrganizerCancel
  • export_iCalendar
  • GetItip
  • GetTZID
  • handle_cancel_request
  • handle_freebusy_request
  • handle_schedule_reply
  • handle_schedule_request
  • import_addressbook_collection
  • import_calendar_collection
  • import_collection
  • late_catch_fatal_error
  • logRequestHeaders
  • obfuscated_event
  • process_ace
  • processItipCancel
  • property_response
  • public_events_only
  • rollback
  • rollback_on_error
  • send_dav_header
  • simple_write_resource
  • write_alarms
  • write_attendees
  • write_resource
  • Overview
  • Package
  • Function
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: /**
  3: * CalDAV Server - handle ACL method
  4: *
  5: * @package   davical
  6: * @subpackage   caldav
  7: * @author    Andrew McMillan <andrew@morphoss.com>
  8: * @copyright Morphoss Ltd
  9: * @license   http://gnu.org/copyleft/gpl.html GNU GPL v2
 10: */
 11: dbg_error_log("ACL", "method handler");
 12: 
 13: require_once('DAVResource.php');
 14: 
 15: $request->NeedPrivilege('DAV::write-acl');
 16: 
 17: if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || (isset($c->dbg['put']) && $c->dbg['put'])) ) {
 18:   $fh = fopen('/var/log/davical/MOVE.debug','w');
 19:   if ( $fh ) {
 20:     fwrite($fh,$request->raw_post);
 21:     fclose($fh);
 22:   }
 23: }
 24: 
 25: $resource = new DAVResource( $request->path );
 26: 
 27: /**
 28: * Preconditions
 29:    (DAV:no-ace-conflict): The ACEs submitted in the ACL request MUST NOT
 30:    conflict with each other.  This is a catchall error code indicating
 31:    that an implementation-specific ACL restriction has been violated.
 32: 
 33:    (DAV:no-protected-ace-conflict): The ACEs submitted in the ACL
 34:    request MUST NOT conflict with the protected ACEs on the resource.
 35:    For example, if the resource has a protected ACE granting DAV:write
 36:    to a given principal, then it would not be consistent if the ACL
 37:    request submitted an ACE denying DAV:write to the same principal.
 38: 
 39:    (DAV:no-inherited-ace-conflict): The ACEs submitted in the ACL
 40:    request MUST NOT conflict with the inherited ACEs on the resource.
 41:    For example, if the resource inherits an ACE from its parent
 42:    collection granting DAV:write to a given principal, then it would not
 43:    be consistent if the ACL request submitted an ACE denying DAV:write
 44:    to the same principal.  Note that reporting of this error will be
 45:    implementation-dependent.  Implementations MUST either report this
 46:    error or allow the ACE to be set, and then let normal ACE evaluation
 47:    rules determine whether the new ACE has any impact on the privileges
 48:    available to a specific principal.
 49: 
 50:    (DAV:limited-number-of-aces): The number of ACEs submitted in the ACL
 51:    request MUST NOT exceed the number of ACEs allowed on that resource.
 52:    However, ACL-compliant servers MUST support at least one ACE granting
 53:    privileges to a single principal, and one ACE granting privileges to
 54:    a group.
 55: 
 56:    (DAV:deny-before-grant): All non-inherited deny ACEs MUST precede all
 57:    non-inherited grant ACEs.
 58: 
 59:    (DAV:grant-only): The ACEs submitted in the ACL request MUST NOT
 60:    include a deny ACE.  This precondition applies only when the ACL
 61:    restrictions of the resource include the DAV:grant-only constraint
 62:    (defined in Section 5.6.1).
 63: 
 64:    (DAV:no-invert):  The ACL request MUST NOT include a DAV:invert
 65:    element.  This precondition applies only when the ACL semantics of
 66:    the resource includes the DAV:no-invert constraint (defined in
 67:    Section 5.6.2).
 68: 
 69:    (DAV:no-abstract): The ACL request MUST NOT attempt to grant or deny
 70:    an abstract privilege (see Section 5.3).
 71: 
 72:    (DAV:not-supported-privilege): The ACEs submitted in the ACL request
 73:    MUST be supported by the resource.
 74: 
 75:    (DAV:missing-required-principal): The result of the ACL request MUST
 76:    have at least one ACE for each principal identified in a
 77:    DAV:required-principal XML element in the ACL semantics of that
 78:    resource (see Section 5.5).
 79: 
 80:    (DAV:recognized-principal): Every principal URL in the ACL request
 81:    MUST identify a principal resource.
 82: 
 83:    (DAV:allowed-principal): The principals specified in the ACEs
 84:    submitted in the ACL request MUST be allowed as principals for the
 85:    resource.  For example, a server where only authenticated principals
 86:    can access resources would not allow the DAV:all or
 87:    DAV:unauthenticated principals to be used in an ACE, since these
 88:    would allow unauthenticated access to resources.
 89: */
 90: 
 91: $position = 0;
 92: $xmltree = BuildXMLTree( $request->xml_tags, $position);
 93: $aces = $xmltree->GetPath("/DAV::acl/*");
 94: 
 95: $grantor = new DAVResource($request->path);
 96: if ( ! $grantor->Exists() ) $request->DoResponse( 404 );
 97: if ( ! $grantor->IsCollection() )
 98:   $request->PreconditionFailed(403,'not-supported-privilege','ACLs are only supported on Principals or Collections');
 99: 
100: $grantor->NeedPrivilege('write-acl');
101: 
102: $cache_delete_list = array();
103: 
104: $qry = new AwlQuery('BEGIN');
105: $qry->Exec('ACL',__LINE__,__FILE__);
106: 
107: function process_ace( $grantor, $by_principal, $by_collection, $ace ) {
108:   global $cache_delete_list, $request;
109: 
110:   $elements = $ace->GetContent();
111:   $principal_node = $elements[0];
112:   $grant = $elements[1];
113:   if ( $principal_node->GetNSTag() != 'DAV::principal' ) $request->MalformedRequest('ACL request must contain a principal, not '.$principal->GetNSTag());
114:   $grant_tag = $grant->GetNSTag();
115:   if ( $grant_tag == 'DAV::deny' )   $request->PreconditionFailed(403,'grant-only');
116:   if ( $grant_tag == 'DAV::invert' ) $request->PreconditionFailed(403,'no-invert');
117:   if ( $grant->GetNSTag() != 'DAV::grant' ) $request->MalformedRequest('ACL request must contain a principal for each ACE');
118: 
119:   $privilege_names = array();
120:   $xml_privs = $grant->GetPath("/DAV::grant/DAV::privilege/*");
121:   foreach( $xml_privs AS $k => $priv ) {
122:     $privilege_names[] = $priv->GetNSTag();
123:   }
124:   $privileges = privilege_to_bits($privilege_names);
125: 
126:   $principal_content = $principal_node->GetContent();
127:   if ( count($principal_content) != 1 ) $request->MalformedRequest('ACL request must contain exactly one principal per ACE');
128:   $principal_content = $principal_content[0];
129:   switch( $principal_content->GetNSTag() ) {
130:     case 'DAV::property':
131:       $principal_property = $principal_content->GetContent();
132:       if ( $principal_property[0]->GetNSTag() != 'DAV::owner' ) $request->PreconditionFailed(403, 'recognized-principal' );
133:       if ( privilege_to_bits('all') != $privileges ) {
134:         $request->PreconditionFailed(403, 'no-protected-ace-conflict', 'Owner must always have all permissions' );
135:       }
136:       continue;  // and then we ignore it, since it's protected
137:       break;
138: 
139:     case 'DAV::unauthenticated':
140:       $request->PreconditionFailed(403, 'allowed-principal', 'May not set privileges for unauthenticated users' );
141:       break;
142: 
143:     case 'DAV::href':
144:       $principal_type = 'href';
145:       $grantee = new DAVResource( DeconstructURL($principal_content->GetContent()) );
146:       $grantee_id = $grantee->getProperty('principal_id');
147:       if ( !$grantee->Exists() || !$grantee->IsPrincipal() )
148:         $request->PreconditionFailed(403,'recognized-principal', 'Principal "' + $principal_content->GetContent() + '" not found.');
149:       $sqlparms = array( ':to_principal' => $grantee_id);
150:       $where = 'WHERE to_principal=:to_principal AND ';
151:       if ( isset($by_principal) ) {
152:         $sqlparms[':by_principal'] = $by_principal;
153:         $where .= 'by_principal = :by_principal';
154:       }
155:       else {
156:         $sqlparms[':by_collection'] = $by_collection;
157:         $where .= 'by_collection = :by_collection';
158:       }
159:       $qry = new AwlQuery('SELECT privileges FROM grants '.$where, $sqlparms);
160:       if ( $qry->Exec('ACL',__LINE__,__FILE__) && $qry->rows() == 1 && $current = $qry->Fetch() ) {
161:         $sql = 'UPDATE grants SET privileges=:privileges::INT::BIT(24) '.$where;
162:       }
163:       else {
164:         $sqlparms[':by_principal'] = $by_principal;
165:         $sqlparms[':by_collection'] = $by_collection;
166:         $sql = 'INSERT INTO grants (by_principal, by_collection, to_principal, privileges) VALUES(:by_principal, :by_collection, :to_principal, :privileges::INT::BIT(24))';
167:       }
168:       $sqlparms[':privileges'] = $privileges;
169:       $qry = new AwlQuery($sql, $sqlparms);
170:       if ( $qry->Exec('ACL',__LINE__,__FILE__) ) {
171:         Principal::cacheDelete('dav_name',$grantee->dav_name());
172:         Principal::cacheFlush('principal_id IN (SELECT member_id FROM group_member WHERE group_id = ?)', array($grantee_id));
173:       }
174:       break;
175: 
176:     case 'DAV::authenticated':
177:       $principal_type = 'authenticated';
178:       if ( bindec($grantor->GetProperty('default_privileges')) == $privileges ) continue; // There is no change, so skip it
179:       $sqlparms = array( ':privileges' => $privileges );
180:       if ( isset($by_collection) ) {
181:         $sql = 'UPDATE collection SET default_privileges=:privileges::INT::BIT(24) WHERE collection_id=:by_collection';
182:         $sqlparms[':by_collection'] = $by_collection;
183:       }
184:       else {
185:         $sql = 'UPDATE principal SET default_privileges=:privileges::INT::BIT(24) WHERE principal_id=:by_principal';
186:         $sqlparms[':by_principal'] = $by_principal;
187:       }
188:       $qry = new AwlQuery($sql, $sqlparms);
189:       if ( $qry->Exec('ACL',__LINE__,__FILE__) ) {
190:         /**
191:          *  Basically this has changed everyone's permissions now, so...
192:          */
193:         Principal::cacheFlush('TRUE');
194:       }
195:       break;
196: 
197:     case 'DAV::all':
198: //      $principal_type = 'all';
199:       $request->PreconditionFailed(403, 'allowed-principal', 'May not set privileges for unauthenticated users' );
200:       break;
201: 
202:     default:
203:       $request->PreconditionFailed(403, 'recognized-principal' );
204:       break;
205:   }
206: 
207: }
208: 
209: $by_principal  = ($grantor->IsPrincipal() ? $grantor->GetProperty('principal_id') : null);
210: $by_collection = ($grantor->IsPrincipal() ? null : $grantor->GetProperty('collection_id'));
211: 
212: foreach( $aces AS $k => $ace ) {
213:   process_ace($grantor, $by_principal, $by_collection, $ace);
214: }
215: 
216: $qry = new AwlQuery('COMMIT');
217: $qry->Exec('ACL',__LINE__,__FILE__);
218: 
219: 
220: $request->DoResponse( 200 );
221: 
DAViCal API documentation generated by ApiGen 2.8.0