Return-Path: Delivered-To: apmail-new-httpd-archive@apache.org Received: (qmail 38278 invoked by uid 500); 14 Aug 2001 19:50:10 -0000 Mailing-List: contact new-httpd-help@apache.org; run by ezmlm Precedence: bulk Reply-To: new-httpd@apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list new-httpd@apache.org Received: (qmail 38267 invoked from network); 14 Aug 2001 19:50:10 -0000 Errors-To: Message-ID: <013e01c124f9$f09ad4a0$96c0b0d0@roweclan.net> From: "William A. Rowe, Jr." To: References: Subject: Re: [ENHANCEMENT] htpasswd utility with DBM support Date: Tue, 14 Aug 2001 14:40:25 -0500 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_00F3_01C124CF.0E4AD520" X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 5.50.4133.2400 X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4133.2400 X-Spam-Rating: h31.sny.collab.net 1.6.2 0/1000/N Status: O X-Status: X-Keywords: X-UID: 571 This is a multi-part message in MIME format. ------=_NextPart_000_00F3_01C124CF.0E4AD520 Content-Type: text/plain; charset="iso-8859-2" Content-Transfer-Encoding: 7bit From: "Mladen Turk" 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. ------=_NextPart_000_00F3_01C124CF.0E4AD520 Content-Type: text/plain; name="htpasswd.dbm.diffs" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="htpasswd.dbm.diffs" 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 @@ -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; } ------=_NextPart_000_00F3_01C124CF.0E4AD520--