~ubuntu-branches/ubuntu/natty/freeradius/natty-updates

« back to all changes in this revision

Viewing changes to src/modules/rlm_otp/otp_cardops.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Hampson
  • Date: 2006-01-15 13:34:13 UTC
  • mto: (3.1.3 dapper) (4.1.3 sid) (1.1.14 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060115133413-zo1dslttvdoalqym
Tags: upstream-1.1.0
ImportĀ upstreamĀ versionĀ 1.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * otp_cardops.c
 
3
 * $Id: otp_cardops.c,v 1.62.2.1 2005/12/08 01:30:50 fcusack Exp $
 
4
 *
 
5
 * Passcode verification functions for otp.
 
6
 *
 
7
 *   This program is free software; you can redistribute it and/or modify
 
8
 *   it under the terms of the GNU General Public License as published by
 
9
 *   the Free Software Foundation; either version 2 of the License, or
 
10
 *   (at your option) any later version.
 
11
 *
 
12
 *   This program is distributed in the hope that it will be useful,
 
13
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 *   GNU General Public License for more details.
 
16
 *
 
17
 *   You should have received a copy of the GNU General Public License
 
18
 *   along with this program; if not, write to the Free Software
 
19
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
20
 *
 
21
 *
 
22
 * Copyright 2002-2005  Google, Inc.
 
23
 * Copyright 2005 TRI-D Systems, Inc.
 
24
 */
 
25
 
 
26
static const char rcsid[] = "$Id: otp_cardops.c,v 1.62.2.1 2005/12/08 01:30:50 fcusack Exp $";
 
27
 
 
28
#if defined(__linux__) && !defined(_GNU_SOURCE)
 
29
#define _GNU_SOURCE     /* RTLD_DEFAULT */
 
30
#endif
 
31
#include <dlfcn.h>
 
32
#include <inttypes.h>
 
33
#include <limits.h>
 
34
#include <stdlib.h>
 
35
#include <string.h>
 
36
#include <time.h>
 
37
 
 
38
#include "otp.h"
 
39
#include "otp_cardops.h"
 
40
 
 
41
/* Global data */
 
42
cardops_t otp_cardops[OTP_MAX_VENDORS]; /* cardops objects */
 
43
int otp_num_cardops = 0;                /* number of cardops modules loaded */
 
44
 
 
45
 
 
46
/*
 
47
 * Test for passcode validity.
 
48
 *
 
49
 * If challenge is supplied, it is used to generate the card response
 
50
 * against which the passcode will be compared.  If challenge is not
 
51
 * supplied, or if the comparison fails, synchronous responses are
 
52
 * generated and tested.  NOTE: for async authentications, sync mode
 
53
 * responses are still considered valid!  (Assuming module configuration
 
54
 * allows sync mode.)
 
55
 *
 
56
 * If passcode is supplied, a simple string comparison is done, else if
 
57
 * cmp is supplied, it is called to test for validity.  The cmp function
 
58
 * is required for RADIUS, where we might have a CHAP response instead
 
59
 * of the plaintext of the passcode from the user.
 
60
 *
 
61
 * If challenge is supplied, then resync is used to determine if the card
 
62
 * should be resynced or if this is a one-off response.  (If challenge is
 
63
 * not supplied, this is sync mode response and the card is always resynced.)
 
64
 *
 
65
 * Returns one of the OTP_RC_* return codes.  challenge is overwritten.
 
66
 */
 
67
int
 
68
otp_pw_valid(const char *username, char *challenge, const char *passcode,
 
69
             int resync, const otp_option_t *opt,
 
70
             cmpfunc_t cmpfunc, void *data,
 
71
             const char *log_prefix)
 
72
{
 
73
  int   rc, nmatch, i;
 
74
  int   e = 0, t = 0;   /* must initialize for async auth path */
 
75
  int   fc;             /* failcondition */
 
76
 
 
77
        /* expected response */
 
78
  char  e_response[OTP_MAX_RESPONSE_LEN + OTP_MAX_PIN_LEN + 1];
 
79
  int   pin_offset = 0; /* pin offset in e_response (prepend or append) */
 
80
 
 
81
  otp_card_info_t       card_info  = { .cardops = NULL };
 
82
  otp_user_state_t      user_state = { .locked = 0 };
 
83
 
 
84
  time_t now = time(NULL);
 
85
 
 
86
  /*
 
87
   * In the Cyclades ACS environment (2.3.0 tested), the runtime linker
 
88
   * apparently does not run static constructors in ELF .ctors sections.
 
89
   * Since that is how we initialize cardops modules, we have an ugly
 
90
   * workaround here.  Our other choice is to implement cardops modules
 
91
   * as full-fledged shared libraries, which is just too much work.
 
92
   */
 
93
  if (otp_num_cardops == 0) {
 
94
    void (*cardops_init)(void);
 
95
 
 
96
    /* ctors did not run; execute all known constructors */
 
97
    if ((cardops_init = dlsym(RTLD_DEFAULT, "cryptocard_init")))
 
98
      (*cardops_init)();
 
99
    if ((cardops_init = dlsym(RTLD_DEFAULT, "trid_init")))
 
100
      (*cardops_init)();
 
101
  }
 
102
 
 
103
  /* sanity */
 
104
  if (!challenge) {
 
105
    rc = OTP_RC_SERVICE_ERR;
 
106
    goto auth_done_service_err;
 
107
  }
 
108
  if (!passcode && !cmpfunc) {
 
109
    otp_log(OTP_LOG_CRIT, "%s: %s: Can't test passcode validity!",
 
110
            log_prefix, __func__);
 
111
    rc = OTP_RC_SERVICE_ERR;
 
112
    goto auth_done_service_err;
 
113
  }
 
114
 
 
115
  /* Look up user info.  (errors are logged by the function) */
 
116
  rc = otp_get_card_info(opt->pwdfile, username, &card_info, log_prefix);
 
117
  if (rc == -1) {
 
118
    rc = OTP_RC_USER_UNKNOWN;
 
119
    goto auth_done_service_err;
 
120
  } else if (rc == -2) {
 
121
    rc = OTP_RC_AUTHINFO_UNAVAIL;
 
122
    goto auth_done_service_err;
 
123
  }
 
124
  card_info.username = username;
 
125
 
 
126
  /* Find the correct cardops module. */
 
127
  for (i = 0; otp_cardops[i].prefix; i++) {
 
128
    if (!strncasecmp(otp_cardops[i].prefix, card_info.card,
 
129
                     otp_cardops[i].prefix_len)) {
 
130
      card_info.cardops = &otp_cardops[i];
 
131
      break;
 
132
    }
 
133
  }
 
134
  if (!card_info.cardops) {
 
135
    otp_log(OTP_LOG_ERR, "%s: %s: invalid card type '%s' for [%s]",
 
136
            log_prefix, __func__, card_info.card, username);
 
137
    rc = OTP_RC_SERVICE_ERR;
 
138
    goto auth_done_service_err;
 
139
  }
 
140
 
 
141
  /* Convert name to a feature mask once, for fast operations later. */
 
142
  if (card_info.cardops->name2fm(card_info.card, &card_info.featuremask)) {
 
143
    otp_log(OTP_LOG_ERR, "%s: %s: invalid card type '%s' for [%s]",
 
144
            log_prefix, __func__, card_info.card, username);
 
145
    rc = OTP_RC_SERVICE_ERR;
 
146
    goto auth_done_service_err;
 
147
  }
 
148
 
 
149
  /* Convert keystring to a keyblock. */
 
150
  if (card_info.cardops->keystring2keyblock(card_info.keystring,
 
151
                                            card_info.keyblock) < 0) {
 
152
    otp_log(OTP_LOG_ERR, "%s: %s: invalid key '%s' for [%s]",
 
153
            log_prefix, __func__, card_info.keystring, username);
 
154
    rc = OTP_RC_SERVICE_ERR;
 
155
    goto auth_done_service_err;
 
156
  }
 
157
 
 
158
  /* Adjust e_response for PIN prepend. */
 
159
  if (opt->prepend_pin) {
 
160
    (void) strcpy(e_response, card_info.pin);
 
161
    pin_offset = strlen(e_response);
 
162
  }
 
163
 
 
164
  /* Get user state. */
 
165
  if (otp_state_get(opt, username, &user_state, log_prefix) != 0) {
 
166
    otp_log(OTP_LOG_ERR, "%s: %s: unable to get state for [%s]",
 
167
            log_prefix, __func__, username);
 
168
    rc = OTP_RC_SERVICE_ERR;
 
169
    goto auth_done_service_err;
 
170
  }
 
171
  if (user_state.nullstate) {
 
172
    if (card_info.cardops->nullstate(opt, &card_info, &user_state,
 
173
                                     now, log_prefix)) {
 
174
      otp_log(OTP_LOG_ERR, "%s: %s: unable to set null state for [%s]",
 
175
              log_prefix, __func__, username);
 
176
      rc = OTP_RC_SERVICE_ERR;
 
177
      goto auth_done_service_err;
 
178
    }
 
179
  }
 
180
 
 
181
  /* Set fc (failcondition). */
 
182
  if (opt->hardfail && user_state.failcount >= (unsigned) opt->hardfail) {
 
183
    /* NOTE: persistent softfail stops working */
 
184
    fc = OTP_FC_FAIL_HARD;
 
185
  } else if (opt->softfail && user_state.authtime == INT32_MAX) {
 
186
    fc = OTP_FC_FAIL_SOFT;
 
187
  } else if (opt->softfail &&
 
188
             user_state.failcount >= (unsigned) opt->softfail) {
 
189
    uint32_t when;
 
190
    int fcount;
 
191
 
 
192
    /*
 
193
     * Determine the next time this user can authenticate.
 
194
     *
 
195
     * Once we hit softfail, we introduce a 1m delay before the user
 
196
     * can authenticate.  For each successive failed authentication,
 
197
     * we double the delay time, up to a max of 32 minutes.  While in
 
198
     * the "delay mode" of operation, all authentication ATTEMPTS are
 
199
     * considered failures.  Also, each attempt during the delay period
 
200
     * restarts the clock.
 
201
     *
 
202
     * The advantage of a delay instead of a simple lockout is that an
 
203
     * attacker can't lock out a user as easily; the user need only wait
 
204
     * a bit before he can authenticate.
 
205
     *
 
206
     * Note that if the user waits for the delay period to expire, he
 
207
     * is no longer in softfail and can only use ewindow, not rwindow.
 
208
     */
 
209
    fcount = user_state.failcount - opt->softfail;
 
210
    /*
 
211
     * when and authtime are uint32, but time is saved as int32,
 
212
     * so this can't overflow
 
213
     */
 
214
    when = user_state.authtime +
 
215
           (fcount > 5 ? 32 * 60 : (1 << fcount) * 60);
 
216
    if ((uint32_t) now < when)
 
217
      fc = OTP_FC_FAIL_SOFT;
 
218
    else
 
219
      fc = OTP_FC_FAIL_NONE;
 
220
  } else {
 
221
    fc = OTP_FC_FAIL_NONE;
 
222
  }
 
223
 
 
224
async_response:
 
225
  /*
 
226
   * Test async response.
 
227
   */
 
228
  if (*challenge && (card_info.featuremask & OTP_CF_AM) && opt->allow_async) {
 
229
    ssize_t chal_len;
 
230
 
 
231
    /* Perform any site-specific transforms of the challenge. */
 
232
    if ((chal_len = otp_challenge_transform(username,
 
233
                                            challenge, opt->chal_len)) < 0) {
 
234
      otp_log(OTP_LOG_ERR, "%s: %s: challenge transform failed for [%s]",
 
235
              log_prefix, __func__, username);
 
236
      rc = OTP_RC_SERVICE_ERR;
 
237
      goto auth_done_service_err;
 
238
      /* NB: state not updated. */
 
239
    }
 
240
 
 
241
    /* Calculate the async response. */
 
242
    if (card_info.cardops->response(&card_info, challenge, chal_len,
 
243
                                    &e_response[pin_offset],
 
244
                                    log_prefix) != 0) {
 
245
      otp_log(OTP_LOG_ERR,
 
246
              "%s: %s: unable to calculate async response for [%s], "
 
247
              "to challenge %s", log_prefix, __func__, username, challenge);
 
248
      rc = OTP_RC_SERVICE_ERR;
 
249
      goto auth_done_service_err;
 
250
      /* NB: state not updated. */
 
251
    }
 
252
 
 
253
    /* NOTE: We do not display the PIN. */
 
254
    if (opt->debug) {
 
255
      char s[OTP_MAX_CHALLENGE_LEN * 2 + 1];
 
256
 
 
257
      otp_log(OTP_LOG_DEBUG,
 
258
              "%s: %s: [%s], async challenge %s, expecting response %s",
 
259
              log_prefix, __func__, username,
 
260
              card_info.cardops->printchallenge(s, challenge, chal_len),
 
261
              &e_response[pin_offset]);
 
262
    }
 
263
 
 
264
    /* Add PIN if needed. */
 
265
    if (!opt->prepend_pin)
 
266
      (void) strcat(e_response, card_info.pin);
 
267
 
 
268
    /* Test user-supplied passcode. */
 
269
    if (passcode)
 
270
      nmatch = strcmp(passcode, e_response);
 
271
    else
 
272
      nmatch = cmpfunc(data, e_response, log_prefix);
 
273
    if (!nmatch) {
 
274
      if (!opt->allow_async) {
 
275
        otp_log(OTP_LOG_AUTH, "%s: %s: bad async auth for [%s]: "
 
276
                              "valid but disallowed by config",
 
277
                log_prefix, __func__, username);
 
278
        rc = OTP_RC_AUTH_ERR;
 
279
        goto auth_done;
 
280
      }
 
281
      if (fc == OTP_FC_FAIL_HARD) {
 
282
        otp_log(OTP_LOG_AUTH,
 
283
                "%s: %s: bad async auth for [%s]: valid but in hardfail "
 
284
                " (%d/%d failed/max)", log_prefix, __func__, username,
 
285
                user_state.failcount, opt->hardfail);
 
286
        rc = OTP_RC_MAXTRIES;
 
287
        goto auth_done;
 
288
      }
 
289
      if (fc == OTP_FC_FAIL_SOFT) {
 
290
        otp_log(OTP_LOG_AUTH,
 
291
                "%s: %s: bad async auth for [%s]: valid but in softfail "
 
292
                " (%d/%d failed/max)", log_prefix, __func__, username,
 
293
                user_state.failcount, opt->softfail);
 
294
        rc = OTP_RC_MAXTRIES;
 
295
        goto auth_done;
 
296
      }
 
297
#ifdef FREERADIUS
 
298
      if ((uint32_t) now - user_state.authtime < (unsigned) opt->chal_delay) {
 
299
        otp_log(OTP_LOG_AUTH,
 
300
                "%s: %s: bad async auth for [%s]: valid but too soon",
 
301
                log_prefix, __func__, username);
 
302
        rc = OTP_RC_MAXTRIES;
 
303
        goto auth_done;
 
304
      }
 
305
#endif
 
306
 
 
307
      /* Authenticated in async mode. */
 
308
      rc = OTP_RC_OK;
 
309
      /* special log message for sync users */
 
310
      if (card_info.featuremask & OTP_CF_SM)
 
311
        otp_log(OTP_LOG_INFO, "%s: %s: [%s] authenticated in async mode",
 
312
                log_prefix, __func__, username);
 
313
      goto auth_done;
 
314
    } /* if (user authenticated async) */
 
315
  } /* if (async mode possible) */
 
316
 
 
317
sync_response:
 
318
  /*
 
319
   * Calculate and test sync responses in the window.  Note that we
 
320
   * always accept a sync response, even if a challenge or resync was
 
321
   * explicitly requested.
 
322
   *
 
323
   * Note that we always start at the t=0 e=0 window position, even
 
324
   * though we may already know a previous authentication is further
 
325
   * ahead in the window (when in softfail).  This has the effect that
 
326
   * an rwindow softfail override can occur in a sequence like 6,3,4.
 
327
   * That is, the user can always move backwards in the window to
 
328
   * restart the rwindow sequence, as long as they don't go beyond
 
329
   * (prior to) the last successful authentication.
 
330
   */
 
331
  if ((card_info.featuremask & OTP_CF_SM) && opt->allow_sync) {
 
332
    int tend, end, ewindow, rwindow;
 
333
 
 
334
    /* set ending ewin counter */
 
335
    if (card_info.featuremask & OTP_CF_FRW) {
 
336
      /* force rwindow for e+t cards */
 
337
      rwindow = (card_info.featuremask & OTP_CF_FRW) >> OTP_CF_FRW_SHIFT;
 
338
      ewindow = 0; /* quiet compiler */
 
339
    } else {
 
340
      ewindow = opt->ewindow_size;
 
341
      /* Increase window for softfail+rwindow. */
 
342
      if (opt->rwindow_size && fc == OTP_FC_FAIL_SOFT)
 
343
        rwindow = opt->rwindow_size;
 
344
      else
 
345
        rwindow = 0;
 
346
    }
 
347
    end = rwindow ? rwindow : ewindow;
 
348
 
 
349
    /* Setup initial challenge. */
 
350
    (void) memcpy(challenge, user_state.challenge, user_state.clen);
 
351
 
 
352
    /* Test each sync response in the window. */
 
353
    tend = card_info.cardops->maxtwin(&card_info, user_state.csd);
 
354
    for (t = 0; t <= tend; ++t) {
 
355
      for (e = 0; e <= end; ++e) {
 
356
        /* Get next challenge. */
 
357
        rc = card_info.cardops->challenge(&card_info, &user_state, challenge,
 
358
                                          now, t, e, log_prefix);
 
359
        if (rc == -1) {
 
360
          otp_log(OTP_LOG_ERR,
 
361
                  "%s: %s: unable to get sync challenge t:%d e:%d for [%s]",
 
362
                  log_prefix, __func__, t, e, username);
 
363
          rc = OTP_RC_SERVICE_ERR;
 
364
          goto auth_done_service_err;
 
365
          /* NB: state not updated. */
 
366
        } else if (rc == -2) {
 
367
          /*
 
368
           * For event synchronous modes, we can never go backwards (the
 
369
           * challenge() method can only walk forward on the event counter),
 
370
           * so there is an implicit guarantee that we'll never get a
 
371
           * response matching an event in the past.
 
372
           *
 
373
           * But for time synchronous modes, challenge() can walk backwards,
 
374
           * in order to accomodate clock drift.  We must never allow a
 
375
           * successful auth for a correct passcode earlier in time than
 
376
           * one already used successfully, so we skip out early here.
 
377
           */
 
378
          if (opt->debug)
 
379
            otp_log(OTP_LOG_DEBUG,
 
380
                    "%s: %s: [%s], sync challenge t:%d e:%d is early",
 
381
                    log_prefix, __func__, username, t, e);
 
382
          continue;
 
383
        }
 
384
 
 
385
        /* Calculate sync response. */
 
386
        if (card_info.cardops->response(&card_info, challenge, user_state.clen,
 
387
                                        &e_response[pin_offset],
 
388
                                        log_prefix) != 0) {
 
389
          otp_log(OTP_LOG_ERR,
 
390
                  "%s: %s: unable to calculate sync response "
 
391
                  "t:%d e:%d for [%s], to challenge %s",
 
392
                  log_prefix, __func__, t, e, username, challenge);
 
393
          rc = OTP_RC_SERVICE_ERR;
 
394
          goto auth_done_service_err;
 
395
          /* NB: state not updated. */
 
396
        }
 
397
 
 
398
        /* NOTE: We do not display the PIN. */
 
399
        if (opt->debug) {
 
400
          char s[OTP_MAX_CHALLENGE_LEN * 2 + 1];
 
401
 
 
402
          otp_log(OTP_LOG_DEBUG, "%s: %s: [%s], sync challenge t:%d e:%d %s, "
 
403
                                 "expecting response %s",
 
404
                  log_prefix, __func__, username, t, e,
 
405
                  card_info.cardops->printchallenge(s, challenge,
 
406
                                                    user_state.clen),
 
407
                  &e_response[pin_offset]);
 
408
        }
 
409
 
 
410
        /* Add PIN if needed. */
 
411
        if (!opt->prepend_pin)
 
412
          (void) strcat(e_response, card_info.pin);
 
413
 
 
414
        /* Test user-supplied passcode. */
 
415
        if (passcode)
 
416
          nmatch = strcmp(passcode, e_response);
 
417
        else
 
418
          nmatch = cmpfunc(data, e_response, log_prefix);
 
419
        if (!nmatch) {
 
420
          if (fc == OTP_FC_FAIL_HARD) {
 
421
            otp_log(OTP_LOG_AUTH,
 
422
                    "%s: %s: bad sync auth for [%s]: valid but in hardfail "
 
423
                    " (%d/%d failed/max)", log_prefix, __func__, username,
 
424
                    user_state.failcount, opt->hardfail);
 
425
            rc = OTP_RC_MAXTRIES;
 
426
          } else if (fc == OTP_FC_FAIL_SOFT) {
 
427
            /*
 
428
             * rwindow logic
 
429
             */
 
430
            if (!rwindow) {
 
431
              /* rwindow mode not configured */
 
432
              otp_log(OTP_LOG_AUTH,
 
433
                      "%s: %s: bad sync auth for [%s]: valid but in softfail "
 
434
                      " (%d/%d failed/max)", log_prefix, __func__, username,
 
435
                      user_state.failcount, opt->softfail);
 
436
              rc = OTP_RC_MAXTRIES;
 
437
              goto auth_done;
 
438
            }
 
439
 
 
440
            /*
 
441
             * User must enter two consecutive correct sync passcodes
 
442
             * for rwindow softfail override.
 
443
             */
 
444
            if (card_info.cardops->isconsecutive(&card_info, &user_state,
 
445
                                                 e, log_prefix)) {
 
446
              /*
 
447
               * This is the 2nd of two consecutive responses, is it
 
448
               * soon enough?  Note that for persistent softfail we can't
 
449
               * enforce rwindow_delay b/c the previous authtime is also
 
450
               * the persistent softfail sentinel.
 
451
               */
 
452
              if (user_state.authtime == INT32_MAX ||
 
453
                  now - user_state.authtime < (unsigned) opt->rwindow_delay) {
 
454
                otp_log(OTP_LOG_AUTH,
 
455
                        "%s: %s: rwindow softfail override for [%s] at "
 
456
                        "window position t:%d e:%d", log_prefix, __func__,
 
457
                        username, t, e);
 
458
                rc = OTP_RC_OK;
 
459
                goto sync_done;
 
460
              } else {
 
461
                /* consecutive but not soon enough */
 
462
                otp_log(OTP_LOG_AUTH,
 
463
                        "%s: %s: late override for [%s] at "
 
464
                        "window position t:%d e:%d", log_prefix, __func__,
 
465
                        username, t, e);
 
466
                rc = OTP_RC_AUTH_ERR;
 
467
              }
 
468
            } /* if (passcode is consecutive */
 
469
 
 
470
            /* passcode correct, but not consecutive or not soon enough */
 
471
            if (opt->debug)
 
472
              otp_log(OTP_LOG_DEBUG,
 
473
                      "%s: %s: [%s] rwindow candidate "
 
474
                      "at window position t:%d e:%d", log_prefix, __func__,
 
475
                      username, t, e);
 
476
            rc = OTP_RC_AUTH_ERR;
 
477
 
 
478
          } else {
 
479
            /* normal sync mode auth */
 
480
            rc = OTP_RC_OK;
 
481
          } /* else (!hardfail && !softfail) */
 
482
 
 
483
sync_done:
 
484
          /* force resync; this only has an effect if (rc == OTP_RC_OK) */
 
485
          resync = 1;
 
486
          /* update csd (et al.) on successful auth or rwindow candidate */
 
487
          if (card_info.cardops->updatecsd(&user_state, now, t, e, rc) != 0) {
 
488
            otp_log(OTP_LOG_ERR, "%s: %s: unable to update csd for [%s]",
 
489
                    log_prefix, __func__, username);
 
490
            rc = OTP_RC_SERVICE_ERR;
 
491
            goto auth_done_service_err;
 
492
            /* NB: state not updated. */
 
493
          }
 
494
          goto auth_done;
 
495
 
 
496
        } /* if (passcode is valid) */
 
497
      } /* for (each slot in the ewindow) */
 
498
    } /* for (each slot in the twindow) */
 
499
  } /* if (sync mode possible) */
 
500
 
 
501
  /* Both async and sync mode failed. */
 
502
  rc = OTP_RC_AUTH_ERR;
 
503
 
 
504
auth_done:
 
505
  if (rc == OTP_RC_OK) {
 
506
    if (resync)
 
507
      (void) memcpy(user_state.challenge, challenge, user_state.clen);
 
508
    user_state.failcount   = 0;
 
509
    user_state.authtime    = now;
 
510
  } else {
 
511
    if (++user_state.failcount == UINT_MAX)
 
512
      user_state.failcount--;
 
513
    /* authtime set to INT32_MAX by nullstate(); leave it to force softfail */
 
514
    if (user_state.authtime != INT32_MAX)
 
515
      user_state.authtime = (int32_t) now;      /* cast prevents overflow */
 
516
    /*
 
517
     * Note that we don't update the challenge.  Even for softfail (where
 
518
     * we might have actually had a good auth), we want the challenge
 
519
     * unchanged because we always start our sync loop at e=0 t=0 (and so
 
520
     * challenge must stay as the 0'th challenge regardless of next valid
 
521
     * window position, because the challenge() method can't return
 
522
     * arbitrary event window positions--since we start at e=0 the challenge
 
523
     * must be the 0th challenge, i.e. unchanged).
 
524
     */
 
525
  } /* else (rc != OTP_RC_OK) */
 
526
  user_state.updated = 1;
 
527
 
 
528
auth_done_service_err:  /* exit here for system errors */
 
529
  /*
 
530
   * Release and update state.
 
531
   *
 
532
   * We "fail-out" if we can't do this, because for sync mode the
 
533
   * response can be reused until state data is updated, an obvious
 
534
   * replay attack.
 
535
   *
 
536
   * For async mode with RADIUS, if we can't update the last auth
 
537
   * time, we will be open to a less obvious replay attack over the
 
538
   * lifetime of the State attribute (opt->chal_delay): if someone
 
539
   * that can see RADIUS traffic captures an Access-Request containing
 
540
   * a State attribute, and can cause the NAS to cycle the request id
 
541
   * within opt->chal_delay secs, then they can login to the NAS and
 
542
   * insert the captured State attribute into the new Access-Request,
 
543
   * and we'll give an Access-Accept.
 
544
   */
 
545
  if (user_state.locked) {
 
546
    if (otp_state_put(username, &user_state, log_prefix) != 0) {
 
547
      otp_log(OTP_LOG_ERR, "%s: %s: unable to put state for [%s]",
 
548
              log_prefix, __func__, username);
 
549
      rc = OTP_RC_SERVICE_ERR;  /* no matter what it might have been */
 
550
    }
 
551
  }
 
552
 
 
553
  return rc;
 
554
}