~ubuntu-branches/ubuntu/precise/classpath/precise

« back to all changes in this revision

Viewing changes to gnu/javax/crypto/sasl/SaslInputStream.java

  • Committer: Bazaar Package Importer
  • Author(s): Michael Koch
  • Date: 2006-05-27 16:11:15 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060527161115-h6e39eposdt5snb6
Tags: 2:0.91-3
* Install header files to /usr/include/classpath.
* debian/control: classpath: Conflict with jamvm < 1.4.3 and
  cacao < 0.96 (Closes: #368172).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* SaslInputStream.java -- 
 
2
   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
 
3
 
 
4
This file is a part of GNU Classpath.
 
5
 
 
6
GNU Classpath is free software; you can redistribute it and/or modify
 
7
it under the terms of the GNU General Public License as published by
 
8
the Free Software Foundation; either version 2 of the License, or (at
 
9
your option) any later version.
 
10
 
 
11
GNU Classpath is distributed in the hope that it will be useful, but
 
12
WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with GNU Classpath; if not, write to the Free Software
 
18
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 
19
USA
 
20
 
 
21
Linking this library statically or dynamically with other modules is
 
22
making a combined work based on this library.  Thus, the terms and
 
23
conditions of the GNU General Public License cover the whole
 
24
combination.
 
25
 
 
26
As a special exception, the copyright holders of this library give you
 
27
permission to link this library with independent modules to produce an
 
28
executable, regardless of the license terms of these independent
 
29
modules, and to copy and distribute the resulting executable under
 
30
terms of your choice, provided that you also meet, for each linked
 
31
independent module, the terms and conditions of the license of that
 
32
module.  An independent module is a module which is not derived from
 
33
or based on this library.  If you modify this library, you may extend
 
34
this exception to your version of the library, but you are not
 
35
obligated to do so.  If you do not wish to do so, delete this
 
36
exception statement from your version.  */
 
37
 
 
38
 
 
39
package gnu.javax.crypto.sasl;
 
40
 
 
41
import gnu.java.security.util.Util;
 
42
 
 
43
import java.io.InputStream;
 
44
import java.io.InterruptedIOException;
 
45
import java.io.IOException;
 
46
import java.io.PrintWriter;
 
47
 
 
48
import javax.security.sasl.Sasl;
 
49
import javax.security.sasl.SaslClient;
 
50
import javax.security.sasl.SaslServer;
 
51
 
 
52
/**
 
53
 * An input stream that uses either a {@link SaslClient} or a {@link SaslServer}
 
54
 * to process the data through these entities' security layer filter(s).
 
55
 */
 
56
public class SaslInputStream extends InputStream
 
57
{
 
58
 
 
59
  // Debugging methods and variables
 
60
  // -------------------------------------------------------------------------
 
61
 
 
62
  private static final String NAME = "SaslOutputStream";
 
63
 
 
64
  private static final String ERROR = "ERROR";
 
65
 
 
66
  private static final String WARN = " WARN";
 
67
 
 
68
  //   private static final String INFO =  " INFO";
 
69
  private static final String TRACE = "DEBUG";
 
70
 
 
71
  private static final boolean DEBUG = true;
 
72
 
 
73
  private static final int debuglevel = 3;
 
74
 
 
75
  private static final PrintWriter err = new PrintWriter(System.out, true);
 
76
 
 
77
  private static void debug(String level, Object obj)
 
78
  {
 
79
    err.println("[" + level + "] " + NAME + ": " + String.valueOf(obj));
 
80
  }
 
81
 
 
82
  // Constants and variables
 
83
  // -------------------------------------------------------------------------
 
84
 
 
85
  private SaslClient client;
 
86
 
 
87
  private SaslServer server;
 
88
 
 
89
  private int maxRawSendSize;
 
90
 
 
91
  private InputStream source;
 
92
 
 
93
  private byte[] internalBuf;
 
94
 
 
95
  // Constructor(s)
 
96
  // -------------------------------------------------------------------------
 
97
 
 
98
  public SaslInputStream(SaslClient client, InputStream source)
 
99
      throws IOException
 
100
  {
 
101
    super();
 
102
 
 
103
    this.client = client;
 
104
    maxRawSendSize = Integer.parseInt((String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE));
 
105
    server = null;
 
106
    this.source = source;
 
107
  }
 
108
 
 
109
  public SaslInputStream(SaslServer server, InputStream source)
 
110
      throws IOException
 
111
  {
 
112
    super();
 
113
 
 
114
    this.server = server;
 
115
    maxRawSendSize = Integer.parseInt((String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE));
 
116
    client = null;
 
117
    this.source = source;
 
118
  }
 
119
 
 
120
  // Class methods
 
121
  // -------------------------------------------------------------------------
 
122
 
 
123
  // Instance methods
 
124
  // -------------------------------------------------------------------------
 
125
 
 
126
  // Overloaded java.io.InputStream methods ----------------------------------
 
127
 
 
128
  public int available() throws IOException
 
129
  {
 
130
    return (internalBuf == null) ? 0 : internalBuf.length;
 
131
  }
 
132
 
 
133
  public void close() throws IOException
 
134
  {
 
135
    source.close();
 
136
  }
 
137
 
 
138
  /**
 
139
   * <p>Reads the next byte of data from the input stream. The value byte is
 
140
   * returned as an <code>int</code> in the range <code>0</code> to
 
141
   * <code>255</code>. If no byte is available because the end of the stream
 
142
   * has been reached, the value <code>-1</code> is returned. This method
 
143
   * blocks until input data is available, the end of the stream is detected,
 
144
   * or an exception is thrown.</p>
 
145
   *
 
146
   * <p>From a SASL mechanism provider's perspective, if a security layer has
 
147
   * been negotiated, the underlying <i>source</i> is expected to contain SASL
 
148
   * buffers, as defined in RFC 2222. Four octets in network byte order in the
 
149
   * front of each buffer identify the length of the buffer. The provider is
 
150
   * responsible for performing any integrity checking or other processing on
 
151
   * the buffer before returning the data as a stream of octets. For example,
 
152
   * the protocol driver's request for a single octet from the stream might;
 
153
   * i.e. an invocation of this method, may result in an entire SASL buffer
 
154
   * being read and processed before that single octet can be returned.</p>
 
155
   *
 
156
   * @return the next byte of data, or <code>-1</code> if the end of the stream
 
157
   * is reached.
 
158
   * @throws IOException if an I/O error occurs.
 
159
   */
 
160
  public int read() throws IOException
 
161
  {
 
162
    int result = -1;
 
163
    if (internalBuf != null && internalBuf.length > 0)
 
164
      {
 
165
        result = internalBuf[0] & 0xFF;
 
166
        if (internalBuf.length == 1)
 
167
          internalBuf = new byte[0];
 
168
        else
 
169
          {
 
170
            byte[] tmp = new byte[internalBuf.length - 1];
 
171
            //            System.arraycopy(internalBuf, 0, tmp, 0, tmp.length);
 
172
            System.arraycopy(internalBuf, 1, tmp, 0, tmp.length);
 
173
            internalBuf = tmp;
 
174
          }
 
175
      }
 
176
    else
 
177
      {
 
178
        byte[] buf = new byte[1];
 
179
        int check = read(buf);
 
180
        result = (check > 0) ? (buf[0] & 0xFF) : -1;
 
181
      }
 
182
 
 
183
    return result;
 
184
  }
 
185
 
 
186
  /**
 
187
   * <p>Reads up to <code>len</code> bytes of data from the underlying
 
188
   * <i>source</i> input stream into an array of bytes. An attempt is made to
 
189
   * read as many as <code>len</code> bytes, but a smaller number may be read,
 
190
   * possibly zero. The number of bytes actually read is returned as an
 
191
   * integer.</p>
 
192
   *
 
193
   * <p>This method blocks until input data is available, end of file is
 
194
   * detected, or an exception is thrown.</p>
 
195
   *
 
196
   * <p>If <code>b</code> is <code>null</code>, a {@link NullPointerException} is
 
197
   * thrown.</p>
 
198
   *
 
199
   * <p>If <code>off</code> is negative, or <code>len</code> is negative, or
 
200
   * <code>off+len</code> is greater than the length of the array <code>b</code>,
 
201
   * then an {@link IndexOutOfBoundsException} is thrown.</p>
 
202
   *
 
203
   * <p>If <code>len</code> is zero, then no bytes are read and <code>0</code>
 
204
   * is returned; otherwise, there is an attempt to read at least one byte. If
 
205
   * no byte is available because the stream is at end of file, the value
 
206
   * <code>-1</code> is returned; otherwise, at least one byte is read and
 
207
   * stored into <code>b</code>.</p>
 
208
   *
 
209
   * <p>The first byte read is stored into element <code>b[off]</code>, the
 
210
   * next one into <code>b[off+1]</code>, and so on. The number of bytes read
 
211
   * is, at most, equal to <code>len</code>. Let <code>k</code> be the number
 
212
   * of bytes actually read; these bytes will be stored in elements
 
213
   * <code>b[off]</code> through <code>b[off+k-1]</code>, leaving elements
 
214
   * <code>b[off+k]</code> through <code>b[off+len-1]</code> unaffected.</p>
 
215
   *
 
216
   * <p>In every case, elements <code>b[0]</code> through <code>b[off]</code>
 
217
   * and elements <code>b[off+len]</code> through <code>b[b.length-1]</code>
 
218
   * are unaffected.</p>
 
219
   *
 
220
   * <p>If the first byte cannot be read for any reason other than end of file,
 
221
   * then an {@link IOException} is thrown. In particular, an {@link IOException}
 
222
   * is thrown if the input stream has been closed.</p>
 
223
   *
 
224
   * <p>From the SASL mechanism provider's perspective, if a security layer has
 
225
   * been negotiated, the underlying <i>source</i> is expected to contain SASL
 
226
   * buffers, as defined in RFC 2222. Four octets in network byte order in the
 
227
   * front of each buffer identify the length of the buffer. The provider is
 
228
   * responsible for performing any integrity checking or other processing on
 
229
   * the buffer before returning the data as a stream of octets. The protocol
 
230
   * driver's request for a single octet from the stream might result in an
 
231
   * entire SASL buffer being read and processed before that single octet can
 
232
   * be returned.</p>
 
233
   *
 
234
   * @param b the buffer into which the data is read.
 
235
   * @param off the start offset in array <code>b</code> at which the data is
 
236
   * wricodeen.
 
237
   * @param len the maximum number of bytes to read.
 
238
   * @return the total number of bytes read into the buffer, or <code>-1</code>
 
239
   * if there is no more data because the end of the stream has been reached.
 
240
   * @throws IOException if an I/O error occurs.
 
241
   */
 
242
  public int read(byte[] b, int off, int len) throws IOException
 
243
  {
 
244
    if (DEBUG && debuglevel > 8)
 
245
      debug(TRACE, "==> read(b, " + String.valueOf(off) + ", "
 
246
                   + String.valueOf(len) + ")");
 
247
 
 
248
    if (b == null)
 
249
      {
 
250
        throw new NullPointerException("b");
 
251
      }
 
252
    if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
 
253
        || ((off + len) < 0))
 
254
      {
 
255
        throw new IndexOutOfBoundsException("off=" + String.valueOf(off)
 
256
                                            + ", len=" + String.valueOf(len)
 
257
                                            + ", b.length="
 
258
                                            + String.valueOf(b.length));
 
259
      }
 
260
    if (len == 0)
 
261
      {
 
262
        if (DEBUG && debuglevel > 8)
 
263
          debug(TRACE, "<== read() --> 0");
 
264
        return 0;
 
265
      }
 
266
 
 
267
    if (DEBUG && debuglevel > 6)
 
268
      debug(TRACE, "Available: " + String.valueOf(available()));
 
269
 
 
270
    int result = 0;
 
271
    if (internalBuf == null || internalBuf.length < 1)
 
272
      try
 
273
        {
 
274
          internalBuf = readSaslBuffer();
 
275
          if (internalBuf == null)
 
276
            {
 
277
              if (DEBUG && debuglevel > 4)
 
278
                debug(WARN, "Underlying stream empty. Returning -1");
 
279
              if (DEBUG && debuglevel > 8)
 
280
                debug(TRACE, "<== read() --> -1");
 
281
              return -1;
 
282
            }
 
283
        }
 
284
      catch (InterruptedIOException x)
 
285
        {
 
286
          if (DEBUG && debuglevel > 6)
 
287
            debug(TRACE, x);
 
288
          if (DEBUG && debuglevel > 4)
 
289
            debug(WARN, "Reading thread was interrupted. Returning -1");
 
290
          if (DEBUG && debuglevel > 8)
 
291
            debug(TRACE, "<== read() --> -1");
 
292
          return -1;
 
293
        }
 
294
 
 
295
    if (len <= internalBuf.length)
 
296
      {
 
297
        result = len;
 
298
        System.arraycopy(internalBuf, 0, b, off, len);
 
299
        if (len == internalBuf.length)
 
300
          internalBuf = null;
 
301
        else
 
302
          {
 
303
            byte[] tmp = new byte[internalBuf.length - len];
 
304
            System.arraycopy(internalBuf, len, tmp, 0, tmp.length);
 
305
            internalBuf = tmp;
 
306
          }
 
307
      }
 
308
    else
 
309
      {
 
310
        // first copy the available bytes to b
 
311
        result = internalBuf.length;
 
312
        System.arraycopy(internalBuf, 0, b, off, result);
 
313
        internalBuf = null;
 
314
 
 
315
        off += result;
 
316
        len -= result;
 
317
 
 
318
        int remaining; // count of bytes remaining in buffer after an iteration
 
319
        int delta; // count of bytes moved to b after an iteration
 
320
        int datalen;
 
321
        byte[] data;
 
322
        while (len > 0)
 
323
          // we need to read SASL buffers, as long as there are at least
 
324
          // 4 bytes available at the source
 
325
          if (source.available() > 3)
 
326
            {
 
327
              // process a buffer
 
328
              data = readSaslBuffer();
 
329
              if (data == null)
 
330
                {
 
331
                  if (DEBUG && debuglevel > 4)
 
332
                    debug(WARN, "Underlying stream exhausted. Breaking...");
 
333
                  break;
 
334
                }
 
335
 
 
336
              datalen = data.length;
 
337
 
 
338
              // copy [part of] the result to b
 
339
              remaining = (datalen <= len) ? 0 : datalen - len;
 
340
              delta = datalen - remaining;
 
341
              System.arraycopy(data, 0, b, off, delta);
 
342
              if (remaining > 0)
 
343
                {
 
344
                  internalBuf = new byte[remaining];
 
345
                  System.arraycopy(data, delta, internalBuf, 0, remaining);
 
346
                }
 
347
 
 
348
              // update off, result and len
 
349
              off += delta;
 
350
              result += delta;
 
351
              len -= delta;
 
352
            }
 
353
          else
 
354
            { // nothing much we can do except return what we have
 
355
              if (DEBUG && debuglevel > 4)
 
356
                debug(WARN,
 
357
                      "Not enough bytes in source to read a buffer. Breaking...");
 
358
              break;
 
359
            }
 
360
      }
 
361
 
 
362
    if (DEBUG && debuglevel > 6)
 
363
      debug(TRACE, "Remaining: "
 
364
                   + (internalBuf == null ? 0 : internalBuf.length));
 
365
    if (DEBUG && debuglevel > 8)
 
366
      debug(TRACE, "<== read() --> " + String.valueOf(result));
 
367
    return result;
 
368
  }
 
369
 
 
370
  // other nstance methods ---------------------------------------------------
 
371
 
 
372
  /**
 
373
   * Reads a SASL buffer from the underlying source if at least 4 bytes are
 
374
   * available.
 
375
   *
 
376
   * @return the byte[] of decoded buffer contents, or null if the underlying
 
377
   * source was exhausted.
 
378
   * @throws IOException if an I/O exception occurs during the operation.
 
379
   */
 
380
  private byte[] readSaslBuffer() throws IOException
 
381
  {
 
382
    if (DEBUG && debuglevel > 8)
 
383
      debug(TRACE, "==> readSaslBuffer()");
 
384
 
 
385
    int realLength; // check if we read as many bytes as we're supposed to
 
386
    byte[] result = new byte[4];
 
387
    try
 
388
      {
 
389
        realLength = source.read(result);
 
390
        if (realLength == -1)
 
391
          {
 
392
            if (DEBUG && debuglevel > 8)
 
393
              debug(TRACE, "<== readSaslBuffer() --> null");
 
394
            return null;
 
395
          }
 
396
      }
 
397
    catch (IOException x)
 
398
      {
 
399
        if (DEBUG && debuglevel > 0)
 
400
          debug(ERROR, x);
 
401
        throw x;
 
402
      }
 
403
 
 
404
    if (realLength != 4)
 
405
      {
 
406
        throw new IOException("Was expecting 4 but found "
 
407
                              + String.valueOf(realLength));
 
408
      }
 
409
    int bufferLength = result[0] << 24 | (result[1] & 0xFF) << 16
 
410
                       | (result[2] & 0xFF) << 8 | (result[3] & 0xFF);
 
411
 
 
412
    if (DEBUG && debuglevel > 6)
 
413
      debug(TRACE, "SASL buffer size: " + bufferLength);
 
414
    if (bufferLength > maxRawSendSize || bufferLength < 0)
 
415
      {
 
416
        throw new SaslEncodingException("SASL buffer (security layer) too long");
 
417
      }
 
418
 
 
419
    result = new byte[bufferLength];
 
420
    try
 
421
      {
 
422
        realLength = source.read(result);
 
423
      }
 
424
    catch (IOException x)
 
425
      {
 
426
        if (DEBUG && debuglevel > 0)
 
427
          debug(ERROR, x);
 
428
        throw x;
 
429
      }
 
430
 
 
431
    if (realLength != bufferLength)
 
432
      throw new IOException("Was expecting " + String.valueOf(bufferLength)
 
433
                            + " but found " + String.valueOf(realLength));
 
434
    if (DEBUG && debuglevel > 6)
 
435
      debug(TRACE, "Incoming buffer (before security) (hex): "
 
436
                   + Util.dumpString(result));
 
437
    if (DEBUG && debuglevel > 6)
 
438
      debug(TRACE, "Incoming buffer (before security) (str): \""
 
439
                   + new String(result) + "\"");
 
440
 
 
441
    if (client != null)
 
442
      {
 
443
        result = client.unwrap(result, 0, realLength);
 
444
      }
 
445
    else
 
446
      {
 
447
        result = server.unwrap(result, 0, realLength);
 
448
      }
 
449
    if (DEBUG && debuglevel > 6)
 
450
      debug(TRACE, "Incoming buffer (after security) (hex): "
 
451
                   + Util.dumpString(result));
 
452
    if (DEBUG && debuglevel > 6)
 
453
      debug(TRACE, "Incoming buffer (after security) (str): \""
 
454
                   + new String(result) + "\"");
 
455
    if (DEBUG && debuglevel > 8)
 
456
      debug(TRACE, "<== readSaslBuffer()");
 
457
    return result;
 
458
  }
 
459
}
 
 
b'\\ No newline at end of file'