1
14
15 package com.liferay.portal.security.ntlm;
16
17 import com.liferay.portal.security.ntlm.msrpc.NetlogonAuthenticator;
18 import com.liferay.portal.security.ntlm.msrpc.NetrServerAuthenticate3;
19 import com.liferay.portal.security.ntlm.msrpc.NetrServerReqChallenge;
20
21 import java.io.IOException;
22
23 import java.security.MessageDigest;
24 import java.security.NoSuchAlgorithmException;
25 import java.security.SecureRandom;
26
27 import java.util.Arrays;
28
29 import jcifs.dcerpc.DcerpcHandle;
30
31 import jcifs.smb.NtlmPasswordAuthentication;
32
33 import jcifs.util.DES;
34 import jcifs.util.Encdec;
35 import jcifs.util.HMACT64;
36 import jcifs.util.MD4;
37
38
43 public class NetlogonConnection {
44
45 public NetlogonAuthenticator computeNetlogonAuthenticator() {
46 int timestamp = (int)System.currentTimeMillis();
47
48 int input = Encdec.dec_uint32le(_clientCredential, 0) + timestamp;
49
50 Encdec.enc_uint32le(input, _clientCredential, 0);
51
52 byte[] credential = computeNetlogonCredential(
53 _clientCredential, _sessionKey);
54
55 return new NetlogonAuthenticator(credential, timestamp);
56 }
57
58 public void connect(
59 String domainController, String domainControllerName,
60 NtlmServiceAccount ntlmServiceAccount, SecureRandom secureRandom)
61 throws IOException, NtlmLogonException, NoSuchAlgorithmException {
62
63 NtlmPasswordAuthentication ntlmPasswordAuthentication =
64 new NtlmPasswordAuthentication(
65 null, ntlmServiceAccount.getAccount(),
66 ntlmServiceAccount.getPassword());
67
68 String endpoint = "ncacn_np:" + domainController + "[\\PIPE\\NETLOGON]";
69
70 DcerpcHandle dcerpcHandle = DcerpcHandle.getHandle(
71 endpoint, ntlmPasswordAuthentication);
72
73 setDcerpcHandle(dcerpcHandle);
74
75 dcerpcHandle.bind();
76
77 byte[] clientChallenge = new byte[8];
78
79 secureRandom.nextBytes(clientChallenge);
80
81 NetrServerReqChallenge netrServerReqChallenge =
82 new NetrServerReqChallenge(
83 domainControllerName, ntlmServiceAccount.getComputerName(),
84 clientChallenge, new byte[8]);
85
86 dcerpcHandle.sendrecv(netrServerReqChallenge);
87
88 MD4 md4 = new MD4();
89
90 md4.update(ntlmServiceAccount.getPassword().getBytes("UTF-16LE"));
91
92 byte[] sessionKey = computeSessionKey(
93 md4.digest(), clientChallenge,
94 netrServerReqChallenge.getServerChallenge());
95
96 byte[] clientCredential = computeNetlogonCredential(
97 clientChallenge, sessionKey);
98
99 NetrServerAuthenticate3 netrServerAuthenticate3 =
100 new NetrServerAuthenticate3(
101 domainControllerName, ntlmServiceAccount.getAccountName(), 2,
102 ntlmServiceAccount.getComputerName(), clientCredential,
103 new byte[8], 0xFFFFFFFF);
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 byte[] _clientCredential;
184 private DcerpcHandle _dcerpcHandle;
185 private byte[] _sessionKey;
186
187 }