xref: /freebsd/crypto/krb5/src/plugins/pwqual/test/main.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* plugins/pwqual/test/main.c - test module for password quality interface */
3 /*
4  * Copyright (C) 2010,2013 by the Massachusetts Institute of Technology.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  *
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * This file implements a module named "combo" which tests whether a password
35  * matches a pair of words in the dictionary.  It also implements several dummy
36  * modules named "dyn1", "dyn2", and "dyn3" which are used for ordering tests.
37  */
38 
39 #include <k5-platform.h>
40 #include <krb5/pwqual_plugin.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 
46 typedef struct combo_moddata_st {
47     const char **word_list;     /* list of word pointers */
48     char *word_block;           /* actual word data */
49 } *combo_moddata;
50 
51 static krb5_error_code
init_dict(combo_moddata dict,const char * dict_file)52 init_dict(combo_moddata dict, const char *dict_file)
53 {
54     int fd;
55     size_t count, len, i;
56     char *p, *t;
57     struct stat sb;
58 
59     /* Read the dictionary file into memory in one blob. */
60     if (dict_file == NULL)
61         return 0;
62     fd = open(dict_file, O_RDONLY);
63     if (fd == -1)
64         return (errno == ENOENT) ? 0 : errno;
65     if (fstat(fd, &sb) == -1) {
66         close(fd);
67         return errno;
68     }
69     dict->word_block = malloc(sb.st_size + 1);
70     if (dict->word_block == NULL)
71         return ENOMEM;
72     if (read(fd, dict->word_block, sb.st_size) != sb.st_size)
73         return errno;
74     close(fd);
75     dict->word_block[sb.st_size] = '\0';
76 
77     /* Decompose the blob into newline-separated words. */
78     p = dict->word_block;
79     len = sb.st_size;
80     count = 0;
81     while (len > 0 && (t = memchr(p, '\n', len)) != NULL) {
82         *t = '\0';
83         len -= t - p + 1;
84         p = t + 1;
85         count++;
86     }
87     dict->word_list = calloc(count + 1, sizeof(char *));
88     if (dict->word_list == NULL)
89         return ENOMEM;
90     p = dict->word_block;
91     for (i = 0; i < count; i++) {
92         dict->word_list[i] = p;
93         p += strlen(p) + 1;
94     }
95     return 0;
96 }
97 
98 static void
destroy_dict(combo_moddata dict)99 destroy_dict(combo_moddata dict)
100 {
101     if (dict == NULL)
102         return;
103     free(dict->word_list);
104     free(dict->word_block);
105     free(dict);
106 }
107 
108 static krb5_error_code
combo_open(krb5_context context,const char * dict_file,krb5_pwqual_moddata * data)109 combo_open(krb5_context context, const char *dict_file,
110            krb5_pwqual_moddata *data)
111 {
112     krb5_error_code ret;
113     combo_moddata dict;
114 
115     *data = NULL;
116 
117     /* Allocate and initialize a dictionary structure. */
118     dict = malloc(sizeof(*dict));
119     if (dict == NULL)
120         return ENOMEM;
121     dict->word_list = NULL;
122     dict->word_block = NULL;
123 
124     /* Fill in the dictionary structure with data from dict_file. */
125     ret = init_dict(dict, dict_file);
126     if (ret != 0) {
127         destroy_dict(dict);
128         return ret;
129     }
130 
131     *data = (krb5_pwqual_moddata)dict;
132     return 0;
133 }
134 
135 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)136 combo_check(krb5_context context, krb5_pwqual_moddata data,
137             const char *password, const char *policy_name,
138             krb5_principal princ, const char **languages)
139 {
140     combo_moddata dict = (combo_moddata)data;
141     const char *remainder, **word1, **word2;
142 
143     if (dict->word_list == NULL)
144         return 0;
145 
146     for (word1 = dict->word_list; *word1 != NULL; word1++) {
147         if (strncasecmp(password, *word1, strlen(*word1)) != 0)
148             continue;
149         remainder = password + strlen(*word1);
150         for (word2 = dict->word_list; *word2 != NULL; word2++) {
151             if (strcasecmp(remainder, *word2) == 0) {
152                 krb5_set_error_message(context, KADM5_PASS_Q_DICT,
153                                        "Password may not be a pair of "
154                                        "dictionary words");
155                 return KADM5_PASS_Q_DICT;
156             }
157         }
158     }
159 
160     return 0;
161 }
162 
163 static void
combo_close(krb5_context context,krb5_pwqual_moddata data)164 combo_close(krb5_context context, krb5_pwqual_moddata data)
165 {
166     destroy_dict((combo_moddata)data);
167 }
168 
169 krb5_error_code
170 pwqual_combo_initvt(krb5_context context, int maj_ver, int min_ver,
171                     krb5_plugin_vtable vtable);
172 krb5_error_code
173 pwqual_dyn1_initvt(krb5_context context, int maj_ver, int min_ver,
174                    krb5_plugin_vtable vtable);
175 krb5_error_code
176 pwqual_dyn2_initvt(krb5_context context, int maj_ver, int min_ver,
177                    krb5_plugin_vtable vtable);
178 krb5_error_code
179 pwqual_dyn3_initvt(krb5_context context, int maj_ver, int min_ver,
180                    krb5_plugin_vtable vtable);
181 
182 krb5_error_code
pwqual_combo_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)183 pwqual_combo_initvt(krb5_context context, int maj_ver, int min_ver,
184                     krb5_plugin_vtable vtable)
185 {
186     krb5_pwqual_vtable vt;
187 
188     if (maj_ver != 1)
189         return KRB5_PLUGIN_VER_NOTSUPP;
190     vt = (krb5_pwqual_vtable)vtable;
191     vt->name = "combo";
192     vt->open = combo_open;
193     vt->check = combo_check;
194     vt->close = combo_close;
195     return 0;
196 }
197 
198 krb5_error_code
pwqual_dyn1_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)199 pwqual_dyn1_initvt(krb5_context context, int maj_ver, int min_ver,
200                    krb5_plugin_vtable vtable)
201 {
202     ((krb5_pwqual_vtable)vtable)->name = "dyn1";
203     return 0;
204 }
205 
206 krb5_error_code
pwqual_dyn2_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)207 pwqual_dyn2_initvt(krb5_context context, int maj_ver, int min_ver,
208                    krb5_plugin_vtable vtable)
209 {
210     ((krb5_pwqual_vtable)vtable)->name = "dyn2";
211     return 0;
212 }
213 
214 krb5_error_code
pwqual_dyn3_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)215 pwqual_dyn3_initvt(krb5_context context, int maj_ver, int min_ver,
216                    krb5_plugin_vtable vtable)
217 {
218     ((krb5_pwqual_vtable)vtable)->name = "dyn3";
219     return 0;
220 }
221