1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Stig Bakken <ssb@php.net> |
16 : | Zeev Suraski <zeev@zend.com> |
17 : | Rasmus Lerdorf <rasmus@php.net> |
18 : +----------------------------------------------------------------------+
19 : */
20 :
21 : /* $Id: crypt.c 272370 2008-12-31 11:15:49Z sebastian $ */
22 :
23 : #include <stdlib.h>
24 :
25 : #include "php.h"
26 : #if HAVE_CRYPT
27 :
28 : #if HAVE_UNISTD_H
29 : #include <unistd.h>
30 : #endif
31 : #ifdef PHP_USE_PHP_CRYPT_R
32 : # include "php_crypt_r.h"
33 : # include "crypt_freesec.h"
34 : #else
35 : # if HAVE_CRYPT_H
36 : # if defined(CRYPT_R_GNU_SOURCE) && !defined(_GNU_SOURCE)
37 : # define _GNU_SOURCE
38 : # endif
39 : # include <crypt.h>
40 : # endif
41 : #endif
42 : #if TM_IN_SYS_TIME
43 : #include <sys/time.h>
44 : #else
45 : #include <time.h>
46 : #endif
47 : #if HAVE_STRING_H
48 : #include <string.h>
49 : #else
50 : #include <strings.h>
51 : #endif
52 :
53 : #ifdef PHP_WIN32
54 : #include <process.h>
55 : #endif
56 :
57 : #include "php_lcg.h"
58 : #include "php_crypt.h"
59 : #include "php_rand.h"
60 :
61 : /* The capabilities of the crypt() function is determined by the test programs
62 : * run by configure from aclocal.m4. They will set PHP_STD_DES_CRYPT,
63 : * PHP_EXT_DES_CRYPT, PHP_MD5_CRYPT and PHP_BLOWFISH_CRYPT as appropriate
64 : * for the target platform. */
65 :
66 : #if PHP_STD_DES_CRYPT
67 : #define PHP_MAX_SALT_LEN 2
68 : #endif
69 :
70 : #if PHP_EXT_DES_CRYPT
71 : #undef PHP_MAX_SALT_LEN
72 : #define PHP_MAX_SALT_LEN 9
73 : #endif
74 :
75 : #if PHP_MD5_CRYPT
76 : #undef PHP_MAX_SALT_LEN
77 : #define PHP_MAX_SALT_LEN 12
78 : #endif
79 :
80 : #if PHP_BLOWFISH_CRYPT
81 : #undef PHP_MAX_SALT_LEN
82 : #define PHP_MAX_SALT_LEN 60
83 : #endif
84 :
85 : /* If the configure-time checks fail, we provide DES.
86 : * XXX: This is a hack. Fix the real problem! */
87 :
88 : #ifndef PHP_MAX_SALT_LEN
89 : #define PHP_MAX_SALT_LEN 2
90 : #undef PHP_STD_DES_CRYPT
91 : #define PHP_STD_DES_CRYPT 1
92 : #endif
93 :
94 : #define PHP_CRYPT_RAND php_rand(TSRMLS_C)
95 :
96 : PHP_MINIT_FUNCTION(crypt) /* {{{ */
97 17633 : {
98 17633 : REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_CS | CONST_PERSISTENT);
99 17633 : REGISTER_LONG_CONSTANT("CRYPT_STD_DES", PHP_STD_DES_CRYPT, CONST_CS | CONST_PERSISTENT);
100 17633 : REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", PHP_EXT_DES_CRYPT, CONST_CS | CONST_PERSISTENT);
101 17633 : REGISTER_LONG_CONSTANT("CRYPT_MD5", PHP_MD5_CRYPT, CONST_CS | CONST_PERSISTENT);
102 17633 : REGISTER_LONG_CONSTANT("CRYPT_BLOWFISH", PHP_BLOWFISH_CRYPT, CONST_CS | CONST_PERSISTENT);
103 :
104 : #ifdef PHP_USE_PHP_CRYPT_R
105 17633 : php_init_crypt_r();
106 : #endif
107 :
108 17633 : return SUCCESS;
109 : }
110 : /* }}} */
111 :
112 : PHP_MSHUTDOWN_FUNCTION(crypt) /* {{{ */
113 17665 : {
114 : #ifdef PHP_USE_PHP_CRYPT_R
115 17665 : php_shutdown_crypt_r();
116 : #endif
117 :
118 17665 : return SUCCESS;
119 : }
120 : /* }}} */
121 :
122 : static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
123 :
124 : static void php_to64(char *s, long v, int n) /* {{{ */
125 2 : {
126 12 : while (--n >= 0) {
127 8 : *s++ = itoa64[v&0x3f];
128 8 : v >>= 6;
129 : }
130 2 : }
131 : /* }}} */
132 :
133 : /* {{{ proto string crypt(string str [, string salt])
134 : Hash a string */
135 : PHP_FUNCTION(crypt)
136 8 : {
137 : char salt[PHP_MAX_SALT_LEN + 1];
138 8 : char *str, *salt_in = NULL;
139 8 : int str_len, salt_in_len = 0;
140 :
141 8 : salt[0] = salt[PHP_MAX_SALT_LEN] = '\0';
142 :
143 : /* This will produce suitable results if people depend on DES-encryption
144 : * available (passing always 2-character salt). At least for glibc6.1 */
145 8 : memset(&salt[1], '$', PHP_MAX_SALT_LEN - 1);
146 :
147 8 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &salt_in, &salt_in_len) == FAILURE) {
148 2 : return;
149 : }
150 :
151 6 : if (salt_in) {
152 5 : memcpy(salt, salt_in, MIN(PHP_MAX_SALT_LEN, salt_in_len));
153 : }
154 :
155 : /* The automatic salt generation covers standard DES, md5-crypt and Blowfish (simple) */
156 6 : if (!*salt) {
157 : #if PHP_MD5_CRYPT
158 1 : strcpy(salt, "$1$");
159 1 : php_to64(&salt[3], PHP_CRYPT_RAND, 4);
160 1 : php_to64(&salt[7], PHP_CRYPT_RAND, 4);
161 1 : strcpy(&salt[11], "$");
162 : #elif PHP_STD_DES_CRYPT
163 : php_to64(&salt[0], PHP_CRYPT_RAND, 2);
164 : salt[2] = '\0';
165 : #endif
166 : }
167 :
168 : /* Windows (win32/crypt) has a stripped down version of libxcrypt and
169 : a CryptoApi md5_crypt implementation */
170 : #if PHP_USE_PHP_CRYPT_R
171 : {
172 : struct php_crypt_extended_data buffer;
173 :
174 6 : if (salt[0]=='$' && salt[1]=='1' && salt[2]=='$') {
175 : char output[MD5_HASH_MAX_LEN];
176 :
177 3 : RETURN_STRING(php_md5_crypt_r(str, salt, output), 1);
178 4 : } else if (
179 : salt[0] == '$' &&
180 : salt[1] == '2' &&
181 : salt[2] == 'a' &&
182 : salt[3] == '$' &&
183 : salt[4] >= '0' && salt[4] <= '3' &&
184 : salt[5] >= '0' && salt[5] <= '9' &&
185 : salt[6] == '$') {
186 : char output[PHP_MAX_SALT_LEN + 1];
187 :
188 1 : memset(output, 0, PHP_MAX_SALT_LEN + 1);
189 1 : php_crypt_blowfish_rn(str, salt, output, sizeof(output));
190 :
191 1 : RETVAL_STRING(output, 1);
192 1 : memset(output, 0, PHP_MAX_SALT_LEN + 1);
193 : } else {
194 2 : memset(&buffer, 0, sizeof(buffer));
195 2 : _crypt_extended_init_r();
196 2 : RETURN_STRING(_crypt_extended_r(str, salt, &buffer), 1);
197 : }
198 : }
199 : #else
200 :
201 : # if defined(HAVE_CRYPT_R) && (defined(_REENTRANT) || defined(_THREAD_SAFE))
202 : {
203 : # if defined(CRYPT_R_STRUCT_CRYPT_DATA)
204 : struct crypt_data buffer;
205 : memset(&buffer, 0, sizeof(buffer));
206 : # elif defined(CRYPT_R_CRYPTD)
207 : CRYPTD buffer;
208 : # else
209 : # error Data struct used by crypt_r() is unknown. Please report.
210 : # endif
211 :
212 : RETURN_STRING(crypt_r(str, salt, &buffer), 1);
213 : }
214 : # endif
215 : #endif
216 : }
217 : /* }}} */
218 : #endif
219 :
220 : /*
221 : * Local variables:
222 : * tab-width: 4
223 : * c-basic-offset: 4
224 : * End:
225 : * vim600: sw=4 ts=4 fdm=marker
226 : * vim<600: sw=4 ts=4
227 : */
|