Coverage Report

Created: 2026-09-28 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/server/password.c
Line
Count
Source
1
/*
2
 *   This program is free software; you can redistribute it and/or modify
3
 *   it under the terms of the GNU General Public License as published by
4
 *   the Free Software Foundation; either version 2 of the License, or
5
 *   (at your option) any later version.
6
 *
7
 *   This program is distributed in the hope that it will be useful,
8
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 *   GNU General Public License for more details.
11
 *
12
 *   You should have received a copy of the GNU General Public License
13
 *   along with this program; if not, write to the Free Software
14
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15
 */
16
17
/**
18
 * @file src/lib/server/password.c
19
 * @brief Password normalisation functions
20
 *
21
 * @copyright 2019 The FreeRADIUS server project
22
 * @copyright 2019 Arran Cudbard-Bell \<a.cudbardb@freeradius.org\>
23
 */
24
RCSID("$Id: c1c61498cd5a90d713b7cb5fb8e43cc76c3b78e4 $")
25
26
#include <freeradius-devel/server/password.h>
27
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>
36
37
#include <freeradius-devel/protocol/freeradius/freeradius.internal.password.h>
38
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>
43
#endif
44
45
typedef enum {
46
  PASSWORD_CLEARTEXT = 0,     //!< Variable length.
47
  PASSWORD_HASH,        //!< Fixed length.
48
  PASSWORD_HASH_SALTED,     //!< Fixed length hash, variable length salt.
49
  PASSWORD_HASH_VARIABLE      //!< Variable length everything.
50
} password_type_t;
51
52
/** Apply preprocessing logic to a password value
53
 *
54
 * @param[in] ctx to allocate returned value in.
55
 * @param[in] request currently being processed.
56
 * @param[in] in  Pair containing the password to process.
57
 * @
58
 */
59
typedef fr_pair_t *(*password_preprocess_t)(TALLOC_CTX *ctx, request_t *request, fr_pair_t *in);
60
61
/** Password information
62
 *
63
 */
