static void _rs_rekey(unsigned char *dat, size_t datlen) { #ifndef KEYSTREAM_ONLY pure_memzero(rs_buf, RSBUFSZ); #endif /* fill rs_buf with the keystream */ chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ); /* mix in optional user provided data */ if (dat != NULL) { size_t i, m; if (datlen < KEYSZ + IVSZ) { m = datlen; } else { m = KEYSZ + IVSZ; } for (i = 0; i < m; i++) { rs_buf[i] ^= dat[i]; } } /* immediately reinit for backtracking resistance */ _rs_init(rs_buf, KEYSZ + IVSZ); pure_memzero(rs_buf, KEYSZ + IVSZ); rs_have = RSBUFSZ - KEYSZ - IVSZ; }
static void _rs_stir(void) { unsigned char rnd[KEYSZ + IVSZ]; if (!rs_initialized) { random_data_source_fd = _rs_random_dev_open(); } if (random_data_source_fd != -1) { safe_read(random_data_source_fd, rnd, sizeof rnd); } else { #ifdef HAVE_RANDOM_DEV _exit(1); #else size_t i = (size_t) 0U; # ifdef HAVE_ARC4RANDOM crypto_uint4 r; do { r = arc4random(); memcpy(&rnd[i], &r, (size_t) 4U); i += (size_t) 4U; } while (i < sizeof(rnd)); # elif defined(HAVE_RANDOM) unsigned short r; do { r = (unsigned short) random(); rnd[i++] = r & 0xFF; rnd[i++] = (r << 8) & 0xFF; } while (i < sizeof(rnd)); # else unsigned char r; do { r = (unsigned char) rand(); rnd[i++] = r; } while (i < sizeof(rnd)); # endif #endif } if (!rs_initialized) { rs_initialized = 1; _rs_init(rnd, sizeof rnd); } else { _rs_rekey(rnd, sizeof rnd); } pure_memzero(rnd, sizeof rnd); /* invalidate rs_buf */ rs_have = 0; pure_memzero(rs_buf, RSBUFSZ); rs_count = 1600000; }
static char *do_get_passwd(void) { static char pwd[LINE_MAX]; char pwd2[LINE_MAX]; int tries = MAX_PASSWD_CHANGE_TRIES; *pwd = 0; *pwd2 = 0; again: printf("Password: "******"\nEnter it again: "); fflush(stdout); disable_echo(); if (fgets(pwd2, (int) (sizeof pwd2 - 1U), stdin) == NULL) { enable_echo(); return NULL; } strip_lf(pwd2); puts(""); if (strcmp(pwd, pwd2) != 0) { if (*pwd2 != 0) { pure_memzero(pwd2, strlen(pwd2)); } if (*pwd != 0) { pure_memzero(pwd, strlen(pwd)); } puts("You didn't enter the same password"); if (--tries > 0) { goto again; } enable_echo(); return NULL; } if (*pwd2 != 0) { pure_memzero(pwd2, strlen(pwd2)); } enable_echo(); return pwd; }
static void _rs_random_buf(void *_buf, size_t n) { unsigned char *buf = (unsigned char *)_buf; size_t m; _rs_stir_if_needed(n); while (n > 0) { if (rs_have > 0) { if (n < rs_have) { m = n; } else { m = rs_have; } memcpy(buf, rs_buf + RSBUFSZ - rs_have, m); pure_memzero(rs_buf + RSBUFSZ - rs_have, m); buf += m; n -= m; rs_have -= m; } if (rs_have == 0) { _rs_rekey(NULL, 0); } } }
static inline void _rs_random_u32(crypto_uint4 *val) { _rs_stir_if_needed(sizeof(*val)); if (rs_have < sizeof(*val)) { _rs_rekey(NULL, 0); } memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val)); pure_memzero(rs_buf + RSBUFSZ - rs_have, sizeof(*val)); rs_have -= sizeof(*val); }
static int do_usermod(const char * const file, const PWInfo *pwinfo, const unsigned long max_concurrent_logins, const unsigned long long max_auth_memory) { char *file2; FILE *fp2; PWInfo fetched_info; static char line[LINE_MAX]; if (pwinfo->login == NULL || *(pwinfo->login) == 0) { fprintf(stderr, "Missing login\n"); return PW_ERROR_MISSING_LOGIN; } if (file == NULL) { fprintf(stderr, "Missing passwd file\n"); return PW_ERROR_MISSING_PASSWD_FILE; } if (fetch_pw_account(file, &fetched_info, line, sizeof line, pwinfo->login) != 0) { fprintf(stderr, "Unable to fetch info about user [%s] in file [%s]\n", pwinfo->login, file); return PW_ERROR_UNABLE_TO_FETCH; } if (pwinfo->pwd != NULL) { char *cleartext = pwinfo->pwd; fetched_info.pwd = best_crypt(cleartext, max_concurrent_logins, max_auth_memory); if (*cleartext != 0) { pure_memzero(cleartext, strlen(cleartext)); } } if (pwinfo->uid > (uid_t) 0) { fetched_info.uid = pwinfo->uid; } if (pwinfo->gid > (gid_t) 0) { fetched_info.gid = pwinfo->gid; } if (pwinfo->home != NULL) { fetched_info.home = pwinfo->home; } if (pwinfo->gecos != NULL) { fetched_info.gecos = pwinfo->gecos; } if (pwinfo->has_bw_dl != 0) { if (pwinfo->has_bw_dl < 0) { fetched_info.has_bw_dl = 0; } else { fetched_info.has_bw_dl = pwinfo->has_bw_dl; fetched_info.bw_dl = pwinfo->bw_dl; } } if (pwinfo->has_bw_ul != 0) { if (pwinfo->has_bw_ul < 0) { fetched_info.has_bw_ul = 0; } else { fetched_info.has_bw_ul = pwinfo->has_bw_ul; fetched_info.bw_ul = pwinfo->bw_ul; } } if (pwinfo->has_quota_files != 0) { if (pwinfo->has_quota_files < 0) { fetched_info.has_quota_files = 0; } else { fetched_info.has_quota_files = pwinfo->has_quota_files; fetched_info.quota_files = pwinfo->quota_files; } } if (pwinfo->has_quota_size != 0) { if (pwinfo->has_quota_size < 0) { fetched_info.has_quota_size = 0; } else { fetched_info.has_quota_size = pwinfo->has_quota_size; fetched_info.quota_size = pwinfo->quota_size; } } if (pwinfo->has_ul_ratio != 0) { if (pwinfo->has_ul_ratio < 0) { fetched_info.has_ul_ratio = 0; } else { fetched_info.has_ul_ratio = pwinfo->has_ul_ratio; fetched_info.ul_ratio = pwinfo->ul_ratio; } } if (pwinfo->has_dl_ratio != 0) { if (pwinfo->has_dl_ratio < 0) { fetched_info.has_dl_ratio = 0; } else { fetched_info.has_dl_ratio = pwinfo->has_dl_ratio; fetched_info.dl_ratio = pwinfo->dl_ratio; } } if (pwinfo->allow_local_ip != NULL) { fetched_info.allow_local_ip = pwinfo->allow_local_ip; } if (pwinfo->deny_local_ip != NULL) { fetched_info.deny_local_ip = pwinfo->deny_local_ip; } if (pwinfo->allow_client_ip != NULL) { fetched_info.allow_client_ip = pwinfo->allow_client_ip; } if (pwinfo->deny_client_ip != NULL) { fetched_info.deny_client_ip = pwinfo->deny_client_ip; } if (pwinfo->has_time != 0) { if (pwinfo->has_time < 0) { fetched_info.has_time = 0; } else { fetched_info.has_time = pwinfo->has_time; } fetched_info.time_begin = pwinfo->time_begin; fetched_info.time_end = pwinfo->time_end; } if (pwinfo->has_per_user_max != 0) { if (pwinfo->has_per_user_max < 0) { fetched_info.has_per_user_max = 0; } else { fetched_info.has_per_user_max = pwinfo->has_per_user_max; fetched_info.per_user_max = pwinfo->per_user_max; } } if ((file2 = newpasswd_filename(file)) == NULL) { no_mem(); } if ((fp2 = create_newpasswd(file, file2, pwinfo->login, 0, 1)) == NULL) { fprintf(stderr, "Error.\n" "Check that [%s] already exists,\n" "and that [%s] can be written.\n", pwinfo->login, file2); free(file2); return PW_ERROR_USER_ALREADY_EXIST; } if (add_new_pw_line(fp2, &fetched_info) != 0) { fprintf(stderr, "Unable to append a line\n"); goto bye; } fflush(fp2); #ifdef HAVE_FILENO fsync(fileno(fp2)); #endif if (fclose(fp2) != 0) { perror("Unable to close the file"); goto bye2; } if (rename(file2, file) != 0) { perror("Unable to rename the file"); goto bye2; } free(file2); return 0; bye: fclose(fp2); bye2: unlink(file2); free(file2); return PW_ERROR_UNEXPECTED_ERROR; }
static int do_useradd(const char * const file, const PWInfo * const pwinfo_, const unsigned long max_concurrent_logins, const unsigned long long max_auth_memory) { char *file2; FILE *fp2; PWInfo pwinfo = *pwinfo_; if (pwinfo.login == NULL || *(pwinfo.login) == 0) { fprintf(stderr, "Missing login\n"); return PW_ERROR_MISSING_LOGIN; } if (file == NULL) { fprintf(stderr, "Missing passwd file\n"); return PW_ERROR_MISSING_PASSWD_FILE; } #ifndef ACCEPT_ROOT_VIRTUAL_USERS if (pwinfo.uid <= (uid_t) 0 || pwinfo.gid <= (gid_t) 0) { fprintf(stderr, "You must give (non-root) uid and gid\n"); return PW_ERROR_USERADD_NOT_ROOT; } #endif if (pwinfo.home == NULL) { fprintf(stderr, "Missing home directory\n"); return PW_ERROR_USERADD_MISSING_HOME_DIR; } if (pwinfo.gecos == NULL) { if ((pwinfo.gecos = strdup("")) == NULL) { no_mem(); } } if ((pwinfo.pwd = do_get_passwd()) == NULL) { fprintf(stderr, "Error with entering password - aborting\n"); return PW_ERROR_ENTER_PASSWD_PW_ERROR; } { char *cleartext = pwinfo.pwd; pwinfo.pwd = best_crypt(cleartext, max_concurrent_logins, max_auth_memory); if (*cleartext != 0) { pure_memzero(cleartext, strlen(cleartext)); } } if ((file2 = newpasswd_filename(file)) == NULL) { no_mem(); } if ((fp2 = create_newpasswd(file, file2, pwinfo.login, 1, 0)) == NULL) { fprintf(stderr, "Error.\n" "Check that [%s] doesn't already exist,\n" "and that [%s] can be written.\n", pwinfo.login, file2); free(file2); return PW_ERROR_USER_ALREADY_EXIST; } if (add_new_pw_line(fp2, &pwinfo) != 0) { fprintf(stderr, "Unable to append a line\n"); goto bye; } fflush(fp2); #ifdef HAVE_FILENO fsync(fileno(fp2)); #endif if (fclose(fp2) != 0) { perror("Unable to close the file"); goto bye2; } if (rename(file2, file) != 0) { perror("Unable to rename the file"); goto bye2; } free(file2); return 0; bye: fclose(fp2); bye2: unlink(file2); free(file2); return PW_ERROR_UNEXPECTED_ERROR; }