Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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 
45 static char salt_chars[] =
46  "abcdefghijklmnopqrstuvwxyz"
47  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
48  "0123456789"
49  "./";
50 
51 /*! Randomly select a character for a salt string */
52 static 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 max_len Length of \a current_salt.
69  * \return 0 on success.
70  * \return Non-zero on error.
71  */
72 static 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 
121 char *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 
136 int 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  */
147 AST_MUTEX_DEFINE_STATIC(crypt_mutex);
148 
149 char *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 
166 int 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 
174 char *ast_crypt(const char *key, const char *salt)
175 {
177  "crypt() support not available; cannot encrypt password\n");
178  return NULL;
179 }
180 
181 int 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 
190 char *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 }
Asterisk main include file. File version handling, generic pbx functions.
static char salt_chars[]
Definition: crypt.c:45
static char gen_salt_char(void)
Definition: crypt.c:52
int ast_crypt_validate(const char *key, const char *expected)
Asterisk wrapper around crypt(3) for validating passwords.
Definition: crypt.c:136
#define LOG_WARNING
Definition: logger.h:274
static int gen_salt(char *current_salt, size_t maxlen)
Generates a salt to try with crypt.
Definition: crypt.c:72
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
Utility functions.
#define ast_log
Definition: astobj2.c:42
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:587
ast_mutex_t lock
Definition: app_meetme.c:1091
#define MAX_SALT_LEN
Max length of a salt string.
Definition: crypt.c:43
char * ast_crypt_encrypt(const char *key)
Asterisk wrapper around crypt(3) for encrypting passwords.
Definition: crypt.c:190
char * ast_crypt(const char *key, const char *salt)
Asterisk wrapper around crypt(3).
Definition: crypt.c:121
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Definition: strings.h:94
#define ast_random_double()
Returns a random number between 0.0 and 1.0, inclusive.
Definition: utils.h:599
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518