Return-Path: Delivered-To: apmail-httpd-dev-archive@httpd.apache.org Received: (qmail 29745 invoked by uid 500); 16 May 2002 16:36:53 -0000 Mailing-List: contact dev-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list dev@httpd.apache.org Received: (qmail 29729 invoked from network); 16 May 2002 16:36:53 -0000 Errors-To: Message-Id: <5.1.0.14.2.20020516111018.02095eb8@pop3.rowe-clan.net> X-Sender: wrowe%rowe-clan.net@pop3.rowe-clan.net X-Mailer: QUALCOMM Windows Eudora Version 5.1 Date: Thu, 16 May 2002 11:29:55 -0500 To: dev@httpd.apache.org From: "William A. Rowe, Jr." Subject: Re: [Patch] Add check for valid file to htpasswd Cc: HTTPD Dev List In-Reply-To: References: <20020516155013.GA25361@eustasy> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=====================_474844156==_" X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N --=====================_474844156==_ Content-Type: text/plain; charset="us-ascii"; format=flowed At 11:02 AM 5/16/2002, Cliff Woolley wrote: >On Thu, 16 May 2002, Thom May wrote: > > > As the topic. My ultimate (ie, next week) aim is to apr-ise htpasswd fully, > > unless there is a reason this wasn't done originally? > >Haven't had a chance to extensively look at this, but two quick comments: >no tabs please, and yes htpasswd should be APRized. It hasn't been done >because nobody got around to it. Actually Mladen Turk had a big patch for >this purpose, but it was rather more extensive than some of us thought was >necessary and never got committed. If you can find that and trim it down >a bit, I bet that would be a step in the right direction. Actually, I didn't realize how crufty htpasswd has really become. I believe it's worth looking at Mladen's patch on its own merits. The problem is that he cleaned up the code and apr'ized it in the same pass, making it appear to be a much bigger patch than it was. In fact, his newer code was considerably more elegant. However, it was overkill in the 'as a library' dept. If we want to add some essential flat file handling stuff in apr/file_io, fine... or some more accessors elsewhere, then cool. Anyway, his code, as I have it from Oct '01 is here; he may have revised it. Bill --=====================_474844156==_ Content-Type: text/plain; charset="us-ascii" /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * Portions of this software are based upon public domain software * originally written at the National Center for Supercomputing Applications, * University of Illinois, Urbana-Champaign. */ /* * htpasswd.c: simple program for manipulating flat-file * password databases for the Apache HTTP server * * Contributed by Mladen Turk * 12 Oct 2001 */ #include "apr.h" #include "apr_lib.h" #include "apr_strings.h" #include "apr_file_io.h" #include "apr_file_info.h" #include "apr_pools.h" #include "apr_hash.h" #include "apr_signal.h" #include "apr_md5.h" #include "apr_sha1.h" #if APR_HAVE_STDLIB_H #include #endif #if APR_HAVE_STRING_H #include #endif #if APR_HAVE_STRINGS_H #include #endif #if APR_CHARSET_EBCDIC #include "apr_xlate.h" #endif /*APR_CHARSET_EBCDIC*/ #if APR_HAVE_CRYPT_H #include #endif #if !APR_CHARSET_EBCDIC #define LF 10 #define CR 13 #else /*APR_CHARSET_EBCDIC*/ #define LF '\n' #define CR '\r' #endif /*APR_CHARSET_EBCDIC*/ #define MAX_STRING_LEN 256 #define ALG_PLAIN 0 #define ALG_APMD5 1 #define ALG_APSHA 2 #if APR_HAVE_CRYPT_H #define ALG_CRYPT 3 #endif #define ERR_FILEPERM 1 #define ERR_SYNTAX 2 #define ERR_PWMISMATCH 3 #define ERR_INTERRUPTED 4 #define ERR_OVERFLOW 5 #define ERR_BADUSER 6 #define ERR_EMPTY 7 typedef struct apu_htpasswd_t apu_htpasswd_t; struct apu_htpasswd_t { apr_file_t *file; apr_file_t *temp; apr_pool_t *pool; apr_hash_t *hash; #if APR_CHARSET_EBCDIC apr_xlate_t *to_ascii; #endif char *filename; char *tempname; char *username; char *userpass; apr_status_t error; int create; int alg; int rdonly; }; #define APU_HTPASSWD_DECLARE(x) static x #define APU_HTPASSWD_STANDALONE 1 #define APU_HTPASSWD_MAXFSIZE (512*1024) #define APU_HTPASSWD_MAKE 0 #define APU_HTPASSWD_DELETE 1 #define APU_HTPASSWD_VERIFY 2 #define APU_HTPASSWD_LIST 3 #define APU_HTPASSWD_NOFILE 4 #define APU_HTPASSWD_STDIN 5 APU_HTPASSWD_DECLARE(void) apu_htpasswd_terminate(apu_htpasswd_t *htpwd) { if (htpwd->file) apr_file_close(htpwd->file); if (htpwd->temp) apr_file_close(htpwd->temp); htpwd->file = NULL; htpwd->temp = NULL; } #if APU_HTPASSWD_STANDALONE static apu_htpasswd_t *h; APU_HTPASSWD_DECLARE(void) apu_htpasswd_interrupted(void) { apu_htpasswd_terminate(h); fprintf(stderr, "htpasswd Interrupted !\n"); exit(ERR_INTERRUPTED); } #endif APU_HTPASSWD_DECLARE(apr_status_t) apu_htpasswd_init(apr_pool_t **pool, apu_htpasswd_t **htpwd) { #if APR_CHARSET_EBCDIC apr_status_t rv; #endif #if APU_HTPASSWD_STANDALONE apr_initialize(); atexit(apr_terminate); apr_pool_create( pool, NULL); apr_signal(SIGINT, (void (*)(int)) apu_htpasswd_interrupted); #endif (*htpwd) = (apu_htpasswd_t *)apr_pcalloc(*pool, sizeof(apu_htpasswd_t)); (*htpwd)->pool = *pool; #if APR_CHARSET_EBCDIC rv = apr_xlate_open(to_ascii, "ISO8859-1", APR_DEFAULT_CHARSET, (*htpwd)->pool); if (rv) { fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", rv); return APR_EGENERAL; } rv = apr_SHA1InitEBCDIC((*htpwd)->to_ascii); if (rv) { fprintf(stderr, "apr_SHA1InitEBCDIC()->%d\n", rv); return APR_EGENERAL; } rv = apr_MD5InitEBCDIC((*htpwd)->to_ascii); if (rv) { fprintf(stderr, "apr_MD5InitEBCDIC()->%d\n", rv); return APR_EGENERAL; } #endif /*APR_CHARSET_EBCDIC*/ /* Set MD5 as default */ (*htpwd)->alg = ALG_APMD5; (*htpwd)->hash = NULL; (*htpwd)->tempname = apr_pstrdup(*pool, "htpasswd.tmp.XXXXXX"); return APR_SUCCESS; } APU_HTPASSWD_DECLARE(apr_status_t) apu_htpasswd_open(apu_htpasswd_t *htpwd) { apr_status_t rv; apr_finfo_t i; /* We don't need the temp file in case of creation */ if (htpwd->create) return apr_file_open(&htpwd->file, htpwd->filename, APR_BINARY | APR_READ | APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT, htpwd->pool); rv = apr_stat(&i, htpwd->filename, APR_FINFO_SIZE, htpwd->pool); if (rv != APR_SUCCESS) return rv; /* If we have a 'small' database use the hash table to load all the records or use the temporary backing file if the database is too large. */ if (i.size < APU_HTPASSWD_MAXFSIZE) { rv = apr_file_open(&htpwd->file, htpwd->filename, APR_BINARY | (htpwd->rdonly ? APR_READ : APR_READ | APR_WRITE), APR_OS_DEFAULT, htpwd->pool); /* Create the hash table that will hold all the records */ htpwd->hash = apr_hash_make(htpwd->pool); if (htpwd->hash == NULL) { fprintf(stderr, "Unable to allocate hash array\n"); return APR_EGENERAL; } } else { /* The database is too large so open a backing temp file*/ rv = apr_file_open(&htpwd->file, htpwd->filename, APR_BINARY | ( htpwd->rdonly ? APR_READ : APR_READ | APR_WRITE), APR_OS_DEFAULT, htpwd->pool); if (rv == APR_SUCCESS && !htpwd->rdonly) rv = apr_file_mktemp(&htpwd->temp, htpwd->tempname, htpwd->pool); } return rv; } APU_HTPASSWD_DECLARE(char *) ap_getword(apr_pool_t *atrans, char **line, char stop) { char *pos = strrchr(*line, stop); char *res; if (!pos) { res = apr_pstrdup(atrans, *line); *line += strlen(*line); return res; } res = apr_pstrndup(atrans, *line, pos - *line); while (*pos == stop) ++pos; *line = pos; return res; } APU_HTPASSWD_DECLARE(apr_status_t) apu_htpasswd_get_record(apu_htpasswd_t *htpwd, char **username, char **password) { apr_status_t rv; char l[MAX_STRING_LEN]; char *w; char ch; w = l; htpwd->error = APR_SUCCESS; do { rv = apr_file_getc(&ch, htpwd->file); if (rv == APR_SUCCESS) { if (ch == '\n') *w++ = '\0'; else if (ch != '\r') *w++ = ch; } else if (rv == APR_EOF) { htpwd->error = APR_EOF; *w++ = '\0'; ch = '\n'; } else return rv; } while (ch != '\n'); if (w == l || l[0] == '#') { htpwd->error = APR_EINVAL; return APR_SUCCESS; } /* parse the line */ w = l; *username = ap_getword(htpwd->pool, &w, ':'); *password = ap_getword(htpwd->pool, &w, ':'); return APR_SUCCESS; } /* * Load the entire password file in the hash table from the flat-file database */ APU_HTPASSWD_DECLARE(apr_status_t) apu_htpasswd_load(apu_htpasswd_t *htpwd) { apr_status_t rv; char *username, *password; if (!htpwd->hash) return APR_SUCCESS; while ((rv = apu_htpasswd_get_record(htpwd, &username, &password)) == APR_SUCCESS) { if (htpwd->error != APR_EINVAL && strlen(username)) { apr_hash_set(htpwd->hash, username, APR_HASH_KEY_STRING, password); } if (htpwd->error == APR_EOF) break; } if (htpwd->error != APR_EOF) { fprintf(stderr, "Didn't reach the EOF\n"); return APR_EBADF; } return APR_SUCCESS; } APU_HTPASSWD_DECLARE(apr_status_t) apr_file_copy(apr_file_t *from, apr_file_t *to, apr_pool_t *cntx) { apr_off_t off; apr_status_t rv; apr_size_t blen = HUGE_STRING_LEN; char *buf; buf = apr_palloc(cntx, HUGE_STRING_LEN); off = 0; rv = apr_file_seek(from, APR_SET, &off); if (rv != APR_SUCCESS) return rv; rv = apr_file_trunc(to, 0); if (rv != APR_SUCCESS) return rv; off = 0; rv = apr_file_seek(to, APR_SET, &off); if (rv != APR_SUCCESS) return rv; while ((rv = apr_file_read(from, buf, &blen)) == APR_SUCCESS) { while (!*buf && blen--) ++buf; if ((rv = apr_file_write(to, buf, &blen)) != APR_SUCCESS) return rv; if (blen != HUGE_STRING_LEN) break; } return rv; } /* Truncate the existing file and save the hash table * or in case of large database save to temp file and copy to database */ APU_HTPASSWD_DECLARE(apr_status_t) apu_htpasswd_save(apu_htpasswd_t *htpwd, int *changed) { apr_status_t rv; apr_hash_index_t *hi; char *username, *password; apr_ssize_t len; if (!htpwd->hash && !htpwd->temp && !htpwd->file) return APR_EGENERAL; if (htpwd->hash) { apr_off_t off = 0; if ((rv = apr_file_trunc(htpwd->file, 0)) != APR_SUCCESS) return rv; if ((rv = apr_file_seek(htpwd->file, APR_SET, &off)) != APR_SUCCESS) return rv; for (hi = apr_hash_first(htpwd->pool, htpwd->hash); hi; hi = apr_hash_next(hi)) { apr_hash_this(hi,(void*) &username, &len, (void*) &password); apr_file_printf(htpwd->file, "%s:%s\n", username, password); } } else if (htpwd->temp) { *changed = 0; while ((rv = apu_htpasswd_get_record(htpwd, &username, &password)) == APR_SUCCESS) { if (htpwd->error != APR_EINVAL && strlen(username)) { if (strcmp(username, htpwd->username) == 0) { /* skip if password is NULL */ if (htpwd->userpass && strlen(htpwd->userpass)) apr_file_printf(htpwd->temp, "%s:%s\n", htpwd->username, htpwd->userpass); *changed = 1; } else apr_file_printf(htpwd->temp, "%s:%s\n", username, password); } if (htpwd->error == APR_EOF) break; } if (!*changed) apr_file_printf(htpwd->temp, "%s:%s\n", htpwd->username, htpwd->userpass); return apr_file_copy(htpwd->temp, htpwd->file, htpwd->pool); } else apr_file_printf(htpwd->file, "%s:%s\n", htpwd->username, htpwd->userpass); return APR_SUCCESS; } APU_HTPASSWD_DECLARE(apr_status_t) apu_htpasswd_del(apu_htpasswd_t *htpwd) { if (htpwd->hash) { if (!apr_hash_get(htpwd->hash, htpwd->username, APR_HASH_KEY_STRING)) return APR_ENOENT; apr_hash_set(htpwd->hash, htpwd->username, APR_HASH_KEY_STRING, NULL); } else htpwd->userpass = NULL; return APR_SUCCESS; } APU_HTPASSWD_DECLARE(apr_status_t) apu_htpasswd_verify(apu_htpasswd_t *htpwd) { char *rec = NULL; if (htpwd->hash) { rec = apr_hash_get(htpwd->hash, htpwd->username, APR_HASH_KEY_STRING); if (!rec) return APR_ENOENT; return apr_password_validate(htpwd->userpass, rec); } else { char *username; while (apu_htpasswd_get_record(htpwd, &username, &rec) == APR_SUCCESS) { if (htpwd->error != APR_EINVAL && strlen(username)) { if (strcmp(username, htpwd->username) == 0) return apr_password_validate(htpwd->userpass, rec); } if (htpwd->error == APR_EOF) break; } } return APR_ENOENT; } APU_HTPASSWD_DECLARE(void) apu_htpasswd_list(apu_htpasswd_t *htpwd) { apr_hash_index_t *hi; char *username, *password; apr_ssize_t len; int i = 0; if (!htpwd->hash) { fprintf(stderr, "Database %s is too large to be dumped!\n", htpwd->filename); return; } fprintf(stderr, "Dumping records from database %s\n", htpwd->filename); fprintf(stderr, " Username:\n", htpwd->filename); for (hi = apr_hash_first(htpwd->pool, htpwd->hash); hi; hi = apr_hash_next(hi)) { apr_hash_this(hi,(void*) &username, &len, (void*) &password); fprintf(stderr, " %-32s\n", username); i++; } fprintf(stderr, "Total #records : %d\n", i); } static void to64(char *s, unsigned long v, int n) { static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; while (--n >= 0) { *s++ = itoa64[v&0x3f]; v >>= 6; } } APU_HTPASSWD_DECLARE(apr_status_t) apu_htpasswd_make(apu_htpasswd_t *htpwd) { char cpw[MAX_STRING_LEN]; char salt[9]; switch (htpwd->alg) { case ALG_APSHA: /* XXX cpw >= 28 + strlen(sha1) chars - fixed len SHA */ apr_sha1_base64(htpwd->userpass,strlen(htpwd->userpass),cpw); break; case ALG_APMD5: (void) srand((int) time((time_t *) NULL)); to64(&salt[0], rand(), 8); salt[8] = '\0'; apr_md5_encode((const char *)htpwd->userpass, (const char *)salt, cpw, sizeof(cpw)); break; case ALG_PLAIN: /* XXX this len limitation is not in sync with any HTTPd len. */ apr_cpystrn(cpw,htpwd->userpass,sizeof(cpw)); break; #if APR_HAVE_CRYPT_H case ALG_CRYPT: (void) srand((int) time((time_t *) NULL)); to64(&salt[0], rand(), 8); salt[8] = '\0'; apr_cpystrn(cpw, (char *)crypt(htpwd->userpass, salt), sizeof(cpw) - 1); fprintf(stderr, "CRYPT is now depriciated, use MD5 instead !\n"); #endif default: break; } if (htpwd->hash) apr_hash_set(htpwd->hash, htpwd->username, APR_HASH_KEY_STRING, apr_pstrdup(htpwd->pool, cpw)); else htpwd->userpass = apr_pstrdup(htpwd->pool, cpw); return APR_SUCCESS; } APU_HTPASSWD_DECLARE(apr_status_t) apu_htpasswd_valid_username(apu_htpasswd_t *htpwd) { if (!htpwd->username || (strlen(htpwd->username) > 64) || (strlen(htpwd->username) < 1)) { fprintf(stderr, "Invalid username length\n"); return APR_EINVAL; } if (strchr(htpwd->username, ':')) { fprintf(stderr, "Username contains invalid characters\n"); return APR_EINVAL; } return APR_SUCCESS; } static void htpasswd_usage(void) { #if APR_HAVE_CRYPT_H #define CRYPT_OPTION "d" #else #define CRYPT_OPTION "" #endif fprintf(stderr, "htpasswd -- program for manipulating flat-file password databases.\n\n"); fprintf(stderr, "Usage: htpasswd [-cm"CRYPT_OPTION"psvx] passwordfile username\n"); fprintf(stderr, " -b[cm"CRYPT_OPTION"psv] passwordfile username password\n"); fprintf(stderr, " -n[m"CRYPT_OPTION"ps] username\n"); fprintf(stderr, " -nb[m"CRYPT_OPTION"ps] username password\n"); fprintf(stderr, " -v[m"CRYPT_OPTION"ps] passwordfile username\n"); fprintf(stderr, " -vb[m"CRYPT_OPTION"ps] passwordfile username password\n"); fprintf(stderr, " -x[m"CRYPT_OPTION"ps] passwordfile username\n"); fprintf(stderr, " -l passwordfile\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -b Use the password from the command line rather" "than prompting for it.\n"); fprintf(stderr, " -c Create a new file (truncate existing).\n"); fprintf(stderr, " -n Don't update file; display results on stdout.\n"); fprintf(stderr, " -m Force MD5 encryption of the password (default).\n"); #if APR_HAVE_CRYPT_H fprintf(stderr, " -d Force CRYPT encryption of the password (now depriciated).\n"); #endif fprintf(stderr, " -p Do not encrypt the password (plaintext).\n"); fprintf(stderr, " -s Force SHA encryption of the password.\n"); fprintf(stderr, " -l Display usernames from file on stdout.\n"); fprintf(stderr, " -v Verify the username/password.\n"); fprintf(stderr, " -x Remove the username record from database.\n"); exit(ERR_SYNTAX); } int main(int argc, const char *argv[]) { apr_pool_t *pool; apr_status_t rv; apr_size_t l; char pwi[MAX_STRING_LEN]; char pwc[MAX_STRING_LEN]; char errbuf[MAX_STRING_LEN]; const char *arg; int need_file = 1; int need_user = 1; int need_pwd = 1; int pwd_supplied = 0; int changed; int cmd = APU_HTPASSWD_MAKE; int i; int args_left = 2; if ((rv = apu_htpasswd_init(&pool, &h)) != APR_SUCCESS) { fprintf(stderr, "Unable to initialize htpasswd terminating!\n"); apr_strerror(rv, errbuf, sizeof(errbuf)); exit(1); } /* * Preliminary check to make sure they provided at least * three arguments, we'll do better argument checking as * we parse the command line. */ if (argc < 3) htpasswd_usage(); /* * Go through the argument list and pick out any options. They * have to precede any other arguments. */ for (i = 1; i < argc; i++) { arg = argv[i]; if (*arg != '-') break; while (*++arg != '\0') { switch (*arg) { case 'b': pwd_supplied = 1; need_pwd = 0; args_left++; break; case 'c': h->create = 1; break; case 'n': need_file = 0; cmd = APU_HTPASSWD_NOFILE; args_left--; break; case 'l': need_pwd = 0; need_user = 0; cmd = APU_HTPASSWD_LIST; h->rdonly = 1; args_left--; break; case 'v': h->rdonly = 1; cmd = APU_HTPASSWD_VERIFY; break; case 'x': need_pwd = 0; cmd = APU_HTPASSWD_DELETE; break; case 'm': h->alg = ALG_APMD5; break; case 'p': h->alg = ALG_PLAIN; break; case 's': h->alg = ALG_APSHA; break; #if APR_HAVE_CRYPT_H case 'd': h->alg = ALG_CRYPT; break; #endif default: htpasswd_usage(); break; } } } /* * Make sure we still have exactly the right number of arguments left * (the filename, the username, and possibly the password if -b was * specified). */ if ((argc - i) != args_left) htpasswd_usage(); if (!need_file) i--; else { h->filename = apr_pstrdup(h->pool, argv[i]); if ((rv = apu_htpasswd_open(h)) != APR_SUCCESS) { fprintf(stderr, "Error oppening database %s\n", argv[i]); apr_strerror(rv, errbuf, sizeof(errbuf)); exit(ERR_FILEPERM); } if ((rv = apu_htpasswd_load(h)) != APR_SUCCESS) { apr_strerror(rv, errbuf, sizeof(errbuf)); exit(ERR_EMPTY); } } if (need_user) { h->username = apr_pstrdup(pool, argv[i+1]); if (apu_htpasswd_valid_username(h) != APR_SUCCESS) exit(ERR_BADUSER); } if (pwd_supplied) h->userpass = apr_pstrdup(pool, argv[i+2]); if (need_pwd) { l = sizeof(pwc); if (apr_password_get("Enter password : ", pwi, &l) != APR_SUCCESS) { fprintf(stderr, "Password too long\n"); exit(ERR_OVERFLOW); } l = sizeof(pwc); if (apr_password_get("Re-type password : ", pwc, &l) != APR_SUCCESS) { fprintf(stderr, "Password too long\n"); exit(ERR_OVERFLOW); } if (strcmp(pwi, pwc) != 0) { fprintf(stderr, "Password verification error\n"); exit(ERR_PWMISMATCH); } h->userpass = apr_pstrdup(pool, pwi); } switch (cmd) { case APU_HTPASSWD_VERIFY: if ((rv = apu_htpasswd_verify(h)) != APR_SUCCESS) { if(rv == APR_ENOENT) { fprintf(stderr, "The user '%s' cold not be found in database\n", h->username); exit(ERR_BADUSER); } else { fprintf(stderr, "Password mismatch for user '%s'\n", h->username); exit(ERR_PWMISMATCH); } } else fprintf(stderr, "Password validated for user '%s'\n", h->username); break; case APU_HTPASSWD_DELETE: if (apu_htpasswd_del(h) != APR_SUCCESS) { fprintf(stderr, "Cannot find user '%s' in database\n", h->username); exit(ERR_BADUSER); } break; case APU_HTPASSWD_LIST: apu_htpasswd_list(h); break; default: apu_htpasswd_make(h); break; } if (need_file && !h->rdonly) { if ((rv = apu_htpasswd_save(h, &changed)) != APR_SUCCESS) { apr_strerror(rv, errbuf, sizeof(errbuf)); exit(ERR_FILEPERM); } fprintf(stdout, "Database %s %s.\n", h->filename, h->create ? "created" : (changed ? "modified" : "updated")); } if (cmd == APU_HTPASSWD_NOFILE) fprintf(stderr, "%s:%s\n", h->username, h->userpass); apu_htpasswd_terminate(h); apr_terminate(); return 0; /* Supress compiler warning. */ } --=====================_474844156==_ Content-Type: text/plain; charset="us-ascii"; format=flowed --=====================_474844156==_--