📄 x99_sync.c
字号:
unsignedx99_get_last_auth_pos(const char *syncdir, const char *username){ int 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, NULL, NULL, &pos); x99_release_sd_lock(lock); return rc ? 0 : pos;}/* * Record the last auth window position (for ewindow2). */intx99_set_last_auth_pos(const char *syncdir, const char *username, unsigned pos){ int rc; char *lock; char challenge[MAX_CHALLENGE_LEN + 1]; int failcount; time_t last_auth; if ((lock = x99_acquire_sd_lock(syncdir, username)) == NULL) return -1; rc = x99_get_sd(syncdir, username, challenge, &failcount, &last_auth, NULL); if (rc == 0) rc = x99_set_sd(syncdir, username, challenge, failcount, last_auth, pos); x99_release_sd_lock(lock); return rc;}/* * Return the failed login count for a user. * Returns 0 on success, non-zero otherwise. */static intx99_get_failcount(const char *syncdir, const char *username, int *failcount){ int rc; char *lock; if ((lock = x99_acquire_sd_lock(syncdir, username)) == NULL) return -1; rc = x99_get_sd(syncdir, username, NULL, failcount, NULL, NULL); x99_release_sd_lock(lock); return rc;}/* * Sync data is kept in a flat file[s], only because it's easy to implement. * It might be worth looking at Berkeley DB, but the flat file implementation * gives maximal concurrency with minimal complexity. Performance will be * better on filesystems like ext2fs, ffs w/ soft updates, etc, due to * the large number of ephemeral dot-files created/destroyed for locking. * * One file per user is created, and we typically expect that each thread * is handling a different user (even if a user is authenticating to * multiple NASs/ports, he can't really authenticate simultaneously to * each -- unless it's an attack), so this should give us maximal * concurrency. * * The file format is 'version:user:challenge:key:failures:last_auth:'. * Version is there to provide easy forward compatibility. The trailing * colon is there for the same reason. Future versions must add data to * the end. The current version is 1. * * For performance enhancements, it might be more worthwhile to look at * caching the inst->pwdfile data. Users who are disabled should also * be cached somehow, to reduce the impact of possible attacks. *//* * x99_acquire_sd_lock() returns NULL on failure, or a char * * which must be passed to x99_release_sd_lock() later. */static char *x99_acquire_sd_lock(const char *syncdir, const char *username){ char *lockfile; int i, fd = -1; struct stat st; /* Verify permissions first. */ if (stat(syncdir, &st) != 0) { x99_log(X99_LOG_ERR, "syncdir %s error: %s", syncdir, strerror(errno)); return NULL; } if (st.st_mode != (S_IFDIR|S_IRUSR|S_IWUSR|S_IXUSR)) { x99_log(X99_LOG_ERR, "x99_acquire_sd_lock: syncdir %s has loose permissions", syncdir); return NULL; } /* We use dotfile locking. */ lockfile = malloc(strlen(syncdir) + strlen(username) + 3); if (!lockfile) { x99_log(X99_LOG_CRIT, "x99_acquire_sd_lock: out of memory"); return NULL; } (void) sprintf(lockfile, "%s/.%s", syncdir, username); /* * Try to obtain exclusive access. 10 should be *plenty* of * iterations, we don't expect concurrent accesses to the same file, * and any accesses should be very quick. This is broken over NFS, * but you shouldn't have this data on NFS anyway. */ for (i = 0; i < 10; ++i) { if ((fd = open(lockfile, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) != -1) { break; } /* break stale locks (older than 60s) */ if (stat(lockfile, &st) == 0) if (st.st_ctime < time(NULL) - 60) (void) unlink(lockfile); usleep(500000); /* 0.5 second */ } if (fd == -1) { x99_log(X99_LOG_ERR, "x99_acquire_sd_lock: unable to acquire lock for [%s]", username); free(lockfile); return NULL; } (void) close(fd); return lockfile;}static voidx99_release_sd_lock(char *lockfile){ (void) unlink(lockfile); free(lockfile);}/* * x99_get_sd() returns 0 on success, non-zero otherwise. * On successful returns, challenge, failures, last_auth, pos are filled in, * if non-NULL. * On unsuccessful returns, challenge, failures, last_auth, pos may be garbage. * challenge should be sized as indicated (if non-NULL). * The caller must have obtained an exclusive lock on the sync file. */static intx99_get_sd(const char *syncdir, const char *username, char challenge[MAX_CHALLENGE_LEN + 1], int *failures, time_t *last_auth, unsigned *pos){ char syncfile[PATH_MAX + 1]; FILE *fp; char syncdata[BUFSIZ]; char *p, *q; unsigned ver = UINT_MAX; (void) snprintf(syncfile, PATH_MAX, "%s/%s", syncdir, username); syncfile[PATH_MAX] = '\0'; /* Open sync file. */ if ((fp = fopen(syncfile, "r")) == NULL) { if (errno != ENOENT) { x99_log(X99_LOG_ERR, "x99_get_sd: unable to open sync file %s: %s", syncfile, strerror(errno)); return -1; } /* * Sync file did not exist. If we can create it, all is well. * Set the challenge to something "impossible". */ if (failures) *failures = 0; return x99_set_sd(syncdir, username, "NEWSTATE", 0, 0, 0); } /* Read sync data. */ if ((fgets(syncdata, sizeof(syncdata), fp) == NULL) || !strlen(syncdata)) { x99_log(X99_LOG_ERR, "x99_get_sd: unable to read sync data from %s: %s", syncfile, strerror(errno)); (void) fclose(fp); return -1; } (void) fclose(fp); p = syncdata; /* Now, parse the sync data. */ /* Get the version. */ if ((q = strchr(p, ':')) == NULL) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data for user %s", username); return -1; } *q++ = '\0'; if ((sscanf(p, "%u", &ver) != 1) || (ver > 2)) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (version) for user %s", username); return -1; } p = q; /* Sanity check the username. */ if ((q = strchr(p, ':')) == NULL) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (username) for user %s", username); return -1; } *q++ = '\0'; if (strcmp(p, username)) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (user mismatch) for user %s", username); return -1; } p = q; /* Get challenge. */ if ((q = strchr(p, ':')) == NULL) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (challenge) for user %s", username); return -1; } *q++ = '\0'; if (strlen(p) > MAX_CHALLENGE_LEN) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (challenge length) for user %s", username); return -1; } if (challenge) strcpy(challenge, p); p = q; /* Eat key. */ if ((p = strchr(p, ':')) == NULL) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (key) for user %s", username); return -1; } p++; /* Get failures. */ if ((q = strchr(p, ':')) == NULL) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (failures) for user %s", username); return -1; } *q++ = '\0'; if (failures && (sscanf(p, "%d", failures) != 1)) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (failures) for user %s", username); return -1; } p = q; /* Get last_auth. */ if ((q = strchr(p, ':')) == NULL) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (last_auth) for user %s", username); return -1; } *q++ = '\0'; if (last_auth && (sscanf(p, "%ld", last_auth) != 1)) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (last_auth) for user %s", username); return -1; } p = q; /* Get last auth position. */ if (pos) { if (ver == 1) { *pos = 0; } else if (sscanf(p, "%u", pos) != 1) { x99_log(X99_LOG_ERR, "x99_get_sd: invalid sync data (win. pos) for user %s", username); return -1; } } return 0;}/* * See x99_get_sd(). * The caller must have obtained an exclusive lock on the sync file. */static intx99_set_sd(const char *syncdir, const char *username, const char *challenge, int failures, time_t last_auth, unsigned pos){ char syncfile[PATH_MAX + 1]; FILE *fp; (void) snprintf(syncfile, PATH_MAX, "%s/%s", syncdir, username); syncfile[PATH_MAX] = '\0'; if ((fp = fopen(syncfile, "w")) == NULL) { x99_log(X99_LOG_ERR, "x99_set_sd: unable to open sync file %s: %s", syncfile, strerror(errno)); return -1; } /* Write our (version 2) sync data. */ (void) fprintf(fp, "2:%s:%s:%s:%d:%ld:%u:\n", username, challenge, "", failures, last_auth, pos); if (fclose(fp) != 0) { x99_log(X99_LOG_ERR, "x99_set_sd: unable to write sync file %s: %s", syncfile, strerror(errno)); return -1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -