Hi, The patch enables htdbm utility to manage the groups. The group management enables that both passwords and groups exists in the same database or in different ones.
for example: htdbm -cmbgt .htdbm username password group1,group2 "Some comment" will create the record with key=username and value=encryptedpassword:group1,group2:Some comment there is other addon switch that enables one to modify the record without the need to retype the password (switch u). htdbm -gtu .htdbm username group1,group3 "The user moved from group2" will preserve the old username password and the record will look like key=username and value=oldencryptedpassword:group1,group3:Some comment MT.
Index: htdbm.c =================================================================== RCS file: /home/cvspublic/httpd-2.0/support/htdbm.c,v retrieving revision 1.3 diff -u -r1.3 htdbm.c --- htdbm.c 2001/11/06 21:11:45 1.3 +++ htdbm.c 2001/11/24 19:41:13 @@ -103,12 +103,12 @@ #endif /*APR_CHARSET_EBCDIC*/ #define MAX_STRING_LEN 256 -#define ALG_PLAIN 0 -#define ALG_APMD5 1 -#define ALG_APSHA 2 +#define ALG_PLAIN 1 +#define ALG_APMD5 2 +#define ALG_APSHA 3 #if APR_HAVE_CRYPT_H -#define ALG_CRYPT 3 +#define ALG_CRYPT 4 #endif @@ -133,6 +133,7 @@ char *username; char *userpass; char *comment; + char *groups; int create; int rdonly; int alg; @@ -234,23 +235,45 @@ static apr_status_t htdbm_save(htdbm_t *htdbm, int *changed) { apr_datum_t key, val; + char *record, *old = NULL; if (!htdbm->username) return APR_SUCCESS; key.dptr = htdbm->username; key.dsize = strlen(htdbm->username); - if (apr_dbm_exists(htdbm->dbm, key)) + if (apr_dbm_exists(htdbm->dbm, key)) { + if (!htdbm->userpass) { + if (apr_dbm_fetch(htdbm->dbm, key, &val) != APR_SUCCESS) + return APR_ENOENT; + old = apr_pstrndup(htdbm->pool, val.dptr, val.dsize); + record = strchr(old, ':'); + if (record) { + *record = '\0'; + htdbm->userpass = old; + } + } *changed = 1; - - val.dsize = strlen(htdbm->userpass); - if (!htdbm->comment) - val.dptr = htdbm->userpass; + } + if (!htdbm->userpass) + htdbm->userpass = ""; + if (htdbm->groups) { + if (htdbm->comment) + record = apr_pstrcat(htdbm->pool, htdbm->userpass, ":", + htdbm->groups, ":", htdbm->comment, NULL); + else + record = apr_pstrcat(htdbm->pool, htdbm->userpass, ":", + htdbm->groups, NULL); + } else { - val.dptr = apr_pstrcat(htdbm->pool, htdbm->userpass, ";", + if (htdbm->comment) + record = apr_pstrcat(htdbm->pool, htdbm->userpass, ";", htdbm->comment, NULL); - val.dsize += (strlen(htdbm->comment) + 1); + else + record = htdbm->userpass; } + val.dptr = record; + val.dsize = strlen(record); return apr_dbm_store(htdbm->dbm, key, val); } @@ -280,6 +303,9 @@ return APR_ENOENT; rec = apr_pstrndup(htdbm->pool, val.dptr, val.dsize); cmnt = strchr(rec, ';'); + if (!cmnt) + cmnt = strchr(rec, ';'); + if (cmnt) strncpy(pwd, rec, cmnt - rec); else @@ -291,7 +317,7 @@ { apr_status_t rv; apr_datum_t key, val; - char *rec, *cmnt; + char *rec, *cmnt, *grp; char kb[MAX_STRING_LEN]; int i = 0; @@ -303,7 +329,7 @@ rec = apr_pcalloc(htdbm->pool, HUGE_STRING_LEN); fprintf(stderr, "Dumping records from database -- %s\n", htdbm->filename); - fprintf(stderr, " %-32sComment\n", "Username"); + fprintf(stderr, " %-25s%-25sComment\n", "Username", "Group(s)"); while (key.dptr != NULL) { rv = apr_dbm_fetch(htdbm->dbm, key, &val); if (rv != APR_SUCCESS) { @@ -312,10 +338,16 @@ } strncpy(kb, key.dptr, key.dsize); kb[key.dsize] = '\0'; - fprintf(stderr, " %-32s", kb); + fprintf(stderr, " %-25s", kb); strncpy(rec, val.dptr, val.dsize); rec[val.dsize] = '\0'; - cmnt = strchr(rec, ';'); + grp = strchr(rec, ':'); + if (grp) + cmnt = strchr(grp+1, ':'); + else + cmnt = strchr(rec, ';'); + *cmnt = '\0'; + fprintf(stderr, "%-25s", grp ? grp + 1 : " "); if (cmnt) fprintf(stderr, cmnt + 1); fprintf(stderr, "\n"); @@ -345,6 +377,9 @@ char cpw[MAX_STRING_LEN]; char salt[9]; + if (!htdbm->userpass) + return APR_SUCCESS; + switch (htdbm->alg) { case ALG_APSHA: /* XXX cpw >= 28 + strlen(sha1) chars - fixed len SHA */ @@ -371,6 +406,7 @@ fprintf(stderr, "CRYPT is now depriciated, use MD5 instead !\n"); #endif default: + cpw[0] = '\0'; break; } htdbm->userpass = apr_pstrdup(htdbm->pool, cpw); @@ -395,8 +431,10 @@ #if APR_HAVE_CRYPT_H #define CRYPT_OPTION "d" +#define IDENT_OPTION " " #else #define CRYPT_OPTION "" +#define IDENT_OPTION "" #endif fprintf(stderr, "htdbm -- program for manipulating DBM password databases.\n\n"); fprintf(stderr, "Usage: htdbm [-cm"CRYPT_OPTION"pstvx] database username\n"); @@ -406,9 +444,10 @@ fprintf(stderr, " -v[m"CRYPT_OPTION"ps] database username\n"); fprintf(stderr, " -vb[m"CRYPT_OPTION"ps] database username password\n"); fprintf(stderr, " -x[m"CRYPT_OPTION"ps] database username\n"); - fprintf(stderr, " -l database\n"); + fprintf(stderr, " -g[u]"IDENT_OPTION" database username +group(s)\n"); + fprintf(stderr, " -l"IDENT_OPTION" database\n"); fprintf(stderr, "Options:\n"); - fprintf(stderr, " -b Use the password from the command line rather" + fprintf(stderr, " -b Use the password from the command line rather " "than prompting for it.\n"); fprintf(stderr, " -c Create a new database.\n"); fprintf(stderr, " -n Don't update database; display results on stdout.\n"); @@ -419,9 +458,11 @@ 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 database on stdout.\n"); - fprintf(stderr, " -t The last param is username comment.\n"); + fprintf(stderr, " -t The last param is the record comment.\n"); fprintf(stderr, " -v Verify the username/password.\n"); fprintf(stderr, " -x Remove the username record from database.\n"); + fprintf(stderr, " -g Add the username to specified group(s).\n"); + fprintf(stderr, " -u Update the username record if exists.\n"); exit(ERR_SYNTAX); } @@ -440,6 +481,7 @@ int need_user = 1; int need_pwd = 1; int need_cmnt = 0; + int need_grp = 0; int pwd_supplied = 0; int changed; int cmd = HTDBM_MAKE; @@ -474,6 +516,9 @@ need_pwd = 0; args_left++; break; + case 'u': + need_pwd = 0; + break; case 'c': h->create = 1; break; @@ -493,6 +538,10 @@ need_cmnt = 1; args_left++; break; + case 'g': + need_grp = 1; + args_left++; + break; case 'v': h->rdonly = 1; cmd = HTDBM_VERIFY; @@ -539,13 +588,14 @@ exit(ERR_FILEPERM); } } + ++i; if (need_user) { - h->username = apr_pstrdup(pool, argv[i+1]); + h->username = apr_pstrdup(pool, argv[i++]); if (htdbm_valid_username(h) != APR_SUCCESS) exit(ERR_BADUSER); } if (pwd_supplied) - h->userpass = apr_pstrdup(pool, argv[i+2]); + h->userpass = apr_pstrdup(pool, argv[i++]); if (need_pwd) { l = sizeof(pwc); @@ -565,10 +615,12 @@ h->userpass = apr_pstrdup(pool, pwi); } - if (need_cmnt && pwd_supplied) - h->comment = apr_pstrdup(pool, argv[i+3]); - else if (need_cmnt) - h->comment = apr_pstrdup(pool, argv[i+2]); + + if (need_grp) + h->groups = apr_pstrdup(pool, argv[i++]); + + if (need_cmnt) + h->comment = apr_pstrdup(pool, argv[i]); switch (cmd) { case HTDBM_VERIFY: