You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ji...@apache.org on 2013/04/30 16:19:44 UTC

svn commit: r1477651 - in /httpd/httpd/branches/2.4.x: ./ CHANGES STATUS docs/manual/ docs/manual/programs/htpasswd.xml support/htpasswd.c support/passwd_common.c support/passwd_common.h

Author: jim
Date: Tue Apr 30 14:19:43 2013
New Revision: 1477651

URL: http://svn.apache.org/r1477651
Log:
Merge r1465116 from trunk:

htpasswd: Add -v option to verify a password

htpasswd and htdbm could use some more refactoring...

Submitted by: sf
Reviewed/backported by: jim

Modified:
    httpd/httpd/branches/2.4.x/   (props changed)
    httpd/httpd/branches/2.4.x/CHANGES
    httpd/httpd/branches/2.4.x/STATUS
    httpd/httpd/branches/2.4.x/docs/manual/   (props changed)
    httpd/httpd/branches/2.4.x/docs/manual/programs/htpasswd.xml
    httpd/httpd/branches/2.4.x/support/htpasswd.c
    httpd/httpd/branches/2.4.x/support/passwd_common.c
    httpd/httpd/branches/2.4.x/support/passwd_common.h

Propchange: httpd/httpd/branches/2.4.x/
------------------------------------------------------------------------------
  Merged /httpd/httpd/trunk:r1465116

Modified: httpd/httpd/branches/2.4.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/CHANGES?rev=1477651&r1=1477650&r2=1477651&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.4.x/CHANGES [utf-8] Tue Apr 30 14:19:43 2013
@@ -2,6 +2,8 @@
 
 Changes with Apache 2.4.5
 
+  *) htpasswd: Add -v option to verify a password. [Stefan Fritsch]
+
   *) mod_proxy: Add BalancerInherit and ProxyPassInherit to control
      whether Proxy Balancers and Workers are inherited by vhosts
      (default is On). [Jim Jagielski]

Modified: httpd/httpd/branches/2.4.x/STATUS
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/STATUS?rev=1477651&r1=1477650&r2=1477651&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/STATUS (original)
+++ httpd/httpd/branches/2.4.x/STATUS Tue Apr 30 14:19:43 2013
@@ -90,11 +90,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-    * htpasswd: Add -v option
-      trunk patches: https://svn.apache.org/r1465116
-      2.4.x patch: trunk patches work
-      +1: sf, minfrin, jim
-
     * mod_cache_socache: New cache implementation backed by mod_socache
       that replaces mod_mem_cache removed from httpd v2.2.
       trunk patches: http://svn.apache.org/r1305167

Propchange: httpd/httpd/branches/2.4.x/docs/manual/
------------------------------------------------------------------------------
  Merged /httpd/httpd/trunk/docs/manual:r1465116

Modified: httpd/httpd/branches/2.4.x/docs/manual/programs/htpasswd.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/docs/manual/programs/htpasswd.xml?rev=1477651&r1=1477650&r2=1477651&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/docs/manual/programs/htpasswd.xml (original)
+++ httpd/httpd/branches/2.4.x/docs/manual/programs/htpasswd.xml Tue Apr 30 14:19:43 2013
@@ -68,7 +68,8 @@ distribution.</seealso>
       -<strong>s</strong> |
       -<strong>p</strong> ]
     [ -<strong>C</strong> <var>cost</var> ]
-    [ -<strong>D</strong> ]  <var>passwdfile</var> <var>username</var></code></p>
+    [ -<strong>D</strong> ]
+    [ -<strong>v</strong> ]  <var>passwdfile</var> <var>username</var></code></p>
 
     <p><code><strong>htpasswd</strong> -<strong>b</strong>
     [ -<strong>c</strong> ]
@@ -78,7 +79,8 @@ distribution.</seealso>
       -<strong>s</strong> |
       -<strong>p</strong> ]
     [ -<strong>C</strong> <var>cost</var> ]
-    [ -<strong>D</strong> ]  <var>passwdfile</var> <var>username</var>
+    [ -<strong>D</strong> ]
+    [ -<strong>v</strong> ]  <var>passwdfile</var> <var>username</var>
     <var>password</var></code></p>
 
     <p><code><strong>htpasswd</strong> -<strong>n</strong>
