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>
14 #include <sys/types.h>
22 #include <netinet/in.h>
31 #include <des_prototypes.h>
34 #include <afs/com_err.h>
40 #define UBIK_HEADERSIZE 64
41 #define UBIK_BUFFERSIZE 1024
43 char *whoami
= "kadb_check";
47 void badEntry(afs_int32
, afs_int32
);
49 int listuheader
, listkheader
, listentries
, verbose
;
55 struct ubik_hdr uheader
;
57 offset
= lseek(fd
, 0, 0);
59 printf("error: lseek to 0 failed: %d %d\n", offset
, errno
);
63 /* now read the info */
64 r
= read(fd
, &uheader
, sizeof(uheader
));
65 if (r
!= sizeof(uheader
)) {
66 printf("error: read of %" AFS_SIZET_FMT
" bytes failed: %d %d\n", sizeof(uheader
), r
,
71 uheader
.magic
= ntohl(uheader
.magic
);
72 uheader
.size
= ntohs(uheader
.size
);
73 uheader
.version
.epoch
= ntohl(uheader
.version
.epoch
);
74 uheader
.version
.counter
= ntohl(uheader
.version
.counter
);
77 printf("Ubik Header\n");
78 printf(" Magic = 0x%x\n", uheader
.magic
);
79 printf(" Size = %u\n", uheader
.size
);
80 printf(" Version.epoch = %u\n", uheader
.version
.epoch
);
81 printf(" Version.counter = %u\n", uheader
.version
.counter
);
84 if (uheader
.size
!= UBIK_HEADERSIZE
)
85 printf("Ubik header size is %u (should be %u)\n", uheader
.size
,
87 if (uheader
.magic
!= UBIK_MAGIC
)
88 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader
.magic
,
95 PrintHeader(struct kaheader
*header
)
97 printf("Version = %d\n", header
->version
);
98 printf("HeaderSize = %d\n", header
->headerSize
);
99 printf("Free Ptr = %u\n", header
->freePtr
);
100 printf("EOF Ptr = %u\n", header
->eofPtr
);
101 printf("Kvno Ptr = %u\n", header
->kvnoPtr
);
102 printf("SpecialKeysVersion changed = %d\n", header
->specialKeysVersion
);
103 printf("# admin accounts = %d\n", header
->admin_accounts
);
104 printf("HashSize = %d\n", header
->hashsize
);
105 printf("Check Version = %d\n", header
->checkVersion
);
106 printf("stats.minorVersion = %d\n", header
->stats
.minor_version
);
107 printf("stats.AllocBlock calls = %d\n", header
->stats
.allocs
);
108 printf("stats.FreeBlock calls = %d\n", header
->stats
.frees
);
109 printf("stats.cpw commands = %d\n", header
->stats
.cpws
);
113 PrintEntry(afs_int32 index
, struct kaentry
*entry
)
119 time_t modification_time
= entry
->modification_time
;
120 time_t change_password_time
= entry
->change_password_time
;
121 time_t max_ticket_lifetime
= entry
->max_ticket_lifetime
;
125 i
= (index
- sizeof(struct kaheader
)) / sizeof(struct kaentry
);
127 printf("Entry %5d (%u):\n", i
, index
);
129 if (entry
->flags
& KAFNORMAL
) {
130 printf(" Name = %s", entry
->userID
.name
);
131 if (strlen(entry
->userID
.instance
) > 0) {
132 printf(".%s", entry
->userID
.instance
);
138 if (entry
->flags
& KAFNORMAL
)
140 if (entry
->flags
& KAFADMIN
)
142 if (entry
->flags
& KAFNOTGS
)
144 if (entry
->flags
& KAFNOSEAL
)
146 if (entry
->flags
& KAFNOCPW
)
149 if (entry
->flags
& KAFNEWASSOC
)
151 if (entry
->flags
& KAFFREE
)
153 if (entry
->flags
& KAFOLDKEYS
)
155 if (entry
->flags
& KAFSPECIAL
)
157 if (entry
->flags
& KAFASSOCROOT
)
158 printf("ROOT-ASSOC ");
159 if (entry
->flags
& KAFASSOC
)
163 printf(" Next = %u\n", entry
->next
);
165 if (entry
->flags
& KAFFREE
)
167 if (entry
->flags
& KAFOLDKEYS
)
170 tt
= entry
->user_expiration
;
171 tm_p
= localtime(&tt
);
173 strftime(Time
, 100, "%m/%d/%Y %H:%M", tm_p
);
175 printf(" User Expiration = %s\n",
176 (entry
->user_expiration
== 0xffffffff) ? "never" : Time
);
178 printf(" Password Expiration = %u days %s\n",
179 entry
->misc_auth_bytes
[EXPIRES
],
180 (entry
->misc_auth_bytes
[EXPIRES
] ? "" : "(never)"));
182 printf(" Password Attempts before lock = ");
183 if (!entry
->misc_auth_bytes
[ATTEMPTS
])
184 printf("unlimited\n");
186 printf("%d\n", entry
->misc_auth_bytes
[ATTEMPTS
]);
188 printf(" Password lockout time = ");
189 if (!entry
->misc_auth_bytes
[LOCKTIME
])
190 printf("unlimited\n");
192 printf("%.1f min\n", (entry
->misc_auth_bytes
[LOCKTIME
] * 8.5));
194 printf(" Is entry locked = %s\n",
195 (entry
->misc_auth_bytes
[REUSEFLAGS
] ==
196 KA_ISLOCKED
) ? "yes" : "no");
198 printf(" Permit password reuse = %s\n",
199 (!entry
->pwsums
[0] && !entry
->pwsums
[1]) ? "yes" : "no");
201 printf(" Mod Time = %u: %s", entry
->modification_time
,
202 ctime(&modification_time
));
203 printf(" Mod ID = %u\n", entry
->modification_id
);
204 printf(" Change Password Time = %u: %s", entry
->change_password_time
,
205 ctime(&change_password_time
));
206 printf(" Ticket lifetime = %u: %s", entry
->max_ticket_lifetime
,
207 ctime(&max_ticket_lifetime
));
208 printf(" Key Version = %d\n", entry
->key_version
);
211 ka_PrintBytes((char *)&entry
->key
, sizeof(entry
->key
));
214 /* What about asServer structs and such and misc_ath_bytes */
217 /* ntohEntry - convert back to host-order */
219 ntohEntry(struct kaentry
*entryp
)
221 entryp
->flags
= ntohl(entryp
->flags
);
222 entryp
->next
= ntohl(entryp
->next
);
223 entryp
->user_expiration
= ntohl(entryp
->user_expiration
);
224 entryp
->modification_time
= ntohl(entryp
->modification_time
);
225 entryp
->modification_id
= ntohl(entryp
->modification_id
);
226 entryp
->change_password_time
= ntohl(entryp
->change_password_time
);
227 entryp
->max_ticket_lifetime
= ntohl(entryp
->max_ticket_lifetime
);
228 entryp
->key_version
= ntohl(entryp
->key_version
);
229 entryp
->misc
.asServer
.nOldKeys
= ntohl(entryp
->misc
.asServer
.nOldKeys
);
230 entryp
->misc
.asServer
.oldKeys
= ntohl(entryp
->misc
.asServer
.oldKeys
);
235 EntryName(struct kaentry
*entryp
)
237 char name
[32], inst
[32];
239 ka_ConvertBytes(name
, sizeof(name
), entryp
->userID
.name
,
240 strlen(entryp
->userID
.name
));
241 ka_ConvertBytes(inst
, sizeof(inst
), entryp
->userID
.instance
,
242 strlen(entryp
->userID
.instance
));
244 if (strlen(entryp
->userID
.instance
)) {
245 sprintf(principal
, "%s.%s", name
, inst
);
247 strcpy(principal
, name
);
254 RebuildEntry(struct kaentry
*entryp
)
260 /* Special entries are not rebuilt */
261 if (entryp
->flags
& KAFSPECIAL
)
264 fprintf(out
, "create -name %s", EntryName(entryp
));
266 ka_ConvertBytes(key
, sizeof(key
), (char *)&entryp
->key
,
267 sizeof(entryp
->key
));
268 fprintf(out
, " -initial_password foo\n");
271 if (entryp
->flags
& KAFADMIN
)
272 strcat(flags
, "+ADMIN");
273 if (entryp
->flags
& KAFNOTGS
)
274 strcat(flags
, "+NOTGS");
275 if (entryp
->flags
& KAFNOSEAL
)
276 strcat(flags
, "+NOSEAL");
277 if (entryp
->flags
& KAFNOCPW
)
278 strcat(flags
, "+NOCPW");
280 fprintf(out
, "setfields -name %s", principal
);
281 if (strcmp(flags
, "") != 0)
282 fprintf(out
, " -flags %s", &flags
[1]);
283 if (entryp
->user_expiration
!= 0xffffffff) {
284 time_t tt
= entryp
->user_expiration
;
285 strftime(Time
, 50, "%m/%d/%Y %H:%M",localtime(&tt
));
286 fprintf(out
, " -expiration '%s'", Time
);
288 fprintf(out
, " -lifetime %u", entryp
->max_ticket_lifetime
);
289 if (entryp
->misc_auth_bytes
[EXPIRES
])
290 fprintf(out
, " -pwexpires %u", entryp
->misc_auth_bytes
[EXPIRES
]);
291 if (entryp
->pwsums
[0] || entryp
->pwsums
[1])
292 fprintf(out
, " -reuse no");
293 if (entryp
->misc_auth_bytes
[ATTEMPTS
])
294 fprintf(out
, " -attempts %u", entryp
->misc_auth_bytes
[ATTEMPTS
]);
295 if (entryp
->misc_auth_bytes
[LOCKTIME
])
296 fprintf(out
, " -locktime %d",
297 (int)(entryp
->misc_auth_bytes
[LOCKTIME
] * 8.5));
300 fprintf(out
, "setkey -name %s -new_key %s -kvno %d\n", principal
, key
,
301 ntohl(entryp
->key_version
));
305 CheckHeader(struct kaheader
*header
)
307 afs_int32 i
, code
= 0;
309 header
->version
= ntohl(header
->version
);
310 header
->headerSize
= ntohl(header
->headerSize
);
311 header
->freePtr
= ntohl(header
->freePtr
);
312 header
->eofPtr
= ntohl(header
->eofPtr
);
313 header
->kvnoPtr
= ntohl(header
->kvnoPtr
);
314 header
->stats
.minor_version
= ntohl(header
->stats
.minor_version
);
315 header
->stats
.allocs
= ntohl(header
->stats
.allocs
);
316 header
->stats
.frees
= ntohl(header
->stats
.frees
);
317 header
->stats
.cpws
= ntohl(header
->stats
.cpws
);
318 header
->admin_accounts
= ntohl(header
->admin_accounts
);
319 header
->specialKeysVersion
= ntohl(header
->specialKeysVersion
);
320 header
->hashsize
= ntohl(header
->hashsize
);
321 for (i
= 0; i
< HASHSIZE
; i
++) {
322 header
->nameHash
[i
] = ntohl(header
->nameHash
[i
]);
324 header
->checkVersion
= ntohl(header
->checkVersion
);
326 if (header
->version
!= header
->checkVersion
) {
328 fprintf(stderr
, "HEADER VERSION MISMATCH: initial %d, final %d\n",
329 header
->version
, header
->checkVersion
);
331 if (header
->headerSize
!= sizeof(struct kaheader
)) {
334 "HEADER SIZE WRONG: file indicates %d, should be %" AFS_SIZET_FMT
"\n",
335 header
->headerSize
, sizeof(struct kaheader
));
337 if (header
->hashsize
!= HASHSIZE
) {
339 fprintf(stderr
, "HASH SIZE WRONG: file indicates %d, should be %d\n",
340 header
->hashsize
, HASHSIZE
);
342 if ((header
->kvnoPtr
&& ((header
->kvnoPtr
< header
->headerSize
)
343 || (header
->eofPtr
< header
->freePtr
)))
344 || (header
->freePtr
&& ((header
->freePtr
< header
->headerSize
)
345 || (header
->eofPtr
< header
->kvnoPtr
)))) {
348 "DATABASE POINTERS BAD: header size = %d, freePtr = %d, kvnoPtr = %d, eofPtr = %d\n",
349 header
->headerSize
, header
->freePtr
, header
->kvnoPtr
,
354 * fprintf(stderr, "DB Version %d, %d possible entries\n", header->version,
355 * (header->eofPtr-header->headerSize) / sizeof(struct kaentry));
361 NameHash(struct kaentry
*entryp
)
365 char *aname
= entryp
->userID
.name
;
366 char *ainstance
= entryp
->userID
.instance
;
368 /* stolen directly from the HashString function in the vol package */
370 for (i
= strlen(aname
), aname
+= i
- 1; i
--; aname
--)
371 hash
= (hash
* 31) + (*((unsigned char *)aname
) - 31);
372 for (i
= strlen(ainstance
), ainstance
+= i
- 1; i
--; ainstance
--)
373 hash
= (hash
* 31) + (*((unsigned char *)ainstance
) - 31);
374 return (hash
% HASHSIZE
);
378 readDB(afs_int32 offset
, void *buffer
, afs_int32 size
)
382 offset
+= UBIK_HEADERSIZE
;
383 code
= lseek(fd
, offset
, SEEK_SET
);
384 if (code
!= offset
) {
385 afs_com_err(whoami
, errno
, "skipping Ubik header");
388 code
= read(fd
, buffer
, size
);
390 afs_com_err(whoami
, errno
, "reading db got %d bytes", code
);
396 #include "AFS_component_version_number.c"
399 WorkerBee(struct cmd_syndesc
*as
, void *arock
)
406 struct kaheader header
;
407 int nentries
, i
, j
, count
;
409 struct kaentry entry
;
411 dbFile
= as
->parms
[0].items
->data
; /* -database */
412 listuheader
= (as
->parms
[1].items
? 1 : 0); /* -uheader */
413 listkheader
= (as
->parms
[2].items
? 1 : 0); /* -kheader */
414 listentries
= (as
->parms
[3].items
? 1 : 0); /* -entries */
415 verbose
= (as
->parms
[4].items
? 1 : 0); /* -verbose */
416 outFile
= (as
->parms
[5].items
? as
->parms
[5].items
->data
: NULL
); /* -rebuild */
419 out
= fopen(outFile
, "w");
421 afs_com_err(whoami
, errno
, "opening output file %s", outFile
);
427 fd
= open(dbFile
, O_RDONLY
, 0);
429 afs_com_err(whoami
, errno
, "opening database file %s", dbFile
);
432 code
= fstat(fd
, &info
);
434 afs_com_err(whoami
, errno
, "stat'ing file %s", dbFile
);
437 if ((info
.st_size
- UBIK_HEADERSIZE
) % UBIK_BUFFERSIZE
)
439 "DATABASE SIZE INCONSISTENT: was %d, should be (n*%d + %d), for integral n\n",
440 (int) info
.st_size
, UBIK_BUFFERSIZE
, UBIK_HEADERSIZE
);
444 readDB(0, &header
, sizeof(header
));
445 code
= CheckHeader(&header
);
447 PrintHeader(&header
);
451 (UBIK_HEADERSIZE
+ header
.headerSize
)) / sizeof(struct kaentry
);
452 entrys
= (int *)malloc(nentries
* sizeof(int));
453 memset(entrys
, 0, nentries
* sizeof(int));
455 for (i
= 0, index
= sizeof(header
); i
< nentries
;
456 i
++, index
+= sizeof(struct kaentry
)) {
457 readDB(index
, &entry
, sizeof(entry
));
459 if (index
>= header
.eofPtr
) {
461 } else if (listentries
) {
462 PrintEntry(index
, &entry
);
465 if (entry
.flags
& KAFNORMAL
) {
466 entrys
[i
] |= 0x1; /* user entry */
468 if (strlen(entry
.userID
.name
) == 0) {
470 printf("Entry %d has zero length name\n", i
);
473 if (!des_check_key_parity(ktc_to_cblock(&entry
.key
))
474 || des_is_weak_key(ktc_to_cblock(&entry
.key
))) {
475 fprintf(stderr
, "Entry %d, %s, has bad key\n", i
,
481 RebuildEntry(&entry
);
484 } else if (entry
.flags
& KAFFREE
) {
485 entrys
[i
] |= 0x2; /* free entry */
487 } else if (entry
.flags
& KAFOLDKEYS
) {
488 entrys
[i
] |= 0x4; /* old keys block */
489 /* Should check the structure of the oldkeys block? */
492 if (index
< header
.eofPtr
) {
493 fprintf(stderr
, "Entry %d is unrecognizable\n", i
);
498 /* Follow the hash chains */
499 for (j
= 0; j
< HASHSIZE
; j
++) {
500 for (index
= header
.nameHash
[j
]; index
; index
= entry
.next
) {
501 readDB(index
, &entry
, sizeof(entry
));
503 /* check to see if the name is hashed correctly */
504 i
= NameHash(&entry
);
507 "Entry %" AFS_SIZET_FMT
", %s, found in hash chain %d (should be %d)\n",
509 sizeof(struct kaheader
)) / sizeof(struct kaentry
)),
510 EntryName(&entry
), j
, i
);
513 /* Is it on another hash chain or circular hash chain */
514 i
= (index
- header
.headerSize
) / sizeof(entry
);
515 if (entrys
[i
] & 0x10) {
517 "Entry %d, %s, hash index %d, was found on another hash chain\n",
518 i
, EntryName(&entry
), j
);
520 fprintf(stderr
, "Skipping rest of hash chain %d\n", j
);
522 fprintf(stderr
, "No next entry in hash chain %d\n", j
);
526 entrys
[i
] |= 0x10; /* On hash chain */
530 /* Follow the free pointers */
532 for (index
= header
.freePtr
; index
; index
= entry
.next
) {
533 readDB(index
, &entry
, sizeof(entry
));
535 /* Is it on another chain or circular free chain */
536 i
= (index
- header
.headerSize
) / sizeof(entry
);
537 if (entrys
[i
] & 0x20) {
538 fprintf(stderr
, "Entry %d, %s, already found on free chain\n", i
,
540 fprintf(stderr
, "Skipping rest of free chain\n");
544 entrys
[i
] |= 0x20; /* On free chain */
549 printf("Found %d free entries\n", count
);
551 /* Follow the oldkey blocks */
553 for (index
= header
.kvnoPtr
; index
; index
= entry
.next
) {
554 readDB(index
, &entry
, sizeof(entry
));
556 /* Is it on another chain or circular free chain */
557 i
= (index
- header
.headerSize
) / sizeof(entry
);
558 if (entrys
[i
] & 0x40) {
559 fprintf(stderr
, "Entry %d, %s, already found on olkeys chain\n",
560 i
, EntryName(&entry
));
561 fprintf(stderr
, "Skipping rest of oldkeys chain\n");
565 entrys
[i
] |= 0x40; /* On free chain */
570 printf("Found %d oldkey blocks\n", count
);
572 /* Now recheck all the blocks and see if they are allocated correctly
573 * 0x1 --> User Entry 0x10 --> On hash chain
574 * 0x2 --> Free Entry 0x20 --> On Free chain
575 * 0x4 --> OldKeys Entry 0x40 --> On Oldkeys chain
578 for (i
= 0; i
< nentries
; i
++) {
580 if (j
& 0x1) { /* user entry */
582 badEntry(j
, i
); /* on hash chain? */
584 badEntry(j
, i
); /* anything else? */
585 } else if (j
& 0x2) { /* free entry */
587 badEntry(j
, i
); /* on free chain? */
589 badEntry(j
, i
); /* anything else? */
590 } else if (j
& 0x4) { /* oldkeys entry */
592 badEntry(j
, i
); /* on oldkeys chain? */
594 badEntry(j
, i
); /* anything else? */
595 } else if (j
& 0x8) { /* past eof */
597 badEntry(j
, i
); /* anything else? */
599 badEntry(j
, i
); /* anything else? */
606 badEntry(afs_int32 e
, afs_int32 i
)
609 struct kaentry entry
;
611 offset
= i
* sizeof(struct kaentry
) + sizeof(struct kaheader
);
612 readDB(offset
, &entry
, sizeof(entry
));
614 fprintf(stderr
, "Entry %d, %s, hash index %d, is bad: [", i
,
615 EntryName(&entry
), NameHash(&entry
));
617 fprintf(stderr
, " UserEntry");
619 fprintf(stderr
, " FreeEntry");
621 fprintf(stderr
, " OldkeysEntry");
623 fprintf(stderr
, " PastEOF");
625 fprintf(stderr
, " <NULL>");
626 fprintf(stderr
, " ] [");
628 fprintf(stderr
, " UserChain");
630 fprintf(stderr
, " FreeChain");
632 fprintf(stderr
, " OldkeysChain");
634 fprintf(stderr
, " <NULL>");
635 fprintf(stderr
, " ]\n");
639 main(int argc
, char **argv
)
641 struct cmd_syndesc
*ts
;
645 ts
= cmd_CreateSyntax(NULL
, WorkerBee
, NULL
, "KADB check");
646 cmd_AddParm(ts
, "-database", CMD_SINGLE
, CMD_REQUIRED
, "kadb_file");
647 cmd_AddParm(ts
, "-uheader", CMD_FLAG
, CMD_OPTIONAL
,
648 "Display UBIK header");
649 cmd_AddParm(ts
, "-kheader", CMD_FLAG
, CMD_OPTIONAL
,
650 "Display KADB header");
651 cmd_AddParm(ts
, "-entries", CMD_FLAG
, CMD_OPTIONAL
, "Display entries");
652 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, "verbose");
653 cmd_AddParm(ts
, "-rebuild", CMD_SINGLE
, CMD_OPTIONAL
, "out_file");
655 return cmd_Dispatch(argc
, argv
);