DAViCal
auth-functions.php
1 <?php
28 require_once("DataUpdate.php");
29 
30 if ( !function_exists('auth_functions_deprecated') ) {
34  function auth_functions_deprecated( $method, $message = null ) {
35  $stack = debug_backtrace();
36  array_shift($stack);
37  dbg_error_log("ERROR", " auth-functions: Call to deprecated routine '%s'%s", $method, (isset($message)?': '.$message:'') );
38  foreach( $stack AS $k => $v ) {
39  dbg_error_log( 'ERROR', ' auth-functions: Deprecated call from line %4d of %s', $v['line'], $v['file']);
40  }
41  }
42 }
43 
47 function getUserByName( $username, $use_cache=true ) {
48  auth_functions_deprecated('getUserByName','replaced by Principal class');
49  return new Principal('username', $username, $use_cache);
50 }
51 
55 function getUserByEMail( $email, $use_cache = true ) {
56  auth_functions_deprecated('getUserByEMail','replaced by Principal class');
57  return new Principal('email', $email, $use_cache);
58 }
59 
63 function getUserByID( $user_no, $use_cache = true ) {
64  auth_functions_deprecated('getUserByID','replaced by Principal class');
65  return new Principal('user_no', $user_no, $use_cache);
66 }
67 
71 function getPrincipalByID( $principal_id, $use_cache = true ) {
72  auth_functions_deprecated('getPrincipalByID','replaced by Principal class');
73  return new Principal('principal_id', $principal_id, $use_cache);
74 }
75 
76 
81 function CreateHomeCollections( $username, $defult_timezone = null ) {
82  global $session, $c;
83 
84  if ( !isset($c->default_collections) )
85  {
86  $c->default_collections = array();
87 
88  if( !empty($c->home_calendar_name) )
89  $c->default_collections[] = array( 'type' => 'calendar', 'name' => $c->home_calendar_name );
90  if( !empty($c->home_addressbook_name) )
91  $c->default_collections[] = array( 'type' => 'addressbook', 'name' => $c->home_addressbook_name );
92  }
93 
94  if ( !is_array($c->default_collections) || !count($c->default_collections) ) return true;
95 
96  $principal = new Principal('username',$username);
97 
98  $user_fullname = $principal->fullname; // user fullname
99  $user_rfullname = implode(' ', array_reverse(explode(' ', $principal->fullname))); // user fullname in reverse order
100 
101  $sql = 'INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, is_addressbook, default_privileges, created, modified, resourcetypes) ';
102  $sql .= 'VALUES( :user_no, :parent_container, :collection_path, :dav_etag, :displayname, :is_calendar, :is_addressbook, :privileges::BIT(24), current_timestamp, current_timestamp, :resourcetypes );';
103 
104  foreach( $c->default_collections as $v ) {
105  if ( $v['type'] == 'calendar' || $v['type']=='addressbook' ) {
106  if ( !empty($v['name']) ) {
107  $qry = new AwlQuery( 'SELECT 1 FROM collection WHERE dav_name = :dav_name', array( ':dav_name' => $principal->dav_name().$v['name'].'/') );
108  if ( !$qry->Exec() ) {
109  $c->messages[] = i18n('There was an error reading from the database.');
110  return false;
111  }
112  if ( $qry->rows() > 0 ) {
113  $c->messages[] = i18n('Home '.( $v['type']=='calendar' ? 'calendar' : 'addressbook' ).' already exists.');
114  return true;
115  }
116  else {
117  $params[':user_no'] = $principal->user_no();
118  $params[':parent_container'] = $principal->dav_name();
119  $params[':dav_etag'] = '-1';
120  $params[':collection_path'] = $principal->dav_name().$v['name'].'/';
121  $params[':displayname'] = ( !isset($v['displayname']) || empty($v['displayname']) ? $user_fullname.( $v['type']=='calendar' ? ' calendar' : ' addressbook' ) : str_replace(array('%fn', '%rfn'), array($user_fullname, $user_rfullname), $v['displayname']) );
122  $params[':resourcetypes'] = ( $v['type']=='calendar' ? '<DAV::collection/><urn:ietf:params:xml:ns:caldav:calendar/>' : '<DAV::collection/><urn:ietf:params:xml:ns:carddav:addressbook/>' );
123  $params[':is_calendar'] = ( $v['type']=='calendar' ? true : false );
124  $params[':is_addressbook'] = ( $v['type']=='addressbook' ? true : false );
125  $params[':privileges'] = ( !isset($v['privileges']) || $v['privileges']===null ? null : privilege_to_bits($v['privileges']) );
126 
127  $qry = new AwlQuery( $sql, $params );
128  if ( $qry->Exec() ) {
129  $c->messages[] = i18n('Home '.( $v['type']=='calendar' ? 'calendar' : 'addressbook' ).' added.');
130  dbg_error_log("User",":Write: Created user's home ".( $v['type']=='calendar' ? 'calendar' : 'addressbook' )." at '%s'", $params[':collection_path'] );
131 
132  // create value for urn:ietf:params:xml:ns:caldav:supported-calendar-component-set property
133  if($v['type'] == 'calendar' && isset($v['calendar_components']) && $v['calendar_components'] != null && is_array($v['calendar_components']) && count($v['calendar_components'])) {
134  // convert the array to uppercase and allow only real calendar compontents
135  $components_clean=array_intersect(array_map("strtoupper", $v['calendar_components']), array('VEVENT', 'VTODO', 'VJOURNAL', 'VTIMEZONE', 'VFREEBUSY', 'VPOLL', 'VAVAILABILITY'));
136 
137  // convert the $components_clean array to XML string
138  $result_xml='';
139  foreach($components_clean as $curr)
140  $result_xml.=sprintf('<comp name="%s" xmlns="urn:ietf:params:xml:ns:caldav"/>', $curr);
141 
142  // handle the components XML string as user defined property (see below)
143  if($result_xml!='')
144  $v['default_properties']['urn:ietf:params:xml:ns:caldav:supported-calendar-component-set']=$result_xml;
145  }
146 
147  // store all user defined properties (note: it also handles 'calendar_components' - see above)
148  if(isset($v['default_properties']) && $v['default_properties'] != null && is_array($v['default_properties']) && count($v['default_properties'])) {
149  $sql2='INSERT INTO property (dav_name, property_name, property_value, changed_on, changed_by) ';
150  $sql2.='VALUES (:collection_path, :property_name, :property_value, current_timestamp, :user_no);';
151  $params2[':user_no'] = $principal->user_no();
152  $params2[':collection_path'] = $principal->dav_name().$v['name'].'/';
153 
154  foreach( $v['default_properties'] AS $key => $val ) {
155  $params2[':property_name'] = $key;
156  $params2[':property_value'] = $val;
157 
158  $qry2 = new AwlQuery( $sql2, $params2 );
159  if ( $qry2->Exec() ) {
160  dbg_error_log("User",":Write: Created property '%s' for ".( $v['type']=='calendar' ? 'calendar' : 'addressbook' )." at '%s'", $params2[':property_name'], $params2[':collection_path'] );
161  }
162  else {
163  $c->messages[] = i18n("There was an error writing to the database.");
164  return false;
165  }
166  }
167  }
168  }
169  else {
170  $c->messages[] = i18n("There was an error writing to the database.");
171  return false;
172  }
173  }
174  }
175  }
176  }
177  return true;
178 }
179 
184 function CreateHomeCalendar($username) {
185  auth_functions_deprecated('CreateHomeCalendar','renamed to CreateHomeCollections');
186  return CreateHomeCollections($username);
187 }
188 
193 function CreateDefaultRelationships( $username ) {
194  global $c;
195  if(! isset($c->default_relationships) || count($c->default_relationships) == 0) return true;
196 
197  $changes = false;
198  $principal = new Principal('username', $username, true);
199  foreach($c->default_relationships as $group => $relationships)
200  {
201  $sql = 'INSERT INTO grants (by_principal, to_principal, privileges) VALUES(:by_principal, :to_principal, :privileges::INT::BIT(24))';
202  $params = array(
203  ':by_principal' => $principal->principal_id,
204  ':to_principal' => $group,
205  ':privileges' => privilege_to_bits($relationships)
206  );
207  $qry = new AwlQuery($sql, $params);
208 
209  if ( $qry->Exec() ) {
210  $changes = true;
211  dbg_error_log("User",":Write: Created user's default relationship by:'%s', to:'%s', privileges:'%s'",$params[':by_principal'],$params[':to_principal'],$params[':privileges']);
212  }
213  else {
214  $c->messages[] = i18n("There was an error writing to the database.");
215  return false;
216  }
217  }
218 
219  if($changes)
220  $c->messages[] = i18n("Default relationships added.");
221 
222  return true;
223 }
224 
230 function UpdateCollectionTimezones( $username, $new_timezone=null ) {
231  if ( empty($new_timezone) ) return;
232  $qry = new AwlQuery('UPDATE collection SET timezone=? WHERE dav_name LIKE ? AND is_calendar', '/'.$username.'/%', $new_timezone);
233  $qry->Exec();
234 
235  require_once("instance_range.php");
236  update_instance_ranges($dav_resource->dav_name());
237 }
238 
243 function UpdateUserFromExternal( &$usr ) {
244  global $c;
245 
246  auth_functions_deprecated('UpdateUserFromExternal','refactor to use the "Principal" class');
250  if ( !isset($usr->user_no) || intval($usr->user_no) == 0 ) {
251  $qry = new AwlQuery( "SELECT nextval('usr_user_no_seq');" );
252  $qry->Exec('Login',__LINE__,__FILE__);
253  $sequence_value = $qry->Fetch(true); // Fetch as an array
254  $usr->user_no = $sequence_value[0];
255  }
256 
257  $qry = new AwlQuery('SELECT * FROM usr WHERE user_no = :user_no', array(':user_no' => $usr->user_no) );
258  if ( $qry->Exec('Login',__LINE__,__FILE__) && $qry->rows() == 1 ) {
259  $type = "UPDATE";
260  if ( $old = $qry->Fetch() ) {
261  $changes = false;
262  foreach( $usr AS $k => $v ) {
263  if ( $old->{$k} != $v ) {
264  $changes = true;
265  dbg_error_log("Login","User '%s' field '%s' changed from '%s' to '%s'", $usr->username, $k, $old->{$k}, $v );
266  break;
267  }
268  }
269  if ( !$changes ) {
270  dbg_error_log("Login","No changes to user record for '%s' - leaving as-is.", $usr->username );
271  if ( isset($usr->active) && $usr->active == 'f' ) return false;
272  return; // Normal case, if there are no changes
273  }
274  else {
275  dbg_error_log("Login","Changes to user record for '%s' - updating.", $usr->username );
276  }
277  }
278  }
279  else
280  $type = "INSERT";
281 
282  $params = array();
283  if ( $type != 'INSERT' ) $params[':user_no'] = $usr->user_no;
284  $qry = new AwlQuery( sql_from_object( $usr, $type, 'usr', 'WHERE user_no= :user_no' ), $params );
285  $qry->Exec('Login',__LINE__,__FILE__);
286 
290  if ( isset($usr->active) && ($usr->active === 'f' || $usr->active === false) ) return false;
291 
292  if ( $type == 'INSERT' ) {
293  $qry = new AwlQuery( 'INSERT INTO principal( type_id, user_no, displayname, default_privileges) SELECT 1, user_no, fullname, :privs::INT::BIT(24) FROM usr WHERE username=(text(:username))',
294  array( ':privs' => privilege_to_bits($c->default_privileges), ':username' => $usr->username) );
295  $qry->Exec('Login',__LINE__,__FILE__);
296  CreateHomeCalendar($usr->username);
297  CreateDefaultRelationships($usr->username);
298  }
299  else if ( $usr->fullname != $old->{'fullname'} ) {
300  // Also update the displayname if the fullname has been updated.
301  $qry->QDo( 'UPDATE principal SET displayname=:new_display WHERE user_no=:user_no',
302  array(':new_display' => $usr->fullname, ':user_no' => $usr->user_no)
303  );
304  }
305 }
306 
307 
328 function AuthExternalAWL( $username, $password ) {
329  global $c;
330 
331  $persistent = isset($c->authenticate_hook['config']['use_persistent']) && $c->authenticate_hook['config']['use_persistent'];
332 
333  if ( isset($c->authenticate_hook['config']['columns']) )
334  $cols = $c->authenticate_hook['config']['columns'];
335  else
336  $cols = '*';
337 
338  if ( isset($c->authenticate_hook['config']['where']) )
339  $andwhere = ' AND '.$c->authenticate_hook['config']['where'];
340  else
341  $andwhere = '';
342 
343  $qry = new AwlQuery('SELECT '.$cols.' FROM usr WHERE lower(username) = :username '. $andwhere, array( ':username' => strtolower($username) ));
344  $authconn = $qry->SetConnection($c->authenticate_hook['config']['connection'], ($persistent ? array(PDO::ATTR_PERSISTENT => true) : null));
345  if ( ! $authconn ) {
346  echo <<<EOERRMSG
347  <html><head><title>Database Connection Failure</title></head><body>
348  <h1>Database Error</h1>
349  <h3>Could not connect to PostgreSQL database</h3>
350  </body>
351  </html>
352 EOERRMSG;
353  @ob_flush(); exit(1);
354  }
355 
356  if ( $qry->Exec('Login',__LINE__,__FILE__) && $qry->rows() == 1 ) {
357  $usr = $qry->Fetch();
358  if ( session_validate_password( $password, $usr->password ) ) {
359  $principal = new Principal('username',$username);
360  if ( $principal->Exists() ) {
361  if ( $principal->modified <= $usr->updated )
362  $principal->Update($usr);
363  }
364  else {
365  $principal->Create($usr);
366  CreateHomeCollections($username);
367  CreateDefaultRelationships($username);
368  }
369 
373  if ( isset($usr->active) && $usr->active == 'f' ) return false;
374 
375  return $principal;
376  }
377  }
378 
379  return false;
380 
381 }
Principal
Definition: Principal.php:19