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