24RCSID(
"$Id: 461707e1d7994b1fd728cabe07b6ecdea3415637 $")
26#include <freeradius-devel/server/password.h>
28#include <freeradius-devel/util/atexit.h>
29#include <freeradius-devel/util/base64.h>
30#include <freeradius-devel/util/base16.h>
31#include <freeradius-devel/util/md4.h>
32#include <freeradius-devel/util/md5.h>
33#include <freeradius-devel/util/misc.h>
34#include <freeradius-devel/util/sha1.h>
35#include <freeradius-devel/util/value.h>
37#include <freeradius-devel/protocol/freeradius/freeradius.internal.password.h>
39#ifdef HAVE_OPENSSL_EVP_H
40# include <freeradius-devel/tls/openssl_user_macros.h>
41# include <openssl/evp.h>
42# include <openssl/sha.h>
207 {
L(
"{base64_md5}"), FR_MD5 },
208 {
L(
"{clear}"), FR_CLEARTEXT },
209 {
L(
"{cleartext}"), FR_CLEARTEXT },
210 {
L(
"{crypt}"), FR_CRYPT },
211 {
L(
"{md4}"), FR_NT },
212 {
L(
"{md5}"), FR_MD5 },
213 {
L(
"{ns-mta-md5}"), FR_NS_MTA_MD5 },
214 {
L(
"{nt}"), FR_NT },
215 {
L(
"{nthash}"), FR_NT },
217 {
L(
"{pbkdf2-sha1}"), FR_PBKDF2_SHA1 },
218 {
L(
"{pbkdf2-sha256}"), FR_PBKDF2_SHA256 },
219 {
L(
"{pbkdf2-sha512}"), FR_PBKDF2_SHA512 },
220 {
L(
"{pbkdf2_sha256}"), FR_PBKDF2_SHA256_LEGACY },
222#ifdef HAVE_OPENSSL_EVP_H
223 {
L(
"{sha224}"), FR_SHA2 },
224 {
L(
"{sha256}"), FR_SHA2 },
225 {
L(
"{sha2}"), FR_SHA2 },
226 {
L(
"{sha384}"), FR_SHA2_384 },
227 {
L(
"{sha512}"), FR_SHA2_512 },
229 {
L(
"{sha}"), FR_SHA1 },
230 {
L(
"{smd5}"), FR_SMD5 },
231#ifdef HAVE_OPENSSL_EVP_H
232 {
L(
"{ssha224}"), FR_SSHA2_224 },
233 {
L(
"{ssha256}"), FR_SSHA2_256 },
234 {
L(
"{ssha3-224}"), FR_SSHA3_224 },
235 {
L(
"{ssha3-256}"), FR_SSHA3_256 },
236 {
L(
"{ssha3-384}"), FR_SSHA3_384 },
237 {
L(
"{ssha3-512}"), FR_SSHA3_512 },
238 {
L(
"{ssha384}"), FR_SSHA2_384 },
239 {
L(
"{ssha512}"), FR_SSHA2_512 },
241 {
L(
"{ssha}"), FR_SSHA1 },
242 {
L(
"{x- orcllmv}"), FR_LM },
243 {
L(
"{x- orclntv}"), FR_NT },
244 {
L(
"{x-nthash}"), FR_NT },
245 {
L(
"{x-pbkdf2}"), FR_PBKDF2 },
249#ifdef HAVE_OPENSSL_EVP_H
301 [FR_PBKDF2_SHA256] = {
305 [FR_PBKDF2_SHA512] = {
309 [FR_PBKDF2_SHA256_LEGACY] = {
318#ifdef HAVE_OPENSSL_EVP_H
322 .func = password_process_sha2,
323 .min_hash_len = SHA224_DIGEST_LENGTH,
324 .max_hash_len = SHA512_DIGEST_LENGTH
329 .min_hash_len = SHA224_DIGEST_LENGTH,
334 .min_hash_len = SHA256_DIGEST_LENGTH,
339 .min_hash_len = SHA384_DIGEST_LENGTH,
344 .min_hash_len = SHA512_DIGEST_LENGTH,
349 .func = password_process_sha3,
350 .min_hash_len = SHA224_DIGEST_LENGTH,
355 .min_hash_len = SHA224_DIGEST_LENGTH,
360 .min_hash_len = SHA256_DIGEST_LENGTH,
365 .min_hash_len = SHA384_DIGEST_LENGTH,
370 .min_hash_len = SHA512_DIGEST_LENGTH
383#ifdef HAVE_OPENSSL_EVP_H
387 .min_hash_len = SHA224_DIGEST_LENGTH
392 .min_hash_len = SHA256_DIGEST_LENGTH
397 .min_hash_len = SHA384_DIGEST_LENGTH
402 .min_hash_len = SHA512_DIGEST_LENGTH
407 .min_hash_len = SHA224_DIGEST_LENGTH,
412 .min_hash_len = SHA256_DIGEST_LENGTH
417 .min_hash_len = SHA384_DIGEST_LENGTH
422 .min_hash_len = SHA512_DIGEST_LENGTH
427#define MIN_LEN(_info) (info->type == PASSWORD_HASH_SALTED ? (info->min_hash_len + 1) : info->min_hash_len)
430 char const *known_good,
size_t len,
size_t min_len)
437 if (min_len >= bufflen)
return 0;
443 if (!(len & 0x01) && len >= (2 * min_len)) {
449 if (decoded == (
ssize_t)(len >> 1)) {
459 if ((len * 3) >= ((min_len * 4))) {
463 if (decoded <= 0)
return 0;
464 if (decoded >= (
ssize_t) min_len) {
505 if (min_len >=
sizeof(
buffer))
return NULL;
507 switch (known_good->vp_type) {
510 (
char const *)known_good->vp_octets, known_good->vp_length, min_len);
515 known_good->vp_strvalue, known_good->vp_length, min_len);
523 RDEBUG2(
"Normalizing %s %s encoding, %zu bytes -> %zu bytes",
525 known_good->vp_length, decoded);
537#ifdef HAVE_OPENSSL_EVP_H
551 switch (known_good->vp_length) {
552 case SHA224_DIGEST_LENGTH:
557 case SHA256_DIGEST_LENGTH:
562 case SHA384_DIGEST_LENGTH:
567 case SHA512_DIGEST_LENGTH:
574 if (!
out)
return NULL;
576 normalised = password_process_sha2(ctx, request,
out);
596 switch (known_good->vp_length) {
597 case SHA224_DIGEST_LENGTH:
602 case SHA256_DIGEST_LENGTH:
607 case SHA384_DIGEST_LENGTH:
612 case SHA512_DIGEST_LENGTH:
619 if (!
out)
return NULL;
621 normalised = password_process_sha3(ctx, request,
out);
646 char const *p, *q, *end;
665 p = known_good->vp_strvalue;
666 end = p + known_good->vp_length;
672 if ((*p ==
'{') && (q = memchr(p,
'}', end - p))) {
678 if (hlen >=
sizeof(header)) {
679 REDEBUG(
"Password header too long. Got %zu bytes must be less than %zu bytes",
680 hlen,
sizeof(header));
684 memcpy(header, p, hlen);
693 RDEBUG3(
"Unknown header %s in %pP, re-writing to %s",
694 header, known_good, def->name);
696 RDEBUG2(
"Unknown header %s in %s, re-writing to %s",
697 header, known_good->
da->name, def->name);
709 switch ((*(info->
da))->type) {
725#ifdef STATIC_ANALYZER
729 memset(n1, 0,
sizeof(n1));
742 decoded =
normify(&normalised, n1,
sizeof(n1), p, end - p, 4);
744 if ((n1[0] ==
'{') && (memchr(n1,
'}', decoded) != NULL)) {
745 RDEBUG2(
"Normalizing %s %s encoding, %zu bytes -> %zu bytes",
747 known_good->vp_length, decoded);
754 memcpy(n2, n1, decoded);
755 p = (
char const *)n2;
769 RDEBUG3(
"No {...} in control.%pP, re-writing to %s", known_good, def->name);
771 RDEBUG2(
"No {...} in control.%s, re-writing to %s", known_good->
da->name, def->name);
797 from_func = info->
func(ctx, request, known_good);
798 if (!from_func)
return NULL;
812 if (from_func != known_good) TALLOC_FREE(from_func);
815 if ((from_func != known_good) && (from_recurse != from_func)) TALLOC_FREE(from_func);
828 out = from_normify ? from_normify : known_good;
838 RWDEBUG3(
"control.%pP too short, expected %zu bytes, got %zu bytes",
841 RWDEBUG2(
"control.%s too short, expected %zu bytes, got %zu bytes",
845 if (
out != known_good) TALLOC_FREE(
out);
854 RWDEBUG3(
"control.%pP too long, expected %zu bytes, got %zu bytes",
857 RWDEBUG2(
"control.%s too long, expected %zu bytes, got %zu bytes",
869 RWDEBUG3(
"control.%pP incorrect length, expected %zu bytes, got %zu bytes",
872 RWDEBUG2(
"control.%s incorrect length, expected %zu bytes, got %zu bytes",
905 RDEBUG3(
"Replacing control.%pP with control.%pP",
909 RDEBUG2(
"Replacing control.%s with control.%s",
910 known_good->
da->name, new->da->name);
933 if (!
new)
return NULL;
940 if (new->da != known_good->
da) {
941 for (j = 0; j < allowed_attrs_len; j++)
if (allowed_attrs[j] == new->da)
return new;
990 RWDEBUG(
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
991 RWDEBUG(
"!!! Ignoring control.User-Password. Update your !!!");
992 RWDEBUG(
"!!! configuration so that the \"known good\" clear text !!!");
993 RWDEBUG(
"!!! password is in Password.Cleartext and NOT in !!!");
994 RWDEBUG(
"!!! User-Password. !!!");
995 RWDEBUG(
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
1015 allowed_attrs, allowed_attrs_len,
1020 RDEBUG3(
"Using \"known good\" %s password %pP",
1025 RDEBUG2(
"Using \"known good\" %s password %s",
1028 "<INVALID>"),
out->da->name);
1030 if (ephemeral) *ephemeral = (known_good !=
out);
1034 for (i = 0; i < allowed_attrs_len; i++) {
1035 if (allowed_attrs[i] != known_good->
da)
continue;
1038 allowed_attrs, allowed_attrs_len,
1051 PERROR(
"%s", __FUNCTION__);
1055 PERROR(
"%s", __FUNCTION__);
static int const char char buffer[256]
#define fr_base16_decode(_err, _out, _in, _no_trailing)
#define fr_base64_decode(_out, _in, _expect_padding, _no_trailing)
#define L(_str)
Helper for initialising arrays of string literals.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void fr_dcursor_free_item(fr_dcursor_t *cursor)
talloc_free the current item
static int fr_dcursor_prepend(fr_dcursor_t *cursor, void *v)
Insert a single item at the start of the list.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
#define fr_dict_autofree(_to_free)
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
#define fr_dict_autoload(_to_load)
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
#define RWDEBUG2(fmt,...)
#define RWDEBUG3(fmt,...)
#define MD4_DIGEST_LENGTH
#define MD5_DIGEST_LENGTH
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_OCTETS
Raw octets.
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
int fr_pair_value_copy(fr_pair_t *dst, fr_pair_t *src)
Copy the value from one pair to another.
static fr_dict_attr_t const * attr_lm
@ PASSWORD_HASH
Fixed length.
@ PASSWORD_HASH_VARIABLE
Variable length everything.
@ PASSWORD_HASH_SALTED
Fixed length hash, variable length salt.
@ PASSWORD_CLEARTEXT
Variable length.
static fr_dict_attr_t const * attr_pbkdf2_sha256_legacy
static fr_dict_attr_t const * attr_ssha2_512
static fr_table_num_sorted_t const password_type_table[]
size_t max_hash_len
Maximum length of the decoded string if normifying.
password_preprocess_t func
Preprocessing function.
static fr_pair_t * password_normalise_and_recheck(TALLOC_CTX *ctx, request_t *request, fr_dict_attr_t const *allowed_attrs[], size_t allowed_attrs_len, bool normify, fr_pair_t *const known_good)
static fr_dict_attr_t const * attr_sha2_256
password_type_t type
What type of password value this is.
static fr_dict_attr_t const * attr_nt
static fr_dict_attr_t const * attr_ssha2_384
static fr_dict_attr_t const * attr_pbkdf2
static fr_dict_attr_t const * attr_pbkdf2_sha512
static int _password_init(UNUSED void *uctx)
static fr_dict_attr_t const * attr_crypt
static fr_pair_t * password_process(TALLOC_CTX *ctx, request_t *request, fr_pair_t *known_good, bool normify)
Apply any processing and normification.
static fr_dict_attr_t const * attr_sha3_256
static fr_dict_t const * dict_freeradius
static ssize_t normify(normalise_t *action, uint8_t *buffer, size_t bufflen, char const *known_good, size_t len, size_t min_len)
static fr_dict_attr_t const * attr_sha2_512
static fr_dict_attr_t const * attr_pbkdf2_sha256
static fr_dict_attr_t const * attr_ns_mta_md5
int password_init(void)
Load our dictionaries.
static size_t password_header_table_len
static fr_dict_t const * dict_radius
static fr_dict_attr_t const * attr_user
fr_pair_t *(* password_preprocess_t)(TALLOC_CTX *ctx, request_t *request, fr_pair_t *in)
Apply preprocessing logic to a password value.
static fr_dict_attr_t const * attr_pbkdf2_sha1
static password_info_t password_info[]
Metadata for various password attributes.
static fr_dict_attr_t const * attr_sha2_224
size_t min_hash_len
Minimum length of the decoded string if normifying.
static int _password_free(UNUSED void *uctx)
bool always_allow
Always allow processing of this attribute, irrespective of what the caller says.
static fr_dict_attr_t const * attr_ssha3_224
static fr_pair_t * password_normify(TALLOC_CTX *ctx, request_t *request, fr_pair_t const *known_good)
Hex or base64 or bin auto-discovery.
static fr_pair_t * password_process_header(TALLOC_CTX *ctx, request_t *request, fr_pair_t *known_good)
Convert a Password.With-Header attribute to the correct type.
static fr_dict_attr_t const * attr_md5
static fr_dict_attr_t const * attr_sha3_224
static fr_dict_attr_t const * attr_ssha2_256
bool no_normify
Don't attempt to normalise the contents of this attribute using the hex/base64 decoders.
static fr_dict_attr_t const * attr_root
static fr_dict_attr_t const * attr_sha3_384
static fr_dict_attr_t const * attr_ssha3_256
static fr_dict_attr_t const * attr_sha2
int password_normalise_and_replace(request_t *request, bool normify)
Find all password attributes in the control list of a request and normalise them.
fr_dict_autoload_t password_dict[]
static fr_table_num_sorted_t const password_header_table[]
static fr_dict_attr_t const * attr_ssha3_512
static fr_dict_attr_t const * attr_sha3
static fr_dict_attr_t const * attr_ssha2_224
static size_t normalise_table_len
fr_pair_t * password_find(bool *ephemeral, TALLOC_CTX *ctx, request_t *request, fr_dict_attr_t const *allowed_attrs[], size_t allowed_attrs_len, bool normify)
Find a "known good" password in the control list of a request.
static fr_dict_attr_t const * attr_sha2_384
static fr_dict_attr_t const * attr_ssha1
static size_t password_type_table_len
static fr_dict_attr_t const * attr_cleartext
static fr_dict_attr_t const * attr_ssha3_384
fr_dict_attr_autoload_t password_dict_attr[]
static fr_dict_attr_t const * attr_smd5
static fr_dict_attr_t const * attr_sha1
static fr_dict_attr_t const * attr_sha3_512
fr_dict_attr_t const ** da
Dictionary attribute representing this type of password.
static fr_table_num_sorted_t const normalise_table[]
static fr_dict_attr_t const * attr_with_header
#define FR_SBUFF_IN(_start, _len_or_end)
#define SHA1_DIGEST_LENGTH
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
#define fr_table_value_by_substr(_table, _name, _name_len, _def)
Convert a partial string to a value using an ordered or sorted table.
An element in a lexicographically sorted array of name to num mappings.
#define fr_pair_dcursor_by_ancestor_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes descended from the specified fr_dict_attr_t.
static size_t char ** out