/*
* ====================================================================
* Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.util.jna;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.util.SVNBase64;
import org.tmatesoft.svn.core.internal.util.jna.ISVNSecurityLibrary.SEC_WINNT_AUTH_IDENTITY;
import org.tmatesoft.svn.core.internal.util.jna.ISVNSecurityLibrary.SecBuffer;
import org.tmatesoft.svn.core.internal.util.jna.ISVNSecurityLibrary.SecBufferDesc;
import org.tmatesoft.svn.core.internal.util.jna.ISVNSecurityLibrary.SecHandle;
import org.tmatesoft.svn.core.internal.util.jna.ISVNSecurityLibrary.TimeStamp;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
import com.sun.jna.Memory;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
/**
* @version 1.1.2
* @author TMate Software Ltd.
*/
public class SVNWinSecurity {
public static boolean isNativeLibraryAvailable() {
return JNALibraryLoader.getSecurityLibrary() != null;
}
public static SVNNTSecurityParameters getSecurityParams(String userName, String password,
String ntDomain) {
SecHandle crdHandle = getCredentialsHandle(userName, password, ntDomain);
if (crdHandle == null) {
return null;
}
SVNNTSecurityParameters secParams = new SVNNTSecurityParameters();
secParams.myUsername = userName;
secParams.myPassword = password;
secParams.myNTDomain = ntDomain;
secParams.myState = 0;
secParams.myCrdHandle = crdHandle;
return secParams;
}
public static String getAuthHeader(String token, SVNNTSecurityParameters params) throws SVNException {
byte[] input = null;
if (token != null) {
StringBuffer tokenBuffer = new StringBuffer(token);
byte[] tmp = new byte[tokenBuffer.length()];
StringBuffer sb = SVNBase64.normalizeBase64(tokenBuffer);
int resultLength = SVNBase64.base64ToByteArray(sb, tmp);
input = new byte[resultLength];
System.arraycopy(tmp, 0, input, 0, resultLength);
}
byte[] nextTokenBytes = getNextToken(params, input);
if (nextTokenBytes == null) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR,
"Internal authentication error");
SVNErrorManager.error(err, SVNLogType.DEFAULT);
}
return SVNBase64.byteArrayToBase64(nextTokenBytes);
}
private static byte[] getNextToken(SVNNTSecurityParameters params, byte[] lastToken) {
ISVNSecurityLibrary library = JNALibraryLoader.getSecurityLibrary();
if (library == null) {
return null;
}
SecHandle newContext = null;
SecHandle pContext = params.myCtxHandle;
if (pContext == null) {
newContext = new SecHandle();
newContext.dwLower = new NativeLong(0);
newContext.dwUpper = new NativeLong(0);
newContext.write();
params.myCtxHandle = newContext;
} else {
newContext = pContext;
}
final int bufferSize = 8192;
SecBuffer outSecBuffer = new SecBuffer();
outSecBuffer.cbBuffer = new NativeLong(bufferSize);
outSecBuffer.BufferType = new NativeLong(ISVNSecurityLibrary.SECBUFFER_TOKEN);
outSecBuffer.pvBuffer = new Memory(bufferSize);
outSecBuffer.write();
SecBufferDesc outBufferDescription = new SecBufferDesc();
outBufferDescription.ulVersion = new NativeLong(0);
outBufferDescription.cBuffers = new NativeLong(1);
outBufferDescription.pBuffers = outSecBuffer.getPointer();
outBufferDescription.write();
SecBufferDesc inBufferDescription = null;
SecBuffer inSecBuffer = null;
if (lastToken != null) {
inSecBuffer = new SecBuffer();
inSecBuffer.cbBuffer = new NativeLong(lastToken.length);
inSecBuffer.BufferType = new NativeLong(ISVNSecurityLibrary.SECBUFFER_TOKEN);
inSecBuffer.pvBuffer = new Memory(lastToken.length);
inSecBuffer.pvBuffer.write(0, lastToken, 0, lastToken.length);
inSecBuffer.write();
inBufferDescription = new SecBufferDesc();
inBufferDescription.ulVersion = new NativeLong(0);
inBufferDescription.cBuffers = new NativeLong(1);
inBufferDescription.pBuffers = inSecBuffer.getPointer();
inBufferDescription.write();
}
Pointer contextAttributes = new Memory(NativeLong.SIZE);
TimeStamp ltime = new TimeStamp();
ltime.HighPart = new NativeLong(0);
ltime.LowPart = new NativeLong(0);
ltime.write();
int securityStatus = library.InitializeSecurityContextW(params.myCrdHandle.getPointer(),
pContext != null ? pContext.getPointer() : Pointer.NULL,
null,
new NativeLong(0),
new NativeLong(0),
new NativeLong(ISVNSecurityLibrary.SECURITY_NATIVE_DREP),
lastToken != null ? inBufferDescription.getPointer() : Pointer.NULL,
new NativeLong(0),
newContext.getPointer(),
outBufferDescription.getPointer(),
contextAttributes,
ltime.getPointer());
if (securityStatus < 0) {
endSequence(params);
return null;
}
newContext.read();
params.myCtxHandle.read();
if (securityStatus == ISVNSecurityLibrary.SEC_I_COMPLETE_NEEDED ||
securityStatus == ISVNSecurityLibrary.SEC_I_COMPLETE_AND_CONTINUE) {
outBufferDescription.read();
securityStatus = library.CompleteAuthToken(params.myCtxHandle.getPointer(),
outBufferDescription.getPointer());
if (securityStatus < 0) {
endSequence(params);
return null;
}
}
byte[] result = null;
outBufferDescription.read();
outSecBuffer.read();
boolean sequenceIsEnded = false;
if (outSecBuffer.cbBuffer.intValue() > 0) {
result = outSecBuffer.pvBuffer.getByteArray(0, outSecBuffer.cbBuffer.intValue());
if (lastToken != null) {
endSequence(params);
sequenceIsEnded = true;
}
}
if (securityStatus != ISVNSecurityLibrary.SEC_I_CONTINUE_NEEDED &&
securityStatus == ISVNSecurityLibrary.SEC_I_COMPLETE_AND_CONTINUE) {
if (!sequenceIsEnded) {
endSequence(params);
}
}
return result;
}
private static SecHandle getCredentialsHandle(String user, String password, String domain) {
ISVNSecurityLibrary library = JNALibraryLoader.getSecurityLibrary();
if (library == null) {
return null;
}
SEC_WINNT_AUTH_IDENTITY authIdentity = null;
if (user != null || password != null || domain != null) {
authIdentity = new SEC_WINNT_AUTH_IDENTITY();
if (user != null) {
authIdentity.User = new WString(user);
authIdentity.UserLength = new NativeLong(user.length());
}
if (password != null) {
authIdentity.Password = new WString(password);
authIdentity.PasswordLength = new NativeLong(password.length());
}
if (domain != null) {
authIdentity.Domain = new WString(domain);
authIdentity.DomainLength = new NativeLong(domain.length());
}
authIdentity.Flags = new NativeLong(ISVNSecurityLibrary.SEC_WINNT_AUTH_IDENTITY_UNICODE);
authIdentity.write();
}
SecHandle pCred = new SecHandle();
pCred.dwLower = new NativeLong(0);
pCred.dwUpper = new NativeLong(0);
pCred.write();
ISVNSecurityLibrary.TimeStamp ltime = new ISVNSecurityLibrary.TimeStamp();
ltime.HighPart = new NativeLong(0);
ltime.LowPart = new NativeLong(0);
ltime.write();
int securityStatus = library.AcquireCredentialsHandleW(null, new WString("NTLM"),
new NativeLong(ISVNSecurityLibrary.SECPKG_CRED_OUTBOUND), Pointer.NULL,
authIdentity != null ? authIdentity.getPointer() : Pointer.NULL,
Pointer.NULL, Pointer.NULL, pCred.getPointer(), ltime.getPointer());
if (securityStatus == 0) {
pCred.read();
return pCred;
}
return null;
}
private static void endSequence(SVNNTSecurityParameters params) {
ISVNSecurityLibrary library = JNALibraryLoader.getSecurityLibrary();
if (library == null) {
return;
}
if (params.myCrdHandle != null) {
library.FreeCredentialsHandle(params.myCrdHandle.getPointer());
params.myCrdHandle = null;
}
if (params.myCtxHandle != null) {
library.DeleteSecurityContext(params.myCtxHandle.getPointer());
params.myCtxHandle = null;
}
}
public static class SVNNTSecurityParameters {
public String myUsername;
public String myPassword;
public String myNTDomain;
public int myState;
public SecHandle myCrdHandle;
public SecHandle myCtxHandle;
}
}