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