All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_logintime.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: c04554e6d9ceec6fbdfe62471815a6cdff4a5fe1 $
19  * @file rlm_logintime.c
20  * @brief Allow login only during a given timeslot.
21  *
22  * @copyright 2001,2006 The FreeRADIUS server project
23  * @copyright 2004 Kostas Kalevras <kkalev@noc.ntua.gr>
24  */
25 RCSID("$Id: c04554e6d9ceec6fbdfe62471815a6cdff4a5fe1 $")
26 
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29 
30 #include <ctype.h>
31 
32 /* timestr.c */
33 int timestr_match(char const *, time_t);
34 
35 /*
36  * Define a structure for our module configuration.
37  *
38  * These variables do not need to be in a structure, but it's
39  * a lot cleaner to do so, and a pointer to the structure can
40  * be used as the instance handle.
41  */
42 typedef struct rlm_logintime_t {
43  uint32_t min_time;
45 
46 /*
47  * A mapping of configuration file names to internal variables.
48  *
49  * Note that the string is dynamically allocated, so it MUST
50  * be freed. When the configuration file parse re-reads the string,
51  * it free's the old one, and strdup's the new one, placing the pointer
52  * to the strdup'd string into 'config.string'. This gets around
53  * buffer over-flows.
54  */
55 static const CONF_PARSER module_config[] = {
56  { FR_CONF_OFFSET("minimum_timeout", PW_TYPE_INTEGER, rlm_logintime_t, min_time), .dflt = "60" },
58 };
59 
60 
61 /*
62  * Compare the current time to a range.
63  */
64 static int timecmp(UNUSED void *instance, REQUEST *req, UNUSED VALUE_PAIR *request, VALUE_PAIR *check,
65  UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
66 {
67  /*
68  * If there's a request, use that timestamp.
69  */
70  if (timestr_match(check->vp_strvalue,
71  req ? req->timestamp.tv_sec : time(NULL)) >= 0)
72  return 0;
73 
74  return -1;
75 }
76 
77 
78 /*
79  * Time-Of-Day support
80  */
81 static int time_of_day(UNUSED void *instance, REQUEST *req, UNUSED VALUE_PAIR *request, VALUE_PAIR *check,
82  UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
83 {
84  int scan;
85  int hhmmss, when;
86  char const *p;
87  struct tm *tm, s_tm;
88 
89  /*
90  * Must be called with a request pointer.
91  */
92  if (!req) return -1;
93 
94  if (strspn(check->vp_strvalue, "0123456789: ") != strlen(check->vp_strvalue)) {
95  DEBUG("rlm_logintime: Bad Time-Of-Day value \"%s\"",
96  check->vp_strvalue);
97  return -1;
98  }
99 
100  tm = localtime_r(&req->timestamp.tv_sec, &s_tm);
101  hhmmss = (tm->tm_hour * 3600) + (tm->tm_min * 60) + tm->tm_sec;
102 
103  /*
104  * Time of day is a 24-hour clock
105  */
106  p = check->vp_strvalue;
107  scan = atoi(p);
108  p = strchr(p, ':');
109  if ((scan > 23) || !p) {
110  DEBUG("rlm_logintime: Bad Time-Of-Day value \"%s\"",
111  check->vp_strvalue);
112  return -1;
113  }
114  when = scan * 3600;
115  p++;
116 
117  scan = atoi(p);
118  if (scan > 59) {
119  DEBUG("rlm_logintime: Bad Time-Of-Day value \"%s\"",
120  check->vp_strvalue);
121  return -1;
122  }
123  when += scan * 60;
124 
125  p = strchr(p, ':');
126  if (p) {
127  scan = atoi(p + 1);
128  if (scan > 59) {
129  DEBUG("rlm_logintime: Bad Time-Of-Day value \"%s\"",
130  check->vp_strvalue);
131  return -1;
132  }
133  when += scan;
134  }
135 
136  fprintf(stderr, "returning %d - %d\n",
137  hhmmss, when);
138 
139  return hhmmss - when;
140 }
141 
142 /*
143  * Check if account has expired, and if user may login now.
144  */
145 static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
146 {
147  rlm_logintime_t *inst = instance;
148  VALUE_PAIR *ends, *timeout;
149  int left;
150 
151  ends = fr_pair_find_by_num(request->config, 0, PW_LOGIN_TIME, TAG_ANY);
152  if (!ends) {
153  return RLM_MODULE_NOOP;
154  }
155 
156  /*
157  * Authentication is OK. Now see if this user may login at this time of the day.
158  */
159  RDEBUG("Checking Login-Time");
160 
161  /*
162  * Compare the time the request was received with the current Login-Time value
163  */
164  left = timestr_match(ends->vp_strvalue, request->timestamp.tv_sec);
165  if (left < 0) return RLM_MODULE_USERLOCK; /* outside of the allowed time */
166 
167  /*
168  * Do nothing, login time is not controlled (unendsed).
169  */
170  if (left == 0) {
171  return RLM_MODULE_OK;
172  }
173 
174  /*
175  * The min_time setting is to deal with NAS that won't allow Session-Timeout values below a certain value
176  * For example some Alcatel Lucent products won't allow a Session-Timeout < 300 (5 minutes).
177  *
178  * We don't know were going to get another chance to lock out the user, so we need to do it now.
179  */
180  if (left < (int) inst->min_time) {
181  REDEBUG("Login outside of allowed time-slot (session end %s, with lockout %i seconds before)",
182  ends->vp_strvalue, inst->min_time);
183 
184  return RLM_MODULE_USERLOCK;
185  }
186 
187  /* else left > inst->min_time */
188 
189  /*
190  * There's time left in the users session, inform the NAS by including a Session-Timeout
191  * attribute in the reply, or modifying the existing one.
192  */
193  RDEBUG("Login within allowed time-slot, %d seconds left in this session", left);
194 
195  timeout = fr_pair_find_by_num(request->reply->vps, 0, PW_SESSION_TIMEOUT, TAG_ANY);
196  if (timeout) { /* just update... */
197  if (timeout->vp_integer > (unsigned int) left) {
198  timeout->vp_integer = left;
199  }
200  } else {
201  timeout = radius_pair_create(request->reply, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
202  timeout->vp_integer = left;
203  }
204 
205  RDEBUG("reply:Session-Timeout set to %d", left);
206 
207  return RLM_MODULE_OK;
208 }
209 
210 
211 /*
212  * Do any per-module initialization that is separate to each
213  * configured instance of the module. e.g. set up connections
214  * to external databases, read configuration files, set up
215  * dictionary entries, etc.
216  *
217  * If configuration information is given in the config section
218  * that must be referenced in later calls, store a handle to it
219  * in *instance otherwise put a null pointer there.
220  */
221 static int mod_instantiate(CONF_SECTION *conf, void *instance)
222 {
223  rlm_logintime_t *inst = instance;
224 
225  if (inst->min_time == 0) {
226  cf_log_err_cs(conf, "Invalid value '0' for minimum_timeout");
227  return -1;
228  }
229 
230  /*
231  * Register a Current-Time comparison function
232  */
233  paircompare_register(fr_dict_attr_by_num(NULL, 0, PW_CURRENT_TIME), NULL, true, timecmp, inst);
234  paircompare_register(fr_dict_attr_by_num(NULL, 0, PW_TIME_OF_DAY), NULL, true, time_of_day, inst);
235 
236  return 0;
237 }
238 
239 /*
240  * The module name should be the only globally exported symbol.
241  * That is, everything else should be 'static'.
242  *
243  * If the module needs to temporarily modify it's instantiation
244  * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
245  * The server will then take care of ensuring that the module
246  * is single-threaded.
247  */
248 extern module_t rlm_logintime;
249 module_t rlm_logintime = {
251  .name = "logintime",
252  .inst_size = sizeof(rlm_logintime_t),
253  .config = module_config,
254  .instantiate = mod_instantiate,
255  .methods = {
258  },
259 };
int timestr_match(char const *, time_t)
Definition: timestr.c:199
int paircompare_register(fr_dict_attr_t const *attribute, fr_dict_attr_t const *from, bool first_only, RAD_COMPARE_FUNC func, void *instance)
Register a function as compare function.
Definition: pair.c:395
The module is OK, continue.
Definition: radiusd.h:91
Metadata exported by the module.
Definition: modules.h:134
7 methods index for postauth section.
Definition: modules.h:48
VALUE_PAIR * radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor)
Create a VALUE_PAIR and add it to a list of VALUE_PAIR s.
Definition: pair.c:704
static const CONF_PARSER module_config[]
Definition: rlm_logintime.c:55
static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
Handle authorization requests using Couchbase document data.
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
static int time_of_day(UNUSED void *instance, REQUEST *req, UNUSED VALUE_PAIR *request, VALUE_PAIR *check, UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
Definition: rlm_logintime.c:81
static float timeout
Definition: radclient.c:43
#define inst
static int timecmp(UNUSED void *instance, REQUEST *req, UNUSED VALUE_PAIR *request, VALUE_PAIR *check, UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
Definition: rlm_logintime.c:64
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
struct rlm_logintime_t rlm_logintime_t
Reject the request (user is locked out).
Definition: radiusd.h:94
module_t rlm_logintime
#define DEBUG(fmt,...)
Definition: log.h:175
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
static rlm_rcode_t CC_HINT(nonnull)
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
32 Bit unsigned integer.
Definition: radius.h:34
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
static rs_t * conf
Definition: radsniff.c:46
Module succeeded without doing anything.
Definition: radiusd.h:96
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
#define TAG_ANY
Definition: pair.h:191
struct timeval timestamp
When we started processing the request.
Definition: radiusd.h:214
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
#define REDEBUG(fmt,...)
Definition: log.h:254
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
uint32_t min_time
Definition: rlm_logintime.c:43
static int mod_instantiate(CONF_SECTION *conf, void *instance)
fr_dict_attr_t const * fr_dict_attr_by_num(fr_dict_t *dict, unsigned int vendor, unsigned int attr)
Lookup a fr_dict_attr_t by its vendor and attribute numbers.
Definition: dict.c:3519
1 methods index for authorize section.
Definition: modules.h:42
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
Definition: missing.c:152
#define RCSID(id)
Definition: build.h:135
#define RDEBUG(fmt,...)
Definition: log.h:243