KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jcifs > ntlmssp > Type2Message


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 jcifs.Config;
27
28 import jcifs.netbios.NbtAddress;
29
30 /**
31  * Represents an NTLMSSP Type-2 message.
32  */

33 public class Type2Message extends NtlmMessage {
34
35     private static final int DEFAULT_FLAGS;
36
37     private static final String JavaDoc DEFAULT_DOMAIN;
38
39     private static final byte[] DEFAULT_TARGET_INFORMATION;
40
41     private byte[] challenge;
42
43     private String JavaDoc target;
44
45     private byte[] context;
46
47     private byte[] targetInformation;
48
49     static {
50         DEFAULT_FLAGS = NTLMSSP_NEGOTIATE_NTLM |
51                 (Config.getBoolean("jcifs.smb.client.useUnicode", true) ?
52                         NTLMSSP_NEGOTIATE_UNICODE : NTLMSSP_NEGOTIATE_OEM);
53         DEFAULT_DOMAIN = Config.getProperty("jcifs.smb.client.domain", null);
54         byte[] domain = new byte[0];
55         if (DEFAULT_DOMAIN != null) {
56             try {
57                 domain = DEFAULT_DOMAIN.getBytes("UnicodeLittleUnmarked");
58             } catch (IOException JavaDoc ex) { }
59         }
60         int domainLength = domain.length;
61         byte[] server = new byte[0];
62         try {
63             String JavaDoc host = NbtAddress.getLocalHost().getHostName();
64             if (host != null) {
65                 try {
66                     server = host.getBytes("UnicodeLittleUnmarked");
67                 } catch (IOException JavaDoc ex) { }
68             }
69         } catch (UnknownHostException JavaDoc ex) { }
70         int serverLength = server.length;
71         byte[] targetInfo = new byte[(domainLength > 0 ? domainLength + 4 : 0) +
72                 (serverLength > 0 ? serverLength + 4 : 0) + 4];
73         int offset = 0;
74         if (domainLength > 0) {
75             writeUShort(targetInfo, offset, 2);
76             offset += 2;
77             writeUShort(targetInfo, offset, domainLength);
78             offset += 2;
79             System.arraycopy(domain, 0, targetInfo, offset, domainLength);
80             offset += domainLength;
81         }
82         if (serverLength > 0) {
83             writeUShort(targetInfo, offset, 1);
84             offset += 2;
85             writeUShort(targetInfo, offset, serverLength);
86             offset += 2;
87             System.arraycopy(server, 0, targetInfo, offset, serverLength);
88         }
89         DEFAULT_TARGET_INFORMATION = targetInfo;
90     }
91
92     /**
93      * Creates a Type-2 message using default values from the current
94      * environment.
95      */

96     public Type2Message() {
97         this(getDefaultFlags(), null, null);
98     }
99
100     /**
101      * Creates a Type-2 message in response to the given Type-1 message
102      * using default values from the current environment.
103      *
104      * @param type1 The Type-1 message which this represents a response to.
105      */

106     public Type2Message(Type1Message type1) {
107         this(type1, null, null);
108     }
109
110     /**
111      * Creates a Type-2 message in response to the given Type-1 message.
112      *
113      * @param type1 The Type-1 message which this represents a response to.
114      * @param challenge The challenge from the domain controller/server.
115      * @param target The authentication target.
116      */

117     public Type2Message(Type1Message type1, byte[] challenge, String JavaDoc target) {
118         this(getDefaultFlags(type1), challenge, (type1 != null &&
119                 target == null && type1.getFlag(NTLMSSP_REQUEST_TARGET)) ?
120                         getDefaultDomain() : target);
121     }
122
123     /**
124      * Creates a Type-2 message with the specified parameters.
125      *
126      * @param flags The flags to apply to this message.
127      * @param challenge The challenge from the domain controller/server.
128      * @param target The authentication target.
129      */

130     public Type2Message(int flags, byte[] challenge, String JavaDoc target) {
131         setFlags(flags);
132         setChallenge(challenge);
133         setTarget(target);
134         if (target != null) setTargetInformation(getDefaultTargetInformation());
135     }
136
137     /**
138      * Creates a Type-2 message using the given raw Type-2 material.
139      *
140      * @param material The raw Type-2 material used to construct this message.
141      * @throws IOException If an error occurs while parsing the material.
142      */

143     public Type2Message(byte[] material) throws IOException JavaDoc {
144         parse(material);
145     }
146
147     /**
148      * Returns the challenge for this message.
149      *
150      * @return A <code>byte[]</code> containing the challenge.
151      */

152     public byte[] getChallenge() {
153         return challenge;
154     }
155
156     /**
157      * Sets the challenge for this message.
158      *
159      * @param challenge The challenge from the domain controller/server.
160      */

161     public void setChallenge(byte[] challenge) {
162         this.challenge = challenge;
163     }
164
165     /**
166      * Returns the authentication target.
167      *
168      * @return A <code>String</code> containing the authentication target.
169      */

170     public String JavaDoc getTarget() {
171         return target;
172     }
173
174     /**
175      * Sets the authentication target.
176      *
177      * @param target The authentication target.
178      */

179     public void setTarget(String JavaDoc target) {
180         this.target = target;
181     }
182
183     /**
184      * Returns the target information block.
185      *
186      * @return A <code>byte[]</code> containing the target information block.
187      * The target information block is used by the client to create an
188      * NTLMv2 response.
189      */

190     public byte[] getTargetInformation() {
191         return targetInformation;
192     }
193
194     /**
195      * Sets the target information block.
196      * The target information block is used by the client to create
197      * an NTLMv2 response.
198      *
199      * @param targetInformation The target information block.
200      */

201     public void setTargetInformation(byte[] targetInformation) {
202         this.targetInformation = targetInformation;
203     }
204
205     /**
206      * Returns the local security context.
207      *
208      * @return A <code>byte[]</code> containing the local security
209      * context. This is used by the client to negotiate local
210      * authentication.
211      */

212     public byte[] getContext() {
213         return context;
214     }
215
216     /**
217      * Sets the local security context. This is used by the client
218      * to negotiate local authentication.
219      *
220      * @param context The local security context.
221      */

222     public void setContext(byte[] context) {
223         this.context = context;
224     }
225
226     public byte[] toByteArray() {
227         try {
228             String JavaDoc targetName = getTarget();
229             byte[] challenge = getChallenge();
230             byte[] context = getContext();
231             byte[] targetInformation = getTargetInformation();
232             int flags = getFlags();
233             byte[] target = new byte[0];
234             if ((flags & (NTLMSSP_TARGET_TYPE_DOMAIN |
235                     NTLMSSP_TARGET_TYPE_SERVER |
236                             NTLMSSP_TARGET_TYPE_SHARE)) != 0) {
237                 if (targetName != null && targetName.length() != 0) {
238                     target = (flags & NTLMSSP_NEGOTIATE_UNICODE) != 0 ?
239                             targetName.getBytes("UnicodeLittleUnmarked") :
240                             targetName.toUpperCase().getBytes(getOEMEncoding());
241                 } else {
242                     flags &= (0xffffffff ^ (NTLMSSP_TARGET_TYPE_DOMAIN |
243                             NTLMSSP_TARGET_TYPE_SERVER |
244                                     NTLMSSP_TARGET_TYPE_SHARE));
245                 }
246             }
247             if (targetInformation != null) {
248                 flags ^= NTLMSSP_NEGOTIATE_TARGET_INFO;
249                 // empty context is needed for padding when t.i. is supplied.
250
if (context == null) context = new byte[8];
251             }
252             int data = 32;
253             if (context != null) data += 8;
254             if (targetInformation != null) data += 8;
255             byte[] type2 = new byte[data + target.length +
256                     (targetInformation != null ? targetInformation.length : 0)];
257             System.arraycopy(NTLMSSP_SIGNATURE, 0, type2, 0, 8);
258             writeULong(type2, 8, 2);
259             writeSecurityBuffer(type2, 12, data, target);
260             writeULong(type2, 20, flags);
261             System.arraycopy(challenge != null ? challenge : new byte[8], 0,
262                     type2, 24, 8);
263             if (context != null) System.arraycopy(context, 0, type2, 32, 8);
264             if (targetInformation != null) {
265                 writeSecurityBuffer(type2, 40, data + target.length,
266                         targetInformation);
267             }
268             return type2;
269         } catch (IOException JavaDoc ex) {
270             throw new IllegalStateException JavaDoc(ex.getMessage());
271         }
272     }
273
274     public String JavaDoc toString() {
275         String JavaDoc target = getTarget();
276         byte[] challenge = getChallenge();
277         byte[] context = getContext();
278         byte[] targetInformation = getTargetInformation();
279         int flags = getFlags();
280         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
281         if (target != null) {
282             buffer.append("target: ").append(target);
283         }
284         if (challenge != null) {
285             if (buffer.length() > 0) buffer.append("; ");
286             buffer.append("challenge: ");
287             buffer.append("0x");
288             for (int i = 0; i < challenge.length; i++) {
289                 buffer.append(Integer.toHexString((challenge[i] >> 4) & 0x0f));
290                 buffer.append(Integer.toHexString(challenge[i] & 0x0f));
291             }
292         }
293         if (context != null) {
294             if (buffer.length() > 0) buffer.append("; ");
295             buffer.append("context: ");
296             buffer.append("0x");
297             for (int i = 0; i < context.length; i++) {
298                 buffer.append(Integer.toHexString((context[i] >> 4) & 0x0f));
299                 buffer.append(Integer.toHexString(context[i] & 0x0f));
300             }
301         }
302         if (targetInformation != null) {
303             if (buffer.length() > 0) buffer.append("; ");
304             buffer.append("targetInformation: ");
305             buffer.append("0x");
306             for (int i = 0; i < targetInformation.length; i++) {
307                 buffer.append(Integer.toHexString((targetInformation[i] >> 4) &
308                         0x0f));
309                 buffer.append(Integer.toHexString(targetInformation[i] & 0x0f));
310             }
311         }
312         if (flags != 0) {
313             if (buffer.length() > 0) buffer.append("; ");
314             buffer.append("flags: ");
315             buffer.append("0x");
316             buffer.append(Integer.toHexString((flags >> 28) & 0x0f));
317             buffer.append(Integer.toHexString((flags >> 24) & 0x0f));
318             buffer.append(Integer.toHexString((flags >> 20) & 0x0f));
319             buffer.append(Integer.toHexString((flags >> 16) & 0x0f));
320             buffer.append(Integer.toHexString((flags >> 12) & 0x0f));
321             buffer.append(Integer.toHexString((flags >> 8) & 0x0f));
322             buffer.append(Integer.toHexString((flags >> 4) & 0x0f));
323             buffer.append(Integer.toHexString(flags & 0x0f));
324         }
325         return buffer.toString();
326     }
327
328     /**
329      * Returns the default flags for a generic Type-2 message in the
330      * current environment.
331      *
332      * @return An <code>int</code> containing the default flags.
333      */

334     public static int getDefaultFlags() {
335         return DEFAULT_FLAGS;
336     }
337
338     /**
339      * Returns the default flags for a Type-2 message created in response
340      * to the given Type-1 message in the current environment.
341      *
342      * @return An <code>int</code> containing the default flags.
343      */

344     public static int getDefaultFlags(Type1Message type1) {
345         if (type1 == null) return DEFAULT_FLAGS;
346         int flags = NTLMSSP_NEGOTIATE_NTLM;
347         int type1Flags = type1.getFlags();
348         flags |= ((type1Flags & NTLMSSP_NEGOTIATE_UNICODE) != 0) ?
349                 NTLMSSP_NEGOTIATE_UNICODE : NTLMSSP_NEGOTIATE_OEM;
350         if ((type1Flags & NTLMSSP_REQUEST_TARGET) != 0) {
351             String JavaDoc domain = getDefaultDomain();
352             if (domain != null) {
353                 flags |= NTLMSSP_REQUEST_TARGET | NTLMSSP_TARGET_TYPE_DOMAIN;
354             }
355         }
356         return flags;
357     }
358
359     /**
360      * Returns the default domain from the current environment.
361      *
362      * @return A <code>String</code> containing the domain.
363      */

364     public static String JavaDoc getDefaultDomain() {
365         return DEFAULT_DOMAIN;
366     }
367
368     public static byte[] getDefaultTargetInformation() {
369         return DEFAULT_TARGET_INFORMATION;
370     }
371
372     private void parse(byte[] material) throws IOException JavaDoc {
373         for (int i = 0; i < 8; i++) {
374             if (material[i] != NTLMSSP_SIGNATURE[i]) {
375                 throw new IOException JavaDoc("Not an NTLMSSP message.");
376             }
377         }
378         if (readULong(material, 8) != 2) {
379             throw new IOException JavaDoc("Not a Type 2 message.");
380         }
381         int flags = readULong(material, 20);
382         setFlags(flags);
383         String JavaDoc target = null;
384         byte[] bytes = readSecurityBuffer(material, 12);
385         if (bytes.length != 0) {
386             target = new String JavaDoc(bytes,
387                     ((flags & NTLMSSP_NEGOTIATE_UNICODE) != 0) ?
388                             "UnicodeLittleUnmarked" : getOEMEncoding());
389         }
390         setTarget(target);
391         for (int i = 24; i < 32; i++) {
392             if (material[i] != 0) {
393                 byte[] challenge = new byte[8];
394                 System.arraycopy(material, 24, challenge, 0, 8);
395                 setChallenge(challenge);
396                 break;
397             }
398         }
399         int offset = readULong(material, 16); // offset of targetname start
400
if (offset == 32 || material.length == 32) return;
401         for (int i = 32; i < 40; i++) {
402             if (material[i] != 0) {
403                 byte[] context = new byte[8];
404                 System.arraycopy(material, 32, context, 0, 8);
405                 setContext(context);
406                 break;
407             }
408         }
409         if (offset == 40 || material.length == 40) return;
410         bytes = readSecurityBuffer(material, 40);
411         if (bytes.length != 0) setTargetInformation(bytes);
412     }
413
414 }
415
Popular Tags