The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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: 50818f979867e98520f89503d6dc9a7290019d21 $
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 */
26RCSID("$Id: 50818f979867e98520f89503d6dc9a7290019d21 $")
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>
63static 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 */
77
78typedef 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
80static const conf_parser_t module_config[] = {
81 { FR_CONF_OFFSET("normalise", rlm_pap_t, normify), .dflt = "yes" },
83};
84
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
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
119static 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 { L("HMACSHA3+224"), FR_SSHA3_224 },
126 { L("HMACSHA3+256"), FR_SSHA3_256 },
127 { L("HMACSHA3+384"), FR_SSHA3_384 },
128 { L("HMACSHA3+512"), FR_SSHA3_512 },
129};
130static size_t pbkdf2_crypt_names_len = NUM_ELEMENTS(pbkdf2_crypt_names);
131
132static fr_table_num_sorted_t const pbkdf2_passlib_names[] = {
133 { L("sha1"), FR_SSHA1 },
134 { L("sha256"), FR_SSHA2_256 },
135 { L("sha512"), FR_SSHA2_512 }
136};
137static size_t pbkdf2_passlib_names_len = NUM_ELEMENTS(pbkdf2_passlib_names);
138#endif
139
141
142/*
143 * Authorize the user for PAP authentication.
144 *
145 * This isn't strictly necessary, but it does make the
146 * server simpler to configure.
147 */
148static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
149{
151 pap_call_env_t *env_data = talloc_get_type_abort(mctx->env_data, pap_call_env_t);
152
153 if (fr_pair_find_by_da(&request->control_pairs, NULL, attr_auth_type) != NULL) {
154 RDEBUG3("Auth-Type is already set. Not setting 'Auth-Type := %s'", mctx->mi->name);
156 }
157
158 if (env_data->password.type != FR_TYPE_STRING) {
159 RDEBUG2("No %s attribute in the request. Cannot do PAP", env_data->password_tmpl->name);
161 }
162
163 if (!inst->auth_type) {
164 WARN("No 'authenticate %s {...}' section or 'Auth-Type = %s' set. Cannot setup PAP authentication.",
165 mctx->mi->name, mctx->mi->name);
167 }
168
170
172}
173
174/*
175 * PAP authentication functions
176 */
177
179 UNUSED rlm_pap_t const *inst, request_t *request,
180 fr_pair_t const *known_good, fr_value_box_t const *password)
181{
182 if ((known_good->vp_length != password->vb_length) ||
183 (fr_digest_cmp(known_good->vp_octets, password->vb_octets, known_good->vp_length) != 0)) {
184 REDEBUG("Cleartext password does not match \"known good\" password");
185 REDEBUG3("Password : %pV", password);
186 REDEBUG3("Expected : %pV", &known_good->data);
188 }
190}
191
192#ifdef HAVE_CRYPT
193static unlang_action_t CC_HINT(nonnull) pap_auth_crypt(rlm_rcode_t *p_result,
194 UNUSED rlm_pap_t const *inst, request_t *request,
195 fr_pair_t const *known_good, fr_value_box_t const *password)
196{
197 char *crypt_out;
198 int cmp = 0;
199
200#ifdef HAVE_CRYPT_R
201 struct crypt_data crypt_data = { .initialized = 0 };
202
203 crypt_out = crypt_r(password->vb_strvalue, known_good->vp_strvalue, &crypt_data);
204 if (crypt_out) cmp = strcmp(known_good->vp_strvalue, crypt_out);
205#else
206 /*
207 * Ensure we're thread-safe, as crypt() isn't.
208 */
209 pthread_mutex_lock(&fr_crypt_mutex);
210 crypt_out = crypt(password->vb_strvalue, known_good->vp_strvalue);
211
212 /*
213 * Got something, check it within the lock. This is
214 * faster than copying it to a local buffer, and the
215 * time spent within the lock is critical.
216 */
217 if (crypt_out) cmp = strcmp(known_good->vp_strvalue, crypt_out);
218 pthread_mutex_unlock(&fr_crypt_mutex);
219#endif
220
221 /*
222 * Error.
223 */
224 if (!crypt_out || (cmp != 0)) {
225 REDEBUG("Crypt digest does not match \"known good\" digest");
227 }
228
230}
231#endif
232
234 UNUSED rlm_pap_t const *inst, request_t *request,
235 fr_pair_t const *known_good, fr_value_box_t const *password)
236{
238
239 if (known_good->vp_length != MD5_DIGEST_LENGTH) {
240 REDEBUG("\"known-good\" MD5 password has incorrect length, expected 16 got %zu", known_good->vp_length);
242 }
243
244 fr_md5_calc(digest, password->vb_octets, password->vb_length);
245
246 if (fr_digest_cmp(digest, known_good->vp_octets, known_good->vp_length) != 0) {
247 REDEBUG("MD5 digest does not match \"known good\" digest");
248 REDEBUG3("Password : %pV", password);
249 REDEBUG3("Calculated : %pH", fr_box_octets(digest, MD5_DIGEST_LENGTH));
250 REDEBUG3("Expected : %pH", fr_box_octets(known_good->vp_octets, MD5_DIGEST_LENGTH));
252 }
253
255}
256
257
259 UNUSED rlm_pap_t const *inst, request_t *request,
260 fr_pair_t const *known_good, fr_value_box_t const *password)
261{
262 fr_md5_ctx_t *md5_ctx;
264
265 if (known_good->vp_length <= MD5_DIGEST_LENGTH) {
266 REDEBUG("\"known-good\" Password.SMD5 has incorrect length, expected 16 got %zu", known_good->vp_length);
268 }
269
270 md5_ctx = fr_md5_ctx_alloc_from_list();
271 fr_md5_update(md5_ctx, password->vb_octets, password->vb_length);
272 fr_md5_update(md5_ctx, known_good->vp_octets + MD5_DIGEST_LENGTH, known_good->vp_length - MD5_DIGEST_LENGTH);
273 fr_md5_final(digest, md5_ctx);
275
276 /*
277 * Compare only the MD5 hash results, not the salt.
278 */
279 if (fr_digest_cmp(digest, known_good->vp_octets, MD5_DIGEST_LENGTH) != 0) {
280 REDEBUG("SMD5 digest does not match \"known good\" digest");
281 REDEBUG3("Password : %pV", password);
282 REDEBUG3("Calculated : %pH", fr_box_octets(digest, MD5_DIGEST_LENGTH));
283 REDEBUG3("Expected : %pH", fr_box_octets(known_good->vp_octets, MD5_DIGEST_LENGTH));
285 }
286
288}
289
291 UNUSED rlm_pap_t const *inst, request_t *request,
292 fr_pair_t const *known_good, fr_value_box_t const *password)
293{
294 fr_sha1_ctx sha1_context;
296
297 if (known_good->vp_length != SHA1_DIGEST_LENGTH) {
298 REDEBUG("\"known-good\" Password.SHA1 has incorrect length, expected 20 got %zu", known_good->vp_length);
300 }
301
302 fr_sha1_init(&sha1_context);
303 fr_sha1_update(&sha1_context, password->vb_octets, password->vb_length);
304 fr_sha1_final(digest,&sha1_context);
305
306 if (fr_digest_cmp(digest, known_good->vp_octets, known_good->vp_length) != 0) {
307 REDEBUG("SHA1 digest does not match \"known good\" digest");
308 REDEBUG3("Password : %pV", password);
309 REDEBUG3("Calculated : %pH", fr_box_octets(digest, SHA1_DIGEST_LENGTH));
310 REDEBUG3("Expected : %pH", fr_box_octets(known_good->vp_octets, SHA1_DIGEST_LENGTH));
312 }
313
315}
316
318 UNUSED rlm_pap_t const *inst, request_t *request,
319 fr_pair_t const *known_good, fr_value_box_t const *password)
320{
321 fr_sha1_ctx sha1_context;
323
324 if (known_good->vp_length <= SHA1_DIGEST_LENGTH) {
325 REDEBUG("\"known-good\" Password.SSHA has incorrect length, expected > 20 got %zu", known_good->vp_length);
327 }
328
329 fr_sha1_init(&sha1_context);
330 fr_sha1_update(&sha1_context, password->vb_octets, password->vb_length);
331
332 fr_sha1_update(&sha1_context, known_good->vp_octets + SHA1_DIGEST_LENGTH, known_good->vp_length - SHA1_DIGEST_LENGTH);
333 fr_sha1_final(digest, &sha1_context);
334
335 if (fr_digest_cmp(digest, known_good->vp_octets, SHA1_DIGEST_LENGTH) != 0) {
336 REDEBUG("SSHA digest does not match \"known good\" digest");
337 REDEBUG3("Password : %pV", password);
338 REDEBUG3("Salt : %pH", fr_box_octets(known_good->vp_octets + SHA1_DIGEST_LENGTH,
339 known_good->vp_length - SHA1_DIGEST_LENGTH));
340 REDEBUG3("Calculated : %pH", fr_box_octets(digest, SHA1_DIGEST_LENGTH));
341 REDEBUG3("Expected : %pH", fr_box_octets(known_good->vp_octets, SHA1_DIGEST_LENGTH));
343 }
344
346}
347
348#ifdef HAVE_OPENSSL_EVP_H
349static unlang_action_t CC_HINT(nonnull) pap_auth_evp_md(rlm_rcode_t *p_result,
350 UNUSED rlm_pap_t const *inst, request_t *request,
351 fr_pair_t const *known_good, fr_value_box_t const *password,
352 char const *name, EVP_MD const *md)
353{
354 EVP_MD_CTX *ctx;
355 uint8_t digest[EVP_MAX_MD_SIZE];
356 unsigned int digest_len;
357
358 ctx = EVP_MD_CTX_create();
359 EVP_DigestInit_ex(ctx, md, NULL);
360 EVP_DigestUpdate(ctx, password->vb_octets, password->vb_length);
361 EVP_DigestFinal_ex(ctx, digest, &digest_len);
362 EVP_MD_CTX_destroy(ctx);
363
364 fr_assert((size_t) digest_len == known_good->vp_length); /* This would be an OpenSSL bug... */
365
366 if (fr_digest_cmp(digest, known_good->vp_octets, known_good->vp_length) != 0) {
367 REDEBUG("%s digest does not match \"known good\" digest", name);
368 REDEBUG3("Password : %pV", password);
369 REDEBUG3("Calculated : %pH", fr_box_octets(digest, digest_len));
370 REDEBUG3("Expected : %pH", &known_good->data);
372 }
373
375}
376
377static unlang_action_t CC_HINT(nonnull) pap_auth_evp_md_salted(rlm_rcode_t *p_result,
378 UNUSED rlm_pap_t const *inst, request_t *request,
379 fr_pair_t const *known_good, fr_value_box_t const *password,
380 char const *name, EVP_MD const *md)
381{
382 EVP_MD_CTX *ctx;
383 uint8_t digest[EVP_MAX_MD_SIZE];
384 unsigned int digest_len, min_len;
385
386 min_len = EVP_MD_size(md);
387 ctx = EVP_MD_CTX_create();
388 EVP_DigestInit_ex(ctx, md, NULL);
389 EVP_DigestUpdate(ctx, password->vb_octets, password->vb_length);
390 EVP_DigestUpdate(ctx, known_good->vp_octets + min_len, known_good->vp_length - min_len);
391 EVP_DigestFinal_ex(ctx, digest, &digest_len);
392 EVP_MD_CTX_destroy(ctx);
393
394 fr_assert((size_t) digest_len == min_len); /* This would be an OpenSSL bug... */
395
396 /*
397 * Only compare digest_len bytes, the rest is salt.
398 */
399 if (fr_digest_cmp(digest, known_good->vp_octets, (size_t)digest_len) != 0) {
400 REDEBUG("%s digest does not match \"known good\" digest", name);
401 REDEBUG3("Password : %pV", password);
402 REDEBUG3("Salt : %pH",
403 fr_box_octets(known_good->vp_octets + digest_len, known_good->vp_length - digest_len));
404 REDEBUG3("Calculated : %pH", fr_box_octets(digest, digest_len));
405 REDEBUG3("Expected : %pH", fr_box_octets(known_good->vp_octets, digest_len));
407 }
408
410}
411
412/** Define a new OpenSSL EVP based password hashing function
413 *
414 */
415#define PAP_AUTH_EVP_MD(_func, _new_func, _name, _md) \
416static unlang_action_t CC_HINT(nonnull) _new_func(rlm_rcode_t *p_result, \
417 rlm_pap_t const *inst, request_t *request, \
418 fr_pair_t const *known_good, fr_value_box_t const *password) \
419{ \
420 return _func(p_result, inst, request, known_good, password, _name, _md); \
421}
422
423PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha2_224, "SHA2-224", EVP_sha224())
424PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha2_256, "SHA2-256", EVP_sha256())
425PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha2_384, "SHA2-384", EVP_sha384())
426PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha2_512, "SHA2-512", EVP_sha512())
427PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha2_224, "SSHA2-224", EVP_sha224())
428PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha2_256, "SSHA2-256", EVP_sha256())
429PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha2_384, "SSHA2-384", EVP_sha384())
430PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha2_512, "SSHA2-512", EVP_sha512())
431
432PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha3_224, "SHA3-224", EVP_sha3_224())
433PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha3_256, "SHA3-256", EVP_sha3_256())
434PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha3_384, "SHA3-384", EVP_sha3_384())
435PAP_AUTH_EVP_MD(pap_auth_evp_md, pap_auth_sha3_512, "SHA3-512", EVP_sha3_512())
436PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha3_224, "SSHA3-224", EVP_sha3_224())
437PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha3_256, "SSHA3-256", EVP_sha3_256())
438PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha3_384, "SSHA3-384", EVP_sha3_384())
439PAP_AUTH_EVP_MD(pap_auth_evp_md_salted, pap_auth_ssha3_512, "SSHA3-512", EVP_sha3_512())
440
441/** Validates Crypt::PBKDF2 LDAP format strings
442 *
443 * @param[out] p_result The result of comparing the pbkdf2 hash with the password.
444 * @param[in] request The current request.
445 * @param[in] str Raw PBKDF2 string.
446 * @param[in] len Length of string.
447 * @param[in] hash_names Table containing valid hash names.
448 * @param[in] hash_names_len How long the table is.
449 * @param[in] scheme_sep Separation character between the scheme and the next component.
450 * @param[in] iter_sep Separation character between the iterations and the next component.
451 * @param[in] salt_sep Separation character between the salt and the next component.
452 * @param[in] iter_is_base64 Whether the iterations is are encoded as base64.
453 * @param[in] password to validate.
454 * @return
455 * - RLM_MODULE_REJECT
456 * - RLM_MODULE_OK
457 */
458static inline CC_HINT(nonnull) unlang_action_t pap_auth_pbkdf2_parse(rlm_rcode_t *p_result,
459 request_t *request, const uint8_t *str, size_t len,
460 fr_table_num_sorted_t const hash_names[], size_t hash_names_len,
461 char scheme_sep, char iter_sep, char salt_sep,
462 bool iter_is_base64, fr_value_box_t const *password)
463{
465
466 uint8_t const *p, *q, *end;
467 ssize_t slen;
468
469 EVP_MD const *evp_md;
470 int digest_type;
471 size_t digest_len;
472
473 uint32_t iterations = 1;
474
475 uint8_t *salt = NULL;
476 size_t salt_len;
477 uint8_t hash[EVP_MAX_MD_SIZE];
478 uint8_t digest[EVP_MAX_MD_SIZE];
479
480 RDEBUG2("Comparing with \"known-good\" Password.PBKDF2");
481
482 if (len <= 1) {
483 REDEBUG("Password.PBKDF2 is too short");
484 goto finish;
485 }
486
487 /*
488 * Parse PBKDF string = {hash_algorithm}<scheme_sep><iterations><iter_sep>b64(<salt>)<salt_sep>b64(<hash>)
489 */
490 p = str;
491 end = p + len;
492
493 q = memchr(p, scheme_sep, end - p);
494 if (!q) {
495 REDEBUG("Password.PBKDF2 has no component separators");
496 goto finish;
497 }
498
499 digest_type = fr_table_value_by_substr(hash_names, (char const *)p, q - p, -1);
500 switch (digest_type) {
501 case FR_SSHA1:
502 evp_md = EVP_sha1();
503 digest_len = SHA1_DIGEST_LENGTH;
504 break;
505
506 case FR_SSHA2_224:
507 evp_md = EVP_sha224();
508 digest_len = SHA224_DIGEST_LENGTH;
509 break;
510
511 case FR_SSHA2_256:
512 evp_md = EVP_sha256();
513 digest_len = SHA256_DIGEST_LENGTH;
514 break;
515
516 case FR_SSHA2_384:
517 evp_md = EVP_sha384();
518 digest_len = SHA384_DIGEST_LENGTH;
519 break;
520
521 case FR_SSHA2_512:
522 evp_md = EVP_sha512();
523 digest_len = SHA512_DIGEST_LENGTH;
524 break;
525
526 case FR_SSHA3_224:
527 evp_md = EVP_sha3_224();
528 digest_len = SHA224_DIGEST_LENGTH;
529 break;
530
531 case FR_SSHA3_256:
532 evp_md = EVP_sha3_256();
533 digest_len = SHA256_DIGEST_LENGTH;
534 break;
535
536 case FR_SSHA3_384:
537 evp_md = EVP_sha3_384();
538 digest_len = SHA384_DIGEST_LENGTH;
539 break;
540
541 case FR_SSHA3_512:
542 evp_md = EVP_sha3_512();
543 digest_len = SHA512_DIGEST_LENGTH;
544 break;
545
546 default:
547 REDEBUG("Unknown PBKDF2 hash method \"%.*s\"", (int)(q - p), p);
548 goto finish;
549 }
550
551 p = q + 1;
552
553 if (((end - p) < 1) || !(q = memchr(p, iter_sep, end - p))) {
554 REDEBUG("Password.PBKDF2 missing iterations component");
555 goto finish;
556 }
557
558 if ((q - p) == 0) {
559 REDEBUG("Password.PBKDF2 iterations component too short");
560 goto finish;
561 }
562
563 /*
564 * If it's not base64 encoded, assume it's ascii
565 */
566 if (!iter_is_base64) {
567 char iterations_buff[sizeof("4294967295") + 1];
568 char *qq;
569
570 /*
571 * While passwords come from "trusted" sources, we don't trust them too much!
572 */
573 if ((size_t) (q - p) >= sizeof(iterations_buff)) {
574 REMARKER((char const *) p, q - p,
575 "Password.PBKDF2 iterations field is too large");
576
577 goto finish;
578 }
579
580 strlcpy(iterations_buff, (char const *)p, (q - p) + 1);
581
582 iterations = strtoul(iterations_buff, &qq, 10);
583 if (*qq != '\0') {
584 REMARKER(iterations_buff, qq - iterations_buff,
585 "Password.PBKDF2 iterations field contains an invalid character");
586
587 goto finish;
588 }
589 p = q + 1;
590 /*
591 * base64 encoded and big endian
592 */
593 } else {
595 slen = fr_base64_decode(&FR_DBUFF_TMP((uint8_t *)&iterations, sizeof(iterations)),
596 &FR_SBUFF_IN((char const *)p, (char const *)q), false, false);
597 if (slen <= 0) {
598 RPEDEBUG("Failed decoding Password.PBKDF2 iterations component (%.*s)", (int)(q - p), p);
599 goto finish;
600 }
601 if (slen != sizeof(iterations)) {
602 REDEBUG("Decoded Password.PBKDF2 iterations component is wrong size");
603 }
604
605 iterations = ntohl(iterations);
606
607 p = q + 1;
608 }
609
610 /*
611 * 0 iterations is invalid (we need at least one)
612 */
613 if (iterations == 0) iterations = 1;
614
615 if (((end - p) < 1) || !(q = memchr(p, salt_sep, end - p))) {
616 REDEBUG("Password.PBKDF2 missing salt component");
617 goto finish;
618 }
619
620 if ((q - p) == 0) {
621 REDEBUG("Password.PBKDF2 salt component too short");
622 goto finish;
623 }
624
625 MEM(salt = talloc_array(request, uint8_t, FR_BASE64_DEC_LENGTH(q - p)));
626 slen = fr_base64_decode(&FR_DBUFF_TMP(salt, talloc_array_length(salt)),
627 &FR_SBUFF_IN((char const *) p, (char const *)q), false, false);
628 if (slen <= 0) {
629 RPEDEBUG("Failed decoding Password.PBKDF2 salt component");
630 goto finish;
631 }
632 salt_len = (size_t)slen;
633
634 p = q + 1;
635
636 if ((q - p) == 0) {
637 REDEBUG("Password.PBKDF2 hash component too short");
638 goto finish;
639 }
640
641 slen = fr_base64_decode(&FR_DBUFF_TMP(hash, sizeof(hash)),
642 &FR_SBUFF_IN((char const *)p, (char const *)end), false, false);
643 if (slen <= 0) {
644 RPEDEBUG("Failed decoding Password.PBKDF2 hash component");
645 goto finish;
646 }
647
648 if ((size_t)slen != digest_len) {
649 REDEBUG("Password.PBKDF2 hash component length is incorrect for hash type, expected %zu, got %zd",
650 digest_len, slen);
651
652 RHEXDUMP2(hash, slen, "hash component");
653
654 goto finish;
655 }
656
657 RDEBUG2("PBKDF2 %s: Iterations %u, salt length %zu, hash length %zd",
658 fr_table_str_by_value(pbkdf2_crypt_names, digest_type, "<UNKNOWN>"),
659 iterations, salt_len, slen);
660
661 /*
662 * Hash and compare
663 */
664 if (PKCS5_PBKDF2_HMAC((char const *)password->vb_octets, (int)password->vb_length,
665 (unsigned char const *)salt, (int)salt_len,
666 (int)iterations,
667 evp_md,
668 (int)digest_len, (unsigned char *)digest) == 0) {
669 fr_tls_log(request, "PBKDF2 digest failure");
670 goto finish;
671 }
672
673 if (fr_digest_cmp(digest, hash, (size_t)digest_len) != 0) {
674 REDEBUG("PBKDF2 digest does not match \"known good\" digest");
675 REDEBUG3("Salt : %pH", fr_box_octets(salt, salt_len));
676 REDEBUG3("Calculated : %pH", fr_box_octets(digest, digest_len));
677 REDEBUG3("Expected : %pH", fr_box_octets(hash, slen));
678 rcode = RLM_MODULE_REJECT;
679 } else {
680 rcode = RLM_MODULE_OK;
681 }
682
683finish:
684 talloc_free(salt);
685
686 RETURN_MODULE_RCODE(rcode);
687}
688
689static inline unlang_action_t CC_HINT(nonnull) pap_auth_pbkdf2(rlm_rcode_t *p_result,
690 UNUSED rlm_pap_t const *inst,
691 request_t *request,
692 fr_pair_t const *known_good, fr_value_box_t const *password)
693{
694 uint8_t const *p = known_good->vp_octets, *q, *end = p + known_good->vp_length;
695
696 if (end - p < 2) {
697 REDEBUG("Password.PBKDF2 too short");
699 }
700
701 /*
702 * If it doesn't begin with a $ assume
703 * It's Crypt::PBKDF2 LDAP format
704 *
705 * {X-PBKDF2}<digest>:<b64 rounds>:<b64_salt>:<b64_hash>
706 */
707 if (*p != '$') {
708 /*
709 * Strip the header if it's present
710 */
711 if (*p == '{') {
712 q = memchr(p, '}', end - p);
713 p = q + 1;
714 }
715 return pap_auth_pbkdf2_parse(p_result, request, p, end - p,
716 pbkdf2_crypt_names, pbkdf2_crypt_names_len,
717 ':', ':', ':', true, password);
718 }
719
720 /*
721 * Crypt::PBKDF2 Crypt format
722 *
723 * $PBKDF2$<digest>:<rounds>:<b64_salt>$<b64_hash>
724 */
725 if ((size_t)(end - p) >= sizeof("$PBKDF2$") && (memcmp(p, "$PBKDF2$", sizeof("$PBKDF2$") - 1) == 0)) {
726 p += sizeof("$PBKDF2$") - 1;
727 return pap_auth_pbkdf2_parse(p_result, request, p, end - p,
728 pbkdf2_crypt_names, pbkdf2_crypt_names_len,
729 ':', ':', '$', false, password);
730 }
731
732 /*
733 * Python's passlib format
734 *
735 * $pbkdf2-<digest>$<rounds>$<alt_b64_salt>$<alt_b64_hash>
736 *
737 * Note: Our base64 functions also work with alt_b64
738 */
739 if ((size_t)(end - p) >= sizeof("$pbkdf2-") && (memcmp(p, "$pbkdf2-", sizeof("$pbkdf2-") - 1) == 0)) {
740 p += sizeof("$pbkdf2-") - 1;
741 return pap_auth_pbkdf2_parse(p_result, request, p, end - p,
742 pbkdf2_passlib_names, pbkdf2_passlib_names_len,
743 '$', '$', '$', false, password);
744 }
745
746 REDEBUG("Can't determine format of Password.PBKDF2");
747
749}
750#endif
751
753 UNUSED rlm_pap_t const *inst, request_t *request,
754 fr_pair_t const *known_good, fr_value_box_t const *password)
755{
756 ssize_t len;
758 uint8_t ucs2[512];
759
760 RDEBUG2("Comparing with \"known-good\" Password.NT");
761
762 if (known_good->vp_length != MD4_DIGEST_LENGTH) {
763 REDEBUG("\"known good\" Password.NT has incorrect length, expected 16 got %zu", known_good->vp_length);
765 }
766
767 len = fr_utf8_to_ucs2(ucs2, sizeof(ucs2),
768 password->vb_strvalue, password->vb_length);
769 if (len < 0) {
770 REDEBUG("User-Password is not in UCS2 format");
772 }
773
774 fr_md4_calc(digest, (uint8_t *)ucs2, len);
775
776 if (fr_digest_cmp(digest, known_good->vp_octets, known_good->vp_length) != 0) {
777 REDEBUG("NT digest does not match \"known good\" digest");
778 REDEBUG3("Calculated : %pH", fr_box_octets(digest, sizeof(digest)));
779 REDEBUG3("Expected : %pH", &known_good->data);
781 }
782
784}
785
787 UNUSED rlm_pap_t const *inst, request_t *request,
788 fr_pair_t const *known_good, fr_value_box_t const *password)
789{
790 uint8_t digest[128];
792 uint8_t buff2[FR_MAX_STRING_LEN + 50];
793 fr_dbuff_t digest_dbuff = FR_DBUFF_TMP(digest, sizeof(digest));
794
795 RDEBUG2("Using Password.NT-MTA-MD5");
796
797 if (known_good->vp_length != 64) {
798 REDEBUG("\"known good\" Password.NS-MTA-MD5 has incorrect length, expected 64 got %zu",
799 known_good->vp_length);
801 }
802
803 /*
804 * Sanity check the value of Password.NS-MTA-MD5
805 */
806 if (fr_base16_decode(NULL, &digest_dbuff,
807 &FR_SBUFF_IN(known_good->vp_strvalue, known_good->vp_length), false) != 16) {
808 REDEBUG("\"known good\" Password.NS-MTA-MD5 has invalid value");
810 }
811
812 /*
813 * Ensure we don't have buffer overflows.
814 *
815 * This really: sizeof(buff) - 2 - 2*32 - strlen(passwd)
816 */
817 if (password->vb_length >= (sizeof(buff) - 2 - 2 * 32)) {
818 REDEBUG("\"known good\" Password.NS-MTA-MD5 is too long");
820 }
821
822 /*
823 * Set up the algorithm.
824 */
825 {
826 uint8_t *p = buff2;
827
828 memcpy(p, &known_good->vp_octets[32], 32);
829 p += 32;
830 *(p++) = 89;
831 memcpy(p, password->vb_strvalue, password->vb_length);
832 p += password->vb_length;
833 *(p++) = 247;
834 memcpy(p, &known_good->vp_octets[32], 32);
835 p += 32;
836
837 fr_md5_calc(buff, (uint8_t *) buff2, p - buff2);
838 }
839
840 if (fr_digest_cmp(fr_dbuff_start(&digest_dbuff), buff, 16) != 0) {
841 REDEBUG("NS-MTA-MD5 digest does not match \"known good\" digest");
843 }
844
846}
847
848/** Auth func for password types that should have been normalised away
849 *
850 */
852 UNUSED rlm_pap_t const *inst, UNUSED request_t *request,
853 UNUSED fr_pair_t const *known_good, UNUSED fr_value_box_t const *password)
854{
856}
857
858/** Table of password types we can process
859 *
860 */
862 [FR_CLEARTEXT] = pap_auth_clear,
863 [FR_MD5] = pap_auth_md5,
864 [FR_SMD5] = pap_auth_smd5,
865
866#ifdef HAVE_CRYPT
867 [FR_CRYPT] = pap_auth_crypt,
868#endif
869 [FR_NS_MTA_MD5] = pap_auth_ns_mta_md5,
870 [FR_NT] = pap_auth_nt,
871 [FR_WITH_HEADER] = pap_auth_dummy,
872 [FR_SHA1] = pap_auth_sha1,
873 [FR_SSHA1] = pap_auth_ssha1,
874
875#ifdef HAVE_OPENSSL_EVP_H
876 [FR_PBKDF2] = pap_auth_pbkdf2,
877 [FR_SHA2] = pap_auth_dummy,
878 [FR_SHA2_224] = pap_auth_sha2_224,
879 [FR_SHA2_256] = pap_auth_sha2_256,
880 [FR_SHA2_384] = pap_auth_sha2_384,
881 [FR_SHA2_512] = pap_auth_sha2_512,
882 [FR_SSHA2_224] = pap_auth_ssha2_224,
883 [FR_SSHA2_256] = pap_auth_ssha2_256,
884 [FR_SSHA2_384] = pap_auth_ssha2_384,
885 [FR_SSHA2_512] = pap_auth_ssha2_512,
886 [FR_SHA3] = pap_auth_dummy,
887 [FR_SHA3_224] = pap_auth_sha3_224,
888 [FR_SHA3_256] = pap_auth_sha3_256,
889 [FR_SHA3_384] = pap_auth_sha3_384,
890 [FR_SHA3_512] = pap_auth_sha3_512,
891 [FR_SSHA3_224] = pap_auth_ssha3_224,
892 [FR_SSHA3_256] = pap_auth_ssha3_256,
893 [FR_SSHA3_384] = pap_auth_ssha3_384,
894 [FR_SSHA3_512] = pap_auth_ssha3_512,
895#endif /* HAVE_OPENSSL_EVP_H */
896};
897
898/*
899 * Authenticate the user via one of any well-known password.
900 */
901static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
902{
904 fr_pair_t *known_good;
906 pap_auth_func_t auth_func;
907 bool ephemeral;
908 pap_call_env_t *env_data = talloc_get_type_abort(mctx->env_data, pap_call_env_t);
909
910 if (env_data->password.type != FR_TYPE_STRING) {
911 REDEBUG("You set 'Auth-Type = PAP' for a request that does not contain a %s attribute!",
912 env_data->password_tmpl->name);
914 }
915
916 /*
917 * The user MUST supply a non-zero-length password.
918 */
919 if (env_data->password.vb_length == 0) {
920 REDEBUG("Password must not be empty");
922 }
923
924 if (RDEBUG_ENABLED3) {
925 RDEBUG3("Login attempt with %s = %pV (%zd)", env_data->password_tmpl->name,
926 &env_data->password, env_data->password.vb_length);
927 } else {
928 RDEBUG2("Login attempt with password");
929 }
930
931 /*
932 * Retrieve the normalised version of
933 * the known_good password, without
934 * mangling the current password attributes
935 * in the request.
936 */
937 known_good = password_find(&ephemeral, request, request,
938 pap_alloweds, talloc_array_length(pap_alloweds),
939 inst->normify);
940 if (!known_good) {
941 REDEBUG("No \"known good\" password found for user");
943 }
944
945 fr_assert(known_good->da->attr < NUM_ELEMENTS(auth_func_table));
946
947 auth_func = auth_func_table[known_good->da->attr];
948 fr_assert(auth_func);
949
950 if (RDEBUG_ENABLED3) {
951 RDEBUG3("Comparing with \"known good\" %pP (%zu)", known_good, known_good->vp_length);
952 } else {
953 RDEBUG2("Comparing with \"known-good\" %s (%zu)", known_good->da->name, known_good->vp_length);
954 }
955
956 /*
957 * Authenticate, and return.
958 */
959 auth_func(&rcode, inst, request, known_good, &env_data->password);
960 if (ephemeral) TALLOC_FREE(known_good);
961 switch (rcode) {
963 REDEBUG("Password incorrect");
964 break;
965
966 case RLM_MODULE_OK:
967 RDEBUG2("User authenticated successfully");
968 break;
969
970 default:
971 break;
972 }
973
974 RETURN_MODULE_RCODE(rcode);
975}
976
977static int mod_instantiate(module_inst_ctx_t const *mctx)
978{
979 rlm_pap_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_pap_t);
980
981 inst->auth_type = fr_dict_enum_by_name(attr_auth_type, mctx->mi->name, -1);
982 if (!inst->auth_type) {
983 WARN("Failed to find 'authenticate %s {...}' section. PAP will likely not work",
984 mctx->mi->name);
985 }
986
987 return 0;
988}
989
990static int mod_load(void)
991{
992 size_t i, j = 0;
993 size_t allowed = 0;
994
995 /*
996 * Load the dictionaries early
997 */
999 PERROR("%s", __FUNCTION__);
1000 return -1;
1001 }
1003 PERROR("%s", __FUNCTION__);
1005 return -1;
1006 }
1007
1008 /*
1009 * Figure out how many password types we allow
1010 */
1011 for (i = 0; i < NUM_ELEMENTS(auth_func_table); i++) {
1012 if (auth_func_table[i] == NULL) continue;
1013
1014 allowed++;
1015 }
1016
1017 /*
1018 * Get a list of the DAs that match are allowed
1019 * functions.
1020 */
1021 pap_alloweds = talloc_array(NULL, fr_dict_attr_t const *, allowed);
1022 for (i = 0; i < NUM_ELEMENTS(auth_func_table); i++) {
1023 fr_dict_attr_t const *password_da;
1024
1025 if (auth_func_table[i] == NULL) continue;
1026
1027 password_da = fr_dict_attr_child_by_num(attr_root, i);
1028 if (!fr_cond_assert(password_da)) {
1029 ERROR("Could not resolve password attribute %zu", i);
1032 return -1;
1033 }
1034
1035 pap_alloweds[j++] = password_da;
1036 }
1037
1038 return 0;
1039}
1040
1041static void mod_unload(void)
1042{
1045}
1046
1047/*
1048 * The module name should be the only globally exported symbol.
1049 * That is, everything else should be 'static'.
1050 *
1051 * If the module needs to temporarily modify it's instantiation
1052 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
1053 * The server will then take care of ensuring that the module
1054 * is single-threaded.
1055 */
1056extern module_rlm_t rlm_pap;
1058 .common = {
1059 .magic = MODULE_MAGIC_INIT,
1060 .name = "pap",
1061 .inst_size = sizeof(rlm_pap_t),
1062 .onload = mod_load,
1063 .unload = mod_unload,
1066 },
1067 .method_group = {
1068 .bindings = (module_method_binding_t[]){
1069 /*
1070 * Hack to support old configurations
1071 */
1072 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &pap_method_env },
1073 { .section = SECTION_NAME("authorize", CF_IDENT_ANY), .method = mod_authorize, .method_env = &pap_method_env },
1074 { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_authorize, .method_env = &pap_method_env },
1075
1077 }
1078 }
1079};
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:470
#define RCSID(id)
Definition build.h:483
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
#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:642
#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:579
#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:898
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:514
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define fr_dict_autofree(_to_free)
Definition dict.h:853
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:268
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
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:3395
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:850
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:3328
Specifies an attribute which must be present for the module to function.
Definition dict.h:267
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
Value of an enumerated attribute.
Definition dict.h:227
#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:482
#define MD4_DIGEST_LENGTH
Definition md4.h:25
fr_md5_update_t fr_md5_update
Definition md5.c:442
fr_md5_final_t fr_md5_final
Definition md5.c:443
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
Definition md5.c:522
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
Definition md5.c:477
void fr_md5_ctx_t
Definition md5.h:28
#define MD5_DIGEST_LENGTH
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
unsigned int uint32_t
long int ssize_t
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.
unsigned char uint8_t
unsigned long int size_t
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:315
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:472
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:693
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
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 const conf_parser_t config[]
Definition base.c:183
#define fr_assert(_expr)
Definition rad_assert.h:38
#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_FAIL
Definition rcode.h:56
#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:861
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:851
static int mod_load(void)
Definition rlm_pap.c:990
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:233
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:178
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:258
static fr_dict_t const * dict_freeradius
Definition rlm_pap.c:101
module_rlm_t rlm_pap
Definition rlm_pap.c:1057
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:752
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:786
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_pap.c:901
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:290
static void mod_unload(void)
Definition rlm_pap.c:1041
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:317
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_pap.c:148
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:140
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:977
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:1310
#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
size_t inst_size
Size of the module's instance data.
Definition module.h:203
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
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: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 talloc_get_type_abort_const
Definition talloc.h:282
@ 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:288