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