#include <k5-platform.h>
#include <krb5/pwqual_plugin.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
typedef struct combo_moddata_st {
const char **word_list;
char *word_block;
} *combo_moddata;
static krb5_error_code
init_dict(combo_moddata dict, const char *dict_file)
{
int fd;
size_t count, len, i;
char *p, *t;
struct stat sb;
if (dict_file == NULL)
return 0;
fd = open(dict_file, O_RDONLY);
if (fd == -1)
return (errno == ENOENT) ? 0 : errno;
if (fstat(fd, &sb) == -1) {
close(fd);
return errno;
}
dict->word_block = malloc(sb.st_size + 1);
if (dict->word_block == NULL)
return ENOMEM;
if (read(fd, dict->word_block, sb.st_size) != sb.st_size)
return errno;
close(fd);
dict->word_block[sb.st_size] = '\0';
p = dict->word_block;
len = sb.st_size;
count = 0;
while (len > 0 && (t = memchr(p, '\n', len)) != NULL) {
*t = '\0';
len -= t - p + 1;
p = t + 1;
count++;
}
dict->word_list = calloc(count + 1, sizeof(char *));
if (dict->word_list == NULL)
return ENOMEM;
p = dict->word_block;
for (i = 0; i < count; i++) {
dict->word_list[i] = p;
p += strlen(p) + 1;
}
return 0;
}
static void
destroy_dict(combo_moddata dict)
{
if (dict == NULL)
return;
free(dict->word_list);
free(dict->word_block);
free(dict);
}
static krb5_error_code
combo_open(krb5_context context, const char *dict_file,
krb5_pwqual_moddata *data)
{
krb5_error_code ret;
combo_moddata dict;
*data = NULL;
dict = malloc(sizeof(*dict));
if (dict == NULL)
return ENOMEM;
dict->word_list = NULL;
dict->word_block = NULL;
ret = init_dict(dict, dict_file);
if (ret != 0) {
destroy_dict(dict);
return ret;
}
*data = (krb5_pwqual_moddata)dict;
return 0;
}
static krb5_error_code
combo_check(krb5_context context, krb5_pwqual_moddata data,
const char *password, const char *policy_name,
krb5_principal princ, const char **languages)
{
combo_moddata dict = (combo_moddata)data;
const char *remainder, **word1, **word2;
if (dict->word_list == NULL)
return 0;
for (word1 = dict->word_list; *word1 != NULL; word1++) {
if (strncasecmp(password, *word1, strlen(*word1)) != 0)
continue;
remainder = password + strlen(*word1);
for (word2 = dict->word_list; *word2 != NULL; word2++) {
if (strcasecmp(remainder, *word2) == 0) {
krb5_set_error_message(context, KADM5_PASS_Q_DICT,
"Password may not be a pair of "
"dictionary words");
return KADM5_PASS_Q_DICT;
}
}
}
return 0;
}
static void
combo_close(krb5_context context, krb5_pwqual_moddata data)
{
destroy_dict((combo_moddata)data);
}
krb5_error_code
pwqual_combo_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable);
krb5_error_code
pwqual_dyn1_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable);
krb5_error_code
pwqual_dyn2_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable);
krb5_error_code
pwqual_dyn3_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable);
krb5_error_code
pwqual_combo_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable)
{
krb5_pwqual_vtable vt;
if (maj_ver != 1)
return KRB5_PLUGIN_VER_NOTSUPP;
vt = (krb5_pwqual_vtable)vtable;
vt->name = "combo";
vt->open = combo_open;
vt->check = combo_check;
vt->close = combo_close;
return 0;
}
krb5_error_code
pwqual_dyn1_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable)
{
((krb5_pwqual_vtable)vtable)->name = "dyn1";
return 0;
}
krb5_error_code
pwqual_dyn2_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable)
{
((krb5_pwqual_vtable)vtable)->name = "dyn2";
return 0;
}
krb5_error_code
pwqual_dyn3_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable)
{
((krb5_pwqual_vtable)vtable)->name = "dyn3";
return 0;
}