コード例 #1
0
        /// <summary>
        /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
        /// </summary>
        /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source.</param>
        /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
        /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
        /// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="NotSupportedException">Is raised when reading not supported.</exception>
        public override int Read(byte[] buffer,int offset,int count)
        {
            if(buffer == null){
                throw new ArgumentNullException("buffer");
            }
            if(offset < 0 || offset > buffer.Length){
                throw new ArgumentException("Invalid argument 'offset' value.");
            }
            if(offset + count > buffer.Length){
                throw new ArgumentException("Invalid argument 'count' value.");
            }
            if((m_AccessMode & FileAccess.Read) == 0){
                throw new NotSupportedException();
            }

            while(true){
                // Read next quoted-printable line and decode it.
                if(m_DecodedOffset >= m_DecodedCount){
                    m_DecodedOffset = 0;
                    m_DecodedCount  = 0;
                    SmartStream.ReadLineAsyncOP readLineOP = new SmartStream.ReadLineAsyncOP(new byte[32000],SizeExceededAction.ThrowException);
                    m_pStream.ReadLine(readLineOP,false);
                    // IO error reading line.
                    if(readLineOP.Error != null){
                        throw readLineOP.Error;
                    }
                    // We reached end of stream.
                    else if(readLineOP.BytesInBuffer == 0){
                        return 0;
                    }
                    // Decode quoted-printable line.
                    else{
                        // Process bytes.
                        bool softLineBreak = false;
                        int lineLength     = readLineOP.LineBytesInBuffer;
                        for(int i=0;i<readLineOP.LineBytesInBuffer;i++){
                            byte b = readLineOP.Buffer[i];
                            // We have soft line-break.
                            if(b == '=' && i == (lineLength - 1)){
                                softLineBreak = true;
                            }
                            // We should have =XX hex-byte.
                            else if(b == '='){
                                byte b1 = readLineOP.Buffer[++i];
                                byte b2 = readLineOP.Buffer[++i];
                        
                                byte b3 = 0;
                                if(byte.TryParse(new string(new char[]{(char)b1,(char)b2}),System.Globalization.NumberStyles.HexNumber,null,out b3)){
                                    m_pDecodedBuffer[m_DecodedCount++] = b3;
                                }
                                // Not hex number, leave it as it is.
                                else{
                                    m_pDecodedBuffer[m_DecodedCount++] = (byte)'=';
                                    m_pDecodedBuffer[m_DecodedCount++] = b1;
                                    m_pDecodedBuffer[m_DecodedCount++] = b2;
                                }
                            }
                            // Normal char.
                            else{
                                m_pDecodedBuffer[m_DecodedCount++] = b;
                            }
                        }

                        // Add hard line break only if there was one in original data.
                        if(readLineOP.LineBytesInBuffer != readLineOP.BytesInBuffer && !softLineBreak){
                            m_pDecodedBuffer[m_DecodedCount++] = (byte)'\r';
                            m_pDecodedBuffer[m_DecodedCount++] = (byte)'\n';
                        }
                    }
                }

                // We have some decoded data, return it.
                if(m_DecodedOffset < m_DecodedCount){
                    int countToCopy = Math.Min(count,m_DecodedCount - m_DecodedOffset);
                    Array.Copy(m_pDecodedBuffer,m_DecodedOffset,buffer,offset,countToCopy);
                    m_DecodedOffset += countToCopy;

                    return countToCopy;
                }
            }
        }
