passwd.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  4. */
  5. #include "libbb.h"
  6. #include <syslog.h>
  7. static void nuke_str(char *str)
  8. {
  9. if (str) memset(str, 0, strlen(str));
  10. }
  11. static char* new_password(const struct passwd *pw, uid_t myuid, int algo)
  12. {
  13. char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */
  14. char *orig = (char*)"";
  15. char *newp = NULL;
  16. char *cp = NULL;
  17. char *ret = NULL; /* failure so far */
  18. if (myuid && pw->pw_passwd[0]) {
  19. char *encrypted;
  20. orig = bb_ask_stdin("Old password:"); /* returns ptr to static */
  21. if (!orig)
  22. goto err_ret;
  23. encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
  24. if (strcmp(encrypted, pw->pw_passwd) != 0) {
  25. syslog(LOG_WARNING, "incorrect password for %s",
  26. pw->pw_name);
  27. bb_do_delay(FAIL_DELAY);
  28. puts("Incorrect password");
  29. goto err_ret;
  30. }
  31. if (ENABLE_FEATURE_CLEAN_UP) free(encrypted);
  32. }
  33. orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */
  34. newp = bb_ask_stdin("New password:"); /* returns ptr to static */
  35. if (!newp)
  36. goto err_ret;
  37. newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */
  38. if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
  39. && obscure(orig, newp, pw) && myuid)
  40. goto err_ret; /* non-root is not allowed to have weak passwd */
  41. cp = bb_ask_stdin("Retype password:");
  42. if (!cp)
  43. goto err_ret;
  44. if (strcmp(cp, newp)) {
  45. puts("Passwords don't match");
  46. goto err_ret;
  47. }
  48. crypt_make_salt(salt, 1, 0); /* des */
  49. if (algo) { /* MD5 */
  50. strcpy(salt, "$1$");
  51. crypt_make_salt(salt + 3, 4, 0);
  52. }
  53. /* pw_encrypt returns malloced str */
  54. ret = pw_encrypt(newp, salt, 1);
  55. /* whee, success! */
  56. err_ret:
  57. nuke_str(orig);
  58. if (ENABLE_FEATURE_CLEAN_UP) free(orig);
  59. nuke_str(newp);
  60. if (ENABLE_FEATURE_CLEAN_UP) free(newp);
  61. nuke_str(cp);
  62. return ret;
  63. }
  64. int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  65. int passwd_main(int argc UNUSED_PARAM, char **argv)
  66. {
  67. enum {
  68. OPT_algo = 0x1, /* -a - password algorithm */
  69. OPT_lock = 0x2, /* -l - lock account */
  70. OPT_unlock = 0x4, /* -u - unlock account */
  71. OPT_delete = 0x8, /* -d - delete password */
  72. OPT_lud = 0xe,
  73. STATE_ALGO_md5 = 0x10,
  74. //STATE_ALGO_des = 0x20, not needed yet
  75. };
  76. unsigned opt;
  77. int rc;
  78. const char *opt_a = "";
  79. const char *filename;
  80. char *myname;
  81. char *name;
  82. char *newp;
  83. struct passwd *pw;
  84. uid_t myuid;
  85. struct rlimit rlimit_fsize;
  86. char c;
  87. #if ENABLE_FEATURE_SHADOWPASSWDS
  88. /* Using _r function to avoid pulling in static buffers */
  89. struct spwd spw;
  90. char buffer[256];
  91. #endif
  92. logmode = LOGMODE_BOTH;
  93. openlog(applet_name, 0, LOG_AUTH);
  94. opt = getopt32(argv, "a:lud", &opt_a);
  95. //argc -= optind;
  96. argv += optind;
  97. if (strcasecmp(opt_a, "des") != 0) /* -a */
  98. opt |= STATE_ALGO_md5;
  99. //else
  100. // opt |= STATE_ALGO_des;
  101. myuid = getuid();
  102. /* -l, -u, -d require root priv and username argument */
  103. if ((opt & OPT_lud) && (myuid || !argv[0]))
  104. bb_show_usage();
  105. /* Will complain and die if username not found */
  106. myname = xstrdup(xuid2uname(myuid));
  107. name = argv[0] ? argv[0] : myname;
  108. pw = xgetpwnam(name);
  109. if (myuid && pw->pw_uid != myuid) {
  110. /* LOGMODE_BOTH */
  111. bb_error_msg_and_die("%s can't change password for %s", myname, name);
  112. }
  113. #if ENABLE_FEATURE_SHADOWPASSWDS
  114. {
  115. /* getspnam_r may return 0 yet set result to NULL.
  116. * At least glibc 2.4 does this. Be extra paranoid here. */
  117. struct spwd *result = NULL;
  118. if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result)
  119. || !result || strcmp(result->sp_namp, pw->pw_name) != 0) {
  120. /* LOGMODE_BOTH */
  121. bb_error_msg("no record of %s in %s, using %s",
  122. name, bb_path_shadow_file,
  123. bb_path_passwd_file);
  124. } else {
  125. pw->pw_passwd = result->sp_pwdp;
  126. }
  127. }
  128. #endif
  129. /* Decide what the new password will be */
  130. newp = NULL;
  131. c = pw->pw_passwd[0] - '!';
  132. if (!(opt & OPT_lud)) {
  133. if (myuid && !c) { /* passwd starts with '!' */
  134. /* LOGMODE_BOTH */
  135. bb_error_msg_and_die("cannot change "
  136. "locked password for %s", name);
  137. }
  138. printf("Changing password for %s\n", name);
  139. newp = new_password(pw, myuid, opt & STATE_ALGO_md5);
  140. if (!newp) {
  141. logmode = LOGMODE_STDIO;
  142. bb_error_msg_and_die("password for %s is unchanged", name);
  143. }
  144. } else if (opt & OPT_lock) {
  145. if (!c) goto skip; /* passwd starts with '!' */
  146. newp = xasprintf("!%s", pw->pw_passwd);
  147. } else if (opt & OPT_unlock) {
  148. if (c) goto skip; /* not '!' */
  149. /* pw->pw_passwd points to static storage,
  150. * strdup'ing to avoid nasty surprizes */
  151. newp = xstrdup(&pw->pw_passwd[1]);
  152. } else if (opt & OPT_delete) {
  153. //newp = xstrdup("");
  154. newp = (char*)"";
  155. }
  156. rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
  157. setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
  158. bb_signals(0
  159. + (1 << SIGHUP)
  160. + (1 << SIGINT)
  161. + (1 << SIGQUIT)
  162. , SIG_IGN);
  163. umask(077);
  164. xsetuid(0);
  165. #if ENABLE_FEATURE_SHADOWPASSWDS
  166. filename = bb_path_shadow_file;
  167. rc = update_passwd(bb_path_shadow_file, name, newp, NULL);
  168. if (rc == 0) /* no lines updated, no errors detected */
  169. #endif
  170. {
  171. filename = bb_path_passwd_file;
  172. rc = update_passwd(bb_path_passwd_file, name, newp, NULL);
  173. }
  174. /* LOGMODE_BOTH */
  175. if (rc < 0)
  176. bb_error_msg_and_die("cannot update password file %s",
  177. filename);
  178. bb_info_msg("Password for %s changed by %s", name, myname);
  179. //if (ENABLE_FEATURE_CLEAN_UP) free(newp);
  180. skip:
  181. if (!newp) {
  182. bb_error_msg_and_die("password for %s is already %slocked",
  183. name, (opt & OPT_unlock) ? "un" : "");
  184. }
  185. if (ENABLE_FEATURE_CLEAN_UP) free(myname);
  186. return 0;
  187. }