From: "Mladen Turk" <[EMAIL PROTECTED]>
Sent: Monday, August 13, 2001 6:21 AM


> Here is an enhancement that enables username management using either SDBM or
> any other apr supported DBM. I've tested it only using SDBM on WIN32, but it
> should compile on other platforms.
> 
> I know that there is a dbmmanage.pl perl script that is used to manage DBM
> files, but since apr supports dbm, here is the solution.

+1

> Didn't make a diff, but rather attached the entire htpasswd.c

-1 - don't do that.  I've attached the diff for others to review, since I too
would like to see it committed.


Index: htpasswd.c
===================================================================
RCS file: /home/cvs/httpd-2.0/support/htpasswd.c,v
retrieving revision 1.38
diff -u -r1.38 htpasswd.c
--- htpasswd.c  2001/07/20 19:19:39     1.38
+++ htpasswd.c  2001/08/14 19:38:42
@@ -86,6 +86,7 @@
 #include "apr_file_io.h"
 #include "apr_general.h"
 #include "apr_signal.h"
+#include "apr_dbm.h"
 
 #if APR_HAVE_STDIO_H
 #include <stdio.h>
@@ -200,7 +201,7 @@
  * error message instead.
  */
 static int mkrecord(char *user, char *record, size_t rlen, char *passwd,
-                   int alg)
+                   int alg, int dbm)
 {
     char *pw;
     char cpw[120];
@@ -270,17 +271,22 @@
        apr_cpystrn(record, "resultant record too long", (rlen - 1));
        return ERR_OVERFLOW;
     }
-    strcpy(record, user);
-    strcat(record, ":");
-    strcat(record, cpw);
+    if (! dbm) {
+        strcpy(record, user);
+        strcat(record, ":");
+        strcat(record, cpw);
+    }
+    else
+        strcpy(record, cpw);
+
     return 0;
 }
 
 static int usage(void)
 {
     fprintf(stderr, "Usage:\n");
-    fprintf(stderr, "\thtpasswd [-cmdps] passwordfile username\n");
-    fprintf(stderr, "\thtpasswd -b[cmdps] passwordfile username password\n\n");
+    fprintf(stderr, "\thtpasswd [-cmdpsx] passwordfile username\n");
+    fprintf(stderr, "\thtpasswd -b[cmdpsx] passwordfile username password\n\n");
     fprintf(stderr, "\thtpasswd -n[mdps] username\n");
     fprintf(stderr, "\thtpasswd -nb[mdps] username password\n");
     fprintf(stderr, " -c  Create a new file.\n");
@@ -299,6 +305,7 @@
     fprintf(stderr, " -s  Force SHA encryption of the password.\n");
     fprintf(stderr, " -b  Use the password from the command line rather "
            "than prompting for it.\n");
+    fprintf(stderr, " -x  Use the DBM rather than flat file.\n");
     fprintf(stderr,
            "On Windows and TPF systems the '-m' flag is used by default.\n");
     fprintf(stderr,
@@ -354,12 +361,40 @@
 {
     apr_finfo_t sbuf;
     apr_status_t check;
-
     check = apr_stat(&sbuf, fname, APR_FINFO_TYPE, pool);
     return ((check || sbuf.filetype != APR_REG) ? 0 : 1);
 }
 
 /*
+ * Return true if the named dbm file exists, regardless of permissions.
+ */
+static int exists_dbm(char *fname, apr_pool_t *pool)
+{
+    apr_dbm_t *db;
+    if (apr_dbm_open(&db, fname, APR_DBM_READONLY, APR_OS_DEFAULT, pool) == 
+APR_SUCCESS) {
+        apr_dbm_close( db);
+        return 1;
+    }
+    else
+        return 0;
+
+}
+
+/*
+ * Return true if the specified file can be opened for write access.
+ */
+static int writable_dbm(char *fname, apr_pool_t *pool)
+{
+    apr_dbm_t *db;
+    if (apr_dbm_open(&db, fname, APR_DBM_READWRITE, APR_OS_DEFAULT, pool) == 
+APR_SUCCESS) {
+        apr_dbm_close( db);
+        return 1;
+    }
+    else
+        return 0;
+}
+
+/*
  * Copy from the current position of one file to the current position
  * of another.
  */
@@ -372,6 +407,7 @@
     }
 }
 
