Do not use any libmysql functions to
scramble passwords: mysql people are evidently unable to keep this API stable.
Showing
1 changed file
with
58 additions
and
1 deletions
... | @@ -194,6 +194,61 @@ errstr (mu_sql_connection_t conn) | ... | @@ -194,6 +194,61 @@ errstr (mu_sql_connection_t conn) |
194 | return mysql_error (mp->mysql); | 194 | return mysql_error (mp->mysql); |
195 | } | 195 | } |
196 | 196 | ||
197 | |||
198 | /* MySQL scrambled password support */ | ||
199 | |||
200 | /* Convert a single hex digit to corresponding number */ | ||
201 | static unsigned | ||
202 | digit_to_number (char c) | ||
203 | { | ||
204 | return (unsigned) (c >= '0' && c <= '9' ? c-'0' : | ||
205 | c >= 'A' && c <= 'Z' ? c-'A'+10 : | ||
206 | c-'a'+10); | ||
207 | } | ||
208 | |||
209 | /* Extract salt value from MySQL scrambled password. | ||
210 | |||
211 | WARNING: The code assumes that | ||
212 | 1. strlen (password) % 8 == 0 | ||
213 | 2. number_of_entries (RES) = strlen (password) / 8 | ||
214 | |||
215 | For MySQL >= 3.21, strlen(password) == 16 */ | ||
216 | static void | ||
217 | get_salt_from_scrambled (unsigned long *res, const char *password) | ||
218 | { | ||
219 | res[0] = res[1] = 0; | ||
220 | while (*password) | ||
221 | { | ||
222 | unsigned long val = 0; | ||
223 | unsigned i; | ||
224 | |||
225 | for (i = 0; i < 8 ; i++) | ||
226 | val = (val << 4) + digit_to_number (*password++); | ||
227 | *res++ = val; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | /* Scramble a plaintext password */ | ||
232 | static void | ||
233 | scramble_password (unsigned long *result, const char *password) | ||
234 | { | ||
235 | unsigned long nr = 1345345333L, add = 7, nr2 = 0x12345671L; | ||
236 | unsigned long tmp; | ||
237 | |||
238 | for (; *password ; password++) | ||
239 | { | ||
240 | if (*password == ' ' || *password == '\t') | ||
241 | continue; | ||
242 | tmp = (unsigned long) (unsigned char) *password; | ||
243 | nr ^= (((nr & 63) + add) * tmp)+ (nr << 8); | ||
244 | nr2 += (nr2 << 8) ^ nr; | ||
245 | add += tmp; | ||
246 | } | ||
247 | |||
248 | result[0] = nr & (((unsigned long) 1L << 31) -1L); | ||
249 | result[1] = nr2 & (((unsigned long) 1L << 31) -1L); | ||
250 | } | ||
251 | |||
197 | /* Check whether a plaintext password MESSAGE matches MySQL scrambled password | 252 | /* Check whether a plaintext password MESSAGE matches MySQL scrambled password |
198 | PASSWORD */ | 253 | PASSWORD */ |
199 | int | 254 | int |
... | @@ -219,11 +274,13 @@ mu_check_mysql_scrambled_password (const char *scrambled, const char *message) | ... | @@ -219,11 +274,13 @@ mu_check_mysql_scrambled_password (const char *scrambled, const char *message) |
219 | } | 274 | } |
220 | 275 | ||
221 | get_salt_from_password (hash_pass, scrambled); | 276 | get_salt_from_password (hash_pass, scrambled); |
222 | hash_password (hash_message, message); | 277 | scramble_password (hash_message, message); |
223 | return !(hash_message[0] == hash_pass[0] | 278 | return !(hash_message[0] == hash_pass[0] |
224 | && hash_message[1] == hash_pass[1]); | 279 | && hash_message[1] == hash_pass[1]); |
225 | } | 280 | } |
226 | 281 | ||
282 | |||
283 | /* Register module */ | ||
227 | MU_DECL_SQL_DISPATCH_T(mysql) = { | 284 | MU_DECL_SQL_DISPATCH_T(mysql) = { |
228 | "mysql", | 285 | "mysql", |
229 | 3306, | 286 | 3306, | ... | ... |
-
Please register or sign in to post a comment