Asterisk - The Open Source Telephony Project GIT-master-f36a736
crypt.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2012 - 2013, Digium, Inc.
5 *
6 * David M. Lee, II <dlee@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Asterisk wrapper for crypt(3)
22 * \author David M. Lee, II <dlee@digium.com>
23 */
24
25/*** MODULEINFO
26 <support_level>core</support_level>
27 ***/
28
29#include "asterisk.h"
30
31#include <unistd.h>
32#if defined(HAVE_CRYPT_R) && !defined(__FreeBSD__)
33#include <crypt.h>
34#endif
35
36#include "asterisk/utils.h"
37
38/*!
39 * \brief Max length of a salt string.
40 *
41 * $[1,5,6]$[a–zA–Z0–9./]{1,16}$, plus null terminator
42 */
43#define MAX_SALT_LEN 21
44
45static char salt_chars[] =
46 "abcdefghijklmnopqrstuvwxyz"
47 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
48 "0123456789"
49 "./";
50
51/*! Randomly select a character for a salt string */
52static char gen_salt_char(void)
53{
54 int which = ast_random_double() * 64;
55 return salt_chars[which];
56}
57
58/*!
59 * \brief Generates a salt to try with crypt.
60 *
61 * If given an empty string, will generate a salt for the most secure algorithm
62 * to try with crypt(). If given a previously generated salt, the algorithm will
63 * be lowered by one level of security.
64 *
65 * \param[out] current_salt Output string in which to generate the salt.
66 * This can be an empty string, or the results of a
67 * prior gen_salt call.
68 * \param maxlen Length of \a current_salt.
69 * \return 0 on success.
70 * \return Non-zero on error.
71 */
72static int gen_salt(char *current_salt, size_t maxlen)
73{
74 int i;
75
76 if (maxlen < MAX_SALT_LEN || current_salt == NULL) {
77 return -1;
78 }
79
80 switch (current_salt[0]) {
81 case '\0':
82 /* Initial generation; $6$ = SHA-512 */
83 *current_salt++ = '$';
84 *current_salt++ = '6';
85 *current_salt++ = '$';
86 for (i = 0; i < 16; ++i) {
87 *current_salt++ = gen_salt_char();
88 }
89 *current_salt++ = '$';
90 *current_salt++ = '\0';
91 return 0;
92 case '$':
93 switch (current_salt[1]) {
94 case '6':
95 /* Downgrade to SHA-256 */
96 current_salt[1] = '5';
97 return 0;
98 case '5':
99 /* Downgrade to MD5 */
100 current_salt[1] = '1';
101 return 0;
102 case '1':
103 /* Downgrade to traditional crypt */
104 *current_salt++ = gen_salt_char();
105 *current_salt++ = gen_salt_char();
106 *current_salt++ = '\0';
107 return 0;
108 default:
109 /* Unrecognized algorithm */
110 return -1;
111 }
112 default:
113 /* Was already as insecure as it gets */
114 return -1;
115 }
116
117}
118
119#if defined(HAVE_CRYPT_R)
120
121char *ast_crypt(const char *key, const char *salt)
122{
123 struct crypt_data data = {};
124 const char *crypted = crypt_r(key, salt, &data);
125
126 /* Crypt may return success even if it doesn't recognize the salt. But
127 * in those cases it always mangles the salt in some way.
128 */
129 if (!crypted || !ast_begins_with(crypted, salt)) {
130 return NULL;
131 }
132
133 return ast_strdup(crypted);
134}
135
136int ast_crypt_validate(const char *key, const char *expected)
137{
138 struct crypt_data data = {};
139 return strcmp(expected, crypt_r(key, expected, &data)) == 0;
140}
141
142#elif defined(HAVE_CRYPT)
143
144/* crypt is not reentrant. A global mutex is neither ideal nor perfect, but good
145 * enough if crypt_r support is unavailable
146 */
147AST_MUTEX_DEFINE_STATIC(crypt_mutex);
148
149char *ast_crypt(const char *key, const char *salt)
150{
151 const char *crypted;
152 SCOPED_MUTEX(lock, &crypt_mutex);
153
154 crypted = crypt(key, salt);
155
156 /* Crypt may return success even if it doesn't recognize the salt. But
157 * in those cases it always mangles the salt in some way.
158 */
159 if (!crypted || !ast_begins_with(crypted, salt)) {
160 return NULL;
161 }
162
163 return ast_strdup(crypted);
164}
165
166int ast_crypt_validate(const char *key, const char *expected)
167{
168 SCOPED_MUTEX(lock, &crypt_mutex);
169 return strcmp(expected, crypt(key, expected)) == 0;
170}
171
172#else /* No crypt support */
173
174char *ast_crypt(const char *key, const char *salt)
175{
177 "crypt() support not available; cannot encrypt password\n");
178 return NULL;
179}
180
181int ast_crypt_validate(const char *key, const char *expected)
182{
184 "crypt() support not available; cannot validate password\n");
185 return 0;
186}
187
188#endif /* No crypt support */
189
190char *ast_crypt_encrypt(const char *key)
191{
192 char salt[MAX_SALT_LEN] = {};
193 while (gen_salt(salt, sizeof(salt)) == 0) {
194 char *crypted = ast_crypt(key, salt);
195 if (crypted) {
196 return crypted;
197 }
198 }
199 return NULL;
200}
ast_mutex_t lock
Definition: app_sla.c:331
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_log
Definition: astobj2.c:42
static char gen_salt_char(void)
Definition: crypt.c:52
static int gen_salt(char *current_salt, size_t maxlen)
Generates a salt to try with crypt.
Definition: crypt.c:72
#define MAX_SALT_LEN
Max length of a salt string.
Definition: crypt.c:43
int ast_crypt_validate(const char *key, const char *expected)
Asterisk wrapper around crypt(3) for validating passwords.
Definition: crypt.c:136
char * ast_crypt(const char *key, const char *salt)
Asterisk wrapper around crypt(3).
Definition: crypt.c:121
static char salt_chars[]
Definition: crypt.c:45
char * ast_crypt_encrypt(const char *key)
Asterisk wrapper around crypt(3) for encrypting passwords.
Definition: crypt.c:190
#define LOG_WARNING
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:589
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
#define NULL
Definition: resample.c:96
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition: strings.h:97
Utility functions.
#define ast_random_double()
Returns a random number between 0.0 and 1.0, inclusive.
Definition: utils.h:624