001
014
015 package com.liferay.portal.security.ntlm;
016
017 import com.liferay.portal.security.ntlm.msrpc.NetlogonAuthenticator;
018 import com.liferay.portal.security.ntlm.msrpc.NetrServerAuthenticate3;
019 import com.liferay.portal.security.ntlm.msrpc.NetrServerReqChallenge;
020
021 import java.io.IOException;
022
023 import java.security.MessageDigest;
024 import java.security.NoSuchAlgorithmException;
025 import java.security.SecureRandom;
026
027 import java.util.Arrays;
028
029 import jcifs.dcerpc.DcerpcHandle;
030
031 import jcifs.smb.NtlmPasswordAuthentication;
032
033 import jcifs.util.DES;
034 import jcifs.util.Encdec;
035 import jcifs.util.HMACT64;
036 import jcifs.util.MD4;
037
038
041 public class NetlogonConnection {
042
043 public NetlogonAuthenticator computeNetlogonAuthenticator() {
044 int timestamp = (int)System.currentTimeMillis();
045
046 int input = Encdec.dec_uint32le(_clientCredential, 0) + timestamp;
047
048 Encdec.enc_uint32le(input, _clientCredential, 0);
049
050 byte[] credential = computeNetlogonCredential(
051 _clientCredential, _sessionKey);
052
053 return new NetlogonAuthenticator(credential, timestamp);
054 }
055
056 public void connect(
057 String domainController, String domainControllerName,
058 NtlmServiceAccount ntlmServiceAccount, SecureRandom secureRandom)
059 throws IOException, NtlmLogonException, NoSuchAlgorithmException {
060
061 NtlmPasswordAuthentication ntlmPasswordAuthentication =
062 new NtlmPasswordAuthentication(
063 null, ntlmServiceAccount.getAccount(),
064 ntlmServiceAccount.getPassword());
065
066 String endpoint = "ncacn_np:" + domainController + "[\\PIPE\\NETLOGON]";
067
068 DcerpcHandle dcerpcHandle = DcerpcHandle.getHandle(
069 endpoint, ntlmPasswordAuthentication);
070
071 setDcerpcHandle(dcerpcHandle);
072
073 dcerpcHandle.bind();
074
075 byte[] clientChallenge = new byte[8];
076
077 secureRandom.nextBytes(clientChallenge);
078
079 NetrServerReqChallenge netrServerReqChallenge =
080 new NetrServerReqChallenge(
081 domainControllerName, ntlmServiceAccount.getComputerName(),
082 clientChallenge, new byte[8]);
083
084 dcerpcHandle.sendrecv(netrServerReqChallenge);
085
086 MD4 md4 = new MD4();
087
088 md4.update(ntlmServiceAccount.getPassword().getBytes("UTF-16LE"));
089
090 byte[] sessionKey = computeSessionKey(
091 md4.digest(), clientChallenge,
092 netrServerReqChallenge.getServerChallenge());
093
094 byte[] clientCredential = computeNetlogonCredential(
095 clientChallenge, sessionKey);
096
097 NetrServerAuthenticate3 netrServerAuthenticate3 =
098 new NetrServerAuthenticate3(
099 domainControllerName, ntlmServiceAccount.getAccountName(), 2,
100 ntlmServiceAccount.getComputerName(), clientCredential,
101 new byte[8], 0xFFFFFFFF);
102
103 dcerpcHandle.sendrecv(netrServerAuthenticate3);
104
105 byte[] serverCredential = computeNetlogonCredential(
106 netrServerReqChallenge.getServerChallenge(), sessionKey);
107
108 if (!Arrays.equals(
109 serverCredential,
110 netrServerAuthenticate3.getServerCredential())) {
111
112 throw new NtlmLogonException("Session key negotiation failed");
113 }
114
115 _clientCredential = clientCredential;
116 _sessionKey = sessionKey;
117 }
118
119 public void disconnect() throws IOException {
120 if (_dcerpcHandle != null) {
121 _dcerpcHandle.close();
122 }
123 }
124
125 public byte[] getClientCredential() {
126 return _clientCredential;
127 }
128
129 public DcerpcHandle getDcerpcHandle() {
130 return _dcerpcHandle;
131 }
132
133 public byte[] getSessionKey() {
134 return _sessionKey;
135 }
136
137 public void setDcerpcHandle(DcerpcHandle dcerpcHandle) {
138 _dcerpcHandle = dcerpcHandle;
139 }
140
141 protected byte[] computeNetlogonCredential(
142 byte[] input, byte[] sessionKey) {
143
144 byte[] k1 = new byte[7];
145 byte[] k2 = new byte[7];
146
147 System.arraycopy(sessionKey, 0, k1, 0, 7);
148 System.arraycopy(sessionKey, 7, k2, 0, 7);
149
150 DES k3 = new DES(k1);
151 DES k4 = new DES(k2);
152
153 byte[] output1 = new byte[8];
154 byte[] output2 = new byte[8];
155
156 k3.encrypt(input, output1);
157 k4.encrypt(output1, output2);
158
159 return output2;
160 }
161
162 protected byte[] computeSessionKey(
163 byte[] sharedSecret, byte[] clientChallenge, byte[] serverChallenge)
164 throws NoSuchAlgorithmException {
165
166 MessageDigest messageDigest = MessageDigest.getInstance("MD5");
167
168 byte[] zeroes = {0, 0, 0, 0};
169
170 messageDigest.update(zeroes, 0, 4);
171 messageDigest.update(clientChallenge, 0, 8);
172 messageDigest.update(serverChallenge, 0, 8);
173
174 HMACT64 hmact64 = new HMACT64(sharedSecret);
175
176 hmact64.update(messageDigest.digest());
177
178 return hmact64.digest();
179 }
180
181 private byte[] _clientCredential;
182 private DcerpcHandle _dcerpcHandle;
183 private byte[] _sessionKey;
184
185 }