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