/* Copyright (C) 1990 Transarc Corporation - All rights reserved */ #include #include #include #ifdef AFS_NT40_ENV #include #include #include #else #include #include #endif #include #include #include #include #include #include #include "kauth.h" #include "kautils.h" #include "kaserver.h" #define UBIK_HEADERSIZE 64 #define UBIK_BUFFERSIZE 1024 char *whoami = "kadb_check"; int fd; FILE *out; int listuheader, listkheader, listentries, verbose; int readUbikHeader() { int offset, r; struct ubik_hdr uheader; offset = lseek(fd, 0, 0); if (offset != 0) { printf("error: lseek to 0 failed: %d %d\n", offset, errno); return(-1); } /* now read the info */ r = read(fd, &uheader, sizeof(uheader)); if (r != sizeof(uheader)) { printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r, errno); return(-1); } uheader.magic = ntohl(uheader.magic); uheader.size = ntohl(uheader.size); uheader.version.epoch = ntohl(uheader.version.epoch); uheader.version.counter = ntohl(uheader.version.counter); if (listuheader) { printf("Ubik Header\n"); printf(" Magic = 0x%x\n", uheader.magic); printf(" Size = %u\n", uheader.size); printf(" Version.epoch = %u\n", uheader.version.epoch); printf(" Version.counter = %u\n", uheader.version.counter); } if (uheader.size != UBIK_HEADERSIZE) printf("Ubik header size is %u (should be %u)\n", uheader.size, UBIK_HEADERSIZE); if (uheader.magic != UBIK_MAGIC) printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic, UBIK_MAGIC); return(0); } PrintHeader(header) struct kaheader *header; { printf("Version = %d\n", header->version); printf("HeaderSize = %d\n", header->headerSize); printf("Free Ptr = %u\n", header->freePtr); printf("EOF Ptr = %u\n", header->eofPtr); printf("Kvno Ptr = %u\n", header->kvnoPtr); printf("SpecialKeysVersion changed = %d\n", header->specialKeysVersion); printf("# admin accounts = %d\n", header->admin_accounts); printf("HashSize = %d\n", header->hashsize); printf("Check Version = %d\n", header->checkVersion); printf("stats.minorVersion = %d\n", header->stats.minor_version); printf("stats.AllocBlock calls = %d\n", header->stats.allocs); printf("stats.FreeBlock calls = %d\n", header->stats.frees); printf("stats.cpw commands = %d\n", header->stats.cpws); } PrintEntry(index, entry) afs_int32 index; struct kaentry *entry; { int i; char Time[100]; struct tm *tm_p; printf("\n"); i = (index - sizeof(struct kaheader))/sizeof(struct kaentry); printf("Entry %5d (%u):\n", i, index); if (entry->flags & KAFNORMAL) { printf (" Name = %s", entry->userID.name); if (strlen(entry->userID.instance) > 0) { printf (".%s", entry->userID.instance); } printf("\n"); } printf(" flags = "); if (entry->flags & KAFNORMAL) printf("NORMAL "); if (entry->flags & KAFADMIN) printf("ADMIN "); if (entry->flags & KAFNOTGS) printf("NOTGS "); if (entry->flags & KAFNOSEAL) printf("NOSEAL "); if (entry->flags & KAFNOCPW) printf("NOCPW "); if (entry->flags & KAFNEWASSOC) printf("CR-ASSOC "); if (entry->flags & KAFFREE) printf("FREE "); if (entry->flags & KAFOLDKEYS) printf("OLDKEYS "); if (entry->flags & KAFSPECIAL) printf("SPECIAL "); if (entry->flags & KAFASSOCROOT) printf("ROOT-ASSOC "); if (entry->flags & KAFASSOC) printf("AN-ASSOC "); printf("\n"); printf(" Next = %u\n", entry->next); if (entry->flags & KAFFREE) return; if (entry->flags & KAFOLDKEYS) return; tm_p = localtime((time_t *)&entry->user_expiration); if (tm_p) strftime(Time, 100, "%m/%d/%Y %H:%M", tm_p); printf(" User Expiration = %s\n", (entry->user_expiration == 0xffffffff) ? "never" : Time); printf(" Password Expiration = %u days %s\n", entry->misc_auth_bytes[EXPIRES], (entry->misc_auth_bytes[EXPIRES]?"":"(never)")); printf(" Password Attempts before lock = "); if (!entry->misc_auth_bytes[ATTEMPTS]) printf("unlimited\n"); else printf("%d\n", entry->misc_auth_bytes[ATTEMPTS]); printf(" Password lockout time = "); if (!entry->misc_auth_bytes[LOCKTIME]) printf("unlimited\n"); else printf("%.1f min\n", (entry->misc_auth_bytes[LOCKTIME] * 8.5)); printf(" Is entry locked = %s\n", (entry->misc_auth_bytes[REUSEFLAGS] == KA_ISLOCKED) ? "yes" : "no"); printf(" Permit password reuse = %s\n", (!entry->pwsums[0] && !entry->pwsums[1]) ? "yes" : "no"); printf(" Mod Time = %u: %s", entry->modification_time, ctime((time_t *)&entry->modification_time)); printf(" Mod ID = %u\n", entry->modification_id); printf(" Change Password Time = %u: %s", entry->change_password_time, ctime((time_t *)&entry->change_password_time)); printf(" Ticket lifetime = %u: %s", entry->max_ticket_lifetime, ctime((time_t *)&entry->max_ticket_lifetime)); printf(" Key Version = %d\n", entry->key_version); printf(" Key = "); ka_PrintBytes (&entry->key, sizeof(entry->key)); printf("\n"); /* What about asServer structs and such and misc_ath_bytes */ } /* ntohEntry - convert back to host-order */ ntohEntry(struct kaentry *entryp) { entryp->flags = ntohl(entryp->flags); entryp->next = ntohl(entryp->next); entryp->user_expiration = ntohl(entryp->user_expiration); entryp->modification_time = ntohl(entryp->modification_time); entryp->modification_id = ntohl(entryp->modification_id); entryp->change_password_time = ntohl(entryp->change_password_time); entryp->max_ticket_lifetime = ntohl(entryp->max_ticket_lifetime); entryp->key_version = ntohl(entryp->key_version); entryp->misc.asServer.nOldKeys = ntohl(entryp->misc.asServer.nOldKeys); entryp->misc.asServer.oldKeys = ntohl(entryp->misc.asServer.oldKeys); } char principal[64]; char *EntryName(entryp) struct kaentry *entryp; { char name[32], inst[32]; ka_ConvertBytes(name, sizeof(name), entryp->userID.name, strlen(entryp->userID.name)); ka_ConvertBytes(inst, sizeof(inst), entryp->userID.instance, strlen(entryp->userID.instance)); if (strlen(entryp->userID.instance)) { sprintf (principal, "%s.%s", name, inst); } else { strcpy (principal, name); } return(principal); } RebuildEntry(entryp) struct kaentry *entryp; { char key[33]; char flags[128]; char Time[50]; /* Special entries are not rebuilt */ if (entryp->flags & KAFSPECIAL) return; fprintf(out, "create -name %s", EntryName(entryp)); ka_ConvertBytes (key, sizeof(key), &entryp->key, sizeof(entryp->key)); fprintf(out, " -initial_password foo\n", key); strcpy(flags,""); if (entryp->flags & KAFADMIN) strcat(flags, "+ADMIN"); if (entryp->flags & KAFNOTGS) strcat(flags, "+NOTGS"); if (entryp->flags & KAFNOSEAL) strcat(flags, "+NOSEAL"); if (entryp->flags & KAFNOCPW) strcat(flags, "+NOCPW"); fprintf(out, "setfields -name %s", principal); if (strcmp(flags,"") != 0) fprintf(out, " -flags %s", &flags[1]); if (entryp->user_expiration != 0xffffffff) { strftime(Time, 50, "%m/%d/%Y %H:%M", localtime((time_t *)&entryp->user_expiration)); fprintf(out, " -expiration '%s'", Time); } fprintf(out, " -lifetime %u", entryp->max_ticket_lifetime); if (entryp->misc_auth_bytes[EXPIRES]) fprintf(out, " -pwexpires %u", entryp->misc_auth_bytes[EXPIRES]); if (entryp->pwsums[0] || entryp->pwsums[1]) fprintf(out, " -reuse no"); if (entryp->misc_auth_bytes[ATTEMPTS]) fprintf(out, " -attempts %u", entryp->misc_auth_bytes[ATTEMPTS]); if (entryp->misc_auth_bytes[LOCKTIME]) fprintf(out, " -locktime %d", (int)(entryp->misc_auth_bytes[LOCKTIME]*8.5)); fprintf(out, "\n"); fprintf(out, "setkey -name %s -new_key %s -kvno %d\n", principal, key, ntohl(entryp->key_version)); } CheckHeader(header) struct kaheader *header; { afs_int32 i, code = 0; header->version = ntohl(header->version); header->headerSize = ntohl(header->headerSize); header->freePtr = ntohl(header->freePtr); header->eofPtr = ntohl(header->eofPtr); header->kvnoPtr = ntohl(header->kvnoPtr); header->stats.minor_version = ntohl(header->stats.minor_version); header->stats.allocs = ntohl(header->stats.allocs); header->stats.frees = ntohl(header->stats.frees); header->stats.cpws = ntohl(header->stats.cpws); header->admin_accounts = ntohl(header->admin_accounts); header->specialKeysVersion = ntohl(header->specialKeysVersion); header->hashsize = ntohl(header->hashsize); for (i=0; inameHash[i] = ntohl(header->nameHash[i]); } header->checkVersion = ntohl(header->checkVersion); if (header->version != header->checkVersion) { code++; fprintf(stderr, "HEADER VERSION MISMATCH: initial %d, final %d\n", header->version, header->checkVersion); } if (header->headerSize != sizeof(struct kaheader)) { code++; fprintf(stderr, "HEADER SIZE WRONG: file indicates %d, should be %d\n", header->headerSize, sizeof(struct kaheader)); } if (header->hashsize != HASHSIZE) { code++; fprintf(stderr, "HASH SIZE WRONG: file indicates %d, should be %d\n", header->hashsize, HASHSIZE); } if ((header->kvnoPtr && ((header->kvnoPtr < header->headerSize) || (header->eofPtr < header->freePtr))) || (header->freePtr && ((header->freePtr < header->headerSize) || (header->eofPtr < header->kvnoPtr)))) { code++; fprintf(stderr, "DATABASE POINTERS BAD: header size = %d, freePtr = %d, kvnoPtr = %d, eofPtr = %d\n", header->headerSize, header->freePtr, header->kvnoPtr, header->eofPtr); } /* * fprintf(stderr, "DB Version %d, %d possible entries\n", header->version, * (header->eofPtr-header->headerSize) / sizeof(struct kaentry)); */ return code; } afs_int32 NameHash(entryp) struct kaentry *entryp; { unsigned int hash; int i; char *aname = entryp->userID.name; char *ainstance = entryp->userID.instance; /* stolen directly from the HashString function in the vol package */ hash = 0; for (i=strlen(aname), aname += i-1; i--; aname--) hash = (hash*31) + (*((unsigned char *)aname) - 31); for (i=strlen(ainstance), ainstance += i-1; i--; ainstance--) hash = (hash*31) + (*((unsigned char *)ainstance) - 31); return(hash % HASHSIZE); } readDB(offset, buffer, size) afs_int32 offset; char *buffer; afs_int32 size; { afs_int32 code; offset += UBIK_HEADERSIZE; code = lseek(fd, offset, SEEK_SET); if (code != offset) { com_err (whoami, errno, "skipping Ubik header"); exit(2); } code = read(fd, buffer, size); if (code != size) { com_err (whoami, errno, "reading db got %d bytes", code); exit(3); } } #include "AFS_component_version_number.c" WorkerBee (as, arock) struct cmd_syndesc *as; char *arock; { afs_int32 code; int a; char *dbFile; char *outFile; afs_int32 index; struct stat info; struct kaheader header; int nentries, i, j, count; int *entrys; struct kaentry entry; dbFile = as->parms[0].items->data; /* -database */ listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */ listkheader = (as->parms[2].items ? 1 : 0); /* -kheader */ listentries = (as->parms[3].items ? 1 : 0); /* -entries */ verbose = (as->parms[4].items ? 1 : 0); /* -verbose */ outFile = (as->parms[5].items ? as->parms[5].items->data : (char *)0); /* -rebuild */ if (outFile) { out = fopen (outFile, "w"); if (!out) { com_err (whoami, errno, "opening output file %s", outFile); exit (7); } } else out = 0; fd = open (dbFile, O_RDONLY, 0); if (fd < 0) { com_err (whoami, errno, "opening database file %s", dbFile); exit (6); } code = fstat (fd, &info); if (code) { com_err (whoami, errno, "stat'ing file %s", dbFile); exit (6); } if ((info.st_size - UBIK_HEADERSIZE) % UBIK_BUFFERSIZE) fprintf(stderr, "DATABASE SIZE INCONSISTENT: was %d, should be (n*%d + %d), for integral n\n", info.st_size, UBIK_BUFFERSIZE, UBIK_HEADERSIZE); readUbikHeader(); readDB(0, &header, sizeof(header)); code = CheckHeader(&header); if (listkheader) PrintHeader(&header); nentries = (info.st_size-(UBIK_HEADERSIZE + header.headerSize)) / sizeof(struct kaentry); entrys = (int *)malloc(nentries * sizeof(int)); bzero(entrys, nentries * sizeof(int)); for (i=0, index=sizeof(header); i= header.eofPtr) { entrys[i] |= 0x8; } else if (listentries) { PrintEntry(index, &entry); } if (entry.flags & KAFNORMAL) { entrys[i] |= 0x1; /* user entry */ if (strlen(entry.userID.name) == 0) { if (verbose) printf("Entry %d has zero length name\n", i); continue; } if (!des_check_key_parity (&entry.key) || des_is_weak_key (&entry.key)) { fprintf(stderr, "Entry %d, %s, has bad key\n", i, EntryName(&entry)); continue; } if (out) { RebuildEntry(&entry); } } else if (entry.flags & KAFFREE) { entrys[i] |= 0x2; /* free entry */ } else if (entry.flags & KAFOLDKEYS) { entrys[i] |= 0x4; /* old keys block */ /* Should check the structure of the oldkeys block? */ } else { if (index < header.eofPtr) { fprintf(stderr, "Entry %d is unrecognizable\n", i); } } } /* Follow the hash chains */ for (j=0; j User Entry 0x10 --> On hash chain * 0x2 --> Free Entry 0x20 --> On Free chain * 0x4 --> OldKeys Entry 0x40 --> On Oldkeys chain * 0x8 --> Past EOF */ for (i=0; i"); fprintf(stderr, " ] ["); if ( e & 0x10) fprintf(stderr, " UserChain"); if ( e & 0x20) fprintf(stderr, " FreeChain"); if ( e & 0x40) fprintf(stderr, " OldkeysChain"); if (!(e & 0xf0)) fprintf(stderr, " "); fprintf(stderr, " ]\n"); } main (argc, argv) int argc; char *argv[]; { struct cmd_syndesc *ts; struct cmd_item *ti; setlinebuf(stdout); ts=cmd_CreateSyntax((char *)0, WorkerBee, (char *) 0, "KADB check"); cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "kadb_file"); cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL, "Display UBIK header"); cmd_AddParm(ts, "-kheader", CMD_FLAG, CMD_OPTIONAL, "Display KADB header"); cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries"); cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose"); cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL, "out_file"); return cmd_Dispatch(argc, argv); }