+
 /*
  * 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.
@@ -398,6 +434,10 @@
     apr_status_t rv;
     apr_xlate_t *to_ascii;
 #endif
+    apr_datum_t key;
+    apr_datum_t val;
+    apr_dbm_t   *dbm;
+    int usedbm = 0;
 
     apr_initialize();
     atexit(apr_terminate);
@@ -466,6 +506,9 @@
                noninteractive++;
                args_left++;
            }
+           else if (*arg == 'x') {
+               usedbm++;
+           }
            else {
                return usage();
            }
@@ -527,7 +570,7 @@
                "just not work on this platform.\n");
     }
 #endif
-    if (! nofile) {
+    if (! nofile && ! usedbm) {
        /*
         * Only do the file checks if we're supposed to frob it.
         *
@@ -573,7 +616,29 @@
            exit(ERR_FILEPERM);
        }
     }
-
+    else if (! nofile && usedbm)
+    {
+       /*
+        * Verify that the file exists if -c was omitted.  We give a special
+        * message if it doesn't.
+        */
+       if ((! newfile) && (! exists_dbm(pwfilename, pool))) {
+           fprintf(stderr,
+                   "%s: cannot modify file %s; use '-c' to create it\n",
+                   argv[0], pwfilename);
+           perror("apr_dbm_open");
+           exit(ERR_FILEPERM);
+       }
+       /*
+        * Now verify that the file is writable!
+        */
+       if ((! newfile) && (! writable_dbm(pwfilename, pool))) {
+           fprintf(stderr, "%s: cannot open file %s for write access\n",
+                   argv[0], pwfilename);
+           perror("apr_dbm_open");
+           exit(ERR_FILEPERM);
+       }
+    }
     /*
      * All the file access checks (if any) have been made.  Time to go to work;
      * try to create the record for the username in question.  If that
@@ -583,7 +648,7 @@
      */
     i = mkrecord(user, record, sizeof(record) - 1,
                 noninteractive ? password : NULL,
-                alg);
+                alg, usedbm);
     if (i != 0) {
        fprintf(stderr, "%s: %s\n", argv[0], record);
        exit(i);
@@ -593,6 +658,7 @@
        exit(0);
     }
 
+    if (! usedbm) {
     /*
      * We can access the files the right way, and we have a record
      * to add or update.  Let's do it..
@@ -677,5 +743,49 @@
     fclose(fpw);
     fclose(ftemp);
     unlink(tempfilename);
+    }
+    else {
+       /*
+        * Create the file or open existing for update
+        */
+    if (newfile) {
+        if (apr_dbm_open(&dbm, pwfilename, APR_DBM_RWCREATE, APR_OS_DEFAULT, pool) != 
+APR_SUCCESS) {
+           fprintf(stderr, "%s: cannot create file %s\n",
+                   argv[0], pwfilename);
+               perror("apr_dbm_open");
+               exit(ERR_FILEPERM);
+        }
+    }
+    else {
+        if (apr_dbm_open(&dbm, pwfilename, APR_DBM_READWRITE, APR_OS_DEFAULT, pool) 
+!= APR_SUCCESS) {
+           fprintf(stderr, "%s: cannot open file %s for update\n",
+                   argv[0], pwfilename);
+               perror("apr_dbm_open");
+               exit(ERR_FILEPERM);
+        }
+    }
+    key.dptr = user;
+    key.dsize = strlen(user); /* add 1 to len to include trailing '\0' */    
+    if (apr_dbm_exists(dbm, key))
+        found = 1;
+    val.dptr = record;
+    val.dsize = strlen(record);
+    if (apr_dbm_store(dbm, key, val) != APR_SUCCESS) {
+        apr_dbm_close(dbm);
+           fprintf(stderr, "%s: cannot store user %s to file %s\n",
+                   argv[0], user, pwfilename);
+        perror("apr_dbm_store");
+        exit(ERR_FILEPERM);
+    }
+    if (found) {
+       fprintf(stderr, "Updating ");
+    }
+    else {
+       fprintf(stderr, "Adding ");
+    }
+    fprintf(stderr, "password for user %s\n", user);
+    apr_dbm_close(dbm);
+
+    }
     return 0;
 }

Reply via email to