2023-02-20 18:05:51 -05:00
|
|
|
/* Icecast
|
|
|
|
*
|
|
|
|
* Copyright 2023 Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>
|
|
|
|
*
|
|
|
|
* This program is distributed under the GNU General Public License, version 2.
|
|
|
|
* A copy of this license is included with this source.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <rhash.h>
|
|
|
|
|
2023-02-21 04:58:51 -05:00
|
|
|
#ifdef HAVE_CRYPT_H
|
|
|
|
#include <crypt.h>
|
|
|
|
#endif
|
|
|
|
|
2023-02-21 17:47:40 -05:00
|
|
|
#if (defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)) && defined(HAVE_PTHREAD)
|
2023-02-21 04:58:51 -05:00
|
|
|
#include <pthread.h>
|
|
|
|
#endif
|
|
|
|
|
2023-02-21 17:47:40 -05:00
|
|
|
#include <igloo/prng.h>
|
|
|
|
|
|
|
|
#include "global.h"
|
2023-02-20 18:05:51 -05:00
|
|
|
#include "util_crypt.h"
|
|
|
|
#include "util_string.h"
|
|
|
|
|
|
|
|
#define HASH_LEN 16
|
|
|
|
|
2023-02-21 04:58:51 -05:00
|
|
|
#if !defined(HAVE_CRYPT_R) && defined(HAVE_CRYPT) && defined(HAVE_PTHREAD)
|
|
|
|
static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
#endif
|
|
|
|
|
2023-02-21 17:47:40 -05:00
|
|
|
#if (defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)) && HAVE_PTHREAD
|
2023-02-21 18:38:14 -05:00
|
|
|
struct algo {
|
|
|
|
const char prefix[4];
|
|
|
|
const size_t saltlen;
|
|
|
|
const bool secure;
|
|
|
|
};
|
|
|
|
|
2023-02-21 17:47:40 -05:00
|
|
|
static pthread_once_t crypt_detect = PTHREAD_ONCE_INIT;
|
2023-02-21 18:38:14 -05:00
|
|
|
static const struct algo *new_algo;
|
|
|
|
#define HAVE_new_algo
|
2023-02-21 17:47:40 -05:00
|
|
|
|
|
|
|
void crypt_detect_run(void)
|
|
|
|
{
|
2023-02-21 18:38:14 -05:00
|
|
|
static const struct algo list[] = {{"$6$", 12, true}, {"$5$", 12, true}, {"$1$", 6, false}};
|
2023-02-21 17:47:40 -05:00
|
|
|
|
|
|
|
for (size_t i = 0; i < (sizeof(list)/sizeof(*list)); i++) {
|
|
|
|
if (util_crypt_is_supported(list[i].prefix)) {
|
2023-02-21 18:38:14 -05:00
|
|
|
new_algo = &(list[i]);
|
2023-02-21 17:47:40 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
char * util_crypt_hash_oldstyle(const char *pw)
|
2023-02-20 18:05:51 -05:00
|
|
|
{
|
|
|
|
unsigned char digest[HASH_LEN];
|
|
|
|
|
|
|
|
if (rhash_msg(RHASH_MD5, pw, strlen(pw), digest) != 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return util_bin_to_hex(digest, HASH_LEN);
|
|
|
|
}
|
|
|
|
|
2023-02-21 17:47:40 -05:00
|
|
|
char * util_crypt_hash(const char *pw)
|
|
|
|
{
|
|
|
|
#if (defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)) && HAVE_PTHREAD
|
|
|
|
if (pthread_once(&crypt_detect, crypt_detect_run) != 0)
|
|
|
|
return NULL;
|
|
|
|
|
2023-02-21 18:38:14 -05:00
|
|
|
if (new_algo) {
|
2023-02-21 17:47:40 -05:00
|
|
|
char input[128];
|
|
|
|
char salt[64];
|
|
|
|
char *salt_base64;
|
|
|
|
ssize_t len;
|
|
|
|
#ifdef HAVE_CRYPT_R
|
|
|
|
struct crypt_data data;
|
|
|
|
#elif defined(HAVE_CRYPT) && defined(HAVE_PTHREAD)
|
|
|
|
char *data;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* if this is true, we have a bug */
|
2023-02-21 18:38:14 -05:00
|
|
|
if (new_algo->saltlen > sizeof(salt))
|
2023-02-21 17:47:40 -05:00
|
|
|
return NULL;
|
|
|
|
|
2023-02-21 18:38:14 -05:00
|
|
|
len = igloo_prng_read(igloo_instance, salt, new_algo->saltlen, igloo_PRNG_FLAG_NONE);
|
|
|
|
if (len != (ssize_t)new_algo->saltlen)
|
2023-02-21 17:47:40 -05:00
|
|
|
return NULL;
|
|
|
|
|
2023-02-21 18:38:14 -05:00
|
|
|
salt_base64 = util_base64_encode(salt, new_algo->saltlen);
|
2023-02-21 17:47:40 -05:00
|
|
|
if (!salt_base64)
|
|
|
|
return NULL;
|
|
|
|
|
2023-02-21 18:38:14 -05:00
|
|
|
snprintf(input, sizeof(input), "%s%s", new_algo->prefix, salt_base64);
|
2023-02-21 17:47:40 -05:00
|
|
|
|
|
|
|
free(salt_base64);
|
|
|
|
|
|
|
|
#ifdef HAVE_CRYPT_R
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
|
|
|
|
return strdup(crypt_r(pw, input, &data));
|
|
|
|
#elif defined(HAVE_CRYPT) && defined(HAVE_PTHREAD)
|
|
|
|
if (pthread_mutex_lock(&crypt_mutex) != 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
data = strdup(crypt(pw, input));
|
|
|
|
pthread_mutex_unlock(&crypt_mutex);
|
|
|
|
return data;
|
|
|
|
#else
|
|
|
|
#error "BUG"
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
#endif
|
|
|
|
return util_crypt_hash_oldstyle(pw);
|
|
|
|
#if (defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)) && HAVE_PTHREAD
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:05:51 -05:00
|
|
|
bool util_crypt_check(const char *plain, const char *crypted)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (!plain || !crypted)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
len = strlen(crypted);
|
2023-02-21 04:58:51 -05:00
|
|
|
if (!len)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* below here we know that plain and crypted are non-null and that crypted is at least one byte long */
|
|
|
|
|
2023-02-20 18:05:51 -05:00
|
|
|
if (len == (HASH_LEN*2) && crypted[0] != '$') {
|
2023-02-21 17:47:40 -05:00
|
|
|
char *digest = util_crypt_hash_oldstyle(plain);
|
2023-02-20 18:05:51 -05:00
|
|
|
bool res;
|
|
|
|
|
|
|
|
if (!digest)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
res = strcmp(digest, crypted) == 0;
|
|
|
|
free(digest);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-02-21 04:58:51 -05:00
|
|
|
if (crypted[0] == '$') {
|
|
|
|
const char *cres;
|
|
|
|
#ifdef HAVE_CRYPT_R
|
|
|
|
struct crypt_data data;
|
|
|
|
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
|
|
|
|
cres = crypt_r(plain, crypted, &data);
|
|
|
|
if (cres && strcmp(crypted, cres) == 0)
|
|
|
|
return true;
|
|
|
|
#elif defined(HAVE_CRYPT) && defined(HAVE_PTHREAD)
|
|
|
|
bool res = false;
|
|
|
|
|
|
|
|
if (pthread_mutex_lock(&crypt_mutex) != 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
cres = crypt(plain, crypted);
|
|
|
|
if (cres && strcmp(crypted, cres) == 0)
|
|
|
|
res = true;
|
|
|
|
pthread_mutex_unlock(&crypt_mutex);
|
|
|
|
return res;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:05:51 -05:00
|
|
|
return false;
|
|
|
|
}
|
2023-02-21 08:56:05 -05:00
|
|
|
|
|
|
|
bool util_crypt_is_supported(const char *prefix)
|
|
|
|
{
|
|
|
|
static const struct {
|
|
|
|
const char *plain;
|
|
|
|
const char *crypted;
|
|
|
|
const bool expected;
|
|
|
|
} vectors[] = {
|
|
|
|
{"abc", "$1$xxxxxxxx$3GbMJKRcRFz50R9Q96xFb.", true},
|
|
|
|
{"abX", "$1$xxxxxxxx$3GbMJKRcRFz50R9Q96xFb.", false},
|
|
|
|
{"abc", "$1$xxxxxxxx$3GbMJKRcRFz50R9Q96xFbY", false},
|
|
|
|
{"abX", "$1$xxxxxxxx$3GbMJKRcRFz50R9Q96xFbY", false},
|
2023-02-21 12:03:08 -05:00
|
|
|
{"abc", "$3$$e0fba38268d0ec66ef1cb452d5885e53", true},
|
|
|
|
{"abX", "$3$$e0fba38268d0ec66ef1cb452d5885e53", false},
|
|
|
|
{"abc", "$3$$e0fba38268d0ec66ef1cb452d5885e5Y", false},
|
|
|
|
{"abX", "$3$$e0fba38268d0ec66ef1cb452d5885e5Y", false},
|
2023-02-21 08:56:05 -05:00
|
|
|
{"abc", "$5$xxxxxxxxxxxxxxxx$zNpAueQbvBleD3aSz0KwnySLaHSedk8ULXPvT1m7DUC", true},
|
|
|
|
{"abX", "$5$xxxxxxxxxxxxxxxx$zNpAueQbvBleD3aSz0KwnySLaHSedk8ULXPvT1m7DUC", false},
|
|
|
|
{"abc", "$5$xxxxxxxxxxxxxxxx$zNpAueQbvBleD3aSz0KwnySLaHSedk8ULXPvT1m7DUY", false},
|
|
|
|
{"abX", "$5$xxxxxxxxxxxxxxxx$zNpAueQbvBleD3aSz0KwnySLaHSedk8ULXPvT1m7DUY", false},
|
|
|
|
{"abc", "$6$xxxxxxxxxxxxxxxx$yNfBmH1zabagyi9HZwRuCgebrSjfr1zXUE6pFhnTG1BcvINxhgU53sjSUJDnQ5s6FPq8NSIntrpmc5ox87wX5.", true},
|
|
|
|
{"abX", "$6$xxxxxxxxxxxxxxxx$yNfBmH1zabagyi9HZwRuCgebrSjfr1zXUE6pFhnTG1BcvINxhgU53sjSUJDnQ5s6FPq8NSIntrpmc5ox87wX5.", false},
|
|
|
|
{"abc", "$6$xxxxxxxxxxxxxxxx$yNfBmH1zabagyi9HZwRuCgebrSjfr1zXUE6pFhnTG1BcvINxhgU53sjSUJDnQ5s6FPq8NSIntrpmc5ox87wX5Y", false},
|
2023-02-21 12:03:08 -05:00
|
|
|
{"abX", "$6$xxxxxxxxxxxxxxxx$yNfBmH1zabagyi9HZwRuCgebrSjfr1zXUE6pFhnTG1BcvINxhgU53sjSUJDnQ5s6FPq8NSIntrpmc5ox87wX5Y", false},
|
|
|
|
{"abc", "$7$DU..../....2Q9obwLhin8qvQl6sisAO/$n4xOT1fpjmazI6Ekeq3slWypZS0PKKV/QVpUE1X0MH6", true},
|
|
|
|
{"abX", "$7$DU..../....2Q9obwLhin8qvQl6sisAO/$n4xOT1fpjmazI6Ekeq3slWypZS0PKKV/QVpUE1X0MH6", false},
|
|
|
|
{"abc", "$7$DU..../....2Q9obwLhin8qvQl6sisAO/$n4xOT1fpjmazI6Ekeq3slWypZS0PKKV/QVpUE1X0MHY", false},
|
|
|
|
{"abX", "$7$DU..../....2Q9obwLhin8qvQl6sisAO/$n4xOT1fpjmazI6Ekeq3slWypZS0PKKV/QVpUE1X0MHY", false},
|
|
|
|
{"abc", "$md5$GUBv0xjJ$$59nlXSorBz79sJsp1gfwk1", true},
|
|
|
|
{"abX", "$md5$GUBv0xjJ$$59nlXSorBz79sJsp1gfwk1", false},
|
|
|
|
{"abc", "$md5$GUBv0xjJ$$59nlXSorBz79sJsp1gfwkY", false},
|
|
|
|
{"abX", "$md5$GUBv0xjJ$$59nlXSorBz79sJsp1gfwkY", false},
|
|
|
|
{"abc", "$sha1$40000$jtNX3nZ2$Cw.7bEep2dEG6qIx3.0HkiF/YoLW", true},
|
|
|
|
{"abX", "$sha1$40000$jtNX3nZ2$Cw.7bEep2dEG6qIx3.0HkiF/YoLW", false},
|
|
|
|
{"abc", "$sha1$40000$jtNX3nZ2$Cw.7bEep2dEG6qIx3.0HkiF/YoLY", false},
|
|
|
|
{"abX", "$sha1$40000$jtNX3nZ2$Cw.7bEep2dEG6qIx3.0HkiF/YoLY", false},
|
|
|
|
{"abc", "$y$j9T$F5Jx5fExrKuPp53xLKQ..1$aC5fZPrKSlHTuOtuJjdRm7BCdVfOnO9UIkyfXQcyB83", true},
|
|
|
|
{"abX", "$y$j9T$F5Jx5fExrKuPp53xLKQ..1$aC5fZPrKSlHTuOtuJjdRm7BCdVfOnO9UIkyfXQcyB83", false},
|
|
|
|
{"abc", "$y$j9T$F5Jx5fExrKuPp53xLKQ..1$aC5fZPrKSlHTuOtuJjdRm7BCdVfOnO9UIkyfXQcyB8Y", false},
|
|
|
|
{"abX", "$y$j9T$F5Jx5fExrKuPp53xLKQ..1$aC5fZPrKSlHTuOtuJjdRm7BCdVfOnO9UIkyfXQcyB8Y", false},
|
|
|
|
{"abc", "$gy$jCT$HM87v.7RwpQLba8fDjNSk1$3jEy/aqqTrXmZVCK3RqOQJJS8ve8hM5pSUTTkaTO.l5", true},
|
|
|
|
{"abX", "$gy$jCT$HM87v.7RwpQLba8fDjNSk1$3jEy/aqqTrXmZVCK3RqOQJJS8ve8hM5pSUTTkaTO.l5", false},
|
|
|
|
{"abc", "$gy$jCT$HM87v.7RwpQLba8fDjNSk1$3jEy/aqqTrXmZVCK3RqOQJJS8ve8hM5pSUTTkaTO.lY", false},
|
|
|
|
{"abX", "$gy$jCT$HM87v.7RwpQLba8fDjNSk1$3jEy/aqqTrXmZVCK3RqOQJJS8ve8hM5pSUTTkaTO.lY", false}
|
2023-02-21 08:56:05 -05:00
|
|
|
};
|
|
|
|
size_t prefixlen = strlen(prefix);
|
|
|
|
bool supported = false;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < (sizeof(vectors)/sizeof(*vectors)); i++) {
|
|
|
|
if (strncmp(vectors[i].crypted, prefix, prefixlen) == 0) {
|
|
|
|
bool res = util_crypt_check(vectors[i].plain, vectors[i].crypted);
|
|
|
|
if (res != vectors[i].expected)
|
|
|
|
return false;
|
|
|
|
supported = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return supported;
|
|
|
|
}
|
2023-02-21 18:38:14 -05:00
|
|
|
|
|
|
|
bool util_crypt_is_new_secure(void)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_new_algo
|
|
|
|
if (pthread_once(&crypt_detect, crypt_detect_run) != 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return new_algo->secure;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|