📄 x99_sync.c
字号:
/* * x99_sync.c * $Id: x99_sync.c,v 1.16 2003/01/10 07:04:08 fcusack Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2001,2002 Google, Inc. */#ifdef FREERADIUS#include "radiusd.h"#endif#include "x99.h"#include "x99_sync.h"#include <errno.h>#include <limits.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <openssl/des.h> /* des_cblock */static const char rcsid[] = "$Id: x99_sync.c,v 1.16 2003/01/10 07:04:08 fcusack Exp $";/* * Sync data fields changed slightly between v1 and v2, and were renamed. * These routines, however, retain the v1 names. The name:field mapping is: * *_last_auth: last_auth_t last authentication time * *_failcount: last_auth_s number of consecutive auth failures * *_last_auth_pos: last_auth_p window pos. of last auth (not in v1) *//* * Get sync data for a given user. * Returns 0 on success, non-zero otherwise. * * syncdir: duh * username: duh * card_id: duh * ewin: event window position (0 == now) * twin: time window position (0 == now) (NOT IMPLEMENTED) * challenge: On successful return it will be filled in with the challenge * expected for the given window slot. On unsuccesful return, * challenge may be overwritten and contain garbage. * If ewin == 0, the stored "ewin 0" value is returned. * If ewin > 0 and challenge points to a non-empty string, it * will be taken as the challenge for (ewin - 1). That is, * ewin will not be used to calculate the next challenge; * instead the passed in challenge is run through the sync * calculation once to arrive at the next challenge. This * speeds things up since we don't have to iterate ewin times. * If ewin > 0 and challenge points to an empty string, the * stored "ewin 0" challenge value is run through the sync * calculation ewin times. * keyblock: Similar to challenge. It may be updated for key changing * sync modes. (NOT IMPLEMENTED) */intx99_get_sync_data(const char *syncdir, const char *username, uint32_t card_id, int ewin, int twin, char challenge[MAX_CHALLENGE_LEN + 1], des_cblock keyblock){ /* ARGSUSED */ des_cblock output; int i, rc = -1; char *lock; if (ewin == 0) { if ((lock = x99_acquire_sd_lock(syncdir, username)) == NULL) return -1; rc = x99_get_sd(syncdir, username, challenge, NULL, NULL, NULL); x99_release_sd_lock(lock); return rc; } else if (challenge[0]) { ewin = 1; /* only iterate once */ } else { /* The hard way. Get the zeroeth challenge. */ rc = x99_get_sync_data(syncdir, username, card_id, 0, twin, challenge, keyblock); if (rc) return rc; } while (ewin--) { if (card_id & X99_CF_CRYPTOCARD) { if ((rc = x99_mac(challenge, output, keyblock)) == 0) { for (i = 0; i < 8; ++i) { output[i] &= 0x0f; if (output[i] > 9) output[i] -= 10; output[i] |= 0x30; } (void) memcpy(challenge, output, 8); challenge[8] = '\0'; } else { break; } } else { /* No other vendors implemented yet. */ rc = -1; break; } } return rc;}/* * Set sync data for a given user. * Returns 0 on success, non-zero otherwise. * Side effects: * - Resets failure count to 0 on successful return. * - Sets last auth time to "now" on successful return. * - Sets last auth window position to 0. * Because of the failure count reset, this should only be called for/after * successful authentications. * * username: duh * challenge: The challenge to be stored. * keyblock: The key to be stored. This is for sync modes in which the * key changes for successive challenges. (NOT IMPLEMENTED) */intx99_set_sync_data(const char *syncdir, const char *username, const char *challenge, const des_cblock keyblock){ /* ARGSUSED */ int rc; char *lock; if ((lock = x99_acquire_sd_lock(syncdir, username)) == NULL) return -1; rc = x99_set_sd(syncdir, username, challenge, 0, time(NULL), 0); x99_release_sd_lock(lock); return rc;}/* * Return the last time the user authenticated. * Returns 0 on success, non-zero otherwise. */intx99_get_last_auth(const char *syncdir, const char *username, time_t *last_auth){ int rc; char *lock; if ((lock = x99_acquire_sd_lock(syncdir, username)) == NULL) return -1; rc = x99_get_sd(syncdir, username, NULL, NULL, last_auth, NULL); x99_release_sd_lock(lock); return rc;}/* * Set the last auth time for a user to "now". * Returns 0 on success, non-zero otherwise. * Note that x99_set_sync_data() also resets the auth time. * This function is no longer called, (the failcount() routines do this work), * but I'm saving it here for reference. */intx99_upd_last_auth(const char *syncdir, const char *username){ int failcount, rc; char *lock; char challenge[MAX_CHALLENGE_LEN + 1]; unsigned pos; if ((lock = x99_acquire_sd_lock(syncdir, username)) == NULL) return -1; rc = x99_get_sd(syncdir, username, challenge, &failcount, NULL, &pos); if (rc == 0) rc = x99_set_sd(syncdir, username, challenge, failcount, time(NULL), pos); x99_release_sd_lock(lock); return rc;}/* * Atomically increment a user's failed login count. * Also updates last_auth. */intx99_incr_failcount(const char *syncdir, const char *username){ int failcount, rc; char *lock; char challenge[MAX_CHALLENGE_LEN + 1]; unsigned pos; if ((lock = x99_acquire_sd_lock(syncdir, username)) == NULL) return -1; /* Get current value. */ rc = x99_get_sd(syncdir, username, challenge, &failcount, NULL, &pos); if (rc == 0) { /* Increment. */ if (++failcount == INT_MAX) failcount--; rc = x99_set_sd(syncdir, username, challenge, failcount, time(NULL), pos); } x99_release_sd_lock(lock); return rc;}/* * Reset failure count to 0. Also updates last_auth and resets pos. * Returns 0 on success, non-zero otherwise. * This is almost just like x99_incr_failcount(). * x99_set_sync_data() resets the failcount also, but that's because * we keep the failcount and other sync data together; we don't want * to necessarily make that visible to our callers (x99_rlm.c). */intx99_reset_failcount(const char *syncdir, const char *username){ int rc; char *lock; char challenge[MAX_CHALLENGE_LEN + 1]; if ((lock = x99_acquire_sd_lock(syncdir, username)) == NULL) return -1; rc = x99_get_sd(syncdir, username, challenge, NULL, NULL, NULL); if (rc == 0) rc = x99_set_sd(syncdir, username, challenge, 0, time(NULL), 0); x99_release_sd_lock(lock); return rc;}/* * checks the failure counter. * returns 0 if the user is allowed to authenticate, < 0 otherwise: * FAIL_ERR if the user is failed due to internal error, * FAIL_HARD if the user is failed "hard", * FAIL_SOFT if the user is failed "soft". * caller does not need to log failures, we do it (in order to be specific). */intx99_check_failcount(const char *username, const x99_token_t *inst){ time_t last_auth; int failcount; if (x99_get_last_auth(inst->syncdir, username, &last_auth) != 0) { x99_log(X99_LOG_ERR, "auth: unable to get last auth time for [%s]", username); return FAIL_ERR; } if (x99_get_failcount(inst->syncdir, username, &failcount) != 0) { x99_log(X99_LOG_ERR, "auth: unable to get failure count for [%s]", username); return FAIL_ERR; } /* Check against hardfail setting. */ if (inst->hardfail && failcount >= inst->hardfail) { x99_log(X99_LOG_AUTH, "auth: %d/%d failed/max authentications for [%s]", failcount, inst->hardfail, username); if (x99_incr_failcount(inst->syncdir, username) != 0) { x99_log(X99_LOG_ERR, "auth: unable to increment failure count for " "locked out user [%s]", username); } return FAIL_HARD; } /* Check against softfail setting. */ if (inst->softfail && failcount >= inst->softfail) { time_t when; int fcount; /* * Determine the next time this user can authenticate. * * Once we hit softfail, we introduce a 1m delay before the user * can authenticate. For each successive failed authentication, * we double the delay time, up to a max of 32 minutes. While in * the "delay mode" of operation, all authentication ATTEMPTS are * considered failures (we don't test if the password is correct). * Also, each attempt during the delay period restarts the clock. * * The advantage of a delay instead of a simple lockout is that an * attacker can't lock out a user as easily; the user need only wait * a bit before he can authenticate. */ fcount = failcount - inst->softfail; when = last_auth + (fcount > 5 ? 32 * 60 : (1 << fcount) * 60); if (time(NULL) < when) { x99_log(X99_LOG_AUTH, "auth: user [%s] auth too soon while delayed, " "%d/%d failed/softfail authentications", username, failcount, inst->softfail); if (x99_incr_failcount(inst->syncdir, username) != 0) { x99_log(X99_LOG_ERR, "auth: unable to increment failure count for " "delayed user [%s]", username); } return FAIL_SOFT; } } return 0;}/* * Get the last auth window position for ewindow2. * Returns 0 on failure (caller cannot distinguish between failure and * a 0 position). */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -