afs_int32 AllocBlock(struct ubik_trans *at, struct kaentry *tentry) { afs_int32 code; afs_int32 temp; if (cheader.freePtr) { /* allocate this dude */ temp = ntohl(cheader.freePtr); code = karead(at, temp, (char *)tentry, sizeof(kaentry)); if (code) return 0; /* can't read block */ code = set_header_word(at, freePtr, tentry->next); } else { /* hosed, nothing on free list, grow file */ temp = ntohl(cheader.eofPtr); /* remember this guy */ code = set_header_word(at, eofPtr, htonl(temp + sizeof(kaentry))); } if (code) return 0; code = inc_header_word(at, stats.allocs); if (code) return 0; memset(tentry, 0, sizeof(kaentry)); /* zero new entry */ return temp; }
afs_int32 FreeBlock(struct ubik_trans *at, afs_int32 index) { struct kaentry tentry; int code; /* check index just to be on the safe side */ if (!index_OK(index)) return KABADINDEX; memset(&tentry, 0, sizeof(kaentry)); tentry.next = cheader.freePtr; tentry.flags = htonl(KAFFREE); code = set_header_word(at, freePtr, htonl(index)); if (code) return KAIO; code = kawrite(at, index, (char *)&tentry, sizeof(kaentry)); if (code) return KAIO; code = inc_header_word(at, stats.frees); if (code) return KAIO; return 0; }
afs_int32 GetInstanceId(struct rx_call *call, afs_uint32 *instanceId) { struct ubik_trans *ut; afs_int32 code; afs_int32 instanceValue; LogDebug(4, "GetInstanceId:\n"); /* *** Allow anyone to get the instance id *** * if ( callPermitted(call) == 0 ) * return(BUDB_NOTPERMITTED); */ code = InitRPC(&ut, LOCKWRITE, 1); if (code) return (code); instanceValue = ntohl(db.h.lastInstanceId) + 1; set_header_word(ut, lastInstanceId, htonl(instanceValue)); code = ubik_EndTrans(ut); return (code); }
afs_int32 ka_DelKey(struct ubik_trans *tt, afs_int32 tentryaddr, struct kaentry *tentry) { int code; struct kaOldKeys okeys; /* old keys block */ afs_int32 okeysaddr, nextaddr; /* offset of old keys block */ afs_int32 prevptr = 0; es_Report("DelKey for %s.%s\n", tentry->userID.name, tentry->userID.instance); /* An entry may have more than one oldkeys blocks. The entry * points to the most current, but all the oldkeys blocks for an * entry are not linked together. All oldkeys blocks for all * entries are linked together off of the header. So we follow * this link. */ for (okeysaddr = ntohl(cheader.kvnoPtr); okeysaddr; okeysaddr = nextaddr) { /* foreacholdkeysblock */ /* Read the oldKeys block */ code = karead(tt, okeysaddr, (char *)&okeys, sizeof(okeys)); if (code) return code; nextaddr = ntohl(okeys.next); /* We only want oldkey blocks that belong to this entry */ if (ntohl(okeys.entry) != tentryaddr) { prevptr = DOFFSET(okeysaddr, &okeys, &okeys.next); continue; } /* Delete the oldkeys block */ if (prevptr) { code = kawrite(tt, prevptr, (char *)&okeys.next, sizeof(afs_int32)); } else { code = set_header_word(tt, kvnoPtr, okeys.next); } if (code) return code; code = FreeBlock(tt, okeysaddr); if (code) return code; } /* foreacholdkeysblock */ /* Update the tentry. We rely on caller to write it out */ tentry->misc.asServer.oldKeys = 0; tentry->misc.asServer.nOldKeys = 0; /* invalidate key caches everywhere */ code = inc_header_word(tt, specialKeysVersion); if (code) return code; return 0; }
afs_int32 ThreadBlock(struct ubik_trans *at, afs_int32 index, struct kaentry *tentry) { int code; int hi; /* hash index */ if (!index_OK(index)) return KABADINDEX; hi = NameHash(tentry->userID.name, tentry->userID.instance); tentry->next = cheader.nameHash[hi]; code = set_header_word(at, nameHash[hi], htonl(index)); if (code) return KAIO; code = kawrite(at, index, (char *)tentry, sizeof(kaentry)); if (code) return KAIO; return 0; }
afs_int32 AddToOrphan(struct ubik_trans *at, afs_int32 gid) { afs_int32 code; afs_int32 loc; struct prentry tentry; loc = FindByID(at, gid); if (!loc) return PRNOENT; code = pr_ReadEntry(at, 0, loc, &tentry); if (code != 0) return PRDBFAIL; tentry.nextOwned = ntohl(cheader.orphan); code = set_header_word(at, orphan, htonl(loc)); if (code != 0) return PRDBFAIL; tentry.owner = 0; /* so there's no confusion later */ code = pr_WriteEntry(at, 0, loc, &tentry); if (code != 0) return PRDBFAIL; return PRSUCCESS; }
afs_int32 UnthreadBlock(struct ubik_trans *at, struct kaentry *aentry) { afs_int32 i, code; afs_int32 to; afs_int32 lo; struct kaentry tentry; i = NameHash(aentry->userID.name, aentry->userID.instance); lo = 0; for (to = ntohl(cheader.nameHash[i]); to != NULLO; to = ntohl(tentry.next)) { code = karead(at, to, (char *)&tentry, sizeof(kaentry)); if (code) return KAIO; /* see if the name matches */ if (!strcmp(aentry->userID.name, tentry.userID.name) && !strcmp(aentry->userID.instance, tentry.userID.instance)) { /* found it */ if (lo) { /* unthread from last block */ code = kawrite(at, lo, (char *)&tentry.next, sizeof(afs_int32)); if (code) return KAIO; } else { /* unthread from hash table */ code = set_header_word(at, nameHash[i], tentry.next); if (code) return KAIO; } aentry->next = 0; /* just to be sure */ return 0; } lo = DOFFSET(to, &tentry, &tentry.next); } return KANOENT; }
afs_int32 ka_NewKey(struct ubik_trans *tt, afs_int32 tentryaddr, struct kaentry *tentry, struct ktc_encryptionKey *key) { struct kaOldKeys okeys; /* old keys block */ afs_int32 okeysaddr, nextaddr; /* offset of old keys block */ afs_int32 prevptr, nextprevptr; int code, i; Date now = time(0); afs_int32 newkeyver; /* new key version number */ afs_int32 newtotalkeyentries = 0, oldtotalkeyentries = 0, keyentries; int addednewkey = 0, modified; #ifdef AUTH_DBM_LOG int foundcurrentkey = 0; #endif es_Report("Newkey for %s.%s\n", tentry->userID.name, tentry->userID.instance); newkeyver = ntohl(tentry->key_version) + 1; if ((newkeyver < 1) || (newkeyver >= MAXKAKVNO)) newkeyver = 1; /* An entry may have more than one oldkeys blocks. The entry * points to the most current, but all the oldkeys blocks for an * entry are not linked together. All oldkeys blocks for all * entries are linked together off of the header. So we follow * this link. */ for (prevptr = 0, okeysaddr = ntohl(cheader.kvnoPtr); okeysaddr; prevptr = nextprevptr, okeysaddr = nextaddr) { /* foreacholdkeysblock */ /* Read the oldKeys block */ code = karead(tt, okeysaddr, (char *)&okeys, sizeof(okeys)); if (code) return code; nextaddr = ntohl(okeys.next); nextprevptr = DOFFSET(okeysaddr, &okeys, &okeys.next); /* We only want oldkey blocks that belong to this entry */ if (ntohl(okeys.entry) != tentryaddr) continue; modified = 0; /* This oldkeys block has not been modified */ keyentries = 0; /* Number of valid key entries in the block */ for (i = 0; i < NOLDKEYS; i++) { /* foreachkey */ /* Keep count of number of entries found */ if (okeys.keys[i].superseded != 0) { oldtotalkeyentries++; } /* If we find the entry that is not superseded, then supersede it */ if (ntohl(okeys.keys[i].superseded) == NEVERDATE) { okeys.keys[i].superseded = htonl(now); modified = 1; #ifdef AUTH_DBM_LOG if (foundcurrentkey) { ViceLog(0, ("Warning: Entry %s.%s contains more than one valid key: fixing\n", tentry->userID.name, tentry->userID.instance)); } foundcurrentkey = 1; #endif } /* If we find an oldkey of the same version or * an old key that has expired, then delete it. */ if ((ntohl(okeys.keys[i].version) == newkeyver) || ((now - ntohl(okeys.keys[i].superseded) > maxKeyLifetime))) { okeys.keys[i].superseded = 0; okeys.keys[i].version = htonl(-1); memset(&okeys.keys[i].key, 0, sizeof(struct ktc_encryptionKey)); modified = 1; es_Report("Dropped oldkey %d seconds old with kvno %d\n", now - ntohl(okeys.keys[i].superseded), ntohl(okeys.keys[i].version)); } /* Add our key here if its free */ if (!addednewkey && (okeys.keys[i].superseded == 0)) { okeys.keys[i].version = htonl(newkeyver); okeys.keys[i].superseded = htonl(NEVERDATE); memcpy(&okeys.keys[i].key, key, sizeof(struct ktc_encryptionKey)); modified = 1; addednewkey = okeysaddr; } /* Keep count of number of entries found */ if (okeys.keys[i].superseded != 0) { keyentries++; newtotalkeyentries++; } } /* foreachkey */ /* If we modified the block, write it out */ if (modified && keyentries) { code = kawrite(tt, okeysaddr, (char *)&okeys, sizeof(okeys)); if (code) return code; } /* If there are no more entries in this oldkeys block, delete it */ if (keyentries == 0) { if (!prevptr) { code = set_header_word(tt, kvnoPtr, okeys.next); } else { code = kawrite(tt, prevptr, (char *)&okeys.next, sizeof(afs_int32)); } if (code) return code; code = FreeBlock(tt, okeysaddr); if (code) return code; nextprevptr = prevptr; /* won't bump prevptr */ } } /* foreacholdkeysblock */ /* If we could not add the key, create a new oldkeys block */ if (!addednewkey) { /* Allocate and fill in an oldkeys block */ addednewkey = AllocBlock(tt, (struct kaentry *)&okeys); if (!addednewkey) return KACREATEFAIL; okeys.flags = htonl(KAFOLDKEYS); okeys.entry = htonl(tentryaddr); okeys.keys[0].version = htonl(newkeyver); okeys.keys[0].superseded = htonl(NEVERDATE); memcpy(&okeys.keys[0].key, key, sizeof(struct ktc_encryptionKey)); newtotalkeyentries++; /* Thread onto the header's chain of oldkeys */ okeys.next = cheader.kvnoPtr; code = set_header_word(tt, kvnoPtr, htonl(addednewkey)); if (code) return code; /* Write the oldkeys block out */ code = kawrite(tt, addednewkey, (char *)&okeys, sizeof(okeys)); if (code) return code; es_Report("New oldkey block allocated at %d\n", addednewkey); } #ifdef AUTH_DBM_LOG if (oldtotalkeyentries != ntohl(tentry->misc.asServer.nOldKeys)) { ViceLog(0, ("Warning: Entry %s.%s reports %d oldkeys, found %d: fixing\n", tentry->userID.name, tentry->userID.instance, ntohl(tentry->misc.asServer.nOldKeys), oldtotalkeyentries)); } #endif /* Update the tentry. We rely on caller to write it out */ tentry->misc.asServer.oldKeys = htonl(addednewkey); tentry->misc.asServer.nOldKeys = htonl(newtotalkeyentries); tentry->key_version = htonl(newkeyver); memcpy(&tentry->key, key, sizeof(tentry->key)); /* invalidate key caches everywhere */ code = inc_header_word(tt, specialKeysVersion); if (code) return code; es_Report("New kvno is %d, now are %d oldkeys\n", newkeyver, newtotalkeyentries); return 0; }