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