/* apachedbm.c (c) 1999 Mrs. Brisby a dbmmanage replacement. dbmmanage is a tool supplied with Apache that modifies DBM databases. However, unless PERL and Apache are built to use the same DBM library (which can be trying) dbmmanage will not function properly AT ALL! This works with almost the exact same syntax, and operates using the same DBM api that Apache uses (e.g. the NDBM api). I've noticed no problems with this program. If you do, by all means let me know (patches also welcome). Compile using: cc -o apachedbm apachedbm.c -ldbm If you have an external crypt library: cc -o apachedbm apachedbm.c -ldbm -lcrypt If you want this to work with NETSCAPE's dbm files/server, you can add cc -DNETSCAPE_DBM_COMPAT -o apachedbm apachedbm.c -ldbm 4.4BSD derived systems (BSD/OS 2.0) may or may not support longer crypt results, and bigger salts. Support for this can be enabled using: cc -DNEWSTYLE_CRYPT -o apachedbm apachedbm.c -ldbm In general: The same CFLAGS and libraries used to build apache should function well here. If you use GDBM for apache, specify -lgdbm instead of -ldbm. Look in your .../apache/src/Configuration for the proper flags. */ #include #include #include #include #include #include #include enum { ADBM_ADD, ADBM_ADDUSER, ADBM_CHECK, ADBM_DELETE, ADBM_IMPORT, ADBM_UPDATE, ADBM_VIEW }; static char randchar(void) { int i; char *rmap = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; i = rand() % strlen(rmap); return rmap[i]; } static char *gensalt(void) { #ifdef NEWSTYLE_CRYPT static char salt[10]; salt[0] = '_'; salt[1] = randchar(); salt[2] = 'a'; salt[3] = '.'; salt[4] = '.'; salt[5] = randchar(); salt[6] = randchar(); salt[7] = randchar(); salt[8] = randchar(); salt[9] = '\0'; #else static char salt[3]; salt[0] = randchar(); salt[1] = randchar(); salt[2] = '\0'; #endif return salt; } int main(int argc, char *argv[]) { #define USAGE \ printf("usage: %s filename [add|adduser|check|delete|import|update|view] [username]\n", argv[0]); exit(0); DBM *f; datum d, q; char *filename; char *ip, *ap; char buf[256]; int command; if (argc < 3) { USAGE } filename = argv[1]; if (strcasecmp(argv[2], "adduser") == 0) { command = ADBM_ADDUSER; } else switch (*(argv[2])) { case 'a': case 'A': command = ADBM_ADD; break; case 'c': case 'C': command = ADBM_CHECK; break; case 'd': case 'D': command = ADBM_DELETE; break; case 'i': case 'I': command = ADBM_IMPORT; break; case 'u': case 'U': command = ADBM_UPDATE; break; case 'v': case 'V': command = ADBM_VIEW; break; default: USAGE }; if (command != ADBM_IMPORT && command != ADBM_CHECK && command != ADBM_VIEW) { if (argc < 4) { USAGE } q.dptr = argv[3]; #ifndef NETSCAPE_DBM_COMPAT q.dsize = strlen(q.dptr); #else q.dsize = strlen(q.dptr)+1; #endif } if (!(f = dbm_open(filename, O_RDWR|O_CREAT, 0644))) { perror("dbm_open"); exit(1); } if (command == ADBM_VIEW) { q = dbm_firstkey(f); while (q.dptr) { d = dbm_fetch(f, q); fwrite(q.dptr, q.dsize, 1, stdout); fputc(':', stdout); fwrite(d.dptr, d.dsize, 1, stdout); fputc('\n', stdout); q = dbm_nextkey(f); } dbm_close(f); exit(0); } if (command == ADBM_IMPORT) { while (fgets(buf, 255, stdin)) { ap = strchr(buf, '\r'); if (ap) { *ap = 0; } ap = strchr(buf, '\n'); if (ap) { *ap = 0; } ap = strchr(buf, ':'); if (ap) { *ap = 0; ap++; } else ap = ""; q.dptr = ip; #ifndef NETSCAPE_DBM_COMPAT q.dsize = strlen(ip); #else q.dsize = strlen(ip)+1; #endif d.dptr = ap; d.dsize = strlen(ap); (void) dbm_store(f, q, d, DBM_REPLACE); } dbm_close(f); exit(0); } if (command == ADBM_DELETE) { if (dbm_delete(f, q) == -1) { printf("Sorry, user `%s' doesn't exist!\n", argv[3]); dbm_close(f); exit(1); } dbm_close(f); exit(0); } if (command == ADBM_CHECK) { d = dbm_fetch(f, q); if (!d.dptr) { printf("Sorry, user `%s' doesn't exist!\n", argv[3]); dbm_close(f); exit(1); } ip = getpass("Password: "); ap = (char *)crypt(ip, d.dptr); if (d.dsize == strlen(ap) && strncmp(ap, d.dptr, d.dsize) == 0) puts("password ok"); else puts("password mismatch"); dbm_close(f); exit(0); } if (command == ADBM_ADD || command == ADBM_ADDUSER || command == ADBM_UPDATE) { ip = getpass("New password: "); ap = getpass("Re-type new password: "); if (strcmp(ip, ap) != 0) { puts("They don't match, sorry."); dbm_close(f); exit(1); } if (ADBM_ADD) ap = ip; else { srand(time(0)); ap = (char *)crypt(ip, gensalt()); } d.dptr = ap; d.dsize = strlen(ap); if (-1 == dbm_store(f, q, d, (command==ADBM_UPDATE)?DBM_REPLACE:DBM_INSERT)) { if (command = ADBM_UPDATE) printf("Sorry, user `%s' doesn't exist!\n", argv[3]); else printf("Sorry, user `%s' already exists!\n", argv[3]); dbm_close(f); exit(1); } /* done */ dbm_close(f); exit(0); } dbm_close(f); return 0; /* should never reach */ }