Example #1
0
static long
GetTicket(long *versionP, struct ktc_encryptionKey *session,
	  int *ticketLenP, char *ticket, char *cell)
{
    long code;

    /* create random session key, using key for seed to good random */
    des_init_random_number_generator(ktc_to_cblock(&serviceKey));
    code = des_random_key(ktc_to_cblock(session));
    if (code)
	return code;

    /* now create the actual ticket */
    *ticketLenP = 0;
    code =
	tkt_MakeTicket(ticket, ticketLenP, &serviceKey, RXKST_CLIENT_NAME,
		       RXKST_CLIENT_INST, cell,
		       /*start,end */ 0, 0xffffffff, session, /*host */ 0,
		       RXKST_SERVER_NAME, RXKST_SERVER_NAME);
    /* parms were buffer, ticketlen, key to seal ticket with, principal name,
     * instance and cell, start time, end time, session key to seal in ticket,
     * inet host, server name and server instance */
    if (code)
	return code;
    *versionP = serviceKeyVersion;
    return 0;
}
Example #2
0
static void
StringToKey(char *str, char *cell,	/* cell for password */
	    struct ktc_encryptionKey *key)
{
    DES_key_schedule schedule;
    DES_cblock temp_key;
    DES_cblock ivec;
    char password[BUFSIZ];
    int passlen;

    strncpy(password, str, sizeof(password));
    if ((passlen = strlen(password)) < sizeof(password) - 1)
	strncat(password, cell, sizeof(password) - passlen);
    if ((passlen = strlen(password)) > sizeof(password))
	passlen = sizeof(password);

    memcpy(&ivec, "kerberos", 8);
    memcpy(&temp_key, "kerberos", 8);
    DES_set_odd_parity(&temp_key);
    DES_key_sched(&temp_key, &schedule);
    DES_cbc_cksum((DES_cblock *) password, &ivec, passlen, &schedule, &ivec);

    memcpy(&temp_key, &ivec, 8);
    DES_set_odd_parity(&temp_key);
    DES_key_sched(&temp_key, &schedule);
    DES_cbc_cksum((DES_cblock *)password, ktc_to_cblock(key), passlen,
		   &schedule, &ivec);

