| 
									
										
										
										
											2013-07-04 13:06:15 +00:00
										 |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Copyright (C) 2012 - 2013, Digium, Inc. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * David M. Lee, II <dlee@digium.com> | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /*! \file
 | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * \brief Asterisk wrapper for crypt(3) | 
					
						
							|  |  |  |  |  * \author David M. Lee, II <dlee@digium.com> | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  |  | 	<support_level>core</support_level> | 
					
						
							|  |  |  |  |  ***/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2017-06-08 17:36:00 +02:00
										 |  |  |  | #if defined(HAVE_CRYPT_R) && !defined(__FreeBSD__)
 | 
					
						
							| 
									
										
										
										
											2013-07-04 13:06:15 +00:00
										 |  |  |  | #include <crypt.h>
 | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include "asterisk/utils.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /*!
 | 
					
						
							|  |  |  |  |  * \brief Max length of a salt string. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * $[1,5,6]$[a–zA–Z0–9./]{1,16}$, plus null terminator | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | #define MAX_SALT_LEN 21
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static char salt_chars[] = | 
					
						
							|  |  |  |  | 	"abcdefghijklmnopqrstuvwxyz" | 
					
						
							|  |  |  |  | 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ" | 
					
						
							|  |  |  |  | 	"0123456789" | 
					
						
							|  |  |  |  | 	"./"; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /*! Randomly select a character for a salt string */ | 
					
						
							|  |  |  |  | static char gen_salt_char(void) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	int which = ast_random_double() * 64; | 
					
						
							|  |  |  |  | 	return salt_chars[which]; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /*!
 | 
					
						
							|  |  |  |  |  * \brief Generates a salt to try with crypt. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * If given an empty string, will generate a salt for the most secure algorithm | 
					
						
							|  |  |  |  |  * to try with crypt(). If given a previously generated salt, the algorithm will | 
					
						
							|  |  |  |  |  * be lowered by one level of security. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * \param[out] current_salt Output string in which to generate the salt. | 
					
						
							|  |  |  |  |  *                          This can be an empty string, or the results of a | 
					
						
							|  |  |  |  |  *                          prior gen_salt call. | 
					
						
							| 
									
										
										
										
											2021-11-19 16:47:25 +01:00
										 |  |  |  |  * \param maxlen Length of \a current_salt. | 
					
						
							| 
									
										
										
										
											2013-07-04 13:06:15 +00:00
										 |  |  |  |  * \return 0 on success. | 
					
						
							|  |  |  |  |  * \return Non-zero on error. | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | static int gen_salt(char *current_salt, size_t maxlen) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	int i; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if (maxlen < MAX_SALT_LEN || current_salt == NULL) { | 
					
						
							|  |  |  |  | 		return -1; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	switch (current_salt[0]) { | 
					
						
							|  |  |  |  | 	case '\0': | 
					
						
							|  |  |  |  | 		/* Initial generation; $6$ = SHA-512 */ | 
					
						
							|  |  |  |  | 		*current_salt++ = '$'; | 
					
						
							|  |  |  |  | 		*current_salt++ = '6'; | 
					
						
							|  |  |  |  | 		*current_salt++ = '$'; | 
					
						
							|  |  |  |  | 		for (i = 0; i < 16; ++i) { | 
					
						
							|  |  |  |  | 			*current_salt++ = gen_salt_char(); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		*current_salt++ = '$'; | 
					
						
							|  |  |  |  | 		*current_salt++ = '\0'; | 
					
						
							|  |  |  |  | 		return 0; | 
					
						
							|  |  |  |  | 	case '$': | 
					
						
							|  |  |  |  | 		switch (current_salt[1]) { | 
					
						
							|  |  |  |  | 		case '6': | 
					
						
							|  |  |  |  | 			/* Downgrade to SHA-256 */ | 
					
						
							|  |  |  |  | 			current_salt[1] = '5'; | 
					
						
							|  |  |  |  | 			return 0; | 
					
						
							|  |  |  |  | 		case '5': | 
					
						
							|  |  |  |  | 			/* Downgrade to MD5 */ | 
					
						
							|  |  |  |  | 			current_salt[1] = '1'; | 
					
						
							|  |  |  |  | 			return 0; | 
					
						
							|  |  |  |  | 		case '1': | 
					
						
							|  |  |  |  | 			/* Downgrade to traditional crypt */ | 
					
						
							|  |  |  |  | 			*current_salt++ = gen_salt_char(); | 
					
						
							|  |  |  |  | 			*current_salt++ = gen_salt_char(); | 
					
						
							|  |  |  |  | 			*current_salt++ = '\0'; | 
					
						
							|  |  |  |  | 			return 0; | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			/* Unrecognized algorithm */ | 
					
						
							|  |  |  |  | 			return -1; | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	default: | 
					
						
							|  |  |  |  | 		/* Was already as insecure as it gets */ | 
					
						
							|  |  |  |  | 		return -1; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #if defined(HAVE_CRYPT_R)
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | char *ast_crypt(const char *key, const char *salt) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	struct crypt_data data = {}; | 
					
						
							|  |  |  |  | 	const char *crypted = crypt_r(key, salt, &data); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/* Crypt may return success even if it doesn't recognize the salt. But
 | 
					
						
							|  |  |  |  | 	 * in those cases it always mangles the salt in some way. | 
					
						
							|  |  |  |  | 	 */ | 
					
						
							|  |  |  |  | 	if (!crypted || !ast_begins_with(crypted, salt)) { | 
					
						
							|  |  |  |  | 		return NULL; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return ast_strdup(crypted); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | int ast_crypt_validate(const char *key, const char *expected) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	struct crypt_data data = {}; | 
					
						
							|  |  |  |  | 	return strcmp(expected, crypt_r(key, expected, &data)) == 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #elif defined(HAVE_CRYPT)
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* crypt is not reentrant. A global mutex is neither ideal nor perfect, but good
 | 
					
						
							|  |  |  |  |  * enough if crypt_r support is unavailable | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | AST_MUTEX_DEFINE_STATIC(crypt_mutex); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | char *ast_crypt(const char *key, const char *salt) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	const char *crypted; | 
					
						
							|  |  |  |  | 	SCOPED_MUTEX(lock, &crypt_mutex); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	crypted = crypt(key, salt); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/* Crypt may return success even if it doesn't recognize the salt. But
 | 
					
						
							|  |  |  |  | 	 * in those cases it always mangles the salt in some way. | 
					
						
							|  |  |  |  | 	 */ | 
					
						
							|  |  |  |  | 	if (!crypted || !ast_begins_with(crypted, salt)) { | 
					
						
							|  |  |  |  | 		return NULL; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return ast_strdup(crypted); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | int ast_crypt_validate(const char *key, const char *expected) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	SCOPED_MUTEX(lock, &crypt_mutex); | 
					
						
							|  |  |  |  | 	return strcmp(expected, crypt(key, expected)) == 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #else /* No crypt support */
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | char *ast_crypt(const char *key, const char *salt) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	ast_log(LOG_WARNING, | 
					
						
							|  |  |  |  | 		"crypt() support not available; cannot encrypt password\n"); | 
					
						
							|  |  |  |  | 	return NULL; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | int ast_crypt_validate(const char *key, const char *expected) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	ast_log(LOG_WARNING, | 
					
						
							|  |  |  |  | 		"crypt() support not available; cannot validate password\n"); | 
					
						
							|  |  |  |  | 	return 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #endif  /* No crypt support */
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | char *ast_crypt_encrypt(const char *key) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	char salt[MAX_SALT_LEN] = {}; | 
					
						
							|  |  |  |  | 	while (gen_salt(salt, sizeof(salt)) == 0) { | 
					
						
							|  |  |  |  | 		char *crypted = ast_crypt(key, salt); | 
					
						
							|  |  |  |  | 		if (crypted) { | 
					
						
							|  |  |  |  | 			return crypted; | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return NULL; | 
					
						
							|  |  |  |  | } |