3 * SourceForge Session Module
5 * Copyright 1999-2001 (c) VA Linux Systems
9 * This file is part of GForge.
11 * GForge is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * GForge is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with GForge; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 require_once('common/include/account.php');
27 require_once('common/include/escapingUtils.php');
30 * A User object if user is logged in
32 * @var constant $G_SESSION
39 $session_ser = getStringFromCookie('session_ser');
42 * session_build_session_cookie() - Construct session cookie for the user
44 * @param int User_id of the logged in user
45 * @return cookie value
47 function session_build_session_cookie($user_id) {
48 $session_serial = $user_id.'-*-'.time().'-*-'.getStringFromServer('REMOTE_ADDR').'-*-'.getStringFromServer('HTTP_USER_AGENT');
49 $session_serial_hash = md5($session_serial.$GLOBALS['sys_session_key']);
50 $session_serial_cookie = base64_encode($session_serial).'-*-'.$session_serial_hash;
51 return $session_serial_cookie;
55 * session_get_session_cookie_hash() - Get hash of session cookie
57 * This hash can be used as a key to identify session, e.g. in DB.
59 * @param string Value of the session cookie
62 function session_get_session_cookie_hash($session_cookie) {
63 list ($junk, $hash) = explode('-*-', $session_cookie);
68 * session_check_session_cookie() - Check that session cookie passed from user is ok
70 * @param string Value of the session cookie
71 * @return user_id if cookie is ok, false otherwise
73 function session_check_session_cookie($session_cookie) {
75 list ($session_serial, $hash) = explode('-*-', $session_cookie);
76 $session_serial = base64_decode($session_serial);
77 $new_hash = md5($session_serial.$GLOBALS['sys_session_key']);
79 if ($hash != $new_hash) {
83 list($user_id, $time, $ip, $user_agent) = explode('-*-', $session_serial, 4);
85 if (!session_check_ip($ip, getStringFromServer('REMOTE_ADDR'))) {
88 if (trim($user_agent) != getStringFromServer('HTTP_USER_AGENT')) {
91 if (($GLOBALS['sys_session_expire'] > 0) &&
92 ($time - time() >= $GLOBALS['sys_session_expire'])) {
100 * session_logout() - Log the user off the system.
102 * This function destroys object associated with the current session,
103 * making user "logged out". Deletes both user and session cookies.
108 function session_logout() {
110 // delete both session and username cookies
111 // NB: cookies must be deleted with the same scope parameters they were set with
113 session_cookie('session_ser', '');
118 * session_login_valid() - Log the user to the system.
120 * High-level function for user login. Check credentials, and if they
121 * are valid, open new session.
123 * @param string User name
124 * @param string User password (in clear text)
125 * @param bool Allow login to non-confirmed user account (only for confirmation of the very account)
126 * @return true/false, if false reason is in global $feedback
130 function session_login_valid($loginname, $passwd, $allowpending=0) {
131 global $feedback,$Language;
133 if (!$loginname || !$passwd) {
134 $feedback = _('Missing Password Or Users Name');
138 $hook_params = array () ;
139 $hook_params['loginname'] = $loginname ;
140 $hook_params['passwd'] = $passwd ;
141 plugin_hook ("session_before_login", $hook_params) ;
143 return session_login_valid_dbonly ($loginname, $passwd, $allowpending) ;
146 function session_login_valid_dbonly ($loginname, $passwd, $allowpending) {
147 global $feedback,$userstatus,$Language;
149 // Try to get the users from the database using user_id and (MD5) user_pw
151 SELECT user_id,status,unix_pw
153 WHERE user_name='$loginname'
154 AND user_pw='".md5($passwd)."'
156 if (!$res || db_numrows($res) < 1) {
157 // No user whose MD5 passwd matches the MD5 of the provided passwd
158 // Selecting by user_name only
159 $res = db_query("SELECT user_id,status,unix_pw
161 WHERE user_name='$loginname'");
162 if (!$res || db_numrows($res) < 1) {
163 // No user by that name
164 $feedback=_('Invalid Password Or User Name');
167 // There is a user with the provided user_name, but the MD5 passwds do not match
168 // We'll have to try checking the (crypt) unix_pw
169 $usr = db_fetch_array($res);
171 if (crypt ($passwd, $usr['unix_pw']) != $usr['unix_pw']) {
172 // Even the (crypt) unix_pw does not patch
173 // This one has clearly typed a bad passwd
174 $feedback=_('Invalid Password Or User Name');
177 // User exists, (crypt) unix_pw matches
178 // Update the (MD5) user_pw and retry authentication
179 // It should work, except for status errors
180 $res = db_query ("UPDATE users
181 SET user_pw='" . md5($passwd) . "'
182 WHERE user_id='".$usr['user_id']."'");
183 return session_login_valid_dbonly($loginname, $passwd, $allowpending) ;
186 // If we're here, then the user has typed a password matching the (MD5) user_pw
187 // Let's check whether it also matches the (crypt) unix_pw
188 $usr = db_fetch_array($res);
190 if (crypt ($passwd, $usr['unix_pw']) != $usr['unix_pw']) {
191 // The (crypt) unix_pw does not match
192 if ($usr['unix_pw'] == '') {
193 // Empty unix_pw, we'll take the MD5 as authoritative
194 // Update the (crypt) unix_pw and retry authentication
195 // It should work, except for status errors
196 $res = db_query ("UPDATE users
197 SET unix_pw='" . account_genunixpw($passwd) . "'
198 WHERE user_id='".$usr['user_id']."'");
199 return session_login_valid_dbonly($loginname, $passwd, $allowpending) ;
201 // Invalidate (MD5) user_pw, refuse authentication
202 $res = db_query ("UPDATE users
203 SET user_pw='OUT OF DATE'
204 WHERE user_id='".$usr['user_id']."'");
205 $feedback=_('Invalid Password Or User Name');
211 // Yay. The provided password matches both fields in the database.
212 // Let's check the status of this user
214 // if allowpending (for verify.php) then allow
215 $userstatus=$usr['status'];
216 if ($allowpending && ($usr['status'] == 'P')) {
219 if ($usr['status'] == 'S') {
221 $feedback = _('Account Suspended');
224 if ($usr['status'] == 'P') {
226 $feedback = _('Account Pending');
229 if ($usr['status'] == 'D') {
231 $feedback = _('Account Deleted');
234 if ($usr['status'] != 'A') {
235 //unacceptable account flag
236 $feedback = _('Account Not Active');
240 //create a new session
241 session_set_new(db_result($res,0,'user_id'));
248 * session_check_ip() - Check 2 IP addresses for match
250 * This function checks that IP addresses match with the
251 * given fuzz factor (within 255.255.0.0 subnet).
253 * @param string The old IP address
254 * @param string The new IP address
258 function session_check_ip($oldip,$newip) {
259 $eoldip = explode(".",$oldip);
260 $enewip = explode(".",$newip);
262 // ## require same class b subnet
263 if (($eoldip[0]!=$enewip[0])||($eoldip[1]!=$enewip[1])) {
271 * session_issecure() - Check if current session is secure
276 function session_issecure() {
277 return (strtoupper(getStringFromServer('HTTPS')) == "ON");
281 * session_cookie() - Set a session cookie
283 * Set a cookie with default temporal scope of the current browser session
284 * and URL space of the current webserver
286 * @param string Name of cookie
287 * @param string Value of cookie
288 * @param string Domain scope (default '')
289 * @param string Expiration time in UNIX seconds (default 0)
292 function session_cookie($name ,$value, $domain = '', $expiration = 0) {
293 if ( $expiration != 0){
294 setcookie($name, $value, time() + $expiration, '/', $domain, 0);
296 setcookie($name, $value, $expiration, '/', $domain, 0);
301 * session_redirect() - Redirect browser within the site
303 * @param string Absolute path within the site
304 * @return never returns
306 function session_redirect($loc) {
307 header('Location: http' . (session_issecure()?'s':'') . '://' . getStringFromServer('HTTP_HOST') . $loc);
313 * session_require() - Convenience function to easily enforce permissions
315 * Calling page will terminate with error message if current user
318 * @param array Associative array specifying criteria
319 * @return does not return if check is failed
322 function session_require($req) {
323 if (!session_loggedin()) {
324 exit_not_logged_in();
328 $group =& group_get_object($req['group']);
329 if (!$group || !is_object($group)) {
330 exit_error('Error','Could Not Get Group');
331 } elseif ($group->isError()) {
332 exit_error('Error',$group->getErrorMessage());
335 $perm =& $group->getPermission( session_get_user() );
336 if (!$perm || !is_object($perm) || $perm->isError()) {
337 exit_permission_denied();
340 //don't really like this, but as admin_flags is not mandatory
341 //I add @ to remove the warning
342 if (@$req['admin_flags']) {
343 if (!$perm->isAdmin()) {
344 exit_permission_denied();
347 if (!$perm->isMember()) {
348 exit_permission_denied();
351 } else if ($req['isloggedin']) {
352 //no need to check as long as the check is present at top of function
354 exit_permission_denied();
359 * session_set_new() - Setup session for the given user
361 * This function sets up SourceForge session for the given user,
362 * making one be "logged in".
364 * @param int The user ID
367 function session_set_new($user_id) {
368 global $G_SESSION,$session_ser,$Language;
370 // set session cookie
372 $cookie = session_build_session_cookie($user_id);
373 session_cookie("session_ser", $cookie, "", $GLOBALS['sys_session_expire']);
374 $session_ser=$cookie;
377 INSERT INTO user_session (session_hash, ip_addr, time, user_id)
379 '".session_get_session_cookie_hash($cookie)."',
380 '".getStringFromServer('REMOTE_ADDR')."',
386 // check uniqueness of the session_hash in the database
388 $res = session_getdata($user_id);
390 if (!$res || db_numrows($res) < 1) {
391 exit_error(_('ERROR'),_('ERROR').": ".db_error());
394 //set up the new user object
396 $G_SESSION = user_get_object($user_id,$res);
398 $G_SESSION->setLoggedIn(true);
405 * Private optimization function for logins - fetches user data, language, and session
408 * @param int The user ID
411 function session_getdata($user_id) {
412 $res=db_query("SELECT
413 u.*,sl.language_id, sl.name, sl.filename, sl.classname, sl.language_code, t.dirname, t.fullname
415 supported_languages sl,
417 WHERE u.language=sl.language_id
418 AND u.theme_id=t.theme_id
419 AND u.user_id='$user_id'");
424 * session_set() - Re-initialize session for the logged in user
426 * This function checks that the user is logged in and if so, initialize
427 * internal session environment.
431 function session_set() {
432 plugin_hook('session_set_entry');
434 global $session_ser, $session_key;
436 // assume bad session_hash and session. If all checks work, then allow
437 // otherwise make new session
440 // If user says he's logged in (by presenting cookie), check that
443 $user_id = session_check_session_cookie($session_ser);
447 $result = session_getdata($user_id);
449 if (db_numrows($result) > 0) {
453 } // else (hash does not exist) or (session hash is bad)
456 $G_SESSION = user_get_object($user_id, $result);
458 $G_SESSION->setLoggedIn(true);
463 // if there was bad session cookie, kill it and the user cookie
469 plugin_hook('session_set_return');
472 //TODO - this should be generalized and used for pre.php, squal_pre.php,
473 //SOAP, forum_gateway.php, tracker_gateway.php, etc to
475 function session_continue($sessionKey) {
476 global $session_ser, $Language, $sys_strftimefmt, $sys_datefmt;
477 $session_ser = $sessionKey;
479 $Language=new BaseLanguage();
480 $Language->loadLanguage("English"); // TODO use the user's default language
481 setlocale (LC_TIME, _('en_US'));
482 $sys_strftimefmt = _('%Y %B %e %H:%M');
483 $sys_datefmt = _('Y-m-d H:i');
484 $LUSER =& session_get_user();
485 if (!is_object($LUSER) || $LUSER->isError()) {
488 putenv('TZ='. $LUSER->getTimeZone());
494 * session_get_user() - Wrapper function to return the User object for the logged in user.
499 function &session_get_user() {
506 * Get user_id of logged in user
509 function user_getid() {
512 return $G_SESSION->getID();
520 * See if user is logged in
522 function session_loggedin() {
526 return $G_SESSION->isLoggedIn();