int pefs_keyparam_setfile(struct pefs_keyparam *kp, const char **files, const char *arg) { int *countp; if (files == kp->kp_keyfile) countp = &kp->kp_keyfile_count; else if (files == kp->kp_passfile) countp = &kp->kp_passfile_count; else { pefs_warn("internal error. invalid key parameters file type"); return (PEFS_ERR_INVALID); } if (arg == NULL || arg[0] == '\0') { pefs_warn("invalid key file"); return (PEFS_ERR_INVALID); } if (*countp == PEFS_KEYPARAM_FILES_MAX) { pefs_warn("key file limit exceed, %d max", PEFS_KEYPARAM_FILES_MAX); return (PEFS_ERR_INVALID); } files[(*countp)++] = arg; return (0); }
static int pam_pefs_delkeys(const char *homedir) { struct pefs_xkey k; int fd; fd = open(homedir, O_RDONLY); if (fd == -1) { pefs_warn("cannot open homedir %s: %s", homedir, strerror(errno)); return (PAM_USER_UNKNOWN); } bzero(&k, sizeof(k)); while (1) { if (ioctl(fd, PEFS_GETKEY, &k) == -1) break; if (ioctl(fd, PEFS_DELKEY, &k) == -1) { pefs_warn("cannot del key: %s: %s", homedir, strerror(errno)); k.pxk_index++; } } close(fd); return (PAM_SUCCESS); }
int pefs_keyparam_setiterations(struct pefs_keyparam *kp, const char *arg) { kp->kp_iterations = atoi(arg); if (kp->kp_iterations < 0) { pefs_warn("invalid iterations number: %s", arg); return (PEFS_ERR_INVALID); } return (0); }
static int pam_pefs_addkeys(const char *homedir, struct pefs_keychain_head *kch) { struct pefs_keychain *kc; int fd; fd = open(homedir, O_RDONLY); if (fd == -1) { pefs_warn("cannot open homedir %s: %s", homedir, strerror(errno)); return (PAM_USER_UNKNOWN); } TAILQ_FOREACH(kc, kch, kc_entry) { if (ioctl(fd, PEFS_ADDKEY, &kc->kc_key) == -1) { pefs_warn("cannot add key: %s: %s", homedir, strerror(errno)); break; } } close(fd); return (PAM_SUCCESS); }
int pefs_keyparam_setalg(struct pefs_keyparam *kp, const char *algname) { struct algorithm *alg; for (alg = algs; alg->name != NULL; alg++) { if (strcmp(algname, alg->name) == 0) { kp->kp_alg = alg->id; kp->kp_keybits = alg->keybits; return (0); } } pefs_warn("invalid algorithm %s", algname); return (PEFS_ERR_INVALID); }
static int pefs_keyparam_handle(struct pefs_keyparam *kp, int ind, const char *param) { int err; if (*param == '\0') return (0); switch (ind) { case PEFS_KEYCONF_ALG_IND: err = pefs_keyparam_setalg(kp, param); break; case PEFS_KEYCONF_ITERATIONS_IND: err = pefs_keyparam_setiterations(kp, param); break; default: pefs_warn("invalid configuration option at position %d: %s", ind + 1, param); err = PEFS_ERR_USAGE; } return (err); }
static int flopen_retry(const char *filename) { int fd, try; for (try = 1; try <= 1024; try *= 2) { fd = flopen(filename, PEFS_SESSION_FILE_FLAGS, PEFS_SESSION_FILE_MODE); if (fd != -1) return (fd); else if (errno != EWOULDBLOCK) return (-1); // Exponential back-off up to 1 second usleep(try * 1000000 / 1024); } errno = ETIMEDOUT; return (-1); } static int pefs_session_count_incr(const char *user, bool incr) { struct stat sb; struct timespec tp_uptime, tp_now; ssize_t offset; int fd, total = 0; char filename[MAXPATHLEN], buf[16]; const char *errstr; snprintf(filename, sizeof(filename), "%s/%s", PEFS_SESSION_DIR, user); if (lstat(PEFS_SESSION_DIR, &sb) == -1) { if (errno != ENOENT) { pefs_warn("unable to access session directory %s: %s", PEFS_SESSION_DIR, strerror(errno)); return (-1); } if (mkdir(PEFS_SESSION_DIR, PEFS_SESSION_DIR_MODE) == -1) { pefs_warn("unable to create session directory %s: %s", PEFS_SESSION_DIR, strerror(errno)); return (-1); } } else if (!S_ISDIR(sb.st_mode)) { pefs_warn("%s is not a directory", PEFS_SESSION_DIR); return (-1); } if ((fd = flopen_retry(filename)) == -1) { pefs_warn("unable to create session counter file %s: %s", filename, strerror(errno)); return (-1); } if ((offset = pread(fd, buf, sizeof(buf) - 1, 0)) == -1) { pefs_warn("unable to read from the session counter file %s: %s", filename, strerror(errno)); close(fd); return (-1); } buf[offset] = '\0'; if (offset != 0) { total = strtonum(buf, 0, INT_MAX, &errstr); if (errstr != NULL) pefs_warn("corrupted session counter file: %s: %s", filename, errstr); } /* * Determine if this is the first increment of the session file. * * It is considered the first increment if the session file has not * been modified since the last boot time. */ if (incr && total > 0) { if (fstat(fd, &sb) == -1) { pefs_warn("unable to access session counter file %s: %s", filename, strerror(errno)); close(fd); return (-1); } /* * Check is messy and will fail if wall clock isn't monotonical * (e.g. because of ntp, DST, leap seconds) */ clock_gettime(CLOCK_REALTIME_FAST, &tp_now); clock_gettime(CLOCK_UPTIME_FAST, &tp_uptime); if (sb.st_mtime < tp_now.tv_sec - tp_uptime.tv_sec) { pefs_warn("stale session counter file: %s", filename); total = 0; } } lseek(fd, 0L, SEEK_SET); ftruncate(fd, 0L); total += incr ? 1 : -1; if (total < 0) { pefs_warn("corrupted session counter file: %s", filename); total = 0; } else pefs_warn("%s: session count %d", user, total); buf[0] = '\0'; snprintf(buf, sizeof(buf), "%d", total); pwrite(fd, buf, strlen(buf), 0); close(fd); return (total); } static int pam_pefs_checkfs(const char *homedir) { char fsroot[MAXPATHLEN]; int error; error = pefs_getfsroot(homedir, 0, fsroot, sizeof(fsroot)); if (error != 0) { pefs_warn("file system is not mounted: %s", homedir); return (PAM_USER_UNKNOWN); } if (strcmp(fsroot, homedir) != 0) { pefs_warn("file system is not mounted on home dir: %s", fsroot); return (PAM_USER_UNKNOWN); } return (PAM_SUCCESS); }