package org.apache.kerberos.kerb.keytab; import org.apache.kerberos.kerb.spec.common.EncryptionKey; import org.apache.kerberos.kerb.spec.common.EncryptionType; import org.apache.kerberos.kerb.spec.common.PrincipalName; import java.io.*; import java.nio.ByteBuffer; import java.util.*; public class Keytab implements KrbKeytab { public static final int V501 = 0x0501; public static final int V502 = 0x0502; private int version = V502; private Map<PrincipalName, List<KeytabEntry>> principalEntries; public Keytab() { this.principalEntries = new HashMap<PrincipalName, List<KeytabEntry>>(); } @Override public List<PrincipalName> getPrincipals() { return new ArrayList<PrincipalName>(principalEntries.keySet()); } @Override public void addKeytabEntries(List<KeytabEntry> entries) { for (KeytabEntry entry : entries) { addEntry(entry); } } @Override public void removeKeytabEntries(PrincipalName principal) { principalEntries.remove(principal); } @Override public void removeKeytabEntry(KeytabEntry entry) { PrincipalName principal = entry.getPrincipal(); List<KeytabEntry> entries = principalEntries.get(principal); if (entries != null) { Iterator<KeytabEntry> iter = entries.iterator(); KeytabEntry tmp; while (iter.hasNext()) { tmp = iter.next(); if (entry.equals(tmp)) { iter.remove(); break; } } } } @Override public List<KeytabEntry> getKeytabEntries(PrincipalName principal) { return principalEntries.get(principal); } @Override public EncryptionKey getKey(PrincipalName principal, EncryptionType keyType) { List<KeytabEntry> entries = getKeytabEntries(principal); for (KeytabEntry ke : entries) { if (ke.getKey().getKeyType() == keyType) { return ke.getKey(); } } return null; } @Override public void load(File keytabFile) throws IOException { if (! keytabFile.exists() || ! keytabFile.canRead()) { throw new IllegalArgumentException("Invalid keytab file: " + keytabFile.getAbsolutePath()); } InputStream is = new FileInputStream(keytabFile); load(is); } @Override public void load(InputStream inputStream) throws IOException { if (inputStream == null) { throw new IllegalArgumentException("Invalid and null input stream"); } KeytabInputStream kis = new KeytabInputStream(inputStream); doLoad(kis); } private void doLoad(KeytabInputStream kis) throws IOException { this.version = readVersion(kis); List<KeytabEntry> entries = readEntries(kis); addKeytabEntries(entries); } @Override public void addEntry(KeytabEntry entry) { PrincipalName principal = entry.getPrincipal(); List<KeytabEntry> entries = principalEntries.get(principal); if (entries == null) { entries = new ArrayList<KeytabEntry>(); principalEntries.put(principal, entries); } entries.add(entry); } private int readVersion(KeytabInputStream kis) throws IOException { return kis.readShort(); } private List<KeytabEntry> readEntries(KeytabInputStream kis) throws IOException { List<KeytabEntry> entries = new ArrayList<KeytabEntry>(); int entrySize; ByteBuffer entryData; KeytabEntry entry; while (kis.available() > 0) { entrySize = kis.readInt(); if (kis.available() < entrySize) { throw new IOException("Bad input stream with less data than expected: " + entrySize); } entry = readEntry(kis); entries.add(entry); } return entries; } private KeytabEntry readEntry(KeytabInputStream kis) throws IOException { KeytabEntry entry = new KeytabEntry(); entry.load(kis, version); return entry; } @Override public void store(File keytabFile) throws IOException { OutputStream outputStream = new FileOutputStream(keytabFile); store(outputStream); } @Override public void store(OutputStream outputStream) throws IOException { if (outputStream == null) { throw new IllegalArgumentException("Invalid and null output stream"); } KeytabOutputStream kos = new KeytabOutputStream(outputStream); writeVersion(kos); writeEntries(kos); } private void writeVersion(KeytabOutputStream kos) throws IOException { byte[] bytes = new byte[2]; bytes[0] = (byte) 0x05; bytes[1] = version == V502 ? (byte) 0x02 : (byte) 0x01; kos.write(bytes); } private void writeEntries(KeytabOutputStream kos) throws IOException { for (PrincipalName principal : principalEntries.keySet()) { for (KeytabEntry entry : principalEntries.get(principal)) { entry.store(kos); } } } }