1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.proxy.handlers.http.ntlm;
21
22 import java.io.BufferedReader;
23 import java.io.ByteArrayOutputStream;
24 import java.io.IOException;
25 import java.io.InputStreamReader;
26 import java.io.PrintWriter;
27 import java.io.UnsupportedEncodingException;
28 import java.util.StringTokenizer;
29
30 import org.apache.mina.proxy.utils.ByteUtilities;
31
32
33
34
35
36
37
38 public class NTLMUtilities implements NTLMConstants {
39
40
41
42 public final static byte[] writeSecurityBuffer(short length,
43 int bufferOffset) {
44 byte[] b = new byte[8];
45 writeSecurityBuffer(length, length, bufferOffset, b, 0);
46 return b;
47 }
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 public final static void writeSecurityBuffer(short length, short allocated,
65 int bufferOffset, byte[] b, int offset) {
66 ByteUtilities.writeShort(length, b, offset);
67 ByteUtilities.writeShort(allocated, b, offset + 2);
68 ByteUtilities.writeInt(bufferOffset, b, offset + 4);
69 }
70
71
72
73
74
75
76
77
78
79
80
81
82 public final static void writeOSVersion(byte majorVersion,
83 byte minorVersion, short buildNumber, byte[] b, int offset) {
84 b[offset] = majorVersion;
85 b[offset + 1] = minorVersion;
86 b[offset + 2] = (byte) buildNumber;
87 b[offset + 3] = (byte) (buildNumber >> 8);
88 b[offset + 4] = 0;
89 b[offset + 5] = 0;
90 b[offset + 6] = 0;
91 b[offset + 7] = 0x0F;
92 }
93
94
95
96
97
98
99
100
101 public final static byte[] getOsVersion() {
102 String os = System.getProperty("os.name");
103
104 if (os == null || !os.toUpperCase().contains("WINDOWS")) {
105 return DEFAULT_OS_VERSION;
106 }
107
108 byte[] osVer = new byte[8];
109
110
111
112
113 try {
114 Process pr = Runtime.getRuntime().exec("cmd /C ver");
115 BufferedReader reader = new BufferedReader(
116 new InputStreamReader(pr.getInputStream()));
117 pr.waitFor();
118
119 String line;
120
121
122 do {
123 line = reader.readLine();
124 } while ((line != null) && (line.length() != 0));
125
126 reader.close();
127
128
129 if (line == null) {
130
131 throw new Exception();
132 }
133
134
135
136 int pos = line.toLowerCase().indexOf("version");
137
138 if (pos == -1) {
139
140 throw new Exception();
141 }
142
143 pos += 8;
144 line = line.substring(pos, line.indexOf(']'));
145 StringTokenizer tk = new StringTokenizer(line, ".");
146
147 if (tk.countTokens() != 3) {
148
149 throw new Exception();
150 }
151
152 writeOSVersion(Byte.parseByte(tk.nextToken()), Byte
153 .parseByte(tk.nextToken()), Short.parseShort(tk
154 .nextToken()), osVer, 0);
155 } catch (Exception ex) {
156 try {
157 String version = System.getProperty("os.version");
158 writeOSVersion(Byte.parseByte(version.substring(0, 1)),
159 Byte.parseByte(version.substring(2, 3)), (short) 0,
160 osVer, 0);
161 } catch (Exception ex2) {
162 return DEFAULT_OS_VERSION;
163 }
164 }
165
166 return osVer;
167 }
168
169
170
171
172
173
174
175
176
177
178
179
180 public final static byte[] createType1Message(String workStation,
181 String domain, Integer customFlags, byte[] osVersion) {
182 byte[] msg = null;
183
184 if (osVersion != null && osVersion.length != 8) {
185 throw new IllegalArgumentException(
186 "osVersion parameter should be a 8 byte wide array");
187 }
188
189 if (workStation == null || domain == null) {
190 throw new NullPointerException(
191 "workStation and domain must be non null");
192 }
193
194 int flags = customFlags != null ? customFlags
195 | FLAG_NEGOTIATE_WORKSTATION_SUPPLIED
196 | FLAG_NEGOTIATE_DOMAIN_SUPPLIED : DEFAULT_FLAGS;
197
198 ByteArrayOutputStream baos = new ByteArrayOutputStream();
199
200 try {
201 baos.write(NTLM_SIGNATURE);
202 baos.write(ByteUtilities.writeInt(MESSAGE_TYPE_1));
203 baos.write(ByteUtilities.writeInt(flags));
204
205 byte[] domainData = ByteUtilities.getOEMStringAsByteArray(domain);
206 byte[] workStationData = ByteUtilities
207 .getOEMStringAsByteArray(workStation);
208
209 int pos = (osVersion != null) ? 40 : 32;
210 baos.write(writeSecurityBuffer((short) domainData.length, pos
211 + workStationData.length));
212 baos
213 .write(writeSecurityBuffer((short) workStationData.length,
214 pos));
215
216 if (osVersion != null) {
217 baos.write(osVersion);
218 }
219
220
221 baos.write(workStationData);
222 baos.write(domainData);
223
224 msg = baos.toByteArray();
225 baos.close();
226 } catch (IOException e) {
227 return null;
228 }
229
230 return msg;
231 }
232
233
234
235
236
237
238
239
240
241
242
243 public final static int writeSecurityBufferAndUpdatePointer(
244 ByteArrayOutputStream baos, short len, int pointer)
245 throws IOException {
246 baos.write(writeSecurityBuffer(len, pointer));
247 return pointer + len;
248 }
249
250
251
252
253
254
255
256 public final static byte[] extractChallengeFromType2Message(byte[] msg) {
257 byte[] challenge = new byte[8];
258 System.arraycopy(msg, 24, challenge, 0, 8);
259 return challenge;
260 }
261
262
263
264
265
266
267
268 public final static int extractFlagsFromType2Message(byte[] msg) {
269 byte[] flagsBytes = new byte[4];
270
271 System.arraycopy(msg, 20, flagsBytes, 0, 4);
272 ByteUtilities.changeWordEndianess(flagsBytes, 0, 4);
273
274 return ByteUtilities.makeIntFromByte4(flagsBytes);
275 }
276
277
278
279
280
281
282
283
284
285 public final static byte[] readSecurityBufferTarget(
286 byte[] msg, int securityBufferOffset) {
287 byte[] securityBuffer = new byte[8];
288
289 System.arraycopy(msg, securityBufferOffset, securityBuffer, 0, 8);
290 ByteUtilities.changeWordEndianess(securityBuffer, 0, 8);
291 int length = ByteUtilities.makeIntFromByte2(securityBuffer);
292 int offset = ByteUtilities.makeIntFromByte4(securityBuffer, 4);
293
294 byte[] secBufValue = new byte[length];
295 System.arraycopy(msg, offset, secBufValue, 0, length);
296
297 return secBufValue;
298 }
299
300
301
302
303
304
305
306
307
308
309
310 public final static String extractTargetNameFromType2Message(byte[] msg,
311 Integer msgFlags) throws UnsupportedEncodingException {
312
313
314 byte[] targetName = readSecurityBufferTarget(msg, 12);
315
316
317 int flags = msgFlags == null ? extractFlagsFromType2Message(msg)
318 : msgFlags;
319 if (ByteUtilities.isFlagSet(flags, FLAG_NEGOTIATE_UNICODE)) {
320 return new String(targetName, "UTF-16LE");
321 }
322
323 return new String(targetName, "ASCII");
324 }
325
326
327
328
329
330
331
332
333
334 public final static byte[] extractTargetInfoFromType2Message(byte[] msg,
335 Integer msgFlags) {
336 int flags = msgFlags == null ? extractFlagsFromType2Message(msg)
337 : msgFlags;
338
339 if (!ByteUtilities.isFlagSet(flags, FLAG_NEGOTIATE_TARGET_INFO))
340 return null;
341
342 int pos = 40;
343
344 return readSecurityBufferTarget(msg, pos);
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358 public final static void printTargetInformationBlockFromType2Message(
359 byte[] msg, Integer msgFlags, PrintWriter out)
360 throws UnsupportedEncodingException {
361 int flags = msgFlags == null ? extractFlagsFromType2Message(msg)
362 : msgFlags;
363
364 byte[] infoBlock = extractTargetInfoFromType2Message(msg, flags);
365 if (infoBlock == null) {
366 out.println("No target information block found !");
367 } else {
368 int pos = 0;
369 while (infoBlock[pos] != 0) {
370 out.print("---\nType " + infoBlock[pos] + ": ");
371 switch (infoBlock[pos]) {
372 case 1:
373 out.println("Server name");
374 break;
375 case 2:
376 out.println("Domain name");
377 break;
378 case 3:
379 out.println("Fully qualified DNS hostname");
380 break;
381 case 4:
382 out.println("DNS domain name");
383 break;
384 case 5:
385 out.println("Parent DNS domain name");
386 break;
387 }
388 byte[] len = new byte[2];
389 System.arraycopy(infoBlock, pos + 2, len, 0, 2);
390 ByteUtilities.changeByteEndianess(len, 0, 2);
391
392 int length = ByteUtilities.makeIntFromByte2(len, 0);
393 out.println("Length: " + length + " bytes");
394 out.print("Data: ");
395 if (ByteUtilities.isFlagSet(flags, FLAG_NEGOTIATE_UNICODE)) {
396 out.println(new String(infoBlock, pos + 4, length,
397 "UTF-16LE"));
398 } else {
399 out.println(new String(infoBlock, pos + 4, length, "ASCII"));
400 }
401 pos += 4 + length;
402 out.flush();
403 }
404 }
405 }
406
407
408
409
410
411
412
413
414
415
416
417
418
419 public final static byte[] createType3Message(String user, String password,
420 byte[] challenge, String target, String workstation,
421 Integer serverFlags, byte[] osVersion) {
422 byte[] msg = null;
423
424 if (challenge == null || challenge.length != 8) {
425 throw new IllegalArgumentException(
426 "challenge[] should be a 8 byte wide array");
427 }
428
429 if (osVersion != null && osVersion.length != 8) {
430 throw new IllegalArgumentException(
431 "osVersion should be a 8 byte wide array");
432 }
433
434
435
436
437
438 int flags = serverFlags != null ? serverFlags : DEFAULT_FLAGS;
439
440 ByteArrayOutputStream baos = new ByteArrayOutputStream();
441
442 try {
443 baos.write(NTLM_SIGNATURE);
444 baos.write(ByteUtilities.writeInt(MESSAGE_TYPE_3));
445
446 byte[] dataLMResponse = NTLMResponses.getLMResponse(password,
447 challenge);
448 byte[] dataNTLMResponse = NTLMResponses.getNTLMResponse(password,
449 challenge);
450
451 boolean useUnicode = ByteUtilities.isFlagSet(flags,
452 FLAG_NEGOTIATE_UNICODE);
453 byte[] targetName = ByteUtilities.encodeString(target, useUnicode);
454 byte[] userName = ByteUtilities.encodeString(user, useUnicode);
455 byte[] workstationName = ByteUtilities.encodeString(workstation,
456 useUnicode);
457
458 int pos = osVersion != null ? 72 : 64;
459 int responsePos = pos + targetName.length + userName.length
460 + workstationName.length;
461 responsePos = writeSecurityBufferAndUpdatePointer(baos,
462 (short) dataLMResponse.length, responsePos);
463 writeSecurityBufferAndUpdatePointer(baos,
464 (short) dataNTLMResponse.length, responsePos);
465 pos = writeSecurityBufferAndUpdatePointer(baos,
466 (short) targetName.length, pos);
467 pos = writeSecurityBufferAndUpdatePointer(baos,
468 (short) userName.length, pos);
469 writeSecurityBufferAndUpdatePointer(baos,
470 (short) workstationName.length, pos);
471
472
473
474
475
476
477
478
479
480
481
482
483
484 baos.write(new byte[] { 0, 0, 0, 0, (byte) 0x9a, 0, 0, 0 });
485
486 baos.write(ByteUtilities.writeInt(flags));
487
488 if (osVersion != null) {
489 baos.write(osVersion);
490 }
491
492
493 baos.write(targetName);
494 baos.write(userName);
495 baos.write(workstationName);
496
497 baos.write(dataLMResponse);
498 baos.write(dataNTLMResponse);
499
500 msg = baos.toByteArray();
501 baos.close();
502 } catch (Exception e) {
503 e.printStackTrace();
504 return null;
505 }
506
507 return msg;
508 }
509 }