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: c3d5f06ba86ca2936ee692b9a3852919328bf267 $
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: c3d5f06ba86ca2936ee692b9a3852919328bf267 $")
26
27#include <freeradius-devel/server/base.h>
28#include <freeradius-devel/server/module_rlm.h>
29#include <freeradius-devel/util/base32.h>
30
31
32#include "totp.h"
33
40
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(unlang_result_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;
84
85 uint8_t const *our_key;
86 size_t our_keylen;
87 uint8_t buffer[80]; /* multiple of 5*8 characters */
88 time_t now;
89
90 if (fr_type_is_null(user_password->type)) RETURN_UNLANG_NOOP;
91
92 if (user_password->vb_length == 0) {
93 RWARN("TOTP.From-User is empty");
95 }
96
97 if (user_password->vb_length != inst->totp.otp_length) {
98 RWARN("TOTP.From-User has incorrect length. Expected %u, got %zu",
99 inst->totp.otp_length, user_password->vb_length);
101 }
102
103 /*
104 * Look for the raw key first.
105 */
106 if (!fr_type_is_null(key->type)) {
107 our_key = key->vb_octets;
108 our_keylen = key->vb_length;
109
110 } else {
111 ssize_t len;
112
114
115 len = fr_base32_decode(&FR_DBUFF_TMP((uint8_t *) buffer, sizeof(buffer)), &FR_SBUFF_IN(secret->vb_strvalue, secret->vb_length), true, true);
116 if (len < 0) {
117 RERROR("TOTP.Secret cannot be decoded");
119 }
120
121 our_key = buffer;
122 our_keylen = len;
123 }
124
125 now = fr_time_to_sec(request->packet->timestamp);
126 if (time_offset->type == FR_TYPE_INT32) {
127 RDEBUG2("Using time offset of %pVs", time_offset);
128 now += time_offset->vb_int32;
129 }
130
131 switch (fr_totp_cmp(&inst->totp, request, now, our_key, our_keylen, user_password->vb_strvalue)) {
132 case 0:
134
135 case -2:
137
138 default:
140 }
141}
142
143/*
144 * Do any per-module initialization that is separate to each
145 * configured instance of the module. e.g. set up connections
146 * to external databases, read configuration files, set up
147 * dictionary entries, etc.
148 *
149 * If configuration information is given in the config section
150 * that must be referenced in later calls, store a handle to it
151 * in *instance otherwise put a null pointer there.
152 */
153static int mod_instantiate(module_inst_ctx_t const *mctx)
154{
155 rlm_totp_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_totp_t);
156
157 FR_INTEGER_BOUND_CHECK("time_step", inst->totp.time_step, >=, 5);
158 FR_INTEGER_BOUND_CHECK("time_step", inst->totp.time_step, <=, 120);
159
160 FR_INTEGER_BOUND_CHECK("lookback_steps", inst->totp.lookback_steps, >=, 1);
161 FR_INTEGER_BOUND_CHECK("lookback_steps", inst->totp.lookback_steps, <=, 10);
162
163 FR_INTEGER_BOUND_CHECK("lookforward_steps", inst->totp.lookforward_steps, <=, 10);
164
165 FR_INTEGER_BOUND_CHECK("lookback_interval", inst->totp.lookback_interval, <=, inst->totp.time_step);
166
167 FR_INTEGER_BOUND_CHECK("otp_length", inst->totp.otp_length, >=, 6);
168 FR_INTEGER_BOUND_CHECK("otp_length", inst->totp.otp_length, <=, 8);
169
170 if (inst->totp.otp_length == 7) inst->totp.otp_length = 8;
171
172 return 0;
173}
174
175/*
176 * The module name should be the only globally exported symbol.
177 * That is, everything else should be 'static'.
178 *
179 * If the module needs to temporarily modify it's instantiation
180 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
181 * The server will then take care of ensuring that the module
182 * is single-threaded.
183 */
186 .common = {
187 .magic = MODULE_MAGIC_INIT,
188 .name = "totp",
189 .inst_size = sizeof(rlm_totp_t),
191 .instantiate = mod_instantiate
192 },
193 .method_group = {
194 .bindings = (module_method_binding_t[]){
195 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &method_env },
197 }
198 }
199};
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:66
#define RCSID(id)
Definition build.h:506
#define CALL_ENV_TERMINATOR
Definition call_env.h:236
#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:240
call_env_parser_t const * env
Parsing rules for call method env.
Definition call_env.h:247
@ CALL_ENV_FLAG_BARE_WORD_ATTRIBUTE
bare words are treated as an attribute, but strings may be xlats.
Definition call_env.h:92
@ 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:340
Per method call config.
Definition call_env.h:180
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:517
#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:280
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
#define CF_IDENT_ANY
Definition cf_util.h:75
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:522
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define RWARN(fmt,...)
Definition log.h:309
#define RERROR(fmt,...)
Definition log.h:310
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_INT32
32 Bit signed integer.
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:163
static char * secret
#define RDEBUG2(fmt,...)
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
#define RETURN_UNLANG_REJECT
Definition rcode.h:62
#define RETURN_UNLANG_OK
Definition rcode.h:64
#define RETURN_UNLANG_NOOP
Definition rcode.h:69
fr_value_box_t time_offset
Definition rlm_totp.c:38
static const call_env_method_t method_env
Definition rlm_totp.c:41
module_rlm_t rlm_totp
Definition rlm_totp.c:185
fr_value_box_t secret
Definition rlm_totp.c:35
fr_value_box_t user_password
Definition rlm_totp.c:37
fr_value_box_t key
Definition rlm_totp.c:36
static unlang_action_t mod_authenticate(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_totp.c:76
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:153
#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:39
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:293
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Named methods exported by a module.
Definition module.h:174
eap_aka_sim_process_conf_t * inst
#define talloc_get_type_abort_const
Definition talloc.h:110
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:118
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
static fr_time_delta_t time_offset
#define fr_type_is_null(_x)
Definition types.h:347
int nonnull(2, 5))