PageRenderTime 27ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/gforge/common/include/session.php

https://github.com/mathieu/fusionforge
PHP | 552 lines | 261 code | 57 blank | 234 comment | 75 complexity | 4a61307dc05f33f9b3cb0a26b576147c MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, GPL-2.0
  1. <?php
  2. /**
  3. * FusionForge session management
  4. *
  5. * Copyright 1999-2001, VA Linux Systems, Inc.
  6. * Copyright 2001-2002, Roland Mas
  7. * Copyright 2004-2005, GForge, LLC
  8. *
  9. * This file is part of FusionForge.
  10. *
  11. * FusionForge is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published
  13. * by the Free Software Foundation; either version 2 of the License,
  14. * or (at your option) any later version.
  15. *
  16. * FusionForge is distributed in the hope that it will be useful, but
  17. * WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with FusionForge; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  24. * USA
  25. */
  26. require_once $gfcommon.'include/account.php';
  27. require_once $gfcommon.'include/escapingUtils.php';
  28. /**
  29. * A User object if user is logged in
  30. *
  31. * @var constant $G_SESSION
  32. */
  33. $G_SESSION = false;
  34. /**
  35. * Get session id
  36. */
  37. $session_ser = getStringFromCookie('session_ser');
  38. /**
  39. * session_build_session_cookie() - Construct session cookie for the user
  40. *
  41. * @param int User_id of the logged in user
  42. * @return cookie value
  43. */
  44. function session_build_session_cookie($user_id) {
  45. $session_serial = $user_id.'-*-'.time().'-*-'.getStringFromServer('REMOTE_ADDR').'-*-'.getStringFromServer('HTTP_USER_AGENT');
  46. $session_serial_hash = md5($session_serial.$GLOBALS['sys_session_key']);
  47. $session_serial_cookie = base64_encode($session_serial).'-*-'.$session_serial_hash;
  48. return $session_serial_cookie;
  49. }
  50. /**
  51. * session_get_session_cookie_hash() - Get hash of session cookie
  52. *
  53. * This hash can be used as a key to identify session, e.g. in DB.
  54. *
  55. * @param string Value of the session cookie
  56. * @return hash
  57. */
  58. function session_get_session_cookie_hash($session_cookie) {
  59. list ($junk, $hash) = explode('-*-', $session_cookie);
  60. return $hash;
  61. }
  62. /**
  63. * session_check_session_cookie() - Check that session cookie passed from user is ok
  64. *
  65. * @param string Value of the session cookie
  66. * @return user_id if cookie is ok, false otherwise
  67. */
  68. function session_check_session_cookie($session_cookie) {
  69. list ($session_serial, $hash) = explode('-*-', $session_cookie);
  70. $session_serial = base64_decode($session_serial);
  71. $new_hash = md5($session_serial.$GLOBALS['sys_session_key']);
  72. if ($hash != $new_hash) {
  73. return false;
  74. }
  75. list($user_id, $time, $ip, $user_agent) = explode('-*-', $session_serial, 4);
  76. if (!session_check_ip($ip, getStringFromServer('REMOTE_ADDR'))) {
  77. return false;
  78. }
  79. if (trim($user_agent) != getStringFromServer('HTTP_USER_AGENT')) {
  80. return false;
  81. }
  82. if (($GLOBALS['sys_session_expire'] > 0) &&
  83. ($time - time() >= $GLOBALS['sys_session_expire'])) {
  84. return false;
  85. }
  86. return $user_id;
  87. }
  88. /**
  89. * session_logout() - Log the user off the system.
  90. *
  91. * This function destroys object associated with the current session,
  92. * making user "logged out". Deletes both user and session cookies.
  93. *
  94. * @return true/false
  95. *
  96. */
  97. function session_logout() {
  98. // delete both session and username cookies
  99. // NB: cookies must be deleted with the same scope parameters they were set with
  100. //
  101. session_cookie('session_ser', '');
  102. return true;
  103. }
  104. /**
  105. * session_login_valid() - Log the user to the system.
  106. *
  107. * High-level function for user login. Check credentials, and if they
  108. * are valid, open new session.
  109. *
  110. * @param string User name
  111. * @param string User password (in clear text)
  112. * @param bool Allow login to non-confirmed user account (only for confirmation of the very account)
  113. * @return true/false, if false reason is in global $feedback
  114. * @access public
  115. *
  116. */
  117. function session_login_valid($loginname, $passwd, $allowpending=0) {
  118. global $feedback;
  119. if (!$loginname || !$passwd) {
  120. $feedback = _('Missing Password Or Users Name');
  121. return false;
  122. }
  123. $hook_params = array () ;
  124. $hook_params['loginname'] = $loginname ;
  125. $hook_params['passwd'] = $passwd ;
  126. plugin_hook ("session_before_login", $hook_params) ;
  127. return session_login_valid_dbonly ($loginname, $passwd, $allowpending) ;
  128. }
  129. function session_login_valid_dbonly ($loginname, $passwd, $allowpending) {
  130. global $feedback,$userstatus;
  131. // Try to get the users from the database using user_id and (MD5) user_pw
  132. $res = db_query("
  133. SELECT user_id,status,unix_pw
  134. FROM users
  135. WHERE user_name='$loginname'
  136. AND user_pw='".md5($passwd)."'
  137. ");
  138. if (!$res || db_numrows($res) < 1) {
  139. // No user whose MD5 passwd matches the MD5 of the provided passwd
  140. // Selecting by user_name only
  141. $res = db_query("SELECT user_id,status,unix_pw
  142. FROM users
  143. WHERE user_name='$loginname'");
  144. if (!$res || db_numrows($res) < 1) {
  145. // No user by that name
  146. $feedback=_('Invalid Password Or User Name');
  147. return false;
  148. } else {
  149. // There is a user with the provided user_name, but the MD5 passwds do not match
  150. // We'll have to try checking the (crypt) unix_pw
  151. $usr = db_fetch_array($res);
  152. if (crypt ($passwd, $usr['unix_pw']) != $usr['unix_pw']) {
  153. // Even the (crypt) unix_pw does not patch
  154. // This one has clearly typed a bad passwd
  155. $feedback=_('Invalid Password Or User Name');
  156. return false;
  157. }
  158. // User exists, (crypt) unix_pw matches
  159. // Update the (MD5) user_pw and retry authentication
  160. // It should work, except for status errors
  161. $res = db_query ("UPDATE users
  162. SET user_pw='" . md5($passwd) . "'
  163. WHERE user_id='".$usr['user_id']."'");
  164. return session_login_valid_dbonly($loginname, $passwd, $allowpending) ;
  165. }
  166. } else {
  167. // If we're here, then the user has typed a password matching the (MD5) user_pw
  168. // Let's check whether it also matches the (crypt) unix_pw
  169. $usr = db_fetch_array($res);
  170. /*
  171. if (crypt ($passwd, $usr['unix_pw']) != $usr['unix_pw']) {
  172. // The (crypt) unix_pw does not match
  173. if ($usr['unix_pw'] == '') {
  174. // Empty unix_pw, we'll take the MD5 as authoritative
  175. // Update the (crypt) unix_pw and retry authentication
  176. // It should work, except for status errors
  177. $res = db_query ("UPDATE users
  178. SET unix_pw='" . account_genunixpw($passwd) . "'
  179. WHERE user_id='".$usr['user_id']."'");
  180. return session_login_valid_dbonly($loginname, $passwd, $allowpending) ;
  181. } else {
  182. // Invalidate (MD5) user_pw, refuse authentication
  183. $res = db_query ("UPDATE users
  184. SET user_pw='OUT OF DATE'
  185. WHERE user_id='".$usr['user_id']."'");
  186. $feedback=_('Invalid Password Or User Name');
  187. return false;
  188. }
  189. }
  190. */
  191. // Yay. The provided password matches both fields in the database.
  192. // Let's check the status of this user
  193. // if allowpending (for verify.php) then allow
  194. $userstatus=$usr['status'];
  195. if ($allowpending && ($usr['status'] == 'P')) {
  196. //1;
  197. } else {
  198. if ($usr['status'] == 'S') {
  199. //acount suspended
  200. $feedback = _('Account Suspended');
  201. return false;
  202. }
  203. if ($usr['status'] == 'P') {
  204. //account pending
  205. $feedback = _('Account Pending');
  206. return false;
  207. }
  208. if ($usr['status'] == 'D') {
  209. //account deleted
  210. $feedback = _('Account Deleted');
  211. return false;
  212. }
  213. if ($usr['status'] != 'A') {
  214. //unacceptable account flag
  215. $feedback = _('Account Not Active');
  216. return false;
  217. }
  218. }
  219. //create a new session
  220. session_set_new(db_result($res,0,'user_id'));
  221. return true;
  222. }
  223. }
  224. /**
  225. * session_check_ip() - Check 2 IP addresses for match
  226. *
  227. * This function checks that IP addresses match
  228. *
  229. * IPv4 addresses are allowed to match with some
  230. * fuzz factor (within 255.255.0.0 subnet).
  231. *
  232. * For IPv6 addresses, no fuzz is needed since there's
  233. * usually no NAT in IPv6.
  234. *
  235. * @param string The old IP address
  236. * @param string The new IP address
  237. * @return true/false
  238. * @access private
  239. */
  240. function session_check_ip($oldip,$newip) {
  241. if (strstr ($oldip, ':')) {
  242. // Old IP is IPv6
  243. if (strstr ($newip, ':')) {
  244. // New IP is IPv6 too
  245. return ($oldip == $newip) ;
  246. } else {
  247. return false ;
  248. }
  249. } else {
  250. // Old IP is IPv4
  251. if (strstr ($newip, ':')) {
  252. // New IP is IPv6
  253. return false ;
  254. } else {
  255. $eoldip = explode(".",$oldip);
  256. $enewip = explode(".",$newip);
  257. // require same class b subnet
  258. return ( ($eoldip[0] == $enewip[0])
  259. && ($eoldip[1] == $enewip[1]) ) ;
  260. }
  261. }
  262. }
  263. /**
  264. * session_issecure() - Check if current session is secure
  265. *
  266. * @return true/false
  267. * @access public
  268. */
  269. function session_issecure() {
  270. return (strtoupper(getStringFromServer('HTTPS')) == "ON");
  271. }
  272. /**
  273. * session_cookie() - Set a session cookie
  274. *
  275. * Set a cookie with default temporal scope of the current browser session
  276. * and URL space of the current webserver
  277. *
  278. * @param string Name of cookie
  279. * @param string Value of cookie
  280. * @param string Domain scope (default '')
  281. * @param string Expiration time in UNIX seconds (default 0)
  282. * @return true/false
  283. */
  284. function session_cookie($name ,$value, $domain = '', $expiration = 0) {
  285. if ( $expiration != 0){
  286. setcookie($name, $value, time() + $expiration, '/', $domain, 0);
  287. } else {
  288. setcookie($name, $value, $expiration, '/', $domain, 0);
  289. }
  290. }
  291. /**
  292. * session_redirect() - Redirect browser within the site
  293. *
  294. * @param string Absolute path within the site
  295. * @return never returns
  296. */
  297. function session_redirect($loc) {
  298. header('Location: '.util_make_url ($loc));
  299. print("\n\n");
  300. exit;
  301. }
  302. /**
  303. * session_require() - Convenience function to easily enforce permissions
  304. *
  305. * Calling page will terminate with error message if current user
  306. * fails checks.
  307. *
  308. * @param array Associative array specifying criteria
  309. * @return does not return if check is failed
  310. *
  311. */
  312. function session_require($req) {
  313. if (!session_loggedin()) {
  314. exit_not_logged_in();
  315. }
  316. if ($req['group']) {
  317. $group =& group_get_object($req['group']);
  318. if (!$group || !is_object($group)) {
  319. exit_error('Error','Could Not Get Group');
  320. } elseif ($group->isError()) {
  321. exit_error('Error',$group->getErrorMessage());
  322. }
  323. $perm =& $group->getPermission( session_get_user() );
  324. if (!$perm || !is_object($perm) || $perm->isError()) {
  325. exit_permission_denied();
  326. }
  327. //don't really like this, but as admin_flags is not mandatory
  328. //I add @ to remove the warning
  329. if (@$req['admin_flags']) {
  330. if (!$perm->isAdmin()) {
  331. exit_permission_denied();
  332. }
  333. } else {
  334. if (!$perm->isMember()) {
  335. exit_permission_denied();
  336. }
  337. }
  338. } else if ($req['isloggedin']) {
  339. //no need to check as long as the check is present at top of function
  340. } else {
  341. exit_permission_denied();
  342. }
  343. }
  344. /**
  345. * session_set_new() - Setup session for the given user
  346. *
  347. * This function sets up SourceForge session for the given user,
  348. * making one be "logged in".
  349. *
  350. * @param int The user ID
  351. * @return none
  352. */
  353. function session_set_new($user_id) {
  354. global $G_SESSION,$session_ser;
  355. // set session cookie
  356. //
  357. $cookie = session_build_session_cookie($user_id);
  358. session_cookie("session_ser", $cookie, "", $GLOBALS['sys_session_expire']);
  359. $session_ser=$cookie;
  360. db_query("
  361. INSERT INTO user_session (session_hash, ip_addr, time, user_id)
  362. VALUES (
  363. '".session_get_session_cookie_hash($cookie)."',
  364. '".getStringFromServer('REMOTE_ADDR')."',
  365. '".time()."',
  366. $user_id
  367. )
  368. ");
  369. // check uniqueness of the session_hash in the database
  370. //
  371. $res = session_getdata($user_id);
  372. if (!$res || db_numrows($res) < 1) {
  373. exit_error(_('ERROR'),_('ERROR').": ".db_error());
  374. } else {
  375. //set up the new user object
  376. //
  377. $G_SESSION = user_get_object($user_id,$res);
  378. if ($G_SESSION) {
  379. $G_SESSION->setLoggedIn(true);
  380. }
  381. }
  382. }
  383. /**
  384. * Private optimization function for logins - fetches user data, language, and session
  385. * with one query
  386. *
  387. * @param int The user ID
  388. * @access private
  389. */
  390. function session_getdata($user_id) {
  391. $res=db_query("SELECT
  392. u.*,sl.language_id, sl.name, sl.filename, sl.classname, sl.language_code, t.dirname, t.fullname
  393. FROM users u,
  394. supported_languages sl,
  395. themes t
  396. WHERE u.language=sl.language_id
  397. AND u.theme_id=t.theme_id
  398. AND u.user_id='$user_id'");
  399. return $res;
  400. }
  401. /**
  402. * session_set() - Re-initialize session for the logged in user
  403. *
  404. * This function checks that the user is logged in and if so, initialize
  405. * internal session environment.
  406. *
  407. * @return none
  408. */
  409. function session_set() {
  410. plugin_hook('session_set_entry');
  411. global $G_SESSION;
  412. global $session_ser, $session_key;
  413. // assume bad session_hash and session. If all checks work, then allow
  414. // otherwise make new session
  415. $id_is_good = false;
  416. // If user says he's logged in (by presenting cookie), check that
  417. if ($session_ser) {
  418. $user_id = session_check_session_cookie($session_ser);
  419. if ($user_id) {
  420. $result = session_getdata($user_id);
  421. if (db_numrows($result) > 0) {
  422. $id_is_good = true;
  423. }
  424. }
  425. } // else (hash does not exist) or (session hash is bad)
  426. if ($id_is_good) {
  427. $G_SESSION = user_get_object($user_id, $result);
  428. if ($G_SESSION) {
  429. $G_SESSION->setLoggedIn(true);
  430. }
  431. } else {
  432. $G_SESSION=false;
  433. // if there was bad session cookie, kill it and the user cookie
  434. //
  435. if ($session_ser) {
  436. session_logout();
  437. }
  438. }
  439. plugin_hook('session_set_return');
  440. }
  441. //TODO - this should be generalized and used for pre.php, squal_pre.php,
  442. //SOAP, forum_gateway.php, tracker_gateway.php, etc to
  443. //setup languages
  444. function session_continue($sessionKey) {
  445. global $session_ser;
  446. $session_ser = $sessionKey;
  447. session_set();
  448. setup_gettext_from_browser() ;
  449. $LUSER =& session_get_user();
  450. if (!is_object($LUSER) || $LUSER->isError()) {
  451. return false;
  452. } else {
  453. putenv('TZ='. $LUSER->getTimeZone());
  454. return true;
  455. }
  456. }
  457. /**
  458. * session_get_user() - Wrapper function to return the User object for the logged in user.
  459. *
  460. * @return User
  461. * @access public
  462. */
  463. function &session_get_user() {
  464. global $G_SESSION;
  465. return $G_SESSION;
  466. }
  467. /**
  468. * user_getid()
  469. * Get user_id of logged in user
  470. */
  471. function user_getid() {
  472. global $G_SESSION;
  473. if ($G_SESSION) {
  474. return $G_SESSION->getID();
  475. } else {
  476. return false;
  477. }
  478. }
  479. /**
  480. * session_loggedin()
  481. * See if user is logged in
  482. */
  483. function session_loggedin() {
  484. global $G_SESSION;
  485. if ($G_SESSION) {
  486. return $G_SESSION->isLoggedIn();
  487. } else {
  488. return false;
  489. }
  490. }
  491. // Local Variables:
  492. // mode: php
  493. // c-file-style: "bsd"
  494. // End:
  495. ?>