1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.security.ntlm;
16  
17  import com.liferay.portal.kernel.log.Log;
18  import com.liferay.portal.kernel.log.LogFactoryUtil;
19  import com.liferay.portal.security.ntlm.msrpc.NetlogonAuthenticator;
20  import com.liferay.portal.security.ntlm.msrpc.NetlogonIdentityInfo;
21  import com.liferay.portal.security.ntlm.msrpc.NetlogonNetworkInfo;
22  import com.liferay.portal.security.ntlm.msrpc.NetlogonValidationSamInfo;
23  import com.liferay.portal.security.ntlm.msrpc.NetrLogonSamLogon;
24  import com.liferay.portal.security.ntlm.msrpc.NetrServerAuthenticate3;
25  import com.liferay.portal.security.ntlm.msrpc.NetrServerReqChallenge;
26  
27  import java.io.IOException;
28  
29  import java.security.MessageDigest;
30  import java.security.NoSuchAlgorithmException;
31  import java.security.SecureRandom;
32  
33  import java.util.Arrays;
34  
35  import jcifs.dcerpc.DcerpcBinding;
36  import jcifs.dcerpc.DcerpcHandle;
37  import jcifs.dcerpc.UnicodeString;
38  
39  import jcifs.smb.NtlmPasswordAuthentication;
40  import jcifs.smb.SmbException;
41  
42  import jcifs.util.DES;
43  import jcifs.util.Encdec;
44  import jcifs.util.HMACT64;
45  import jcifs.util.MD4;
46  
47  /**
48   * <a href="Netlogon.java.html"><b><i>View Source</i></b></a>
49   *
50   * @author Marcellus Tavares
51   */
52  public class Netlogon {
53  
54      public Netlogon() {
55          DcerpcBinding.addInterface(
56              "netlogon", "12345678-1234-abcd-ef00-01234567cffb:1.0");
57      }
58  
59      public NtlmUserAccount logon(
60          String domain, String userName, String workstation,
61          byte[] serverChallenge, byte[] ntResponse, byte[] lmResponse) {
62  
63          try {
64              connect();
65  
66              NetlogonAuthenticator netlogonAuthenticator =
67                  computeNetlogonAuthenticator();
68  
69              NetlogonIdentityInfo netlogonIdentityInfo =
70                  new NetlogonIdentityInfo(
71                      domain, 0x00000820, 0, 0, userName, workstation);
72  
73              NetlogonNetworkInfo netlogonNetworkInfo = new NetlogonNetworkInfo(
74                  netlogonIdentityInfo, serverChallenge,  ntResponse, lmResponse);
75  
76              NetrLogonSamLogon netrLogonSamLogon = new NetrLogonSamLogon(
77                  _domainControllerName, _ntlmServiceAccount.getComputerName(),
78                  netlogonAuthenticator, new NetlogonAuthenticator(), 2,
79                  netlogonNetworkInfo, 2, new NetlogonValidationSamInfo(), 0);
80  
81              _handle.sendrecv(netrLogonSamLogon);
82  
83              if (netrLogonSamLogon.getStatus() == 0) {
84                  NetlogonValidationSamInfo netlogonValidationSamInfo =
85                      netrLogonSamLogon.getNetlogonValidationSamInfo();
86  
87                  UnicodeString name = new UnicodeString(
88                      netlogonValidationSamInfo.getEffectiveName(), false);
89  
90                  return new NtlmUserAccount(name.toString());
91              }
92              else {
93                  SmbException smbe = new SmbException(
94                      netrLogonSamLogon.getStatus(), false);
95  
96                  _log.warn(smbe);
97              }
98          }
99          catch (Exception e) {
100             _log.error(e);
101         }
102         finally {
103             try {
104                 disconnect();
105             }
106             catch (Exception e) {
107                 _log.error(e);
108             }
109         }
110 
111         return null;
112     }
113 
114     public void setConfiguration(
115         String domainController, String domainControllerName,
116         NtlmServiceAccount ntlmServiceAccount) {
117 
118         _domainController = domainController;
119         _domainControllerName = domainControllerName;
120         _ntlmServiceAccount = ntlmServiceAccount;
121     }
122 
123     protected NetlogonAuthenticator computeNetlogonAuthenticator() {
124         int timestamp = (int)System.currentTimeMillis();
125         int input = Encdec.dec_uint32le(_clientCredential, 0) + timestamp;
126 
127         Encdec.enc_uint32le(input, _clientCredential, 0);
128 
129         byte[] credential = computeNetlogonCredential(
130             _clientCredential, _sessionKey);
131 
132         return new NetlogonAuthenticator(credential, timestamp);
133     }
134 
135     protected byte[] computeNetlogonCredential(
136         byte[] input, byte[] sessionKey) {
137 
138         byte[] k1 = new byte[7];
139         byte[] k2 = new byte[7];
140 
141         System.arraycopy(sessionKey, 0, k1, 0, 7);
142         System.arraycopy(sessionKey, 7, k2, 0, 7);
143 
144         DES k3 = new DES(k1);
145         DES k4 = new DES(k2);
146 
147         byte[] output1 = new byte[8];
148         byte[] output2 = new byte[8];
149 
150         k3.encrypt(input, output1);
151         k4.encrypt(output1, output2);
152 
153         return output2;
154     }
155 
156     protected byte[] computeSessionKey(
157         byte[] sharedSecret, byte[] clientChallenge, byte[] serverChallenge) {
158 
159         try {
160             MessageDigest messageDigest = MessageDigest.getInstance("MD5");
161 
162             byte[] zeroes = {0, 0, 0, 0};
163 
164             messageDigest.update(zeroes, 0, 4);
165             messageDigest.update(clientChallenge, 0, 8);
166             messageDigest.update(serverChallenge, 0, 8);
167 
168             HMACT64 hmact64 = new HMACT64(sharedSecret);
169 
170             hmact64.update(messageDigest.digest());
171 
172             return hmact64.digest();
173         }
174         catch (NoSuchAlgorithmException nsae) {
175             _log.error(nsae);
176         }
177 
178         return null;
179     }
180 
181     protected void connect() throws IOException {
182         NtlmPasswordAuthentication ntlmPasswordAuthentication =
183             new NtlmPasswordAuthentication(
184                 null, _ntlmServiceAccount.getAccount(),
185                 _ntlmServiceAccount.getPassword());
186 
187          String endpoint =
188              "ncacn_np:" + _domainController + "[\\PIPE\\NETLOGON]";
189 
190         _handle = DcerpcHandle.getHandle(endpoint, ntlmPasswordAuthentication);
191 
192         _handle.bind();
193 
194         byte[] clientChallenge = new byte[8];
195 
196         _secureRandom.nextBytes(clientChallenge);
197 
198         NetrServerReqChallenge netrServerReqChallenge =
199             new NetrServerReqChallenge(
200                 _domainControllerName, _ntlmServiceAccount.getComputerName(),
201                 clientChallenge, new byte[8]);
202 
203         _handle.sendrecv(netrServerReqChallenge);
204 
205         MD4 md4 = new MD4();
206 
207         md4.update(_ntlmServiceAccount.getPassword().getBytes("UTF-16LE"));
208 
209         byte[] sessionKey = computeSessionKey(
210             md4.digest(), clientChallenge,
211             netrServerReqChallenge.getServerChallenge());
212 
213         byte[] clientCredential = computeNetlogonCredential(
214             clientChallenge, sessionKey);
215 
216         NetrServerAuthenticate3 netrServerAuthenticate3 =
217             new NetrServerAuthenticate3(
218                 _domainControllerName, _ntlmServiceAccount.getAccountName(), 2,
219                 _ntlmServiceAccount.getComputerName(), clientCredential,
220                 new byte[8], 0xFFFFFFFF);
221 
222         _handle.sendrecv(netrServerAuthenticate3);
223 
224         byte[] serverCredential = computeNetlogonCredential(
225             netrServerReqChallenge.getServerChallenge(), sessionKey);
226 
227         if (!Arrays.equals(
228                 serverCredential,
229                 netrServerAuthenticate3.getServerCredential())) {
230 
231             _log.error("Session key negotiation failed");
232 
233             return;
234         }
235 
236         _clientCredential = clientCredential;
237         _sessionKey = sessionKey;
238     }
239 
240     protected void disconnect() throws IOException {
241         if (_handle != null) {
242             _handle.close();
243 
244             _handle = null;
245         }
246     }
247 
248     private static Log _log = LogFactoryUtil.getLog(Netlogon.class);
249 
250     private byte[] _clientCredential;
251     private String _domainController;
252     private String _domainControllerName;
253     private DcerpcHandle _handle;
254     private NtlmServiceAccount _ntlmServiceAccount;
255     private SecureRandom _secureRandom = new SecureRandom();
256     private byte[] _sessionKey;
257 
258 }