The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_totp.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: 9e6800ec4bfaf776927b5adfd62a4e698a5a2c94 $
19 * @file rlm_totp.c
20 * @brief Execute commands and parse the results.
21 *
22 * @copyright 2021 The FreeRADIUS server project
23 * @copyright 2021 Network RADIUS SAS (legal@networkradius.com)
24 */
25RCSID("$Id: 9e6800ec4bfaf776927b5adfd62a4e698a5a2c94 $")
26
27#include <freeradius-devel/server/base.h>
28#include <freeradius-devel/server/module_rlm.h>
29#include <freeradius-devel/unlang/interpret.h>
30#include <freeradius-devel/util/base32.h>
31
32#include <freeradius-devel/unlang/call_env.h>
33
34#include "totp.h"
35
41
44 .env = (call_env_parser_t[]) {
46 .pair.dflt = "&control.TOTP.Secret", .pair.dflt_quote = T_BARE_WORD },
47
49 .pair.dflt = "&control.TOTP.key", .pair.dflt_quote = T_BARE_WORD },
50
52 .pair.dflt = "&request.TOTP.From-User", .pair.dflt_quote = T_BARE_WORD },
53
55 }
56};
57
58/* Define a structure for the configuration variables */
59typedef struct rlm_totp_t {
60 fr_totp_t totp; //! configuration entries passed to libfreeradius-totp
62
63/* Map configuration file names to internal variables */
64static const conf_parser_t module_config[] = {
65 { FR_CONF_OFFSET("time_step", rlm_totp_t, totp.time_step), .dflt = "30" },
66 { FR_CONF_OFFSET("otp_length", rlm_totp_t, totp.otp_length), .dflt = "6" },
67 { FR_CONF_OFFSET("lookback_steps", rlm_totp_t, totp.lookback_steps), .dflt = "1" },
68 { FR_CONF_OFFSET("lookback_interval", rlm_totp_t, totp.lookback_interval), .dflt = "30" },
69 { FR_CONF_OFFSET("lookforward_steps", rlm_totp_t, totp.lookforward_steps), .dflt = "0" },
71};
72
73/*
74 * Do the authentication
75 */
76static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
77{
78 rlm_totp_call_env_t *env_data = talloc_get_type_abort(mctx->env_data, rlm_totp_call_env_t);
80 fr_value_box_t *user_password = &env_data->user_password;
81 fr_value_box_t *secret = &env_data->secret;
82 fr_value_box_t *key = &env_data->key;
83
84 uint8_t const *our_key;
85 size_t our_keylen;
86 uint8_t buffer[80]; /* multiple of 5*8 characters */
87
88 if (fr_type_is_null(user_password->type)) RETURN_MODULE_NOOP;
89
90 if (user_password->vb_length == 0) {
91 RWARN("TOTP.From-User is empty");
93 }
94
95 if ((user_password->vb_length != 6) && (user_password->vb_length != 8)) {
96 RWARN("TOTP.From-User has incorrect length. Expected 6 or 8, got %zu", user_password->vb_length);
98 }
99
100 /*
101 * Look for the raw key first.
102 */
103 if (!fr_type_is_null(key->type)) {
104 our_key = key->vb_octets;
105 our_keylen = key->vb_length;
106
107 } else {
108 ssize_t len;
109
111
112 len = fr_base32_decode(&FR_DBUFF_TMP((uint8_t *) buffer, sizeof(buffer)), &FR_SBUFF_IN(secret->vb_strvalue, secret->vb_length), true, true);
113 if (len < 0) {
114 RERROR("TOTP.Secret cannot be decoded");
116 }
117
118 our_key = buffer;
119 our_keylen = len;
120 }
121
122 switch (fr_totp_cmp(&inst->totp, request, fr_time_to_sec(request->packet->timestamp), our_key, our_keylen, user_password->vb_strvalue)) {
123 case 0:
125
126 case -2:
128
129 default:
131 }
132}
133
134/*
135 * Do any per-module initialization that is separate to each
136 * configured instance of the module. e.g. set up connections
137 * to external databases, read configuration files, set up
138 * dictionary entries, etc.
139 *
140 * If configuration information is given in the config section
141 * that must be referenced in later calls, store a handle to it
142 * in *instance otherwise put a null pointer there.
143 */
144static int mod_instantiate(module_inst_ctx_t const *mctx)
145{
146 rlm_totp_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_totp_t);
147
148 FR_INTEGER_BOUND_CHECK("time_step", inst->totp.time_step, >=, 5);
149 FR_INTEGER_BOUND_CHECK("time_step", inst->totp.time_step, <=, 120);
150
151 FR_INTEGER_BOUND_CHECK("lookback_steps", inst->totp.lookback_steps, >=, 1);
152 FR_INTEGER_BOUND_CHECK("lookback_steps", inst->totp.lookback_steps, <=, 10);
153
154 FR_INTEGER_BOUND_CHECK("lookforward_steps", inst->totp.lookforward_steps, <=, 10);
155
156 FR_INTEGER_BOUND_CHECK("lookback_interval", inst->totp.lookback_interval, <=, inst->totp.time_step);
157
158 FR_INTEGER_BOUND_CHECK("otp_length", inst->totp.otp_length, >=, 6);
159 FR_INTEGER_BOUND_CHECK("otp_length", inst->totp.otp_length, <=, 8);
160
161 if (inst->totp.otp_length == 7) inst->totp.otp_length = 8;
162
163 return 0;
164}
165
166/*
167 * The module name should be the only globally exported symbol.
168 * That is, everything else should be 'static'.
169 *
170 * If the module needs to temporarily modify it's instantiation
171 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
172 * The server will then take care of ensuring that the module
173 * is single-threaded.
174 */
177 .common = {
178 .magic = MODULE_MAGIC_INIT,
179 .name = "totp",
180 .inst_size = sizeof(rlm_totp_t),
183 },
184 .method_group = {
185 .bindings = (module_method_binding_t[]){
186 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &method_env },
188 }
189 }
190};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
static int const char char buffer[256]
Definition acutest.h:576
#define fr_base32_decode(_out, _in, _expect_padding, _no_trailing)
Definition base32.h:69
#define RCSID(id)
Definition build.h:483
#define CALL_ENV_TERMINATOR
Definition call_env.h:231
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
Definition call_env.h:235
call_env_parser_t const * env
Parsing rules for call method env.
Definition call_env.h:242
@ CALL_ENV_FLAG_NULLABLE
Tmpl expansions are allowed to produce no output.
Definition call_env.h:80
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
Definition call_env.h:335
Per method call config.
Definition call_env.h:175
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:502
#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_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:514
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define RWARN(fmt,...)
Definition log.h:297
#define RERROR(fmt,...)
Definition log.h:298
@ FR_TYPE_STRING
String of printable characters.
long int ssize_t
unsigned char uint8_t
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
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
static const conf_parser_t config[]
Definition base.c:183
static char * secret
#define RETURN_MODULE_REJECT
Definition rcode.h:55
#define RETURN_MODULE_NOOP
Definition rcode.h:62
#define RETURN_MODULE_OK
Definition rcode.h:57
#define RETURN_MODULE_FAIL
Definition rcode.h:56
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1310
static const call_env_method_t method_env
Definition rlm_totp.c:42
module_rlm_t rlm_totp
Definition rlm_totp.c:176
fr_value_box_t secret
Definition rlm_totp.c:37
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_totp.c:76
fr_value_box_t user_password
Definition rlm_totp.c:39
fr_value_box_t key
Definition rlm_totp.c:38
fr_totp_t totp
Definition rlm_totp.c:60
static const conf_parser_t module_config[]
Definition rlm_totp.c:64
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_totp.c:144
#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
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
eap_aka_sim_process_conf_t * inst
#define talloc_get_type_abort_const
Definition talloc.h:282
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
Definition time.h:731
@ T_BARE_WORD
Definition token.h:120
int fr_totp_cmp(fr_totp_t const *cfg, request_t *request, time_t now, uint8_t const *key, size_t keylen, char const *totp)
Implement RFC 6238 TOTP algorithm (HMAC-SHA1).
Definition totp.c:71
#define fr_type_is_null(_x)
Definition types.h:326
int nonnull(2, 5))