2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
15 #include <sys/types.h>
23 #include <netinet/in.h>
31 #include <afs/com_err.h>
37 #define UBIK_HEADERSIZE 64
38 #define UBIK_BUFFERSIZE 1024
40 char *whoami = "kadb_check";
44 int listuheader, listkheader, listentries, verbose;
49 struct ubik_hdr uheader;
51 offset = lseek(fd, 0, 0);
53 printf("error: lseek to 0 failed: %d %d\n", offset, errno);
57 /* now read the info */
58 r = read(fd, &uheader, sizeof(uheader));
59 if (r != sizeof(uheader)) {
60 printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r, errno);
64 uheader.magic = ntohl(uheader.magic);
65 uheader.size = ntohl(uheader.size);
66 uheader.version.epoch = ntohl(uheader.version.epoch);
67 uheader.version.counter = ntohl(uheader.version.counter);
70 printf("Ubik Header\n");
71 printf(" Magic = 0x%x\n", uheader.magic);
72 printf(" Size = %u\n", uheader.size);
73 printf(" Version.epoch = %u\n", uheader.version.epoch);
74 printf(" Version.counter = %u\n", uheader.version.counter);
77 if (uheader.size != UBIK_HEADERSIZE)
78 printf("Ubik header size is %u (should be %u)\n", uheader.size, UBIK_HEADERSIZE);
79 if (uheader.magic != UBIK_MAGIC)
80 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic, UBIK_MAGIC);
86 struct kaheader *header;
88 printf("Version = %d\n", header->version);
89 printf("HeaderSize = %d\n", header->headerSize);
90 printf("Free Ptr = %u\n", header->freePtr);
91 printf("EOF Ptr = %u\n", header->eofPtr);
92 printf("Kvno Ptr = %u\n", header->kvnoPtr);
93 printf("SpecialKeysVersion changed = %d\n", header->specialKeysVersion);
94 printf("# admin accounts = %d\n", header->admin_accounts);
95 printf("HashSize = %d\n", header->hashsize);
96 printf("Check Version = %d\n", header->checkVersion);
97 printf("stats.minorVersion = %d\n", header->stats.minor_version);
98 printf("stats.AllocBlock calls = %d\n", header->stats.allocs);
99 printf("stats.FreeBlock calls = %d\n", header->stats.frees);
100 printf("stats.cpw commands = %d\n", header->stats.cpws);
103 PrintEntry(index, entry)
105 struct kaentry *entry;
113 i = (index - sizeof(struct kaheader))/sizeof(struct kaentry);
115 printf("Entry %5d (%u):\n", i, index);
117 if (entry->flags & KAFNORMAL) {
118 printf (" Name = %s", entry->userID.name);
119 if (strlen(entry->userID.instance) > 0) {
120 printf (".%s", entry->userID.instance);
126 if (entry->flags & KAFNORMAL) printf("NORMAL ");
127 if (entry->flags & KAFADMIN) printf("ADMIN ");
128 if (entry->flags & KAFNOTGS) printf("NOTGS ");
129 if (entry->flags & KAFNOSEAL) printf("NOSEAL ");
130 if (entry->flags & KAFNOCPW) printf("NOCPW ");
132 if (entry->flags & KAFNEWASSOC) printf("CR-ASSOC ");
133 if (entry->flags & KAFFREE) printf("FREE ");
134 if (entry->flags & KAFOLDKEYS) printf("OLDKEYS ");
135 if (entry->flags & KAFSPECIAL) printf("SPECIAL ");
136 if (entry->flags & KAFASSOCROOT) printf("ROOT-ASSOC ");
137 if (entry->flags & KAFASSOC) printf("AN-ASSOC ");
140 printf(" Next = %u\n", entry->next);
142 if (entry->flags & KAFFREE)
144 if (entry->flags & KAFOLDKEYS)
147 tm_p = localtime((time_t *)&entry->user_expiration);
149 strftime(Time, 100, "%m/%d/%Y %H:%M", tm_p);
151 printf(" User Expiration = %s\n",
152 (entry->user_expiration == 0xffffffff) ? "never" : Time);
154 printf(" Password Expiration = %u days %s\n",
155 entry->misc_auth_bytes[EXPIRES],
156 (entry->misc_auth_bytes[EXPIRES]?"":"(never)"));
158 printf(" Password Attempts before lock = ");
159 if (!entry->misc_auth_bytes[ATTEMPTS]) printf("unlimited\n");
160 else printf("%d\n", entry->misc_auth_bytes[ATTEMPTS]);
162 printf(" Password lockout time = ");
163 if (!entry->misc_auth_bytes[LOCKTIME]) printf("unlimited\n");
164 else printf("%.1f min\n", (entry->misc_auth_bytes[LOCKTIME] * 8.5));
166 printf(" Is entry locked = %s\n",
167 (entry->misc_auth_bytes[REUSEFLAGS] == KA_ISLOCKED) ? "yes" : "no");
169 printf(" Permit password reuse = %s\n",
170 (!entry->pwsums[0] && !entry->pwsums[1]) ? "yes" : "no");
172 printf(" Mod Time = %u: %s",
173 entry->modification_time, ctime((time_t *)&entry->modification_time));
174 printf(" Mod ID = %u\n", entry->modification_id);
175 printf(" Change Password Time = %u: %s",
176 entry->change_password_time,
177 ctime((time_t *)&entry->change_password_time));
178 printf(" Ticket lifetime = %u: %s",
179 entry->max_ticket_lifetime, ctime((time_t *)&entry->max_ticket_lifetime));
180 printf(" Key Version = %d\n", entry->key_version);
183 ka_PrintBytes ((char *)&entry->key, sizeof(entry->key));
186 /* What about asServer structs and such and misc_ath_bytes */
189 /* ntohEntry - convert back to host-order */
190 ntohEntry(struct kaentry *entryp)
192 entryp->flags = ntohl(entryp->flags);
193 entryp->next = ntohl(entryp->next);
194 entryp->user_expiration = ntohl(entryp->user_expiration);
195 entryp->modification_time = ntohl(entryp->modification_time);
196 entryp->modification_id = ntohl(entryp->modification_id);
197 entryp->change_password_time = ntohl(entryp->change_password_time);
198 entryp->max_ticket_lifetime = ntohl(entryp->max_ticket_lifetime);
199 entryp->key_version = ntohl(entryp->key_version);
200 entryp->misc.asServer.nOldKeys = ntohl(entryp->misc.asServer.nOldKeys);
201 entryp->misc.asServer.oldKeys = ntohl(entryp->misc.asServer.oldKeys);
205 char *EntryName(entryp)
206 struct kaentry *entryp;
208 char name[32], inst[32];
210 ka_ConvertBytes(name, sizeof(name),
211 entryp->userID.name, strlen(entryp->userID.name));
212 ka_ConvertBytes(inst, sizeof(inst),
213 entryp->userID.instance, strlen(entryp->userID.instance));
215 if (strlen(entryp->userID.instance)) {
216 sprintf (principal, "%s.%s", name, inst);
218 strcpy (principal, name);
225 struct kaentry *entryp;
231 /* Special entries are not rebuilt */
232 if (entryp->flags & KAFSPECIAL) return;
234 fprintf(out, "create -name %s", EntryName(entryp));
236 ka_ConvertBytes (key, sizeof(key), (char *)&entryp->key,
237 sizeof(entryp->key));
238 fprintf(out, " -initial_password foo\n");
241 if (entryp->flags & KAFADMIN) strcat(flags, "+ADMIN");
242 if (entryp->flags & KAFNOTGS) strcat(flags, "+NOTGS");
243 if (entryp->flags & KAFNOSEAL) strcat(flags, "+NOSEAL");
244 if (entryp->flags & KAFNOCPW) strcat(flags, "+NOCPW");
246 fprintf(out, "setfields -name %s", principal);
247 if (strcmp(flags,"") != 0)
248 fprintf(out, " -flags %s", &flags[1]);
249 if (entryp->user_expiration != 0xffffffff) {
250 strftime(Time, 50, "%m/%d/%Y %H:%M",
251 localtime((time_t *)&entryp->user_expiration));
252 fprintf(out, " -expiration '%s'", Time);
254 fprintf(out, " -lifetime %u", entryp->max_ticket_lifetime);
255 if (entryp->misc_auth_bytes[EXPIRES])
256 fprintf(out, " -pwexpires %u", entryp->misc_auth_bytes[EXPIRES]);
257 if (entryp->pwsums[0] || entryp->pwsums[1])
258 fprintf(out, " -reuse no");
259 if (entryp->misc_auth_bytes[ATTEMPTS])
260 fprintf(out, " -attempts %u", entryp->misc_auth_bytes[ATTEMPTS]);
261 if (entryp->misc_auth_bytes[LOCKTIME])
262 fprintf(out, " -locktime %d", (int)(entryp->misc_auth_bytes[LOCKTIME]*8.5));
265 fprintf(out, "setkey -name %s -new_key %s -kvno %d\n",
266 principal, key, ntohl(entryp->key_version));
270 struct kaheader *header;
272 afs_int32 i, code = 0;
274 header->version = ntohl(header->version);
275 header->headerSize = ntohl(header->headerSize);
276 header->freePtr = ntohl(header->freePtr);
277 header->eofPtr = ntohl(header->eofPtr);
278 header->kvnoPtr = ntohl(header->kvnoPtr);
279 header->stats.minor_version = ntohl(header->stats.minor_version);
280 header->stats.allocs = ntohl(header->stats.allocs);
281 header->stats.frees = ntohl(header->stats.frees);
282 header->stats.cpws = ntohl(header->stats.cpws);
283 header->admin_accounts = ntohl(header->admin_accounts);
284 header->specialKeysVersion = ntohl(header->specialKeysVersion);
285 header->hashsize = ntohl(header->hashsize);
286 for (i=0; i<HASHSIZE; i++) {
287 header->nameHash[i] = ntohl(header->nameHash[i]);
289 header->checkVersion = ntohl(header->checkVersion);
291 if (header->version != header->checkVersion) {
293 fprintf(stderr, "HEADER VERSION MISMATCH: initial %d, final %d\n",
294 header->version, header->checkVersion);
296 if (header->headerSize != sizeof(struct kaheader)) {
298 fprintf(stderr, "HEADER SIZE WRONG: file indicates %d, should be %d\n",
299 header->headerSize, sizeof(struct kaheader));
301 if (header->hashsize != HASHSIZE) {
303 fprintf(stderr, "HASH SIZE WRONG: file indicates %d, should be %d\n",
304 header->hashsize, HASHSIZE);
306 if ((header->kvnoPtr && ((header->kvnoPtr < header->headerSize) ||
307 (header->eofPtr < header->freePtr))) ||
308 (header->freePtr && ((header->freePtr < header->headerSize) ||
309 (header->eofPtr < header->kvnoPtr)))) {
312 "DATABASE POINTERS BAD: header size = %d, freePtr = %d, kvnoPtr = %d, eofPtr = %d\n",
313 header->headerSize, header->freePtr, header->kvnoPtr,
318 * fprintf(stderr, "DB Version %d, %d possible entries\n", header->version,
319 * (header->eofPtr-header->headerSize) / sizeof(struct kaentry));
324 afs_int32 NameHash(entryp)
325 struct kaentry *entryp;
329 char *aname = entryp->userID.name;
330 char *ainstance = entryp->userID.instance;
332 /* stolen directly from the HashString function in the vol package */
334 for (i=strlen(aname), aname += i-1; i--; aname--)
335 hash = (hash*31) + (*((unsigned char *)aname) - 31);
336 for (i=strlen(ainstance), ainstance += i-1; i--; ainstance--)
337 hash = (hash*31) + (*((unsigned char *)ainstance) - 31);
338 return(hash % HASHSIZE);
341 readDB(offset, buffer, size)
348 offset += UBIK_HEADERSIZE;
349 code = lseek(fd, offset, SEEK_SET);
350 if (code != offset) {
351 com_err (whoami, errno, "skipping Ubik header");
354 code = read(fd, buffer, size);
356 com_err (whoami, errno, "reading db got %d bytes", code);
361 #include "AFS_component_version_number.c"
363 WorkerBee (as, arock)
364 struct cmd_syndesc *as;
373 struct kaheader header;
374 int nentries, i, j, count;
376 struct kaentry entry;
378 dbFile = as->parms[0].items->data; /* -database */
379 listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
380 listkheader = (as->parms[2].items ? 1 : 0); /* -kheader */
381 listentries = (as->parms[3].items ? 1 : 0); /* -entries */
382 verbose = (as->parms[4].items ? 1 : 0); /* -verbose */
383 outFile = (as->parms[5].items ? as->parms[5].items->data :
384 (char *)0); /* -rebuild */
387 out = fopen (outFile, "w");
389 com_err (whoami, errno, "opening output file %s", outFile);
394 fd = open (dbFile, O_RDONLY, 0);
396 com_err (whoami, errno, "opening database file %s", dbFile);
399 code = fstat (fd, &info);
401 com_err (whoami, errno, "stat'ing file %s", dbFile);
404 if ((info.st_size - UBIK_HEADERSIZE) % UBIK_BUFFERSIZE)
406 "DATABASE SIZE INCONSISTENT: was %d, should be (n*%d + %d), for integral n\n",
407 info.st_size, UBIK_BUFFERSIZE, UBIK_HEADERSIZE);
411 readDB(0, &header, sizeof(header));
412 code = CheckHeader(&header);
413 if (listkheader) PrintHeader(&header);
415 nentries = (info.st_size-(UBIK_HEADERSIZE + header.headerSize)) / sizeof(struct kaentry);
416 entrys = (int *)malloc(nentries * sizeof(int));
417 memset(entrys, 0, nentries * sizeof(int));
419 for (i=0, index=sizeof(header); i<nentries; i++, index+=sizeof(struct kaentry)) {
420 readDB (index, &entry, sizeof(entry));
422 if (index >= header.eofPtr) {
425 else if (listentries) {
426 PrintEntry(index, &entry);
429 if (entry.flags & KAFNORMAL) {
430 entrys[i] |= 0x1; /* user entry */
432 if (strlen(entry.userID.name) == 0) {
433 if (verbose) printf("Entry %d has zero length name\n", i);
436 if (!des_check_key_parity (&entry.key) || des_is_weak_key (&entry.key)) {
437 fprintf(stderr, "Entry %d, %s, has bad key\n", i, EntryName(&entry));
442 RebuildEntry(&entry);
445 } else if (entry.flags & KAFFREE) {
446 entrys[i] |= 0x2; /* free entry */
448 } else if (entry.flags & KAFOLDKEYS) {
449 entrys[i] |= 0x4; /* old keys block */
450 /* Should check the structure of the oldkeys block? */
453 if (index < header.eofPtr) {
454 fprintf(stderr, "Entry %d is unrecognizable\n", i);
459 /* Follow the hash chains */
460 for (j=0; j<HASHSIZE; j++) {
461 for (index = header.nameHash[j]; index; index=entry.next) {
462 readDB (index, &entry, sizeof(entry));
464 /* check to see if the name is hashed correctly */
465 i = NameHash(&entry);
468 "Entry %d, %s, found in hash chain %d (should be %d)\n",
469 ((index - sizeof(struct kaheader))/sizeof(struct kaentry)),
470 EntryName(&entry), j, i);
473 /* Is it on another hash chain or circular hash chain */
474 i = (index - header.headerSize)/sizeof(entry);
475 if (entrys[i] & 0x10) {
477 "Entry %d, %s, hash index %d, was found on another hash chain\n",
478 i, EntryName(&entry), j);
480 fprintf(stderr, "Skipping rest of hash chain %d\n", j);
482 fprintf(stderr, "No next entry in hash chain %d\n", j);
486 entrys[i] |= 0x10; /* On hash chain */
490 /* Follow the free pointers */
492 for (index = header.freePtr; index; index=entry.next) {
493 readDB (index, &entry, sizeof(entry));
495 /* Is it on another chain or circular free chain */
496 i = (index - header.headerSize)/sizeof(entry);
497 if (entrys[i] & 0x20) {
498 fprintf(stderr, "Entry %d, %s, already found on free chain\n",
499 i, EntryName(&entry));
500 fprintf(stderr, "Skipping rest of free chain\n");
504 entrys[i] |= 0x20; /* On free chain */
508 if (verbose) printf("Found %d free entries\n", count);
510 /* Follow the oldkey blocks */
512 for (index = header.kvnoPtr; index; index=entry.next) {
513 readDB (index, &entry, sizeof(entry));
515 /* Is it on another chain or circular free chain */
516 i = (index - header.headerSize)/sizeof(entry);
517 if (entrys[i] & 0x40) {
518 fprintf(stderr, "Entry %d, %s, already found on olkeys chain\n",
519 i, EntryName(&entry));
520 fprintf(stderr, "Skipping rest of oldkeys chain\n");
524 entrys[i] |= 0x40; /* On free chain */
528 if (verbose) printf("Found %d oldkey blocks\n", count);
530 /* Now recheck all the blocks and see if they are allocated correctly
531 * 0x1 --> User Entry 0x10 --> On hash chain
532 * 0x2 --> Free Entry 0x20 --> On Free chain
533 * 0x4 --> OldKeys Entry 0x40 --> On Oldkeys chain
536 for (i=0; i<nentries; i++) {
538 if (j & 0x1) { /* user entry */
539 if (!(j & 0x10)) badEntry(j, i); /* on hash chain? */
540 else if (j & 0xee) badEntry(j, i); /* anything else? */
542 else if (j & 0x2) { /* free entry */
543 if (!(j & 0x20)) badEntry(j, i); /* on free chain? */
544 else if (j & 0xdd) badEntry(j, i); /* anything else? */
546 else if (j & 0x4) { /* oldkeys entry */
547 if (!(j & 0x40)) badEntry(j, i); /* on oldkeys chain? */
548 else if (j & 0xbb) badEntry(j, i); /* anything else? */
550 else if (j & 0x8) { /* past eof */
551 if (j & 0xf7) badEntry(j, i); /* anything else? */
553 else badEntry(j, i); /* anything else? */
563 struct kaentry entry;
565 offset = i * sizeof(struct kaentry) + sizeof(struct kaheader);
566 readDB (offset, &entry, sizeof(entry));
568 fprintf(stderr, "Entry %d, %s, hash index %d, is bad: [",
569 i, EntryName(&entry), NameHash(&entry));
570 if ( e & 0x1) fprintf(stderr, " UserEntry");
571 if ( e & 0x2) fprintf(stderr, " FreeEntry");
572 if ( e & 0x4) fprintf(stderr, " OldkeysEntry");
573 if ( e & 0x8) fprintf(stderr, " PastEOF");
574 if (!(e & 0xf)) fprintf(stderr, " <NULL>");
575 fprintf(stderr, " ] [");
576 if ( e & 0x10) fprintf(stderr, " UserChain");
577 if ( e & 0x20) fprintf(stderr, " FreeChain");
578 if ( e & 0x40) fprintf(stderr, " OldkeysChain");
579 if (!(e & 0xf0)) fprintf(stderr, " <NULL>");
580 fprintf(stderr, " ]\n");
587 struct cmd_syndesc *ts;
592 ts=cmd_CreateSyntax((char *)0, WorkerBee, (char *) 0, "KADB check");
593 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "kadb_file");
594 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL, "Display UBIK header");
595 cmd_AddParm(ts, "-kheader", CMD_FLAG, CMD_OPTIONAL, "Display KADB header");
596 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
597 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
598 cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL, "out_file");
600 return cmd_Dispatch(argc, argv);