blob: dd6657abb5ee4d63399b5d102773d3c98061abe2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.kerberos.credentials.cache;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import org.apache.directory.server.kerberos.protocol.codec.KerberosEncoder;
import org.apache.directory.shared.kerberos.KerberosTime;
import org.apache.directory.shared.kerberos.components.AuthorizationData;
import org.apache.directory.shared.kerberos.components.AuthorizationDataEntry;
import org.apache.directory.shared.kerberos.components.EncryptionKey;
import org.apache.directory.shared.kerberos.components.HostAddress;
import org.apache.directory.shared.kerberos.components.HostAddresses;
import org.apache.directory.shared.kerberos.components.PrincipalName;
import org.apache.directory.shared.kerberos.messages.Ticket;
/**
* Writing credentials cache according to FCC format by reference the following
* https://www.gnu.org/software/shishi/manual/html_node/The-Credential-Cache-Binary-File-Format.html
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class CacheOutputStream extends DataOutputStream
{
public CacheOutputStream( OutputStream out )
{
super( out );
}
public void write( CredentialsCache credCache ) throws IOException
{
/**
* Currently we always write using this version to limit the test effort.
* This version seems to be the easiest to be compatible with MIT tools.
* In future we might allow to specify the format version to write if necessary.
*/
int writeVersion = CredentialsCacheConstants.FCC_FVNO_3;
writeVersion( writeVersion );
if ( writeVersion == CredentialsCacheConstants.FCC_FVNO_4 )
{
writeTags( credCache.getTags() );
}
writePrincipal( credCache.getPrimaryPrincipalName(), writeVersion );
List<Credentials> credentialsList = credCache.getCredsList();
if ( credentialsList != null )
{
for ( Credentials cred : credentialsList )
{
writeCredentials( cred, writeVersion );
}
}
}
private void writeVersion( int version ) throws IOException
{
writeShort( version );
}
private void writeTags( List<Tag> tags ) throws IOException
{
int length = 0;
if ( tags != null )
{
for ( Tag tag : tags )
{
if ( tag.tag != CredentialsCacheConstants.FCC_TAG_DELTATIME )
{
continue;
}
length += tag.length;
}
}
writeShort( length );
if ( tags != null )
{
for ( Tag tag : tags )
{
if ( tag.tag != CredentialsCacheConstants.FCC_TAG_DELTATIME )
{
continue;
}
writeTag( tag );
}
}
}
private void writeTag( Tag tag ) throws IOException
{
writeShort( tag.tag );
writeShort( tag.length );
writeInt( tag.time );
writeInt( tag.usec );
}
private void writePrincipal( PrincipalName pname, int version ) throws IOException
{
int num = pname.getNames().size();
if ( version != CredentialsCacheConstants.FCC_FVNO_1 )
{
writeInt( pname.getNameType().getValue() );
}
else
{
num++;
}
writeInt( num );
if ( pname.getRealm() != null)
{
byte[] realmBytes = null;
realmBytes = pname.getRealm().getBytes();
writeInt( realmBytes.length );
write( realmBytes );
}
else
{
writeInt( 0 );
}
byte[] bytes = null;
for ( int i = 0; i < pname.getNames().size(); i++ )
{
bytes = pname.getNames().get( i ).getBytes();
writeInt( bytes.length );
write( bytes );
}
}
private void writeCredentials( Credentials creds, int version ) throws IOException
{
writePrincipal( creds.getClientName(), version );
writePrincipal( creds.getServerName(), version );
writeKey( creds.getKey(), version );
writeKerberosTime( creds.getAuthTime() );
writeKerberosTime( creds.getStartTime() );
writeKerberosTime( creds.getEndTime() );
writeKerberosTime( creds.getRenewTill() );
writeByte( creds.isEncInSKey() ? 1 : 0);
writeInt( creds.getFlags().getIntValue() );
writeAddrs( creds.getClientAddresses() );
writeAuth( creds.getAuthzData() );
writeTicket( creds.getTicket() );
writeTicket( creds.getSecondTicket() );
}
private void writeKerberosTime( KerberosTime ktime) throws IOException
{
int time = 0;
if (ktime != null)
{
time = (int) ( ktime.getTime() / 1000 );
}
writeInt( time );
}
private void writeKey( EncryptionKey key, int version ) throws IOException
{
writeShort( key.getKeyType().getValue());
if ( version == CredentialsCacheConstants.FCC_FVNO_3 )
{
writeShort( key.getKeyType().getValue() );
}
// It's not correct with "uint16_t keylen", instead "uint32_t keylen" in keyblock
writeInt( key.getKeyValue().length );
write( key.getKeyValue() );
}
private void writeAddrs( HostAddresses addresses ) throws IOException
{
if (addresses == null)
{
writeInt( 0 );
}
else
{
HostAddress[] addrs = addresses.getAddresses();
write( addrs.length );
for ( int i = 0; i < addrs.length; i++ )
{
write( addrs[i].getAddrType().getValue() );
write( addrs[i].getAddress().length );
write( addrs[i].getAddress(), 0,
addrs[i].getAddress().length );
}
}
}
private void writeAuth( AuthorizationData authData ) throws IOException
{
if ( authData == null )
{
writeInt( 0 );
}
else
{
for (AuthorizationDataEntry ade : authData.getAuthorizationData())
{
write(ade.getAdType().getValue());
write(ade.getAdData().length);
write(ade.getAdData());
}
}
}
private void writeTicket( Ticket t ) throws IOException
{
if (t == null)
{
writeInt( 0 );
}
else
{
byte[] bytes = KerberosEncoder.encode(t, false).array();
writeInt( bytes.length );
write( bytes );
}
}
}