64
typedef struct {
65
  password_type_t   type;   //!< What type of password value this is.
66
  fr_dict_attr_t const  **da;   //!< Dictionary attribute representing this type of password.
67
  password_preprocess_t func;   //!< Preprocessing function.
68
  size_t      min_hash_len; //!< Minimum length of the decoded string if normifying.
69
            ///< If 0, will be ignored.
70
  size_t      max_hash_len; //!< Maximum length of the decoded string if normifying.
71
            ///< If 0, will be ignored.
72
  bool      no_normify; //!< Don't attempt to normalise the contents of this
73
            ///< attribute using the hex/base64 decoders.
74
  bool      always_allow; //!< Always allow processing of this attribute, irrespective
75
            ///< of what the caller says.
76
} password_info_t;
77
78
static fr_dict_t const *dict_freeradius = NULL;
79
static fr_dict_t const *dict_radius = NULL;
80
81
static fr_dict_attr_t const *attr_cleartext;
82
static fr_dict_attr_t const *attr_with_header;
83
static fr_dict_attr_t const *attr_root;
84
85
static fr_dict_attr_t const *attr_md5;
86
static fr_dict_attr_t const *attr_smd5;
87
static fr_dict_attr_t const *attr_crypt;
88
89
static fr_dict_attr_t const *attr_sha1;
90
static fr_dict_attr_t const *attr_ssha1;
91
92
static fr_dict_attr_t const *attr_sha2;
93
static fr_dict_attr_t const *attr_sha2_224;
94
static fr_dict_attr_t const *attr_sha2_256;
95
static fr_dict_attr_t const *attr_sha2_384;
96
static fr_dict_attr_t const *attr_sha2_512;
97
98
static fr_dict_attr_t const *attr_ssha2_224;
99
static fr_dict_attr_t const *attr_ssha2_256;
100
static fr_dict_attr_t const *attr_ssha2_384;
101
static fr_dict_attr_t const *attr_ssha2_512;
102
103
static fr_dict_attr_t const *attr_sha3;
104
static fr_dict_attr_t const *attr_sha3_224;
105
static fr_dict_attr_t const *attr_sha3_256;
106
static fr_dict_attr_t const *attr_sha3_384;
107
static fr_dict_attr_t const *attr_sha3_512;
108
109
static fr_dict_attr_t const *attr_ssha3_224;
110
static fr_dict_attr_t const *attr_ssha3_256;
111
static fr_dict_attr_t const *attr_ssha3_384;
112
static fr_dict_attr_t const *attr_ssha3_512;
113
114
static fr_dict_attr_t const *attr_pbkdf2;
115
static fr_dict_attr_t const *attr_pbkdf2_sha1;
116
static fr_dict_attr_t const *attr_pbkdf2_sha256;
117
static fr_dict_attr_t const *attr_pbkdf2_sha512;
118
static fr_dict_attr_t const *attr_pbkdf2_sha256_legacy;
119
static fr_dict_attr_t const *attr_lm;
120
static fr_dict_attr_t const *attr_nt;
121
static fr_dict_attr_t const *attr_ns_mta_md5;
122
123
static fr_dict_attr_t const *attr_psk;
124
125
static fr_dict_attr_t const *attr_user;
126
127
extern fr_dict_autoload_t password_dict[];
128
fr_dict_autoload_t password_dict[] = {
129
  { .out = &dict_freeradius, .proto = "freeradius" },
130
  { .out = &dict_radius, .proto = "radius" },
131
  DICT_AUTOLOAD_TERMINATOR
132
};
133
134
extern fr_dict_attr_autoload_t password_dict_attr[];
135
fr_dict_attr_autoload_t password_dict_attr[] = {
136
  { .out = &attr_cleartext, .name = "Password.Cleartext", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
137
  { .out = &attr_with_header, .name = "Password.With-Header", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
138
  { .out = &attr_root, .name = "Password", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
139
140
  { .out = &attr_md5, .name = "Password.MD5", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
141
  { .out = &attr_smd5, .name = "Password.SMD5", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
142
  { .out = &attr_crypt, .name = "Password.Crypt", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
143
  { .out = &attr_sha1, .name = "Password.SHA1", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
144
  { .out = &attr_ssha1, .name = "Password.SSHA1", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
145
146
  { .out = &attr_sha2, .name = "Password.SHA2", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
147
  { .out = &attr_sha2_224, .name = "Password.SHA2-224", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
148
  { .out = &attr_sha2_256, .name = "Password.SHA2-256", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
149
  { .out = &attr_sha2_384, .name = "Password.SHA2-384", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
150
  { .out = &attr_sha2_512, .name = "Password.SHA2-512", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
151
152
  { .out = &attr_ssha2_224, .name = "Password.SSHA2-224", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
153
  { .out = &attr_ssha2_256, .name = "Password.SSHA2-256", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
154
  { .out = &attr_ssha2_384, .name = "Password.SSHA2-384", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
155
  { .out = &attr_ssha2_512, .name = "Password.SSHA2-512", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
156
157
  { .out = &attr_sha3, .name = "Password.SHA3", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
158
  { .out = &attr_sha3_224, .name = "Password.SHA3-224", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
159
  { .out = &attr_sha3_256, .name = "Password.SHA3-256", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
160
  { .out = &attr_sha3_384, .name = "Password.SHA3-384", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
161
  { .out = &attr_sha3_512, .name = "Password.SHA3-512", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
162
163
  { .out = &attr_ssha3_224, .name = "Password.SSHA3-224", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
164
  { .out = &attr_ssha3_256, .name = "Password.SSHA3-256", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
165
  { .out = &attr_ssha3_384, .name = "Password.SSHA3-384", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
166
  { .out = &attr_ssha3_512, .name = "Password.SSHA3-512", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
167
168
  { .out = &attr_pbkdf2, .name = "Password.PBKDF2", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
169
  { .out = &attr_pbkdf2_sha1, .name = "Password.PBKDF2-SHA1", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
170
  { .out = &attr_pbkdf2_sha256, .name = "Password.PBKDF2-SHA256", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
171
  { .out = &attr_pbkdf2_sha512, .name = "Password.PBKDF2-SHA512", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
172
  { .out = &attr_pbkdf2_sha256_legacy, .name = "Password.PBKDF2-SHA256-LEGACY", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
173
  { .out = &attr_lm, .name = "Password.LM", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
174
  { .out = &attr_nt, .name = "Password.NT", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
175
  { .out = &attr_ns_mta_md5, .name = "Password.NS-MTA-MD5", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
176
177
  { .out = &attr_psk, .name = "Password.PSK", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
178
179
  { .out = &attr_user, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
180
181
  DICT_AUTOLOAD_TERMINATOR
182
};
183
184
typedef enum {
185
  NORMALISED_NOTHING = 0,
186
  NORMALISED_B64,
187
  NORMALISED_HEX
188
} normalise_t;
189
190
static fr_table_num_sorted_t const normalise_table[] = {
191
  { L("base64"),      NORMALISED_B64    },
192
  { L("hex"),     NORMALISED_HEX    },
193
  { L("nothing"),     NORMALISED_NOTHING  }
194
};
195
static size_t normalise_table_len = NUM_ELEMENTS(normalise_table);
196
197
static fr_table_num_sorted_t const password_type_table[] = {
198
  { L("cleartext"),     PASSWORD_CLEARTEXT  },
199
  { L("hashed"),      PASSWORD_HASH   },
200
  { L("salted-hash"),   PASSWORD_HASH_SALTED  },
201
  { L("variable-length-hash"),  PASSWORD_HASH_VARIABLE  }
202
};
203
static size_t password_type_table_len = NUM_ELEMENTS(password_type_table);
204
205
/*
206
 *  Headers for the Password-with-Header attribute
207
 *
208
 *  @note Header comparison is case insensitive.
209
 */
210
static fr_table_num_sorted_t const password_header_table[] = {
211
  { L("{base64_md5}"),      FR_MD5    },
212
  { L("{clear}"),       FR_CLEARTEXT  },
213
  { L("{cleartext}"),     FR_CLEARTEXT  },
214
  { L("{crypt}"),       FR_CRYPT  },
215
  { L("{md4}"),       FR_NT   },
216
  { L("{md5}"),       FR_MD5    },
217
  { L("{ns-mta-md5}"),      FR_NS_MTA_MD5 },
218
  { L("{nt}"),        FR_NT   },
219
  { L("{nthash}"),      FR_NT   },
220
221
  { L("{pbkdf2-sha1}"),     FR_PBKDF2_SHA1  },
222
  { L("{pbkdf2-sha256}"),     FR_PBKDF2_SHA256 },
223
  { L("{pbkdf2-sha512}"),     FR_PBKDF2_SHA512 },
224
  { L("{pbkdf2_sha256}"),     FR_PBKDF2_SHA256_LEGACY },
225
226
#ifdef HAVE_OPENSSL_EVP_H
227
  { L("{sha224}"),      FR_SHA2 },
228
  { L("{sha256}"),      FR_SHA2 },
229
  { L("{sha2}"),        FR_SHA2 },
230
  { L("{sha384}"),      FR_SHA2_384 },
231
  { L("{sha512}"),      FR_SHA2_512 },
232
#endif
233
  { L("{sha}"),       FR_SHA1 },
234
  { L("{smd5}"),        FR_SMD5 },
235
#ifdef HAVE_OPENSSL_EVP_H
236
  { L("{ssha224}"),     FR_SSHA2_224  },
237
  { L("{ssha256}"),     FR_SSHA2_256  },
238
  { L("{ssha3-224}"),     FR_SSHA3_224  },
239
  { L("{ssha3-256}"),     FR_SSHA3_256  },
240
  { L("{ssha3-384}"),     FR_SSHA3_384  },
241
  { L("{ssha3-512}"),     FR_SSHA3_512  },
242
  { L("{ssha384}"),     FR_SSHA2_384  },
243
  { L("{ssha512}"),     FR_SSHA2_512  },
244
#endif
245
  { L("{ssha}"),        FR_SSHA1  },
246
  { L("{x- orcllmv}"),      FR_LM   },
247
  { L("{x- orclntv}"),      FR_NT   },
248
  { L("{x-nthash}"),      FR_NT   },
249
  { L("{x-pbkdf2}"),      FR_PBKDF2 },
250
};
251
static size_t password_header_table_len = NUM_ELEMENTS(password_header_table);
252
253
#ifdef HAVE_OPENSSL_EVP_H
254
static fr_pair_t *password_process_sha2(TALLOC_CTX *ctx, request_t *request, fr_pair_t *known_good);
255
static fr_pair_t *password_process_sha3(TALLOC_CTX *ctx, request_t *request, fr_pair_t *known_good);
256
#endif
257
static fr_pair_t *password_process_header(TALLOC_CTX *ctx, request_t *request, fr_pair_t *known_good);
258
259
/** Metadata for various password attributes
260
 *
261
 */
262
static password_info_t password_info[] = {
263
  [FR_CLEARTEXT]      = {
264
            .type = PASSWORD_CLEARTEXT,
265
            .da = &attr_cleartext,
266
            .no_normify = true
267
          },
268
  [FR_CRYPT]      = {
269
            .type = PASSWORD_HASH,
270
            .da = &attr_crypt
271
          },
272
  [FR_LM]       = {
273
            .type = PASSWORD_HASH,
274
            .da = &attr_lm,
275
            .min_hash_len = MD4_DIGEST_LENGTH
276
          },
277
  [FR_MD5]      = {
278
            .type = PASSWORD_HASH,
279
            .da = &attr_md5,
280
            .min_hash_len = MD5_DIGEST_LENGTH
281
          },
282
  [FR_NS_MTA_MD5]     = {
283
            .type = PASSWORD_HASH,
284
            .da = &attr_ns_mta_md5
285
          },
286
  [FR_NT]       = {
287
            .type = PASSWORD_HASH,
288
            .da = &attr_nt,
289
            .min_hash_len = MD4_DIGEST_LENGTH
290
          },
291
  [FR_WITH_HEADER]    = {
292
            .type = PASSWORD_HASH_VARIABLE,
293
            .da = &attr_with_header,
294
            .func = password_process_header,
295
            .always_allow = true
296
          },
297
  [FR_PBKDF2]     = {
298
            .type = PASSWORD_HASH_VARIABLE,
299
            .da = &attr_pbkdf2
300
          },
301
  [FR_PBKDF2_SHA1]    = {
302
            .type = PASSWORD_HASH_VARIABLE,
303
            .da = &attr_pbkdf2_sha1
304
          },
305
  [FR_PBKDF2_SHA256]    = {
306
            .type = PASSWORD_HASH_VARIABLE,
307
            .da = &attr_pbkdf2_sha256
308
          },
309
  [FR_PBKDF2_SHA512]    = {
310
            .type = PASSWORD_HASH_VARIABLE,
311
            .da = &attr_pbkdf2_sha512
312
          },
313
  [FR_PBKDF2_SHA256_LEGACY] = {
314
            .type = PASSWORD_HASH_VARIABLE,
315
            .da = &attr_pbkdf2_sha256_legacy
316
          },
317
  [FR_SHA1]     = {
318
            .type = PASSWORD_HASH,
319
            .da = &attr_sha1,
320
            .min_hash_len = SHA1_DIGEST_LENGTH
321
          },
322
#ifdef HAVE_OPENSSL_EVP_H
323
  [FR_SHA2]     = {
324
            .type = PASSWORD_HASH_VARIABLE,
325
            .da = &attr_sha2,
326
            .func = password_process_sha2,
327
            .min_hash_len = SHA224_DIGEST_LENGTH,
328
            .max_hash_len = SHA512_DIGEST_LENGTH
329
          },
330
  [FR_SHA2_224]     = {
331
            .type = PASSWORD_HASH,
332
            .da = &attr_sha2_224,
333
            .min_hash_len = SHA224_DIGEST_LENGTH,
334
          },
335
  [FR_SHA2_256]     = {
336
            .type = PASSWORD_HASH,
337
            .da = &attr_sha2_256,
338
            .min_hash_len = SHA256_DIGEST_LENGTH,
339
          },
340
  [FR_SHA2_384]     = {
341
            .type = PASSWORD_HASH,
342
            .da = &attr_sha2_384,
343
            .min_hash_len = SHA384_DIGEST_LENGTH,
344
          },
345
  [FR_SHA2_512]     = {
346
            .type = PASSWORD_HASH,
347
            .da = &attr_sha2_512,
348
            .min_hash_len = SHA512_DIGEST_LENGTH,
349
          },
350
  [FR_SHA3]     = {
351
            .type = PASSWORD_HASH_VARIABLE,
352
            .da = &attr_sha3,
353
            .func = password_process_sha3,
354
            .min_hash_len = SHA224_DIGEST_LENGTH,
355
          },
356
  [FR_SHA3_224]     = {
357
            .type = PASSWORD_HASH,
358
            .da = &attr_sha3_224,
359
            .min_hash_len = SHA224_DIGEST_LENGTH,
360
          },
361
  [FR_SHA3_256]     = {
362
            .type = PASSWORD_HASH,
363
            .da = &attr_sha3_256,
364
            .min_hash_len = SHA256_DIGEST_LENGTH,
365
          },
366
  [FR_SHA3_384]     = {
367
            .type = PASSWORD_HASH,
368
            .da = &attr_sha3_384,
369
            .min_hash_len = SHA384_DIGEST_LENGTH,
370
          },
371
  [FR_SHA3_512]     = {
372
            .type = PASSWORD_HASH,
373
            .da = &attr_sha3_512,
374
            .min_hash_len = SHA512_DIGEST_LENGTH
375
          },
376
#endif
377
  [FR_SMD5]     = {
378
            .type = PASSWORD_HASH,
379
            .da = &attr_smd5,
380
            .min_hash_len = MD5_DIGEST_LENGTH
381
          },
382
  [FR_SSHA1]      = {
383
            .type = PASSWORD_HASH_SALTED,
384
            .da = &attr_ssha1,
385
            .min_hash_len = SHA1_DIGEST_LENGTH
386
          },
387
#ifdef HAVE_OPENSSL_EVP_H
388
  [FR_SSHA2_224]      = {
389
            .type = PASSWORD_HASH_SALTED,
390
            .da = &attr_ssha2_224,
391
            .min_hash_len = SHA224_DIGEST_LENGTH
392
          },
393
  [FR_SSHA2_256]      = {
394
            .type = PASSWORD_HASH_SALTED,
395
            .da = &attr_ssha2_256,
396
            .min_hash_len = SHA256_DIGEST_LENGTH
397
          },
398
  [FR_SSHA2_384]      = {
399
            .type = PASSWORD_HASH_SALTED,
400
            .da = &attr_ssha2_384,
401
            .min_hash_len = SHA384_DIGEST_LENGTH
402
          },
403
  [FR_SSHA2_512]      = {
404
            .type = PASSWORD_HASH_SALTED,
405
            .da = &attr_ssha2_512,
406
            .min_hash_len = SHA512_DIGEST_LENGTH
407
          },
408
  [FR_SSHA3_224]      = {
409
            .type = PASSWORD_HASH_SALTED,
410
            .da = &attr_ssha3_224,
411
            .min_hash_len = SHA224_DIGEST_LENGTH,
412
          },
413
  [FR_SSHA3_256]      = {
414
            .type = PASSWORD_HASH_SALTED,
415
            .da = &attr_ssha3_256,
416
            .min_hash_len = SHA256_DIGEST_LENGTH
417
          },
418
  [FR_SSHA3_384]      = {
419
            .type = PASSWORD_HASH_SALTED,
420
            .da = &attr_ssha3_384,
421
            .min_hash_len = SHA384_DIGEST_LENGTH
422
          },
423
  [FR_SSHA3_512]      = {
424
            .type = PASSWORD_HASH_SALTED,
425
            .da = &attr_ssha3_512,
426
            .min_hash_len = SHA512_DIGEST_LENGTH
427
          },
428
#endif
429
430
  [FR_PSK]      = {
431
            .type = PASSWORD_HASH,
432
            .da = &attr_psk,
433
            .min_hash_len = 16
434
          },
435
};
436
437
0
#define MIN_LEN(_info) ((_info)->type == PASSWORD_HASH_SALTED ? ((_info)->min_hash_len + 1) : (_info)->min_hash_len)
438
439
static ssize_t normify(normalise_t *action, uint8_t *buffer, size_t bufflen,
440
           char const *known_good, size_t len, size_t min_len)
441
0
{
442
  /*
443
   *  Else unknown encoding, or already binary.  Leave it.
444
   */
445
0
  if (action) *action = NORMALISED_NOTHING;
446
447
0
  if (min_len >= bufflen) return 0; /* paranoia */
448
449
  /*
450
   *  Hex encoding. Length is even, and it's greater than
451
   *  twice the minimum length.
452
   */
453
0
  if (!(len & 0x01) && len >= (2 * min_len)) {
454
0
    ssize_t decoded;
455
456
0
    buffer[0] = 0x00; /* clang scan */
457
458
0
    decoded = fr_base16_decode(NULL, &FR_DBUFF_TMP(buffer, bufflen), &FR_SBUFF_IN(known_good, len), true);
459
0
    if (decoded == (ssize_t)(len >> 1)) {
460
0
      if (action) *action = NORMALISED_HEX;
461
0
      return decoded;
462
0
    }
463
0
  }
464
465
  /*
466
   *  Base 64 encoding.  It's at least 4/3 the original size,
467
   *  and we want to avoid division...
468
   */
469
0
  if ((len * 3) >= ((min_len * 4))) {
470
0
    ssize_t decoded;
471
472
0
    decoded = fr_base64_decode(&FR_DBUFF_TMP(buffer, bufflen), &FR_SBUFF_IN(known_good, len), true, true);
473
0
    if (decoded <= 0) return 0;
474
0
    if (decoded >= (ssize_t) min_len) {
475
0
      if (action) *action = NORMALISED_B64;
476
0
      return decoded;
477
0
    }
478
0
  }
479
480
0
  return 0;
481
0
}
482
483
/** Hex or base64 or bin auto-discovery
484
 *
485
 * Here we try and autodiscover what encoding was used for the password/hash, and
486
 * convert it back to binary or plaintext.
487
 *
488
 * @note Earlier versions used a 0x prefix as a hard indicator that the string was
489
 *       hex encoded, and would fail if the 0x was present but the string didn't
490
 *       consist of hexits. The base64 char set is a superset of hex, and it was
491
 *       observed in the wild, that occasionally base64 encoded data really could
492
 *       start with 0x. That's why min_len (and decodability) are used as the
493
 *       only heuristics now.
494
 *
495
 * @param[in] ctx   to allocate new pairs in.
496
 * @param[in] request   The current request.
497
 * @param[in] known_good  password to normify.
498
 * @return
499
 *  - NULL if known_good was already normalised, or couldn't be normalised.
500
 *  - A new normalised password pair.
501
 */
502
static fr_pair_t *password_normify(TALLOC_CTX *ctx, request_t *request, fr_pair_t const *known_good)
503
{
504
  uint8_t     buffer[256];
505
  ssize_t     decoded;
506
  fr_pair_t   *out;
507
  normalise_t   normalised;
508
  password_info_t   *info;
509
  size_t      min_len;
510
511
  if (!fr_cond_assert(known_good->da->attr < NUM_ELEMENTS(password_info))) return NULL;
512
513
  info = &password_info[known_good->da->attr];
514
  min_len = MIN_LEN(info);
515
  if (min_len >= sizeof(buffer)) return NULL; /* paranoia */
516
517
  switch (known_good->vp_type) {
518
  case FR_TYPE_OCTETS:
519
    decoded = normify(&normalised, buffer, sizeof(buffer),
520
          (char const *)known_good->vp_octets, known_good->vp_length, min_len);
521
    break;
522
523
  case FR_TYPE_STRING:
524
    decoded = normify(&normalised, buffer, sizeof(buffer),
525
          known_good->vp_strvalue, known_good->vp_length, min_len);
526
    break;
527
528
  default:
529
    return NULL;
530
  }
531
532
  if (normalised != NORMALISED_NOTHING) {
533
    RDEBUG2("Normalizing %s %s encoding, %zu bytes -> %zu bytes",
534
      known_good->da->name, fr_table_str_by_value(normalise_table, normalised, 0),
535
      known_good->vp_length, decoded);
536
    MEM(out = fr_pair_afrom_da(ctx, known_good->da));
537
    fr_pair_value_memdup(out, buffer, decoded, known_good->vp_tainted);
538
    return out;
539
  }
540
541
  /*
542
   *  Else unknown encoding, or already binary.  Leave it.
543
   */
544
  return NULL;
545
}
546
547
#ifdef HAVE_OPENSSL_EVP_H
548
/** Split SHA2 hashes into separate attributes based on their length
549
 *
550
 * @param[in] ctx   to allocate attributes in.
551
 * @param[in] request   The current request.
552
 * @param[in] known_good  attribute to split.
553
 * @return
554
 *  - A SHA2 length specific attribute.
555
 *  - NULL on error.
556
 */
557
static fr_pair_t *password_process_sha2(TALLOC_CTX *ctx, request_t *request, fr_pair_t *known_good)
558
0
{
559
0
  fr_pair_t *out, *normalised;
560
561
0
  switch (known_good->vp_length) {
562
0
  case SHA224_DIGEST_LENGTH:
563
0
    MEM(out = fr_pair_afrom_da(ctx, attr_sha2_224));
564
0
    fr_pair_value_copy(out, known_good);
565
0
    return out;
566
567
0
  case SHA256_DIGEST_LENGTH:
568
0
    MEM(out = fr_pair_afrom_da(ctx, attr_sha2_256));
569
0
    fr_pair_value_copy(out, known_good);
570
0
    return out;
571
572
0
  case SHA384_DIGEST_LENGTH:
573
0
    MEM(out = fr_pair_afrom_da(ctx, attr_sha2_384));
574
0
    fr_pair_value_copy(out, known_good);
575
0
    return out;
576
577
0
  case SHA512_DIGEST_LENGTH:
578
0
    MEM(out = fr_pair_afrom_da(ctx, attr_sha2_512));
579
0
    fr_pair_value_copy(out, known_good);
580
0
    return out;
581
582
0
  default:
583
0
    out = password_normify(ctx, request, known_good);
584
0
    if (!out) return NULL;
585
586
0
    normalised = password_process_sha2(ctx, request, out);
587
0
    TALLOC_FREE(out);
588
589
0
    return normalised;
590
0
  }
591
0
}
592
593
/** Split SHA3 hashes into separate attributes based on their length
594
 *
595
 * @param[in] ctx   to allocate attributes in.
596
 * @param[in] request   The current request.
597
 * @param[in] known_good  attribute to split.
598
 * @return
599
 *  - A SHA3 length specific attribute.
600
 *  - NULL on error.
601
 */
602
static fr_pair_t *password_process_sha3(TALLOC_CTX *ctx, request_t *request, fr_pair_t *known_good)
603
0
{
604
0
  fr_pair_t *out, *normalised;
605
606
0
  switch (known_good->vp_length) {
607
0
  case SHA224_DIGEST_LENGTH:
608
0
    MEM(out = fr_pair_afrom_da(ctx, attr_sha3_224));
609
0
    fr_pair_value_copy(out, known_good);
610
0
    return out;
611
612
0
  case SHA256_DIGEST_LENGTH:
613
0
    MEM(out = fr_pair_afrom_da(ctx, attr_sha3_256));
614
0
    fr_pair_value_copy(out, known_good);
615
0
    return out;
616
617
0
  case SHA384_DIGEST_LENGTH:
618
0
    MEM(out = fr_pair_afrom_da(ctx, attr_sha3_384));
619
0
    fr_pair_value_copy(out, known_good);
620
0
    return out;
621
622
0
  case SHA512_DIGEST_LENGTH:
623
0
    MEM(out = fr_pair_afrom_da(ctx, attr_sha3_512));
624
0
    fr_pair_value_copy(out, known_good);
625
0
    return out;
626
627
0
  default:
628
0
    out = password_normify(ctx, request, known_good);
629
0
    if (!out) return NULL;
630
631
0
    normalised = password_process_sha3(ctx, request, out);
632
0
    TALLOC_FREE(out);
633
634
0
    return normalised;
635
0
  }
636
0
}
637
#endif
638
639
/** Convert a Password.With-Header attribute to the correct type
640
 *
641
 * Attribute may be base64 encoded, in which case it will be decoded
642
 * first, then evaluated.
643
 *
644
 * @note The buffer for octets types\ attributes is extended by one byte
645
 *  and '\0' terminated, to allow it to be used as a char buff.
646
 *
647
 * @param[in] ctx   to allocate new pairs in.
648
 * @param[in] request   Current request.
649
 * @param[in] known_good  Password.With-Header attribute to convert.
650
 * @return
651
 *  - Buffer containing normified value on success.
652
 *  - NULL on error.
653
 */
654
static fr_pair_t *password_process_header(TALLOC_CTX *ctx, request_t *request, fr_pair_t *known_good)
655
{
656
  char const      *p, *q, *end;
657
658
  uint8_t       n1[256], n2[256];
659
  ssize_t       decoded;
660
661
  char        header[128];
662
  normalise_t     normalised;
663
664
  fr_pair_t     *new;
665
  fr_dict_attr_t const    *def = attr_cleartext;
666
667
  PAIR_VERIFY(known_good);
668
669
  /*
670
   *  Ensure this is only ever called with a
671
   *  string type attribute.
672
   */
673
  fr_assert(known_good->vp_type == FR_TYPE_STRING);
674
675
  p = known_good->vp_strvalue;
676
  end = p + known_good->vp_length;
677
678
  /*
679
   *  Has a header {...} prefix
680
   */
681
do_header:
682
  if ((*p == '{') && (q = memchr(p, '}', end - p))) {
683
    size_t      hlen;
684
    int     attr;
685
    password_info_t   *info;
686
687
    hlen = (q - p) + 1;
688
    if (hlen >= sizeof(header)) {
689
      REDEBUG("Password header too long.  Got %zu bytes must be less than %zu bytes",
690
        hlen, sizeof(header));
691
      return NULL;
692
    }
693
694
    memcpy(header, p, hlen);
695
    header[hlen] = '\0';
696
697
    attr = fr_table_value_by_substr(password_header_table, header, hlen, -1);
698
    if (attr < 0) {
699
      /*
700
       *  header buffer retains { and }
701
       */
702
      if (RDEBUG_ENABLED3) {
703
        RDEBUG3("Unknown header %s in %pP, re-writing to %s",
704
          header, known_good, def->name);
705
      } else {
706
        RDEBUG2("Unknown header %s in %s, re-writing to %s",
707
          header, known_good->da->name, def->name);
708
      }
709
      p = q + 1;
710
      goto bad_header;
711
    }
712
713
    p = q + 1;
714
715
    if (!fr_cond_assert((size_t) attr < NUM_ELEMENTS(password_info))) return NULL;
716
    info = &password_info[attr];
717
718
    MEM(new = fr_pair_afrom_da(ctx, *(info->da)));
719
    switch ((*(info->da))->type) {
720
    case FR_TYPE_OCTETS:
721
      fr_pair_value_memdup(new, (uint8_t const *)p, end - p, true);
722
      break;
723
724
    case FR_TYPE_STRING:
725
      fr_pair_value_bstrndup(new, p, end - p, true);
726
      break;
727
728
    default:
729
      talloc_free(new);
730
      fr_assert_fail(NULL);
731
      return NULL;
732
    }
733
    return new;
734
  }
735
736
#ifdef STATIC_ANALYZER
737
  /*
738
   *  static analyzer isn't smart enough to notice that "normify" clears out n1.
739
   */
740
  memset(n1, 0, sizeof(n1));
741
#endif
742
743
  /*
744
   *  Doesn't have a header {...} prefix
745
   *
746
   *  See if it's base64 or hex, if it is, decode it and check again!
747
   *
748
   *  We ignore request not to normify, as curly braces aren't
749
   *  in either of the character sets for the encoding schemes
750
   *  we're normifying, so there's not the possibility for error
751
   *  as there is normifying other password hashes.
752
   */
753
  decoded = normify(&normalised, n1, sizeof(n1), p, end - p, 4);  /* { + <char> + } + <char> */
754
  if (decoded > 0) {
755
    if ((n1[0] == '{') && (memchr(n1, '}', decoded) != NULL)) {
756
      RDEBUG2("Normalizing %s %s encoding, %zu bytes -> %zu bytes",
757
        known_good->da->name, fr_table_str_by_value(normalise_table, normalised, 0),
758
        known_good->vp_length, decoded);
759
760
      /*
761
       *  Password.With-Header is a string attribute.
762
       *  Even though we're handling binary data, the header
763
       *  must be \0 terminated.
764
       */
765
      memcpy(n2, n1, decoded);
766
      p = (char const *)n2;
767
      end = p + decoded;
768
      goto do_header;
769
    }
770
  }
771
772
  /*
773
   *  Rewrite to the default attribute type
774
   *  currently Password.Cleartext.
775
   *
776
   *  This is usually correct if there's no
777
   *  header to indicate hash type.
778
   */
779
  if (RDEBUG_ENABLED3) {
780
    RDEBUG3("No {...} in control.%pP, re-writing to %s", known_good, def->name);
781
  } else {
782
    RDEBUG2("No {...} in control.%s, re-writing to %s", known_good->da->name, def->name);
783
  }
784
785
bad_header:
786
  MEM(new = fr_pair_afrom_da(ctx, def));
787
  fr_pair_value_bstrndup(new, p, end - p, true);
788
789
  return new;
790
}
791
792
/** Apply any processing and normification
793
 *
794
 */
795
static fr_pair_t *password_process(TALLOC_CTX *ctx, request_t *request, fr_pair_t *known_good, bool normify)
796
0
{
797
0
  password_info_t   *info;
798
0
  fr_pair_t   *out;
799
800
0
  if (!fr_cond_assert(known_good->da->attr < NUM_ELEMENTS(password_info))) return NULL;
801
802
0
  info = &password_info[known_good->da->attr];
803
0
  if (info->func) {
804
0
    fr_pair_t *from_func, *from_recurse;
805
806
    /*
807
     *  Pass our input attribute to a custom preprocessing
808
     *  function to manipulate it.
809
     */
810
0
    from_func = info->func(ctx, request, known_good);
811
0
    if (!from_func) return NULL;
812
813
    /*
814
     *  Processing function may have produced a different
815
     *  password type, recurse to deal with it...
816
     */
817
0
    from_recurse = password_process(ctx, request, from_func, normify);
818
819
    /*
820
     *  Cleanup any intermediary password attributes created
821
     *  from running the different normalisation and parsing
822
     *  operations.
823
     */
824
0
    if (!from_recurse) {
825
0
      if (from_func != known_good) TALLOC_FREE(from_func);
826
0
      return NULL;
827
0
    }
828
0
    if ((from_func != known_good) && (from_recurse != from_func)) TALLOC_FREE(from_func);
829
830
0
    return from_recurse;
831
0
  }
832
833
  /*
834
   *  Only normify if we're told to, and we have more data
835
   *  than the minimum length.
836
   */
837
0
  if (normify && !info->no_normify && (known_good->vp_length > info->min_hash_len)) {
838
0
    fr_pair_t *from_normify;
839
840
0
    from_normify = password_normify(ctx, request, known_good);
841
0
    out = from_normify ? from_normify : known_good;
842
0
  } else {
843
0
    out = known_good;
844
0
  }
845
846
  /*
847
   *  Sanity checks - Too short
848
   */
849
0
  if (info->min_hash_len && (out->vp_length < MIN_LEN(info))) {
850
0
    if (RDEBUG_ENABLED3) {
851
0
      RWDEBUG3("control.%pP too short, expected %zu bytes, got %zu bytes",
852
0
         out, MIN_LEN(info), out->vp_length);
853
0
    } else {
854
0
      RWDEBUG2("control.%s too short, expected %zu bytes, got %zu bytes",
855
0
         out->da->name, MIN_LEN(info), out->vp_length);
856
0
    }
857
0
  invalid:
858
0
    if (out != known_good) TALLOC_FREE(out); /* Free attribute we won't be returning */
859
0
    return NULL;
860
0
  }
861
862
  /*
863
   *  Sanity checks - Too long
864
   */
865
0
  if (info->max_hash_len && (out->vp_length > info->max_hash_len)) {
866
0
    if (RDEBUG_ENABLED3) {
867
0
      RWDEBUG3("control.%pP too long, expected %zu bytes, got %zu bytes",
868
0
         out, info->max_hash_len, out->vp_length);
869
0
    } else {
870
0
      RWDEBUG2("control.%s too long, expected %zu bytes, got %zu bytes",
871
0
         out->da->name, info->max_hash_len, out->vp_length);
872
0
    }
873
0
    goto invalid;
874
0
  }
875
876
  /*
877
   *  Sanity checks - Hashes are a fixed length
878
   */
879
0
  if ((info->type == PASSWORD_HASH) && (out->vp_length != info->min_hash_len)) {
880
881
0
    if (RDEBUG_ENABLED3) {
882
0
      RWDEBUG3("control.%pP incorrect length, expected %zu bytes, got %zu bytes",
883
0
         out, info->min_hash_len, out->vp_length);
884
0
    } else {
885
0
      RWDEBUG2("control.%s incorrect length, expected %zu bytes, got %zu bytes",
886
0
         out->da->name, info->min_hash_len, out->vp_length);
887
0
    }
888
0
    goto invalid;
889
0
  }
890
891
0
  return out;
892
0
}
893
894
/** Find all password attributes in the control list of a request and normalise them
895
 *
896
 * @param[in] request The current request.
897
 * @param[in] normify Apply hex/base64 normalisation to attributes.
898
 * @return the number of attributes normalised.
899
 */
900
int password_normalise_and_replace(request_t *request, bool normify)
901
0
{
902
0
  fr_dcursor_t  cursor;
903
0
  int   replaced = 0;
904
0
  fr_pair_t *known_good, *new;
905
906
0
  for (known_good = fr_pair_dcursor_by_ancestor_init(&cursor, &request->control_pairs, attr_root);
907
0
       known_good;
908
0
       known_good = fr_dcursor_next(&cursor)) {
909
0
    if (!fr_cond_assert(known_good->da->attr < NUM_ELEMENTS(password_info))) return -1;
910
911
    /*
912
     *  Apply preprocessing steps and normalisation.
913
     */
914
0
    new = password_process(request, request, known_good, normify);
915
0
    if (!new) continue;   /* Process next input attribute */
916
917
    /*
918
     *  If we didn't do anything to it, we do nothing.
919
     */
920
0
    if (new == known_good) {
921
0
      replaced++;
922
0
      continue;
923
0
    }
924
925
0
    if (RDEBUG_ENABLED3) {
926
0
      RDEBUG3("Replacing control.%pP with control.%pP",
927
0
        known_good, new);
928
929
0
    } else {
930
0
      RDEBUG2("Replacing control.%s with control.%s",
931
0
        known_good->da->name, new->da->name);
932
0
    }
933
0
    fr_dcursor_free_item(&cursor);
934
0
    fr_dcursor_prepend(&cursor, new);
935
0
    replaced++;
936
0
  }
937
938
0
  return replaced;
939
0
}
940
941
static fr_pair_t *password_normalise_and_recheck(TALLOC_CTX *ctx, request_t *request,
942
              fr_dict_attr_t const *allowed_attrs[], size_t allowed_attrs_len,
943
              bool normify, fr_pair_t *const known_good)
944
0
{
945
0
  fr_pair_t *new;
946
0
  size_t    j;
947
948
0
  if (!fr_cond_assert(known_good->da->attr < NUM_ELEMENTS(password_info))) return NULL;
949
950
  /*
951
   *  Apply preprocessing steps and normalisation.
952
   */
953
0
  new = password_process(ctx, request, known_good, normify);
954
0
  if (!new) return NULL;
955
956
  /*
957
   *  If new != known_good, then we need
958
   *  to check what was produced is still
959
   *  acceptable.
960
   */
961
0
  if (new->da != known_good->da) {
962
0
    for (j = 0; j < allowed_attrs_len; j++) if (allowed_attrs[j] == new->da) return new;
963
964
    /*
965
     *  New attribute not in our allowed list
966
     */
967
0
    TALLOC_FREE(new);    /* da didn't match, treat as ephemeral */
968
0
    return NULL;     /* Process next input attribute */
969
0
  }
970
971
  /*
972
   *  Return attribute for processing
973
   */
974
0
  return new;
975
0
}
976
977
/** Find a "known good" password in the control list of a request
978
 *
979
 * Searches for a "known good" password attribute, and applies any processing
980
 * and normification operations to it, returning a new normalised fr_pair_t.
981
 *
982
 * The ctx passed in should be freed when the caller is done with the returned
983
 * fr_pair_t, or alternatively, a persistent ctx may be used and the value
984
 * of ephemeral checked.
985
 * If ephemeral is false the returned pair *MUST NOT BE FREED*, it may be an
986
 * attribute in the request->control_pairs list.  If ephemeral is true, the returned
987
 * pair *MUST* be freed, or added to one of the pair lists appropriate to the
988
 * ctx passed in.
989
 *
990
 * @param[out] ephemeral  If true, the caller must use TALLOC_FREE
991
 *        to free the return value of this function.
992
 *        Alternatively 'ctx' can be freed, which is
993
 *        simpler and cleaner, but some people have
994
 *        religious objections to that.
995
 * @param[in] ctx   Ephemeral ctx to allocate new attributes in.
996
 * @param[in] request   The current request.
997
 * @param[in] allowed_attrs Optional list of allowed attributes.
998
 * @param[in] allowed_attrs_len Length of allowed attributes list.
999
 * @param[in] normify   Apply hex/base64 normalisation to attributes.
1000
 * @return
1001
 *  - A fr_pair_t containing a "known good" password.
1002
 *  - NULL on error, or if no usable password attributes were found.
1003
 */
1004
fr_pair_t *password_find(bool *ephemeral, TALLOC_CTX *ctx, request_t *request,
1005
        fr_dict_attr_t const *allowed_attrs[], size_t allowed_attrs_len, bool normify)
1006
0
{
1007
0
  fr_dcursor_t  cursor;
1008
0
  fr_pair_t *known_good;
1009
1010
0
  if (fr_pair_find_by_da(&request->control_pairs, NULL, attr_user) != NULL) {
1011
0
    RWDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
1012
0
    RWDEBUG("!!! Ignoring control.User-Password.  Update your        !!!");
1013
0
    RWDEBUG("!!! configuration so that the \"known good\" clear text   !!!");
1014
0
    RWDEBUG("!!! password is in Password.Cleartext and NOT in        !!!");
1015
0
    RWDEBUG("!!! User-Password.                                      !!!");
1016
0
    RWDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
1017
0
  }
1018
1019
0
  for (known_good = fr_pair_dcursor_by_ancestor_init(&cursor, &request->control_pairs, attr_root);
1020
0
       known_good;
1021
0
       known_good = fr_dcursor_next(&cursor)) {
1022
0
    password_info_t   *info;
1023
0
    fr_pair_t   *out;
1024
0
    size_t      i;
1025
1026
0
    if (known_good->da->attr >= NUM_ELEMENTS(password_info)) continue;
1027
1028
0
    info = &password_info[known_good->da->attr];
1029
1030
    /*
1031
     *  Minor reduction in work for the caller
1032
     *  for a moderate increase in code complexity.
1033
     */
1034
0
    if (info->always_allow) {
1035
0
      out = password_normalise_and_recheck(ctx, request,
1036
0
                     allowed_attrs, allowed_attrs_len,
1037
0
                     normify, known_good);
1038
0
      if (!out) continue;
1039
0
    done:
1040
0
      if (RDEBUG_ENABLED3) {
1041
0
        RDEBUG3("Using \"known good\" %s password %pP",
1042
0
          fr_table_str_by_value(password_type_table,
1043
0
                    password_info[out->da->attr].type,
1044
0
                    "<INVALID>"), out);
1045
0
      } else {
1046
0
        RDEBUG2("Using \"known good\" %s password %s",
1047
0
          fr_table_str_by_value(password_type_table,
1048
0
                    password_info[out->da->attr].type,
1049
0
                    "<INVALID>"), out->da->name);
1050
0
      }
1051
0
      if (ephemeral) *ephemeral = (known_good != out);
1052
0
      return out;
1053
0
    }
1054
1055
0
    for (i = 0; i < allowed_attrs_len; i++) {
1056
0
      if (allowed_attrs[i] != known_good->da) continue;
1057
1058
0
      out = password_normalise_and_recheck(ctx, request,
1059
0
                     allowed_attrs, allowed_attrs_len,
1060
0
                     normify, known_good);
1061
0
      if (!out) continue;
1062
0
      goto done;
1063
0
    }
1064
0
  }
1065
1066
0
  return NULL;
1067
0
}
1068
1069
static int _password_init(UNUSED void *uctx)
1070
0
{
1071
0
  if (fr_dict_autoload(password_dict) < 0) {
1072
0
    PERROR("%s", __FUNCTION__);
1073
0
    return -1;
1074
0
  }
1075
0
  if (fr_dict_attr_autoload(password_dict_attr) < 0) {
1076
0
    PERROR("%s", __FUNCTION__);
1077
0
    fr_dict_autofree(password_dict);
1078
0
    return -1;
1079
0
  }
1080
1081
0
  return 0;
1082
0
}
1083
1084
static int _password_free(UNUSED void *uctx)
1085
0
{
1086
0
  fr_dict_autofree(password_dict);
1087
1088
0
  return 0;
1089
0
}
1090
1091
/** Load our dictionaries
1092
 *
1093
 */
1094
int password_init(void)
1095
0
{
1096
0
  int ret;
1097
1098
0
  fr_atexit_global_once_ret(&ret, _password_init, _password_free, NULL);
1099
1100
0
  return ret;
1101
0
}