Example #1
0
File: mem.c Project: vocho/openqnx
void           *
fr_alloc(FRAME *fr)
{
	FRAME          *p, *c;
	void           *uptr;

	if (fr == 0) {
		return 0;
	}
	for (c = fr, p = 0; c != 0; p = c, c = c->next) {
		if (c->freelist != FR_NULL) {
			/* take this member out of the free list */
			uptr = (char *) c->frbuf + c->freelist;
			c->freelist = *(int *) uptr;
			return uptr;
		}
	}
	/* no memory found, add to the chain */
	if (p == 0)
		p = fr;
	if ((p->next = fr_create(fr->nentry, fr->nsize)) == 0) {
		no_mem("fr_alloc");
		return 0;
	}
	p = p->next;
	uptr = (char *) p->frbuf + p->freelist;
	p->freelist = *(int *) uptr;
	return uptr;
}
Example #2
0
File: num.c Project: vocho/openqnx
static
void init_number()
{
	if ((num_pool = fr_create(NUM_FRSIZE, sizeof(numb_t))) == 0) {
		no_mem("init_number");
	}
}
Example #3
0
File: num.c Project: vocho/openqnx
numb_t         *
create_num()
{
	numb_t         *n;

	if (num_pool == 0)
		init_number();
	if ((n = fr_alloc(num_pool)) == 0) {
		no_mem("create_num");
	}
	memset(n, 0, sizeof(numb_t));
	return n;
}
Example #4
0
static int do_userdel(const char * const file,
                      const PWInfo * const pwinfo)
{
    char *file2;
    FILE *fp2;
    
    if (pwinfo->login == NULL || *(pwinfo->login) == 0) {
        fprintf(stderr, "Missing login\n");
        return -1;
    }
    if (file == NULL) {
        fprintf(stderr, "Missing passwd file\n");
        return PW_ERROR_MISSING_PASSWD_FILE;
    }    
    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;
    }
    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;
    
    bye2:
    unlink(file2);
    free(file2);
    
    return PW_ERROR_UNEXPECTED_ERROR;
}
Example #5
0
static int do_usermod(const char * const file,
                      const PWInfo *pwinfo)
{
    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);
        if (*cleartext != 0) {
            memset(cleartext, 0, 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;
}
Example #6
0
static int do_useradd(const char * const file,
                      const PWInfo * const pwinfo_)
{
    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;
    }
    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;
    }
    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);
        if (*cleartext != 0) {
            memset(cleartext, 0, 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;
}
Example #7
0
int main(int argc, char *argv[])
{
    const char *action;
    char *file = NULL;
    char *dbfile = NULL;
    PWInfo pwinfo;
    int fodder;
    int ret = 0;
    int with_chroot = 1;
    int with_mkdb = 0;
        
    if (argc < 2) {
        help();
    }

#ifdef HAVE_SETLOCALE
# ifdef LC_MESSAGES
    (void) setlocale(LC_MESSAGES, "");
# endif
# ifdef LC_CTYPE
    (void) setlocale(LC_CTYPE, "");
# endif
# ifdef LC_COLLATE
    (void) setlocale(LC_COLLATE, "");
# endif
#endif    

#ifdef PROBE_RANDOM_AT_RUNTIME
    pw_zrand_probe();
#endif
    
    pwinfo.pwd = NULL;
    pwinfo.gecos = NULL;
    pwinfo.home = NULL;
    pwinfo.allow_local_ip = pwinfo.deny_local_ip = NULL;
    pwinfo.allow_client_ip = pwinfo.deny_client_ip = NULL;        
    pwinfo.has_bw_dl = 0;
    pwinfo.has_bw_ul = 0;
    pwinfo.has_quota_files = 0;
    pwinfo.has_quota_size = 0;
    pwinfo.has_ul_ratio = 0;
    pwinfo.has_dl_ratio = 0;
    pwinfo.has_time = 0;
    pwinfo.time_begin = pwinfo.time_end = 0U;
    pwinfo.has_per_user_max = 0;
    pwinfo.per_user_max = 0U;
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
    pwinfo.uid = (uid_t) 42U;
    pwinfo.gid = (gid_t) 42U;
#else
    pwinfo.uid = (uid_t) 0U;
    pwinfo.gid = (gid_t) 0U;
#endif
    
    argv++;
    argc--;
    action = *argv;
    if (argc > 1) {
        argv++;
        argc--;
        pwinfo.login = *argv;
    } else {
        pwinfo.login = NULL;
    }
    filter_pw_line_sep(pwinfo.login);
    while ((fodder =
            getopt(argc, argv, 
                   "c:d:D:f:F:g:hi:I:mn:N:q:Q:r:R:t:T:u:y:z:")) != -1) {
        switch(fodder) {
        case 'c' : {
            if ((pwinfo.gecos = strdup(optarg)) == NULL) {
                no_mem();
            }
            filter_pw_line_sep(pwinfo.gecos);
            break;
        }
        case 'D' :
            with_chroot = 0;
        case 'd' : {
            char *optarg_copy;
            size_t sizeof_home;
            size_t optarg_len;
            
            if ((optarg_copy = strdup(optarg)) == NULL) {
                no_mem();
            }
            again:
            optarg_len = strlen(optarg_copy);
            if (optarg_len < (size_t) 1U) {
                fprintf(stderr, "home directory is missing\n");
                exit(EXIT_FAILURE);
            }
            if (optarg_copy[optarg_len - 1U] == '/') {
                optarg_len--;
                optarg_copy[optarg_len] = 0;
                goto again;
            }
            sizeof_home = optarg_len + sizeof "/./";
            if ((pwinfo.home = malloc(sizeof_home)) == NULL) {
                no_mem();
            }
            snprintf(pwinfo.home, sizeof_home, "%s%s", optarg_copy,
                     with_chroot != 0 ? "/./" : "");
            filter_pw_line_sep(pwinfo.home);            
            break;
        }
        case 'f' : {
            if ((file = strdup(optarg)) == NULL) {
                no_mem();
            }
            break;
        }
        case 'F' : {
            if ((dbfile = strdup(optarg)) == NULL) {
                no_mem();
            }
            break;
        }
        case 'g' : {
            struct group *gr;
            
            if (pwinfo.gid > (gid_t) 0 && pwinfo.uid <= (uid_t) 0) {
                fprintf(stderr, "You already gave a gid\n");
                exit(EXIT_FAILURE);
            }                
            if ((gr = getgrnam(optarg)) != NULL) {
                pwinfo.gid = gr->gr_gid;
            } else {
                pwinfo.gid = (gid_t) strtoul(optarg, NULL, 10);
            }            
            break;
        }
        case 'h' : {
            help();
            /* doesn't return */
        }
        case 'i' : {
            if ((pwinfo.allow_local_ip = strdup(optarg)) == NULL) {
                no_mem();
            }
            break;
        }
        case 'I' : {
            if ((pwinfo.deny_local_ip = strdup(optarg)) == NULL) {
                no_mem();
            }
            break;
        }
        case 'm' : {
            with_mkdb = 1;
            break;
        }
        case 'n' : {
            if (*optarg == 0) {
                pwinfo.has_quota_files = -1;
            } else {
                pwinfo.quota_files = strtoull(optarg, NULL, 10);
                pwinfo.has_quota_files = 1;
            }
            break;
        }
        case 'N' : {
            if (*optarg == 0) {
                pwinfo.has_quota_size = -1;
            } else {
                pwinfo.quota_size = strtoull(optarg, NULL, 10) * 
                    (1024ULL * 1024ULL);
                pwinfo.has_quota_size = 1;
            }
            break;
        }
        case 'q' : {
            if (*optarg == 0) {
                pwinfo.has_ul_ratio = -1;
            } else {
                pwinfo.ul_ratio = (unsigned int) strtoul(optarg, NULL, 10);
                if (pwinfo.ul_ratio < 1U) {
                    fprintf(stderr, "Illegal upload ratio\n");
                    exit(EXIT_FAILURE);
                }
                pwinfo.has_ul_ratio = 1;
            }
            break;
        }            
        case 'Q' : {
            if (*optarg == 0) {
                pwinfo.has_dl_ratio = -1;
            } else {
                pwinfo.dl_ratio = (unsigned int) strtoul(optarg, NULL, 10);
                if (pwinfo.dl_ratio < 1U) {
                    fprintf(stderr, "Illegal download ratio\n");
                    exit(EXIT_FAILURE);
                }            
                pwinfo.has_dl_ratio = 1;
            }
            break;
        }
        case 'r' : {
            if ((pwinfo.allow_client_ip = strdup(optarg)) == NULL) {
                no_mem();
            }
            break;
        }
        case 'R' : {
            if ((pwinfo.deny_client_ip = strdup(optarg)) == NULL) {
                no_mem();
            }
            break;
        }            
        case 't' : {
            if (*optarg == 0) {
                pwinfo.has_bw_dl = -1;
            } else {
                if ((pwinfo.bw_dl = strtoul(optarg, NULL, 10)) > 0UL) {
                    pwinfo.bw_dl *= 1024UL;                    
                    pwinfo.has_bw_dl = 1;
                }
            }
            break;
        }
        case 'T' : {
            if (*optarg == 0) {
                pwinfo.has_bw_ul = -1;
            } else {
                if ((pwinfo.bw_ul = strtoul(optarg, NULL, 10)) > 0UL) {
                    pwinfo.bw_ul *= 1024UL;
                    pwinfo.has_bw_ul = 1;
                }
            }
            break;
        }            
        case 'u' : {
            struct passwd *pw;                
            
            if (pwinfo.uid > (uid_t) 0) {
                fprintf(stderr, "You already gave an uid\n");
                exit(EXIT_FAILURE);
            }
            if ((pw = getpwnam(optarg)) != NULL) {
                pwinfo.uid = pw->pw_uid;
                if (pwinfo.gid <= (gid_t) 0) {
                    pwinfo.gid = pw->pw_gid;
                }
            } else {
                pwinfo.uid = (uid_t) strtoul(optarg, NULL, 10);
            }
            break;
        }
    case 'y' : {
        if ((pwinfo.per_user_max = (unsigned int) strtoul(optarg, NULL, 10)) <= 0U) {
                pwinfo.has_per_user_max = -1;
            } else {
                pwinfo.has_per_user_max = 1;
            }
        break;
    }
        case 'z' : {
            if (sscanf(optarg, "%u-%u", 
                       &pwinfo.time_begin, &pwinfo.time_end) == 2 &&
                pwinfo.time_begin < 2360 && (pwinfo.time_begin % 100) < 60 &&
                pwinfo.time_end < 2360 && (pwinfo.time_end % 100) < 60) {
                pwinfo.has_time = 1;
            } else if (*optarg != 0) {
                fprintf(stderr, "Time should be given as hhmm-hhmm\n"
                        "Example : 0900-1800 (9 am to 6 pm)\n");
                exit(EXIT_FAILURE);                    
            } else {
                pwinfo.has_time = -1;
            }
            break;
        }
        case '?' :
            help();
        }
    }
    if (file == NULL) {
        char *file_;
        
        if ((file_ = getenv(ENV_DEFAULT_PW_FILE)) != NULL && *file_ != 0) {
            file = file_;
        } else if ((file = strdup(DEFAULT_PW_FILE)) == NULL) {
            no_mem();
        }
    }
    (void) umask(0177);
    init_zrand();
    if (strcasecmp(action, "useradd") == 0) {
        ret = do_useradd(file, &pwinfo);
        if (with_mkdb != 0) {
            ret |= do_mkdb(dbfile, file);
        }
    } else if (strcasecmp(action, "usermod") == 0) {
        ret = do_usermod(file, &pwinfo);
        if (with_mkdb != 0) {
            ret |= do_mkdb(dbfile, file);
        }        
    } else if (strcasecmp(action, "userdel") == 0) {
        ret = do_userdel(file, &pwinfo);
        if (with_mkdb != 0) {
            ret |= do_mkdb(dbfile, file);
        }        
    } else if (strcasecmp(action, "passwd") == 0) {
        ret = do_passwd(file, &pwinfo);
        if (with_mkdb != 0) {
            ret |= do_mkdb(dbfile, file);
        }        
    } else if (strcasecmp(action, "show") == 0) {
        ret = do_show(file, &pwinfo);
    } else if (strcasecmp(action, "mkdb") == 0) {
        ret = do_mkdb(pwinfo.login, file);
    } else if (strcasecmp(action, "list") == 0) {
        ret = do_list(file);
    } else {
        ret = PW_ERROR_UNEXPECTED_ERROR;
        help();
    }
               
    return ret;
}
Example #8
0
static int do_mkdb(const char *dbfile, const char * const file)
{
    FILE *fp;
    char *index_dbfile;
    size_t sizeof_index_dbfile;
    char *data_dbfile;
    size_t sizeof_data_dbfile;
    char *s;
    PureDBW dbw;
    int ret = PW_ERROR_UNEXPECTED_ERROR;
    char line[LINE_MAX];
    
    if (dbfile == NULL || *dbfile == 0) {
        char *dbfile_;
        
        if ((dbfile_ = getenv(ENV_DEFAULT_PW_DB)) != NULL && *dbfile_ != 0) {
            dbfile = dbfile_;
        } else {        
            dbfile = DEFAULT_PW_DB;
        }
    }
    if (file == NULL) {
        fprintf(stderr, "Missing passwd file\n");
        return PW_ERROR_MISSING_PASSWD_FILE;
    }    
    if ((fp = fopen(file, "r")) == NULL) {
        perror("Unable to open the passwd file");
        return PW_ERROR_MISSING_PASSWD_FILE;
    }
    sizeof_index_dbfile = strlen(dbfile) + sizeof NEWPASSWD_INDEX_SUFFIX;
    if ((index_dbfile = ALLOCA(sizeof_index_dbfile)) == NULL) {
        fclose(fp);
        no_mem();
    }
    sizeof_data_dbfile = strlen(dbfile) + sizeof NEWPASSWD_DATA_SUFFIX;
    if ((data_dbfile = ALLOCA(sizeof_data_dbfile)) == NULL) {
        fclose(fp);
        ALLOCA_FREE(index_dbfile);
        no_mem();
    }
    snprintf(index_dbfile, sizeof_index_dbfile, "%s%s",
             dbfile, NEWPASSWD_INDEX_SUFFIX);
    snprintf(data_dbfile, sizeof_data_dbfile, "%s%s",
             dbfile, NEWPASSWD_DATA_SUFFIX);
    if (puredbw_open(&dbw, index_dbfile, data_dbfile, dbfile) != 0) {
        perror("Unable to create the database");
        goto err;
    }
    while (fgets(line, (int) sizeof line - 1U, fp) != NULL) {
        strip_lf(line);
        if (*line == PW_LINE_COMMENT) {
            continue;
        }
        if (*line == 0 || (s = strchr(line, *PW_LINE_SEP)) == NULL ||
            s[1] == 0) {
            continue;
        }
        *s++ = 0;
        if (puredbw_add_s(&dbw, line, s) != 0) {
            perror("Error while indexing a new entry");
            goto err;
        }
    }
    if (puredbw_close(&dbw) != 0) {
        perror("Unable to close the database");
    } else {
        ret = 0;
    }
    err:
    puredbw_free(&dbw);
    ALLOCA_FREE(index_dbfile);
    ALLOCA_FREE(data_dbfile);    
    fclose(fp);
    
    return ret;
}
Example #9
0
static char *best_crypt(const char * const pwd,
                        const unsigned long max_concurrent_logins,
                        const unsigned long long max_auth_memory)
{
#if defined(crypto_pwhash_STRBYTES) || defined(crypto_pwhash_scryptsalsa208sha256_STRBYTES)
# ifndef crypto_pwhash_STRBYTES
#  define crypto_pwhash_STRBYTES crypto_pwhash_scryptsalsa208sha256_STRBYTES
#  define crypto_pwhash_str crypto_pwhash_scryptsalsa208sha256_str
# endif
    static char hash[crypto_pwhash_STRBYTES];
    struct timeval tv_start, tv_now;
    struct timezone tz;
    unsigned long long probe_ops = MIN_AUTH_OPS;
    unsigned long long ops = 0ULL;
    unsigned long long auth_memory =
        max_auth_memory / (unsigned long long) max_concurrent_logins;
    unsigned long long elapsed;
    unsigned long long auth_time_ms = DEFAULT_AUTH_TIME_MS;

    if (max_concurrent_logins > AUTH_CORES) {
        auth_time_ms /= (unsigned long long) max_concurrent_logins / AUTH_CORES;
    }
    if (auth_time_ms < MIN_AUTH_TIME_MS) {
        auth_time_ms = MIN_AUTH_TIME_MS;
    }
    if (auth_memory < MIN_AUTH_MEMORY) {
        auth_memory = MIN_AUTH_MEMORY;
    }
    gettimeofday(&tv_start, &tz);
    for (;;) {
        if (crypto_pwhash_str(hash, pwd, strlen(pwd),
                              probe_ops, auth_memory) != 0) {
            no_mem();
        }
        ops += probe_ops;
        probe_ops *= 2;
        gettimeofday(&tv_now, &tz);
        elapsed = (tv_now.tv_sec * 1000ULL + tv_now.tv_usec / 1000ULL) -
            (tv_start.tv_sec * 1000ULL + tv_start.tv_usec / 1000ULL);
        if (elapsed >= auth_time_ms) {
            break;
        }
    }
    if (ops < MIN_AUTH_OPS) {
        ops = MIN_AUTH_OPS;
    }
    if (crypto_pwhash_str(hash, pwd, strlen(pwd), ops, auth_memory) != 0) {
        no_mem();
    }
    return hash;
#else
    static const char crcars[64] =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
    const char *crypted;

    if ((crypted = (const char *)      /* bcrypt */
         crypt("test", "$2a$08$1234567890123456789012")) != NULL &&
        strcmp(crypted,
               "$2a$08$123456789012345678901uBdmsfIXjJcWQwz1wT/IZrWhimJ6xy6a")
        == 0) {
        char salt[] = "$2a$10$0000000000000000000000";
        int c = 28;

        do {
            c--;
            salt[c] = crcars[alt_arc4random() & 63];
        } while (c > 7);

        return (char *) crypt(pwd, salt);
    } else if ((crypted = (const char *)    /* SHA-512 */
                crypt("test", "$6$1234567890123456$")) != NULL &&
               strcmp(crypted,
                      "$6$1234567890123456$d.pgKQFaiD8bRiExg5NesbGR/"
                      "3u51YvxeYaQXPzx4C6oSYREw8VoReiuYZjx0V9OhGVTZF"
                      "qhc6emAxT1RC5BV.") == 0) {
        char salt[] = "$6$0000000000000000";
        int c = 18;

        do {
            c--;
            salt[c] = crcars[alt_arc4random() & 63];
        } while (c > 3);

        return (char *) crypt(pwd, salt);
    } else if ((crypted = (const char *)    /* MD5 */
                crypt("test", "$1$12345678$")) != NULL &&
               strcmp(crypted, "$1$12345678$oEitTZYQtRHfNGmsFvTBA/") == 0) {
        char salt[] = "$1$00000000";
        int c = 10;

        do {
            c--;
            salt[c] = crcars[alt_arc4random() & 63];
        } while (c > 3);

        return (char *) crypt(pwd, salt);
    } else {
        fprintf(stderr, "No useable password hashing function found\n"
               "Please install libsodium (https://libsodium.org) and recompile pure-ftpd.\n");
        exit(EXIT_FAILURE);
    }
#endif
}