source: vendor/current/lib/util/genrand_util.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 6.8 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Functions to create reasonable random numbers for crypto use.
5
6 Copyright (C) Jeremy Allison 2001
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "includes.h"
23#include "system/locale.h"
24
25/**
26 * @file
27 * @brief Random number generation
28 */
29
30/**
31 generate a single random uint32_t
32**/
33_PUBLIC_ uint32_t generate_random(void)
34{
35 uint8_t v[4];
36 generate_random_buffer(v, 4);
37 return IVAL(v, 0);
38}
39
40
41/**
42 Microsoft composed the following rules (among others) for quality
43 checks. This is an abridgment from
44 http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx:
45
46 Passwords must contain characters from three of the following five
47 categories:
48
49 - Uppercase characters of European languages (A through Z, with
50 diacritic marks, Greek and Cyrillic characters)
51 - Lowercase characters of European languages (a through z, sharp-s,
52 with diacritic marks, Greek and Cyrillic characters)
53 - Base 10 digits (0 through 9)
54 - Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
55 - Any Unicode character that is categorized as an alphabetic character
56 but is not uppercase or lowercase. This includes Unicode characters
57 from Asian languages.
58
59 Note: for now do not check if the unicode category is
60 alphabetic character
61**/
62_PUBLIC_ bool check_password_quality(const char *pwd)
63{
64 size_t ofs = 0;
65 size_t num_chars = 0;
66 size_t num_digits = 0;
67 size_t num_upper = 0;
68 size_t num_lower = 0;
69 size_t num_nonalpha = 0;
70 size_t num_unicode = 0;
71 size_t num_categories = 0;
72
73 if (pwd == NULL) {
74 return false;
75 }
76
77 while (true) {
78 const char *s = &pwd[ofs];
79 size_t len = 0;
80 codepoint_t c;
81
82 c = next_codepoint(s, &len);
83 if (c == INVALID_CODEPOINT) {
84 return false;
85 } else if (c == 0) {
86 break;
87 }
88 ofs += len;
89 num_chars += 1;
90
91 if (len == 1) {
92 const char *na = "~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?/";
93
94 if (isdigit(c)) {
95 num_digits += 1;
96 continue;
97 }
98
99 if (isupper(c)) {
100 num_upper += 1;
101 continue;
102 }
103
104 if (islower(c)) {
105 num_lower += 1;
106 continue;
107 }
108
109 if (strchr(na, c)) {
110 num_nonalpha += 1;
111 continue;
112 }
113
114 /*
115 * the rest does not belong to
116 * a category.
117 */
118 continue;
119 }
120
121 if (isupper_m(c)) {
122 num_upper += 1;
123 continue;
124 }
125
126 if (islower_m(c)) {
127 num_lower += 1;
128 continue;
129 }
130
131 /*
132 * Note: for now do not check if the unicode category is
133 * alphabetic character
134 *
135 * We would have to import the details from
136 * ftp://ftp.unicode.org/Public/6.3.0/ucd/UnicodeData-6.3.0d1.txt
137 */
138 num_unicode += 1;
139 continue;
140 }
141
142 if (num_digits > 0) {
143 num_categories += 1;
144 }
145 if (num_upper > 0) {
146 num_categories += 1;
147 }
148 if (num_lower > 0) {
149 num_categories += 1;
150 }
151 if (num_nonalpha > 0) {
152 num_categories += 1;
153 }
154 if (num_unicode > 0) {
155 num_categories += 1;
156 }
157
158 if (num_categories >= 3) {
159 return true;
160 }
161
162 return false;
163}
164
165/**
166 Use the random number generator to generate a random string.
167**/
168
169_PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list)
170{
171 size_t i;
172 size_t list_len = strlen(list);
173
174 char *retstr = talloc_array(mem_ctx, char, len + 1);
175 if (!retstr) return NULL;
176
177 generate_random_buffer((uint8_t *)retstr, len);
178 for (i = 0; i < len; i++) {
179 retstr[i] = list[retstr[i] % list_len];
180 }
181 retstr[i] = '\0';
182
183 return retstr;
184}
185
186/**
187 * Generate a random text string consisting of the specified length.
188 * The returned string will be allocated.
189 *
190 * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
191 */
192
193_PUBLIC_ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
194{
195 char *retstr;
196 const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
197
198again:
199 retstr = generate_random_str_list(mem_ctx, len, c_list);
200 if (!retstr) return NULL;
201
202 /* we need to make sure the random string passes basic quality tests
203 or it might be rejected by windows as a password */
204 if (len >= 7 && !check_password_quality(retstr)) {
205 talloc_free(retstr);
206 goto again;
207 }
208
209 return retstr;
210}
211
212/**
213 * Generate a random text password.
214 */
215
216_PUBLIC_ char *generate_random_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
217{
218 char *retstr;
219 /* This list does not include { or } because they cause
220 * problems for our provision (it can create a substring
221 * ${...}, and for Fedora DS (which treats {...} at the start
222 * of a stored password as special
223 * -- Andrew Bartlett 2010-03-11
224 */
225 const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~";
226 size_t len = max;
227 size_t diff;
228
229 if (min > max) {
230 errno = EINVAL;
231 return NULL;
232 }
233
234 diff = max - min;
235
236 if (diff > 0 ) {
237 size_t tmp;
238
239 generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
240
241 tmp %= diff;
242
243 len = min + tmp;
244 }
245
246again:
247 retstr = generate_random_str_list(mem_ctx, len, c_list);
248 if (!retstr) return NULL;
249
250 /* we need to make sure the random string passes basic quality tests
251 or it might be rejected by windows as a password */
252 if (len >= 7 && !check_password_quality(retstr)) {
253 talloc_free(retstr);
254 goto again;
255 }
256
257 return retstr;
258}
259
260/**
261 * Generate an array of unique text strings all of the same length.
262 * The returned string will be allocated.
263 * Returns NULL if the number of unique combinations cannot be created.
264 *
265 * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
266 */
267_PUBLIC_ char** generate_unique_strs(TALLOC_CTX *mem_ctx, size_t len,
268 uint32_t num)
269{
270 const char *c_list = "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
271 const unsigned c_size = 42;
272 size_t i, j;
273 unsigned rem;
274 char ** strs = NULL;
275
276 if (num == 0 || len == 0)
277 return NULL;
278
279 strs = talloc_array(mem_ctx, char *, num);
280 if (strs == NULL) return NULL;
281
282 for (i = 0; i < num; i++) {
283 char *retstr = (char *)talloc_size(strs, len + 1);
284 if (retstr == NULL) {
285 talloc_free(strs);
286 return NULL;
287 }
288 rem = i;
289 for (j = 0; j < len; j++) {
290 retstr[j] = c_list[rem % c_size];
291 rem = rem / c_size;
292 }
293 retstr[j] = 0;
294 strs[i] = retstr;
295 if (rem != 0) {
296 /* we were not able to fit the number of
297 * combinations asked for in the length
298 * specified */
299 DEBUG(0,(__location__ ": Too many combinations %u for length %u\n",
300 num, (unsigned)len));
301
302 talloc_free(strs);
303 return NULL;
304 }
305 }
306
307 return strs;
308}
Note: See TracBrowser for help on using the repository browser.