KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jcifs > ntlmssp > Type3Message


1 /* jcifs smb client library in Java
2  * Copyright (C) 2002 "Michael B. Allen" <jcifs at samba dot org>
3  * "Eric Glass" <jcifs at samba dot org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package jcifs.ntlmssp;
21
22 import java.io.IOException JavaDoc;
23
24 import java.net.UnknownHostException JavaDoc;
25
26 import java.security.SecureRandom JavaDoc;
27
28 import jcifs.Config;
29
30 import jcifs.netbios.NbtAddress;
31
32 import jcifs.smb.NtlmPasswordAuthentication;
33
34 /**
35  * Represents an NTLMSSP Type-3 message.
36  */

37 public class Type3Message extends NtlmMessage {
38
39     private static final int DEFAULT_FLAGS;
40
41     private static final String JavaDoc DEFAULT_DOMAIN;
42
43     private static final String JavaDoc DEFAULT_USER;
44
45     private static final String JavaDoc DEFAULT_PASSWORD;
46
47     private static final String JavaDoc DEFAULT_WORKSTATION;
48
49     private static final int LM_COMPATIBILITY;
50
51     private static final SecureRandom JavaDoc RANDOM = new SecureRandom JavaDoc();
52
53     private byte[] lmResponse;
54
55     private byte[] ntResponse;
56
57     private String JavaDoc domain;
58
59     private String JavaDoc user;
60
61     private String JavaDoc workstation;
62
63     private byte[] sessionKey;
64
65     static {
66         DEFAULT_FLAGS = NTLMSSP_NEGOTIATE_NTLM |
67                 (Config.getBoolean("jcifs.smb.client.useUnicode", true) ?
68                         NTLMSSP_NEGOTIATE_UNICODE : NTLMSSP_NEGOTIATE_OEM);
69         DEFAULT_DOMAIN = Config.getProperty("jcifs.smb.client.domain", null);
70         DEFAULT_USER = Config.getProperty("jcifs.smb.client.username", null);
71         DEFAULT_PASSWORD = Config.getProperty("jcifs.smb.client.password",
72                 null);
73         String JavaDoc defaultWorkstation = null;
74         try {
75             defaultWorkstation = NbtAddress.getLocalHost().getHostName();
76         } catch (UnknownHostException JavaDoc ex) { }
77         DEFAULT_WORKSTATION = defaultWorkstation;
78         LM_COMPATIBILITY = Config.getInt("jcifs.smb.lmCompatibility", 0);
79     }
80
81     /**
82      * Creates a Type-3 message using default values from the current
83      * environment.
84      */

85     public Type3Message() {
86         setFlags(getDefaultFlags());
87         setDomain(getDefaultDomain());
88         setUser(getDefaultUser());
89         setWorkstation(getDefaultWorkstation());
90     }
91
92     /**
93      * Creates a Type-3 message in response to the given Type-2 message
94      * using default values from the current environment.
95      *
96      * @param type2 The Type-2 message which this represents a response to.
97      */

98     public Type3Message(Type2Message type2) {
99         setFlags(getDefaultFlags(type2));
100         setWorkstation(getDefaultWorkstation());
101         String JavaDoc domain = getDefaultDomain();
102         setDomain(domain);
103         String JavaDoc user = getDefaultUser();
104         setUser(user);
105         String JavaDoc password = getDefaultPassword();
106         switch (LM_COMPATIBILITY) {
107         case 0:
108         case 1:
109             setLMResponse(getLMResponse(type2, password));
110             setNTResponse(getNTResponse(type2, password));
111             break;
112         case 2:
113             byte[] nt = getNTResponse(type2, password);
114             setLMResponse(nt);
115             setNTResponse(nt);
116             break;
117         case 3:
118         case 4:
119         case 5:
120             byte[] clientChallenge = new byte[8];
121             RANDOM.nextBytes(clientChallenge);
122             setLMResponse(getLMv2Response(type2, domain, user, password,
123                     clientChallenge));
124             /*
125             setNTResponse(getNTLMv2Response(type2, domain, user, password,
126                     clientChallenge));
127             */

128             break;
129         default:
130             setLMResponse(getLMResponse(type2, password));
131             setNTResponse(getNTResponse(type2, password));
132         }
133     }
134
135     /**
136      * Creates a Type-3 message in response to the given Type-2 message.
137      *
138      * @param type2 The Type-2 message which this represents a response to.
139      * @param password The password to use when constructing the response.
140      * @param domain The domain in which the user has an account.
141      * @param user The username for the authenticating user.
142      * @param workstation The workstation from which authentication is
143      * taking place.
144      */

145     public Type3Message(Type2Message type2, String JavaDoc password, String JavaDoc domain,
146             String JavaDoc user, String JavaDoc workstation) {
147         setFlags(getDefaultFlags(type2));
148         setDomain(domain);
149         setUser(user);
150         setWorkstation(workstation);
151         switch (LM_COMPATIBILITY) {
152         case 0:
153         case 1:
154             setLMResponse(getLMResponse(type2, password));
155             setNTResponse(getNTResponse(type2, password));
156             break;
157         case 2:
158             byte[] nt = getNTResponse(type2, password);
159             setLMResponse(nt);
160             setNTResponse(nt);
161             break;
162         case 3:
163         case 4:
164         case 5:
165             byte[] clientChallenge = new byte[8];
166             RANDOM.nextBytes(clientChallenge);
167             setLMResponse(getLMv2Response(type2, domain, user, password,
168                     clientChallenge));
169             /*
170             setNTResponse(getNTLMv2Response(type2, domain, user, password,
171                     clientChallenge));
172             */

173             break;
174         default:
175             setLMResponse(getLMResponse(type2, password));
176             setNTResponse(getNTResponse(type2, password));
177         }
178     }
179
180     /**
181      * Creates a Type-3 message with the specified parameters.
182      *
183      * @param flags The flags to apply to this message.
184      * @param lmResponse The LanManager/LMv2 response.
185      * @param ntResponse The NT/NTLMv2 response.
186      * @param domain The domain in which the user has an account.
187      * @param user The username for the authenticating user.
188      * @param workstation The workstation from which authentication is
189      * taking place.
190      */

191     public Type3Message(int flags, byte[] lmResponse, byte[] ntResponse,
192             String JavaDoc domain, String JavaDoc user, String JavaDoc workstation) {
193         setFlags(flags);
194         setLMResponse(lmResponse);
195         setNTResponse(ntResponse);
196         setDomain(domain);
197         setUser(user);
198         setWorkstation(workstation);
199     }
200
201     /**
202      * Creates a Type-3 message using the given raw Type-3 material.
203      *
204      * @param material The raw Type-3 material used to construct this message.
205      * @throws IOException If an error occurs while parsing the material.
206      */

207     public Type3Message(byte[] material) throws IOException JavaDoc {
208         parse(material);
209     }
210
211     /**
212      * Returns the LanManager/LMv2 response.
213      *
214      * @return A <code>byte[]</code> containing the LanManager response.
215      */

216     public byte[] getLMResponse() {
217         return lmResponse;
218     }
219
220     /**
221      * Sets the LanManager/LMv2 response for this message.
222      *
223      * @param lmResponse The LanManager response.
224      */

225     public void setLMResponse(byte[] lmResponse) {
226         this.lmResponse = lmResponse;
227     }
228
229     /**
230      * Returns the NT/NTLMv2 response.
231      *
232      * @return A <code>byte[]</code> containing the NT/NTLMv2 response.
233      */

234     public byte[] getNTResponse() {
235         return ntResponse;
236     }
237
238     /**
239      * Sets the NT/NTLMv2 response for this message.
240      *
241      * @param ntResponse The NT/NTLMv2 response.
242      */

243     public void setNTResponse(byte[] ntResponse) {
244         this.ntResponse = ntResponse;
245     }
246
247     /**
248      * Returns the domain in which the user has an account.
249      *
250      * @return A <code>String</code> containing the domain for the user.
251      */

252     public String JavaDoc getDomain() {
253         return domain;
254     }
255
256     /**
257      * Sets the domain for this message.
258      *
259      * @param domain The domain.
260      */

261     public void setDomain(String JavaDoc domain) {
262         this.domain = domain;
263     }
264
265     /**
266      * Returns the username for the authenticating user.
267      *
268      * @return A <code>String</code> containing the user for this message.
269      */

270     public String JavaDoc getUser() {
271         return user;
272     }
273
274     /**
275      * Sets the user for this message.
276      *
277      * @param user The user.
278      */

279     public void setUser(String JavaDoc user) {
280         this.user = user;
281     }
282
283     /**
284      * Returns the workstation from which authentication is being performed.
285      *
286      * @return A <code>String</code> containing the workstation.
287      */

288     public String JavaDoc getWorkstation() {
289         return workstation;
290     }
291
292     /**
293      * Sets the workstation for this message.
294      *
295      * @param workstation The workstation.
296      */

297     public void setWorkstation(String JavaDoc workstation) {
298         this.workstation = workstation;
299     }
300
301     /**
302      * Returns the session key.
303      *
304      * @return A <code>byte[]</code> containing the session key.
305      */

306     public byte[] getSessionKey() {
307         return sessionKey;
308     }
309
310     /**
311      * Sets the session key.
312      *
313      * @param sessionKey The session key.
314      */

315     public void setSessionKey(byte[] sessionKey) {
316         this.sessionKey = sessionKey;
317     }
318
319     public byte[] toByteArray() {
320         try {
321             int flags = getFlags();
322             boolean unicode = (flags & NTLMSSP_NEGOTIATE_UNICODE) != 0;
323             String JavaDoc oem = unicode ? null : getOEMEncoding();
324             String JavaDoc domainName = getDomain();
325             byte[] domain = null;
326             if (domainName != null && domainName.length() != 0) {
327                 domain = unicode ?
328                         domainName.toUpperCase().getBytes("UnicodeLittleUnmarked") :
329                                 domainName.toUpperCase().getBytes(oem);
330             }
331             int domainLength = (domain != null) ? domain.length : 0;
332             String JavaDoc userName = getUser();
333             byte[] user = null;
334             if (userName != null && userName.length() != 0) {
335                 user = unicode ? userName.getBytes("UnicodeLittleUnmarked") :
336                         userName.toUpperCase().getBytes(oem);
337             }
338             int userLength = (user != null) ? user.length : 0;
339             String JavaDoc workstationName = getWorkstation();
340             byte[] workstation = null;
341             if (workstationName != null && workstationName.length() != 0) {
342                 workstation = unicode ?
343                         workstationName.getBytes("UnicodeLittleUnmarked") :
344                                 workstationName.toUpperCase().getBytes(oem);
345             }
346             int workstationLength = (workstation != null) ?
347                     workstation.length : 0;
348             byte[] lmResponse = getLMResponse();
349             int lmLength = (lmResponse != null) ? lmResponse.length : 0;
350             byte[] ntResponse = getNTResponse();
351             int ntLength = (ntResponse != null) ? ntResponse.length : 0;
352             byte[] sessionKey = getSessionKey();
353             int keyLength = (sessionKey != null) ? sessionKey.length : 0;
354             byte[] type3 = new byte[64 + domainLength + userLength +
355                     workstationLength + lmLength + ntLength + keyLength];
356             System.arraycopy(NTLMSSP_SIGNATURE, 0, type3, 0, 8);
357             writeULong(type3, 8, 3);
358             int offset = 64;
359             writeSecurityBuffer(type3, 12, offset, lmResponse);
360             offset += lmLength;
361             writeSecurityBuffer(type3, 20, offset, ntResponse);
362             offset += ntLength;
363             writeSecurityBuffer(type3, 28, offset, domain);
364             offset += domainLength;
365             writeSecurityBuffer(type3, 36, offset, user);
366             offset += userLength;
367             writeSecurityBuffer(type3, 44, offset, workstation);
368             offset += workstationLength;
369             writeSecurityBuffer(type3, 52, offset, sessionKey);
370             writeULong(type3, 60, flags);
371             return type3;
372         } catch (IOException JavaDoc ex) {
373             throw new IllegalStateException JavaDoc(ex.getMessage());
374         }
375     }
376
377     public String JavaDoc toString() {
378         String JavaDoc user = getUser();
379         String JavaDoc domain = getDomain();
380         String JavaDoc workstation = getWorkstation();
381         byte[] lmResponse = getLMResponse();
382         byte[] ntResponse = getNTResponse();
383         byte[] sessionKey = getSessionKey();
384         int flags = getFlags();
385         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
386         if (domain != null) {
387             buffer.append("domain: ").append(domain);
388         }
389         if (user != null) {
390             if (buffer.length() > 0) buffer.append("; ");
391             buffer.append("user: ").append(user);
392         }
393         if (workstation != null) {
394             if (buffer.length() > 0) buffer.append("; ");
395             buffer.append("workstation: ").append(workstation);
396         }
397         if (lmResponse != null) {
398             if (buffer.length() > 0) buffer.append("; ");
399             buffer.append("lmResponse: ");
400             buffer.append("0x");
401             for (int i = 0; i < lmResponse.length; i++) {
402                 buffer.append(Integer.toHexString((lmResponse[i] >> 4) & 0x0f));
403                 buffer.append(Integer.toHexString(lmResponse[i] & 0x0f));
404             }
405         }
406         if (ntResponse != null) {
407             if (buffer.length() > 0) buffer.append("; ");
408             buffer.append("ntResponse: ");
409             buffer.append("0x");
410             for (int i = 0; i < ntResponse.length; i++) {
411                 buffer.append(Integer.toHexString((ntResponse[i] >> 4) & 0x0f));
412                 buffer.append(Integer.toHexString(ntResponse[i] & 0x0f));
413             }
414         }
415         if (sessionKey != null) {
416             if (buffer.length() > 0) buffer.append("; ");
417             buffer.append("sessionKey: ");
418             buffer.append("0x");
419             for (int i = 0; i < sessionKey.length; i++) {
420                 buffer.append(Integer.toHexString((sessionKey[i] >> 4) & 0x0f));
421                 buffer.append(Integer.toHexString(sessionKey[i] & 0x0f));
422             }
423         }
424         if (flags != 0) {
425             if (buffer.length() > 0) buffer.append("; ");
426             buffer.append("flags: ");
427             buffer.append("0x");
428             buffer.append(Integer.toHexString((flags >> 28) & 0x0f));
429             buffer.append(Integer.toHexString((flags >> 24) & 0x0f));
430             buffer.append(Integer.toHexString((flags >> 20) & 0x0f));
431             buffer.append(Integer.toHexString((flags >> 16) & 0x0f));
432             buffer.append(Integer.toHexString((flags >> 12) & 0x0f));
433             buffer.append(Integer.toHexString((flags >> 8) & 0x0f));
434             buffer.append(Integer.toHexString((flags >> 4) & 0x0f));
435             buffer.append(Integer.toHexString(flags & 0x0f));
436         }
437         return buffer.toString();
438     }
439
440     /**
441      * Returns the default flags for a generic Type-3 message in the
442      * current environment.
443      *
444      * @return An <code>int</code> containing the default flags.
445      */

446     public static int getDefaultFlags() {
447         return DEFAULT_FLAGS;
448     }
449
450     /**
451      * Returns the default flags for a Type-3 message created in response
452      * to the given Type-2 message in the current environment.
453      *
454      * @return An <code>int</code> containing the default flags.
455      */

456     public static int getDefaultFlags(Type2Message type2) {
457         if (type2 == null) return DEFAULT_FLAGS;
458         int flags = NTLMSSP_NEGOTIATE_NTLM;
459         flags |= ((type2.getFlags() & NTLMSSP_NEGOTIATE_UNICODE) != 0) ?
460                 NTLMSSP_NEGOTIATE_UNICODE : NTLMSSP_NEGOTIATE_OEM;
461         return flags;
462     }
463
464     /**
465      * Constructs the LanManager response to the given Type-2 message using
466      * the supplied password.
467      *
468      * @param type2 The Type-2 message.
469      * @param password The password.
470      * @return A <code>byte[]</code> containing the LanManager response.
471      */

472     public static byte[] getLMResponse(Type2Message type2, String JavaDoc password) {
473         if (type2 == null || password == null) return null;
474         return NtlmPasswordAuthentication.getPreNTLMResponse(password,
475                 type2.getChallenge());
476     }
477
478     public static byte[] getLMv2Response(Type2Message type2,
479             String JavaDoc domain, String JavaDoc user, String JavaDoc password,
480                     byte[] clientChallenge) {
481         if (type2 == null || domain == null || user == null ||
482                 password == null || clientChallenge == null) {
483             return null;
484         }
485         return NtlmPasswordAuthentication.getLMv2Response(domain, user,
486                 password, type2.getChallenge(), clientChallenge);
487     }
488
489     /**
490      * Constructs the NT response to the given Type-2 message using
491      * the supplied password.
492      *
493      * @param type2 The Type-2 message.
494      * @param password The password.
495      * @return A <code>byte[]</code> containing the NT response.
496      */

497     public static byte[] getNTResponse(Type2Message type2, String JavaDoc password) {
498         if (type2 == null || password == null) return null;
499         return NtlmPasswordAuthentication.getNTLMResponse(password,
500                 type2.getChallenge());
501     }
502
503     /**
504      * Returns the default domain from the current environment.
505      *
506      * @return The default domain.
507      */

508     public static String JavaDoc getDefaultDomain() {
509         return DEFAULT_DOMAIN;
510     }
511
512     /**
513      * Returns the default user from the current environment.
514      *
515      * @return The default user.
516      */

517     public static String JavaDoc getDefaultUser() {
518         return DEFAULT_USER;
519     }
520
521     /**
522      * Returns the default password from the current environment.
523      *
524      * @return The default password.
525      */

526     public static String JavaDoc getDefaultPassword() {
527         return DEFAULT_PASSWORD;
528     }
529
530     /**
531      * Returns the default workstation from the current environment.
532      *
533      * @return The default workstation.
534      */

535     public static String JavaDoc getDefaultWorkstation() {
536         return DEFAULT_WORKSTATION;
537     }
538
539     private void parse(byte[] material) throws IOException JavaDoc {
540         for (int i = 0; i < 8; i++) {
541             if (material[i] != NTLMSSP_SIGNATURE[i]) {
542                 throw new IOException JavaDoc("Not an NTLMSSP message.");
543             }
544         }
545         if (readULong(material, 8) != 3) {
546             throw new IOException JavaDoc("Not a Type 3 message.");
547         }
548         byte[] lmResponse = readSecurityBuffer(material, 12);
549         int lmResponseOffset = readULong(material, 16);
550         byte[] ntResponse = readSecurityBuffer(material, 20);
551         int ntResponseOffset = readULong(material, 24);
552         byte[] domain = readSecurityBuffer(material, 28);
553         int domainOffset = readULong(material, 32);
554         byte[] user = readSecurityBuffer(material, 36);
555         int userOffset = readULong(material, 40);
556         byte[] workstation = readSecurityBuffer(material, 44);
557         int workstationOffset = readULong(material, 48);
558         int flags;
559         String JavaDoc charset;
560         if (lmResponseOffset == 52 || ntResponseOffset == 52 ||
561                 domainOffset == 52 || userOffset == 52 ||
562                         workstationOffset == 52) {
563             flags = NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_OEM;
564             charset = getOEMEncoding();
565         } else {
566             setSessionKey(readSecurityBuffer(material, 52));
567             flags = readULong(material, 60);
568             charset = ((flags & NTLMSSP_NEGOTIATE_UNICODE) != 0) ?
569                 "UnicodeLittleUnmarked" : getOEMEncoding();
570         }
571         setFlags(flags);
572         setLMResponse(lmResponse);
573         /* NTLMv2 issues w/cross-domain authentication; leave
574          * NT empty if NTLMv2 was sent by the client. NTLM response
575          * will always be 24 bytes; NTLMv2 response will always be
576          * longer. - Kevin Tapperson
577          */

578         if (ntResponse.length == 24) setNTResponse(ntResponse);
579         setDomain(new String JavaDoc(domain, charset));
580         setUser(new String JavaDoc(user, charset));
581         setWorkstation(new String JavaDoc(workstation, charset));
582     }
583 }
584
Popular Tags