Advertisement
Guest User

passwd.c from Busybox 1.0.1

a guest
Feb 24th, 2020
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.16 KB | None | 0 0
  1. /* vi: set sw=4 ts=4: */
  2. #include <fcntl.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <signal.h>
  6. #include <sys/stat.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9. #include <utime.h>
  10. #include <syslog.h>
  11. #include <time.h>
  12. #include <sys/resource.h>
  13. #include <errno.h>
  14.  
  15. #include "busybox.h"
  16.  
  17. static char crypt_passwd[128];
  18.  
  19. static int create_backup(const char *backup, FILE * fp);
  20. static int new_password(const struct passwd *pw, int amroot, int algo);
  21. static void set_filesize_limit(int blocks);
  22.  
  23.  
  24. int get_algo(char *a)
  25. {
  26.     int x = 1;                  /* standard: MD5 */
  27.  
  28.     if (strcasecmp(a, "des") == 0)
  29.         x = 0;
  30.     return x;
  31. }
  32.  
  33.  
  34. extern int update_passwd(const struct passwd *pw, char *crypt_pw)
  35. {
  36.     char filename[1024];
  37.     char buf[1025];
  38.     char buffer[80];
  39.     char username[32];
  40.     char *pw_rest;
  41.     int mask;
  42.     int continued;
  43.     FILE *fp;
  44.     FILE *out_fp;
  45.     struct stat sb;
  46.     struct flock lock;
  47.  
  48. #ifdef CONFIG_FEATURE_SHADOWPASSWDS
  49.     if (access(bb_path_shadow_file, F_OK) == 0) {
  50.         snprintf(filename, sizeof filename, "%s", bb_path_shadow_file);
  51.     } else
  52. #endif
  53.     {
  54.         snprintf(filename, sizeof filename, "%s", bb_path_passwd_file);
  55.     }
  56.  
  57.     if (((fp = fopen(filename, "r+")) == 0) || (fstat(fileno(fp), &sb))) {
  58.         /* return 0; */
  59.         return 1;
  60.     }
  61.  
  62.     /* Lock the password file before updating */
  63.     lock.l_type = F_WRLCK;
  64.     lock.l_whence = SEEK_SET;
  65.     lock.l_start = 0;
  66.     lock.l_len = 0;
  67.     if (fcntl(fileno(fp), F_SETLK, &lock) < 0) {
  68.         fprintf(stderr, "%s: %s\n", filename, strerror(errno));
  69.         return 1;
  70.     }
  71.     lock.l_type = F_UNLCK;
  72.  
  73.     snprintf(buf, sizeof buf, "%s-", filename);
  74.     if (create_backup(buf, fp)) {
  75.         fcntl(fileno(fp), F_SETLK, &lock);
  76.         fclose(fp);
  77.         return 1;
  78.     }
  79.     snprintf(buf, sizeof buf, "%s+", filename);
  80.     mask = umask(0777);
  81.     out_fp = fopen(buf, "w");
  82.     umask(mask);
  83.     if ((!out_fp) || (fchmod(fileno(out_fp), sb.st_mode & 0777))
  84.         || (fchown(fileno(out_fp), sb.st_uid, sb.st_gid))) {
  85.         fcntl(fileno(fp), F_SETLK, &lock);
  86.         fclose(fp);
  87.         fclose(out_fp);
  88.         return 1;
  89.     }
  90.  
  91.     continued = 0;
  92.     snprintf(username, sizeof username, "%s:", pw->pw_name);
  93.     rewind(fp);
  94.     while (!feof(fp)) {
  95.         fgets(buffer, sizeof buffer, fp);
  96.         if (!continued) {       // Check to see if we're updating this line.
  97.             if (strncmp(username, buffer, strlen(username)) == 0) { // we have a match.
  98.                 pw_rest = strchr(buffer, ':');
  99.                 *pw_rest++ = '\0';
  100.                 pw_rest = strchr(pw_rest, ':');
  101.                 fprintf(out_fp, "%s:%s%s", buffer, crypt_pw, pw_rest);
  102.             } else {
  103.                 fputs(buffer, out_fp);
  104.             }
  105.         } else {
  106.             fputs(buffer, out_fp);
  107.         }
  108.         if (buffer[strlen(buffer) - 1] == '\n') {
  109.             continued = 0;
  110.         } else {
  111.             continued = 1;
  112.         }
  113.         bzero(buffer, sizeof buffer);
  114.     }
  115.  
  116.     if (fflush(out_fp) || fsync(fileno(out_fp)) || fclose(out_fp)) {
  117.         unlink(buf);
  118.         fcntl(fileno(fp), F_SETLK, &lock);
  119.         fclose(fp);
  120.         return 1;
  121.     }
  122.     if (rename(buf, filename) < 0) {
  123.         fcntl(fileno(fp), F_SETLK, &lock);
  124.         fclose(fp);
  125.         return 1;
  126.     } else {
  127.         fcntl(fileno(fp), F_SETLK, &lock);
  128.         fclose(fp);
  129.         return 0;
  130.     }
  131. }
  132.  
  133.  
  134. extern int passwd_main(int argc, char **argv)
  135. {
  136.     int amroot;
  137.     char *cp;
  138.     char *np;
  139.     char *name;
  140.     char *myname;
  141.     int flag;
  142.     int algo = 1;               /* -a - password algorithm */
  143.     int lflg = 0;               /* -l - lock account */
  144.     int uflg = 0;               /* -u - unlock account */
  145.     int dflg = 0;               /* -d - delete password */
  146.     const struct passwd *pw;
  147.  
  148. #ifdef CONFIG_FEATURE_SHADOWPASSWDS
  149.     const struct spwd *sp;
  150. #endif                          /* CONFIG_FEATURE_SHADOWPASSWDS */
  151.     amroot = (getuid() == 0);
  152.     openlog("passwd", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
  153.     while ((flag = getopt(argc, argv, "a:dlu")) != EOF) {
  154.         switch (flag) {
  155.         case 'a':
  156.             algo = get_algo(optarg);
  157.             break;
  158.         case 'd':
  159.             dflg++;
  160.             break;
  161.         case 'l':
  162.             lflg++;
  163.             break;
  164.         case 'u':
  165.             uflg++;
  166.             break;
  167.         default:
  168.             bb_show_usage();
  169.         }
  170.     }
  171.     myname = (char *) bb_xstrdup(my_getpwuid(NULL, getuid(), -1));
  172.     /* exits on error */
  173.     if (optind < argc) {
  174.         name = argv[optind];
  175.     } else {
  176.         name = myname;
  177.     }
  178.     if ((lflg || uflg || dflg) && (optind >= argc || !amroot)) {
  179.         bb_show_usage();
  180.     }
  181.     pw = getpwnam(name);
  182.     if (!pw) {
  183.         bb_error_msg_and_die("Unknown user %s\n", name);
  184.     }
  185.     if (!amroot && pw->pw_uid != getuid()) {
  186.         syslog(LOG_WARNING, "can't change pwd for `%s'", name);
  187.         bb_error_msg_and_die("Permission denied.\n");
  188.     }
  189. #ifdef CONFIG_FEATURE_SHADOWPASSWDS
  190.     sp = getspnam(name);
  191.     if (!sp) {
  192.         sp = (struct spwd *) pwd_to_spwd(pw);
  193.     }
  194.     cp = sp->sp_pwdp;
  195.     np = sp->sp_namp;
  196. #else
  197.     cp = pw->pw_passwd;
  198.     np = name;
  199. #endif                          /* CONFIG_FEATURE_SHADOWPASSWDS */
  200.  
  201.     safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));
  202.     if (!(dflg || lflg || uflg)) {
  203.         if (!amroot) {
  204.             if (cp[0] == '!') {
  205.                 syslog(LOG_WARNING, "password locked for `%s'", np);
  206.                 bb_error_msg_and_die( "The password for `%s' cannot be changed.\n", np);
  207.             }
  208.         }
  209.         printf("Changing password for %s\n", name);
  210.         if (new_password(pw, amroot, algo)) {
  211.             bb_error_msg_and_die( "The password for %s is unchanged.\n", name);
  212.         }
  213.     } else if (lflg) {
  214.         if (crypt_passwd[0] != '!') {
  215.             memmove(&crypt_passwd[1], crypt_passwd,
  216.                     sizeof crypt_passwd - 1);
  217.             crypt_passwd[sizeof crypt_passwd - 1] = '\0';
  218.             crypt_passwd[0] = '!';
  219.         }
  220.     } else if (uflg) {
  221.         if (crypt_passwd[0] == '!') {
  222.             memmove(crypt_passwd, &crypt_passwd[1],
  223.                     sizeof crypt_passwd - 1);
  224.         }
  225.     } else if (dflg) {
  226.         crypt_passwd[0] = '\0';
  227.     }
  228.     set_filesize_limit(30000);
  229.     signal(SIGHUP, SIG_IGN);
  230.     signal(SIGINT, SIG_IGN);
  231.     signal(SIGQUIT, SIG_IGN);
  232.     umask(077);
  233.     if (setuid(0)) {
  234.         syslog(LOG_ERR, "can't setuid(0)");
  235.         bb_error_msg_and_die( "Cannot change ID to root.\n");
  236.     }
  237.     if (!update_passwd(pw, crypt_passwd)) {
  238.         syslog(LOG_INFO, "password for `%s' changed by user `%s'", name,
  239.                myname);
  240.         printf("Password changed.\n");
  241.     } else {
  242.         syslog(LOG_WARNING, "an error occurred updating the password file");
  243.         bb_error_msg_and_die("An error occurred updating the password file.\n");
  244.     }
  245.     return (0);
  246. }
  247.  
  248.  
  249.  
  250. static int create_backup(const char *backup, FILE * fp)
  251. {
  252.     struct stat sb;
  253.     struct utimbuf ub;
  254.     FILE *bkfp;
  255.     int c, mask;
  256.  
  257.     if (fstat(fileno(fp), &sb))
  258.         /* return -1; */
  259.         return 1;
  260.  
  261.     mask = umask(077);
  262.     bkfp = fopen(backup, "w");
  263.     umask(mask);
  264.     if (!bkfp)
  265.         /* return -1; */
  266.         return 1;
  267.  
  268.     /* TODO: faster copy, not one-char-at-a-time.  --marekm */
  269.     rewind(fp);
  270.     while ((c = getc(fp)) != EOF) {
  271.         if (putc(c, bkfp) == EOF)
  272.             break;
  273.     }
  274.     if (c != EOF || fflush(bkfp)) {
  275.         fclose(bkfp);
  276.         /* return -1; */
  277.         return 1;
  278.     }
  279.     if (fclose(bkfp))
  280.         /* return -1; */
  281.         return 1;
  282.  
  283.     ub.actime = sb.st_atime;
  284.     ub.modtime = sb.st_mtime;
  285.     utime(backup, &ub);
  286.     return 0;
  287. }
  288.  
  289. static int i64c(int i)
  290. {
  291.     if (i <= 0)
  292.         return ('.');
  293.     if (i == 1)
  294.         return ('/');
  295.     if (i >= 2 && i < 12)
  296.         return ('0' - 2 + i);
  297.     if (i >= 12 && i < 38)
  298.         return ('A' - 12 + i);
  299.     if (i >= 38 && i < 63)
  300.         return ('a' - 38 + i);
  301.     return ('z');
  302. }
  303.  
  304. static char *crypt_make_salt(void)
  305. {
  306.     time_t now;
  307.     static unsigned long x;
  308.     static char result[3];
  309.  
  310.     time(&now);
  311.     x += now + getpid() + clock();
  312.     result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077);
  313.     result[1] = i64c(((x >> 12) ^ x) & 077);
  314.     result[2] = '\0';
  315.     return result;
  316. }
  317.  
  318.  
  319. static int new_password(const struct passwd *pw, int amroot, int algo)
  320. {
  321.     char *clear;
  322.     char *cipher;
  323.     char *cp;
  324.     char orig[200];
  325.     char pass[200];
  326.     time_t start, now;
  327.  
  328.     if (!amroot && crypt_passwd[0]) {
  329.         if (!(clear = bb_askpass(0, "Old password:"))) {
  330.             /* return -1; */
  331.             return 1;
  332.         }
  333.         cipher = pw_encrypt(clear, crypt_passwd);
  334.         if (strcmp(cipher, crypt_passwd) != 0) {
  335.             syslog(LOG_WARNING, "incorrect password for `%s'",
  336.                    pw->pw_name);
  337.             time(&start);
  338.             now = start;
  339.             while (difftime(now, start) < FAIL_DELAY) {
  340.                 sleep(FAIL_DELAY);
  341.                 time(&now);
  342.             }
  343.             fprintf(stderr, "Incorrect password.\n");
  344.             /* return -1; */
  345.             return 1;
  346.         }
  347.         safe_strncpy(orig, clear, sizeof(orig));
  348.         bzero(clear, strlen(clear));
  349.         bzero(cipher, strlen(cipher));
  350.     } else {
  351.         orig[0] = '\0';
  352.     }
  353.     if (! (cp=bb_askpass(0, "Enter the new password (minimum of 5, maximum of 8 characters)\n"
  354.                       "Please use a combination of upper and lower case letters and numbers.\n"
  355.                       "Enter new password: ")))
  356.     {
  357.         bzero(orig, sizeof orig);
  358.         /* return -1; */
  359.         return 1;
  360.     }
  361.     safe_strncpy(pass, cp, sizeof(pass));
  362.     bzero(cp, strlen(cp));
  363.     /* if (!obscure(orig, pass, pw)) { */
  364.     if (obscure(orig, pass, pw)) {
  365.         if (amroot) {
  366.             printf("\nWarning: weak password (continuing).\n");
  367.         } else {
  368.             /* return -1; */
  369.             return 1;
  370.         }
  371.     }
  372.     if (!(cp = bb_askpass(0, "Re-enter new password: "))) {
  373.         bzero(orig, sizeof orig);
  374.         /* return -1; */
  375.         return 1;
  376.     }
  377.     if (strcmp(cp, pass)) {
  378.         fprintf(stderr, "Passwords do not match.\n");
  379.         /* return -1; */
  380.         return 1;
  381.     }
  382.     bzero(cp, strlen(cp));
  383.     bzero(orig, sizeof(orig));
  384.  
  385.     if (algo == 1) {
  386.         cp = pw_encrypt(pass, "$1$");
  387.     } else
  388.         cp = pw_encrypt(pass, crypt_make_salt());
  389.     bzero(pass, sizeof pass);
  390.     safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));
  391.     return 0;
  392. }
  393.  
  394. static void set_filesize_limit(int blocks)
  395. {
  396.     struct rlimit rlimit_fsize;
  397.  
  398.     rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;
  399.     setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
  400. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement