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 <afs/param.h>
11 #include <sys/types.h>
19 #include <netinet/in.h>
27 #include <afs/com_err.h>
33 #define UBIK_HEADERSIZE 64
34 #define UBIK_BUFFERSIZE 1024
36 char *whoami = "kadb_check";
40 int listuheader, listkheader, listentries, verbose;
45 struct ubik_hdr uheader;
47 offset = lseek(fd, 0, 0);
49 printf("error: lseek to 0 failed: %d %d\n", offset, errno);
53 /* now read the info */
54 r = read(fd, &uheader, sizeof(uheader));
55 if (r != sizeof(uheader)) {
56 printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r, errno);
60 uheader.magic = ntohl(uheader.magic);
61 uheader.size = ntohl(uheader.size);
62 uheader.version.epoch = ntohl(uheader.version.epoch);
63 uheader.version.counter = ntohl(uheader.version.counter);
66 printf("Ubik Header\n");
67 printf(" Magic = 0x%x\n", uheader.magic);
68 printf(" Size = %u\n", uheader.size);
69 printf(" Version.epoch = %u\n", uheader.version.epoch);
70 printf(" Version.counter = %u\n", uheader.version.counter);
73 if (uheader.size != UBIK_HEADERSIZE)
74 printf("Ubik header size is %u (should be %u)\n", uheader.size, UBIK_HEADERSIZE);
75 if (uheader.magic != UBIK_MAGIC)
76 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic, UBIK_MAGIC);
82 struct kaheader *header;
84 printf("Version = %d\n", header->version);
85 printf("HeaderSize = %d\n", header->headerSize);
86 printf("Free Ptr = %u\n", header->freePtr);
87 printf("EOF Ptr = %u\n", header->eofPtr);
88 printf("Kvno Ptr = %u\n", header->kvnoPtr);
89 printf("SpecialKeysVersion changed = %d\n", header->specialKeysVersion);
90 printf("# admin accounts = %d\n", header->admin_accounts);
91 printf("HashSize = %d\n", header->hashsize);
92 printf("Check Version = %d\n", header->checkVersion);
93 printf("stats.minorVersion = %d\n", header->stats.minor_version);
94 printf("stats.AllocBlock calls = %d\n", header->stats.allocs);
95 printf("stats.FreeBlock calls = %d\n", header->stats.frees);
96 printf("stats.cpw commands = %d\n", header->stats.cpws);
99 PrintEntry(index, entry)
101 struct kaentry *entry;
109 i = (index - sizeof(struct kaheader))/sizeof(struct kaentry);
111 printf("Entry %5d (%u):\n", i, index);
113 if (entry->flags & KAFNORMAL) {
114 printf (" Name = %s", entry->userID.name);
115 if (strlen(entry->userID.instance) > 0) {
116 printf (".%s", entry->userID.instance);
122 if (entry->flags & KAFNORMAL) printf("NORMAL ");
123 if (entry->flags & KAFADMIN) printf("ADMIN ");
124 if (entry->flags & KAFNOTGS) printf("NOTGS ");
125 if (entry->flags & KAFNOSEAL) printf("NOSEAL ");
126 if (entry->flags & KAFNOCPW) printf("NOCPW ");
128 if (entry->flags & KAFNEWASSOC) printf("CR-ASSOC ");
129 if (entry->flags & KAFFREE) printf("FREE ");
130 if (entry->flags & KAFOLDKEYS) printf("OLDKEYS ");
131 if (entry->flags & KAFSPECIAL) printf("SPECIAL ");
132 if (entry->flags & KAFASSOCROOT) printf("ROOT-ASSOC ");
133 if (entry->flags & KAFASSOC) printf("AN-ASSOC ");
136 printf(" Next = %u\n", entry->next);
138 if (entry->flags & KAFFREE)
140 if (entry->flags & KAFOLDKEYS)
143 tm_p = localtime((time_t *)&entry->user_expiration);
145 strftime(Time, 100, "%m/%d/%Y %H:%M", tm_p);
147 printf(" User Expiration = %s\n",
148 (entry->user_expiration == 0xffffffff) ? "never" : Time);
150 printf(" Password Expiration = %u days %s\n",
151 entry->misc_auth_bytes[EXPIRES],
152 (entry->misc_auth_bytes[EXPIRES]?"":"(never)"));
154 printf(" Password Attempts before lock = ");
155 if (!entry->misc_auth_bytes[ATTEMPTS]) printf("unlimited\n");
156 else printf("%d\n", entry->misc_auth_bytes[ATTEMPTS]);
158 printf(" Password lockout time = ");
159 if (!entry->misc_auth_bytes[LOCKTIME]) printf("unlimited\n");
160 else printf("%.1f min\n", (entry->misc_auth_bytes[LOCKTIME] * 8.5));
162 printf(" Is entry locked = %s\n",
163 (entry->misc_auth_bytes[REUSEFLAGS] == KA_ISLOCKED) ? "yes" : "no");
165 printf(" Permit password reuse = %s\n",
166 (!entry->pwsums[0] && !entry->pwsums[1]) ? "yes" : "no");
168 printf(" Mod Time = %u: %s",
169 entry->modification_time, ctime((time_t *)&entry->modification_time));
170 printf(" Mod ID = %u\n", entry->modification_id);
171 printf(" Change Password Time = %u: %s",
172 entry->change_password_time,
173 ctime((time_t *)&entry->change_password_time));
174 printf(" Ticket lifetime = %u: %s",
175 entry->max_ticket_lifetime, ctime((time_t *)&entry->max_ticket_lifetime));
176 printf(" Key Version = %d\n", entry->key_version);
179 ka_PrintBytes ((char *)&entry->key, sizeof(entry->key));
182 /* What about asServer structs and such and misc_ath_bytes */
185 /* ntohEntry - convert back to host-order */
186 ntohEntry(struct kaentry *entryp)
188 entryp->flags = ntohl(entryp->flags);
189 entryp->next = ntohl(entryp->next);
190 entryp->user_expiration = ntohl(entryp->user_expiration);
191 entryp->modification_time = ntohl(entryp->modification_time);
192 entryp->modification_id = ntohl(entryp->modification_id);
193 entryp->change_password_time = ntohl(entryp->change_password_time);
194 entryp->max_ticket_lifetime = ntohl(entryp->max_ticket_lifetime);
195 entryp->key_version = ntohl(entryp->key_version);
196 entryp->misc.asServer.nOldKeys = ntohl(entryp->misc.asServer.nOldKeys);
197 entryp->misc.asServer.oldKeys = ntohl(entryp->misc.asServer.oldKeys);
201 char *EntryName(entryp)
202 struct kaentry *entryp;
204 char name[32], inst[32];
206 ka_ConvertBytes(name, sizeof(name),
207 entryp->userID.name, strlen(entryp->userID.name));
208 ka_ConvertBytes(inst, sizeof(inst),
209 entryp->userID.instance, strlen(entryp->userID.instance));
211 if (strlen(entryp->userID.instance)) {
212 sprintf (principal, "%s.%s", name, inst);
214 strcpy (principal, name);
221 struct kaentry *entryp;
227 /* Special entries are not rebuilt */
228 if (entryp->flags & KAFSPECIAL) return;
230 fprintf(out, "create -name %s", EntryName(entryp));
232 ka_ConvertBytes (key, sizeof(key), (char *)&entryp->key,
233 sizeof(entryp->key));
234 fprintf(out, " -initial_password foo\n", key);
237 if (entryp->flags & KAFADMIN) strcat(flags, "+ADMIN");
238 if (entryp->flags & KAFNOTGS) strcat(flags, "+NOTGS");
239 if (entryp->flags & KAFNOSEAL) strcat(flags, "+NOSEAL");
240 if (entryp->flags & KAFNOCPW) strcat(flags, "+NOCPW");
242 fprintf(out, "setfields -name %s", principal);
243 if (strcmp(flags,"") != 0)
244 fprintf(out, " -flags %s", &flags[1]);
245 if (entryp->user_expiration != 0xffffffff) {
246 strftime(Time, 50, "%m/%d/%Y %H:%M",
247 localtime((time_t *)&entryp->user_expiration));
248 fprintf(out, " -expiration '%s'", Time);
250 fprintf(out, " -lifetime %u", entryp->max_ticket_lifetime);
251 if (entryp->misc_auth_bytes[EXPIRES])
252 fprintf(out, " -pwexpires %u", entryp->misc_auth_bytes[EXPIRES]);
253 if (entryp->pwsums[0] || entryp->pwsums[1])
254 fprintf(out, " -reuse no");
255 if (entryp->misc_auth_bytes[ATTEMPTS])
256 fprintf(out, " -attempts %u", entryp->misc_auth_bytes[ATTEMPTS]);
257 if (entryp->misc_auth_bytes[LOCKTIME])
258 fprintf(out, " -locktime %d", (int)(entryp->misc_auth_bytes[LOCKTIME]*8.5));
261 fprintf(out, "setkey -name %s -new_key %s -kvno %d\n",
262 principal, key, ntohl(entryp->key_version));
266 struct kaheader *header;
268 afs_int32 i, code = 0;
270 header->version = ntohl(header->version);
271 header->headerSize = ntohl(header->headerSize);
272 header->freePtr = ntohl(header->freePtr);
273 header->eofPtr = ntohl(header->eofPtr);
274 header->kvnoPtr = ntohl(header->kvnoPtr);
275 header->stats.minor_version = ntohl(header->stats.minor_version);
276 header->stats.allocs = ntohl(header->stats.allocs);
277 header->stats.frees = ntohl(header->stats.frees);
278 header->stats.cpws = ntohl(header->stats.cpws);
279 header->admin_accounts = ntohl(header->admin_accounts);
280 header->specialKeysVersion = ntohl(header->specialKeysVersion);
281 header->hashsize = ntohl(header->hashsize);
282 for (i=0; i<HASHSIZE; i++) {
283 header->nameHash[i] = ntohl(header->nameHash[i]);
285 header->checkVersion = ntohl(header->checkVersion);
287 if (header->version != header->checkVersion) {
289 fprintf(stderr, "HEADER VERSION MISMATCH: initial %d, final %d\n",
290 header->version, header->checkVersion);
292 if (header->headerSize != sizeof(struct kaheader)) {
294 fprintf(stderr, "HEADER SIZE WRONG: file indicates %d, should be %d\n",
295 header->headerSize, sizeof(struct kaheader));
297 if (header->hashsize != HASHSIZE) {
299 fprintf(stderr, "HASH SIZE WRONG: file indicates %d, should be %d\n",
300 header->hashsize, HASHSIZE);
302 if ((header->kvnoPtr && ((header->kvnoPtr < header->headerSize) ||
303 (header->eofPtr < header->freePtr))) ||
304 (header->freePtr && ((header->freePtr < header->headerSize) ||
305 (header->eofPtr < header->kvnoPtr)))) {
308 "DATABASE POINTERS BAD: header size = %d, freePtr = %d, kvnoPtr = %d, eofPtr = %d\n",
309 header->headerSize, header->freePtr, header->kvnoPtr,
314 * fprintf(stderr, "DB Version %d, %d possible entries\n", header->version,
315 * (header->eofPtr-header->headerSize) / sizeof(struct kaentry));
320 afs_int32 NameHash(entryp)
321 struct kaentry *entryp;
325 char *aname = entryp->userID.name;
326 char *ainstance = entryp->userID.instance;
328 /* stolen directly from the HashString function in the vol package */
330 for (i=strlen(aname), aname += i-1; i--; aname--)
331 hash = (hash*31) + (*((unsigned char *)aname) - 31);
332 for (i=strlen(ainstance), ainstance += i-1; i--; ainstance--)
333 hash = (hash*31) + (*((unsigned char *)ainstance) - 31);
334 return(hash % HASHSIZE);
337 readDB(offset, buffer, size)
344 offset += UBIK_HEADERSIZE;
345 code = lseek(fd, offset, SEEK_SET);
346 if (code != offset) {
347 com_err (whoami, errno, "skipping Ubik header");
350 code = read(fd, buffer, size);
352 com_err (whoami, errno, "reading db got %d bytes", code);
357 #include "AFS_component_version_number.c"
359 WorkerBee (as, arock)
360 struct cmd_syndesc *as;
369 struct kaheader header;
370 int nentries, i, j, count;
372 struct kaentry entry;
374 dbFile = as->parms[0].items->data; /* -database */
375 listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
376 listkheader = (as->parms[2].items ? 1 : 0); /* -kheader */
377 listentries = (as->parms[3].items ? 1 : 0); /* -entries */
378 verbose = (as->parms[4].items ? 1 : 0); /* -verbose */
379 outFile = (as->parms[5].items ? as->parms[5].items->data :
380 (char *)0); /* -rebuild */
383 out = fopen (outFile, "w");
385 com_err (whoami, errno, "opening output file %s", outFile);
390 fd = open (dbFile, O_RDONLY, 0);
392 com_err (whoami, errno, "opening database file %s", dbFile);
395 code = fstat (fd, &info);
397 com_err (whoami, errno, "stat'ing file %s", dbFile);
400 if ((info.st_size - UBIK_HEADERSIZE) % UBIK_BUFFERSIZE)
402 "DATABASE SIZE INCONSISTENT: was %d, should be (n*%d + %d), for integral n\n",
403 info.st_size, UBIK_BUFFERSIZE, UBIK_HEADERSIZE);
407 readDB(0, &header, sizeof(header));
408 code = CheckHeader(&header);
409 if (listkheader) PrintHeader(&header);
411 nentries = (info.st_size-(UBIK_HEADERSIZE + header.headerSize)) / sizeof(struct kaentry);
412 entrys = (int *)malloc(nentries * sizeof(int));
413 bzero(entrys, nentries * sizeof(int));
415 for (i=0, index=sizeof(header); i<nentries; i++, index+=sizeof(struct kaentry)) {
416 readDB (index, &entry, sizeof(entry));
418 if (index >= header.eofPtr) {
421 else if (listentries) {
422 PrintEntry(index, &entry);
425 if (entry.flags & KAFNORMAL) {
426 entrys[i] |= 0x1; /* user entry */
428 if (strlen(entry.userID.name) == 0) {
429 if (verbose) printf("Entry %d has zero length name\n", i);
432 if (!des_check_key_parity (&entry.key) || des_is_weak_key (&entry.key)) {
433 fprintf(stderr, "Entry %d, %s, has bad key\n", i, EntryName(&entry));
438 RebuildEntry(&entry);
441 } else if (entry.flags & KAFFREE) {
442 entrys[i] |= 0x2; /* free entry */
444 } else if (entry.flags & KAFOLDKEYS) {
445 entrys[i] |= 0x4; /* old keys block */
446 /* Should check the structure of the oldkeys block? */
449 if (index < header.eofPtr) {
450 fprintf(stderr, "Entry %d is unrecognizable\n", i);
455 /* Follow the hash chains */
456 for (j=0; j<HASHSIZE; j++) {
457 for (index = header.nameHash[j]; index; index=entry.next) {
458 readDB (index, &entry, sizeof(entry));
460 /* check to see if the name is hashed correctly */
461 i = NameHash(&entry);
464 "Entry %d, %s, found in hash chain %d (should be %d)\n",
465 ((index - sizeof(struct kaheader))/sizeof(struct kaentry)),
466 EntryName(&entry), j, i);
469 /* Is it on another hash chain or circular hash chain */
470 i = (index - header.headerSize)/sizeof(entry);
471 if (entrys[i] & 0x10) {
473 "Entry %d, %s, hash index %d, was found on another hash chain\n",
474 i, EntryName(&entry), j);
476 fprintf(stderr, "Skipping rest of hash chain %d\n", j);
478 fprintf(stderr, "No next entry in hash chain %d\n", j);
482 entrys[i] |= 0x10; /* On hash chain */
486 /* Follow the free pointers */
488 for (index = header.freePtr; index; index=entry.next) {
489 readDB (index, &entry, sizeof(entry));
491 /* Is it on another chain or circular free chain */
492 i = (index - header.headerSize)/sizeof(entry);
493 if (entrys[i] & 0x20) {
494 fprintf(stderr, "Entry %d, %s, already found on free chain\n",
495 i, EntryName(&entry));
496 fprintf(stderr, "Skipping rest of free chain\n");
500 entrys[i] |= 0x20; /* On free chain */
504 if (verbose) printf("Found %d free entries\n", count);
506 /* Follow the oldkey blocks */
508 for (index = header.kvnoPtr; index; index=entry.next) {
509 readDB (index, &entry, sizeof(entry));
511 /* Is it on another chain or circular free chain */
512 i = (index - header.headerSize)/sizeof(entry);
513 if (entrys[i] & 0x40) {
514 fprintf(stderr, "Entry %d, %s, already found on olkeys chain\n",
515 i, EntryName(&entry));
516 fprintf(stderr, "Skipping rest of oldkeys chain\n");
520 entrys[i] |= 0x40; /* On free chain */
524 if (verbose) printf("Found %d oldkey blocks\n", count);
526 /* Now recheck all the blocks and see if they are allocated correctly
527 * 0x1 --> User Entry 0x10 --> On hash chain
528 * 0x2 --> Free Entry 0x20 --> On Free chain
529 * 0x4 --> OldKeys Entry 0x40 --> On Oldkeys chain
532 for (i=0; i<nentries; i++) {
534 if (j & 0x1) { /* user entry */
535 if (!(j & 0x10)) badEntry(j, i); /* on hash chain? */
536 else if (j & 0xee) badEntry(j, i); /* anything else? */
538 else if (j & 0x2) { /* free entry */
539 if (!(j & 0x20)) badEntry(j, i); /* on free chain? */
540 else if (j & 0xdd) badEntry(j, i); /* anything else? */
542 else if (j & 0x4) { /* oldkeys entry */
543 if (!(j & 0x40)) badEntry(j, i); /* on oldkeys chain? */
544 else if (j & 0xbb) badEntry(j, i); /* anything else? */
546 else if (j & 0x8) { /* past eof */
547 if (j & 0xf7) badEntry(j, i); /* anything else? */
549 else badEntry(j, i); /* anything else? */
559 struct kaentry entry;
561 offset = i * sizeof(struct kaentry) + sizeof(struct kaheader);
562 readDB (offset, &entry, sizeof(entry));
564 fprintf(stderr, "Entry %d, %s, hash index %d, is bad: [",
565 i, EntryName(&entry), NameHash(&entry));
566 if ( e & 0x1) fprintf(stderr, " UserEntry");
567 if ( e & 0x2) fprintf(stderr, " FreeEntry");
568 if ( e & 0x4) fprintf(stderr, " OldkeysEntry");
569 if ( e & 0x8) fprintf(stderr, " PastEOF");
570 if (!(e & 0xf)) fprintf(stderr, " <NULL>");
571 fprintf(stderr, " ] [");
572 if ( e & 0x10) fprintf(stderr, " UserChain");
573 if ( e & 0x20) fprintf(stderr, " FreeChain");
574 if ( e & 0x40) fprintf(stderr, " OldkeysChain");
575 if (!(e & 0xf0)) fprintf(stderr, " <NULL>");
576 fprintf(stderr, " ]\n");
583 struct cmd_syndesc *ts;
588 ts=cmd_CreateSyntax((char *)0, WorkerBee, (char *) 0, "KADB check");
589 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "kadb_file");
590 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL, "Display UBIK header");
591 cmd_AddParm(ts, "-kheader", CMD_FLAG, CMD_OPTIONAL, "Display KADB header");
592 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
593 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
594 cmd_AddParm(ts, "-rebuild", CMD_SINGLE, CMD_OPTIONAL, "out_file");
596 return cmd_Dispatch(argc, argv);