Path: blob/main/crypto/krb5/src/lib/kadm5/srv/pwqual_dict.c
39566 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* lib/kadm5/srv/pwqual_dict.c */2/*3* Copyright (C) 2010 by the Massachusetts Institute of Technology.4* All rights reserved.5*6* Export of this software from the United States of America may7* require a specific license from the United States Government.8* It is the responsibility of any person or organization contemplating9* export to obtain such a license before exporting.10*11* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and12* distribute this software and its documentation for any purpose and13* without fee is hereby granted, provided that the above copyright14* notice appear in all copies and that both that copyright notice and15* this permission notice appear in supporting documentation, and that16* the name of M.I.T. not be used in advertising or publicity pertaining17* to distribution of the software without specific, written prior18* permission. Furthermore if you modify this software you must label19* your software as modified software and not distribute it in such a20* fashion that it might be confused with the original M.I.T. software.21* M.I.T. makes no representations about the suitability of22* this software for any purpose. It is provided "as is" without express23* or implied warranty.24*/25/*26* Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved27*/2829/* Password quality module to look up passwords within the realm dictionary. */3031#include "k5-platform.h"32#include <krb5/pwqual_plugin.h>33#include <sys/types.h>34#include <sys/stat.h>35#include <unistd.h>36#include <kadm5/admin.h>37#include "adm_proto.h"38#include <syslog.h>39#include "server_internal.h"4041typedef struct dict_moddata_st {42char **word_list; /* list of word pointers */43char *word_block; /* actual word data */44unsigned int word_count; /* number of words */45} *dict_moddata;464748/*49* Function: word_compare50*51* Purpose: compare two words in the dictionary.52*53* Arguments:54* w1 (input) pointer to first word55* w2 (input) pointer to second word56* <return value> result of strcmp57*58* Requires:59* w1 and w2 to point to valid memory60*61*/6263static int64word_compare(const void *s1, const void *s2)65{66return (strcasecmp(*(const char **)s1, *(const char **)s2));67}6869/*70* Function: init-dict71*72* Purpose: Initialize in memory word dictionary73*74* Arguments:75* none76* <return value> KADM5_OK on success errno on failure;77* (but success on ENOENT)78*79* Requires:80* If WORDFILE exists, it must contain a list of words,81* one word per-line.82*83* Effects:84* If WORDFILE exists, it is read into memory sorted for future85* use. If it does not exist, it syslogs an error message and returns86* success.87*88* Modifies:89* word_list to point to a chunk of allocated memory containing90* pointers to words91* word_block to contain the dictionary.92*93*/9495static int96init_dict(dict_moddata dict, const char *dict_file)97{98int fd;99size_t len, i;100char *p, *t;101struct stat sb;102103if (dict_file == NULL) {104krb5_klog_syslog(LOG_INFO,105_("No dictionary file specified, continuing without "106"one."));107return KADM5_OK;108}109if ((fd = open(dict_file, O_RDONLY)) == -1) {110if (errno == ENOENT) {111krb5_klog_syslog(LOG_ERR,112_("WARNING! Cannot find dictionary file %s, "113"continuing without one."), dict_file);114return KADM5_OK;115} else116return errno;117}118set_cloexec_fd(fd);119if (fstat(fd, &sb) == -1) {120close(fd);121return errno;122}123dict->word_block = malloc(sb.st_size + 1);124if (dict->word_block == NULL) {125(void)close(fd);126return ENOMEM;127}128if (read(fd, dict->word_block, sb.st_size) != sb.st_size) {129(void)close(fd);130return errno;131}132(void)close(fd);133dict->word_block[sb.st_size] = '\0';134135p = dict->word_block;136len = sb.st_size;137while(len > 0 && (t = memchr(p, '\n', len)) != NULL) {138*t = '\0';139len -= t - p + 1;140p = t + 1;141dict->word_count++;142}143if ((dict->word_list = malloc(dict->word_count * sizeof(char *))) == NULL)144return ENOMEM;145p = dict->word_block;146for (i = 0; i < dict->word_count; i++) {147dict->word_list[i] = p;148p += strlen(p) + 1;149}150qsort(dict->word_list, dict->word_count, sizeof(char *), word_compare);151return KADM5_OK;152}153154/*155* Function: destroy_dict156*157* Purpose: destroy in-core copy of dictionary.158*159* Arguments:160* none161* <return value> none162* Requires:163* nothing164* Effects:165* frees up memory occupied by word_list and word_block166* sets count back to 0, and resets the pointers to NULL167*168* Modifies:169* word_list, word_block, and word_count.170*171*/172173static void174destroy_dict(dict_moddata dict)175{176if (dict == NULL)177return;178free(dict->word_list);179free(dict->word_block);180free(dict);181return;182}183184/* Implement the password quality open method by reading in dict_file. */185static krb5_error_code186dict_open(krb5_context context, const char *dict_file,187krb5_pwqual_moddata *data)188{189krb5_error_code ret;190dict_moddata dict;191192*data = NULL;193194/* Allocate and initialize a dictionary structure. */195dict = malloc(sizeof(*dict));196if (dict == NULL)197return ENOMEM;198dict->word_list = NULL;199dict->word_block = NULL;200dict->word_count = 0;201202/* Fill in the dictionary structure with data from dict_file. */203ret = init_dict(dict, dict_file);204if (ret != 0) {205destroy_dict(dict);206return ret;207}208209*data = (krb5_pwqual_moddata)dict;210return 0;211}212213/* Implement the password quality check method by checking the password214* against the dictionary, as well as against principal components. */215static krb5_error_code216dict_check(krb5_context context, krb5_pwqual_moddata data,217const char *password, const char *policy_name,218krb5_principal princ, const char **languages)219{220dict_moddata dict = (dict_moddata)data;221222/* Don't check the dictionary for principals with no password policy. */223if (policy_name == NULL)224return 0;225226/* Check against words in the dictionary if we successfully loaded one. */227if (dict->word_list != NULL &&228bsearch(&password, dict->word_list, dict->word_count, sizeof(char *),229word_compare) != NULL)230return KADM5_PASS_Q_DICT;231232return 0;233}234235/* Implement the password quality close method. */236static void237dict_close(krb5_context context, krb5_pwqual_moddata data)238{239destroy_dict((dict_moddata)data);240}241242krb5_error_code243pwqual_dict_initvt(krb5_context context, int maj_ver, int min_ver,244krb5_plugin_vtable vtable)245{246krb5_pwqual_vtable vt;247248if (maj_ver != 1)249return KRB5_PLUGIN_VER_NOTSUPP;250vt = (krb5_pwqual_vtable)vtable;251vt->name = "dict";252vt->open = dict_open;253vt->check = dict_check;254vt->close = dict_close;255return 0;256}257258259