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