system/lib-security.php
author Dirk Haun <dirk@haun-online.de>
Thu, 29 Oct 2009 18:09:46 +0100
branchHEAD
changeset 7400 37fcd14cdee2
parent 7362 aaa5a1f1850e
child 7413 5db714583481
permissions -rw-r--r--
Experimental: Give the user an idea how long they have until the security token expires
     1 <?php
     2 
     3 /* Reminder: always indent with 4 spaces (no tabs). */
     4 // +---------------------------------------------------------------------------+
     5 // | Geeklog 1.6                                                               |
     6 // +---------------------------------------------------------------------------+
     7 // | lib-security.php                                                          |
     8 // |                                                                           |
     9 // | Geeklog security library.                                                 |
    10 // +---------------------------------------------------------------------------+
    11 // | Copyright (C) 2000-2009 by the following authors:                         |
    12 // |                                                                           |
    13 // | Authors: Tony Bibbs       - tony AT tonybibbs DOT com                     |
    14 // |          Mark Limburg     - mlimburg AT users DOT sourceforge DOT net     |
    15 // |          Vincent Furia    - vmf AT abtech DOT org                         |
    16 // |          Michael Jervis   - mike AT fuckingbrit DOT com                   |
    17 // +---------------------------------------------------------------------------+
    18 // |                                                                           |
    19 // | This program is free software; you can redistribute it and/or             |
    20 // | modify it under the terms of the GNU General Public License               |
    21 // | as published by the Free Software Foundation; either version 2            |
    22 // | of the License, or (at your option) any later version.                    |
    23 // |                                                                           |
    24 // | This program is distributed in the hope that it will be useful,           |
    25 // | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
    26 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
    27 // | GNU General Public License for more details.                              |
    28 // |                                                                           |
    29 // | You should have received a copy of the GNU General Public License         |
    30 // | along with this program; if not, write to the Free Software Foundation,   |
    31 // | Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           |
    32 // |                                                                           |
    33 // +---------------------------------------------------------------------------+
    34 
    35 /**
    36 * This is the security library for Geeklog.  This is used to implement Geeklog's
    37 * *nix-style security system.
    38 *
    39 * Programming notes:  For items you need security on you need the following for
    40 * each record in your database:
    41 * owner_id        | mediumint(8)
    42 * group_id        | mediumint(8)
    43 * perm_owner      | tinyint(1) unsigned
    44 * perm_group      | tinyint(1) unsigned
    45 * perm_members    | tinyint(1) unsigned
    46 * perm_anon       | tinyint(1) unsigned
    47 *
    48 * For display one function can handle most needs:
    49 * function SEC_hasAccess($owner_id,$group_id,$perm_owner,$perm_group,$perm_members,$perm_anon)
    50 * A call to this function will allow you to determine if the current user should see the item.
    51 *
    52 * For the admin screen several functions will make life easier:
    53 * function SEC_getPermissionsHTML($perm_owner,$perm_group,$perm_members,$perm_anon)
    54 * This function displays the permissions widget with arrays for each permission
    55 * function SEC_getPermissionValues($perm_owner,$perm_group,$perm_members,$perm_anon)
    56 * This function takes the permissions from the previous function and converts them into
    57 * an integer for saving back to the database.
    58 *
    59 */
    60 
    61 // Turn this on to get various debug messages from the code in this library
    62 $_SEC_VERBOSE = false;
    63 
    64 if (strpos(strtolower($_SERVER['PHP_SELF']), 'lib-security.php') !== false) {
    65     die('This file can not be used on its own!');
    66 }
    67 
    68 /* Constants for account stats */
    69 define('USER_ACCOUNT_DISABLED', 0); // Account is banned/disabled
    70 define('USER_ACCOUNT_AWAITING_ACTIVATION', 1); // Account awaiting user to login.
    71 define('USER_ACCOUNT_AWAITING_APPROVAL', 2); // Account awaiting moderator approval
    72 define('USER_ACCOUNT_ACTIVE', 3); // active account
    73 
    74 /* Constant for Security Token */
    75 if (!defined('CSRF_TOKEN')) {
    76     define('CSRF_TOKEN', '_glsectoken');
    77 }
    78 
    79 /**
    80 * Returns the groups a user belongs to
    81 *
    82 * This is part of the GL security implementation.  This function returns
    83 * all the groups a user belongs to.  This function is called recursively
    84 * as groups can belong to other groups
    85 *
    86 * Note: this is an expensive function -- if you are concerned about speed it should only
    87 *       be used once at the beginning of a page.  The resulting array $_GROUPS can then be
    88 *       used through out the page.
    89 *
    90 * @param        int     $uid            User ID to get information for. If empty current user.
    91 * @return	array	Associative Array grp_name -> ug_main_grp_id of group ID's user belongs to
    92 *
    93 */
    94 function SEC_getUserGroups($uid='')
    95 {
    96     global $_TABLES, $_USER, $_SEC_VERBOSE;
    97 
    98     if ($_SEC_VERBOSE) {
    99         COM_errorLog("****************in getusergroups(uid=$uid,usergroups=$usergroups,cur_grp_id=$cur_grp_id)***************",1);
   100     }
   101 
   102     $groups = array();
   103 
   104     if (empty($uid)) {
   105         if (empty($_USER['uid'])) {
   106             $uid = 1;
   107         } else {
   108             $uid = $_USER['uid'];
   109         }
   110     }
   111 
   112     $result = DB_query("SELECT ug_main_grp_id,grp_name FROM {$_TABLES["group_assignments"]},{$_TABLES["groups"]}"
   113             . " WHERE grp_id = ug_main_grp_id AND ug_uid = $uid",1);
   114 
   115     if ($result == -1) {
   116         return $groups;
   117     }
   118 
   119     $nrows = DB_numRows($result);
   120 
   121     if ($_SEC_VERBOSE) {
   122         COM_errorLog("got $nrows rows",1);
   123     }
   124 
   125     while ($nrows > 0) {
   126         $cgroups = array();
   127 
   128         for ($i = 1; $i <= $nrows; $i++) {
   129             $A = DB_fetchArray($result);
   130 
   131             if ($_SEC_VERBOSE) {
   132                 COM_errorLog('user is in group ' . $A['grp_name'],1);
   133             }
   134             if (!in_array($A['ug_main_grp_id'], $groups)) {
   135                 array_push($cgroups, $A['ug_main_grp_id']);
   136                 $groups[$A['grp_name']] = $A['ug_main_grp_id'];
   137             }
   138         }
   139 
   140         if (count($cgroups) > 0) {
   141             $glist = join(',', $cgroups);
   142             $result = DB_query("SELECT ug_main_grp_id,grp_name FROM {$_TABLES["group_assignments"]},{$_TABLES["groups"]}"
   143                     . " WHERE grp_id = ug_main_grp_id AND ug_grp_id IN ($glist)",1);
   144             $nrows = DB_numRows($result);
   145         } else {
   146             $nrows = 0;
   147         }
   148     }
   149 
   150     uksort($groups, 'strcasecmp');
   151 
   152     if ($_SEC_VERBOSE) {
   153         COM_errorLog("****************leaving getusergroups(uid=$uid)***************",1);
   154     }
   155 
   156     return $groups;
   157 }
   158 
   159 /**
   160   * Checks to see if a user has admin access to the "Remote Users" group
   161   * Admin users will probably not be members, but, User Admin, Root, and
   162   * group admin will have access to it. However, we can not be sure what
   163   * the group id for "Remote User" group is, because it's a later static
   164   * group, and upgraded systems could have it in any id slot.
   165   *
   166   * @param      groupid     int     The id of a group, which might be the remote users group
   167   * @param      groups      array   Array of group ids the user has access to.
   168   * @return     boolean
   169   */
   170 function SEC_groupIsRemoteUserAndHaveAccess($groupid, $groups)
   171 {
   172     global $_TABLES, $_CONF;
   173     if(!isset($_CONF['remote_users_group_id']))
   174     {
   175         $result = DB_query("SELECT grp_id FROM {$_TABLES['groups']} WHERE grp_name='Remote Users'");
   176         if( $result )
   177         {
   178             $row = DB_fetchArray( $result );
   179             $_CONF['remote_users_group_id'] = $row['grp_id'];
   180         }
   181     }
   182     if( $groupid == $_CONF['remote_users_group_id'] )
   183     {
   184         if( in_array( 1, $groups ) || // root
   185             in_array( 9, $groups ) || // user admin
   186             in_array( 11, $groups ) // Group admin
   187           )
   188         {
   189             return true;
   190         } else {
   191             return false;
   192         }
   193     } else {
   194         return false;
   195     }
   196 }
   197 
   198 /**
   199 * Determines if user belongs to specified group
   200 *
   201 * This is part of the Geeklog security implementation. This function
   202 * looks up whether a user belongs to a specified group
   203 *
   204 * @param        string      $grp_to_verify      Group we want to see if user belongs to
   205 * @param        int         $uid                ID for user to check. If empty current user.
   206 * @param        string      $cur_grp_id         NOT USED Current group we are working with in hierarchy
   207 * @return       boolean     true if user is in group, otherwise false
   208 *
   209 */
   210 function SEC_inGroup($grp_to_verify,$uid='',$cur_grp_id='')
   211 {
   212     global $_TABLES, $_USER, $_SEC_VERBOSE, $_GROUPS;
   213 
   214     if (empty ($uid)) {
   215         if (empty ($_USER['uid'])) {
   216             $uid = 1;
   217         } else {
   218             $uid = $_USER['uid'];
   219         }
   220     }
   221 
   222     if ((empty($_USER['uid']) && ($uid == 1)) ||
   223             (isset($_USER['uid']) && ($uid == $_USER['uid']))) {
   224         if (empty($_GROUPS)) {
   225             $_GROUPS = SEC_getUserGroups($uid);
   226         }
   227         $groups = $_GROUPS;
   228     } else {
   229         $groups = SEC_getUserGroups($uid);
   230     }
   231 
   232     if (is_numeric($grp_to_verify)) {
   233         if (in_array($grp_to_verify, $groups)) {
   234            return true;
   235         } else {
   236            return false;
   237         }
   238     } else {
   239         if (!empty($groups[$grp_to_verify])) {
   240             return true;
   241         } else {
   242             return false;
   243         }
   244    }
   245 }
   246 
   247 /**
   248 * Determines if current user is a moderator of any kind
   249 *
   250 * Checks to see if this user is a moderator for any of the GL features OR
   251 * GL plugins
   252 *
   253 * @return   boolean     returns if user has any .moderate rights
   254 *
   255 */
   256 function SEC_isModerator()
   257 {
   258     global $_USER,$_RIGHTS;
   259 
   260     // Loop through GL core rights.
   261     for ($i = 0; $i < count($_RIGHTS); $i++) {
   262         if (stristr($_RIGHTS[$i],'.moderate')) {
   263             return true;
   264         }
   265     }
   266 
   267     // If we get this far they are not a Geeklog moderator
   268     // So, let's return if they're a plugin moderator
   269 
   270     return PLG_isModerator();
   271 }
   272 
   273 /**
   274 * Checks to see if current user has access to a topic
   275 *
   276 * Checks to see if current user has access to a topic
   277 *
   278 * @param        string      $tid        ID for topic to check on
   279 * @return       int 	returns 3 for read/edit 2 for read only 0 for no access
   280 *
   281 */
   282 function SEC_hasTopicAccess($tid)
   283 {
   284     global $_TABLES;
   285 
   286     if (empty($tid)) {
   287         return 0;
   288     }
   289 
   290     $result = DB_query("SELECT owner_id,group_id,perm_owner,perm_group,perm_members,perm_anon FROM {$_TABLES['topics']} WHERE tid = '$tid'");
   291     $A = DB_fetchArray($result);
   292 
   293     return SEC_hasAccess($A['owner_id'],$A['group_id'],$A['perm_owner'],$A['perm_group'],$A['perm_members'],$A['perm_anon']);
   294 }
   295 
   296 /**
   297 * Checks if current user has access to the given object
   298 *
   299 * This function takes the access info from a Geeklog object
   300 * and let's us know if they have access to the object
   301 * returns 3 for read/edit, 2 for read only and 0 for no
   302 * access
   303 *
   304 * @param        int     $owner_id       ID of the owner of object
   305 * @param        int     $group_id       ID of group object belongs to
   306 * @param        int     $perm_owner     Permissions the owner has
   307 * @param        int     $perm_group     Permissions the gorup has
   308 * @param        int     $perm_members   Permissions logged in members have
   309 * @param        int     $perm_anon      Permissions anonymous users have
   310 * @return       int 	returns 3 for read/edit 2 for read only 0 for no access
   311 *
   312 */
   313 function SEC_hasAccess($owner_id,$group_id,$perm_owner,$perm_group,$perm_members,$perm_anon)
   314 {
   315     global $_USER;
   316 
   317     // Cache current user id
   318     if (empty($_USER['uid'])) {
   319         $uid = 1;
   320     } else {
   321         $uid = $_USER['uid'];
   322     }
   323 
   324     // If user is in Root group then return full access
   325     if (SEC_inGroup('Root')) {
   326         return 3;
   327     }
   328 
   329     // If user is owner then return 1 now
   330     if ($uid == $owner_id) return $perm_owner;
   331 
   332     // Not private, if user is in group then give access
   333     if (SEC_inGroup($group_id)) {
   334         return $perm_group;
   335     } else {
   336         if ($uid == 1) {
   337             // This is an anonymous user, return it's rights
   338             return $perm_anon;
   339         } else {
   340             // This is a logged in member, return their rights
   341             return $perm_members;
   342         }
   343     }
   344 }
   345 
   346 /**
   347 * Checks if current user has rights to a feature
   348 *
   349 * Takes either a single feature or an array of features and returns
   350 * an array of whether the user has those rights
   351 *
   352 * @param        string|array        $features       Features to check
   353 * @param        string              $operator       Either 'and' or 'or'. Default is 'and'.  Used if checking more than one feature.
   354 * @return       boolean     Return true if current user has access to feature(s), otherwise false.
   355 *
   356 */
   357 function SEC_hasRights($features,$operator='AND')
   358 {
   359     global $_USER, $_RIGHTS, $_SEC_VERBOSE;
   360 
   361     if (strstr($features,',')) {
   362         $features = explode(',',$features);
   363     }
   364 
   365     if (is_array($features)) {
   366         // check all values passed
   367         for ($i = 0; $i < count($features); $i++) {
   368             if ($operator == 'OR') {
   369                 // OR operator, return as soon as we find a true one
   370                 if (in_array($features[$i],$_RIGHTS)) {
   371                     if ($_SEC_VERBOSE) {
   372                         COM_errorLog('SECURITY: user has access to ' . $features[$i],1);
   373                     }
   374                     return true;
   375                 }
   376             } else {
   377                 // this is an "AND" operator, bail if we find a false one
   378                 if (!in_array($features[$i],$_RIGHTS)) {
   379                     if ($_SEC_VERBOSE) {
   380                         COM_errorLog('SECURITY: user does not have access to ' . $features[$i],1);
   381                     }
   382                     return false;
   383                 }
   384             }
   385         }
   386 
   387         if ($operator == 'OR') {
   388             if ($_SEC_VERBOSE) {
   389                 COM_errorLog('SECURITY: user does not have access to ' . $features[$i],1);
   390             }
   391             return false;
   392                 } else {
   393             if ($_SEC_VERBOSE) {
   394                 COM_errorLog('SECURITY: user has access to ' . $features[$i],1);
   395             }
   396             return true;
   397         }
   398     } else {
   399         // Check the one value
   400         if ($_SEC_VERBOSE) {
   401             if (in_array($features,$_RIGHTS)) {
   402                 COM_errorLog('SECURITY: user has access to ' . $features,1);
   403             } else {
   404                 COM_errorLog('SECURITY: user does not have access to ' . $features,1);
   405             }
   406         }
   407         return in_array($features,$_RIGHTS);
   408     }
   409 }
   410 
   411 /**
   412 * Shows security control for an object
   413 *
   414 * This will return the HTML needed to create the security control see on the admin
   415 * screen for GL objects (i.e. stories, etc)
   416 *
   417 * @param        int     $perm_owner     Permissions the owner has 1 = edit 2 = read 3 = read/edit
   418 * @param        int     $perm_group     Permission the group has
   419 * @param        int     $perm_members   Permissions logged in members have
   420 * @param        int     $perm_anon      Permissions anonymous users have
   421 * @return       string  needed HTML (table) in HTML $perm_owner = array of permissions [edit,read], etc edit = 1 if permission, read = 2 if permission
   422 *
   423 */
   424 function SEC_getPermissionsHTML($perm_owner,$perm_group,$perm_members,$perm_anon)
   425 {
   426     global $LANG_ACCESS, $_CONF;
   427 
   428     $retval = '';
   429 
   430     $perm_templates = new Template($_CONF['path_layout'] . 'admin/common');
   431     $perm_templates->set_file(array('editor'=>'edit_permissions.thtml'));
   432 
   433     $perm_templates->set_var ( 'xhtml', XHTML );
   434     $perm_templates->set_var ('site_url', $_CONF['site_url']);
   435     $perm_templates->set_var ('site_admin_url', $_CONF['site_admin_url']);
   436     $perm_templates->set_var ('layout_url', $_CONF['layout_url']);
   437     $perm_templates->set_var ('owner', $LANG_ACCESS['owner']);
   438     $perm_templates->set_var ('group', $LANG_ACCESS['group']);
   439     $perm_templates->set_var ('members', $LANG_ACCESS['members']);
   440     $perm_templates->set_var ('anonymous', $LANG_ACCESS['anonymous']);
   441 
   442     // Owner Permissions
   443     if ($perm_owner >= 2) {
   444         $perm_templates->set_var ('owner_r_checked',' checked="checked"');
   445     }
   446     if ($perm_owner == 3) {
   447         $perm_templates->set_var ('owner_e_checked',' checked="checked"');
   448     }
   449     // Group Permissions
   450     if ($perm_group >= 2) {
   451         $perm_templates->set_var ('group_r_checked',' checked="checked"');
   452     }
   453     if ($perm_group == 3) {
   454         $perm_templates->set_var ('group_e_checked',' checked="checked"');
   455     }
   456     // Member Permissions
   457     if ($perm_members == 2) {
   458         $perm_templates->set_var ('members_checked',' checked="checked"');
   459     }
   460     // Anonymous Permissions
   461     if ($perm_anon == 2) {
   462         $perm_templates->set_var ('anon_checked',' checked="checked"');
   463     }
   464 
   465     $perm_templates->parse('output','editor');
   466     $retval .= $perm_templates->finish($perm_templates->get_var('output'));
   467 
   468     return $retval;
   469 }
   470 
   471 /**
   472 * Gets everything a user has permissions to within the system
   473 *
   474 * This is part of the Geeklog security implementation.  This function
   475 * will get all the permissions the current user has. Calls itself recursively.
   476 *
   477 * @param    int     $grp_id     DO NOT USE (Used for recursion) Current group function is working on
   478 * @param    int     $uid        User to check, if empty current user.
   479 * @return   string  returns comma delimited list of features the user has access to
   480 *
   481 */
   482 function SEC_getUserPermissions($grp_id='', $uid='')
   483 {
   484     global $_TABLES, $_USER, $_SEC_VERBOSE, $_GROUPS;
   485 
   486     $retval = '';
   487 
   488     if ($_SEC_VERBOSE) {
   489         COM_errorLog("**********inside SEC_getUserPermissions(grp_id=$grp_id)**********",1);
   490     }
   491 
   492     // Get user ID if we don't already have it
   493     if (empty ($uid)) {
   494         if (empty ($_USER['uid'])) {
   495             $uid = 1;
   496         } else {
   497             $uid = $_USER['uid'];
   498         }
   499     }
   500 
   501     if ((empty ($_USER['uid']) && ($uid == 1)) || ($uid == $_USER['uid'])) {
   502         if (empty ($_GROUPS)) {
   503             $_GROUPS = SEC_getUserGroups ($uid);
   504         }
   505         $groups = $_GROUPS;
   506     } else {
   507         $groups = SEC_getUserGroups ($uid);
   508     }
   509 
   510     if (empty($groups)) {
   511         // this shouldn't happen - make a graceful exit to avoid an SQL error
   512         return '';
   513     }
   514 
   515     $glist = join(',', $groups);
   516     $result = DB_query("SELECT DISTINCT ft_name FROM {$_TABLES["access"]},{$_TABLES["features"]} "
   517                      . "WHERE ft_id = acc_ft_id AND acc_grp_id IN ($glist)");
   518 
   519     $nrows = DB_numrows($result);
   520     for ($j = 1; $j <= $nrows; $j++) {
   521         $A = DB_fetchArray($result);
   522         if ($_SEC_VERBOSE) {
   523             COM_errorLog('Adding right ' . $A['ft_name'] . ' in SEC_getUserPermissions',1);
   524         }
   525         $retval .= $A['ft_name'];
   526         if ($j < $nrows) {
   527             $retval .= ',';
   528         }
   529     }
   530 
   531     return $retval;
   532 }
   533 
   534 /**
   535 * Converts permissions to numeric values
   536 *
   537 * This function will take all permissions for an object and get the numeric value
   538 * that can then be used to save the database.
   539 *
   540 * @param        array       $perm_owner     Array of owner permissions  These arrays are set up by SEC_getPermissionsHTML
   541 * @param        array       $perm_group     Array of group permissions
   542 * @param        array       $perm_members   Array of member permissions
   543 * @param        array       $perm_anon      Array of anonymous user permissions
   544 * @return       array       returns numeric equivalent for each permissions array (2 = read, 3=edit/read)
   545 * @see	SEC_getPermissionsHTML
   546 * @see  SEC_getPermissionValue
   547 *
   548 */
   549 function SEC_getPermissionValues($perm_owner,$perm_group,$perm_members,$perm_anon)
   550 {
   551     global $_SEC_VERBOSE;
   552 
   553     if ($_SEC_VERBOSE) {
   554         COM_errorLog('**** Inside SEC_getPermissionValues ****', 1);
   555     }
   556 
   557     if (is_array($perm_owner)) {
   558         $perm_owner = SEC_getPermissionValue($perm_owner);
   559     } else {
   560         $perm_owner = 0;
   561     }
   562 
   563     if (is_array($perm_group)) {
   564         $perm_group = SEC_getPermissionValue($perm_group);
   565     } else {
   566         $perm_group = 0;
   567     }
   568 
   569     if (is_array($perm_members)) {
   570         $perm_members = SEC_getPermissionValue($perm_members);
   571     } else {
   572         $perm_members = 0;
   573     }
   574 
   575     if (is_array($perm_anon)) {
   576         $perm_anon = SEC_getPermissionValue($perm_anon);
   577     } else {
   578         $perm_anon = 0;
   579     }
   580 
   581     if ($_SEC_VERBOSE) {
   582         COM_errorLog('perm_owner = ' . $perm_owner, 1);
   583         COM_errorLog('perm_group = ' . $perm_group, 1);
   584         COM_errorLog('perm_member = ' . $perm_members, 1);
   585         COM_errorLog('perm_anon = ' . $perm_anon, 1);
   586         COM_errorLog('**** Leaving SEC_getPermissionValues ****', 1);
   587     }
   588 
   589     return array($perm_owner,$perm_group,$perm_members,$perm_anon);
   590 }
   591 
   592 /**
   593 * Converts permission array into numeric value
   594 *
   595 * This function converts an array of permissions for either
   596 * the owner/group/members/anon and returns the numeric
   597 * equivalent.  This is typically called by the admin screens
   598 * to prepare the permissions to be save to the database
   599 *
   600 * @param        array       $perm_x     Array of permission values
   601 * @return       int         int representation of a permission array 2 = read 3 = edit/read
   602 * @see SEC_getPermissionValues
   603 *
   604 */
   605 function SEC_getPermissionValue($perm_x)
   606 {
   607     global $_SEC_VERBOSE;
   608 
   609     if ($_SEC_VERBOSE) {
   610         COM_errorLog('**** Inside SEC_getPermissionValue ***', 1);
   611     }
   612 
   613     $retval = 0;
   614 
   615     for ($i = 1; $i <= count($perm_x); $i++) {
   616         if ($_SEC_VERBOSE) {
   617             COM_errorLog("perm_x[$i] = " . current($perm_x), 1);
   618         }
   619         $retval = $retval + current($perm_x);
   620         next($perm_x);
   621     }
   622 
   623     // if they have edit rights, assume read rights
   624     if ($retval == 1) {
   625         $retval = 3;
   626     }
   627 
   628     if ($_SEC_VERBOSE) {
   629         COM_errorLog("Got $retval permission value", 1);
   630         COM_errorLog('**** Leaving SEC_getPermissionValue ***', 1);
   631     }
   632 
   633     return $retval;
   634 }
   635 
   636 /**
   637 * Return the group to a given feature.
   638 *
   639 * Scenario: We have a feature and we want to know from which group the user
   640 * got this feature. Always returns the lowest group ID, in case the feature
   641 * has been inherited from more than one group.
   642 *
   643 * @param    string  $feature    the feature, e.g 'story.edit'
   644 * @param    int     $uid        (optional) user ID
   645 * @return   int                 group ID or 0
   646 *
   647 */
   648 function SEC_getFeatureGroup ($feature, $uid = '')
   649 {
   650     global $_GROUPS, $_TABLES, $_USER;
   651 
   652     $ugroups = array ();
   653 
   654     if (empty ($uid)) {
   655         if (empty ($_USER['uid'])) {
   656             $uid = 1;
   657         } else {
   658             $uid = $_USER['uid'];
   659         }
   660     }
   661 
   662     if ((empty ($_USER['uid']) && ($uid == 1)) || ($uid == $_USER['uid'])) {
   663         if (empty ($_GROUPS)) {
   664             $_GROUPS = SEC_getUserGroups ($uid);
   665         }
   666         $ugroups = $_GROUPS;
   667     } else {
   668         $ugroups = SEC_getUserGroups ($uid);
   669     }
   670 
   671     $group = 0;
   672 
   673     $ft_id = DB_getItem ($_TABLES['features'], 'ft_id', "ft_name = '$feature'");
   674     if (($ft_id > 0) && (count($ugroups) > 0)) {
   675         $grouplist = implode (',', $ugroups);
   676         $result = DB_query ("SELECT acc_grp_id FROM {$_TABLES['access']} WHERE (acc_ft_id = $ft_id) AND (acc_grp_id IN ($grouplist)) ORDER BY acc_grp_id LIMIT 1");
   677         $A = DB_fetchArray ($result);
   678         if (isset ($A['acc_grp_id'])) {
   679             $group = $A['acc_grp_id'];
   680         }
   681     }
   682 
   683     return $group;
   684 }
   685 
   686 /**
   687 * Attempt to login a user.
   688 *
   689 * Checks a users username and password against the database. Returns
   690 * users status.
   691 *
   692 * @param    string  $username   who is logging in?
   693 * @param    string  $password   what they claim is their password
   694 * @param    int     $uid        This is an OUTPUT param, pass by ref,
   695 *                               sends back UID inside it.
   696 * @return   int                 user status, -1 for fail.
   697 *
   698 */
   699 function SEC_authenticate($username, $password, &$uid)
   700 {
   701     global $_CONF, $_TABLES, $LANG01;
   702 
   703     $result = DB_query("SELECT status, passwd, email, uid FROM {$_TABLES['users']} WHERE username='$username' AND ((remoteservice is null) or (remoteservice = ''))");
   704     $tmp = DB_error();
   705     $nrows = DB_numRows($result);
   706 
   707     if (($tmp == 0) && ($nrows == 1)) {
   708         $U = DB_fetchArray($result);
   709         $uid = $U['uid'];
   710         if ($U['status'] == USER_ACCOUNT_DISABLED) {
   711             // banned, jump to here to save an md5 calc.
   712             return USER_ACCOUNT_DISABLED;
   713         } elseif ($U['passwd'] != SEC_encryptPassword($password)) {
   714             return -1; // failed login
   715         } elseif ($U['status'] == USER_ACCOUNT_AWAITING_APPROVAL) {
   716             return USER_ACCOUNT_AWAITING_APPROVAL;
   717         } elseif ($U['status'] == USER_ACCOUNT_AWAITING_ACTIVATION) {
   718             // Awaiting user activation, activate:
   719             DB_change($_TABLES['users'], 'status', USER_ACCOUNT_ACTIVE,
   720                       'username', $username);
   721             return USER_ACCOUNT_ACTIVE;
   722         } else {
   723             return $U['status']; // just return their status
   724         }
   725     } else {
   726         $tmp = $LANG01[32] . ": '" . $username . "'";
   727         COM_errorLog($tmp, 1);
   728         return -1;
   729     }
   730 }
   731 
   732 /**
   733 * Return the current user status for a user.
   734 *
   735 * NOTE:     May not return for banned/non-approved users.
   736 *
   737 * @param    int  $userid   Valid uid value.
   738 * @return   int            user status, 0-3
   739 *
   740 */
   741 function SEC_checkUserStatus($userid)
   742 {
   743     global $_CONF, $_TABLES;
   744 
   745     // Check user status
   746     $status = DB_getItem($_TABLES['users'], 'status', "uid=$userid");
   747 
   748     // only do redirects if we aren't on users.php in a valid mode (logout or
   749     // default)
   750     if (strpos($_SERVER['PHP_SELF'], 'users.php') === false) {
   751         $redirect = true;
   752     } else {
   753         if (empty($_REQUEST['mode']) || ($_REQUEST['mode'] == 'logout')) {
   754             $redirect = false;
   755         } else {
   756             $redirect = true;
   757         }
   758     }
   759     if ($status == USER_ACCOUNT_AWAITING_ACTIVATION) {
   760         DB_change($_TABLES['users'], 'status', USER_ACCOUNT_ACTIVE, 'uid', $userid);
   761     } elseif ($status == USER_ACCOUNT_AWAITING_APPROVAL) {
   762         // If we aren't on users.php with a default action then go to it
   763         if ($redirect) {
   764             COM_accessLog("SECURITY: Attempted Cookie Session login from user awaiting approval $userid.");
   765             echo COM_refresh($_CONF['site_url'] . '/users.php?msg=70');
   766             exit;
   767         }
   768     } elseif ($status == USER_ACCOUNT_DISABLED) {
   769         if ($redirect) {
   770             COM_accessLog("SECURITY: Attempted Cookie Session login from banned user $userid.");
   771             echo COM_refresh($_CONF['site_url'] . '/users.php?msg=69');
   772             exit;
   773         }
   774     }
   775 
   776     return $status;
   777 }
   778 
   779 /**
   780   * Check to see if we can authenticate this user with a remote server
   781   *
   782   * A user has not managed to login localy, but has an @ in their user
   783   * name and we have enabled distributed authentication. Firstly, try to
   784   * see if we have cached the module that we used to authenticate them
   785   * when they signed up (i.e. they've actualy changed their password
   786   * elsewhere and we need to synch.) If not, then try to authenticate
   787   * them with /every/ authentication module. If this suceeds, create
   788   * a user for them.
   789   *
   790   * @param  string  $loginname Their username
   791   * @param  string  $passwd The password entered
   792   * @param  string  $server The server portion of $username
   793   * @param  string  $uid OUTPUT parameter, pass it by ref to get uid back.
   794   * @return int     user status, -1 for fail.
   795   */
   796 function SEC_remoteAuthentication(&$loginname, $passwd, $service, &$uid)
   797 {
   798     global $_CONF, $_TABLES;
   799 
   800     /* First try a local cached login */
   801     $remoteusername = addslashes($loginname);
   802     $remoteservice = addslashes($service);
   803     $result = DB_query("SELECT passwd, status, uid FROM {$_TABLES['users']} WHERE remoteusername='$remoteusername' AND remoteservice='$remoteservice'");
   804     $tmp = DB_error();
   805     $nrows = DB_numRows($result);
   806     if (($tmp == 0) && ($nrows == 1)) {
   807         $U = DB_fetchArray($result);
   808         $uid = $U['uid'];
   809         $mypass = $U['passwd']; // also used to see if the user existed later.
   810         if ($mypass == SEC_encryptPassword($passwd)) {
   811             /* Valid password for cached user, return status */
   812             return $U['status'];
   813         }
   814     }
   815 
   816     $service = COM_sanitizeFilename($service);
   817     $servicefile = $_CONF['path_system'] . 'classes/authentication/' . $service
   818                  . '.auth.class.php';
   819     if (file_exists($servicefile)) {
   820         require_once $servicefile;
   821 
   822         $authmodule = new $service();
   823         if ($authmodule->authenticate($loginname, $passwd)) {
   824             /* check to see if they have logged in before: */
   825             if (empty($mypass)) {
   826                 // no such user, create them
   827 
   828                 // Check to see if their remoteusername is unique locally
   829                 $checkName = DB_getItem($_TABLES['users'], 'username',
   830                                         "username='$remoteusername'");
   831                 if (!empty($checkName)) {
   832                     // no, call custom function.
   833                     if (function_exists('CUSTOM_uniqueRemoteUsername')) {
   834                         $loginname = CUSTOM_uniqueRemoteUsername($loginname,
   835                                                                  $service);
   836                     }
   837                 }
   838                 USER_createAccount($loginname, $authmodule->email, SEC_encryptPassword($passwd), $authmodule->fullname, $authmodule->homepage, $remoteusername, $remoteservice);
   839                 $uid = DB_getItem($_TABLES['users'], 'uid', "remoteusername = '$remoteusername' AND remoteservice='$remoteservice'");
   840                 // Store full remote account name:
   841                 DB_query("UPDATE {$_TABLES['users']} SET remoteusername='$remoteusername', remoteservice='$remoteservice', status=3 WHERE uid='$uid'");
   842                 // Add to remote users:
   843                 $remote_grp = DB_getItem($_TABLES['groups'], 'grp_id',
   844                                          "grp_name='Remote Users'");
   845                 DB_query("INSERT INTO {$_TABLES['group_assignments']} (ug_main_grp_id,ug_uid) VALUES ($remote_grp, $uid)");
   846                 return 3; // Remote auth precludes usersubmission,
   847                           // and integrates user activation, see?
   848             } else {
   849                 // user existed, update local password:
   850                 DB_change($_TABLES['users'], 'passwd', SEC_encryptPassword($passwd), array('remoteusername','remoteservice'), array($remoteusername,$remoteservice));
   851                 // and return their status
   852                 return DB_getItem($_TABLES['users'], 'status', "remoteusername='$remoteusername' AND remoteservice='$remoteservice'");
   853             }
   854         } else {
   855             return -1;
   856         }
   857     } else {
   858         return -1;
   859     }
   860 }
   861 
   862 /**
   863 * Return available modules for Remote Authentication
   864 *
   865 * @return   array   Names of available remote authentication modules
   866 *
   867 */
   868 function SEC_collectRemoteAuthenticationModules()
   869 {
   870     global $_CONF;
   871 
   872     $modules = array();
   873 
   874     $modulespath = $_CONF['path_system'] . 'classes/authentication/';
   875     if (is_dir($modulespath)) {
   876         $folder = opendir($modulespath);
   877         while (($filename = @readdir($folder)) !== false) {
   878             $pos = strpos($filename, '.auth.class.php');
   879             if ($pos && (substr($filename, strlen($filename) - 4) == '.php')) {
   880                 $modules[] = substr($filename, 0, $pos);
   881             }
   882         }
   883     }
   884 
   885     return $modules;
   886 }
   887 
   888 /**
   889   * Add user to a group
   890   *
   891   * work in progress
   892   *
   893   * Rather self explanitory shortcut function
   894   * Is this the right place for this, Dirk?
   895   *
   896   * @author Trinity L Bays, trinity93 AT gmail DOT com
   897   *
   898   * @param  string  $uid Their user id
   899   * @param  string  $gname The group name
   900   * @return boolean status, true or false.
   901   */
   902 function SEC_addUserToGroup($uid, $gname)
   903 {
   904     global $_TABLES, $_CONF;
   905 
   906     $remote_grp = DB_getItem ($_TABLES['groups'], 'grp_id', "grp_name='". $gname ."'");
   907     DB_query ("INSERT INTO {$_TABLES['group_assignments']} (ug_main_grp_id,ug_uid) VALUES ($remote_grp, $uid)");
   908 }
   909 
   910 /**
   911 * Set default permissions for an object
   912 *
   913 * @param    array   $A                  target array
   914 * @param    array   $use_permissions    permissions to set
   915 *
   916 */
   917 function SEC_setDefaultPermissions (&$A, $use_permissions = array ())
   918 {
   919     if (!is_array ($use_permissions) || (count ($use_permissions) != 4)) {
   920         $use_permissions = array (3, 2, 2, 2);
   921     }
   922 
   923     // sanity checks
   924     if (($use_permissions[0] > 3) || ($use_permissions[0] < 0) ||
   925             ($use_permissions[0] == 1)) {
   926         $use_permissions[0] = 3;
   927     }
   928     if (($use_permissions[1] > 3) || ($use_permissions[1] < 0) ||
   929             ($use_permissions[1] == 1)) {
   930         $use_permissions[1] = 2;
   931     }
   932     if (($use_permissions[2] != 2) && ($use_permissions[2] != 0)) {
   933         $use_permissions[2] = 2;
   934     }
   935     if (($use_permissions[3] != 2) && ($use_permissions[3] != 0)) {
   936         $use_permissions[3] = 2;
   937     }
   938 
   939     $A['perm_owner']   = $use_permissions[0];
   940     $A['perm_group']   = $use_permissions[1];
   941     $A['perm_members'] = $use_permissions[2];
   942     $A['perm_anon']    = $use_permissions[3];
   943 }
   944 
   945 
   946 /**
   947 * Common function used to build group access SQL
   948 *
   949 * @param   string  $clause    Optional parm 'WHERE' - default is 'AND'
   950 * @return  string  $groupsql  Formatted SQL string to be appended in calling script SQL statement
   951 */
   952 function SEC_buildAccessSql ($clause = 'AND')
   953 {
   954     global $_TABLES, $_USER;
   955 
   956     if (isset($_USER) AND $_USER['uid'] > 1) {
   957         $uid = $_USER['uid'];
   958     } else {
   959         $uid = 1;
   960     }
   961 
   962     $_GROUPS = SEC_getUserGroups($uid);
   963     $groupsql = '';
   964     if (count($_GROUPS) == 1) {
   965         $groupsql .= " $clause grp_access = '" . current($_GROUPS) ."'";
   966     } else {
   967         $groupsql .= " $clause grp_access IN (" . implode(',',array_values($_GROUPS)) .")";
   968     }
   969 
   970     return $groupsql;
   971 }
   972 
   973 /**
   974 * Remove a feature from the database entirely.
   975 *
   976 * This function can be used by plugins during uninstall.
   977 *
   978 * @param    string  $feature_name   name of the feature, e.g. 'foo.edit'
   979 * @param    boolean $logging        whether to log progress in error.log
   980 * @return   void
   981 *
   982 */
   983 function SEC_removeFeatureFromDB ($feature_name, $logging = false)
   984 {
   985     global $_TABLES;
   986 
   987     if (!empty ($feature_name)) {
   988         $feat_id = DB_getItem ($_TABLES['features'], 'ft_id',
   989                                "ft_name = '$feature_name'");
   990         if (!empty ($feat_id)) {
   991             // Before removing the feature itself, remove it from all groups
   992             if ($logging) {
   993                 COM_errorLog ("Attempting to remove '$feature_name' rights from all groups", 1);
   994             }
   995             DB_delete ($_TABLES['access'], 'acc_ft_id', $feat_id);
   996             if ($logging) {
   997                 COM_errorLog ('...success', 1);
   998             }
   999 
  1000             // now remove the feature itself
  1001             if ($logging) {
  1002                 COM_errorLog ("Attempting to remove the '$feature_name' feature", 1);
  1003             }
  1004             DB_delete ($_TABLES['features'], 'ft_id', $feat_id);
  1005             if ($logging) {
  1006                 COM_errorLog ('...success', 1);
  1007             }
  1008         } else if ($logging) {
  1009             COM_errorLog ("SEC_removeFeatureFromDB: Feature '$feature_name' not found.");
  1010         }
  1011     }
  1012 }
  1013 
  1014 /**
  1015 * Create a group dropdown
  1016 *
  1017 * Creates the group dropdown menu that's used on pretty much every admin page
  1018 *
  1019 * @param    int     $group_id   current group id (to be selected)
  1020 * @param    int     $access     access permission
  1021 * @return   string              HTML for the dropdown
  1022 *
  1023 */
  1024 function SEC_getGroupDropdown ($group_id, $access)
  1025 {
  1026     global $_TABLES;
  1027 
  1028     $groupdd = '';
  1029 
  1030     if ($access == 3) {
  1031         $usergroups = SEC_getUserGroups ();
  1032 
  1033         $groupdd .= '<select name="group_id">' . LB;
  1034         foreach ($usergroups as $ug_name => $ug_id) {
  1035             $groupdd .= '<option value="' . $ug_id . '"';
  1036             if ($group_id == $ug_id) {
  1037                 $groupdd .= ' selected="selected"';
  1038             }
  1039             $groupdd .= '>' . ucwords($ug_name) . '</option>' . LB;
  1040         }
  1041         $groupdd .= '</select>' . LB;
  1042     } else {
  1043         // They can't set the group then
  1044         $groupdd .= DB_getItem ($_TABLES['groups'], 'grp_name',
  1045                                 "grp_id = '$group_id'")
  1046                  . '<input type="hidden" name="group_id" value="' . $group_id
  1047                  . '"' . XHTML . '>';
  1048     }
  1049 
  1050     return $groupdd;
  1051 }
  1052 
  1053 /**
  1054 * Encrypt password
  1055 *
  1056 * For now, this is only a wrapper function to get all the direct calls to
  1057 * md5() out of the core code so that we can switch to another method of
  1058 * encoding / encrypting our passwords in some future release ...
  1059 *
  1060 * @param    string  $password   the password to encrypt, in clear text
  1061 * @return   string              encrypted password
  1062 *
  1063 */
  1064 function SEC_encryptPassword($password)
  1065 {
  1066     return md5($password);
  1067 }
  1068 
  1069 /**
  1070   * Generate a security token.
  1071   *
  1072   * This generates and stores a one time security token. Security tokens are
  1073   * added to forms and urls in the admin section as a non-cookie double-check
  1074   * that the admin user really wanted to do that...
  1075   *
  1076   * @param $ttl int Time to live for token in seconds. Default is 20 minutes.
  1077   *
  1078   * @return string  Generated token, it'll be an MD5 hash (32chars)
  1079   */
  1080 function SEC_createToken($ttl = 1200)
  1081 {
  1082     global $_USER, $_TABLES, $_DB_dbms;
  1083 
  1084     static $last_token;
  1085 
  1086     if (isset($last_token)) {
  1087         return $last_token;
  1088     }
  1089     
  1090     /* Figure out the full url to the current page */
  1091     $pageURL = COM_getCurrentURL();
  1092     
  1093     /* Generate the token */
  1094     $token = md5($_USER['uid'].$pageURL.uniqid (rand (), 1));
  1095     $pageURL = addslashes($pageURL);
  1096 
  1097     /* Destroy exired tokens: */
  1098     $sql['mssql'] = "DELETE FROM {$_TABLES['tokens']} WHERE (DATEADD(ss, ttl, created) < NOW()) AND (ttl > 0)";
  1099     $sql['mysql'] = "DELETE FROM {$_TABLES['tokens']} WHERE (DATE_ADD(created, INTERVAL ttl SECOND) < NOW()) AND (ttl > 0)";
  1100     DB_query($sql);
  1101 
  1102     /* Destroy tokens for this user/url combination */
  1103     $sql = "DELETE FROM {$_TABLES['tokens']} WHERE owner_id={$_USER['uid']} AND urlfor='$pageURL'";
  1104     DB_query($sql);
  1105     
  1106     /* Create a token for this user/url combination */
  1107     /* NOTE: TTL mapping for PageURL not yet implemented */
  1108     $sql = "INSERT INTO {$_TABLES['tokens']} (token, created, owner_id, urlfor, ttl) "
  1109            . "VALUES ('$token', NOW(), {$_USER['uid']}, '$pageURL', $ttl)";
  1110     DB_query($sql);
  1111            
  1112     $last_token = $token;
  1113 
  1114     /* And return the token to the user */
  1115     return $token;
  1116 }
  1117 
  1118 /**
  1119   * Check a security token.
  1120   *
  1121   * Checks the POST and GET data for a security token, if one exists, validates that it's for this
  1122   * user and URL.
  1123   *
  1124   * @return boolean     true if the token is valid and for this user.
  1125   */
  1126 function SEC_checkToken()
  1127 {
  1128     global $_USER, $_TABLES, $_DB_dbms;
  1129     
  1130     $token = ''; // Default to no token.
  1131     $return = false; // Default to fail.
  1132     
  1133     if(array_key_exists(CSRF_TOKEN, $_GET)) {
  1134         $token = COM_applyFilter($_GET[CSRF_TOKEN]);
  1135     } else if(array_key_exists(CSRF_TOKEN, $_POST)) {
  1136         $token = COM_applyFilter($_POST[CSRF_TOKEN]);
  1137     }
  1138     
  1139     if (trim($token) != '') {
  1140         $sql['mysql'] = "SELECT ((DATE_ADD(created, INTERVAL ttl SECOND) < NOW()) AND ttl > 0) as expired, owner_id, urlfor FROM {$_TABLES['tokens']} WHERE token='$token'";
  1141         $sql['mssql'] = "SELECT owner_id, urlfor, expired = 
  1142                       CASE 
  1143                          WHEN (DATEADD(s,ttl,created) < getUTCDate()) AND (ttl>0) THEN 1
  1144                 
  1145                          ELSE 0
  1146                       END
  1147                     FROM {$_TABLES['tokens']} WHERE token='$token'";
  1148         $tokens = DB_query($sql);
  1149 
  1150         $numberOfTokens = DB_numRows($tokens);
  1151         if($numberOfTokens != 1) {
  1152             $return = false; // none, or multiple tokens. Both are invalid. (token is unique key...)
  1153         } else {
  1154             $tokendata = DB_fetchArray($tokens);
  1155             /* Check that:
  1156              *  token's user is the current user.
  1157              *  token is not expired.
  1158              *  the http referer is the url for which the token was created.
  1159              */
  1160             if( $_USER['uid'] != $tokendata['owner_id'] ) {
  1161                 $return = false;
  1162             } else if($tokendata['urlfor'] != $_SERVER['HTTP_REFERER']) {
  1163                 $return = false;
  1164             } else if($tokendata['expired']) {
  1165                 $return = false;
  1166             } else {
  1167                 $return = true; // Everything is AOK in only one condition...
  1168             }
  1169            
  1170             // It's a one time token. So eat it.
  1171             DB_delete($_TABLES['tokens'], 'token', $token);
  1172         }
  1173     } else {
  1174         $return = false; // no token.
  1175     }
  1176     
  1177     return $return;
  1178 }
  1179 
  1180 /**
  1181 * Get a token's expiry time
  1182 *
  1183 * @param    string  $token  the token we're looking for
  1184 * @return   int             UNIX timestamp of the expiry time or 0
  1185 *
  1186 */
  1187 function SEC_getTokenExpiryTime($token)
  1188 {
  1189     global $_TABLES, $_USER;
  1190 
  1191     $retval = 0;
  1192 
  1193     if (!COM_isAnonUser()) {
  1194 
  1195         $sql['mysql'] = "SELECT UNIX_TIMESTAMP(DATE_ADD(created, INTERVAL ttl SECOND)) AS expirytime FROM {$_TABLES['tokens']} WHERE (token = '$token') AND (owner_id = '{$_USER['uid']}') AND (ttl > 0)";
  1196         $sql['mssql'] = "SELECT UNIX_TIMESTAMP(DATEADD(ss, ttl, created)) AS expirytime FROM {$_TABLES['tokens']} WHERE (token = '$token') AND (owner_id = '{$_USER['uid']}') AND (ttl > 0)";
  1197 
  1198         $result = DB_query($sql);
  1199         if (DB_numRows($result) == 1) {
  1200             list($retval) = DB_fetchArray($result);
  1201         }
  1202     }
  1203 
  1204     return $retval;
  1205 }
  1206 
  1207 /**
  1208 * Set a cookie using the HttpOnly flag
  1209 *
  1210 * Use this function to set "important" cookies (session, password, ...).
  1211 * Browsers that support the HttpOnly flag will not allow JavaScript access
  1212 * to such a cookie.
  1213 *
  1214 * @param    string  $name       cookie name
  1215 * @param    string  $value      cookie value
  1216 * @param    int     $expire     expire time
  1217 * @param    string  $path       path on the server or $_CONF['cookie_path']
  1218 * @param    string  $domain     domain or $_CONF['cookiedomain']
  1219 * @param    bool    $secure     whether to use HTTPS or $_CONF['cookiesecure']
  1220 * @link http://blog.mattmecham.com/2006/09/12/http-only-cookies-without-php-52/
  1221 *
  1222 */
  1223 function SEC_setCookie($name, $value, $expire = 0, $path = null, $domain = null, $secure = null)
  1224 {
  1225     global $_CONF;
  1226 
  1227     $retval = false;
  1228 
  1229     if ($path === null) {
  1230         $path = $_CONF['cookie_path'];
  1231     }
  1232     if ($domain === null) {
  1233         $domain = $_CONF['cookiedomain'];
  1234     }
  1235     if ($secure === null) {
  1236         $secure = $_CONF['cookiesecure'];
  1237     }
  1238 
  1239     // the httponly parameter is only available as of PHP 5.2.0
  1240     if (version_compare(PHP_VERSION, '5.2.0', '>=')) {
  1241         $retval = setcookie($name, $value, $expire, $path, $domain, $secure,
  1242                             true);
  1243     } else {
  1244         // fake it for older PHP versions; kudos to Matt Mecham
  1245         $retval = setcookie($name, $value, $expire, $path,
  1246                             $domain . '; httponly', $secure);
  1247     }
  1248 
  1249     return $retval;
  1250 }
  1251 
  1252 /**
  1253 * Prepare an array of the standard permission values
  1254 *
  1255 * This helper functions does the following:
  1256 * 1) filter permission values, e.g. after a POST request
  1257 * 2) translates the permission checkbox arrays into numerical values
  1258 * 3) ensures that all the standard permission entries are set, so you don't
  1259 *    have to check with isset() all the time
  1260 *
  1261 * <code>
  1262 * $PERM = SEC_filterPermissions($_POST);
  1263 * if ($PERM['perm_anon'] != 0) { ...
  1264 * </code>
  1265 *
  1266 * @param    array   $A  array to filter on, e.g. $_POST
  1267 * @return   array       array of only the 6 standard permission values
  1268 * @see      SEC_getPermissionValues
  1269 *
  1270 */
  1271 function SEC_filterPermissions($A)
  1272 {
  1273     $retval = array();
  1274 
  1275     if (isset($A['owner_id'])) {
  1276         $retval['owner_id'] = COM_applyFilter($A['owner_id'], true);
  1277     } else {
  1278         $retval['owner_id'] = 0;
  1279     }
  1280 
  1281     if (isset($A['group_id'])) {
  1282         $retval['group_id'] = COM_applyFilter($A['group_id'], true);
  1283     } else {
  1284         $retval['group_id'] = 0;
  1285     }
  1286 
  1287     $perms = array('perm_owner', 'perm_group', 'perm_members', 'perm_anon');
  1288 
  1289     $B = array();
  1290     foreach ($perms as $p) {
  1291         if (isset($A[$p])) {
  1292             $B[$p] = $A[$p];
  1293         } else {
  1294             $B[$p] = array();
  1295         }
  1296     }
  1297 
  1298     $B = SEC_getPermissionValues($B['perm_owner'], $B['perm_group'],
  1299                                  $B['perm_members'], $B['perm_anon']);
  1300     for ($i = 0; $i < 4; $i++) {
  1301         $retval[$perms[$i]] = $B[$i];
  1302     }
  1303 
  1304     return $retval;
  1305 }
  1306 
  1307 /**
  1308 * Helper function for when you want to call SEC_hasAccess and have all the
  1309 * values to check in an array.
  1310 *
  1311 * @param    array   $A  array with the standard permission values
  1312 * @return   int         returns 3 for read/edit 2 for read only 0 for no access
  1313 * @see      SEC_hasAccess
  1314 *
  1315 */
  1316 function SEC_hasAccess2($A)
  1317 {
  1318     return SEC_hasAccess($A['owner_id'], $A['group_id'], $A['perm_owner'],
  1319                          $A['perm_group'], $A['perm_members'], $A['perm_anon']);
  1320 }
  1321 
  1322 ?>