1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
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  /**
39   * <a href="NetlogonConnection.java.html"><b><i>View Source</i></b></a>
40   *
41   * @author Michael C. Han
42   */
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 }