Coverage Report

Created: 2025-07-23 07:04

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