remove svn:executable from .cs files
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Ntlm / Type3Message.cs
1 //
2 // Mono.Security.Protocol.Ntlm.Type3Message - Authentication
3 //
4 // Author:
5 //      Sebastien Pouliot <sebastien@ximian.com>
6 //
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10 // References
11 // a.   NTLM Authentication Scheme for HTTP, Ronald Tschalär
12 //      http://www.innovation.ch/java/ntlm.html
13 // b.   The NTLM Authentication Protocol, Copyright © 2003 Eric Glass
14 //      http://davenport.sourceforge.net/ntlm.html
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 using System;
37 using System.Globalization;
38 using System.Text;
39
40 namespace Mono.Security.Protocol.Ntlm {
41
42         public class Type3Message : MessageBase {
43
44                 private byte[] _challenge;
45                 private string _host;
46                 private string _domain;
47                 private string _username;
48                 private string _password;
49                 private byte[] _lm;
50                 private byte[] _nt;
51
52                 public Type3Message () : base (3)
53                 {
54                         // default values
55                         _domain = Environment.UserDomainName;
56                         _host = Environment.MachineName;
57                         _username = Environment.UserName;
58                         Flags = (NtlmFlags) 0x8201;
59                 }
60
61                 public Type3Message (byte[] message) : base (3)
62                 {
63                         Decode (message);
64                 }
65
66                 ~Type3Message () 
67                 {
68                         if (_challenge != null)
69                                 Array.Clear (_challenge, 0, _challenge.Length);
70                         if (_lm != null)
71                                 Array.Clear (_lm, 0, _lm.Length);
72                         if (_nt != null)
73                                 Array.Clear (_nt, 0, _nt.Length);
74                 }
75
76                 // properties
77
78                 public byte[] Challenge {
79                         get { 
80                                 if (_challenge == null)
81                                         return null;
82                                 return (byte[]) _challenge.Clone (); }
83                         set { 
84                                 if (value == null)
85                                         throw new ArgumentNullException ("Challenge");
86                                 if (value.Length != 8) {
87                                         string msg = Locale.GetText ("Invalid Challenge Length (should be 8 bytes).");
88                                         throw new ArgumentException (msg, "Challenge");
89                                 }
90                                 _challenge = (byte[]) value.Clone (); 
91                         }
92                 }
93
94                 public string Domain {
95                         get { return _domain; }
96                         set { _domain = value; }
97                 }
98
99                 public string Host {
100                         get { return _host; }
101                         set { _host = value; }
102                 }
103
104                 public string Password {
105                         get { return _password; }
106                         set { _password = value; }
107                 }
108
109                 public string Username {
110                         get { return _username; }
111                         set { _username = value; }
112                 }
113
114                 public byte[] LM {
115                         get { return _lm; }
116                 }
117
118                 public byte[] NT {
119                         get { return _nt; }
120                 }
121
122                 // methods
123
124                 protected override void Decode (byte[] message) 
125                 {
126                         base.Decode (message);
127
128                         if (BitConverterLE.ToUInt16 (message, 56) != message.Length) {
129                                 string msg = Locale.GetText ("Invalid Type3 message length.");
130                                 throw new ArgumentException (msg, "message");
131                         }
132
133                         _password = null;
134
135                         int dom_len = BitConverterLE.ToUInt16 (message, 28);
136                         int dom_off = 64;
137                         _domain = Encoding.Unicode.GetString (message, dom_off, dom_len);
138
139                         int host_len = BitConverterLE.ToUInt16 (message, 44);
140                         int host_off = BitConverterLE.ToUInt16 (message, 48);
141                         _host = Encoding.Unicode.GetString (message, host_off, host_len);
142
143                         int user_len = BitConverterLE.ToUInt16 (message, 36);
144                         int user_off = BitConverterLE.ToUInt16 (message, 40);
145                         _username = Encoding.Unicode.GetString (message, user_off, user_len);
146
147                         _lm = new byte [24];
148                         int lm_off = BitConverterLE.ToUInt16 (message, 16);
149                         Buffer.BlockCopy (message, lm_off, _lm, 0, 24);
150                         
151                         _nt = new byte [24];
152                         int nt_off = BitConverterLE.ToUInt16 (message, 24);
153                         Buffer.BlockCopy (message, nt_off, _nt, 0, 24);
154
155                         if (message.Length >= 64)
156                                 Flags = (NtlmFlags) BitConverterLE.ToUInt32 (message, 60);
157                 }
158
159                 public override byte[] GetBytes () 
160                 {
161                         byte[] domain = Encoding.Unicode.GetBytes (_domain.ToUpper (CultureInfo.InvariantCulture));
162                         byte[] user = Encoding.Unicode.GetBytes (_username);
163                         byte[] host = Encoding.Unicode.GetBytes (_host.ToUpper (CultureInfo.InvariantCulture));
164
165                         byte[] data = PrepareMessage (64 + domain.Length + user.Length + host.Length + 24 + 24);
166
167                         // LM response
168                         short lmresp_off = (short)(64 + domain.Length + user.Length + host.Length);
169                         data [12] = (byte) 0x18;
170                         data [13] = (byte) 0x00;
171                         data [14] = (byte) 0x18;
172                         data [15] = (byte) 0x00;
173                         data [16] = (byte) lmresp_off;
174                         data [17] = (byte)(lmresp_off >> 8);
175
176                         // NT response
177                         short ntresp_off = (short)(lmresp_off + 24);
178                         data [20] = (byte) 0x18;
179                         data [21] = (byte) 0x00;
180                         data [22] = (byte) 0x18;
181                         data [23] = (byte) 0x00;
182                         data [24] = (byte) ntresp_off;
183                         data [25] = (byte)(ntresp_off >> 8);
184
185                         // domain
186                         short dom_len = (short)domain.Length;
187                         short dom_off = 64;
188                         data [28] = (byte) dom_len;
189                         data [29] = (byte)(dom_len >> 8);
190                         data [30] = data [28];
191                         data [31] = data [29];
192                         data [32] = (byte) dom_off;
193                         data [33] = (byte)(dom_off >> 8);
194
195                         // username
196                         short uname_len = (short)user.Length;
197                         short uname_off = (short)(dom_off + dom_len);
198                         data [36] = (byte) uname_len;
199                         data [37] = (byte)(uname_len >> 8);
200                         data [38] = data [36];
201                         data [39] = data [37];
202                         data [40] = (byte) uname_off;
203                         data [41] = (byte)(uname_off >> 8);
204
205                         // host
206                         short host_len = (short)host.Length;
207                         short host_off = (short)(uname_off + uname_len);
208                         data [44] = (byte) host_len;
209                         data [45] = (byte)(host_len >> 8);
210                         data [46] = data [44];
211                         data [47] = data [45];
212                         data [48] = (byte) host_off;
213                         data [49] = (byte)(host_off >> 8);
214
215                         // message length
216                         short msg_len = (short)data.Length;
217                         data [56] = (byte) msg_len;
218                         data [57] = (byte)(msg_len >> 8);
219
220                         // options flags
221                         data [60] = (byte) Flags;
222                         data [61] = (byte)((uint)Flags >> 8);
223                         data [62] = (byte)((uint)Flags >> 16);
224                         data [63] = (byte)((uint)Flags >> 24);
225
226                         Buffer.BlockCopy (domain, 0, data, dom_off, domain.Length);
227                         Buffer.BlockCopy (user, 0, data, uname_off, user.Length);
228                         Buffer.BlockCopy (host, 0, data, host_off, host.Length);
229
230                         using (ChallengeResponse ntlm = new ChallengeResponse (_password, _challenge)) {
231                                 Buffer.BlockCopy (ntlm.LM, 0, data, lmresp_off, 24);
232                                 Buffer.BlockCopy (ntlm.NT, 0, data, ntresp_off, 24);
233                         }
234                         return data;
235                 }
236         }
237 }