@@ -155,6 +157,10 @@ distribution.</seealso>
     <dd>Delete user. If the username exists in the specified htpasswd file, it
     will be deleted.</dd>
 
+    <dt><code>-v</code></dt>
+    <dd>Verify password. Verify that the given password matches the password
+    of the user stored in the specified htpasswd file.</dd>
+
     <dt><code><var>passwdfile</var></code></dt>
     <dd>Name of the file to contain the user name and password. If
     <code>-c</code> is given, this file is created if it does not already exist,

Modified: httpd/httpd/branches/2.4.x/support/htpasswd.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/support/htpasswd.c?rev=1477651&r1=1477650&r2=1477651&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/support/htpasswd.c (original)
+++ httpd/httpd/branches/2.4.x/support/htpasswd.c Tue Apr 30 14:19:43 2013
@@ -67,6 +67,7 @@
 #define APHTP_NEWFILE        1
 #define APHTP_NOFILE         2
 #define APHTP_DELUSER        4
+#define APHTP_VERIFY         8
 
 apr_file_t *ftemp = NULL;
 
@@ -92,8 +93,8 @@ static int mkrecord(struct passwd_ctx *c
 static void usage(void)
 {
     apr_file_printf(errfile, "Usage:" NL
-        "\thtpasswd [-cimBdpsD] [-C cost] passwordfile username" NL
-        "\thtpasswd -b[cmBdpsD] [-C cost] passwordfile username password" NL
+        "\thtpasswd [-cimBdpsDv] [-C cost] passwordfile username" NL
+        "\thtpasswd -b[cmBdpsDv] [-C cost] passwordfile username password" NL
         NL
         "\thtpasswd -n[imBdps] [-C cost] username" NL
         "\thtpasswd -nb[mBdps] [-C cost] username password" NL
@@ -110,6 +111,7 @@ static void usage(void)
         " -s  Force SHA encryption of the password (insecure)." NL
         " -p  Do not encrypt the password (plaintext, insecure)." NL
         " -D  Delete the specified user." NL
+        " -v  Verify password for the specified user." NL
         "On other systems than Windows and NetWare the '-p' flag will "
             "probably not work." NL
         "The SHA algorithm does not use a salt and is less secure than the "
@@ -155,7 +157,7 @@ static void terminate(void)
 }
 
 static void check_args(int argc, const char *const argv[],
-                       struct passwd_ctx *ctx, int *mask, char **user,
+                       struct passwd_ctx *ctx, unsigned *mask, char **user,
                        char **pwfilename)
 {
     const char *arg;
@@ -171,7 +173,7 @@ static void check_args(int argc, const c
     if (rv != APR_SUCCESS)
         exit(ERR_SYNTAX);
 
-    while ((rv = apr_getopt(state, "cnmspdBbDiC:", &opt, &opt_arg)) == APR_SUCCESS) {
+    while ((rv = apr_getopt(state, "cnmspdBbDiC:v", &opt, &opt_arg)) == APR_SUCCESS) {
         switch (opt) {
         case 'c':
             *mask |= APHTP_NEWFILE;
@@ -183,6 +185,9 @@ static void check_args(int argc, const c
         case 'D':
             *mask |= APHTP_DELUSER;
             break;
+        case 'v':
+            *mask |= APHTP_VERIFY;
+            break;
         default:
             ret = parse_common_options(ctx, opt, opt_arg);
             if (ret) {
@@ -196,18 +201,15 @@ static void check_args(int argc, const c
     if (rv != APR_EOF)
         usage();
 
-    if ((*mask & APHTP_NEWFILE) && (*mask & APHTP_NOFILE)) {
-        apr_file_printf(errfile, "%s: -c and -n options conflict" NL, argv[0]);
-        exit(ERR_SYNTAX);
-    }
-    if ((*mask & APHTP_NEWFILE) && (*mask & APHTP_DELUSER)) {
-        apr_file_printf(errfile, "%s: -c and -D options conflict" NL, argv[0]);
-        exit(ERR_SYNTAX);
-    }
-    if ((*mask & APHTP_NOFILE) && (*mask & APHTP_DELUSER)) {
-        apr_file_printf(errfile, "%s: -n and -D options conflict" NL, argv[0]);
+    if ((*mask) & (*mask - 1)) {
+        /* not a power of two, i.e. more than one flag specified */
+        apr_file_printf(errfile, "%s: only one of -c -n -v -D may be specified" NL,
+            argv[0]);
         exit(ERR_SYNTAX);
     }
+    if ((*mask & APHTP_VERIFY) && ctx->passwd_src == PW_PROMPT)
+        ctx->passwd_src = PW_PROMPT_VERIFY;
+
     /*
      * Make sure we still have exactly the right number of arguments left
      * (the filename, the username, and possibly the password if -b was
@@ -246,6 +248,25 @@ static void check_args(int argc, const c
     }
 }
 
+static int verify(struct passwd_ctx *ctx, const char *hash)
+{
+    apr_status_t rv;
+    int ret;
+
+    if (ctx->passwd == NULL && (ret = get_password(ctx)) != 0)
+       return ret;
+    rv = apr_password_validate(ctx->passwd, hash);
+    if (rv == APR_SUCCESS)
+        return 0;
+    if (APR_STATUS_IS_EMISMATCH(rv)) {
+        ctx->errstr = "password verification failed";
+        return ERR_PWMISMATCH;
+    }
+    ctx->errstr = apr_psprintf(ctx->pool, "Could not verify password: %pm",
+                               &rv);
+    return ERR_GENERAL;
+}
+
 /*
  * Let's do it.  We end up doing a lot of file opening and closing,
  * but what do we care?  This application isn't run constantly.
@@ -261,7 +282,7 @@ int main(int argc, const char * const ar
     char *scratch, cp[MAX_STRING_LEN];
     int found = 0;
     int i;
-    int mask = 0;
+    unsigned mask = 0;
     apr_pool_t *pool;
     int existing_file = 0;
     struct passwd_ctx ctx = { 0 };
@@ -341,7 +362,7 @@ int main(int argc, const char * const ar
      * Any error message text is returned in the record buffer, since
      * the mkrecord() routine doesn't have access to argv[].
      */
-    if (!(mask & APHTP_DELUSER)) {
+    if ((mask & (APHTP_DELUSER|APHTP_VERIFY)) == 0) {
         i = mkrecord(&ctx, user);
         if (i != 0) {
             apr_file_printf(errfile, "%s: %s" NL, argv[0], ctx.errstr);
@@ -353,21 +374,23 @@ int main(int argc, const char * const ar
         }
     }
 
-    /*
-     * We can access the files the right way, and we have a record
-     * to add or update.  Let's do it..
-     */
-    if (apr_temp_dir_get((const char**)&dirname, pool) != APR_SUCCESS) {
-        apr_file_printf(errfile, "%s: could not determine temp dir" NL,
-                        argv[0]);
-        exit(ERR_FILEPERM);
-    }
-    dirname = apr_psprintf(pool, "%s/%s", dirname, tn);
+    if ((mask & APHTP_VERIFY) == 0) {
+        /*
+         * We can access the files the right way, and we have a record
+         * to add or update.  Let's do it..
+         */
+        if (apr_temp_dir_get((const char**)&dirname, pool) != APR_SUCCESS) {
+            apr_file_printf(errfile, "%s: could not determine temp dir" NL,
+                            argv[0]);
+            exit(ERR_FILEPERM);
+        }
+        dirname = apr_psprintf(pool, "%s/%s", dirname, tn);
 
-    if (apr_file_mktemp(&ftemp, dirname, 0, pool) != APR_SUCCESS) {
-        apr_file_printf(errfile, "%s: unable to create temporary file %s" NL,
-                        argv[0], dirname);
-        exit(ERR_FILEPERM);
+        if (apr_file_mktemp(&ftemp, dirname, 0, pool) != APR_SUCCESS) {
+            apr_file_printf(errfile, "%s: unable to create temporary file %s" NL,
+                            argv[0], dirname);
+            exit(ERR_FILEPERM);
+        }
     }
 
     /*
@@ -418,33 +441,59 @@ int main(int argc, const char * const ar
                 continue;
             }
             else {
-                if (!(mask & APHTP_DELUSER)) {
-                    /* We found the user we were looking for.
-                     * Add him to the file.
-                    */
-                    apr_file_printf(errfile, "Updating ");
-                    putline(ftemp, ctx.out);
-                    found++;
+                /* We found the user we were looking for */
+                found++;
+                if ((mask & APHTP_DELUSER)) {
+                    /* Delete entry from the file */
+                    apr_file_printf(errfile, "Deleting ");
+                }
+                else if ((mask & APHTP_VERIFY)) {
+                    /* Verify */
+                    char *hash = colon + 1;
+                    size_t len;
+
+                    len = strcspn(hash, "\r\n");
+                    if (len == 0) {
+                        apr_file_printf(errfile, "Empty hash for user %s" NL,
+                                        user);
+                        exit(ERR_INVALID);
+                    }
+                    hash[len] = '\0';
+
+                    i = verify(&ctx, hash);
+                    if (i != 0) {
+                        apr_file_printf(errfile, "%s" NL, ctx.errstr);
+                        exit(i);
+                    }
                 }
                 else {
-                    /* We found the user we were looking for.
-                     * Delete them from the file.
-                     */
-                    apr_file_printf(errfile, "Deleting ");
-                    found++;
+                    /* Update entry */
+                    apr_file_printf(errfile, "Updating ");
+                    putline(ftemp, ctx.out);
                 }
             }
         }
         apr_file_close(fpw);
     }
-    if (!found && !(mask & APHTP_DELUSER)) {
-        apr_file_printf(errfile, "Adding ");
-        putline(ftemp, ctx.out);
+    if (!found) {
+        if (mask & APHTP_DELUSER) {
+            apr_file_printf(errfile, "User %s not found" NL, user);
+            exit(0);
+        }
+        else if (mask & APHTP_VERIFY) {
+            apr_file_printf(errfile, "User %s not found" NL, user);
+            exit(ERR_BADUSER);
+        }
+        else {
+            apr_file_printf(errfile, "Adding ");
+            putline(ftemp, ctx.out);
+        }
     }
-    else if (!found && (mask & APHTP_DELUSER)) {
-        apr_file_printf(errfile, "User %s not found" NL, user);
+    if (mask & APHTP_VERIFY) {
+        apr_file_printf(errfile, "Password for user %s correct." NL, user);
         exit(0);
     }
+
     apr_file_printf(errfile, "password for user %s" NL, user);
 
     /* The temporary file has all the data, just copy it to the new location.

Modified: httpd/httpd/branches/2.4.x/support/passwd_common.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/support/passwd_common.c?rev=1477651&r1=1477650&r2=1477651&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/support/passwd_common.c (original)
+++ httpd/httpd/branches/2.4.x/support/passwd_common.c Tue Apr 30 14:19:43 2013
@@ -103,6 +103,8 @@ static int generate_salt(char *s, size_t
 void putline(apr_file_t *f, const char *l)
 {
     apr_status_t rv;
+    if (f == NULL)
+        return;
     rv = apr_file_puts(l, f);
     if (rv != APR_SUCCESS) {
         apr_file_printf(errfile, "Error writing temp file: %pm", &rv);
@@ -135,6 +137,12 @@ int get_password(struct passwd_ctx *ctx)
         apr_file_close(file_stdin);
         ctx->passwd = apr_pstrdup(ctx->pool, buf);
     }
+    else if (ctx->passwd_src == PW_PROMPT_VERIFY) {
+        apr_size_t bufsize = sizeof(buf);
+        if (apr_password_get("Enter password: ", buf, &bufsize) != 0)
+            goto err_too_long;
+        ctx->passwd = apr_pstrdup(ctx->pool, buf);
+    }
     else {
         apr_size_t bufsize = sizeof(buf);
         if (apr_password_get("New password: ", buf, &bufsize) != 0)

Modified: httpd/httpd/branches/2.4.x/support/passwd_common.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/support/passwd_common.h?rev=1477651&r1=1477650&r2=1477651&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/support/passwd_common.h (original)
+++ httpd/httpd/branches/2.4.x/support/passwd_common.h Tue Apr 30 14:19:43 2013
@@ -80,7 +80,8 @@ struct passwd_ctx {
     enum {
         PW_PROMPT = 0,
         PW_ARG,
-        PW_STDIN
+        PW_STDIN,
+        PW_PROMPT_VERIFY,
     } passwd_src;
 };