001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.kerberos.credentials.cache; 021 022 023import java.io.DataOutputStream; 024import java.io.IOException; 025import java.io.OutputStream; 026import java.util.List; 027 028import org.apache.directory.api.util.Strings; 029import org.apache.directory.shared.kerberos.KerberosTime; 030import org.apache.directory.shared.kerberos.codec.KerberosEncoder; 031import org.apache.directory.shared.kerberos.components.AuthorizationData; 032import org.apache.directory.shared.kerberos.components.AuthorizationDataEntry; 033import org.apache.directory.shared.kerberos.components.EncryptionKey; 034import org.apache.directory.shared.kerberos.components.HostAddress; 035import org.apache.directory.shared.kerberos.components.HostAddresses; 036import org.apache.directory.shared.kerberos.components.PrincipalName; 037import org.apache.directory.shared.kerberos.messages.Ticket; 038 039 040/** 041 * Writing credentials cache according to FCC format by reference the following 042 * https://www.gnu.org/software/shishi/manual/html_node/The-Credential-Cache-Binary-File-Format.html 043 * 044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 045 */ 046public class CacheOutputStream extends DataOutputStream 047{ 048 049 public CacheOutputStream( OutputStream out ) 050 { 051 super( out ); 052 } 053 054 055 public void write( CredentialsCache credCache ) throws IOException 056 { 057 /** 058 * Currently we always write using this version to limit the test effort. 059 * This version seems to be the easiest to be compatible with MIT tools. 060 * In future we might allow to specify the format version to write if necessary. 061 */ 062 int writeVersion = CredentialsCacheConstants.FCC_FVNO_3; 063 064 writeVersion( writeVersion ); 065 066 if ( writeVersion == CredentialsCacheConstants.FCC_FVNO_4 ) 067 { 068 writeTags( credCache.getTags() ); 069 } 070 071 writePrincipal( credCache.getPrimaryPrincipalName(), writeVersion ); 072 073 List<Credentials> credentialsList = credCache.getCredsList(); 074 if ( credentialsList != null ) 075 { 076 for ( Credentials cred : credentialsList ) 077 { 078 writeCredentials( cred, writeVersion ); 079 } 080 } 081 } 082 083 084 private void writeVersion( int version ) throws IOException 085 { 086 writeShort( version ); 087 } 088 089 090 private void writeTags( List<Tag> tags ) throws IOException 091 { 092 int length = 0; 093 if ( tags != null ) 094 { 095 for ( Tag tag : tags ) 096 { 097 if ( tag.tag != CredentialsCacheConstants.FCC_TAG_DELTATIME ) 098 { 099 continue; 100 } 101 length += tag.length; 102 } 103 } 104 105 writeShort( length ); 106 107 if ( tags != null ) 108 { 109 for ( Tag tag : tags ) 110 { 111 if ( tag.tag != CredentialsCacheConstants.FCC_TAG_DELTATIME ) 112 { 113 continue; 114 } 115 writeTag( tag ); 116 } 117 } 118 } 119 120 121 private void writeTag( Tag tag ) throws IOException 122 { 123 writeShort( tag.tag ); 124 writeShort( tag.length ); 125 writeInt( tag.time ); 126 writeInt( tag.usec ); 127 } 128 129 130 private void writePrincipal( PrincipalName pname, int version ) throws IOException 131 { 132 int num = pname.getNames().size(); 133 134 if ( version != CredentialsCacheConstants.FCC_FVNO_1 ) 135 { 136 writeInt( pname.getNameType().getValue() ); 137 } 138 else 139 { 140 num++; 141 } 142 143 writeInt( num ); 144 145 if ( pname.getRealm() != null ) 146 { 147 byte[] realmBytes = null; 148 realmBytes = Strings.getBytesUtf8( pname.getRealm() ); 149 writeInt( realmBytes.length ); 150 write( realmBytes ); 151 } 152 else 153 { 154 writeInt( 0 ); 155 } 156 157 byte[] bytes = null; 158 for ( int i = 0; i < pname.getNames().size(); i++ ) 159 { 160 bytes = Strings.getBytesUtf8( pname.getNames().get( i ) ); 161 writeInt( bytes.length ); 162 write( bytes ); 163 } 164 } 165 166 167 private void writeCredentials( Credentials creds, int version ) throws IOException 168 { 169 writePrincipal( creds.getClientName(), version ); 170 writePrincipal( creds.getServerName(), version ); 171 writeKey( creds.getKey(), version ); 172 173 writeKerberosTime( creds.getAuthTime() ); 174 writeKerberosTime( creds.getStartTime() ); 175 writeKerberosTime( creds.getEndTime() ); 176 writeKerberosTime( creds.getRenewTill() ); 177 178 writeByte( creds.isEncInSKey() ? 1 : 0 ); 179 180 writeInt( creds.getFlags().getIntValue() ); 181 182 writeAddrs( creds.getClientAddresses() ); 183 writeAuth( creds.getAuthzData() ); 184 185 writeTicket( creds.getTicket() ); 186 writeTicket( creds.getSecondTicket() ); 187 } 188 189 190 private void writeKerberosTime( KerberosTime ktime ) throws IOException 191 { 192 int time = 0; 193 if ( ktime != null ) 194 { 195 time = ( int ) ( ktime.getTime() / 1000 ); 196 } 197 writeInt( time ); 198 } 199 200 201 private void writeKey( EncryptionKey key, int version ) throws IOException 202 { 203 writeShort( key.getKeyType().getValue() ); 204 if ( version == CredentialsCacheConstants.FCC_FVNO_3 ) 205 { 206 writeShort( key.getKeyType().getValue() ); 207 } 208 // It's not correct with "uint16_t keylen", instead "uint32_t keylen" in keyblock 209 writeInt( key.getKeyValue().length ); 210 write( key.getKeyValue() ); 211 } 212 213 214 private void writeAddrs( HostAddresses addresses ) throws IOException 215 { 216 if ( addresses == null ) 217 { 218 writeInt( 0 ); 219 } 220 else 221 { 222 HostAddress[] addrs = addresses.getAddresses(); 223 write( addrs.length ); 224 for ( int i = 0; i < addrs.length; i++ ) 225 { 226 write( addrs[i].getAddrType().getValue() ); 227 write( addrs[i].getAddress().length ); 228 write( addrs[i].getAddress(), 0, 229 addrs[i].getAddress().length ); 230 } 231 } 232 } 233 234 235 private void writeAuth( AuthorizationData authData ) throws IOException 236 { 237 if ( authData == null ) 238 { 239 writeInt( 0 ); 240 } 241 else 242 { 243 for ( AuthorizationDataEntry ade : authData.getAuthorizationData() ) 244 { 245 write( ade.getAdType().getValue() ); 246 write( ade.getAdData().length ); 247 write( ade.getAdData() ); 248 } 249 } 250 } 251 252 253 private void writeTicket( Ticket t ) throws IOException 254 { 255 if ( t == null ) 256 { 257 writeInt( 0 ); 258 } 259 else 260 { 261 byte[] bytes = KerberosEncoder.encode( t, false ).array(); 262 writeInt( bytes.length ); 263 write( bytes ); 264 } 265 } 266}