obscure.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Copyright 1989 - 1994, Julianne Frances Haugh <jockgrrl@austin.rr.com>
  4. * Copyright 2006, Bernhard Fischer <busybox@busybox.net>
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
  16. * may be used to endorse or promote products derived from this software
  17. * without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
  23. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. */
  31. /*
  32. * This version of obscure.c contains modifications to support "cracklib"
  33. * by Alec Muffet (alec.muffett@uk.sun.com). You must obtain the Cracklib
  34. * library source code for this function to operate.
  35. */
  36. #include <stdlib.h>
  37. #include <stdio.h>
  38. #include <string.h>
  39. #include <ctype.h>
  40. #include "libbb.h"
  41. /*
  42. * can't be a palindrome - like `R A D A R' or `M A D A M'
  43. */
  44. static int palindrome(const char *newval)
  45. {
  46. int i, j;
  47. i = strlen(newval);
  48. for (j = 0; j < i; j++)
  49. if (newval[i - j - 1] != newval[j])
  50. return 0;
  51. return 1;
  52. }
  53. /*
  54. * more than half of the characters are different ones.
  55. */
  56. static int similiar(const char *old, const char *newval)
  57. {
  58. int i, j;
  59. for (i = j = 0; newval[i] && old[i]; i++)
  60. if (strchr(newval, old[i]))
  61. j++;
  62. if (i >= j * 2)
  63. return 0;
  64. return 1;
  65. }
  66. /*
  67. * a nice mix of characters.
  68. */
  69. static int simple(const char *newval)
  70. {
  71. #define digits 1
  72. #define uppers 2
  73. #define lowers 4
  74. #define others 8
  75. int c, is_simple = 0;
  76. int size;
  77. int i;
  78. for (i = 0; (c = *newval++) != 0; i++) {
  79. if (isdigit(c))
  80. is_simple |= digits;
  81. else if (isupper(c))
  82. is_simple |= uppers;
  83. else if (islower(c))
  84. is_simple |= lowers;
  85. else
  86. is_simple |= others;
  87. }
  88. /*
  89. * The scam is this - a password of only one character type
  90. * must be 8 letters long. Two types, 7, and so on.
  91. */
  92. size = 9;
  93. if (is_simple & digits)
  94. size--;
  95. if (is_simple & uppers)
  96. size--;
  97. if (is_simple & lowers)
  98. size--;
  99. if (is_simple & others)
  100. size--;
  101. if (size <= i)
  102. return 0;
  103. return 1;
  104. #undef digits
  105. #undef uppers
  106. #undef lowers
  107. #undef others
  108. }
  109. static char *str_lower(char *string)
  110. {
  111. char *cp;
  112. for (cp = string; *cp; cp++)
  113. *cp = tolower(*cp);
  114. return string;
  115. }
  116. static const char *
  117. password_check(const char *old, const char *newval, const struct passwd *pwdp)
  118. {
  119. const char *msg;
  120. char *newmono, *wrapped;
  121. int lenwrap;
  122. if (strcmp(newval, old) == 0)
  123. return "no change";
  124. if (simple(newval))
  125. return "too simple";
  126. msg = NULL;
  127. newmono = str_lower(bb_xstrdup(newval));
  128. lenwrap = strlen(old);
  129. wrapped = (char *) xmalloc(lenwrap * 2 + 1);
  130. str_lower(strcpy(wrapped, old));
  131. if (palindrome(newmono))
  132. msg = "a palindrome";
  133. else if (strcmp(wrapped, newmono) == 0)
  134. msg = "case changes only";
  135. else if (similiar(wrapped, newmono))
  136. msg = "too similiar";
  137. else if ( strstr(newval, pwdp->pw_name) )
  138. msg = "username in password";
  139. else {
  140. safe_strncpy(wrapped + lenwrap, wrapped, lenwrap + 1);
  141. if (strstr(wrapped, newmono))
  142. msg = "rotated";
  143. }
  144. memset(newmono, 0, strlen(newmono));
  145. memset(wrapped, 0, lenwrap * 2);
  146. free(newmono);
  147. free(wrapped);
  148. return msg;
  149. }
  150. static const char *
  151. obscure_msg(const char *old, const char *newval, const struct passwd *pwdp)
  152. {
  153. int maxlen, oldlen, newlen;
  154. char *new1, *old1;
  155. const char *msg;
  156. oldlen = strlen(old);
  157. newlen = strlen(newval);
  158. #if 0 /* why not check the password when set for the first time? --marekm */
  159. if (old[0] == '\0')
  160. /* return (1); */
  161. return NULL;
  162. #endif
  163. if (newlen < 5)
  164. return "too short";
  165. /*
  166. * Remaining checks are optional.
  167. */
  168. /* Not for us -- Sean
  169. *if (!getdef_bool("OBSCURE_CHECKS_ENAB"))
  170. * return NULL;
  171. */
  172. msg = password_check(old, newval, pwdp);
  173. if (msg)
  174. return msg;
  175. /* The traditional crypt() truncates passwords to 8 chars. It is
  176. possible to circumvent the above checks by choosing an easy
  177. 8-char password and adding some random characters to it...
  178. Example: "password$%^&*123". So check it again, this time
  179. truncated to the maximum length. Idea from npasswd. --marekm */
  180. maxlen = 8;
  181. if (oldlen <= maxlen && newlen <= maxlen)
  182. return NULL;
  183. new1 = (char *) bb_xstrdup(newval);
  184. old1 = (char *) bb_xstrdup(old);
  185. if (newlen > maxlen)
  186. new1[maxlen] = '\0';
  187. if (oldlen > maxlen)
  188. old1[maxlen] = '\0';
  189. msg = password_check(old1, new1, pwdp);
  190. memset(new1, 0, newlen);
  191. memset(old1, 0, oldlen);
  192. free(new1);
  193. free(old1);
  194. return msg;
  195. }
  196. /*
  197. * Obscure - see if password is obscure enough.
  198. *
  199. * The programmer is encouraged to add as much complexity to this
  200. * routine as desired. Included are some of my favorite ways to
  201. * check passwords.
  202. */
  203. int obscure(const char *old, const char *newval, const struct passwd *pwdp)
  204. {
  205. const char *msg = obscure_msg(old, newval, pwdp);
  206. /* if (msg) { */
  207. if (msg != NULL) {
  208. printf("Bad password: %s.\n", msg);
  209. /* return 0; */
  210. return 1;
  211. }
  212. /* return 1; */
  213. return 0;
  214. }