s3: smbd: Sanitize any "server" and "share" components of SMB1 DFS paths to remove...
[Samba.git] / lib / util / genrand_util.c
blob43005c5666600cd30bf1db00939c734740629ba3
1 /*
2 Unix SMB/CIFS implementation.
4 Functions to create reasonable random numbers for crypto use.
6 Copyright (C) Jeremy Allison 2001
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.
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.
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/>.
22 #include "replace.h"
23 #include "system/locale.h"
24 #include <tevent.h>
25 #include "lib/util/samba_util.h"
26 #include "lib/util/debug.h"
28 /**
29 * @file
30 * @brief Random number generation
33 /**
34 generate a single random uint32_t
35 **/
36 _PUBLIC_ uint32_t generate_random(void)
38 uint8_t v[4];
39 generate_random_buffer(v, 4);
40 return IVAL(v, 0);
43 /**
44 @brief generate a random uint64
45 **/
46 _PUBLIC_ uint64_t generate_random_u64(void)
48 uint8_t v[8];
49 generate_random_buffer(v, 8);
50 return BVAL(v, 0);
53 /**
54 * @brief Generate a random number in the given range.
56 * @param lower The lower value of the range
58 * @param upper The upper value of the range
60 * @return A random number bigger than than lower and smaller than upper.
62 _PUBLIC_ uint64_t generate_random_u64_range(uint64_t lower, uint64_t upper)
64 return generate_random_u64() % (upper - lower) + lower;
67 _PUBLIC_ uint64_t generate_unique_u64(uint64_t veto_value)
69 static struct generate_unique_u64_state {
70 uint64_t next_value;
71 int pid;
72 } generate_unique_u64_state;
74 int pid = tevent_cached_getpid();
76 if (unlikely(pid != generate_unique_u64_state.pid)) {
77 generate_unique_u64_state = (struct generate_unique_u64_state) {
78 .pid = pid,
79 .next_value = veto_value,
83 while (unlikely(generate_unique_u64_state.next_value == veto_value)) {
84 generate_nonce_buffer(
85 (void *)&generate_unique_u64_state.next_value,
86 sizeof(generate_unique_u64_state.next_value));
89 return generate_unique_u64_state.next_value++;
92 /**
93 Microsoft composed the following rules (among others) for quality
94 checks. This is an abridgment from
95 http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx:
97 Passwords must contain characters from three of the following five
98 categories:
100 - Uppercase characters of European languages (A through Z, with
101 diacritic marks, Greek and Cyrillic characters)
102 - Lowercase characters of European languages (a through z, sharp-s,
103 with diacritic marks, Greek and Cyrillic characters)
104 - Base 10 digits (0 through 9)
105 - Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
106 - Any Unicode character that is categorized as an alphabetic character
107 but is not uppercase or lowercase. This includes Unicode characters
108 from Asian languages.
110 Note: for now do not check if the unicode category is
111 alphabetic character
113 _PUBLIC_ bool check_password_quality(const char *pwd)
115 size_t ofs = 0;
116 size_t num_digits = 0;
117 size_t num_upper = 0;
118 size_t num_lower = 0;
119 size_t num_nonalpha = 0;
120 size_t num_unicode = 0;
121 size_t num_categories = 0;
123 if (pwd == NULL) {
124 return false;
127 while (true) {
128 const char *s = &pwd[ofs];
129 size_t len = 0;
130 codepoint_t c;
132 c = next_codepoint(s, &len);
133 if (c == INVALID_CODEPOINT) {
134 return false;
135 } else if (c == 0) {
136 break;
138 ofs += len;
140 if (len == 1) {
141 const char *na = "~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?/";
143 if (isdigit(c)) {
144 num_digits += 1;
145 continue;
148 if (isupper(c)) {
149 num_upper += 1;
150 continue;
153 if (islower(c)) {
154 num_lower += 1;
155 continue;
158 if (strchr(na, c)) {
159 num_nonalpha += 1;
160 continue;
164 * the rest does not belong to
165 * a category.
167 continue;
170 if (isupper_m(c)) {
171 num_upper += 1;
172 continue;
175 if (islower_m(c)) {
176 num_lower += 1;
177 continue;
181 * Note: for now do not check if the unicode category is
182 * alphabetic character
184 * We would have to import the details from
185 * ftp://ftp.unicode.org/Public/6.3.0/ucd/UnicodeData-6.3.0d1.txt
187 num_unicode += 1;
188 continue;
191 if (num_digits > 0) {
192 num_categories += 1;
194 if (num_upper > 0) {
195 num_categories += 1;
197 if (num_lower > 0) {
198 num_categories += 1;
200 if (num_nonalpha > 0) {
201 num_categories += 1;
203 if (num_unicode > 0) {
204 num_categories += 1;
207 if (num_categories >= 3) {
208 return true;
211 return false;
215 Use the random number generator to generate a random string.
218 _PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list)
220 size_t i;
221 size_t list_len = strlen(list);
223 char *retstr = talloc_array(mem_ctx, char, len + 1);
224 if (!retstr) return NULL;
226 generate_secret_buffer((uint8_t *)retstr, len);
227 for (i = 0; i < len; i++) {
228 retstr[i] = list[retstr[i] % list_len];
230 retstr[i] = '\0';
232 return retstr;
236 * Generate a random text string consisting of the specified length.
237 * The returned string will be allocated.
239 * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
242 _PUBLIC_ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
244 char *retstr;
245 const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
247 again:
248 retstr = generate_random_str_list(mem_ctx, len, c_list);
249 if (!retstr) return NULL;
251 /* we need to make sure the random string passes basic quality tests
252 or it might be rejected by windows as a password */
253 if (len >= 7 && !check_password_quality(retstr)) {
254 talloc_free(retstr);
255 goto again;
258 return retstr;
262 * Generate a random text password (based on printable ascii characters).
265 _PUBLIC_ char *generate_random_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
267 char *retstr;
268 /* This list does not include { or } because they cause
269 * problems for our provision (it can create a substring
270 * ${...}, and for Fedora DS (which treats {...} at the start
271 * of a stored password as special
272 * -- Andrew Bartlett 2010-03-11
274 const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~";
275 size_t len = max;
276 size_t diff;
278 if (min > max) {
279 errno = EINVAL;
280 return NULL;
283 diff = max - min;
285 if (diff > 0 ) {
286 size_t tmp;
288 generate_secret_buffer((uint8_t *)&tmp, sizeof(tmp));
290 tmp %= diff;
292 len = min + tmp;
295 again:
296 retstr = generate_random_str_list(mem_ctx, len, c_list);
297 if (!retstr) return NULL;
299 /* we need to make sure the random string passes basic quality tests
300 or it might be rejected by windows as a password */
301 if (len >= 7 && !check_password_quality(retstr)) {
302 talloc_free(retstr);
303 goto again;
306 return retstr;
310 * Generate a random machine password (based on random utf16 characters,
311 * converted to utf8). min must be at least 14, max must be at most 255.
313 * If 'unix charset' is not utf8, the password consist of random ascii
314 * values!
316 * The return value is a talloc string with destructor talloc_keep_secret() set.
317 * The content will be overwritten by zeros when the mem_ctx is destroyed.
320 _PUBLIC_ char *generate_random_machine_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
322 TALLOC_CTX *frame = NULL;
323 struct generate_random_machine_password_state {
324 uint8_t password_buffer[256 * 2];
325 uint8_t tmp;
326 } *state;
327 char *new_pw = NULL;
328 size_t len = max;
329 char *utf8_pw = NULL;
330 size_t utf8_len = 0;
331 char *unix_pw = NULL;
332 size_t unix_len = 0;
333 size_t diff;
334 size_t i;
335 bool ok;
336 int cmp;
338 if (max > 255) {
339 errno = EINVAL;
340 return NULL;
343 if (min < 14) {
344 errno = EINVAL;
345 return NULL;
348 if (min > max) {
349 errno = EINVAL;
350 return NULL;
353 frame = talloc_stackframe_pool(2048);
354 state = talloc_zero(frame, struct generate_random_machine_password_state);
355 talloc_keep_secret(state);
357 diff = max - min;
359 if (diff > 0) {
360 size_t tmp;
362 generate_secret_buffer((uint8_t *)&tmp, sizeof(tmp));
364 tmp %= diff;
366 len = min + tmp;
370 * Create a random machine account password
371 * We create a random buffer and convert that to utf8.
372 * This is similar to what windows is doing.
374 * In future we may store the raw random buffer,
375 * but for now we need to pass the password as
376 * char pointer through some layers.
378 * As most kerberos keys are derived from the
379 * utf8 password we need to fallback to
380 * ASCII passwords if "unix charset" is not utf8.
382 generate_secret_buffer(state->password_buffer, len * 2);
383 for (i = 0; i < len; i++) {
384 size_t idx = i*2;
385 uint16_t c;
388 * both MIT krb5 and HEIMDAL only
389 * handle codepoints up to 0xffff.
391 * It means we need to avoid
392 * 0xD800 - 0xDBFF (high surrogate)
393 * and
394 * 0xDC00 - 0xDFFF (low surrogate)
395 * in the random utf16 data.
397 * 55296 0xD800 0154000 0b1101100000000000
398 * 57343 0xDFFF 0157777 0b1101111111111111
399 * 8192 0x2000 020000 0b10000000000000
401 * The above values show that we can check
402 * for 0xD800 and just add 0x2000 to avoid
403 * the surrogate ranges.
405 * The rest will be handled by CH_UTF16MUNGED
406 * see utf16_munged_pull().
408 c = SVAL(state->password_buffer, idx);
409 if (c & 0xD800) {
410 c |= 0x2000;
412 SSVAL(state->password_buffer, idx, c);
414 ok = convert_string_talloc(frame,
415 CH_UTF16MUNGED, CH_UTF8,
416 state->password_buffer, len * 2,
417 (void *)&utf8_pw, &utf8_len);
418 if (!ok) {
419 DEBUG(0, ("%s: convert_string_talloc() failed\n",
420 __func__));
421 TALLOC_FREE(frame);
422 return NULL;
424 talloc_keep_secret(utf8_pw);
426 ok = convert_string_talloc(frame,
427 CH_UTF16MUNGED, CH_UNIX,
428 state->password_buffer, len * 2,
429 (void *)&unix_pw, &unix_len);
430 if (!ok) {
431 goto ascii_fallback;
433 talloc_keep_secret(unix_pw);
435 if (utf8_len != unix_len) {
436 goto ascii_fallback;
439 cmp = memcmp((const uint8_t *)utf8_pw,
440 (const uint8_t *)unix_pw,
441 utf8_len);
442 if (cmp != 0) {
443 goto ascii_fallback;
446 new_pw = talloc_strdup(mem_ctx, utf8_pw);
447 if (new_pw == NULL) {
448 TALLOC_FREE(frame);
449 return NULL;
451 talloc_keep_secret(new_pw);
452 talloc_set_name_const(new_pw, __func__);
453 TALLOC_FREE(frame);
454 return new_pw;
456 ascii_fallback:
457 for (i = 0; i < len; i++) {
459 * truncate to ascii
461 state->tmp = state->password_buffer[i] & 0x7f;
462 if (state->tmp == 0) {
463 state->tmp = state->password_buffer[i] >> 1;
465 if (state->tmp == 0) {
466 state->tmp = 0x01;
468 state->password_buffer[i] = state->tmp;
470 state->password_buffer[i] = '\0';
472 new_pw = talloc_strdup(mem_ctx, (const char *)state->password_buffer);
473 if (new_pw == NULL) {
474 TALLOC_FREE(frame);
475 return NULL;
477 talloc_keep_secret(new_pw);
478 talloc_set_name_const(new_pw, __func__);
479 TALLOC_FREE(frame);
480 return new_pw;
484 * Generate an array of unique text strings all of the same length.
485 * The returned string will be allocated.
486 * Returns NULL if the number of unique combinations cannot be created.
488 * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
490 _PUBLIC_ char** generate_unique_strs(TALLOC_CTX *mem_ctx, size_t len,
491 uint32_t num)
493 const char *c_list = "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
494 const unsigned c_size = 42;
495 size_t i, j;
496 unsigned rem;
497 char ** strs = NULL;
499 if (num == 0 || len == 0)
500 return NULL;
502 strs = talloc_array(mem_ctx, char *, num);
503 if (strs == NULL) return NULL;
505 for (i = 0; i < num; i++) {
506 char *retstr = (char *)talloc_size(strs, len + 1);
507 if (retstr == NULL) {
508 talloc_free(strs);
509 return NULL;
511 rem = i;
512 for (j = 0; j < len; j++) {
513 retstr[j] = c_list[rem % c_size];
514 rem = rem / c_size;
516 retstr[j] = 0;
517 strs[i] = retstr;
518 if (rem != 0) {
519 /* we were not able to fit the number of
520 * combinations asked for in the length
521 * specified */
522 DEBUG(0,(__location__ ": Too many combinations %u for length %u\n",
523 num, (unsigned)len));
525 talloc_free(strs);
526 return NULL;
530 return strs;