Line data Source code
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 1492522 : _PUBLIC_ uint32_t generate_random(void)
34 : {
35 : uint8_t v[4];
36 1492522 : generate_random_buffer(v, 4);
37 1492522 : return IVAL(v, 0);
38 : }
39 :
40 : /**
41 : @brief generate a random uint64
42 : **/
43 53551 : _PUBLIC_ uint64_t generate_random_u64(void)
44 : {
45 : uint8_t v[8];
46 53551 : generate_random_buffer(v, 8);
47 53551 : return BVAL(v, 0);
48 : }
49 :
50 3511747 : _PUBLIC_ uint64_t generate_unique_u64(uint64_t veto_value)
51 : {
52 : static struct generate_unique_u64_state {
53 : uint64_t next_value;
54 : int pid;
55 : } generate_unique_u64_state;
56 :
57 3511747 : int pid = getpid();
58 :
59 3511747 : if (unlikely(pid != generate_unique_u64_state.pid)) {
60 14041 : generate_unique_u64_state = (struct generate_unique_u64_state) {
61 : .pid = pid,
62 : .next_value = veto_value,
63 : };
64 : }
65 :
66 6532667 : while (unlikely(generate_unique_u64_state.next_value == veto_value)) {
67 14041 : generate_nonce_buffer(
68 : (void *)&generate_unique_u64_state.next_value,
69 : sizeof(generate_unique_u64_state.next_value));
70 : }
71 :
72 3511747 : return generate_unique_u64_state.next_value++;
73 : }
74 :
75 : /**
76 : Microsoft composed the following rules (among others) for quality
77 : checks. This is an abridgment from
78 : http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx:
79 :
80 : Passwords must contain characters from three of the following five
81 : categories:
82 :
83 : - Uppercase characters of European languages (A through Z, with
84 : diacritic marks, Greek and Cyrillic characters)
85 : - Lowercase characters of European languages (a through z, sharp-s,
86 : with diacritic marks, Greek and Cyrillic characters)
87 : - Base 10 digits (0 through 9)
88 : - Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
89 : - Any Unicode character that is categorized as an alphabetic character
90 : but is not uppercase or lowercase. This includes Unicode characters
91 : from Asian languages.
92 :
93 : Note: for now do not check if the unicode category is
94 : alphabetic character
95 : **/
96 15514 : _PUBLIC_ bool check_password_quality(const char *pwd)
97 : {
98 15514 : size_t ofs = 0;
99 15514 : size_t num_chars = 0;
100 15514 : size_t num_digits = 0;
101 15514 : size_t num_upper = 0;
102 15514 : size_t num_lower = 0;
103 15514 : size_t num_nonalpha = 0;
104 15514 : size_t num_unicode = 0;
105 15514 : size_t num_categories = 0;
106 :
107 15514 : if (pwd == NULL) {
108 0 : return false;
109 : }
110 :
111 350116 : while (true) {
112 365630 : const char *s = &pwd[ofs];
113 365630 : size_t len = 0;
114 : codepoint_t c;
115 :
116 365630 : c = next_codepoint(s, &len);
117 365630 : if (c == INVALID_CODEPOINT) {
118 0 : return false;
119 365630 : } else if (c == 0) {
120 15273 : break;
121 : }
122 350116 : ofs += len;
123 350116 : num_chars += 1;
124 :
125 350116 : if (len == 1) {
126 350076 : const char *na = "~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?/";
127 :
128 350076 : if (isdigit(c)) {
129 53073 : num_digits += 1;
130 386659 : continue;
131 : }
132 :
133 297003 : if (isupper(c)) {
134 102294 : num_upper += 1;
135 102294 : continue;
136 : }
137 :
138 194709 : if (islower(c)) {
139 125048 : num_lower += 1;
140 125048 : continue;
141 : }
142 :
143 69661 : if (strchr(na, c)) {
144 69661 : num_nonalpha += 1;
145 69661 : continue;
146 : }
147 :
148 : /*
149 : * the rest does not belong to
150 : * a category.
151 : */
152 0 : continue;
153 : }
154 :
155 40 : if (isupper_m(c)) {
156 0 : num_upper += 1;
157 0 : continue;
158 : }
159 :
160 40 : if (islower_m(c)) {
161 36 : num_lower += 1;
162 36 : continue;
163 : }
164 :
165 : /*
166 : * Note: for now do not check if the unicode category is
167 : * alphabetic character
168 : *
169 : * We would have to import the details from
170 : * ftp://ftp.unicode.org/Public/6.3.0/ucd/UnicodeData-6.3.0d1.txt
171 : */
172 4 : num_unicode += 1;
173 4 : continue;
174 : }
175 :
176 15514 : if (num_digits > 0) {
177 14409 : num_categories += 1;
178 : }
179 15514 : if (num_upper > 0) {
180 7976 : num_categories += 1;
181 : }
182 15514 : if (num_lower > 0) {
183 15428 : num_categories += 1;
184 : }
185 15514 : if (num_nonalpha > 0) {
186 12830 : num_categories += 1;
187 : }
188 15514 : if (num_unicode > 0) {
189 4 : num_categories += 1;
190 : }
191 :
192 15514 : if (num_categories >= 3) {
193 14977 : return true;
194 : }
195 :
196 313 : return false;
197 : }
198 :
199 : /**
200 : Use the random number generator to generate a random string.
201 : **/
202 :
203 9804 : _PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list)
204 : {
205 : size_t i;
206 9804 : size_t list_len = strlen(list);
207 :
208 9804 : char *retstr = talloc_array(mem_ctx, char, len + 1);
209 9804 : if (!retstr) return NULL;
210 :
211 9804 : generate_secret_buffer((uint8_t *)retstr, len);
212 286685 : for (i = 0; i < len; i++) {
213 276881 : retstr[i] = list[retstr[i] % list_len];
214 : }
215 9804 : retstr[i] = '\0';
216 :
217 9804 : return retstr;
218 : }
219 :
220 : /**
221 : * Generate a random text string consisting of the specified length.
222 : * The returned string will be allocated.
223 : *
224 : * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
225 : */
226 :
227 942 : _PUBLIC_ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
228 : {
229 : char *retstr;
230 942 : const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
231 :
232 1153 : again:
233 1153 : retstr = generate_random_str_list(mem_ctx, len, c_list);
234 1153 : if (!retstr) return NULL;
235 :
236 : /* we need to make sure the random string passes basic quality tests
237 : or it might be rejected by windows as a password */
238 1153 : if (len >= 7 && !check_password_quality(retstr)) {
239 211 : talloc_free(retstr);
240 211 : goto again;
241 : }
242 :
243 934 : return retstr;
244 : }
245 :
246 : /**
247 : * Generate a random text password (based on printable ascii characters).
248 : */
249 :
250 3613 : _PUBLIC_ char *generate_random_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
251 : {
252 : char *retstr;
253 : /* This list does not include { or } because they cause
254 : * problems for our provision (it can create a substring
255 : * ${...}, and for Fedora DS (which treats {...} at the start
256 : * of a stored password as special
257 : * -- Andrew Bartlett 2010-03-11
258 : */
259 3613 : const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~";
260 3613 : size_t len = max;
261 : size_t diff;
262 :
263 3613 : if (min > max) {
264 0 : errno = EINVAL;
265 0 : return NULL;
266 : }
267 :
268 3613 : diff = max - min;
269 :
270 3613 : if (diff > 0 ) {
271 : size_t tmp;
272 :
273 2574 : generate_secret_buffer((uint8_t *)&tmp, sizeof(tmp));
274 :
275 2574 : tmp %= diff;
276 :
277 2574 : len = min + tmp;
278 : }
279 :
280 4287 : again:
281 3651 : retstr = generate_random_str_list(mem_ctx, len, c_list);
282 3651 : if (!retstr) return NULL;
283 :
284 : /* we need to make sure the random string passes basic quality tests
285 : or it might be rejected by windows as a password */
286 3651 : if (len >= 7 && !check_password_quality(retstr)) {
287 38 : talloc_free(retstr);
288 38 : goto again;
289 : }
290 :
291 3463 : return retstr;
292 : }
293 :
294 : /**
295 : * Generate a random machine password (based on random utf16 characters,
296 : * converted to utf8). min must be at least 14, max must be at most 255.
297 : *
298 : * If 'unix charset' is not utf8, the password consist of random ascii
299 : * values!
300 : */
301 :
302 461 : _PUBLIC_ char *generate_random_machine_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
303 : {
304 461 : TALLOC_CTX *frame = NULL;
305 : struct generate_random_machine_password_state {
306 : uint8_t password_buffer[256 * 2];
307 : uint8_t tmp;
308 : } *state;
309 461 : char *new_pw = NULL;
310 461 : size_t len = max;
311 461 : char *utf8_pw = NULL;
312 461 : size_t utf8_len = 0;
313 461 : char *unix_pw = NULL;
314 461 : size_t unix_len = 0;
315 : size_t diff;
316 : size_t i;
317 : bool ok;
318 : int cmp;
319 :
320 461 : if (max > 255) {
321 0 : errno = EINVAL;
322 0 : return NULL;
323 : }
324 :
325 461 : if (min < 14) {
326 0 : errno = EINVAL;
327 0 : return NULL;
328 : }
329 :
330 461 : if (min > max) {
331 0 : errno = EINVAL;
332 0 : return NULL;
333 : }
334 :
335 461 : frame = talloc_stackframe_pool(2048);
336 461 : state = talloc_zero(frame, struct generate_random_machine_password_state);
337 :
338 461 : diff = max - min;
339 :
340 461 : if (diff > 0) {
341 : size_t tmp;
342 :
343 197 : generate_secret_buffer((uint8_t *)&tmp, sizeof(tmp));
344 :
345 197 : tmp %= diff;
346 :
347 197 : len = min + tmp;
348 : }
349 :
350 : /*
351 : * Create a random machine account password
352 : * We create a random buffer and convert that to utf8.
353 : * This is similar to what windows is doing.
354 : *
355 : * In future we may store the raw random buffer,
356 : * but for now we need to pass the password as
357 : * char pointer through some layers.
358 : *
359 : * As most kerberos keys are derived from the
360 : * utf8 password we need to fallback to
361 : * ASCII passwords if "unix charset" is not utf8.
362 : */
363 461 : generate_secret_buffer(state->password_buffer, len * 2);
364 67368 : for (i = 0; i < len; i++) {
365 66907 : size_t idx = i*2;
366 : uint16_t c;
367 :
368 : /*
369 : * both MIT krb5 and HEIMDAL only
370 : * handle codepoints up to 0xffff.
371 : *
372 : * It means we need to avoid
373 : * 0xD800 - 0xDBFF (high surrogate)
374 : * and
375 : * 0xDC00 - 0xDFFF (low surrogate)
376 : * in the random utf16 data.
377 : *
378 : * 55296 0xD800 0154000 0b1101100000000000
379 : * 57343 0xDFFF 0157777 0b1101111111111111
380 : * 8192 0x2000 020000 0b10000000000000
381 : *
382 : * The above values show that we can check
383 : * for 0xD800 and just add 0x2000 to avoid
384 : * the surrogate ranges.
385 : *
386 : * The rest will be handled by CH_UTF16MUNGED
387 : * see utf16_munged_pull().
388 : */
389 66907 : c = SVAL(state->password_buffer, idx);
390 66907 : if (c & 0xD800) {
391 62699 : c |= 0x2000;
392 : }
393 66907 : SSVAL(state->password_buffer, idx, c);
394 : }
395 796 : ok = convert_string_talloc(frame,
396 : CH_UTF16MUNGED, CH_UTF8,
397 421 : state->password_buffer, len * 2,
398 : (void *)&utf8_pw, &utf8_len);
399 461 : if (!ok) {
400 0 : DEBUG(0, ("%s: convert_string_talloc() failed\n",
401 : __func__));
402 0 : TALLOC_FREE(frame);
403 0 : return NULL;
404 : }
405 :
406 796 : ok = convert_string_talloc(frame,
407 : CH_UTF16MUNGED, CH_UNIX,
408 421 : state->password_buffer, len * 2,
409 : (void *)&unix_pw, &unix_len);
410 461 : if (!ok) {
411 0 : goto ascii_fallback;
412 : }
413 :
414 461 : if (utf8_len != unix_len) {
415 0 : goto ascii_fallback;
416 : }
417 :
418 461 : cmp = memcmp((const uint8_t *)utf8_pw,
419 : (const uint8_t *)unix_pw,
420 : utf8_len);
421 461 : if (cmp != 0) {
422 0 : goto ascii_fallback;
423 : }
424 :
425 461 : new_pw = talloc_strdup(mem_ctx, utf8_pw);
426 461 : if (new_pw == NULL) {
427 0 : TALLOC_FREE(frame);
428 0 : return NULL;
429 : }
430 461 : talloc_set_name_const(new_pw, __func__);
431 461 : TALLOC_FREE(frame);
432 421 : return new_pw;
433 :
434 0 : ascii_fallback:
435 0 : for (i = 0; i < len; i++) {
436 : /*
437 : * truncate to ascii
438 : */
439 0 : state->tmp = state->password_buffer[i] & 0x7f;
440 0 : if (state->tmp == 0) {
441 0 : state->tmp = state->password_buffer[i] >> 1;
442 : }
443 0 : if (state->tmp == 0) {
444 0 : state->tmp = 0x01;
445 : }
446 0 : state->password_buffer[i] = state->tmp;
447 : }
448 0 : state->password_buffer[i] = '\0';
449 :
450 0 : new_pw = talloc_strdup(mem_ctx, (const char *)state->password_buffer);
451 0 : if (new_pw == NULL) {
452 0 : TALLOC_FREE(frame);
453 0 : return NULL;
454 : }
455 0 : talloc_set_name_const(new_pw, __func__);
456 0 : TALLOC_FREE(frame);
457 0 : return new_pw;
458 : }
459 :
460 : /**
461 : * Generate an array of unique text strings all of the same length.
462 : * The returned string will be allocated.
463 : * Returns NULL if the number of unique combinations cannot be created.
464 : *
465 : * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
466 : */
467 812 : _PUBLIC_ char** generate_unique_strs(TALLOC_CTX *mem_ctx, size_t len,
468 : uint32_t num)
469 : {
470 812 : const char *c_list = "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
471 812 : const unsigned c_size = 42;
472 : size_t i, j;
473 : unsigned rem;
474 812 : char ** strs = NULL;
475 :
476 812 : if (num == 0 || len == 0)
477 0 : return NULL;
478 :
479 812 : strs = talloc_array(mem_ctx, char *, num);
480 812 : if (strs == NULL) return NULL;
481 :
482 12412 : for (i = 0; i < num; i++) {
483 11600 : char *retstr = (char *)talloc_size(strs, len + 1);
484 11600 : if (retstr == NULL) {
485 0 : talloc_free(strs);
486 0 : return NULL;
487 : }
488 11600 : rem = i;
489 844400 : for (j = 0; j < len; j++) {
490 832800 : retstr[j] = c_list[rem % c_size];
491 832800 : rem = rem / c_size;
492 : }
493 11600 : retstr[j] = 0;
494 11600 : strs[i] = retstr;
495 11600 : if (rem != 0) {
496 : /* we were not able to fit the number of
497 : * combinations asked for in the length
498 : * specified */
499 0 : DEBUG(0,(__location__ ": Too many combinations %u for length %u\n",
500 : num, (unsigned)len));
501 :
502 0 : talloc_free(strs);
503 0 : return NULL;
504 : }
505 : }
506 :
507 812 : return strs;
508 : }
|