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;
}