LCOV - code coverage report
Current view: top level - lib/util - genrand_util.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 136 199 68.3 %
Date: 2024-06-13 04:01:37 Functions: 9 10 90.0 %

          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 "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      237036 : _PUBLIC_ uint32_t generate_random(void)
      37             : {
      38             :         uint8_t v[4];
      39      237036 :         generate_random_buffer(v, 4);
      40      237036 :         return IVAL(v, 0);
      41             : }
      42             : 
      43             : /**
      44             :   @brief generate a random uint64
      45             : **/
      46       71065 : _PUBLIC_ uint64_t generate_random_u64(void)
      47             : {
      48             :         uint8_t v[8];
      49       71065 :         generate_random_buffer(v, 8);
      50       71065 :         return BVAL(v, 0);
      51             : }
      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          11 : _PUBLIC_ uint64_t generate_random_u64_range(uint64_t lower, uint64_t upper)
      63             : {
      64          11 :         return generate_random_u64() % (upper - lower) + lower;
      65             : }
      66             : 
      67      132916 : _PUBLIC_ uint64_t generate_unique_u64(uint64_t veto_value)
      68             : {
      69             :         static struct generate_unique_u64_state {
      70             :                 uint64_t next_value;
      71             :                 int pid;
      72             :         } generate_unique_u64_state;
      73             : 
      74      132916 :         int pid = tevent_cached_getpid();
      75             : 
      76      132916 :         if (unlikely(pid != generate_unique_u64_state.pid)) {
      77        1193 :                 generate_unique_u64_state = (struct generate_unique_u64_state) {
      78             :                         .pid = pid,
      79             :                         .next_value = veto_value,
      80             :                 };
      81             :         }
      82             : 
      83      252100 :         while (unlikely(generate_unique_u64_state.next_value == veto_value)) {
      84        1193 :                 generate_nonce_buffer(
      85             :                                 (void *)&generate_unique_u64_state.next_value,
      86             :                                 sizeof(generate_unique_u64_state.next_value));
      87             :         }
      88             : 
      89      132916 :         return generate_unique_u64_state.next_value++;
      90             : }
      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       14435 : _PUBLIC_ bool check_password_quality(const char *pwd)
     114             : {
     115       14435 :         size_t ofs = 0;
     116       14435 :         size_t num_digits = 0;
     117       14435 :         size_t num_upper = 0;
     118       14435 :         size_t num_lower = 0;
     119       14435 :         size_t num_nonalpha = 0;
     120       14435 :         size_t num_unicode = 0;
     121       14435 :         size_t num_categories = 0;
     122             : 
     123       14435 :         if (pwd == NULL) {
     124           0 :                 return false;
     125             :         }
     126             : 
     127      253487 :         while (true) {
     128      267922 :                 const char *s = &pwd[ofs];
     129      267922 :                 size_t len = 0;
     130             :                 codepoint_t c;
     131             : 
     132      267922 :                 c = next_codepoint(s, &len);
     133      267922 :                 if (c == INVALID_CODEPOINT) {
     134           0 :                         return false;
     135      267922 :                 } else if (c == 0) {
     136       14435 :                         break;
     137             :                 }
     138      253487 :                 ofs += len;
     139             : 
     140      253487 :                 if (len == 1) {
     141      253486 :                         const char *na = "~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?/";
     142             : 
     143      253486 :                         if (isdigit(c)) {
     144       44538 :                                 num_digits += 1;
     145      285038 :                                 continue;
     146             :                         }
     147             : 
     148      208948 :                         if (isupper(c)) {
     149       61508 :                                 num_upper += 1;
     150       61508 :                                 continue;
     151             :                         }
     152             : 
     153      147440 :                         if (islower(c)) {
     154      100367 :                                 num_lower += 1;
     155      100367 :                                 continue;
     156             :                         }
     157             : 
     158       47073 :                         if (strchr(na, c)) {
     159       47001 :                                 num_nonalpha += 1;
     160       47001 :                                 continue;
     161             :                         }
     162             : 
     163             :                         /*
     164             :                          * the rest does not belong to
     165             :                          * a category.
     166             :                          */
     167          72 :                         continue;
     168             :                 }
     169             : 
     170           1 :                 if (isupper_m(c)) {
     171           0 :                         num_upper += 1;
     172           0 :                         continue;
     173             :                 }
     174             : 
     175           1 :                 if (islower_m(c)) {
     176           1 :                         num_lower += 1;
     177           1 :                         continue;
     178             :                 }
     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             :         }
     190             : 
     191       14435 :         if (num_digits > 0) {
     192       13668 :                 num_categories += 1;
     193             :         }
     194       14435 :         if (num_upper > 0) {
     195        5414 :                 num_categories += 1;
     196             :         }
     197       14435 :         if (num_lower > 0) {
     198       14374 :                 num_categories += 1;
     199             :         }
     200       14435 :         if (num_nonalpha > 0) {
     201       12734 :                 num_categories += 1;
     202             :         }
     203       14435 :         if (num_unicode > 0) {
     204           0 :                 num_categories += 1;
     205             :         }
     206             : 
     207       14435 :         if (num_categories >= 3) {
     208       14325 :                 return true;
     209             :         }
     210             : 
     211         110 :         return false;
     212             : }
     213             : 
     214             : /**
     215             :  Use the random number generator to generate a random string.
     216             : **/
     217             : 
     218        3484 : _PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list)
     219             : {
     220             :         size_t i;
     221        3484 :         size_t list_len = strlen(list);
     222             : 
     223        3484 :         char *retstr = talloc_array(mem_ctx, char, len + 1);
     224        3484 :         if (!retstr) return NULL;
     225             : 
     226        3484 :         generate_secret_buffer((uint8_t *)retstr, len);
     227      135919 :         for (i = 0; i < len; i++) {
     228      132435 :                 retstr[i] = list[retstr[i] % list_len];
     229             :         }
     230        3484 :         retstr[i] = '\0';
     231             : 
     232        3484 :         return retstr;
     233             : }
     234             : 
     235             : /**
     236             :  * Generate a random text string consisting of the specified length.
     237             :  * The returned string will be allocated.
     238             :  *
     239             :  * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
     240             :  */
     241             : 
     242         226 : _PUBLIC_ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
     243             : {
     244             :         char *retstr;
     245         226 :         const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
     246             : 
     247         256 : again:
     248         256 :         retstr = generate_random_str_list(mem_ctx, len, c_list);
     249         256 :         if (!retstr) return NULL;
     250             : 
     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         256 :         if (len >= 7 && !check_password_quality(retstr)) {
     254          30 :                 talloc_free(retstr);
     255          30 :                 goto again;
     256             :         }
     257             : 
     258         226 :         return retstr;
     259             : }
     260             : 
     261             : /**
     262             :  * Generate a random text password (based on printable ascii characters).
     263             :  */
     264             : 
     265        2491 : _PUBLIC_ char *generate_random_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
     266             : {
     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
     273             :          */
     274        2491 :         const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~";
     275        2491 :         size_t len = max;
     276             :         size_t diff;
     277             : 
     278        2491 :         if (min > max) {
     279           0 :                 errno = EINVAL;
     280           0 :                 return NULL;
     281             :         }
     282             : 
     283        2491 :         diff = max - min;
     284             : 
     285        2491 :         if (diff > 0 ) {
     286             :                 size_t tmp;
     287             : 
     288        1712 :                 generate_secret_buffer((uint8_t *)&tmp, sizeof(tmp));
     289             : 
     290        1712 :                 tmp %= diff;
     291             : 
     292        1712 :                 len = min + tmp;
     293             :         }
     294             : 
     295        3148 : again:
     296        2518 :         retstr = generate_random_str_list(mem_ctx, len, c_list);
     297        2518 :         if (!retstr) return NULL;
     298             : 
     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        2518 :         if (len >= 7 && !check_password_quality(retstr)) {
     302          27 :                 talloc_free(retstr);
     303          27 :                 goto again;
     304             :         }
     305             : 
     306        2491 :         return retstr;
     307             : }
     308             : 
     309             : /**
     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.
     312             :  *
     313             :  * If 'unix charset' is not utf8, the password consist of random ascii
     314             :  * values!
     315             :  */
     316             : 
     317         379 : _PUBLIC_ char *generate_random_machine_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
     318             : {
     319         379 :         TALLOC_CTX *frame = NULL;
     320             :         struct generate_random_machine_password_state {
     321             :                 uint8_t password_buffer[256 * 2];
     322             :                 uint8_t tmp;
     323             :         } *state;
     324         379 :         char *new_pw = NULL;
     325         379 :         size_t len = max;
     326         379 :         char *utf8_pw = NULL;
     327         379 :         size_t utf8_len = 0;
     328         379 :         char *unix_pw = NULL;
     329         379 :         size_t unix_len = 0;
     330             :         size_t diff;
     331             :         size_t i;
     332             :         bool ok;
     333             :         int cmp;
     334             : 
     335         379 :         if (max > 255) {
     336           0 :                 errno = EINVAL;
     337           0 :                 return NULL;
     338             :         }
     339             : 
     340         379 :         if (min < 14) {
     341           0 :                 errno = EINVAL;
     342           0 :                 return NULL;
     343             :         }
     344             : 
     345         379 :         if (min > max) {
     346           0 :                 errno = EINVAL;
     347           0 :                 return NULL;
     348             :         }
     349             : 
     350         379 :         frame = talloc_stackframe_pool(2048);
     351         379 :         state = talloc_zero(frame, struct generate_random_machine_password_state);
     352             : 
     353         379 :         diff = max - min;
     354             : 
     355         379 :         if (diff > 0) {
     356             :                 size_t tmp;
     357             : 
     358          88 :                 generate_secret_buffer((uint8_t *)&tmp, sizeof(tmp));
     359             : 
     360          88 :                 tmp %= diff;
     361             : 
     362          88 :                 len = min + tmp;
     363             :         }
     364             : 
     365             :         /*
     366             :          * Create a random machine account password
     367             :          * We create a random buffer and convert that to utf8.
     368             :          * This is similar to what windows is doing.
     369             :          *
     370             :          * In future we may store the raw random buffer,
     371             :          * but for now we need to pass the password as
     372             :          * char pointer through some layers.
     373             :          *
     374             :          * As most kerberos keys are derived from the
     375             :          * utf8 password we need to fallback to
     376             :          * ASCII passwords if "unix charset" is not utf8.
     377             :          */
     378         379 :         generate_secret_buffer(state->password_buffer, len * 2);
     379       51561 :         for (i = 0; i < len; i++) {
     380       51182 :                 size_t idx = i*2;
     381             :                 uint16_t c;
     382             : 
     383             :                 /*
     384             :                  * both MIT krb5 and HEIMDAL only
     385             :                  * handle codepoints up to 0xffff.
     386             :                  *
     387             :                  * It means we need to avoid
     388             :                  * 0xD800 - 0xDBFF (high surrogate)
     389             :                  * and
     390             :                  * 0xDC00 - 0xDFFF (low surrogate)
     391             :                  * in the random utf16 data.
     392             :                  *
     393             :                  * 55296 0xD800 0154000 0b1101100000000000
     394             :                  * 57343 0xDFFF 0157777 0b1101111111111111
     395             :                  * 8192  0x2000  020000   0b10000000000000
     396             :                  *
     397             :                  * The above values show that we can check
     398             :                  * for 0xD800 and just add 0x2000 to avoid
     399             :                  * the surrogate ranges.
     400             :                  *
     401             :                  * The rest will be handled by CH_UTF16MUNGED
     402             :                  * see utf16_munged_pull().
     403             :                  */
     404       51182 :                 c = SVAL(state->password_buffer, idx);
     405       51182 :                 if (c & 0xD800) {
     406       47983 :                         c |= 0x2000;
     407             :                 }
     408       51182 :                 SSVAL(state->password_buffer, idx, c);
     409             :         }
     410         688 :         ok = convert_string_talloc(frame,
     411             :                                    CH_UTF16MUNGED, CH_UTF8,
     412         379 :                                    state->password_buffer, len * 2,
     413             :                                    (void *)&utf8_pw, &utf8_len);
     414         379 :         if (!ok) {
     415           0 :                 DEBUG(0, ("%s: convert_string_talloc() failed\n",
     416             :                           __func__));
     417           0 :                 TALLOC_FREE(frame);
     418           0 :                 return NULL;
     419             :         }
     420             : 
     421         688 :         ok = convert_string_talloc(frame,
     422             :                                    CH_UTF16MUNGED, CH_UNIX,
     423         379 :                                    state->password_buffer, len * 2,
     424             :                                    (void *)&unix_pw, &unix_len);
     425         379 :         if (!ok) {
     426           0 :                 goto ascii_fallback;
     427             :         }
     428             : 
     429         379 :         if (utf8_len != unix_len) {
     430           0 :                 goto ascii_fallback;
     431             :         }
     432             : 
     433         379 :         cmp = memcmp((const uint8_t *)utf8_pw,
     434             :                      (const uint8_t *)unix_pw,
     435             :                      utf8_len);
     436         379 :         if (cmp != 0) {
     437           0 :                 goto ascii_fallback;
     438             :         }
     439             : 
     440         379 :         new_pw = talloc_strdup(mem_ctx, utf8_pw);
     441         379 :         if (new_pw == NULL) {
     442           0 :                 TALLOC_FREE(frame);
     443           0 :                 return NULL;
     444             :         }
     445         379 :         talloc_set_name_const(new_pw, __func__);
     446         379 :         TALLOC_FREE(frame);
     447         379 :         return new_pw;
     448             : 
     449           0 : ascii_fallback:
     450           0 :         for (i = 0; i < len; i++) {
     451             :                 /*
     452             :                  * truncate to ascii
     453             :                  */
     454           0 :                 state->tmp = state->password_buffer[i] & 0x7f;
     455           0 :                 if (state->tmp == 0) {
     456           0 :                         state->tmp = state->password_buffer[i] >> 1;
     457             :                 }
     458           0 :                 if (state->tmp == 0) {
     459           0 :                         state->tmp = 0x01;
     460             :                 }
     461           0 :                 state->password_buffer[i] = state->tmp;
     462             :         }
     463           0 :         state->password_buffer[i] = '\0';
     464             : 
     465           0 :         new_pw = talloc_strdup(mem_ctx, (const char *)state->password_buffer);
     466           0 :         if (new_pw == NULL) {
     467           0 :                 TALLOC_FREE(frame);
     468           0 :                 return NULL;
     469             :         }
     470           0 :         talloc_set_name_const(new_pw, __func__);
     471           0 :         TALLOC_FREE(frame);
     472           0 :         return new_pw;
     473             : }
     474             : 
     475             : /**
     476             :  * Generate an array of unique text strings all of the same length.
     477             :  * The returned string will be allocated.
     478             :  * Returns NULL if the number of unique combinations cannot be created.
     479             :  *
     480             :  * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
     481             :  */
     482           0 : _PUBLIC_ char** generate_unique_strs(TALLOC_CTX *mem_ctx, size_t len,
     483             :                                      uint32_t num)
     484             : {
     485           0 :         const char *c_list = "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
     486           0 :         const unsigned c_size = 42;
     487             :         size_t i, j;
     488             :         unsigned rem;
     489           0 :         char ** strs = NULL;
     490             : 
     491           0 :         if (num == 0 || len == 0)
     492           0 :                 return NULL;
     493             : 
     494           0 :         strs = talloc_array(mem_ctx, char *, num);
     495           0 :         if (strs == NULL) return NULL;
     496             : 
     497           0 :         for (i = 0; i < num; i++) {
     498           0 :                 char *retstr = (char *)talloc_size(strs, len + 1);
     499           0 :                 if (retstr == NULL) {
     500           0 :                         talloc_free(strs);
     501           0 :                         return NULL;
     502             :                 }
     503           0 :                 rem = i;
     504           0 :                 for (j = 0; j < len; j++) {
     505           0 :                         retstr[j] = c_list[rem % c_size];
     506           0 :                         rem = rem / c_size;
     507             :                 }
     508           0 :                 retstr[j] = 0;
     509           0 :                 strs[i] = retstr;
     510           0 :                 if (rem != 0) {
     511             :                         /* we were not able to fit the number of
     512             :                          * combinations asked for in the length
     513             :                          * specified */
     514           0 :                         DEBUG(0,(__location__ ": Too many combinations %u for length %u\n",
     515             :                                  num, (unsigned)len));
     516             : 
     517           0 :                         talloc_free(strs);
     518           0 :                         return NULL;
     519             :                 }
     520             :         }
     521             : 
     522           0 :         return strs;
     523             : }

Generated by: LCOV version 1.13