IMAP in OCaml
at main 219 lines 6.3 kB view raw view rendered
1# imapd 2 3An IMAP4rev2 server implemented in OCaml. 4 5Implements [RFC 9051](https://datatracker.ietf.org/doc/html/rfc9051) (IMAP4rev2) with support for implicit TLS per [RFC 8314](https://datatracker.ietf.org/doc/html/rfc8314). 6 7## Features 8 9- **IMAP4rev2** (RFC 9051) with IMAP4rev1 compatibility 10- **Fork-per-connection** privilege separation (like UW-IMAP) 11- **Implicit TLS** on port 993 (RFC 8314) 12- **STARTTLS** upgrade for cleartext connections 13- **PAM authentication** using system accounts 14- **Maildir storage** with traditional `~/Maildir` layout 15- **In-memory storage** for development and testing 16 17### Supported Extensions 18 19| Extension | RFC | Description | 20|-----------|-----|-------------| 21| IDLE | [RFC 2177](https://datatracker.ietf.org/doc/html/rfc2177) | Real-time notifications | 22| NAMESPACE | [RFC 2342](https://datatracker.ietf.org/doc/html/rfc2342) | Mailbox namespaces | 23| ID | [RFC 2971](https://datatracker.ietf.org/doc/html/rfc2971) | Server identification | 24| UIDPLUS | [RFC 4315](https://datatracker.ietf.org/doc/html/rfc4315) | UID responses for COPY/APPEND | 25| ENABLE | [RFC 5161](https://datatracker.ietf.org/doc/html/rfc5161) | Capability negotiation | 26| MOVE | [RFC 6851](https://datatracker.ietf.org/doc/html/rfc6851) | Atomic move operation | 27| LITERAL+ | [RFC 7888](https://datatracker.ietf.org/doc/html/rfc7888) | Non-synchronizing literals | 28 29## Installation 30 31### Prerequisites 32 33- OCaml 5.0+ 34- opam 35- PAM development headers (`libpam0g-dev` on Debian/Ubuntu) 36 37### Building 38 39```bash 40opam install . --deps-only 41dune build 42``` 43 44### Running Tests 45 46```bash 47dune test 48``` 49 50## Usage 51 52### Development Server 53 54```bash 55# In-memory storage on port 10143 56imapd -s memory -p 10143 57``` 58 59### Production Server (Recommended) 60 61```bash 62# Fork-per-connection with implicit TLS 63# Uses ~/Maildir for each user 64sudo imapd --fork -s maildir --tls \ 65 --cert /etc/ssl/certs/mail.crt \ 66 --key /etc/ssl/private/mail.key \ 67 -p 993 68``` 69 70### Single-Process with STARTTLS 71 72```bash 73# Cleartext with STARTTLS upgrade 74imapd -s maildir --maildir-path /var/mail \ 75 --cert server.crt --key server.key \ 76 -p 143 77``` 78 79## Operating Modes 80 81### Single-Process (default) 82 83All connections handled in one process. Efficient but all sessions share the same privileges. Suitable for development or trusted environments. 84 85### Fork-per-Connection (`--fork`) 86 87Each connection forks a child process. After successful authentication, the child drops privileges to the authenticated user via `setuid`. This provides strong isolation between users. 88 89- Requires running as root 90- Only works with Maildir storage 91- STARTTLS not supported (use implicit TLS) 92 93## Storage Backends 94 95### Memory 96 97In-memory storage for development and testing. Data is not persisted. 98 99```bash 100imapd -s memory 101``` 102 103### Maildir 104 105Production storage using the [Maildir format](https://cr.yp.to/proto/maildir.html). 106 107**With shared base path:** 108```bash 109imapd -s maildir --maildir-path /var/mail 110# Mail stored at /var/mail/<username>/ 111``` 112 113**With home directories (fork mode default):** 114```bash 115sudo imapd --fork -s maildir 116# Mail stored at ~<username>/Maildir/ 117``` 118 119## Command-Line Options 120 121| Option | Description | 122|--------|-------------| 123| `-p`, `--port` | Port to listen on (default: 143) | 124| `-h`, `--host` | Host address to bind to (default: 127.0.0.1) | 125| `-s`, `--storage` | Storage backend: `memory` or `maildir` | 126| `--maildir-path` | Base path for Maildir storage | 127| `--tls` | Enable implicit TLS (requires `--cert` and `--key`) | 128| `--cert` | TLS certificate file (PEM format) | 129| `--key` | TLS private key file (PEM format) | 130| `--fork` | Fork per connection with privilege separation | 131 132## Architecture 133 134``` 135imapd/ 136├── lib/ 137│ ├── imap_types/ # Core IMAP types (RFC 9051) 138│ ├── imap_parser/ # Menhir parser + Faraday serializer 139│ ├── imap_auth/ # PAM authentication 140│ ├── imap_storage/ # Memory and Maildir backends 141│ └── imap_server/ # Connection handler and state machine 142├── bin/ 143│ └── main.ml # CLI entry point 144└── test/ # Alcotest test suite 145``` 146 147### Connection State Machine 148 149``` 150┌─────────────────────┐ 151│ Not Authenticated │ ← Initial state 152├─────────────────────┤ 153│ CAPABILITY, NOOP │ 154│ STARTTLS, LOGIN │ 155│ LOGOUT │ 156└─────────┬───────────┘ 157 │ LOGIN success 158159┌─────────────────────┐ 160│ Authenticated │ 161├─────────────────────┤ 162│ SELECT, EXAMINE │ 163│ CREATE, DELETE │ 164│ LIST, STATUS │ 165│ APPEND, IDLE │ 166└─────────┬───────────┘ 167 │ SELECT success 168169┌─────────────────────┐ 170│ Selected │ 171├─────────────────────┤ 172│ FETCH, STORE │ 173│ SEARCH, COPY, MOVE │ 174│ EXPUNGE, CLOSE │ 175└─────────────────────┘ 176``` 177 178## Security 179 180- **Privilege separation**: Fork mode drops to authenticated user via `setuid` 181- **Path traversal protection**: Username and mailbox names are validated 182- **DoS mitigation**: Maximum line length enforced (64KB) 183- **TLS**: Implicit TLS recommended for production 184 185## Testing with a Client 186 187```bash 188# Start development server 189imapd -s memory -p 10143 & 190 191# Connect with OpenSSL (cleartext for testing) 192telnet localhost 10143 193 194# Or with TLS 195openssl s_client -connect localhost:993 196``` 197 198Example session: 199``` 200* OK [CAPABILITY IMAP4rev2 ...] IMAP4rev2 Service Ready 201a001 LOGIN username password 202a001 OK [CAPABILITY ...] LOGIN completed 203a002 SELECT INBOX 204* FLAGS (\Seen \Answered \Flagged \Deleted \Draft) 205* 0 EXISTS 206* OK [UIDVALIDITY 1234567890] UIDs valid 207a002 OK [READ-WRITE] SELECT completed 208a003 LOGOUT 209* BYE IMAP4rev2 Server logging out 210a003 OK LOGOUT completed 211``` 212 213## License 214 215ISC License. See [LICENSE.md](LICENSE.md) for details. 216 217## Contributing 218 219Report bugs at https://tangled.org/@anil.recoil.org/ocaml-imap/issues