Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / kauth / rebuild.c
blobd6dad28c7a0942aa6b8d07171fbed4889b32e798
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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
8 */
10 #include <afsconfig.h>
11 #include <afs/param.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #ifdef AFS_NT40_ENV
17 #include <winsock2.h>
18 #include <fcntl.h>
19 #include <io.h>
20 #else
21 #include <sys/file.h>
22 #include <netinet/in.h>
23 #endif
24 #include <string.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <time.h>
28 #include <ubik.h>
29 #include <afs/cmd.h>
30 #include <des.h>
31 #include <des_prototypes.h>
32 #include <rx/rxkad.h>
34 #include <afs/com_err.h>
36 #include "kauth.h"
37 #include "kautils.h"
38 #include "kaserver.h"
40 #define UBIK_HEADERSIZE 64
41 #define UBIK_BUFFERSIZE 1024
43 char *whoami = "kadb_check";
44 int fd;
45 FILE *out;
47 void badEntry(afs_int32, afs_int32);
49 int listuheader, listkheader, listentries, verbose;
51 int
52 readUbikHeader(void)
54 int offset, r;
55 struct ubik_hdr uheader;
57 offset = lseek(fd, 0, 0);
58 if (offset != 0) {
59 printf("error: lseek to 0 failed: %d %d\n", offset, errno);
60 return (-1);
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,
67 errno);
68 return (-1);
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);
76 if (listuheader) {
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,
86 UBIK_HEADERSIZE);
87 if (uheader.magic != UBIK_MAGIC)
88 printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic,
89 UBIK_MAGIC);
91 return (0);
94 void
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);
112 void
113 PrintEntry(afs_int32 index, struct kaentry *entry)
115 int i;
116 char Time[100];
117 struct tm *tm_p;
118 time_t tt;
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;
123 printf("\n");
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);
134 printf("\n");
137 printf(" flags = ");
138 if (entry->flags & KAFNORMAL)
139 printf("NORMAL ");
140 if (entry->flags & KAFADMIN)
141 printf("ADMIN ");
142 if (entry->flags & KAFNOTGS)
143 printf("NOTGS ");
144 if (entry->flags & KAFNOSEAL)
145 printf("NOSEAL ");
146 if (entry->flags & KAFNOCPW)
147 printf("NOCPW ");
149 if (entry->flags & KAFNEWASSOC)
150 printf("CR-ASSOC ");
151 if (entry->flags & KAFFREE)
152 printf("FREE ");
153 if (entry->flags & KAFOLDKEYS)
154 printf("OLDKEYS ");
155 if (entry->flags & KAFSPECIAL)
156 printf("SPECIAL ");
157 if (entry->flags & KAFASSOCROOT)
158 printf("ROOT-ASSOC ");
159 if (entry->flags & KAFASSOC)
160 printf("AN-ASSOC ");
161 printf("\n");
163 printf(" Next = %u\n", entry->next);
165 if (entry->flags & KAFFREE)
166 return;
167 if (entry->flags & KAFOLDKEYS)
168 return;
170 tt = entry->user_expiration;
171 tm_p = localtime(&tt);
172 if (tm_p)
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");
185 else
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");
191 else
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);
210 printf(" Key = ");
211 ka_PrintBytes((char *)&entry->key, sizeof(entry->key));
212 printf("\n");
214 /* What about asServer structs and such and misc_ath_bytes */
217 /* ntohEntry - convert back to host-order */
218 void
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);
233 char principal[64];
234 char *
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);
246 } else {
247 strcpy(principal, name);
250 return (principal);
253 void
254 RebuildEntry(struct kaentry *entryp)
256 char key[33];
257 char flags[128];
258 char Time[50];
260 /* Special entries are not rebuilt */
261 if (entryp->flags & KAFSPECIAL)
262 return;
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");
270 strcpy(flags, "");
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));
298 fprintf(out, "\n");
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) {
327 code++;
328 fprintf(stderr, "HEADER VERSION MISMATCH: initial %d, final %d\n",
329 header->version, header->checkVersion);
331 if (header->headerSize != sizeof(struct kaheader)) {
332 code++;
333 fprintf(stderr,
334 "HEADER SIZE WRONG: file indicates %d, should be %" AFS_SIZET_FMT "\n",
335 header->headerSize, sizeof(struct kaheader));
337 if (header->hashsize != HASHSIZE) {
338 code++;
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)))) {
346 code++;
347 fprintf(stderr,
348 "DATABASE POINTERS BAD: header size = %d, freePtr = %d, kvnoPtr = %d, eofPtr = %d\n",
349 header->headerSize, header->freePtr, header->kvnoPtr,
350 header->eofPtr);
354 * fprintf(stderr, "DB Version %d, %d possible entries\n", header->version,
355 * (header->eofPtr-header->headerSize) / sizeof(struct kaentry));
357 return code;
360 afs_int32
361 NameHash(struct kaentry *entryp)
363 unsigned int hash;
364 int i;
365 char *aname = entryp->userID.name;
366 char *ainstance = entryp->userID.instance;
368 /* stolen directly from the HashString function in the vol package */
369 hash = 0;
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)
380 afs_int32 code;
382 offset += UBIK_HEADERSIZE;
383 code = lseek(fd, offset, SEEK_SET);
384 if (code != offset) {
385 afs_com_err(whoami, errno, "skipping Ubik header");
386 exit(2);
388 code = read(fd, buffer, size);
389 if (code != size) {
390 afs_com_err(whoami, errno, "reading db got %d bytes", code);
391 exit(3);
393 return 0;
396 #include "AFS_component_version_number.c"
398 static int
399 WorkerBee(struct cmd_syndesc *as, void *arock)
401 afs_int32 code;
402 char *dbFile;
403 char *outFile;
404 afs_int32 index;
405 struct stat info;
406 struct kaheader header;
407 int nentries, i, j, count;
408 int *entrys;
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 */
418 if (outFile) {
419 out = fopen(outFile, "w");
420 if (!out) {
421 afs_com_err(whoami, errno, "opening output file %s", outFile);
422 exit(7);
424 } else
425 out = 0;
427 fd = open(dbFile, O_RDONLY, 0);
428 if (fd < 0) {
429 afs_com_err(whoami, errno, "opening database file %s", dbFile);
430 exit(6);
432 code = fstat(fd, &info);
433 if (code) {
434 afs_com_err(whoami, errno, "stat'ing file %s", dbFile);
435 exit(6);
437 if ((info.st_size - UBIK_HEADERSIZE) % UBIK_BUFFERSIZE)
438 fprintf(stderr,
439 "DATABASE SIZE INCONSISTENT: was %d, should be (n*%d + %d), for integral n\n",
440 (int) info.st_size, UBIK_BUFFERSIZE, UBIK_HEADERSIZE);
442 readUbikHeader();
444 readDB(0, &header, sizeof(header));
445 code = CheckHeader(&header);
446 if (listkheader)
447 PrintHeader(&header);
449 nentries =
450 (info.st_size -
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) {
460 entrys[i] |= 0x8;
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) {
469 if (verbose)
470 printf("Entry %d has zero length name\n", i);
471 continue;
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,
476 EntryName(&entry));
477 continue;
480 if (out) {
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? */
491 } else {
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);
505 if (i != j) {
506 fprintf(stderr,
507 "Entry %" AFS_SIZET_FMT ", %s, found in hash chain %d (should be %d)\n",
508 ((index -
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) {
516 fprintf(stderr,
517 "Entry %d, %s, hash index %d, was found on another hash chain\n",
518 i, EntryName(&entry), j);
519 if (entry.next)
520 fprintf(stderr, "Skipping rest of hash chain %d\n", j);
521 else
522 fprintf(stderr, "No next entry in hash chain %d\n", j);
523 code++;
524 break;
526 entrys[i] |= 0x10; /* On hash chain */
530 /* Follow the free pointers */
531 count = 0;
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,
539 EntryName(&entry));
540 fprintf(stderr, "Skipping rest of free chain\n");
541 code++;
542 break;
544 entrys[i] |= 0x20; /* On free chain */
546 count++;
548 if (verbose)
549 printf("Found %d free entries\n", count);
551 /* Follow the oldkey blocks */
552 count = 0;
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");
562 code++;
563 break;
565 entrys[i] |= 0x40; /* On free chain */
567 count++;
569 if (verbose)
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
576 * 0x8 --> Past EOF
578 for (i = 0; i < nentries; i++) {
579 j = entrys[i];
580 if (j & 0x1) { /* user entry */
581 if (!(j & 0x10))
582 badEntry(j, i); /* on hash chain? */
583 else if (j & 0xee)
584 badEntry(j, i); /* anything else? */
585 } else if (j & 0x2) { /* free entry */
586 if (!(j & 0x20))
587 badEntry(j, i); /* on free chain? */
588 else if (j & 0xdd)
589 badEntry(j, i); /* anything else? */
590 } else if (j & 0x4) { /* oldkeys entry */
591 if (!(j & 0x40))
592 badEntry(j, i); /* on oldkeys chain? */
593 else if (j & 0xbb)
594 badEntry(j, i); /* anything else? */
595 } else if (j & 0x8) { /* past eof */
596 if (j & 0xf7)
597 badEntry(j, i); /* anything else? */
598 } else
599 badEntry(j, i); /* anything else? */
602 exit(code != 0);
605 void
606 badEntry(afs_int32 e, afs_int32 i)
608 int offset;
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));
616 if (e & 0x1)
617 fprintf(stderr, " UserEntry");
618 if (e & 0x2)
619 fprintf(stderr, " FreeEntry");
620 if (e & 0x4)
621 fprintf(stderr, " OldkeysEntry");
622 if (e & 0x8)
623 fprintf(stderr, " PastEOF");
624 if (!(e & 0xf))
625 fprintf(stderr, " <NULL>");
626 fprintf(stderr, " ] [");
627 if (e & 0x10)
628 fprintf(stderr, " UserChain");
629 if (e & 0x20)
630 fprintf(stderr, " FreeChain");
631 if (e & 0x40)
632 fprintf(stderr, " OldkeysChain");
633 if (!(e & 0xf0))
634 fprintf(stderr, " <NULL>");
635 fprintf(stderr, " ]\n");
639 main(int argc, char **argv)
641 struct cmd_syndesc *ts;
643 setlinebuf(stdout);
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);