Skip to content

Commit

Permalink
Fixed compile errors due to merges, and fixed the CAPABILITY command …
Browse files Browse the repository at this point in the history
…for STARTTLS.
  • Loading branch information
EtienneBruines committed Jun 28, 2015
1 parent b4f4fd4 commit acd787d
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 56 deletions.
32 changes: 23 additions & 9 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,33 @@ type capability struct {

// execute a capability
func (c *capability) execute(s *session) *response {
// The IMAP server is assumed to be running over SSL and so
// STARTTLS is not supported and LOGIN is not disabled
var commands []string

switch s.listener.encryption {
case unencryptedLevel:
// TODO: do we want to support this?

case starttlsLevel:
if s.encryption == tlsLevel {
commands = append(commands, "AUTH=PLAIN")
} else {
commands = append(commands, "STARTTLS")
commands = append(commands, "LOGINDISABLED")
}

case tlsLevel:
commands = append(commands, "AUTH=PLAIN")
}

// Return all capabilities
return ok(c.tag, "CAPABILITY completed").
extra("CAPABILITY IMAP4rev1 STARTTLS")
extra("CAPABILITY IMAP4rev1 " + strings.Join(commands, " "))
}

//------------------------------------------------------------------------------

type starttls struct {
tag string
parser *parser
tag string
}

func (c *starttls) execute(sess *session) *response {
Expand All @@ -59,10 +75,8 @@ func (c *starttls) execute(sess *session) *response {
sess.conn = tls.Server(sess.conn, &tls.Config{Certificates: sess.listener.certificates})
textConn := textproto.NewConn(sess.conn)

// replace current lexer reader
c.parser.lexer.reader = &textConn.Reader

return empty().replaceBuffers(textConn.R, textConn.W)
sess.encryption = tlsLevel
return empty().replaceBuffers(textConn)
}

//------------------------------------------------------------------------------
Expand Down
2 changes: 0 additions & 2 deletions demo/auth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

func main() {
// This server uses boltDb for its authentication, adding a test user
m := &imap.DummyMailstore{}

// Create a file for the BoltAuthStore - in production this should probably NOT be a temporary file (!)
tmpFile, err := ioutil.TempFile("", "imap_")
Expand All @@ -29,7 +28,6 @@ func main() {
// Put everything together
s := imap.NewServer(
imap.ListenOption("127.0.0.1:1193"),
imap.StoreOption(m),
imap.AuthStoreOption(a),
)

Expand Down
4 changes: 1 addition & 3 deletions demo/customaddress/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ import (
)

func main() {
// This server listens on two different ports, and with a non-default Mailstore
m := &imap.DummyMailstore{}
// This server listens on two different ports

s := imap.NewServer(
imap.ListenOption("127.0.0.1:1193"),
imap.ListenOption("127.0.0.1:1194"),
imap.StoreOption(m),
)

err := s.Start()
Expand Down
25 changes: 0 additions & 25 deletions demo/main.go

This file was deleted.

26 changes: 26 additions & 0 deletions demo/starttls/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"fmt"
imap "github.com/alienscience/imapsrv"
"log"
)

func main() {
// This server listens on two different ports, one of which allows STARTTLS

s := imap.NewServer(
imap.ListenOption("127.0.0.1:1193"), // optionally also listen to non-STARTTLS ports
imap.ListenSTARTTLSOoption("127.0.0.1:1194", "demo/starttls/public.pem", "demo/starttls/private.pem"),
)

fmt.Println("Starting server, you can test by doing:\n",
"$ telnet localhost 1193\n",
"or\n",
"$ openssl s_client -starttls imap -crlf -connect 'localhost:1194'")

err := s.Start()
if err != nil {
log.Print("IMAP server not started")
}
}
File renamed without changes.
File renamed without changes.
19 changes: 9 additions & 10 deletions imap.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package imapsrv

import (
"bufio"
"crypto/tls"
"fmt"
"github.com/alienscience/imapsrv/auth"
"crypto/tls"
"log"
"net"
)
Expand All @@ -27,7 +27,7 @@ type option func(*Server) error
// listener represents a listener as used by the server
type listener struct {
addr string
tls bool
encryption encryptionLevel
certificates []tls.Certificate
listener net.Listener
}
Expand Down Expand Up @@ -89,8 +89,8 @@ func ListenOption(Addr string) option {
}
}

// ListenStartTlsOption enable start tls with the given certificate and keyfile
func ListenStartTlsOption(Addr, certFile, keyFile string) option {
// ListenSTARTTLSOoption enables STARTTLS with the given certificate and keyfile
func ListenSTARTTLSOoption(Addr, certFile, keyFile string) option {
return func(s *Server) error {
// Load the ceritificates
var err error
Expand All @@ -103,7 +103,7 @@ func ListenStartTlsOption(Addr, certFile, keyFile string) option {
// Set up the listener
l := listener{
addr: Addr,
tls: true,
encryption: starttlsLevel,
certificates: certs,
}
s.config.listeners = append(s.config.listeners, l)
Expand Down Expand Up @@ -241,11 +241,10 @@ func (c *client) handle(s *Server) {
response := command.execute(sess)

// Possibly replace buffers (layering)
if response.bufOutReplacement != nil {
c.bufout = response.bufOutReplacement
}
if response.bufInReplacement != nil {
c.bufin = response.bufInReplacement
if response.bufReplacement != nil {
c.bufout = response.bufReplacement.W
c.bufin = response.bufReplacement.R
parser.lexer.reader = &response.bufReplacement.Reader
}

// Write back the response
Expand Down
2 changes: 1 addition & 1 deletion parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (p *parser) login(tag string) command {

// starttls creates a starttls command
func (p *parser) starttls(tag string) command {
return &starttls{tag: tag, parser: p}
return &starttls{tag: tag}
}

// logout creates a LOGOUT command
Expand Down
10 changes: 4 additions & 6 deletions response.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package imapsrv

import (
"bufio"
"net/textproto"
)

// response represents an IMAP response
Expand All @@ -17,9 +18,7 @@ type response struct {
// Should the connection be closed after the response has been sent?
closeConnection bool
// bufInReplacement is not-null if all incoming traffic should be read from this instead
bufInReplacement *bufio.Reader
// bufOutReplacement is not-null if all outgoing traffic should be written to this instead
bufOutReplacement *bufio.Writer
bufReplacement *textproto.Conn
}

// createResponse creates a response
Expand Down Expand Up @@ -72,9 +71,8 @@ func (r *response) shouldClose() *response {
}

// replaceBuffers sets two possible buffers that need replacement
func (r *response) replaceBuffers(reader *bufio.Reader, writer *bufio.Writer) *response {
r.bufInReplacement = reader
r.bufOutReplacement = writer
func (r *response) replaceBuffers(replacement *textproto.Conn) *response {
r.bufReplacement = replacement
return r
}

Expand Down
13 changes: 13 additions & 0 deletions session.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ const (
selected
)

type encryptionLevel int

const (
// unencryptedLevel indicates an unencrypted / cleartext connection
unencryptedLevel encryptionLevel = iota
// starttlsLevel indicates that an unencrypted connection can be used to start a TLS connection
starttlsLevel
// tlsLevel indicates that a secure TLS connection must be set first
tlsLevel
)

// session represents an IMAP session
type session struct {
// id is a unique identifier for this session
Expand All @@ -31,6 +42,8 @@ type session struct {
listener *listener
// conn is the currently active TCP connection
conn net.Conn
// tls indicates whether or not the communication is encrypted
encryption encryptionLevel
}

// Create a new IMAP session
Expand Down

0 comments on commit acd787d

Please sign in to comment.