    DES_set_odd_parity(ktc_to_cblock(key));
}
Example #3
0
static afs_int32
GenericAuth(struct afsconf_dir *adir, 
	    struct rx_securityClass **astr, 
	    afs_int32 *aindex, 
	    rxkad_level enclevel)
{
    char tbuffer[256];
    struct ktc_encryptionKey key, session;
    struct rx_securityClass *tclass;
    afs_int32 kvno;
    afs_int32 ticketLen;
    register afs_int32 code;

    /* first, find the right key and kvno to use */
    code = afsconf_GetLatestKey(adir, &kvno, &key);
    if (code) {
	return QuickAuth(astr, aindex);
    }

    /* next create random session key, using key for seed to good random */
    des_init_random_number_generator(ktc_to_cblock(&key));
    code = des_random_key(ktc_to_cblock(&session));
    if (code) {
	return QuickAuth(astr, aindex);
    }

    /* now create the actual ticket */
    ticketLen = sizeof(tbuffer);
    memset(tbuffer, '\0', sizeof(tbuffer));
    code =
	tkt_MakeTicket(tbuffer, &ticketLen, &key, AUTH_SUPERUSER, "", "", 0,
		       0xffffffff, &session, 0, "afs", "");
    /* parms were buffer, ticketlen, key to seal ticket with, principal
     * name, instance and cell, start time, end time, session key to seal
     * in ticket, inet host, server name and server instance */
    if (code) {
	return QuickAuth(astr, aindex);
    }

    /* Next, we have ticket, kvno and session key, authenticate the connection.
     * We use a magic # instead of a constant because of basic compilation
     * order when compiling the system from scratch (rx/rxkad.h isn't installed
     * yet). */
    tclass = (struct rx_securityClass *)
	rxkad_NewClientSecurityObject(enclevel, &session, kvno, ticketLen,
				      tbuffer);
    *astr = tclass;
    *aindex = RX_SECIDX_KAD;
    return 0;
}
Example #4
0
static afs_int32
check_auth(struct packet *pkt, char *auth, int authLen,
	   struct ktc_encryptionKey *key, char *name, char *inst,
	   char *cell)
{
    char *packet;
    DES_key_schedule schedule;
    afs_int32 cksum;
    afs_int32 time_sec;
    int byteOrder = pkt->byteOrder;

    DES_key_sched(ktc_to_cblock(key), &schedule);
    DES_pcbc_encrypt(auth, auth, authLen, &schedule, ktc_to_cblockptr(key), DECRYPT);
    packet = auth;
    if (strcmp(packet, name) != 0)
	return KABADTICKET;
    packet += strlen(packet) + 1;
    if (strcmp(packet, inst) != 0)
	return KABADTICKET;
    packet += strlen(packet) + 1;
    if (strcmp(packet, cell) != 0)
	return KABADTICKET;
    packet += strlen(packet) + 1;
    getint(cksum);
    /* Comments in the original IBM source suggest this byte was/is "time_msec" */
    packet++;
    getint(time_sec);
    if ((packet - auth) > authLen)
	return KABADTICKET;
    return 0;
}
Example #5
0
int
tkt_MakeTicket(char *ticket, int *ticketLen, struct ktc_encryptionKey *key,
	       char *name, char *inst, char *cell, afs_uint32 start,
	       afs_uint32 end, struct ktc_encryptionKey *sessionKey,
	       afs_uint32 host, char *sname, char *sinst)
{
    int code;
    union Key_schedule_safe schedule;

    *ticketLen = 0;		/* in case we return early */
    code =
	assemble_athena_ticket(ticket, ticketLen, name, inst, cell, host,
			       sessionKey, start, end, sname, sinst);
    *ticketLen = round_up_to_ebs(*ticketLen);	/* round up */
    if (code)
	return -1;

    /* encrypt ticket */
    if ((code = key_sched(ktc_to_cblock(key), schedule.schedule))) {
	printf("In tkt_MakeTicket: key_sched returned %d\n", code);
	return RXKADBADKEY;
    }
    pcbc_encrypt(ticket, ticket, *ticketLen, schedule.schedule, ktc_to_cblockptr(key), ENCRYPT);
    return 0;
}
Example #6
0
static afs_int32
create_cipher(char *cipher, int *cipherLen,
	      struct ktc_encryptionKey *sessionKey, char *sname,
	      char *sinst, Date start, Date end, afs_int32 kvno,
	      char *ticket, int ticketLen, struct ktc_encryptionKey *key)
{
    char *answer;
    int slen;
    unsigned char life = time_to_life(start, end);
    int len;
    DES_key_schedule schedule;
    afs_int32 code;

    answer = cipher;
    len =
	sizeof(*sessionKey) + strlen(sname) + strlen(sinst) + strlen(lrealm) +
	3 /*nulls */  + 3 + ticketLen + sizeof(Date);
    if (len > *cipherLen)
	return KAANSWERTOOLONG;
    if (ticketLen > 255)
	return KAANSWERTOOLONG;
    if (kvno > 255)
	return KAANSWERTOOLONG;

    memcpy(answer, sessionKey, sizeof(*sessionKey));
    answer += sizeof(*sessionKey);
    putstr(sname);
    putstr(sinst);
    putstr(lrealm);
    *answer++ = life;
    *answer++ = (unsigned char)kvno;
    *answer++ = (unsigned char)ticketLen;
    memcpy(answer, ticket, ticketLen);
    answer += ticketLen;
    putint(start);

    if (krb_udp_debug) {
	printf("Printing ticket (%d) and date: ", ticketLen);
	ka_PrintBytes(ticket, ticketLen);
	ka_PrintBytes(answer - 4, 4);
	printf("\n");
    }

    if ((code = DES_key_sched(ktc_to_cblock(key), &schedule)))
	printf("In KAAuthenticate: key_sched returned %d\n", code);
    DES_pcbc_encrypt(cipher, cipher, len, &schedule, ktc_to_cblockptr(key), ENCRYPT);
    *cipherLen = round_up_to_ebs(len);

    if (krb_udp_debug) {
	printf("Printing cipher (%d): ", *cipherLen);
	ka_PrintBytes(cipher, *cipherLen);
	printf("\n");
    }
    return 0;
}
Example #7
0
int
tkt_DecodeTicket(char *asecret, afs_int32 ticketLen,
		 struct ktc_encryptionKey *key, char *name, char *inst,
		 char *cell, struct ktc_encryptionKey *sessionKey, afs_int32 * host,
		 afs_uint32 * start, afs_uint32 * end)
{
    char clear_ticket[MAXKTCTICKETLEN];
    char *ticket;
    union Key_schedule_safe schedule;
    int code;

    if (ticketLen == 0)
	return RXKADBADTICKET;	/* no ticket */
    if ((ticketLen < MINKTCTICKETLEN) ||	/* minimum legal ticket size */
	(ticketLen > MAXKTCTICKETLEN) ||	/* maximum legal ticket size */
	((ticketLen) % 8 != 0))	/* enc. part must be (0 mod 8) bytes */
	return RXKADBADTICKET;

    if (key_sched(ktc_to_cblock(key), schedule.schedule))
	return RXKADBADKEY;

    ticket = clear_ticket;
    pcbc_encrypt(asecret, ticket, ticketLen, schedule.schedule, ktc_to_cblockptr(key), DECRYPT);

    code =
	decode_athena_ticket(ticket, ticketLen, name, inst, cell, host,
			     (struct ktc_encryptionKey *)sessionKey, start, end);

    if (code)
	return RXKADBADTICKET;

    code = tkt_CheckTimes(*start, *end, time(0));
    if (code == 0)
	return RXKADNOAUTH;
    else if (code == -1)
	return RXKADEXPIRED;
    else if (code < -1)
	return RXKADBADTICKET;

    return 0;
}
Example #8
0
static void
Andrew_StringToKey(char *str, char *cell,	/* cell for password */
		   struct ktc_encryptionKey *key)
{
    char password[8 + 1];	/* crypt's limit is 8 chars anyway */
    int i;
    int passlen;

