Merge branch 'master' of github.com:tgiphil/mono
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap.Security.jvm / SecureStream.cs
1 // 
2 // Novell.Directory.Ldap.Security.SecureStream.cs
3 //
4 // Authors:
5 //  Boris Kirzner <borsk@mainsoft.com>
6 //      Konstantin Triger <kostat@mainsoft.com>
7 //      
8 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //\r
31 \r
32 using System;\r
33 using System.IO;\r
34 \r
35 namespace Novell.Directory.Ldap.Security\r
36 {\r
37         internal class SecureStream : Stream\r
38         {\r
39                 #region Fields\r
40 \r
41                 private readonly Stream _stream;\r
42                 private readonly Krb5Helper _helper;\r
43 \r
44                 private readonly byte [] _lenBuf = new byte [4];  \r
45                 private byte [] _buffer;\r
46                 private int _bufferPosition;\r
47 \r
48                 #endregion // Fields\r
49 \r
50                 #region Constructors\r
51 \r
52                 public SecureStream(Stream stream, Krb5Helper helper): base () \r
53                 {\r
54                         _stream = stream;\r
55                         _helper = helper;\r
56                 }\r
57 \r
58                 #endregion // Constructors\r
59 \r
60                 #region Properties\r
61 \r
62                 public override bool CanRead \r
63                 { \r
64                         get { return _stream.CanRead; }\r
65                 }\r
66 \r
67                 public override bool CanSeek \r
68                 { \r
69                         get { return _stream.CanSeek; } \r
70                 }\r
71 \r
72                 public override bool CanWrite \r
73                 { \r
74                         get { return _stream.CanWrite; } \r
75                 }\r
76 \r
77                 public override long Length \r
78                 { \r
79                         get { throw new NotSupportedException (); } \r
80                 }\r
81 \r
82                 public override long Position \r
83                 { \r
84                         get { throw new NotSupportedException (); }\r
85                         set { throw new NotSupportedException (); }\r
86                 }\r
87 \r
88                 #endregion // Properties\r
89 \r
90                 #region Methods\r
91 \r
92                 public override void Flush()\r
93                 {\r
94                         _stream.Flush ();\r
95                 }\r
96 \r
97                 public override int Read( byte [] buffer, int offset, int count)\r
98                 {\r
99                         if (_buffer == null || _bufferPosition >= _buffer.Length) {\r
100                                 int actual = Fill ();\r
101                                 while (actual == 0)\r
102                                         actual = Fill ();\r
103 \r
104                                 if (actual == -1)\r
105                                         return -1;                              \r
106                         }\r
107 \r
108                         int available = _buffer.Length - _bufferPosition;\r
109                         if (count > available) {\r
110                                 Array.Copy (_buffer, _bufferPosition, buffer, offset, available);\r
111                                 _bufferPosition = _buffer.Length;\r
112                                 return available;\r
113                         }\r
114                         else {\r
115                                 Array.Copy (_buffer, _bufferPosition, buffer, offset, count);\r
116                                 _bufferPosition += count;\r
117                                 return count;\r
118                         }               \r
119                 }\r
120 \r
121                 public override void Close() {\r
122                         _stream.Close();\r
123                         _helper.Dispose();\r
124                 }\r
125 \r
126                 private int Fill()\r
127                 {\r
128                         int actual = ReadAll (_lenBuf, 4);\r
129         \r
130                         if (actual != 4) \r
131                                 return -1;\r
132 \r
133                         int length = NetworkByteOrderToInt (_lenBuf, 0, 4);\r
134 \r
135 //                      if (length > _recvMaxBufSize)\r
136 //                              throw new LdapException(length + " exceeds the negotiated receive buffer size limit: " + _recvMaxBufSize, 80, "");\r
137 \r
138                         byte [] rawBuffer = new byte [length];\r
139                         actual = ReadAll (rawBuffer, length);\r
140 \r
141                         if (actual != length)\r
142                                 throw new LdapException("Expected to read " + length + " bytes, but get " + actual, 80, "");\r
143 \r
144                         _buffer = _helper.Unwrap (rawBuffer, 0, length);\r
145                         _bufferPosition = 0;\r
146                         return _buffer.Length;\r
147                 }\r
148 \r
149                 private int ReadAll(byte [] buffer, int total)\r
150                 {\r
151                         int count = 0;\r
152                         int pos = 0;\r
153                         while (total > 0) {\r
154                                 count = _stream.Read (buffer, pos, total);\r
155 \r
156                                 if (count == -1)\r
157                                         break;\r
158                                         //return ((pos == 0) ? -1 : pos);\r
159 \r
160                                 pos += count;\r
161                                 total -= count;\r
162                         }\r
163                         return pos;\r
164                 }\r
165 \r
166                 public override long Seek(long offset, SeekOrigin loc)\r
167                 {\r
168                         return _stream.Seek (offset, loc);\r
169                 }\r
170 \r
171                 public override void SetLength(long value)\r
172                 {\r
173                         _stream.SetLength (value);\r
174                 }\r
175 \r
176                 public override void Write(byte [] buffer, int offset, int count)\r
177                 {\r
178                         // FIXME: use GSSCOntext.getWrapSizeLimit to divide the buffer\r
179                         // Generate wrapped token \r
180                         byte [] wrappedToken = _helper.Wrap (buffer, offset, count);\r
181                         // Write out length\r
182                         IntToNetworkByteOrder (wrappedToken.Length, _lenBuf, 0, 4);\r
183                         _stream.Write (_lenBuf, 0, 4);\r
184                         // Write out wrapped token\r
185                         _stream.Write (wrappedToken, 0, wrappedToken.Length);\r
186                 }\r
187 \r
188                 internal static int NetworkByteOrderToInt(byte [] buf, int start, int count) \r
189                 {\r
190                         int answer = 0;\r
191                         for (int i = 0; i < count; i++) {\r
192                                 answer <<= 8;\r
193                                 answer |= ((int)buf [start + i] & 0xff);\r
194                         }\r
195                         return answer;\r
196                 }\r
197 \r
198                 internal static void IntToNetworkByteOrder(int num, byte [] buf, int start, int count) \r
199                 {\r
200                         for (int i = count-1; i >= 0; i--) {\r
201                                 buf [start + i] = (byte)(num & 0xff);\r
202                                 num >>= 8;\r
203                         }\r
204                 }\r
205 \r
206                 #endregion // Methods\r
207         }\r
208 }\r