view pw.c @ 43:969de79bb4b6 default tip

Added tag version-1 for changeset fb995e5d54e9
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Tue, 20 Aug 2019 21:27:47 +0200
parents fa93d2ff9c62
children
line wrap: on
line source

/*
 * Copyright (C) 2017 Guido Berhoerster <guido+pwm@berhoerster.name>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "compat.h"

#ifdef	HAVE_ERR_H
#include <err.h>
#endif /* HAVE_ERR_H */
#include <pws.h>
#include <stdint.h>
#include <string.h>

#include "pw.h"
#include "rand.h"
#include "util.h"

int
pw_genrandom(struct pw_char_group groups[], size_t groups_len, char *password,
    size_t password_len)
{
	int	retval = -1;
	char	*password_buf = NULL;
	size_t	*group_matches = NULL;
	size_t	i;
	size_t	chars_len = 0;
	char	*chars;
	size_t	j;
	uint32_t r;
	size_t	k;

	password_buf = xmalloc(password_len + 1);
	password_buf[password_len] = '\0';

	group_matches = xmalloc(groups_len * sizeof (size_t));

	for (i = 0; i < groups_len; i++) {
		chars_len += strlen(groups[i].chars);
	}
	if (chars_len == 0) {
		/* there must be at least one character to choose from */
		return (-1);
	}

	chars = xmalloc(chars_len + 1);
	chars[0] = '\0';
	for (i = 0; i < groups_len; i++) {
		strcat(chars, groups[i].chars);
	}

	for (k = 0; k < 100000; k++) {
		memset(group_matches, 0, groups_len * sizeof (size_t));

		for (j = 0; j < password_len; j++) {
			r = rand_uniform(chars_len);
			password_buf[j] = chars[r];

			for (i = 0; i < groups_len; i++) {
				if (strchr(groups[i].chars, chars[r]) != NULL) {
					group_matches[i]++;
					break;
				}
			}
		}

		for (i = 0; i < groups_len; i++) {
			if (group_matches[i] < groups[i].chars_min) {
				/* try again */
				break;
			}
		}
		if (i == groups_len) {
			/* password meets all constraints */
			strcpy(password, password_buf);
			retval = 0;
			break;
		}
	}

	free(chars);
	free(group_matches);
	free(password_buf);

	return (retval);
}