コード例 #2
0
        private void AUTH(string cmdText)
        {
            /* RFC 1734
                
                AUTH mechanism

                    Arguments:
                        a string identifying an IMAP4 authentication mechanism,
                        such as defined by [IMAP4-AUTH].  Any use of the string
                        "imap" used in a server authentication identity in the
                        definition of an authentication mechanism is replaced with
                        the string "pop".
                        
                    Possible Responses:
                        +OK maildrop locked and ready
                        -ERR authentication exchange failed

                    Restrictions:
                        may only be given in the AUTHORIZATION state

                    Discussion:
                        The AUTH command indicates an authentication mechanism to
                        the server.  If the server supports the requested
                        authentication mechanism, it performs an authentication
                        protocol exchange to authenticate and identify the user.
                        Optionally, it also negotiates a protection mechanism for
                        subsequent protocol interactions.  If the requested
                        authentication mechanism is not supported, the server						
                        should reject the AUTH command by sending a negative
                        response.

                        The authentication protocol exchange consists of a series
                        of server challenges and client answers that are specific
                        to the authentication mechanism.  A server challenge,
                        otherwise known as a ready response, is a line consisting
                        of a "+" character followed by a single space and a BASE64
                        encoded string.  The client answer consists of a line
                        containing a BASE64 encoded string.  If the client wishes
                        to cancel an authentication exchange, it should issue a
                        line with a single "*".  If the server receives such an
                        answer, it must reject the AUTH command by sending a
                        negative response.

                        A protection mechanism provides integrity and privacy
                        protection to the protocol session.  If a protection
                        mechanism is negotiated, it is applied to all subsequent
                        data sent over the connection.  The protection mechanism
                        takes effect immediately following the CRLF that concludes
                        the authentication exchange for the client, and the CRLF of
                        the positive response for the server.  Once the protection
                        mechanism is in effect, the stream of command and response
                        octets is processed into buffers of ciphertext.  Each
                        buffer is transferred over the connection as a stream of
                        octets prepended with a four octet field in network byte
                        order that represents the length of the following data.
                        The maximum ciphertext buffer length is defined by the
                        protection mechanism.

                        The server is not required to support any particular
                        authentication mechanism, nor are authentication mechanisms
                        required to support any protection mechanisms.  If an AUTH
                        command fails with a negative response, the session remains
                        in the AUTHORIZATION state and client may try another
                        authentication mechanism by issuing another AUTH command,
                        or may attempt to authenticate by using the USER/PASS or
                        APOP commands.  In other words, the client may request
                        authentication types in decreasing order of preference,
                        with the USER/PASS or APOP command as a last resort.

                        Should the client successfully complete the authentication
                        exchange, the POP3 server issues a positive response and
                        the POP3 session enters the TRANSACTION state.
                        
                Examples:
                            S: +OK POP3 server ready
                            C: AUTH KERBEROS_V4
                            S: + AmFYig==
                            C: BAcAQU5EUkVXLkNNVS5FRFUAOCAsho84kLN3/IJmrMG+25a4DT
                                +nZImJjnTNHJUtxAA+o0KPKfHEcAFs9a3CL5Oebe/ydHJUwYFd
                                WwuQ1MWiy6IesKvjL5rL9WjXUb9MwT9bpObYLGOKi1Qh
                            S: + or//EoAADZI=
                            C: DiAF5A4gA+oOIALuBkAAmw==
                            S: +OK Kerberos V4 authentication successful
                                ...
                            C: AUTH FOOBAR
                            S: -ERR Unrecognized authentication type
             
            */

            if(m_SessionRejected){
                WriteLine("-ERR Bad sequence of commands: Session rejected.");

                return;
            }
            if(this.IsAuthenticated){
                this.TcpStream.WriteLine("-ERR Re-authentication error.");

                return;
            }

            string mechanism = cmdText;

            /* MS specific or someone knows where in RFC let me know about this.
                Empty AUTH commands causes authentication mechanisms listing. 
             
                C: AUTH
                S: PLAIN
                S: .
                
                http://msdn.microsoft.com/en-us/library/cc239199.aspx
            */
            if(string.IsNullOrEmpty(mechanism)){
                StringBuilder resp = new StringBuilder();
                resp.Append("+OK\r\n");
                foreach(AUTH_SASL_ServerMechanism m in m_pAuthentications.Values){
                    resp.Append(m.Name + "\r\n");
                }
                resp.Append(".\r\n");

                WriteLine(resp.ToString());

                return;
            }

            if(!this.Authentications.ContainsKey(mechanism)){
                WriteLine("-ERR Not supported authentication mechanism.");
                return;
            }

            byte[] clientResponse = new byte[0];
            AUTH_SASL_ServerMechanism auth = this.Authentications[mechanism];
            auth.Reset();
            while(true){
                byte[] serverResponse = auth.Continue(clientResponse);
                // Authentication completed.
                if(auth.IsCompleted){
                    if(auth.IsAuthenticated){
                        m_pUser = new GenericIdentity(auth.UserName,"SASL-" + auth.Name);

                        // Get mailbox messages.
                        POP3_e_GetMessagesInfo eMessages = OnGetMessagesInfo();
                        int seqNo = 1;
                        foreach(POP3_ServerMessage message in eMessages.Messages){
                            message.SequenceNumber = seqNo++;
                            m_pMessages.Add(message.UID,message);
                        }

                        WriteLine("+OK Authentication succeeded.");
                    }
                    else{
                        WriteLine("-ERR Authentication credentials invalid.");
                    }
                    break;
                }
                // Authentication continues.
                else{
                    // Send server challange.
                    if(serverResponse.Length == 0){
                        WriteLine("+ ");
                    }
                    else{
                        WriteLine("+ " + Convert.ToBase64String(serverResponse));
                    }

                    // Read client response. 
                    SmartStream.ReadLineAsyncOP readLineOP = new SmartStream.ReadLineAsyncOP(new byte[32000],SizeExceededAction.JunkAndThrowException);
                    this.TcpStream.ReadLine(readLineOP,false);
                    if(readLineOP.Error != null){
                        throw readLineOP.Error;
                    }
                    // Log
                    if(this.Server.Logger != null){
                        this.Server.Logger.AddRead(this.ID,this.AuthenticatedUserIdentity,readLineOP.BytesInBuffer,"base64 auth-data",this.LocalEndPoint,this.RemoteEndPoint);
                    }

                    // Client canceled authentication.
                    if(readLineOP.LineUtf8 == "*"){
                        WriteLine("-ERR Authentication canceled.");
                        return;
                    }
                    // We have base64 client response, decode it.
                    else{
                        try{
                            clientResponse = Convert.FromBase64String(readLineOP.LineUtf8);
                        }
                        catch{
                            WriteLine("-ERR Invalid client response '" + clientResponse + "'.");
                            return;
                        }
                    }
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Reads and logs specified line from connected host.
        /// </summary>
        /// <returns>Returns readed line.</returns>
        protected string ReadLine()
        {
            SmartStream.ReadLineAsyncOP args = new SmartStream.ReadLineAsyncOP(new byte[32000],SizeExceededAction.JunkAndThrowException);
            this.TcpStream.ReadLine(args,false);
            if(args.Error != null){
                throw args.Error;
            }
            string line = args.LineUtf8;
            if(args.BytesInBuffer > 0){
                LogAddRead(args.BytesInBuffer,line);
            }
            else{
                LogAddText("Remote host closed connection.");
            }

            return line;
        }
コード例 #4
0
        /// <summary>
        /// Starts reading incoming command from the connected client.
        /// </summary>
        private void BeginReadCmd()
        {
            if(this.IsDisposed){
                return;
            }

            try{
                SmartStream.ReadLineAsyncOP readLineOP = new SmartStream.ReadLineAsyncOP(new byte[32000],SizeExceededAction.JunkAndThrowException);
                // This event is raised only when read next coomand completes asynchronously.
                readLineOP.Completed += new EventHandler<EventArgs<SmartStream.ReadLineAsyncOP>>(delegate(object sender,EventArgs<SmartStream.ReadLineAsyncOP> e){                
                    if(ProcessCmd(readLineOP)){
                        BeginReadCmd();
                    }
                });
                // Process incoming commands while, command reading completes synchronously.
                while(this.TcpStream.ReadLine(readLineOP,true)){
                    if(!ProcessCmd(readLineOP)){
                        break;
                    }
                }
            }
            catch(Exception x){
                OnError(x);
            }
        }