PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/php/File/Passwd.php

https://bitbucket.org/adarshj/convenient_website
PHP | 416 lines | 182 code | 24 blank | 210 comment | 23 complexity | a69f236fc94b5cc7e32e8ee985190c99 MD5 | raw file
Possible License(s): Apache-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-2-Clause, GPL-2.0, LGPL-3.0
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * File::Passwd
  5. *
  6. * PHP versions 4 and 5
  7. *
  8. * LICENSE: This source file is subject to version 3.0 of the PHP license
  9. * that is available through the world-wide-web at the following URI:
  10. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  11. * the PHP License and are unable to obtain it through the web, please
  12. * send a note to license@php.net so we can mail you a copy immediately.
  13. *
  14. * @category FileFormats
  15. * @package File_Passwd
  16. * @author Michael Wallner <mike@php.net>
  17. * @copyright 2003-2005 Michael Wallner
  18. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  19. * @version CVS: $Id: Passwd.php,v 1.25 2005/04/14 15:00:30 mike Exp $
  20. * @link http://pear.php.net/package/File_Passwd
  21. */
  22. /**
  23. * Requires PEAR.
  24. */
  25. require_once 'PEAR.php';
  26. /**
  27. * Encryption constants.
  28. */
  29. // SHA encryption.
  30. define('FILE_PASSWD_SHA', 'sha');
  31. // MD5 encryption
  32. define('FILE_PASSWD_MD5', 'md5');
  33. // DES encryption
  34. define('FILE_PASSWD_DES', 'des');
  35. // NT hash encryption.
  36. define('FILE_PASSWD_NT', 'nt');
  37. // LM hash encryption.
  38. define('FILE_PASSWD_LM', 'lm');
  39. // PLAIN (no encryption)
  40. define('FILE_PASSWD_PLAIN', 'plain');
  41. /**
  42. * Error constants.
  43. */
  44. // Undefined error.
  45. define('FILE_PASSWD_E_UNDEFINED', 0);
  46. // Invalid file format.
  47. define('FILE_PASSWD_E_INVALID_FORMAT', 1);
  48. define('FILE_PASSWD_E_INVALID_FORMAT_STR', 'Passwd file has invalid format.');
  49. // Invalid extra property.
  50. define('FILE_PASSWD_E_INVALID_PROPERTY', 2);
  51. define('FILE_PASSWD_E_INVALID_PROPERTY_STR', 'Invalid property \'%s\'.');
  52. // Invalid characters.
  53. define('FILE_PASSWD_E_INVALID_CHARS', 3);
  54. define('FILE_PASSWD_E_INVALID_CHARS_STR', '%s\'%s\' contains illegal characters.');
  55. // Invalid encryption mode.
  56. define('FILE_PASSWD_E_INVALID_ENC_MODE', 4);
  57. define('FILE_PASSWD_E_INVALID_ENC_MODE_STR', 'Encryption mode \'%s\' not supported.');
  58. // Exists already.
  59. define('FILE_PASSWD_E_EXISTS_ALREADY', 5);
  60. define('FILE_PASSWD_E_EXISTS_ALREADY_STR', '%s\'%s\' already exists.');
  61. // Exists not.
  62. define('FILE_PASSWD_E_EXISTS_NOT', 6);
  63. define('FILE_PASSWD_E_EXISTS_NOT_STR', '%s\'%s\' doesn\'t exist.');
  64. // User not in group.
  65. define('FILE_PASSWD_E_USER_NOT_IN_GROUP', 7);
  66. define('FILE_PASSWD_E_USER_NOT_IN_GROUP_STR', 'User \'%s\' doesn\'t exist in group \'%s\'.');
  67. // User not in realm.
  68. define('FILE_PASSWD_E_USER_NOT_IN_REALM', 8);
  69. define('FILE_PASSWD_E_USER_NOT_IN_REALM_STR', 'User \'%s\' doesn\'t exist in realm \'%s\'.');
  70. // Parameter must be of type array.
  71. define('FILE_PASSWD_E_PARAM_MUST_BE_ARRAY', 9);
  72. define('FILE_PASSWD_E_PARAM_MUST_BE_ARRAY_STR', 'Parameter %s must be of type array.');
  73. // Method not implemented.
  74. define('FILE_PASSWD_E_METHOD_NOT_IMPLEMENTED', 10);
  75. define('FILE_PASSWD_E_METHOD_NOT_IMPLEMENTED_STR', 'Method \'%s()\' not implemented.');
  76. // Directory couldn't be created.
  77. define('FILE_PASSWD_E_DIR_NOT_CREATED', 11);
  78. define('FILE_PASSWD_E_DIR_NOT_CREATED_STR', 'Couldn\'t create directory \'%s\'.');
  79. // File couldn't be opened.
  80. define('FILE_PASSWD_E_FILE_NOT_OPENED', 12);
  81. define('FILE_PASSWD_E_FILE_NOT_OPENED_STR', 'Couldn\'t open file \'%s\'.');
  82. // File coudn't be locked.
  83. define('FILE_PASSWD_E_FILE_NOT_LOCKED', 13);
  84. define('FILE_PASSWD_E_FILE_NOT_LOCKED_STR', 'Couldn\'t lock file \'%s\'.');
  85. // File couldn't be unlocked.
  86. define('FILE_PASSWD_E_FILE_NOT_UNLOCKED', 14);
  87. define('FILE_PASSWD_E_FILE_NOT_UNLOCKED_STR', 'Couldn\'t unlock file.');
  88. // File couldn't be closed.
  89. define('FILE_PASSWD_E_FILE_NOT_CLOSED', 15);
  90. define('FILE_PASSWD_E_FILE_NOT_CLOSED_STR', 'Couldn\'t close file.');
  91. /**
  92. * Allowed 64 chars for salts
  93. */
  94. $GLOBALS['_FILE_PASSWD_64'] =
  95. './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  96. /**
  97. * The package File_Passwd provides classes and methods
  98. * to handle many different kinds of passwd files.
  99. *
  100. * The File_Passwd class in certain is a factory container for its special
  101. * purpose extension classes, each handling a specific passwd file format.
  102. * It also provides a static method for reasonable fast user authentication.
  103. * Beside that it offers some encryption methods used by the extensions.
  104. *
  105. * @author Michael Wallner <mike@php.net>
  106. * @version $Revision: 1.25 $
  107. *
  108. * Usage Example:
  109. * <code>
  110. * $passwd = &File_Passwd::factory('Unix');
  111. * </code>
  112. */
  113. class File_Passwd
  114. {
  115. /**
  116. * Get API version
  117. *
  118. * @static
  119. * @access public
  120. * @return string API version
  121. */
  122. function apiVersion()
  123. {
  124. return '1.0.0';
  125. }
  126. /**
  127. * Generate salt
  128. *
  129. * @access public
  130. * @return mixed
  131. * @param int $length salt length
  132. * @return string the salt
  133. */
  134. function salt($length = 2)
  135. {
  136. $salt = '';
  137. $length = (int) $length;
  138. $length < 2 && $length = 2;
  139. for($i = 0; $i < $length; $i++) {
  140. $salt .= $GLOBALS['_FILE_PASSWD_64'][rand(0, 63)];
  141. }
  142. return $salt;
  143. }
  144. /**
  145. * No encryption (plaintext)
  146. *
  147. * @access public
  148. * @return string plaintext input
  149. * @param string plaintext passwd
  150. */
  151. function crypt_plain($plain)
  152. {
  153. return $plain;
  154. }
  155. /**
  156. * DES encryption
  157. *
  158. * @static
  159. * @access public
  160. * @return string crypted text
  161. * @param string $plain plaintext to encrypt
  162. * @param string $salt the salt to use for encryption (2 chars)
  163. */
  164. function crypt_des($plain, $salt = null)
  165. {
  166. (is_null($salt) || strlen($salt) < 2) && $salt = File_Passwd::salt(2);
  167. return crypt($plain, $salt);
  168. }
  169. /**
  170. * MD5 encryption
  171. *
  172. * @static
  173. * @access public
  174. * @return string crypted text
  175. * @param string $plain plaintext to encrypt
  176. * @param string $salt the salt to use for encryption
  177. * (>2 chars starting with $1$)
  178. */
  179. function crypt_md5($plain, $salt = null)
  180. {
  181. if (
  182. is_null($salt) ||
  183. strlen($salt) < 3 ||
  184. !preg_match('/^\$1\$/', $salt))
  185. {
  186. $salt = '$1$' . File_Passwd::salt(8);
  187. }
  188. return crypt($plain, $salt);
  189. }
  190. /**
  191. * SHA1 encryption
  192. *
  193. * Returns a PEAR_Error if sha1() is not available (PHP<4.3).
  194. *
  195. * @static
  196. * @throws PEAR_Error
  197. * @access public
  198. * @return mixed crypted string or PEAR_Error
  199. * @param string $plain plaintext to encrypt
  200. */
  201. function crypt_sha($plain)
  202. {
  203. if (!function_exists('sha1')) {
  204. return PEAR::raiseError(
  205. 'SHA1 encryption is not available (PHP < 4.3).',
  206. FILE_PASSWD_E_INVALID_ENC_MODE
  207. );
  208. }
  209. $hash = PEAR_ZE2 ? sha1($plain, true) : pack('H40', sha1($plain));
  210. return '{SHA}' . base64_encode($hash);
  211. }
  212. /**
  213. * APR compatible MD5 encryption
  214. *
  215. * @access public
  216. * @return mixed
  217. * @param string $plain plaintext to crypt
  218. * @param string $salt the salt to use for encryption
  219. */
  220. function crypt_apr_md5($plain, $salt = null)
  221. {
  222. if (is_null($salt)) {
  223. $salt = File_Passwd::salt(8);
  224. } elseif (preg_match('/^\$apr1\$/', $salt)) {
  225. $salt = preg_replace('/^\$apr1\$([^$]+)\$.*/', '\\1', $salt);
  226. } else {
  227. $salt = substr($salt, 0,8);
  228. }
  229. $length = strlen($plain);
  230. $context = $plain . '$apr1$' . $salt;
  231. if (PEAR_ZE2) {
  232. $binary = md5($plain . $salt . $plain, true);
  233. } else {
  234. $binary = pack('H32', md5($plain . $salt . $plain));
  235. }
  236. for ($i = $length; $i > 0; $i -= 16) {
  237. $context .= substr($binary, 0, min(16 , $i));
  238. }
  239. for ( $i = $length; $i > 0; $i >>= 1) {
  240. $context .= ($i & 1) ? chr(0) : $plain[0];
  241. }
  242. $binary = PEAR_ZE2 ? md5($context, true) : pack('H32', md5($context));
  243. for($i = 0; $i < 1000; $i++) {
  244. $new = ($i & 1) ? $plain : $binary;
  245. if ($i % 3) {
  246. $new .= $salt;
  247. }
  248. if ($i % 7) {
  249. $new .= $plain;
  250. }
  251. $new .= ($i & 1) ? $binary : $plain;
  252. $binary = PEAR_ZE2 ? md5($new, true) : pack('H32', md5($new));
  253. }
  254. $p = array();
  255. for ($i = 0; $i < 5; $i++) {
  256. $k = $i + 6;
  257. $j = $i + 12;
  258. if ($j == 16) {
  259. $j = 5;
  260. }
  261. $p[] = File_Passwd::_64(
  262. (ord($binary[$i]) << 16) |
  263. (ord($binary[$k]) << 8) |
  264. (ord($binary[$j])),
  265. 5
  266. );
  267. }
  268. return
  269. '$apr1$' . $salt . '$' . implode($p) .
  270. File_Passwd::_64(ord($binary[11]), 3);
  271. }
  272. /**
  273. * Convert hexadecimal string to binary data
  274. *
  275. * @static
  276. * @access private
  277. * @return mixed
  278. * @param string $hex
  279. */
  280. function _hexbin($hex)
  281. {
  282. $rs = '';
  283. $ln = strlen($hex);
  284. for($i = 0; $i < $ln; $i += 2) {
  285. $rs .= chr(hexdec($hex{$i} . $hex{$i+1}));
  286. }
  287. return $rs;
  288. }
  289. /**
  290. * Convert to allowed 64 characters for encryption
  291. *
  292. * @static
  293. * @access private
  294. * @return string
  295. * @param string $value
  296. * @param int $count
  297. */
  298. function _64($value, $count)
  299. {
  300. $result = '';
  301. while(--$count) {
  302. $result .= $GLOBALS['_FILE_PASSWD_64'][$value & 0x3f];
  303. $value >>= 6;
  304. }
  305. return $result;
  306. }
  307. /**
  308. * Factory for new extensions
  309. *
  310. * o Unix for standard Unix passwd files
  311. * o CVS for CVS pserver passwd files
  312. * o SMB for SMB server passwd files
  313. * o Authbasic for AuthUserFiles
  314. * o Authdigest for AuthDigestFiles
  315. * o Custom for custom formatted passwd files
  316. *
  317. * Returns a PEAR_Error if the desired class/file couldn't be loaded.
  318. *
  319. * @static use &File_Passwd::factory() for instantiating your passwd object
  320. *
  321. * @throws PEAR_Error
  322. * @access public
  323. * @return object File_Passwd_$class - desired Passwd object
  324. * @param string $class the desired subclass of File_Passwd
  325. */
  326. function &factory($class)
  327. {
  328. $class = ucFirst(strToLower($class));
  329. if (!@include_once "File/Passwd/$class.php") {
  330. return PEAR::raiseError("Couldn't load file Passwd/$class.php", 0);
  331. }
  332. $class = 'File_Passwd_'.$class;
  333. if (!class_exists($class)) {
  334. return PEAR::raiseError("Couldn't load class $class.", 0);
  335. }
  336. $instance = &new $class();
  337. return $instance;
  338. }
  339. /**
  340. * Fast authentication of a certain user
  341. *
  342. * Though this approach should be reasonable fast, it is NOT
  343. * with APR compatible MD5 encryption used for htpasswd style
  344. * password files encrypted in MD5. Generating one MD5 password
  345. * takes about 0.3 seconds!
  346. *
  347. * Returns a PEAR_Error if:
  348. * o file doesn't exist
  349. * o file couldn't be opened in read mode
  350. * o file couldn't be locked exclusively
  351. * o file couldn't be unlocked (only if auth fails)
  352. * o file couldn't be closed (only if auth fails)
  353. * o invalid <var>$type</var> was provided
  354. * o invalid <var>$opt</var> was provided
  355. *
  356. * Depending on <var>$type</var>, <var>$opt</var> should be:
  357. * o Smb: encryption method (NT or LM)
  358. * o Unix: encryption method (des or md5)
  359. * o Authbasic: encryption method (des, sha or md5)
  360. * o Authdigest: the realm the user is in
  361. * o Cvs: n/a (empty)
  362. * o Custom: array of 2 elements: encryption function and delimiter
  363. *
  364. * @static call this method statically for a reasonable fast authentication
  365. *
  366. * @throws PEAR_Error
  367. * @access public
  368. * @return return mixed true if authenticated,
  369. * false if not or PEAR_error
  370. *
  371. * @param string $type Unix, Cvs, Smb, Authbasic or Authdigest
  372. * @param string $file path to passwd file
  373. * @param string $user the user to authenticate
  374. * @param string $pass the plaintext password
  375. * @param mixed $opt o Smb: NT or LM
  376. * o Unix: des or md5
  377. * o Authbasic des, sha or md5
  378. * o Authdigest realm the user is in
  379. * o Custom encryption function and
  380. * delimiter character
  381. */
  382. function staticAuth($type, $file, $user, $pass, $opt = '')
  383. {
  384. $type = ucFirst(strToLower($type));
  385. if (!@include_once "File/Passwd/$type.php") {
  386. return PEAR::raiseError("Couldn't load file Passwd/$type.php", 0);
  387. }
  388. $func = array('File_Passwd_' . $type, 'staticAuth');
  389. return call_user_func($func, $file, $user, $pass, $opt);
  390. }
  391. }
  392. ?>