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>
16 #include <sys/types.h>
20 #include <netinet/in.h>
33 #include <afs/afsutil.h>
38 extern struct kaheader cheader;
39 extern Date cheaderReadTime; /* time cheader last read in */
40 extern struct ubik_dbase *KA_dbase;
42 #define set_header_word(tt,field,value) kawrite ((tt), ((char *)&(cheader.field) - (char *)&cheader), ((cheader.field = (value)), (char *)&(cheader.field)), sizeof(afs_int32))
44 #define inc_header_word(tt,field) kawrite ((tt), ((char *)&(cheader.field) - (char *)&cheader), ((cheader.field = (htonl(ntohl(cheader.field)+1))), (char *)&(cheader.field)), sizeof(afs_int32))
46 static int index_OK();
49 NameHash(aname, ainstance)
51 register char *ainstance;
53 register unsigned int hash;
56 /* stolen directly from the HashString function in the vol package */
58 for (i = strlen(aname), aname += i - 1; i--; aname--)
59 hash = (hash * 31) + (*((unsigned char *)aname) - 31);
60 for (i = strlen(ainstance), ainstance += i - 1; i--; ainstance--)
61 hash = (hash * 31) + (*((unsigned char *)ainstance) - 31);
62 return (hash % HASHSIZE);
65 /* package up seek and write into one procedure for ease of use */
68 kawrite(tt, pos, buff, len)
69 struct ubik_trans *tt;
76 code = ubik_Seek(tt, 0, pos);
79 code = ubik_Write(tt, buff, len);
83 /* same thing for read */
86 karead(tt, pos, buff, len)
87 struct ubik_trans *tt;
94 code = ubik_Seek(tt, 0, pos);
97 code = ubik_Read(tt, buff, len);
101 static struct Lock cheader_lock;
102 static struct Lock keycache_lock;
104 static int maxCachedKeys;
106 static struct cachedKey {
108 int superseded; /* NEVERDATE => this is current key */
110 struct ktc_encryptionKey key;
111 char name[MAXKTCNAMELEN];
112 char inst[MAXKTCNAMELEN];
114 static afs_int32 keyCacheVersion = 0;
116 static afs_int32 maxKeyLifetime;
117 static int dbfixup = 0;
119 init_kadatabase(initFlags)
120 int initFlags; /* same as init_kaprocs (see which) */
122 Lock_Init(&cheader_lock);
123 Lock_Init(&keycache_lock);
127 (struct cachedKey *)malloc(maxCachedKeys * sizeof(struct cachedKey));
132 maxKeyLifetime = MAXKTCTICKETLIFETIME;
138 /* check that the database has been initialized. Be careful to fail in a safe
139 manner, to avoid bogusly reinitializing the db. */
142 CheckInit(at, db_init)
143 struct ubik_trans *at;
144 int (*db_init) (); /* procedure to call if rebuilding DB */
146 register afs_int32 code;
150 /* Don't read header if not necessary */
151 if (!ubik_CacheUpdate(at))
154 ObtainWriteLock(&cheader_lock);
155 if ((code = karead(at, 0, (char *)&iversion, sizeof(iversion)))
157 karead(at, sizeof(cheader) - sizeof(afs_int32), (char *)&tversion,
158 sizeof(afs_int32)))) {
160 printf("No data base\n");
162 printf("I/O Error\n");
164 iversion = ntohl(iversion); /* convert to host order */
165 tversion = ntohl(tversion);
166 if ((iversion == KADBVERSION) && (tversion == KADBVERSION)) {
167 code = karead(at, 0, (char *)&cheader, sizeof(cheader));
169 printf("SetupHeader failed\n");
172 cheaderReadTime = time(0);
175 printf("DB version should be %d; Initial = %d; Terminal = %d\n",
176 KADBVERSION, iversion, tversion);
180 ReleaseWriteLock(&cheader_lock);
184 /* if here, we have no version number or the wrong version number in the
186 if ((code == UEOF) || ((iversion == 0) && (tversion == 0)))
191 if ((db_init == 0) || (code == KAIO))
194 printf("Error discovered in header, rebuilding.\n");
196 /* try to write a good header */
197 memset(&cheader, 0, sizeof(cheader));
198 cheader.version = htonl(KADBVERSION);
199 cheader.checkVersion = htonl(KADBVERSION);
200 cheader.headerSize = htonl(sizeof(cheader));
202 cheader.eofPtr = htonl(sizeof(cheader));
204 cheader.specialKeysVersion = htonl(time(0)); /* anything non-zero will do */
205 cheader.stats.cpws = cheader.stats.allocs = cheader.stats.frees = 0;
206 cheader.admin_accounts = 0;
207 cheader.hashsize = htonl(HASHSIZE);
208 code = kawrite(at, 0, (char *)&cheader, sizeof(cheader));
210 return KAIO; /* return the error code */
212 return db_init(at); /* initialize the db */
215 /* Allocate a free block of storage for entry, returning address of a new
216 zeroed entry. If zero is returned, a Ubik I/O error can be assumed. */
219 AllocBlock(at, tentry)
220 register struct ubik_trans *at;
221 struct kaentry *tentry;
223 register afs_int32 code;
226 if (cheader.freePtr) {
227 /* allocate this dude */
228 temp = ntohl(cheader.freePtr);
229 code = karead(at, temp, (char *)tentry, sizeof(kaentry));
231 return 0; /* can't read block */
232 code = set_header_word(at, freePtr, tentry->next);
234 /* hosed, nothing on free list, grow file */
235 temp = ntohl(cheader.eofPtr); /* remember this guy */
236 code = set_header_word(at, eofPtr, htonl(temp + sizeof(kaentry)));
241 code = inc_header_word(at, stats.allocs);
244 memset(tentry, 0, sizeof(kaentry)); /* zero new entry */
248 /* Free a block given its index. It must already have been unthreaded.
249 Returns zero for success or an error code on failure. */
253 struct ubik_trans *at;
256 struct kaentry tentry;
259 /* check index just to be on the safe side */
260 if (!index_OK(index))
263 memset(&tentry, 0, sizeof(kaentry));
264 tentry.next = cheader.freePtr;
265 tentry.flags = htonl(KAFFREE);
266 code = set_header_word(at, freePtr, htonl(index));
269 code = kawrite(at, index, (char *)&tentry, sizeof(kaentry));
273 code = inc_header_word(at, stats.frees);
279 /* Look for a block by name and instance. If found read the block's contents
280 into the area pointed to by tentry and return the block's index. If not
281 found offset is set to zero. If an error is encountered a non-zero code is
285 FindBlock(at, aname, ainstance, toP, tentry)
286 struct ubik_trans *at;
290 struct kaentry *tentry;
292 register afs_int32 i, code;
293 register afs_int32 to;
296 i = NameHash(aname, ainstance);
297 for (to = ntohl(cheader.nameHash[i]); to != NULLO;
298 to = ntohl(tentry->next)) {
299 code = karead(at, to, (char *)tentry, sizeof(kaentry));
302 /* see if the name matches */
303 if (!strcmp(aname, tentry->userID.name)
304 && (ainstance == (char *)0
305 || !strcmp(ainstance, tentry->userID.instance))) {
306 *toP = to; /* found it */
310 *toP = 0; /* no such entry */
314 /* Add a block to the hash table given a pointer to the block and its index.
315 The block is threaded onto the hash table and written to disk. The routine
316 returns zero if there were no errors. */
319 ThreadBlock(at, index, tentry)
320 struct ubik_trans *at;
322 struct kaentry *tentry;
325 int hi; /* hash index */
327 if (!index_OK(index))
329 hi = NameHash(tentry->userID.name, tentry->userID.instance);
330 tentry->next = cheader.nameHash[hi];
331 code = set_header_word(at, nameHash[hi], htonl(index));
334 code = kawrite(at, index, (char *)tentry, sizeof(kaentry));
340 /* Remove a block from the hash table. If success return 0, else return an
344 UnthreadBlock(at, aentry)
345 struct ubik_trans *at;
346 struct kaentry *aentry;
348 register afs_int32 i, code;
349 register afs_int32 to;
351 struct kaentry tentry;
353 i = NameHash(aentry->userID.name, aentry->userID.instance);
355 for (to = ntohl(cheader.nameHash[i]); to != NULLO;
356 to = ntohl(tentry.next)) {
357 code = karead(at, to, (char *)&tentry, sizeof(kaentry));
360 /* see if the name matches */
361 if (!strcmp(aentry->userID.name, tentry.userID.name)
362 && !strcmp(aentry->userID.instance, tentry.userID.instance)) {
364 if (lo) { /* unthread from last block */
366 kawrite(at, lo, (char *)&tentry.next, sizeof(afs_int32));
369 } else { /* unthread from hash table */
370 code = set_header_word(at, nameHash[i], tentry.next);
374 aentry->next = 0; /* just to be sure */
377 lo = DOFFSET(to, &tentry, &tentry.next);
382 /* Given an index to the last block (or zero the first time) read the contents
383 of the next block and return its index. The last argument is a pointer to
384 an estimate of the number of remaining blocks to read out. The remaining
385 count is an estimate because it may include free blocks that are not
386 returned. If there are no more blocks remaining is zero and the returned
387 index is zero. A non-zero index indicates that tentry has been filled with
388 valid data. If an error is encountered the returned index is zero and the
389 remaining count is negative. */
392 NextBlock(at, index, tentry, remaining)
393 struct ubik_trans *at;
395 struct kaentry *tentry;
396 afs_int32 *remaining;
401 if (index == 0) /* get first one */
402 index = sizeof(cheader);
404 if (!index_OK(index)) {
405 *remaining = -1; /* error */
408 index += sizeof(kaentry);
410 /* now search for the first entry that isn't free */
411 for (last = ntohl(cheader.eofPtr); index < last; index += sizeof(kaentry)) {
412 code = karead(at, index, (char *)tentry, sizeof(kaentry));
417 if (!(ntohl(tentry->flags) & (KAFFREE | KAFOLDKEYS))) {
418 /* estimate remaining number of entries, not including this one */
419 *remaining = (last - index) / sizeof(kaentry) - 1;
423 *remaining = 0; /* no more entries */
427 /* These are a collections of routines that deal with externally known keys.
428 They maintain a database of key version numbers and the corresponding key
429 and pointer to the user entry. */
432 ka_NewKey(tt, tentryaddr, tentry, key)
433 struct ubik_trans *tt;
434 afs_int32 tentryaddr;
435 struct kaentry *tentry;
436 struct ktc_encryptionKey *key;
438 struct kaOldKeys okeys; /* old keys block */
439 afs_int32 okeysaddr, nextaddr; /* offset of old keys block */
440 afs_int32 prevptr, nextprevptr;
443 afs_int32 newkeyver; /* new key version number */
444 afs_int32 newtotalkeyentries = 0, oldtotalkeyentries = 0, keyentries;
445 int foundcurrentkey = 0, addednewkey = 0, modified;
447 es_Report("Newkey for %s.%s\n", tentry->userID.name,
448 tentry->userID.instance);
450 newkeyver = ntohl(tentry->key_version) + 1;
451 if ((newkeyver < 1) || (newkeyver >= MAXKAKVNO))
454 /* An entry may have more than one oldkeys blocks. The entry
455 * points to the most current, but all the oldkeys blocks for an
456 * entry are not linked together. All oldkeys blocks for all
457 * entries are linked together off of the header. So we follow
460 for (prevptr = 0, okeysaddr = ntohl(cheader.kvnoPtr); okeysaddr;
461 prevptr = nextprevptr, okeysaddr = nextaddr) {
462 /* foreacholdkeysblock */
463 /* Read the oldKeys block */
464 code = karead(tt, okeysaddr, (char *)&okeys, sizeof(okeys));
468 nextaddr = ntohl(okeys.next);
469 nextprevptr = DOFFSET(okeysaddr, &okeys, &okeys.next);
471 /* We only want oldkey blocks that belong to this entry */
472 if (ntohl(okeys.entry) != tentryaddr)
475 modified = 0; /* This oldkeys block has not been modified */
476 keyentries = 0; /* Number of valid key entries in the block */
477 for (i = 0; i < NOLDKEYS; i++) {
479 /* Keep count of number of entries found */
480 if (okeys.keys[i].superseded != 0) {
481 oldtotalkeyentries++;
484 /* If we find the entry that is not superseded, then supersede it */
485 if (ntohl(okeys.keys[i].superseded) == NEVERDATE) {
486 okeys.keys[i].superseded = htonl(now);
489 if (foundcurrentkey) {
491 ("Warning: Entry %s.%s contains more than one valid key: fixing\n",
492 tentry->userID.name, tentry->userID.instance));
498 /* If we find an oldkey of the same version or
499 * an old key that has expired, then delete it.
501 if ((ntohl(okeys.keys[i].version) == newkeyver)
502 || ((now - ntohl(okeys.keys[i].superseded) > maxKeyLifetime))) {
503 okeys.keys[i].superseded = 0;
504 okeys.keys[i].version = htonl(-1);
505 memset(&okeys.keys[i].key, 0,
506 sizeof(struct ktc_encryptionKey));
509 es_Report("Dropped oldkey %d seconds old with kvno %d\n",
510 now - ntohl(okeys.keys[i].superseded),
511 ntohl(okeys.keys[i].version));
514 /* Add our key here if its free */
515 if (!addednewkey && (okeys.keys[i].superseded == 0)) {
516 okeys.keys[i].version = htonl(newkeyver);
517 okeys.keys[i].superseded = htonl(NEVERDATE);
518 memcpy(&okeys.keys[i].key, key,
519 sizeof(struct ktc_encryptionKey));
521 addednewkey = okeysaddr;
524 /* Keep count of number of entries found */
525 if (okeys.keys[i].superseded != 0) {
527 newtotalkeyentries++;
531 /* If we modified the block, write it out */
532 if (modified && keyentries) {
533 code = kawrite(tt, okeysaddr, (char *)&okeys, sizeof(okeys));
538 /* If there are no more entries in this oldkeys block, delete it */
539 if (keyentries == 0) {
541 code = set_header_word(tt, kvnoPtr, okeys.next);
544 kawrite(tt, prevptr, (char *)&okeys.next,
549 code = FreeBlock(tt, okeysaddr);
553 nextprevptr = prevptr; /* won't bump prevptr */
555 } /* foreacholdkeysblock */
557 /* If we could not add the key, create a new oldkeys block */
559 /* Allocate and fill in an oldkeys block */
560 addednewkey = AllocBlock(tt, (struct kaentry *)&okeys);
563 okeys.flags = htonl(KAFOLDKEYS);
564 okeys.entry = htonl(tentryaddr);
565 okeys.keys[0].version = htonl(newkeyver);
566 okeys.keys[0].superseded = htonl(NEVERDATE);
567 memcpy(&okeys.keys[0].key, key, sizeof(struct ktc_encryptionKey));
568 newtotalkeyentries++;
570 /* Thread onto the header's chain of oldkeys */
571 okeys.next = cheader.kvnoPtr;
572 code = set_header_word(tt, kvnoPtr, htonl(addednewkey));
576 /* Write the oldkeys block out */
577 code = kawrite(tt, addednewkey, (char *)&okeys, sizeof(okeys));
581 es_Report("New oldkey block allocated at %d\n", addednewkey);
584 if (oldtotalkeyentries != ntohl(tentry->misc.asServer.nOldKeys)) {
586 ("Warning: Entry %s.%s reports %d oldkeys, found %d: fixing\n",
587 tentry->userID.name, tentry->userID.instance,
588 ntohl(tentry->misc.asServer.nOldKeys), oldtotalkeyentries));
592 /* Update the tentry. We rely on caller to write it out */
593 tentry->misc.asServer.oldKeys = htonl(addednewkey);
594 tentry->misc.asServer.nOldKeys = htonl(newtotalkeyentries);
595 tentry->key_version = htonl(newkeyver);
596 memcpy(&tentry->key, key, sizeof(tentry->key));
598 /* invalidate key caches everywhere */
599 code = inc_header_word(tt, specialKeysVersion);
603 es_Report("New kvno is %d, now are %d oldkeys\n", newkeyver,
609 ka_DelKey(tt, tentryaddr, tentry)
610 struct ubik_trans *tt;
611 afs_int32 tentryaddr;
612 struct kaentry *tentry;
615 struct kaOldKeys okeys; /* old keys block */
616 afs_int32 okeysaddr, nextaddr; /* offset of old keys block */
617 afs_int32 prevptr = 0;
620 es_Report("DelKey for %s.%s\n", tentry->userID.name,
621 tentry->userID.instance);
623 /* An entry may have more than one oldkeys blocks. The entry
624 * points to the most current, but all the oldkeys blocks for an
625 * entry are not linked together. All oldkeys blocks for all
626 * entries are linked together off of the header. So we follow
629 for (okeysaddr = ntohl(cheader.kvnoPtr); okeysaddr; okeysaddr = nextaddr) {
630 /* foreacholdkeysblock */
631 /* Read the oldKeys block */
632 code = karead(tt, okeysaddr, (char *)&okeys, sizeof(okeys));
635 nextaddr = ntohl(okeys.next);
637 /* We only want oldkey blocks that belong to this entry */
638 if (ntohl(okeys.entry) != tentryaddr) {
639 prevptr = DOFFSET(okeysaddr, &okeys, &okeys.next);
643 /* Delete the oldkeys block */
646 kawrite(tt, prevptr, (char *)&okeys.next, sizeof(afs_int32));
648 code = set_header_word(tt, kvnoPtr, okeys.next);
652 code = FreeBlock(tt, okeysaddr);
655 } /* foreacholdkeysblock */
657 /* Update the tentry. We rely on caller to write it out */
658 tentry->misc.asServer.oldKeys = 0;
659 tentry->misc.asServer.nOldKeys = 0;
661 /* invalidate key caches everywhere */
662 code = inc_header_word(tt, specialKeysVersion);
670 ka_debugKeyCache(info)
671 struct ka_debugInfo *info;
675 memcpy(&info->cheader_lock, &cheader_lock, sizeof(info->cheader_lock));
676 memcpy(&info->keycache_lock, &keycache_lock, sizeof(info->keycache_lock));
678 info->kcVersion = keyCacheVersion;
679 info->kcSize = maxCachedKeys;
681 for (i = 0; i < maxCachedKeys; i++) {
682 if (keyCache[i].used) {
683 if (info->kcUsed < KADEBUGKCINFOSIZE) {
684 int j = info->kcUsed;
685 char principal[sizeof(keyCache[0].name) +
686 sizeof(keyCache[0].inst)];
688 info->kcInfo[j].used = keyCache[i].superseded;
689 info->kcInfo[j].kvno = keyCache[i].kvno;
690 info->kcInfo[j].primary =
691 (keyCache[i].superseded == NEVERDATE);
692 info->kcInfo[j].keycksum = 0;
696 for (k = 0; k < sizeof(struct ktc_encryptionKey); k++)
697 info->kcInfo[j].keycksum += ((char *)&keyCache[i].key)[k];
700 strcpy(principal, keyCache[i].name);
701 strcat(principal, ".");
702 strcat(principal, keyCache[i].inst);
703 strncpy(info->kcInfo[j].principal, principal,
704 sizeof(info->kcInfo[0].principal));
711 /* Add a key to the key cache, expanding it if necessary. */
714 ka_Encache(name, inst, kvno, key, superseded)
718 struct ktc_encryptionKey *key;
723 ObtainWriteLock(&keycache_lock);
724 if (keyCacheVersion != ntohl(cheader.specialKeysVersion)) {
725 for (i = 0; i < maxCachedKeys; i++)
726 keyCache[i].used = 0;
729 for (i = 0; i < maxCachedKeys; i++)
730 if (keyCache[i].used == 0) {
732 keyCache[i].kvno = kvno;
733 strncpy(keyCache[i].name, name, sizeof(keyCache[i].name));
734 strncpy(keyCache[i].inst, inst, sizeof(keyCache[i].inst));
735 keyCacheVersion = ntohl(cheader.specialKeysVersion);
736 memcpy(&keyCache[i].key, key, sizeof(*key));
737 keyCache[i].superseded = superseded;
738 keyCache[i].used = time(0);
740 ReleaseWriteLock(&keycache_lock);
743 /* i == maxCachedKeys */
745 (struct cachedKey *)realloc(keyCache,
747 2) * sizeof(struct cachedKey));
749 es_Report("Can't realloc keyCache! out of memory?");
754 int j = i; /* initialize new storage */
755 while (j < maxCachedKeys)
756 keyCache[j++].used = 0;
761 /* Look up the key given a principal and a kvno. This is called by GetTicket
762 to get the decryption key for the authenticating ticket. It is also called
763 by the rxkad security module to decrypt admin tickets. The rxkad call is
764 with tt==0, since Rx can't call Ubik. */
767 ka_LookupKvno(tt, name, inst, kvno, key)
768 struct ubik_trans *tt;
772 struct ktc_encryptionKey *key;
777 struct kaentry tentry;
779 struct kaOldKeys okeys;
781 ObtainReadLock(&keycache_lock);
782 if (keyCacheVersion != ntohl(cheader.specialKeysVersion))
783 code = KAKEYCACHEINVALID;
785 for (i = 0; i < maxCachedKeys; i++) {
786 if (keyCache[i].used) { /* zero used date means invalid */
787 if ((keyCache[i].kvno == kvno)
788 && (strcmp(keyCache[i].name, name) == 0)
789 && (strcmp(keyCache[i].inst, inst) == 0)) {
790 memcpy(key, &keyCache[i].key, sizeof(*key));
791 keyCache[i].used = time(0);
792 ReleaseReadLock(&keycache_lock);
799 ReleaseReadLock(&keycache_lock);
803 /* we missed in the cache so need to look in the Ubik database */
804 code = FindBlock(tt, name, inst, &to, &tentry);
810 /* first check the current key */
811 if (tentry.key_version == htonl(kvno)) {
812 memcpy(key, &tentry.key, sizeof(*key));
813 ka_Encache(name, inst, kvno, key, NEVERDATE);
816 for (ko = ntohl(cheader.kvnoPtr); ko; ko = ntohl(okeys.next)) {
817 code = karead(tt, ko, (char *)&okeys, sizeof(okeys));
820 if (ntohl(okeys.entry) == to)
821 for (i = 0; i < NOLDKEYS; i++)
822 if (okeys.keys[i].superseded
823 && (ntohl(okeys.keys[i].version) == kvno)) {
824 memcpy(key, &okeys.keys[i].key, sizeof(*key));
825 ka_Encache(name, inst, kvno, key,
826 ntohl(okeys.keys[i].superseded));
833 /* Look up the primary key and key version for a principal. */
836 ka_LookupKey(tt, name, inst, kvno, key)
837 struct ubik_trans *tt;
840 afs_int32 *kvno; /* returned */
841 struct ktc_encryptionKey *key; /* copied out */
845 struct kaentry tentry;
848 ObtainReadLock(&keycache_lock);
849 if (keyCacheVersion != ntohl(cheader.specialKeysVersion))
850 code = KAKEYCACHEINVALID;
852 for (i = 0; i < maxCachedKeys; i++) {
853 if (keyCache[i].used) { /* zero used date means invalid */
854 if ((keyCache[i].superseded == NEVERDATE)
855 && (strcmp(keyCache[i].name, name) == 0)
856 && (strcmp(keyCache[i].inst, inst) == 0)) {
857 memcpy(key, &keyCache[i].key, sizeof(*key));
858 *kvno = keyCache[i].kvno;
859 keyCache[i].used = time(0);
860 ReleaseReadLock(&keycache_lock);
867 ReleaseReadLock(&keycache_lock);
871 /* we missed in the cache so need to look in the Ubik database */
872 code = FindBlock(tt, name, inst, &to, &tentry);
877 memcpy(key, &tentry.key, sizeof(*key));
878 *kvno = ntohl(tentry.key_version);
879 ka_Encache(name, inst, *kvno, key, NEVERDATE);
883 /* This is, hopefully a temporary mechanism to fill the cache will all keys
884 since filling cache misses during rxkad challenge responses will deadlock if
885 Ubik needs to use Rx. */
889 struct ubik_trans *tt;
895 struct ktc_encryptionKey k;
896 struct kaOldKeys okeys;
897 struct kaentry tentry;
899 /* this is a little marginal, but... */
900 if (keyCacheVersion == ntohl(cheader.specialKeysVersion))
904 for (ko = ntohl(cheader.kvnoPtr); ko; ko = ntohl(okeys.next)) {
905 code = karead(tt, ko, (char *)&okeys, sizeof(okeys));
908 /* get name & instance */
910 karead(tt, ntohl(okeys.entry), (char *)&tentry, sizeof(tentry));
914 /* get all the old keys in this block */
915 for (i = 0; i < NOLDKEYS; i++)
916 if (okeys.keys[i].superseded) {
918 ka_LookupKvno(tt, tentry.userID.name,
919 tentry.userID.instance,
920 ntohl(okeys.keys[i].version), &k);
925 if (++nfound > maxCachedKeys)
926 return KADATABASEINCONSISTENT;
931 update_admin_count(tt, delta)
932 struct ubik_trans *tt;
938 cheader.admin_accounts = htonl(ntohl(cheader.admin_accounts) + delta);
939 to = DOFFSET(0, &cheader, &cheader.admin_accounts);
941 kawrite(tt, to, (char *)&cheader.admin_accounts, sizeof(afs_int32));
951 if ((index < sizeof(cheader)) || (index >= ntohl(cheader.eofPtr))
952 || ((index - sizeof(cheader)) % sizeof(kaentry) != 0))
957 #define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
960 name_instance_legal(name, instance)
966 /* No string checks apply anymore. The international people want to use full 8
967 bit ascii without problems. */
969 code = (strlen(name) < MAXKTCNAMELEN)
970 && (strlen(instance) < MAXKTCNAMELEN);
972 map = LEGALCHARS; /* permitted chars, instance allows <period> */
973 code = (strlen(name) > 0) && string_legal(instance, map)
974 && string_legal(name, map + 1);
977 dynamic_statistics.string_checks++;
982 string_legal(str, map)
989 if (slen >= MAXKTCNAMELEN)
990 return 0; /* with trailing null must fit in data base */
991 return (slen == strspn(str, map)); /* strspn returns length(str) if all chars in map */