    memset(key, 0, sizeof(struct ktc_encryptionKey));

    strncpy(password, cell, 8);
    passlen = strlen(str);
    if (passlen > 8)
	passlen = 8;

    for (i = 0; i < passlen; i++)
	password[i] ^= str[i];

    for (i = 0; i < 8; i++)
	if (password[i] == '\0')
	    password[i] = 'X';

    /* crypt only considers the first 8 characters of password but for some
     * reason returns eleven characters of result (plus the two salt chars). */
    strncpy((char *)key, (char *)crypt(password, "p1") + 2,
	    sizeof(struct ktc_encryptionKey));

    /* parity is inserted into the LSB so leftshift each byte up one bit.  This
     * allows ascii characters with a zero MSB to retain as much significance
     * as possible. */
    {
	char *keybytes = (char *)key;
	unsigned int temp;

	for (i = 0; i < 8; i++) {
	    temp = (unsigned int)keybytes[i];
	    keybytes[i] = (unsigned char)(temp << 1);
	}
    }
    DES_set_odd_parity(ktc_to_cblock(key));
}
Example #9
0
afs_int32
UDP_GetTicket(int ksoc, struct packet *pkt, afs_int32 kvno,
	      char *authDomain, char *ticket, int ticketLen, char *auth,
	      int authLen)
{
    afs_int32 code;
    struct ktc_encryptionKey tgskey;
    char name[MAXKTCNAMELEN];
    char inst[MAXKTCNAMELEN];
    char cell[MAXKTCREALMLEN];
    struct ktc_encryptionKey authSessionKey;
    afs_int32 host;
    Date start;
    Date authEnd;
    Date now = time(0);
    int celllen;
    int import;

    char *packet;
    int slen;
    int byteOrder = pkt->byteOrder;
    char sname[MAXKTCNAMELEN];
    char sinst[MAXKTCNAMELEN];
    afs_int32 time_ws;
    unsigned char life;

    struct ubik_trans *tt;
    afs_int32 to;
    struct kaentry caller;
    struct kaentry server;
    Date reqEnd;
    struct ktc_encryptionKey sessionKey;
    int newTicketLen;
    char newTicket[MAXKTCTICKETLEN];

    char cipher[2 * MAXKTCTICKETLEN];	/* put encrypted part of answer here */
    int cipherLen;
    struct packet ans;

    COUNT_REQ(UGetTicket);

    if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
	goto fail;
    code =
	ka_LookupKvno(tt, KA_TGS_NAME,
		      ((strlen(authDomain) > 0) ? authDomain : lrealm), kvno,
		      &tgskey);
    if (code)
	goto abort;

    code =
	tkt_DecodeTicket(ticket, ticketLen, &tgskey, name, inst, cell,
			 &authSessionKey, &host, &start, &authEnd);
    pkt->name = name;
    pkt->inst = inst;
    pkt->realm = cell;
    if (code) {
	code = KERB_ERR_AUTH_EXP;	/* was KANOAUTH */
	goto abort;
    }
    save_principal(udptgsPrincipal, name, inst, cell);
    code = tkt_CheckTimes(start, authEnd, now);
    if (code <= 0) {
	if (code == -1) {
	    code = KERB_ERR_SERVICE_EXP;	/* was RXKADEXPIRED */
	    goto abort;
	}
	code = KERB_ERR_AUTH_EXP;	/* was KANOAUTH */
	goto abort;
    }
    celllen = strlen(cell);
    import = 0;
    if ((strlen(authDomain) > 0) && (strcmp(authDomain, lrealm) != 0))
	import = 1;
    if (import && (celllen == 0)) {
	code = KERB_ERR_PKT_VER;	/* was KABADTICKET */
	goto abort;
    }
    if (celllen == 0) {
	strncpy(cell, lrealm, MAXKTCREALMLEN - 1);
	cell[MAXKTCREALMLEN - 1] = 0;
    };

    if (!krb4_cross && strcmp(lrealm, cell) != 0) {
	code = KERB_ERR_PRINCIPAL_UNKNOWN;
	goto abort;
    }

    if (krb_udp_debug) {
	printf("UGetTicket: got ticket from '%s'.'%s'@'%s'\n", name, inst,
	       cell);
    }

    code = check_auth(pkt, auth, authLen, &authSessionKey, name, inst, cell);
    if (code)
	goto abort;

    /* authenticator and all is OK so read actual request */
    packet = pkt->rest;
    getint(time_ws);
    life = *(unsigned char *)packet++;
    getstr(sname);
    getstr(sinst);
    start = now;
    reqEnd = life_to_time(start, life);
    if (krb_udp_debug) {
	printf("UGetTicket: request for server '%s'.'%s'\n", sname, sinst);
    }
    save_principal(udptgsServerPrincipal, sname, sinst, 0);

    if (import) {
	strcpy(caller.userID.name, name);
	strcpy(caller.userID.instance, inst);
	caller.max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
    } else {
	code = FindBlock(tt, name, inst, &to, &caller);
	if (code)
	    goto abort;
	if (to == 0) {
	    ka_PrintUserID("GetTicket: User ", name, inst, " unknown.\n");
	    code = KERB_ERR_PRINCIPAL_UNKNOWN;	/* KANOENT */
	    goto abort;
	}
	if (ntohl(caller.flags) & KAFNOTGS) {
	    code = KERB_ERR_AUTH_EXP;	/* was KABADUSER */
	    goto abort;
	}
    }

    code = FindBlock(tt, sname, sinst, &to, &server);	/* get server's entry */
    if (code)
	goto abort;
    if (to == 0) {		/* entry not found */
	ka_PrintUserID("GetTicket: Server ", sname, sinst, " unknown.\n");
	code = KERB_ERR_PRINCIPAL_UNKNOWN;	/* KANOENT */
	goto abort;
    }
    code = ubik_EndTrans(tt);
    if (code)
	goto fail;

    if (ntohl(server.flags) & KAFNOSEAL)
	return KABADSERVER;

    code = DES_new_random_key(ktc_to_cblock(&sessionKey));
    if (code) {
	code = KERB_ERR_NULL_KEY;	/* was KANOKEYS */
	goto fail;
    }

    reqEnd =
	umin(umin(reqEnd, authEnd),
	     umin(start + ntohl(caller.max_ticket_lifetime),
		  start + ntohl(server.max_ticket_lifetime)));

    code =
	tkt_MakeTicket(newTicket, &newTicketLen, &server.key,
		       caller.userID.name, caller.userID.instance, cell,
		       start, reqEnd, &sessionKey,
		       htonl(pkt->from.sin_addr.s_addr), server.userID.name,
		       server.userID.instance);
    if (code)
	goto fail;

    cipherLen = sizeof(cipher);
    code =
	create_cipher(cipher, &cipherLen, &sessionKey, sname, sinst, start,
		      reqEnd, ntohl(server.key_version), newTicket,
		      newTicketLen, &authSessionKey);
    if (code)
	goto fail;

    code =
	create_reply(&ans, name, inst, start, reqEnd, 0, cipher, cipherLen);
    if (code)
	goto fail;

    code =
	sendto(ksoc, ans.data, ans.len, 0, (struct sockaddr *)&pkt->from,
	       sizeof(pkt->from));
    if (code != ans.len) {
	perror("calling sendto");
	code = -1;
	goto fail;
    }

    if (cipherLen != 0) {
	KALOG(name, inst, sname, sinst, NULL, host, LOG_GETTICKET);
    }
    osi_audit(UDPGetTicketEvent, 0, AUD_STR, name, AUD_STR, inst, AUD_STR,
	      cell, AUD_STR, sname, AUD_STR, sinst, AUD_END);
    return 0;

  abort:
    ubik_AbortTrans(tt);
  fail:
    osi_audit(UDPGetTicketEvent, code, AUD_STR, name, AUD_STR, inst, AUD_STR,
	      NULL, AUD_STR, NULL, AUD_STR, NULL, AUD_END);
    return code;
}
Example #10
0
afs_int32
UDP_Authenticate(int ksoc, struct sockaddr_in *client, char *name,
		 char *inst, Date startTime, Date endTime, char *sname,
		 char *sinst)
{
    struct ubik_trans *tt;
    afs_int32 to;		/* offset of block */
    struct kaentry tentry;
    afs_int32 tgskvno;		/* key version of service key */
    struct ktc_encryptionKey tgskey;	/* service key for encrypting ticket */
    int tgt;
    Date now = time(0);
    afs_int32 code;

    char ticket[MAXKTCTICKETLEN];	/* our copy of the ticket */
    int ticketLen;
    struct ktc_encryptionKey sessionKey;	/* we have to invent a session key */

    char cipher[2 * MAXKTCTICKETLEN];	/* put encrypted part of answer here */
    int cipherLen;
    struct packet ans;

    COUNT_REQ(UAuthenticate);
    if (!name_instance_legal(name, inst))
	return KERB_ERR_NAME_EXP;	/* KABADNAME */
    if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
	return code;

    code = FindBlock(tt, name, inst, &to, &tentry);
    if (code)
	goto abort;
    if (to) {			/* if user exists check other stuff */
	afs_int32 sto;
	struct kaentry sentry;
	save_principal(udpAuthPrincipal, name, inst, 0);

	tgt = ((strcmp(sname, KA_TGS_NAME) == 0)
	       && (strcmp(sinst, lrealm) == 0));
	if ((ntohl(tentry.user_expiration) < now)
	    || (tgt && (ntohl(tentry.flags) & KAFNOTGS))) {
	    code = KERB_ERR_NAME_EXP;	/* KABADUSER */
	    goto abort;
	}
	code = FindBlock(tt, KA_TGS_NAME, lrealm, &sto, &sentry);
	if (code)
	    goto abort;
	if (sto == 0) {
	    code = KANOENT;
	    goto abort;
	}
	if ((ntohl(sentry.user_expiration) < now)) {
	    code = KERB_ERR_NAME_EXP;	/* XXX Could use another error code XXX */
	    goto abort;
	}
	if (abs(startTime - now) > KTC_TIME_UNCERTAINTY) {
	    code = KERB_ERR_SERVICE_EXP;	/* was KABADREQUEST */
	    goto abort;
	}

	if (tentry.misc_auth_bytes) {
	    unsigned char misc_auth_bytes[4];
	    afs_uint32 temp;	/* unsigned for safety */
	    afs_uint32 pwexpires;

	    memcpy(&temp, tentry.misc_auth_bytes, sizeof(afs_uint32));
	    temp = ntohl(temp);
	    unpack_long(temp, misc_auth_bytes);
	    pwexpires = misc_auth_bytes[0];
	    if (pwexpires) {
		pwexpires =
		    ntohl(tentry.change_password_time) +
		    24 * 60 * 60 * pwexpires;
		if (pwexpires < now) {
		    code = KERB_ERR_AUTH_EXP;	/* was KAPWEXPIRED */
		    goto abort;
		}
	    }
	}

	/* make the ticket */
	code = DES_new_random_key(ktc_to_cblock(&sessionKey));
	if (code) {
	    code = KERB_ERR_NULL_KEY;	/* was KANOKEYS */
	    goto abort;
	}
	endTime =
	    umin(endTime, startTime + ntohl(tentry.max_ticket_lifetime));
	if ((code = ka_LookupKey(tt, sname, sinst, &tgskvno, &tgskey))
	    || (code =
		tkt_MakeTicket(ticket, &ticketLen, &tgskey, name, inst,
			       lrealm, startTime, endTime, &sessionKey,
			       htonl(client->sin_addr.s_addr), sname, sinst)))
	    goto abort;

	cipherLen = sizeof(cipher);
	code =
	    create_cipher(cipher, &cipherLen, &sessionKey, sname, sinst,
			  startTime, endTime, tgskvno, ticket, ticketLen,
			  &tentry.key);
	if (code)
	    goto abort;
    } else {			/* no such user */
	cipherLen = 0;
	tentry.key_version = 0;
    }
    code = ubik_EndTrans(tt);
    if (code)
	goto fail;

    code =
	create_reply(&ans, name, inst, startTime, endTime,
		     ntohl(tentry.key_version), cipher, cipherLen);
    if (code)
	goto fail;

    if (krb_udp_debug) {
	printf("Sending %d bytes ending in: ", ans.len);
	ka_PrintBytes(ans.data + ans.len - 8, 8);
	printf("\n");
    }

    code =
	sendto(ksoc, ans.data, ans.len, 0, (struct sockaddr *)client,
	       sizeof(*client));
    if (code != ans.len) {
	perror("calling sendto");
	code = -1;
	goto fail;
    }
    KALOG(name, inst, sname, sinst, NULL, client->sin_addr.s_addr,
	  LOG_AUTHENTICATE);

    if (cipherLen != 0) {
	KALOG(name, inst, sname, sinst, NULL, client->sin_addr.s_addr,
	      LOG_TGTREQUEST);
    }
    osi_audit(UDPAuthenticateEvent, 0, AUD_STR, name, AUD_STR, inst, AUD_END);
    return 0;

  abort:
    COUNT_ABO;
    ubik_AbortTrans(tt);

  fail:
    osi_audit(UDPAuthenticateEvent, code, AUD_STR, name, AUD_STR, inst,
	      AUD_END);
    return code;
}
Example #11
0
static int
WorkerBee(struct cmd_syndesc *as, void *arock)
{
    afs_int32 code;
    char *dbFile;
    char *outFile;
    afs_int32 index;
    struct stat info;
    struct kaheader header;
    int nentries, i, j, count;
    int *entrys;
    struct kaentry entry;

    dbFile = as->parms[0].items->data;	/* -database */
    listuheader = (as->parms[1].items ? 1 : 0);	/* -uheader  */
    listkheader = (as->parms[2].items ? 1 : 0);	/* -kheader  */
    listentries = (as->parms[3].items ? 1 : 0);	/* -entries  */
    verbose = (as->parms[4].items ? 1 : 0);	/* -verbose  */
    outFile = (as->parms[5].items ? as->parms[5].items->data : NULL);	/* -rebuild  */

    if (outFile) {
	out = fopen(outFile, "w");
	if (!out) {
	    afs_com_err(whoami, errno, "opening output file %s", outFile);
	    exit(7);
	}
    } else
	out = 0;

    fd = open(dbFile, O_RDONLY, 0);
    if (fd < 0) {
	afs_com_err(whoami, errno, "opening database file %s", dbFile);
	exit(6);
    }
    code = fstat(fd, &info);
    if (code) {
	afs_com_err(whoami, errno, "stat'ing file %s", dbFile);
	exit(6);
    }
    if ((info.st_size - UBIK_HEADERSIZE) % UBIK_BUFFERSIZE)
	fprintf(stderr,
		"DATABASE SIZE INCONSISTENT: was %d, should be (n*%d + %d), for integral n\n",
		(int) info.st_size, UBIK_BUFFERSIZE, UBIK_HEADERSIZE);

    readUbikHeader();

    readDB(0, &header, sizeof(header));
    code = CheckHeader(&header);
    if (listkheader)
	PrintHeader(&header);

    nentries =
	(info.st_size -
	 (UBIK_HEADERSIZE + header.headerSize)) / sizeof(struct kaentry);
    entrys = calloc(nentries, sizeof(int));

    for (i = 0, index = sizeof(header); i < nentries;
	 i++, index += sizeof(struct kaentry)) {
	readDB(index, &entry, sizeof(entry));

	if (index >= header.eofPtr) {
	    entrys[i] |= 0x8;
	} else if (listentries) {
	    PrintEntry(index, &entry);
	}

	if (entry.flags & KAFNORMAL) {
	    entrys[i] |= 0x1;	/* user entry */

	    if (strlen(entry.userID.name) == 0) {
		if (verbose)
		    printf("Entry %d has zero length name\n", i);
		continue;
	    }
	    if (!DES_check_key_parity(ktc_to_cblock(&entry.key))
		|| DES_is_weak_key(ktc_to_cblock(&entry.key))) {
		fprintf(stderr, "Entry %d, %s, has bad key\n", i,
			EntryName(&entry));
		continue;
	    }

	    if (out) {
		RebuildEntry(&entry);
	    }

	} else if (entry.flags & KAFFREE) {
	    entrys[i] |= 0x2;	/* free entry */

	} else if (entry.flags & KAFOLDKEYS) {
	    entrys[i] |= 0x4;	/* old keys block */
	    /* Should check the structure of the oldkeys block? */

	} else {
	    if (index < header.eofPtr) {
		fprintf(stderr, "Entry %d is unrecognizable\n", i);
	    }
	}
    }

    /* Follow the hash chains */
    for (j = 0; j < HASHSIZE; j++) {
	for (index = header.nameHash[j]; index; index = entry.next) {
	    readDB(index, &entry, sizeof(entry));

	    /* check to see if the name is hashed correctly */
	    i = NameHash(&entry);
	    if (i != j) {
		fprintf(stderr,
			"Entry %" AFS_SIZET_FMT ", %s, found in hash chain %d (should be %d)\n",
			((index -
			  sizeof(struct kaheader)) / sizeof(struct kaentry)),
			EntryName(&entry), j, i);
	    }

	    /* Is it on another hash chain or circular hash chain */
	    i = (index - header.headerSize) / sizeof(entry);
	    if (entrys[i] & 0x10) {
		fprintf(stderr,
			"Entry %d, %s, hash index %d, was found on another hash chain\n",
			i, EntryName(&entry), j);
		if (entry.next)
		    fprintf(stderr, "Skipping rest of hash chain %d\n", j);
		else
		    fprintf(stderr, "No next entry in hash chain %d\n", j);
		code++;
		break;
	    }
	    entrys[i] |= 0x10;	/* On hash chain */
	}
    }

    /* Follow the free pointers */
    count = 0;
    for (index = header.freePtr; index; index = entry.next) {
	readDB(index, &entry, sizeof(entry));

	/* Is it on another chain or circular free chain */
	i = (index - header.headerSize) / sizeof(entry);
	if (entrys[i] & 0x20) {
	    fprintf(stderr, "Entry %d, %s, already found on free chain\n", i,
		    EntryName(&entry));
	    fprintf(stderr, "Skipping rest of free chain\n");
	    code++;
	    break;
	}
	entrys[i] |= 0x20;	/* On free chain */

	count++;
    }
    if (verbose)
	printf("Found %d free entries\n", count);

    /* Follow the oldkey blocks */
    count = 0;
    for (index = header.kvnoPtr; index; index = entry.next) {
	readDB(index, &entry, sizeof(entry));

	/* Is it on another chain or circular free chain */
	i = (index - header.headerSize) / sizeof(entry);
	if (entrys[i] & 0x40) {
	    fprintf(stderr, "Entry %d, %s, already found on olkeys chain\n",
		    i, EntryName(&entry));
	    fprintf(stderr, "Skipping rest of oldkeys chain\n");
	    code++;
	    break;
	}
	entrys[i] |= 0x40;	/* On free chain */

	count++;
    }
    if (verbose)
	printf("Found %d oldkey blocks\n", count);

    /* Now recheck all the blocks and see if they are allocated correctly
     * 0x1 --> User Entry           0x10 --> On hash chain
     * 0x2 --> Free Entry           0x20 --> On Free chain
     * 0x4 --> OldKeys Entry        0x40 --> On Oldkeys chain
     * 0x8 --> Past EOF
     */
    for (i = 0; i < nentries; i++) {
	j = entrys[i];
	if (j & 0x1) {		/* user entry */
	    if (!(j & 0x10))
		badEntry(j, i);	/* on hash chain? */
	    else if (j & 0xee)
		badEntry(j, i);	/* anything else? */
	} else if (j & 0x2) {	/* free entry */
	    if (!(j & 0x20))
		badEntry(j, i);	/* on free chain? */
	    else if (j & 0xdd)
		badEntry(j, i);	/* anything else? */
	} else if (j & 0x4) {	/* oldkeys entry */
	    if (!(j & 0x40))
		badEntry(j, i);	/* on oldkeys chain? */
	    else if (j & 0xbb)
		badEntry(j, i);	/* anything else? */
	} else if (j & 0x8) {	/* past eof */
	    if (j & 0xf7)
		badEntry(j, i);	/* anything else? */
	} else
	    badEntry(j, i);	/* anything else? */
    }

    exit(code != 0);
}