]> granicus.if.org Git - apache/blobdiff - support/htpasswd.c
Merge r1351737 from trunk:
[apache] / support / htpasswd.c
index 9468a0ce6ada4086e93ff1a33dbb98593cbb9a41..16e55a0630b1d5881bd9706eda99093884390a6a 100644 (file)
@@ -104,6 +104,13 @@ apr_file_t *ftemp = NULL;
 
 #define NL APR_EOL_STR
 
+#if defined(WIN32) || defined(NETWARE)
+#define CRYPT_ALGO_SUPPORTED 0
+#else
+#define CRYPT_ALGO_SUPPORTED 1
+#endif
+
+#if CRYPT_ALGO_SUPPORTED
 static void to64(char *s, unsigned long v, int n)
 {
     static unsigned char itoa64[] =         /* 0 ... 63 => ASCII - 64 */
@@ -114,10 +121,43 @@ static void to64(char *s, unsigned long v, int n)
         v >>= 6;
     }
 }
+#endif
+
+static void generate_salt(char *s, size_t size)
+{
+    static unsigned char tbl[] =
+        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+    size_t i;
+    for (i = 0; i < size; ++i) {
+        int idx = (int) (64.0 * rand() / (RAND_MAX + 1.0));
+        s[i] = tbl[idx];
+    }
+}
+
+static apr_status_t seed_rand(void)
+{
+    int seed = 0;
+    apr_status_t rv;
+    rv = apr_generate_random_bytes((unsigned char*) &seed, sizeof(seed));
+    if (rv) {
+        apr_file_printf(errfile, "Unable to generate random bytes: %pm" NL, &rv);
+        return rv;
+    }
+    srand(seed);
+    return rv;
+}
 
 static void putline(apr_file_t *f, const char *l)
 {
-    apr_file_puts(l, f);
+    apr_status_t rc;
+    rc = apr_file_puts(l, f);
+    if (rc != APR_SUCCESS) {
+        char errstr[MAX_STRING_LEN];
+        apr_strerror(rc, errstr, MAX_STRING_LEN);
+        apr_file_printf(errfile, "Error writing temp file: %s" NL, errstr);
+        apr_file_close(f);
+        exit(ERR_FILEPERM);
+    }
 }
 
 /*
@@ -134,6 +174,9 @@ static int mkrecord(char *user, char *record, apr_size_t rlen, char *passwd,
     char pwv[MAX_STRING_LEN];
     char salt[9];
     apr_size_t bufsize;
+#if CRYPT_ALGO_SUPPORTED
+    char *cbuf;
+#endif
 
     if (passwd != NULL) {
         pw = passwd;
@@ -162,8 +205,10 @@ static int mkrecord(char *user, char *record, apr_size_t rlen, char *passwd,
         break;
 
     case ALG_APMD5:
-        (void) srand((int) time((time_t *) NULL));
-        to64(&salt[0], rand(), 8);
+        if (seed_rand()) {
+            break;
+        }
+        generate_salt(&salt[0], 8);
         salt[8] = '\0';
 
         apr_md5_encode((const char *)pw, (const char *)salt,
@@ -175,16 +220,36 @@ static int mkrecord(char *user, char *record, apr_size_t rlen, char *passwd,
         apr_cpystrn(cpw,pw,sizeof(cpw));
         break;
 
-#if !(defined(WIN32) || defined(NETWARE))
+#if CRYPT_ALGO_SUPPORTED
     case ALG_CRYPT:
     default:
-        (void) srand((int) time((time_t *) NULL));
+        if (seed_rand()) {
+            break;
+        }
         to64(&salt[0], rand(), 8);
         salt[8] = '\0';
 
-        apr_cpystrn(cpw, crypt(pw, salt), sizeof(cpw) - 1);
+        cbuf = crypt(pw, salt);
+        if (cbuf == NULL) {
+            char errbuf[128];
+
+            apr_snprintf(record, rlen-1, "crypt() failed: %s", 
+                         apr_strerror(errno, errbuf, sizeof errbuf));
+            return ERR_PWMISMATCH;
+        }
+
+        apr_cpystrn(cpw, cbuf, sizeof(cpw) - 1);
+        if (strlen(pw) > 8) {
+            char *truncpw = strdup(pw);
+            truncpw[8] = '\0';
+            if (!strcmp(cpw, crypt(truncpw, salt))) {
+                apr_file_printf(errfile, "Warning: Password truncated to 8 characters "
+                                "by CRYPT algorithm." NL);
+            }
+            free(truncpw);
+        }
         break;
-#endif
+#endif /* CRYPT_ALGO_SUPPORTED */
     }
     memset(pw, '\0', strlen(pw));
 
@@ -215,14 +280,9 @@ static void usage(void)
     apr_file_printf(errfile, " -n  Don't update file; display results on "
                     "stdout." NL);
     apr_file_printf(errfile, " -m  Force MD5 encryption of the password"
-#if defined(WIN32) || defined(TPF) || defined(NETWARE)
         " (default)"
-#endif
         "." NL);
     apr_file_printf(errfile, " -d  Force CRYPT encryption of the password"
-#if (!(defined(WIN32) || defined(TPF) || defined(NETWARE)))
-            " (default)"
-#endif
             "." NL);
     apr_file_printf(errfile, " -p  Do not encrypt the password (plaintext)." NL);
     apr_file_printf(errfile, " -s  Force SHA encryption of the password." NL);
@@ -230,10 +290,11 @@ static void usage(void)
             "rather than prompting for it." NL);
     apr_file_printf(errfile, " -D  Delete the specified user." NL);
     apr_file_printf(errfile,
-            "On Windows, NetWare and TPF systems the '-m' flag is used by "
-            "default." NL);
+            "On other systems than Windows and NetWare the '-p' flag will "
+            "probably not work." NL);
     apr_file_printf(errfile,
-            "On all other systems, the '-p' flag will probably not work." NL);
+            "The SHA algorithm does not use a salt and is less secure than "
+            "the MD5 algorithm." NL);
     exit(ERR_SYNTAX);
 }
 
@@ -400,7 +461,7 @@ int main(int argc, const char * const argv[])
     char *scratch, cp[MAX_STRING_LEN];
     int found = 0;
     int i;
-    int alg = ALG_CRYPT;
+    int alg = ALG_APMD5;
     int mask = 0;
     apr_pool_t *pool;
     int existing_file = 0;
@@ -435,14 +496,14 @@ int main(int argc, const char * const argv[])
     check_args(pool, argc, argv, &alg, &mask, &user, &pwfilename, &password);
 
 
-#if defined(WIN32) || defined(NETWARE)
+#if !CRYPT_ALGO_SUPPORTED
     if (alg == ALG_CRYPT) {
         alg = ALG_APMD5;
         apr_file_printf(errfile, "Automatically using MD5 format." NL);
     }
 #endif
 
-#if (!(defined(WIN32) || defined(TPF) || defined(NETWARE)))
+#if CRYPT_ALGO_SUPPORTED
     if (alg == ALG_PLAIN) {
         apr_file_printf(errfile,"Warning: storing passwords as plain text "
                         "might just not work on this platform." NL);