The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_pap.c
Go to the documentation of this file.
1 /*
2  * This program is 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 (at
5  * 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  * $Id: 9e5430140560bc3cc79ac017842df36c05280dec $
19  * @file rlm_pap.c
20  * @brief Hashes plaintext passwords to compare against a prehashed reference.
21  *
22  * @copyright 2001-2012 The FreeRADIUS server project.
23  * @copyright 2012 Matthew Newton (matthew@newtoncomputing.co.uk)
24  * @copyright 2001 Kostas Kalevras (kkalev@noc.ntua.gr)
25  */
26 RCSID("$Id: 9e5430140560bc3cc79ac017842df36c05280dec $")
28 
29 #include <freeradius-devel/server/base.h>
30 #include <freeradius-devel/server/module_rlm.h>
31 #include <freeradius-devel/server/password.h>
32 #include <freeradius-devel/tls/base.h>
33 #include <freeradius-devel/tls/log.h>
34 
35 #include <freeradius-devel/util/base64.h>
36 #include <freeradius-devel/util/debug.h>
37 #include <freeradius-devel/util/base16.h>
38 #include <freeradius-devel/util/md5.h>
39 #include <freeradius-devel/util/sha1.h>
40 
41 #include <freeradius-devel/unlang/call_env.h>
42 
43 #include <freeradius-devel/protocol/freeradius/freeradius.internal.password.h>
44 
45 #include <ctype.h>
46 
47 #ifdef HAVE_CRYPT_H
48 # include <crypt.h>
49 #endif
50 #include <unistd.h> /* Contains crypt function declarations */
51 
52 #ifdef HAVE_OPENSSL_EVP_H
53 # include <freeradius-devel/tls/openssl_user_macros.h>
54 # include <openssl/evp.h>
55 #endif
56 
57 /*
58  * We don't have threadsafe crypt, so we have to wrap
59  * calls in a mutex
60  */
61 #ifndef HAVE_CRYPT_R
62 # include <pthread.h>
63 static pthread_mutex_t fr_crypt_mutex = PTHREAD_MUTEX_INITIALIZER;
64 #endif
65 
66 /*
67  * Define a structure for our module configuration.
68  *
69  * These variables do not need to be in a structure, but it's
70  * a lot cleaner to do so, and a pointer to the structure can
71  * be used as the instance handle.
72  */
73 typedef struct {
75  bool normify;
76 } rlm_pap_t;
77 
78 typedef unlang_action_t (*pap_auth_func_t)(rlm_rcode_t *p_result, rlm_pap_t const *inst, request_t *request, fr_pair_t const *, fr_value_box_t const *);
79 
80 static const conf_parser_t module_config[] = {
81  { FR_CONF_OFFSET("normalise", rlm_pap_t, normify), .dflt = "yes" },
83 };
84 
85 typedef struct {
89 
91  .inst_size = sizeof(pap_call_env_t),
92  .inst_type = "pap_call_env_t",
93  .env = (call_env_parser_t[]) {
94  { FR_CALL_ENV_PARSE_OFFSET("password_attribute", FR_TYPE_STRING,
96  pap_call_env_t, password, password_tmpl), .pair.dflt = "&User-Password", .pair.dflt_quote = T_BARE_WORD },
98  }
99 };
100 
102 
104  { .out = &dict_freeradius, .proto = "freeradius" },
105  { NULL }
106 };
107 
109 static fr_dict_attr_t const *attr_root;
110 
112  { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
113  { .out = &attr_root, .name = "Password", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
114 
115  { NULL }
116 };
117 
118 #ifdef HAVE_OPENSSL_EVP_H
119 static fr_table_num_sorted_t const pbkdf2_crypt_names[] = {
120  { L("HMACSHA1"), FR_SSHA1 },
121  { L("HMACSHA2+224"), FR_SSHA2_224 },
122  { L("HMACSHA2+256"), FR_SSHA2_256 },
123  { L("HMACSHA2+384"), FR_SSHA2_384 },
124  { L("HMACSHA2+512"), FR_SSHA2_512 },
125 # if OPENSSL_VERSION_NUMBER >= 0x10101000L
126  { L("HMACSHA3+224"), FR_SSHA3_224 },
127  { L("HMACSHA3+256"), FR_SSHA3_256 },
128  { L("HMACSHA3+384"), FR_SSHA3_384 },
129  { L("HMACSHA3+512"), FR_SSHA3_512 },
130 # endif
131 };
132 static size_t pbkdf2_crypt_names_len = NUM_ELEMENTS(pbkdf2_crypt_names);
133 
134 static fr_table_num_sorted_t const pbkdf2_passlib_names[] = {
135  { L("sha1"), FR_SSHA1 },
136  { L("sha256"), FR_SSHA2_256 },
137  { L("sha512"), FR_SSHA2_512 }
138 };
139 static size_t pbkdf2_passlib_names_len = NUM_ELEMENTS(pbkdf2_passlib_names);
140 #endif
141 
143 
144 /*
145  * Authorize the user for PAP authentication.
146  *
147  * This isn't strictly necessary, but it does make the
148  * server simpler to configure.
149  */
150 static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
151 {
153  pap_call_env_t *env_data = talloc_get_type_abort(mctx->env_data, pap_call_env_t);
154 
155  if (fr_pair_find_by_da(&request->control_pairs, NULL, attr_auth_type) != NULL) {
156  RDEBUG3("Auth-Type is already set. Not setting 'Auth-Type := %s'", mctx->mi->name);
158  }
159 
160  if (env_data->password.type != FR_TYPE_STRING) {
161  RDEBUG2("No %s attribute in the request. Cannot do PAP", env_data->password_tmpl->name);
163  }
164 
165  if (!inst->auth_type) {
166  WARN("No 'authenticate %s {...}' section or 'Auth-Type = %s' set. Cannot setup PAP authentication.",
167  mctx->mi->name, mctx->mi->name);
169  }
170 
172 
174 }
175 
176 /*
177  * PAP authentication functions
178  */
179 
181  UNUSED rlm_pap_t const *inst, request_t *request,
182  fr_pair_t const *known_good, fr_value_box_t const *password)
183 {
184  if ((known_good->vp_length != password->vb_length) ||
185  (fr_digest_cmp(known_good->vp_octets, password->vb_octets, known_good->vp_length) != 0)) {
186  REDEBUG("Cleartext password does not match \"known good\" password");
187  REDEBUG3("Password : %pV", password);
188  REDEBUG3("Expected : %pV", &known_good->data);
190  }
192 }
193 
194 #ifdef HAVE_CRYPT
195 static unlang_action_t CC_HINT(nonnull) pap_auth_crypt(rlm_rcode_t *p_result,
196  UNUSED rlm_pap_t const *inst, request_t *request,
197  fr_pair_t const *known_good, fr_value_box_t const *password)
198 {
199  char *crypt_out;
200  int cmp = 0;
201 
202 #ifdef HAVE_CRYPT_R
203  struct crypt_data crypt_data = { .initialized = 0 };
204 
205  crypt_out = crypt_r(password->vb_strvalue, known_good->vp_strvalue, &crypt_data);
206  if (crypt_out) cmp = strcmp(known_good->vp_strvalue, crypt_out);
207 #else
208  /*
209  * Ensure we're thread-safe, as crypt() isn't.
210  */
211  pthread_mutex_lock(&fr_crypt_mutex);
212  crypt_out = crypt(password->vb_strvalue, known_good->vp_strvalue);
213 
214  /*
215  * Got something, check it within the lock. This is
216  * faster than copying it to a local buffer, and the
217  * time spent within the lock is critical.
218  */
219  if (crypt_out) cmp = strcmp(known_good->vp_strvalue, crypt_out);
220  pthread_mutex_unlock(&fr_crypt_mutex);
221 #endif
222 
223  /*
224  * Error.
225  */
226  if (!crypt_out || (cmp != 0)) {
227  REDEBUG("Crypt digest does not match \"known good\" digest");
229  }
230 
232 }
233 #endif
234 
236  UNUSED rlm_pap_t const *inst, request_t *request,
237  fr_pair_t const *known_good, fr_value_box_t const *password)
238 {
239  uint8_t digest[MD5_DIGEST_LENGTH];
240 
241  if (known_good->vp_length != MD5_DIGEST_LENGTH) {
242  REDEBUG("\"known-good\" MD5 password has incorrect length, expected 16 got %zu", known_good->vp_length);
244  }
245 
246  fr_md5_calc(digest, password->vb_octets, password->vb_length);
247 
248  if (fr_digest_cmp(digest, known_good->vp_octets, known_good->vp_length) != 0) {
249  REDEBUG("MD5 digest does not match \"known good\" digest");
250  REDEBUG3("Password : %pV", password);
251  REDEBUG3("Calculated : %pH", fr_box_octets(digest, MD5_DIGEST_LENGTH));
252  REDEBUG3("Expected : %pH", fr_box_octets(known_good->vp_octets, MD5_DIGEST_LENGTH));
254  }
255 
257 }
258 
259 
261  UNUSED rlm_pap_t const *inst, request_t *request,
262  fr_pair_t const *known_good, fr_value_box_t const *password)
263 {
264  fr_md5_ctx_t *md5_ctx;
265  uint8_t digest[MD5_DIGEST_LENGTH];
266 
267  if (known_good->vp_length <= MD5_DIGEST_LENGTH) {
268  REDEBUG("\"known-good\" Password.SMD5 has incorrect length, expected 16 got %zu", known_good->vp_length);
270  }
271 
272  md5_ctx = fr_md5_ctx_alloc_from_list();
273  fr_md5_update(md5_ctx, password->vb_octets, password->vb_length);
274  fr_md5_update(md5_ctx, known_good->vp_octets + MD5_DIGEST_LENGTH, known_good->vp_length - MD5_DIGEST_LENGTH);
275  fr_md5_final(digest, md5_ctx);
276  fr_md5_ctx_free_from_list(&md5_ctx);
277 
278  /*
279  * Compare only the MD5 hash results, not the salt.
280  */
281  if (fr_digest_cmp(digest, known_good->vp_octets, MD5_DIGEST_LENGTH) != 0) {
282  REDEBUG("SMD5 digest does not match \"known good\" digest");
283  REDEBUG3("Password : %pV", password);
284  REDEBUG3("Calculated : %pH", fr_box_octets(digest, MD5_DIGEST_LENGTH));
285  REDEBUG3("Expected : %pH", fr_box_octets(known_good->vp_octets, MD5_DIGEST_LENGTH));
287  }
288 
290 }
291 
293  UNUSED rlm_pap_t const *inst, request_t *request,
294  fr_pair_t const *known_good, fr_value_box_t const *password)
295 {
296  fr_sha1_ctx sha1_context;
297  uint8_t digest[SHA1_DIGEST_LENGTH];
298 
299  if (known_good->vp_length != SHA1_DIGEST_LENGTH) {
300  REDEBUG("\"known-good\" Password.SHA1 has incorrect length, expected 20 got %zu", known_good->vp_length);
302  }
303 
304  fr_sha1_init(&sha1_context);
305  fr_sha1_update(&sha1_context, password->vb_octets, password->vb_length);
306  fr_sha1_final(digest,&sha1_context);
307 
308  if (fr_digest_cmp(digest, known_good->vp_octets, known_good->vp_length) != 0) {
309  REDEBUG("SHA1 digest does not match \"known good\" digest");
310  REDEBUG3("Password : %pV", password);
311  REDEBUG3("Calculated : %pH", fr_box_octets(digest, SHA1_DIGEST_LENGTH));
312  REDEBUG3("Expected : %pH", fr_box_octets(known_good->vp_octets, SHA1_DIGEST_LENGTH));
314  }
315 
317 }
318 
320  UNUSED rlm_pap_t const *inst, request_t *request,
321  fr_pair_t const *known_good, fr_value_box_t const *password)
322 {
323  fr_sha1_ctx sha1_context;
324  uint8_t digest[SHA1_DIGEST_LENGTH];
325 
326  if (known_good->vp_length <= SHA1_DIGEST_LENGTH) {
327  REDEBUG("\"known-good\" Password.SSHA has incorrect length, expected > 20 got %zu", known_good->vp_length);
329  }
330 
331  fr_sha1_init(&sha1_context);
332  fr_sha1_update(&sha1_context, password->vb_octets, password->vb_length);
333 
334  fr_sha1_update(&sha1_context, known_good->vp_octets + SHA1_DIGEST_LENGTH, known_good->vp_length - SHA1_DIGEST_LENGTH);
335  fr_sha1_final(digest, &sha1_context);
336 
337  if (fr_digest_cmp(digest, known_good->vp_octets, SHA1_DIGEST_LENGTH) != 0) {
338  REDEBUG("SSHA digest does not match \"known good\" digest");
339  REDEBUG3("Password : %pV", password);
340  REDEBUG3("Salt : %pH", fr_box_octets(known_good->vp_octets + SHA1_DIGEST_LENGTH,
341  known_good->vp_length - SHA1_DIGEST_LENGTH));
342  REDEBUG3("Calculated : %pH", fr_box_octets(digest, SHA1_DIGEST_LENGTH));
343  REDEBUG3("Expected : %pH", fr_box_octets(known_good->vp_octets, SHA1_DIGEST_LENGTH));
345  }
346 
348 }
349 
350 #ifdef HAVE_OPENSSL_EVP_H
351 static unlang_action_t CC_HINT(nonnull) pap_auth_evp_md(rlm_rcode_t *p_result,
352  UNUSED rlm_pap_t const *inst, request_t *request,
353  fr_pair_t const *known_good, fr_value_box_t const *password,
354  char const *name, EVP_MD const *md)
355 {
356  EVP_MD_CTX *ctx;
357  uint8_t digest[EVP_MAX_MD_SIZE];
358  unsigned int digest_len;
359 
360  ctx = EVP_MD_CTX_create();
361  EVP_DigestInit_ex(ctx, md, NULL);
362  EVP_DigestUpdate(ctx, password->vb_octets, password->vb_length);
363  EVP_DigestFinal_ex(ctx, digest, &digest_len);
364  EVP_MD_CTX_destroy(ctx);
365 
366  fr_assert((size_t) digest_len == known_good->vp_length); /* This would be an OpenSSL bug... */
367 
368  if (fr_digest_cmp(digest, known_good->vp_octets, known_good->vp_length) != 0) {
369  REDEBUG("%s digest does not match \"known good\" digest", name);
370  REDEBUG3("Password : %pV", password);
371  REDEBUG3("Calculated : %pH", fr_box_octets(digest, digest_len));
372  REDEBUG3("Expected : %pH", &known_good->data);
374  }
375 
377 }
378 
379 static unlang_action_t CC_HINT(nonnull) pap_auth_evp_md_salted(rlm_rcode_t *p_result,
380  UNUSED rlm_pap_t const *inst, request_t *request,
381  fr_pair_t const *known_good, fr_value_box_t const *password,
382  char const *name, EVP_MD const *md)
383 {
384  EVP_MD_CTX *ctx;
385  uint8_t digest[EVP_MAX_MD_SIZE];
386  unsigned int digest_len, min_len;
387 
388  min_len = EVP_MD_size(md);
389  ctx = EVP_MD_CTX_create();
390  EVP_DigestInit_ex(ctx, md, NULL);
391  EVP_DigestUpdate(ctx, password->vb_octets, password->vb_length);
392  EVP_DigestUpdate(ctx, known_good->vp_octets + min_len, known_good->vp_length - min_len);
393  EVP_DigestFinal_ex(ctx, digest, &digest_len);
394  EVP_MD_CTX_destroy(ctx);
395 
396  fr_assert((size_t) digest_len == min_len); /* This would be an OpenSSL bug... */
397 
398  /*
399  * Only compare digest_len bytes, the rest is salt.
400  */
401  if (fr_digest_cmp(digest, known_good->vp_octets, (size_t)digest_len) != 0) {
402  REDEBUG("%s digest does not match \"known good\" digest", name);
403  REDEBUG3("Password : %pV", password);
404  REDEBUG3("Salt : %pH",
405  fr_box_octets(known_good->vp_octets + digest_len, known_good->vp_length - digest_len));
406  REDEBUG3("Calculated : %pH", fr_box_octets(digest, digest_len));
407  REDEBUG3("Expected : %pH", fr_box_octets(known_good->vp_octets, digest_len));
409  }
410 
412 }
413 
414 /** Define a new OpenSSL EVP based password hashing function
415  *
416  */
417 #define PAP_AUTH_EVP_MD(_func, _new_func, _name, _md) \
418 static unlang_action_t CC_HINT(nonnull) _new_func(rlm_rcode_t *p_result, \
419  rlm_pap_t const *inst, request_t *request, \
420  fr_pair_t const *known_good, fr_value_box_t const *password) \
421 { \
422  return _func(p_result, inst, request, known_good, password, _name, _md); \
423 }
424 
425 PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha2_224, "SHA2-224", EVP_sha224())
426 PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha2_256, "SHA2-256", EVP_sha256())
427 PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha2_384, "SHA2-384", EVP_sha384())
428 PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha2_512, "SHA2-512", EVP_sha512())
429 PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha2_224, "SSHA2-224", EVP_sha224())
430 PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha2_256, "SSHA2-256", EVP_sha256())
431 PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha2_384, "SSHA2-384", EVP_sha384())
432 PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha2_512, "SSHA2-512", EVP_sha512())
433 
434 # if OPENSSL_VERSION_NUMBER >= 0x10101000L
435 PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha3_224, "SHA3-224", EVP_sha3_224())
436 PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha3_256, "SHA3-256", EVP_sha3_256())
437 PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha3_384, "SHA3-384", EVP_sha3_384())
438 PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha3_512, "SHA3-512", EVP_sha3_512())
439 PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha3_224, "SSHA3-224", EVP_sha3_224())
440 PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha3_256, "SSHA3-256", EVP_sha3_256())
441 PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha3_384, "SSHA3-384", EVP_sha3_384())
442 PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha3_512, "SSHA3-512", EVP_sha3_512())
443 # endif
444 
445 /** Validates Crypt::PBKDF2 LDAP format strings
446  *
447  * @param[out] p_result The result of comparing the pbkdf2 hash with the password.
448  * @param[in] request The current request.
449  * @param[in] str Raw PBKDF2 string.
450  * @param[in] len Length of string.
451  * @param[in] hash_names Table containing valid hash names.
452  * @param[in] hash_names_len How long the table is.
453  * @param[in] scheme_sep Separation character between the scheme and the next component.
454  * @param[in] iter_sep Separation character between the iterations and the next component.
455  * @param[in] salt_sep Separation character between the salt and the next component.
456  * @param[in] iter_is_base64 Whether the iterations is are encoded as base64.
457  * @param[in] password to validate.
458  * @return
459  * - RLM_MODULE_REJECT
460  * - RLM_MODULE_OK
461  */
462 static inline CC_HINT(nonnull) unlang_action_t pap_auth_pbkdf2_parse(rlm_rcode_t *p_result,
463  request_t *request, const uint8_t *str, size_t len,
464  fr_table_num_sorted_t const hash_names[], size_t hash_names_len,
465  char scheme_sep, char iter_sep, char salt_sep,
466  bool iter_is_base64, fr_value_box_t const *password)
467 {
469 
470  uint8_t const *p, *q, *end;
471  ssize_t slen;
472 
473  EVP_MD const *evp_md;
474  int digest_type;
475  size_t digest_len;
476 
477  uint32_t iterations = 1;
478 
479  uint8_t *salt = NULL;
480  size_t salt_len;
481  uint8_t hash[EVP_MAX_MD_SIZE];
482  uint8_t digest[EVP_MAX_MD_SIZE];
483 
484  RDEBUG2("Comparing with \"known-good\" Password.PBKDF2");
485 
486  if (len <= 1) {
487  REDEBUG("Password.PBKDF2 is too short");
488  goto finish;
489  }
490 
491  /*
492  * Parse PBKDF string = {hash_algorithm}<scheme_sep><iterations><iter_sep>b64(<salt>)<salt_sep>b64(<hash>)
493  */
494  p = str;
495  end = p + len;
496 
497  q = memchr(p, scheme_sep, end - p);
498  if (!q) {
499  REDEBUG("Password.PBKDF2 has no component separators");
500  goto finish;
501  }
502 
503  digest_type = fr_table_value_by_substr(hash_names, (char const *)p, q - p, -1);
504  switch (digest_type) {
505  case FR_SSHA1:
506  evp_md = EVP_sha1();
507  digest_len = SHA1_DIGEST_LENGTH;
508  break;
509 
510  case FR_SSHA2_224:
511  evp_md = EVP_sha224();
512  digest_len = SHA224_DIGEST_LENGTH;
513  break;
514 
515  case FR_SSHA2_256:
516  evp_md = EVP_sha256();
517  digest_len = SHA256_DIGEST_LENGTH;
518  break;
519 
520  case FR_SSHA2_384:
521  evp_md = EVP_sha384();
522  digest_len = SHA384_DIGEST_LENGTH;
523  break;
524 
525  case FR_SSHA2_512:
526  evp_md = EVP_sha512();
527  digest_len = SHA512_DIGEST_LENGTH;
528  break;
529 
530 # if OPENSSL_VERSION_NUMBER >= 0x10101000L
531  case FR_SSHA3_224:
532  evp_md = EVP_sha3_224();
533  digest_len = SHA224_DIGEST_LENGTH;
534  break;
535 
536  case FR_SSHA3_256:
537  evp_md = EVP_sha3_256();
538  digest_len = SHA256_DIGEST_LENGTH;
539  break;
540 
541  case FR_SSHA3_384:
542  evp_md = EVP_sha3_384();
543  digest_len = SHA384_DIGEST_LENGTH;
544  break;
545 
546  case FR_SSHA3_512:
547  evp_md = EVP_sha3_512();
548  digest_len = SHA512_DIGEST_LENGTH;
549  break;
550 # endif
551 
552  default:
553  REDEBUG("Unknown PBKDF2 hash method \"%.*s\"", (int)(q - p), p);
554  goto finish;
555  }
556 
557  p = q + 1;
558 
559  if (((end - p) < 1) || !(q = memchr(p, iter_sep, end - p))) {
560  REDEBUG("Password.PBKDF2 missing iterations component");
561  goto finish;
562  }
563 
564  if ((q - p) == 0) {
565  REDEBUG("Password.PBKDF2 iterations component too short");
566  goto finish;
567  }
568 
569  /*
570  * If it's not base64 encoded, assume it's ascii
571  */
572  if (!iter_is_base64) {
573  char iterations_buff[sizeof("4294967295") + 1];
574  char *qq;
575 
576  /*
577  * While passwords come from "trusted" sources, we don't trust them too much!
578  */
579  if ((size_t) (q - p) >= sizeof(iterations_buff)) {
580  REMARKER((char const *) p, q - p,
581  "Password.PBKDF2 iterations field is too large");
582 
583  goto finish;
584  }
585 
586  strlcpy(iterations_buff, (char const *)p, (q - p) + 1);
587 
588  iterations = strtoul(iterations_buff, &qq, 10);
589  if (*qq != '\0') {
590  REMARKER(iterations_buff, qq - iterations_buff,
591  "Password.PBKDF2 iterations field contains an invalid character");
592 
593  goto finish;
594  }
595  p = q + 1;
596  /*
597  * base64 encoded and big endian
598  */
599  } else {
601  slen = fr_base64_decode(&FR_DBUFF_TMP((uint8_t *)&iterations, sizeof(iterations)),
602  &FR_SBUFF_IN((char const *)p, (char const *)q), false, false);
603  if (slen <= 0) {
604  RPEDEBUG("Failed decoding Password.PBKDF2 iterations component (%.*s)", (int)(q - p), p);
605  goto finish;
606  }
607  if (slen != sizeof(iterations)) {
608  REDEBUG("Decoded Password.PBKDF2 iterations component is wrong size");
609  }
610 
611  iterations = ntohl(iterations);
612 
613  p = q + 1;
614  }
615 
616  /*
617  * 0 iterations is invalid (we need at least one)
618  */
619  if (iterations == 0) iterations = 1;
620 
621  if (((end - p) < 1) || !(q = memchr(p, salt_sep, end - p))) {
622  REDEBUG("Password.PBKDF2 missing salt component");
623  goto finish;
624  }
625 
626  if ((q - p) == 0) {
627  REDEBUG("Password.PBKDF2 salt component too short");
628  goto finish;
629  }
630 
631  MEM(salt = talloc_array(request, uint8_t, FR_BASE64_DEC_LENGTH(q - p)));
632  slen = fr_base64_decode(&FR_DBUFF_TMP(salt, talloc_array_length(salt)),
633  &FR_SBUFF_IN((char const *) p, (char const *)q), false, false);
634  if (slen <= 0) {
635  RPEDEBUG("Failed decoding Password.PBKDF2 salt component");
636  goto finish;
637  }
638  salt_len = (size_t)slen;
639 
640  p = q + 1;
641 
642  if ((q - p) == 0) {
643  REDEBUG("Password.PBKDF2 hash component too short");
644  goto finish;
645  }
646 
647  slen = fr_base64_decode(&FR_DBUFF_TMP(hash, sizeof(hash)),
648  &FR_SBUFF_IN((char const *)p, (char const *)end), false, false);
649  if (slen <= 0) {
650  RPEDEBUG("Failed decoding Password.PBKDF2 hash component");
651  goto finish;
652  }
653 
654  if ((size_t)slen != digest_len) {
655  REDEBUG("Password.PBKDF2 hash component length is incorrect for hash type, expected %zu, got %zd",
656  digest_len, slen);
657 
658  RHEXDUMP2(hash, slen, "hash component");
659 
660  goto finish;
661  }
662 
663  RDEBUG2("PBKDF2 %s: Iterations %u, salt length %zu, hash length %zd",
664  fr_table_str_by_value(pbkdf2_crypt_names, digest_type, "<UNKNOWN>"),
665  iterations, salt_len, slen);
666 
667  /*
668  * Hash and compare
669  */
670  if (PKCS5_PBKDF2_HMAC((char const *)password->vb_octets, (int)password->vb_length,
671  (unsigned char const *)salt, (int)salt_len,
672  (int)iterations,
673  evp_md,
674  (int)digest_len, (unsigned char *)digest) == 0) {
675  fr_tls_log(request, "PBKDF2 digest failure");
676  goto finish;
677  }
678 
679  if (fr_digest_cmp(digest, hash, (size_t)digest_len) != 0) {
680  REDEBUG("PBKDF2 digest does not match \"known good\" digest");
681  REDEBUG3("Salt : %pH", fr_box_octets(salt, salt_len));
682  REDEBUG3("Calculated : %pH", fr_box_octets(digest, digest_len));
683  REDEBUG3("Expected : %pH", fr_box_octets(hash, slen));
684  rcode = RLM_MODULE_REJECT;
685  } else {
686  rcode = RLM_MODULE_OK;
687  }
688 
689 finish:
690  talloc_free(salt);
691 
692  RETURN_MODULE_RCODE(rcode);
693 }
694 
695 static inline unlang_action_t CC_HINT(nonnull) pap_auth_pbkdf2(rlm_rcode_t *p_result,
696  UNUSED rlm_pap_t const *inst,
697  request_t *request,
698  fr_pair_t const *known_good, fr_value_box_t const *password)
699 {
700  uint8_t const *p = known_good->vp_octets, *q, *end = p + known_good->vp_length;
701 
702  if (end - p < 2) {
703  REDEBUG("Password.PBKDF2 too short");
705  }
706 
707  /*
708  * If it doesn't begin with a $ assume
709  * It's Crypt::PBKDF2 LDAP format
710  *
711  * {X-PBKDF2}<digest>:<b64 rounds>:<b64_salt>:<b64_hash>
712  */
713  if (*p != '$') {
714  /*
715  * Strip the header if it's present
716  */
717  if (*p == '{') {
718  q = memchr(p, '}', end - p);
719  p = q + 1;
720  }
721  return pap_auth_pbkdf2_parse(p_result, request, p, end - p,
722  pbkdf2_crypt_names, pbkdf2_crypt_names_len,
723  ':', ':', ':', true, password);
724  }
725 
726  /*
727  * Crypt::PBKDF2 Crypt format
728  *
729  * $PBKDF2$<digest>:<rounds>:<b64_salt>$<b64_hash>
730  */
731  if ((size_t)(end - p) >= sizeof("$PBKDF2$") && (memcmp(p, "$PBKDF2$", sizeof("$PBKDF2$") - 1) == 0)) {
732  p += sizeof("$PBKDF2$") - 1;
733  return pap_auth_pbkdf2_parse(p_result, request, p, end - p,
734  pbkdf2_crypt_names, pbkdf2_crypt_names_len,
735  ':', ':', '$', false, password);
736  }
737 
738  /*
739  * Python's passlib format
740  *
741  * $pbkdf2-<digest>$<rounds>$<alt_b64_salt>$<alt_b64_hash>
742  *
743  * Note: Our base64 functions also work with alt_b64
744  */
745  if ((size_t)(end - p) >= sizeof("$pbkdf2-") && (memcmp(p, "$pbkdf2-", sizeof("$pbkdf2-") - 1) == 0)) {
746  p += sizeof("$pbkdf2-") - 1;
747  return pap_auth_pbkdf2_parse(p_result, request, p, end - p,
748  pbkdf2_passlib_names, pbkdf2_passlib_names_len,
749  '$', '$', '$', false, password);
750  }
751 
752  REDEBUG("Can't determine format of Password.PBKDF2");
753 
755 }
756 #endif
757 
758 static unlang_action_t CC_HINT(nonnull) pap_auth_nt(rlm_rcode_t *p_result,
759  UNUSED rlm_pap_t const *inst, request_t *request,
760  fr_pair_t const *known_good, fr_value_box_t const *password)
761 {
762  ssize_t len;
763  uint8_t digest[MD4_DIGEST_LENGTH];
764  uint8_t ucs2[512];
765 
766  RDEBUG2("Comparing with \"known-good\" Password.NT");
767 
768  if (known_good->vp_length != MD4_DIGEST_LENGTH) {
769  REDEBUG("\"known good\" Password.NT has incorrect length, expected 16 got %zu", known_good->vp_length);
771  }
772 
773  len = fr_utf8_to_ucs2(ucs2, sizeof(ucs2),
774  password->vb_strvalue, password->vb_length);
775  if (len < 0) {
776  REDEBUG("User-Password is not in UCS2 format");
778  }
779 
780  fr_md4_calc(digest, (uint8_t *)ucs2, len);
781 
782  if (fr_digest_cmp(digest, known_good->vp_octets, known_good->vp_length) != 0) {
783  REDEBUG("NT digest does not match \"known good\" digest");
784  REDEBUG3("Calculated : %pH", fr_box_octets(digest, sizeof(digest)));
785  REDEBUG3("Expected : %pH", &known_good->data);
787  }
788 
790 }
791 
793  UNUSED rlm_pap_t const *inst, request_t *request,
794  fr_pair_t const *known_good, fr_value_box_t const *password)
795 {
796  uint8_t digest[128];
798  uint8_t buff2[FR_MAX_STRING_LEN + 50];
799  fr_dbuff_t digest_dbuff = FR_DBUFF_TMP(digest, sizeof(digest));
800 
801  RDEBUG2("Using Password.NT-MTA-MD5");
802 
803  if (known_good->vp_length != 64) {
804  REDEBUG("\"known good\" Password.NS-MTA-MD5 has incorrect length, expected 64 got %zu",
805  known_good->vp_length);
807  }
808 
809  /*
810  * Sanity check the value of Password.NS-MTA-MD5
811  */
812  if (fr_base16_decode(NULL, &digest_dbuff,
813  &FR_SBUFF_IN(known_good->vp_strvalue, known_good->vp_length), false) != 16) {
814  REDEBUG("\"known good\" Password.NS-MTA-MD5 has invalid value");
816  }
817 
818  /*
819  * Ensure we don't have buffer overflows.
820  *
821  * This really: sizeof(buff) - 2 - 2*32 - strlen(passwd)
822  */
823  if (password->vb_length >= (sizeof(buff) - 2 - 2 * 32)) {
824  REDEBUG("\"known good\" Password.NS-MTA-MD5 is too long");
826  }
827 
828  /*
829  * Set up the algorithm.
830  */
831  {
832  uint8_t *p = buff2;
833 
834  memcpy(p, &known_good->vp_octets[32], 32);
835  p += 32;
836  *(p++) = 89;
837  memcpy(p, password->vb_strvalue, password->vb_length);
838  p += password->vb_length;
839  *(p++) = 247;
840  memcpy(p, &known_good->vp_octets[32], 32);
841  p += 32;
842 
843  fr_md5_calc(buff, (uint8_t *) buff2, p - buff2);
844  }
845 
846  if (fr_digest_cmp(fr_dbuff_start(&digest_dbuff), buff, 16) != 0) {
847  REDEBUG("NS-MTA-MD5 digest does not match \"known good\" digest");
849  }
850 
852 }
853 
854 /** Auth func for password types that should have been normalised away
855  *
856  */
858  UNUSED rlm_pap_t const *inst, UNUSED request_t *request,
859  UNUSED fr_pair_t const *known_good, UNUSED fr_value_box_t const *password)
860 {
862 }
863 
864 /** Table of password types we can process
865  *
866  */
868  [FR_CLEARTEXT] = pap_auth_clear,
869  [FR_MD5] = pap_auth_md5,
870  [FR_SMD5] = pap_auth_smd5,
871 
872 #ifdef HAVE_CRYPT
873  [FR_CRYPT] = pap_auth_crypt,
874 #endif
875  [FR_NS_MTA_MD5] = pap_auth_ns_mta_md5,
876  [FR_NT] = pap_auth_nt,
877  [FR_WITH_HEADER] = pap_auth_dummy,
878  [FR_SHA1] = pap_auth_sha1,
879  [FR_SSHA1] = pap_auth_ssha1,
880 
881 #ifdef HAVE_OPENSSL_EVP_H
882  [FR_PBKDF2] = pap_auth_pbkdf2,
883  [FR_SHA2] = pap_auth_dummy,
884  [FR_SHA2_224] = pap_auth_sha2_224,
885  [FR_SHA2_256] = pap_auth_sha2_256,
886  [FR_SHA2_384] = pap_auth_sha2_384,
887  [FR_SHA2_512] = pap_auth_sha2_512,
888  [FR_SSHA2_224] = pap_auth_ssha2_224,
889  [FR_SSHA2_256] = pap_auth_ssha2_256,
890  [FR_SSHA2_384] = pap_auth_ssha2_384,
891  [FR_SSHA2_512] = pap_auth_ssha2_512,
892 
893 # if OPENSSL_VERSION_NUMBER >= 0x10101000L
894  [FR_SHA3] = pap_auth_dummy,
895  [FR_SHA3_224] = pap_auth_sha3_224,
896  [FR_SHA3_256] = pap_auth_sha3_256,
897  [FR_SHA3_384] = pap_auth_sha3_384,
898  [FR_SHA3_512] = pap_auth_sha3_512,
899  [FR_SSHA3_224] = pap_auth_ssha3_224,
900  [FR_SSHA3_256] = pap_auth_ssha3_256,
901  [FR_SSHA3_384] = pap_auth_ssha3_384,
902  [FR_SSHA3_512] = pap_auth_ssha3_512,
903 # endif
904 #endif /* HAVE_OPENSSL_EVP_H */
905 };
906 
907 /*
908  * Authenticate the user via one of any well-known password.
909  */
910 static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
911 {
913  fr_pair_t *known_good;
915  pap_auth_func_t auth_func;
916  bool ephemeral;
917  pap_call_env_t *env_data = talloc_get_type_abort(mctx->env_data, pap_call_env_t);
918 
919  if (env_data->password.type != FR_TYPE_STRING) {
920  REDEBUG("You set 'Auth-Type = PAP' for a request that does not contain a %s attribute!",
921  env_data->password_tmpl->name);
923  }
924 
925  /*
926  * The user MUST supply a non-zero-length password.
927  */
928  if (env_data->password.vb_length == 0) {
929  REDEBUG("Password must not be empty");
931  }
932 
933  if (RDEBUG_ENABLED3) {
934  RDEBUG3("Login attempt with %s = %pV (%zd)", env_data->password_tmpl->name,
935  &env_data->password, env_data->password.vb_length);
936  } else {
937  RDEBUG2("Login attempt with password");
938  }
939 
940  /*
941  * Retrieve the normalised version of
942  * the known_good password, without
943  * mangling the current password attributes
944  * in the request.
945  */
946  known_good = password_find(&ephemeral, request, request,
947  pap_alloweds, talloc_array_length(pap_alloweds),
948  inst->normify);
949  if (!known_good) {
950  REDEBUG("No \"known good\" password found for user");
952  }
953 
954  fr_assert(known_good->da->attr < NUM_ELEMENTS(auth_func_table));
955 
956  auth_func = auth_func_table[known_good->da->attr];
957  fr_assert(auth_func);
958 
959  if (RDEBUG_ENABLED3) {
960  RDEBUG3("Comparing with \"known good\" %pP (%zu)", known_good, known_good->vp_length);
961  } else {
962  RDEBUG2("Comparing with \"known-good\" %s (%zu)", known_good->da->name, known_good->vp_length);
963  }
964 
965  /*
966  * Authenticate, and return.
967  */
968  auth_func(&rcode, inst, request, known_good, &env_data->password);
969  if (ephemeral) TALLOC_FREE(known_good);
970  switch (rcode) {
971  case RLM_MODULE_REJECT:
972  REDEBUG("Password incorrect");
973  break;
974 
975  case RLM_MODULE_OK:
976  RDEBUG2("User authenticated successfully");
977  break;
978 
979  default:
980  break;
981  }
982 
983  RETURN_MODULE_RCODE(rcode);
984 }
985 
986 static int mod_instantiate(module_inst_ctx_t const *mctx)
987 {
988  rlm_pap_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_pap_t);
989 
990  inst->auth_type = fr_dict_enum_by_name(attr_auth_type, mctx->mi->name, -1);
991  if (!inst->auth_type) {
992  WARN("Failed to find 'authenticate %s {...}' section. PAP will likely not work",
993  mctx->mi->name);
994  }
995 
996  return 0;
997 }
998 
999 static int mod_load(void)
1000 {
1001  size_t i, j = 0;
1002  size_t allowed = 0;
1003 
1004  /*
1005  * Load the dictionaries early
1006  */
1007  if (fr_dict_autoload(rlm_pap_dict) < 0) {
1008  PERROR("%s", __FUNCTION__);
1009  return -1;
1010  }
1012  PERROR("%s", __FUNCTION__);
1014  return -1;
1015  }
1016 
1017  /*
1018  * Figure out how many password types we allow
1019  */
1020  for (i = 0; i < NUM_ELEMENTS(auth_func_table); i++) {
1021  if (auth_func_table[i] == NULL) continue;
1022 
1023  allowed++;
1024  }
1025 
1026  /*
1027  * Get a list of the DAs that match are allowed
1028  * functions.
1029  */
1030  pap_alloweds = talloc_array(NULL, fr_dict_attr_t const *, allowed);
1031  for (i = 0; i < NUM_ELEMENTS(auth_func_table); i++) {
1032  fr_dict_attr_t const *password_da;
1033 
1034  if (auth_func_table[i] == NULL) continue;
1035 
1036  password_da = fr_dict_attr_child_by_num(attr_root, i);
1037  if (!fr_cond_assert(password_da)) {
1038  ERROR("Could not resolve password attribute %zu", i);
1041  return -1;
1042  }
1043 
1044  pap_alloweds[j++] = password_da;
1045  }
1046 
1047  return 0;
1048 }
1049 
1050 static void mod_unload(void)
1051 {
1054 }
1055 
1056 /*
1057  * The module name should be the only globally exported symbol.
1058  * That is, everything else should be 'static'.
1059  *
1060  * If the module needs to temporarily modify it's instantiation
1061  * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
1062  * The server will then take care of ensuring that the module
1063  * is single-threaded.
1064  */
1065 extern module_rlm_t rlm_pap;
1067  .common = {
1068  .magic = MODULE_MAGIC_INIT,
1069  .name = "pap",
1070  .inst_size = sizeof(rlm_pap_t),
1071  .onload = mod_load,
1072  .unload = mod_unload,
1073  .config = module_config,
1075  },
1076  .method_group = {
1077  .bindings = (module_method_binding_t[]){
1078  /*
1079  * Hack to support old configurations
1080  */
1081  { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &pap_method_env },
1082  { .section = SECTION_NAME("authorize", CF_IDENT_ANY), .method = mod_authorize, .method_env = &pap_method_env },
1083  { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_authorize, .method_env = &pap_method_env },
1084 
1086  }
1087  }
1088 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
#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 FR_BASE64_DEC_LENGTH(_inlen)
Definition: base64.h:44
#define USES_APPLE_DEPRECATED_API
Definition: build.h:433
#define RCSID(id)
Definition: build.h:446
#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 CALL_ENV_TERMINATOR
Definition: call_env.h:231
#define FR_CALL_ENV_PARSE_OFFSET(_name, _cast_type, _flags, _struct, _field, _parse_field)
Specify a call_env_parser_t which writes out runtime results and the result of the parsing phase to t...
Definition: call_env.h:360
size_t inst_size
Size of per call env.
Definition: call_env.h:240
@ CALL_ENV_FLAG_CONCAT
If the tmpl produced multiple boxes they should be concatenated.
Definition: call_env.h:76
@ CALL_ENV_FLAG_ATTRIBUTE
Tmpl must contain an attribute reference.
Definition: call_env.h:86
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
Definition: call_env.h:75
@ CALL_ENV_FLAG_NULLABLE
Tmpl expansions are allowed to produce no output.
Definition: call_env.h:80
Per method call config.
Definition: call_env.h:175
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
#define CF_IDENT_ANY
Definition: cf_util.h:78
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition: dbuff.h:893
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:509
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:139
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#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
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition: dict_util.c:2992
#define fr_dict_autoload(_to_load)
Definition: dict.h:671
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition: dict_util.c:2925
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
Value of an enumerated attribute.
Definition: dict.h:209
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
#define PERROR(_fmt,...)
Definition: log.h:228
#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 REDEBUG3(fmt,...)
Definition: log.h:373
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
Definition: log.h:498
#define RPEDEBUG(fmt,...)
Definition: log.h:376
#define RHEXDUMP2(_data, _len, _fmt,...)
Definition: log.h:704
talloc_free(reap)
void fr_md4_calc(uint8_t out[static MD4_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Calculate the MD4 hash of the contents of a buffer.
Definition: md4.c:489
#define MD4_DIGEST_LENGTH
Definition: md4.h:25
fr_md5_update_t fr_md5_update
Definition: md5.c:450
fr_md5_final_t fr_md5_final
Definition: md5.c:451
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
Definition: md5.c:530
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
Definition: md5.c:485
void fr_md5_ctx_t
Definition: md5.h:28
#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_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
void fr_md5_calc(uint8_t out[static MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Perform a single digest operation on a single input buffer.
Definition: merged_model.c:251
unsigned char uint8_t
Definition: merged_model.c:30
unsigned long int size_t
Definition: merged_model.c:25
ssize_t fr_utf8_to_ucs2(uint8_t *out, size_t outlen, char const *in, size_t inlen)
Convert UTF8 string to UCS2 encoding.
Definition: misc.c:306
int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
Do a comparison of two authentication digests by comparing the FULL data.
Definition: misc.c:463
void * env_data
Per call environment data.
Definition: module_ctx.h:44
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:42
module_instance_t * mi
Instance of the module being instantiated.
Definition: module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:50
bool module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv)
Set the next section type if it's not already set.
Definition: module_rlm.c:427
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:39
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
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:408
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:964
static const conf_parser_t config[]
Definition: base.c:188
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#define WARN(fmt,...)
Definition: radclient.h:47
#define RETURN_MODULE_REJECT
Definition: rcode.h:55
#define RETURN_MODULE_NOOP
Definition: rcode.h:62
#define RETURN_MODULE_RCODE(_rcode)
Definition: rcode.h:64
#define RETURN_MODULE_INVALID
Definition: rcode.h:59
#define RETURN_MODULE_OK
Definition: rcode.h:57
#define RETURN_MODULE_UPDATED
Definition: rcode.h:63
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition: rcode.h:45
@ RLM_MODULE_OK
The module is OK, continue.
Definition: rcode.h:43
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition: rcode.h:41
static const pap_auth_func_t auth_func_table[]
Table of password types we can process.
Definition: rlm_pap.c:867
static unlang_action_t pap_auth_dummy(rlm_rcode_t *p_result, UNUSED rlm_pap_t const *inst, UNUSED request_t *request, UNUSED fr_pair_t const *known_good, UNUSED fr_value_box_t const *password)
Auth func for password types that should have been normalised away.
Definition: rlm_pap.c:857
static int mod_load(void)
Definition: rlm_pap.c:999
static fr_dict_attr_autoload_t rlm_pap_dict_attr[]
Definition: rlm_pap.c:111
fr_dict_enum_value_t * auth_type
Definition: rlm_pap.c:74
static unlang_action_t pap_auth_md5(rlm_rcode_t *p_result, UNUSED rlm_pap_t const *inst, request_t *request, fr_pair_t const *known_good, fr_value_box_t const *password)
Definition: rlm_pap.c:235
static unlang_action_t pap_auth_clear(rlm_rcode_t *p_result, UNUSED rlm_pap_t const *inst, request_t *request, fr_pair_t const *known_good, fr_value_box_t const *password)
Definition: rlm_pap.c:180
static unlang_action_t pap_auth_smd5(rlm_rcode_t *p_result, UNUSED rlm_pap_t const *inst, request_t *request, fr_pair_t const *known_good, fr_value_box_t const *password)
Definition: rlm_pap.c:260
static fr_dict_t const * dict_freeradius
Definition: rlm_pap.c:101
module_rlm_t rlm_pap
Definition: rlm_pap.c:1066
fr_value_box_t password
Definition: rlm_pap.c:86
static const call_env_method_t pap_method_env
Definition: rlm_pap.c:90
static unlang_action_t pap_auth_nt(rlm_rcode_t *p_result, UNUSED rlm_pap_t const *inst, request_t *request, fr_pair_t const *known_good, fr_value_box_t const *password)
Definition: rlm_pap.c:758
static fr_dict_autoload_t rlm_pap_dict[]
Definition: rlm_pap.c:103
static unlang_action_t pap_auth_ns_mta_md5(rlm_rcode_t *p_result, UNUSED rlm_pap_t const *inst, request_t *request, fr_pair_t const *known_good, fr_value_box_t const *password)
Definition: rlm_pap.c:792
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_pap.c:910
static fr_dict_attr_t const * attr_auth_type
Definition: rlm_pap.c:108
static unlang_action_t pap_auth_sha1(rlm_rcode_t *p_result, UNUSED rlm_pap_t const *inst, request_t *request, fr_pair_t const *known_good, fr_value_box_t const *password)
Definition: rlm_pap.c:292
static void mod_unload(void)
Definition: rlm_pap.c:1050
static unlang_action_t pap_auth_ssha1(rlm_rcode_t *p_result, UNUSED rlm_pap_t const *inst, request_t *request, fr_pair_t const *known_good, fr_value_box_t const *password)
Definition: rlm_pap.c:319
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_pap.c:150
static fr_dict_attr_t const * attr_root
Definition: rlm_pap.c:109
static fr_dict_attr_t const ** pap_alloweds
Definition: rlm_pap.c:142
static USES_APPLE_DEPRECATED_API pthread_mutex_t fr_crypt_mutex
Definition: rlm_pap.c:63
static const conf_parser_t module_config[]
Definition: rlm_pap.c:80
bool normify
Definition: rlm_pap.c:75
unlang_action_t(* pap_auth_func_t)(rlm_rcode_t *p_result, rlm_pap_t const *inst, request_t *request, fr_pair_t const *, fr_value_box_t const *)
Definition: rlm_pap.c:78
tmpl_t * password_tmpl
Definition: rlm_pap.c:87
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_pap.c:986
static unsigned int hash(char const *username, unsigned int tablesize)
Definition: rlm_passwd.c:132
static char const * name
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1329
#define FR_SBUFF_IN(_start, _len_or_end)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition: section.h:40
char const * name
Instance name e.g. user_database.
Definition: module.h:335
void * data
Module's instance data.
Definition: module.h:271
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition: module.h:151
Named methods exported by a module.
Definition: module.h:173
void fr_sha1_init(fr_sha1_ctx *context)
Definition: sha1.c:93
void fr_sha1_final(uint8_t digest[static SHA1_DIGEST_LENGTH], fr_sha1_ctx *context)
Definition: sha1.c:141
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *in, size_t len)
Definition: sha1.c:105
#define SHA1_DIGEST_LENGTH
Definition: sha1.h:29
static char buff[sizeof("18446744073709551615")+3]
Definition: size_tests.c:41
RETURN_MODULE_FAIL
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:34
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 talloc_get_type_abort_const
Definition: talloc.h:271
@ T_BARE_WORD
Definition: token.h:120
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition: strerror.c:577
#define FR_MAX_STRING_LEN
Definition: value.h:30
int nonnull(2, 5))
#define fr_box_octets(_val, _len)
Definition: value.h:281