smailr 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +168 -0
- data/bin/smailr +45 -22
- data/contrib/exim4.conf +42 -29
- data/contrib/install.pp +95 -0
- data/lib/smailr/dkim.rb +11 -9
- data/lib/smailr/mailbox.rb +6 -0
- data/lib/smailr/model.rb +4 -5
- data/lib/smailr.rb +61 -3
- data/migrations/004_dkims.rb +3 -2
- data/smailr.yml +9 -0
- metadata +6 -3
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,168 @@ | |
| 1 | 
            +
            # Smailr - A Virtual Mail Hosting Management CLI (ALPHA)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Smailr is a small CLI application, which lets you manage the database for a
         | 
| 4 | 
            +
            typical Exim/Dovecot stack.
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Configuration files are provided within the contrib directory, so you should be
         | 
| 7 | 
            +
            able to get everything up and running within a couple of minutes.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Please note, Smailr is still in development!
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ## Installation
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Install Smailr
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                # gem install smailr
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            Add a user which will own the mails and is used for the LDA
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                # useradd -r -d /srv/mail vmail
         | 
| 20 | 
            +
                # mkdir /srv/mail/users
         | 
| 21 | 
            +
                # chown -R vmail:vmail /srv/mail
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            Install Exim and Dovecot
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                # aptitude install exim-daemon-heavy dovecot-imapd dovecot-pop3d
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            Install the example Exim and Dovecot configration files on your mailserver.
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                # smailr setup
         | 
| 30 | 
            +
                *****************************************************************
         | 
| 31 | 
            +
                All needed configuration files are in ./smailr-etc for review.
         | 
| 32 | 
            +
                
         | 
| 33 | 
            +
                Please install exim4, dovecot and then run the commands below, or
         | 
| 34 | 
            +
                adjust the file locations according to your environment.
         | 
| 35 | 
            +
                
         | 
| 36 | 
            +
                Also make sure to configure a location for the SQLite database
         | 
| 37 | 
            +
                file in samilr.yml.
         | 
| 38 | 
            +
                
         | 
| 39 | 
            +
                Then run 'smailr migrate' to initialize the database.
         | 
| 40 | 
            +
                *****************************************************************
         | 
| 41 | 
            +
                
         | 
| 42 | 
            +
                cp smailr-etc/smailr.yml /etc/smailr.yml
         | 
| 43 | 
            +
                cp smailr-etc/dovecot.conf /etc/dovecot/
         | 
| 44 | 
            +
                cp smailr-etc/dovecot-sql.conf /etc/dovecot/
         | 
| 45 | 
            +
                cp smailr-etc/exim4/
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                # invoke-rc.d exim4 restart
         | 
| 48 | 
            +
                # invoke-rc.d dovecot restart
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            Run the setup command to initialize the smailr database run:
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                # smailr migrate
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            You should now be ready to just manage your mailserver with the commands listed
         | 
| 55 | 
            +
            below.
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            ## Managing your mailserver
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            ### Domains
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            Add a local domain
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                smailr add example.com
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            Remove a local domain and all associated mailboxes
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                smailr rm example.com
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            List all domains
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                smailr ls
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            ### Mailboxes
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            Add a new local mailbox. This will interactively ask you for the user password
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                smailr add user@example.com
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            You can as well specify the password on the CLI
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                smailr add user@example.com --password secretpass
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            Remove a local mailbox
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                smailr rm user@example.com
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            List all addresses for a domain
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                smailr ls example.com
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            Update a users passowrd
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                smailr passwd user@example.com
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            ### Aliases
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            Simply add an 'user-alias@example.com' alias to the 'user@example.com' mailbox.
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                smailr add user-alias@example.com --alias user@example.com
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            To remove the alias again, run the rm command.
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                smailr rm user-alias@example.com --alias user@example.com
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            You can as well specify multiple destinations for both commands separated by a comma:
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                smailr add user-alias@example.com --alias user@example.com,user1@example.com
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            ### DKIM
         | 
| 110 | 
            +
             | 
| 111 | 
            +
            You can even manage RSA keys for Domain Key Identified Mail (DKIM).
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            To create a new key for the selector MX do:
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                # smailr add example.com --dkim mx
         | 
| 116 | 
            +
                public-key MIGJAo<snip>AAE= # returns the public key to use
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            To remove the key again run:
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                smailr rm example.com --dkim mx
         | 
| 121 | 
            +
             | 
| 122 | 
            +
            **IMPORTANT NOTE**: You will need to setup DNS manually for DKIM to work. The
         | 
| 123 | 
            +
            above example requires the following DNS records:
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                $ORIGIN example.com
         | 
| 126 | 
            +
                   _domainkey     IN      TXT     "t=y\; o=~\;"
         | 
| 127 | 
            +
                mx._domainkey     IN      TXT     "v=DKIM1\; t=y\; k=rsa\; p=MIGJAo<snip>AAE="
         | 
| 128 | 
            +
             | 
| 129 | 
            +
            Further explenation:
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                'mx'   matches up with your dkim_selector specified on you CLI.
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                't=y'  tells remote MTAs, that you are still testing DKIM.
         | 
| 134 | 
            +
                       Use t=n once everything works.
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                'o=~'  tells everybody, that only some may gets signed.
         | 
| 137 | 
            +
                       Use o=- if you want to sign everything.
         | 
| 138 | 
            +
             | 
| 139 | 
            +
            The exim configuration assumes a selector of 'mx' by default. You can change that, so
         | 
| 140 | 
            +
            it matches something else. Eg. the current month of the year, in case you want
         | 
| 141 | 
            +
            to generate a new key every month.
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            Check the remote\_smtp transport configuration in the supplied Exim configuration file
         | 
| 144 | 
            +
            to change that.
         | 
| 145 | 
            +
             | 
| 146 | 
            +
            ### Mutt
         | 
| 147 | 
            +
             | 
| 148 | 
            +
            Smailr can launch mutt with the required configuration for a specific mailbox
         | 
| 149 | 
            +
            automatically. Open mutt for the specified mailbox:
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                smailr mutt user@example.com
         | 
| 152 | 
            +
             | 
| 153 | 
            +
            ## Compatibility
         | 
| 154 | 
            +
             | 
| 155 | 
            +
            Smailr was developed an tested on Debian/Squeeze and should be easily portable
         | 
| 156 | 
            +
            to any other system.
         | 
| 157 | 
            +
             | 
| 158 | 
            +
            ## BUGS
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            For bugs or feature requests, please use the GitHub issue tracker.
         | 
| 161 | 
            +
             | 
| 162 | 
            +
            https://github.com/sts/smailr/issues
         | 
| 163 | 
            +
             | 
| 164 | 
            +
             | 
| 165 | 
            +
            ## WHO
         | 
| 166 | 
            +
             | 
| 167 | 
            +
            Stefan Schlesinger / sts@ono.at / @stsonoat / http://sts.ono.at
         | 
| 168 | 
            +
             | 
    
        data/bin/smailr
    CHANGED
    
    | @@ -3,8 +3,6 @@ $: << File.expand_path('../../lib', __FILE__) | |
| 3 3 |  | 
| 4 4 | 
             
            require 'smailr'
         | 
| 5 5 |  | 
| 6 | 
            -
            DB = Sequel.connect("sqlite:///etc/exim4/smailr.sqlite")
         | 
| 7 | 
            -
             | 
| 8 6 | 
             
            #
         | 
| 9 7 | 
             
            # CLI Helpers
         | 
| 10 8 | 
             
            #
         | 
| @@ -14,25 +12,27 @@ def determine_object(string) | |
| 14 12 | 
             
            end
         | 
| 15 13 |  | 
| 16 14 | 
             
            def ask_password
         | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 15 | 
            +
                min_password_length = Smailr.config["password_policy"]["length"]
         | 
| 16 | 
            +
                
         | 
| 17 | 
            +
                password = ask("Password: ") { |q| q.echo = "*" }
         | 
| 18 | 
            +
                confirm  = ask("Confirm: ")  { |q| q.echo = "*" }
         | 
| 20 19 |  | 
| 21 20 | 
             
                if password != confirm
         | 
| 22 21 | 
             
                    say("Mismatch; try again.")
         | 
| 23 22 | 
             
                    ask_password
         | 
| 24 23 | 
             
                end
         | 
| 25 24 |  | 
| 26 | 
            -
                if password.length < min_password_length
         | 
| 25 | 
            +
                if password.length < min_password_length.to_i
         | 
| 27 26 | 
             
                    say("Too short; try again.")
         | 
| 28 27 | 
             
                    ask_password
         | 
| 29 28 | 
             
                end
         | 
| 30 29 |  | 
| 31 | 
            -
                 | 
| 30 | 
            +
                password
         | 
| 32 31 | 
             
            end
         | 
| 33 32 |  | 
| 34 33 | 
             
            program :version, Smailr::VERSION
         | 
| 35 | 
            -
            program :description, 'Simple MAIL  | 
| 34 | 
            +
            program :description, 'Simple MAIL manageR - Virtual mail hosting management from the CLI'
         | 
| 35 | 
            +
             | 
| 36 36 |  | 
| 37 37 | 
             
            #
         | 
| 38 38 | 
             
            # Commands
         | 
| @@ -44,9 +44,9 @@ command :add do |c| | |
| 44 44 | 
             
                c.example 'Add a mailbox', 'smailr add user@example.com'
         | 
| 45 45 | 
             
                c.example 'Add an alias',  'smailr add alias@localdom.com --alias user@example.com,user1@example.com'
         | 
| 46 46 | 
             
                c.example 'Setup DKIM for a domain', 'smailr add ono.at --dkim'
         | 
| 47 | 
            -
                c.option  '--alias  | 
| 48 | 
            -
                c.option  '--password  | 
| 49 | 
            -
                c.option  '--dkim', | 
| 47 | 
            +
                c.option  '--alias DESTINATION', String, 'Specify the alias destination.'
         | 
| 48 | 
            +
                c.option  '--password PASSWORD', String, 'The password for a new mailbox. If you omit this option, it prompts for one.'
         | 
| 49 | 
            +
                c.option  '--dkim SELECTOR',     String, 'Add a DKIM Key with the specified selector for domain.'
         | 
| 50 50 | 
             
                c.action do |args, options|
         | 
| 51 51 | 
             
                    address = args[0]
         | 
| 52 52 | 
             
                    type    = determine_object(address)
         | 
| @@ -54,7 +54,10 @@ command :add do |c| | |
| 54 54 | 
             
                    case type
         | 
| 55 55 | 
             
                        when :domain
         | 
| 56 56 | 
             
                            if options.dkim
         | 
| 57 | 
            -
                                 | 
| 57 | 
            +
                                selector = options.dkim
         | 
| 58 | 
            +
                                key = Smailr::Dkim.add(address, selector)
         | 
| 59 | 
            +
                                
         | 
| 60 | 
            +
                                puts "public-key " + key.to_a[1..-2].join.gsub(/\n/, '')
         | 
| 58 61 | 
             
                            else
         | 
| 59 62 | 
             
                                Smailr::Domain.add(address)
         | 
| 60 63 | 
             
                            end
         | 
| @@ -87,7 +90,7 @@ command :ls do |c| | |
| 87 90 | 
             
                                puts "a: #{aliass.localpart}@#{args[0]} > #{aliass.dstlocalpart}@#{aliass.dstdomain}"
         | 
| 88 91 | 
             
                            end
         | 
| 89 92 | 
             
                        when nil
         | 
| 90 | 
            -
                            domains = DB[:domains]
         | 
| 93 | 
            +
                            domains = Smailr::DB[:domains]
         | 
| 91 94 | 
             
                            domains.all.each do |d|
         | 
| 92 95 | 
             
                                domain = Smailr::Model::Domain[:fqdn => d[:fqdn]]
         | 
| 93 96 | 
             
                                puts d[:fqdn]
         | 
| @@ -104,15 +107,16 @@ command :rm do |c| | |
| 104 107 | 
             
                c.summary = 'Remove a domain, mailbox or alias known to the mail system.'
         | 
| 105 108 | 
             
                c.example 'Remove a domain', 'smailr rm example.com'
         | 
| 106 109 | 
             
                c.option '--force', 'Force the operation, do not ask for confirmation.'
         | 
| 107 | 
            -
                c.option '--dkim',  'Remove a dkim key.' 
         | 
| 108 | 
            -
                c.option '--alias  | 
| 110 | 
            +
                c.option '--dkim SELECTOR',  String, 'Remove a dkim key.' 
         | 
| 111 | 
            +
                c.option '--alias DESTINATION', String, 'Specify the destination you want to remove from the alias.'
         | 
| 109 112 | 
             
                c.action do |args, options|
         | 
| 110 113 | 
             
                    address = args[0]
         | 
| 111 114 | 
             
                    type    = determine_object(address)
         | 
| 112 115 | 
             
                    case type
         | 
| 113 116 | 
             
                        when :domain
         | 
| 114 117 | 
             
                            if options.dkim
         | 
| 115 | 
            -
                                 | 
| 118 | 
            +
                                selecotr = options.dkim
         | 
| 119 | 
            +
                                Smailr::Dkim.rm(address, selector)
         | 
| 116 120 | 
             
                            else
         | 
| 117 121 | 
             
                                Smailr::Domain.rm(address, options.force)
         | 
| 118 122 | 
             
                            end
         | 
| @@ -130,6 +134,25 @@ command :rm do |c| | |
| 130 134 | 
             
                end
         | 
| 131 135 | 
             
            end
         | 
| 132 136 |  | 
| 137 | 
            +
            command :passwd do |c|
         | 
| 138 | 
            +
                c.syntax  = 'smailr passwd mailbox'
         | 
| 139 | 
            +
                c.summary = 'Update a users password.'
         | 
| 140 | 
            +
                c.action do |args,options|
         | 
| 141 | 
            +
                    address  = args[0]
         | 
| 142 | 
            +
                    password = ask_password
         | 
| 143 | 
            +
                    Smailr::Mailbox.update_password(address, password)
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
            end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
             | 
| 148 | 
            +
            command :setup do |c|
         | 
| 149 | 
            +
                c.syntax  = 'smailr setup'
         | 
| 150 | 
            +
                c.summary = 'Install a required components on a mailserver'
         | 
| 151 | 
            +
                c.action do |args,options|
         | 
| 152 | 
            +
                    Smailr::setup
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
            end
         | 
| 155 | 
            +
             | 
| 133 156 |  | 
| 134 157 | 
             
            command :migrate do |c|
         | 
| 135 158 | 
             
                c.syntax  = 'smailr migrate [options]'
         | 
| @@ -137,12 +160,12 @@ command :migrate do |c| | |
| 137 160 | 
             
                c.option '--to VERSION', String, 'Migrate the database to a specifict version.'
         | 
| 138 161 | 
             
                c.action do |args,options|
         | 
| 139 162 | 
             
                    require 'sequel/extensions/migration'
         | 
| 140 | 
            -
                    raise "Database not configured" unless DB
         | 
| 163 | 
            +
                    raise "Database not configured" unless Smailr::DB
         | 
| 141 164 |  | 
| 142 165 | 
             
                    if options.version.nil?
         | 
| 143 | 
            -
                        Sequel::Migrator.apply(DB, Smailr.migrations_directory)
         | 
| 166 | 
            +
                        Sequel::Migrator.apply(Smailr::DB, Smailr.migrations_directory)
         | 
| 144 167 | 
             
                    else
         | 
| 145 | 
            -
                        Sequel::Migrator.apply(DB, Smailr.migrations_directory, :target => options.version.to_i)
         | 
| 168 | 
            +
                        Sequel::Migrator.apply(Smailr::DB, Smailr.migrations_directory, :target => options.version.to_i)
         | 
| 146 169 | 
             
                    end
         | 
| 147 170 | 
             
                end
         | 
| 148 171 | 
             
            end
         | 
| @@ -157,9 +180,9 @@ command :mutt do |c| | |
| 157 180 | 
             
                c.example       'Open test@example.com', 'smailr mutt test@example.com'
         | 
| 158 181 | 
             
                c.action do |args,options|
         | 
| 159 182 | 
             
                    localpart, fqdn = args[0].split('@')
         | 
| 160 | 
            -
                    `command -v mutt  | 
| 161 | 
            -
                    if  | 
| 162 | 
            -
                        exec "MAIL=/srv/mail/users/#{fqdn}/#{localpart} MAILDIR=$MAIL mutt -mMaildir | 
| 183 | 
            +
                    mutt = `command -v mutt || { echo "Please install mutt first. Aborting." >&2; exit 1; }`
         | 
| 184 | 
            +
                    if $?
         | 
| 185 | 
            +
                        exec "MAIL=/srv/mail/users/#{fqdn}/#{localpart} MAILDIR=$MAIL #{mutt} -mMaildir"
         | 
| 163 186 | 
             
                    end
         | 
| 164 187 | 
             
                end
         | 
| 165 188 | 
             
            end
         | 
    
        data/contrib/exim4.conf
    CHANGED
    
    | @@ -1,16 +1,29 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            #############################################################################
         | 
| 2 2 | 
             
            # Smailr Exim Configuration
         | 
| 3 3 |  | 
| 4 | 
            +
            EXIM_CONF            = /etc/exim4
         | 
| 4 5 |  | 
| 5 | 
            -
             | 
| 6 | 
            +
            SQLITE_DATABASE_FILE = EXIM_CONF/smailr.sqlite
         | 
| 6 7 |  | 
| 7 | 
            -
             | 
| 8 | 
            +
            DKIM_DOMAIN          = ${lc:${domain:$h_from:}}
         | 
| 8 9 |  | 
| 9 | 
            -
             | 
| 10 | 
            +
            DKIM_SELECTOR        = mx
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            #############################################################################
         | 
| 13 | 
            +
            # Database Queries
         | 
| 10 14 |  | 
| 11 15 | 
             
            VIRTUAL_DOMAINS_SQL  = SELECT DISTINCT fqdn FROM domains WHERE fqdn = '${quote_sqlite:$domain}'
         | 
| 12 16 | 
             
            VIRTUAL_DOMAINS      = ${lookup sqlite{SQLITE_DATABASE_FILE VIRTUAL_DOMAINS_SQL}}
         | 
| 13 17 |  | 
| 18 | 
            +
            R_VIRTUAL_ALIASES_DATA_SQL = \
         | 
| 19 | 
            +
                SELECT aliases.dstlocalpart || '@' || aliases.dstdomain \
         | 
| 20 | 
            +
                  FROM aliases, domains \
         | 
| 21 | 
            +
                 WHERE aliases.localpart = '${quote_sqlite:$local_part}' \
         | 
| 22 | 
            +
                   AND domains.fqdn = '${quote_sqlite:$domain}' \
         | 
| 23 | 
            +
                   AND aliases.domain_id = domains.id
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            R_VIRTUAL_ALIASES_DATA = ${lookup sqlite {SQLITE_DATABASE_FILE R_VIRTUAL_ALIASES_DATA_SQL}{$value}fail}
         | 
| 26 | 
            +
             | 
| 14 27 | 
             
            R_VIRTUAL_MAILBOX_CONDITION_SQL = \
         | 
| 15 28 | 
             
                SELECT '/srv/mail/users/' || domains.fqdn || '/' || mailboxes.localpart \
         | 
| 16 29 | 
             
                  FROM mailboxes, domains \
         | 
| @@ -20,7 +33,23 @@ R_VIRTUAL_MAILBOX_CONDITION_SQL = \ | |
| 20 33 |  | 
| 21 34 | 
             
            R_VIRTUAL_MAILBOX_CONDITION = ${lookup sqlite{SQLITE_DATABASE_FILE R_VIRTUAL_MAILBOX_CONDITION_SQL}}
         | 
| 22 35 |  | 
| 23 | 
            -
             | 
| 36 | 
            +
            DKIM_PRIVATE_KEY_SQL = \
         | 
| 37 | 
            +
                SELECT private_key \
         | 
| 38 | 
            +
                  FROM dkims, domains \
         | 
| 39 | 
            +
                 WHERE dkims.selector  = 'mx' \
         | 
| 40 | 
            +
                   AND domains.fqdn    = '${quote_sqlite:DKIM_DOMAIN}' \
         | 
| 41 | 
            +
                   AND dkims.domain_id = domains.id
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            DKIM_PRIVATE_KEY = ${lookup sqlite{SQLITE_DATABASE_FILE DKIM_PRIVATE_KEY_SQL}{$value}fail}
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            ################################################################################
         | 
| 46 | 
            +
            # Domain Lists
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            domainlist local_domains    = @ : VIRTUAL_DOMAINS
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            domainlist relay_to_domains =
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            hostlist   relay_from_hosts =
         | 
| 24 53 |  | 
| 25 54 | 
             
            #############################################################################
         | 
| 26 55 | 
             
            # Main Settings
         | 
| @@ -124,8 +153,6 @@ acl_smtp_expn    = deny | |
| 124 153 | 
             
            begin acl
         | 
| 125 154 |  | 
| 126 155 | 
             
            acl_check_rcpt:
         | 
| 127 | 
            -
                # TODO: Put up propper spam detection
         | 
| 128 | 
            -
             | 
| 129 156 | 
             
                # Accept if source is local SMTP (not over TCP). We do this by testing
         | 
| 130 157 | 
             
                # for an empty sending host field.
         | 
| 131 158 | 
             
                accept hosts          = :
         | 
| @@ -138,15 +165,6 @@ acl_check_rcpt: | |
| 138 165 | 
             
                # circumvent relaying restrictions.
         | 
| 139 166 | 
             
                deny    local_parts   = ^.*[@%!/|] : ^\\.
         | 
| 140 167 |  | 
| 141 | 
            -
                # Don't scan messages with our cryptographic header.
         | 
| 142 | 
            -
                # This is needed for messages, which run the ACL twize, (eg. redirects)
         | 
| 143 | 
            -
                # to save processing time.
         | 
| 144 | 
            -
                warn    message       = X-SA-Do-Not-Run: Yes
         | 
| 145 | 
            -
                        condition     = ${if eq{\
         | 
| 146 | 
            -
                                            ${hmac{md5}{ACL_DONT_SCAN_TWIZE_SECRET}{$body_linecount}}}\
         | 
| 147 | 
            -
                                            {$h_X-Scan-Signature:}\
         | 
| 148 | 
            -
                                            {1}{0}}
         | 
| 149 | 
            -
             | 
| 150 168 | 
             
                # Accept authenticated messages.
         | 
| 151 169 | 
             
                accept  authenticated = *
         | 
| 152 170 |  | 
| @@ -211,14 +229,8 @@ begin routers | |
| 211 229 | 
             
                    domains = +local_domains
         | 
| 212 230 | 
             
                    allow_fail
         | 
| 213 231 | 
             
                    allow_defer
         | 
| 214 | 
            -
                    # Lookup the mailbox which we route to
         | 
| 215 | 
            -
                    data =  | 
| 216 | 
            -
                                SELECT mailboxes.localpart || '@' || domains.fqdn \
         | 
| 217 | 
            -
                                  FROM mailboxes, domains, aliases \
         | 
| 218 | 
            -
                                 WHERE aliases.address = '${quote_sqlite:$local_part}@${quote_sqlite:$domain}' \
         | 
| 219 | 
            -
                                   AND domains.fqdn = '${quote_sqlite:$domain}' \
         | 
| 220 | 
            -
                                   AND mailboxes.domain_id = domains.id \
         | 
| 221 | 
            -
                                   AND aliases.mailbox_id = mailboxes.id }{$value}fail}
         | 
| 232 | 
            +
                    # Lookup the mailbox which we route the message to
         | 
| 233 | 
            +
                    data = R_VIRTUAL_ALIASES_DATA
         | 
| 222 234 |  | 
| 223 235 | 
             
                virtual_mailbox:
         | 
| 224 236 | 
             
                    debug_print = "R: virtual_mailbox for $local_part@$domain"
         | 
| @@ -251,9 +263,11 @@ begin transports | |
| 251 263 | 
             
                    debug_print = "T: remote_smtp for $local_part@$domain"
         | 
| 252 264 | 
             
                    driver      = smtp
         | 
| 253 265 | 
             
                    hosts_nopass_tls = *
         | 
| 254 | 
            -
                     | 
| 255 | 
            -
                     | 
| 256 | 
            -
                     | 
| 266 | 
            +
                    dkim_domain = DKIM_DOMAIN
         | 
| 267 | 
            +
                    dkim_selector = DKIM_SELECTOR
         | 
| 268 | 
            +
                    dkim_private_key = DKIM_PRIVATE_KEY
         | 
| 269 | 
            +
                    dkim_canon = relaxed
         | 
| 270 | 
            +
                    dkim_strict = 0
         | 
| 257 271 |  | 
| 258 272 |  | 
| 259 273 | 
             
                dovecot_virtual_delivery:
         | 
| @@ -268,8 +282,6 @@ begin transports | |
| 268 282 | 
             
                    log_output
         | 
| 269 283 | 
             
                    user = vmail
         | 
| 270 284 | 
             
                    temp_errors = 64 : 69 : 70: 71 : 72 : 73 : 74 : 75 : 78
         | 
| 271 | 
            -
                    # Remove the X-SA_Exim-Rcpt-To header again, otherwise we would expose BCCs
         | 
| 272 | 
            -
                    headers_remove = "X-SA-Exim-Rcpt-To"
         | 
| 273 285 |  | 
| 274 286 |  | 
| 275 287 | 
             
            #############################################################################
         | 
| @@ -306,3 +318,4 @@ begin authenticators | |
| 306 318 | 
             
                                                               AND domains.fqdn = '${quote_sqlite:${domain:$auth2}}' \
         | 
| 307 319 | 
             
                                                               AND domains.id = mailboxes.domain_id} \
         | 
| 308 320 | 
             
                                  {$value}fail}} }} {yes}{no}}"
         | 
| 321 | 
            +
                    client_condition = ${if !eq{$tls_cipher}{}}
         | 
    
        data/contrib/install.pp
    ADDED
    
    | @@ -0,0 +1,95 @@ | |
| 1 | 
            +
            class smailr::mx
         | 
| 2 | 
            +
            {
         | 
| 3 | 
            +
                include smailr::params
         | 
| 4 | 
            +
                include smailr::mx::common
         | 
| 5 | 
            +
                include smailr::mx::exim
         | 
| 6 | 
            +
                include smailr::mx::dovecot
         | 
| 7 | 
            +
            }
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            class smailr::params
         | 
| 10 | 
            +
            {
         | 
| 11 | 
            +
                $smailr_version = "0.5.0"
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                $smailr_mailstorage = "/srv/mail"
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                $smailr_contrib = $lsbdistcodename ? {
         | 
| 16 | 
            +
                    "Debian": "/var/lib/ruby/gems/smailr-${version}/contrib",
         | 
| 17 | 
            +
                }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                $exim_package_name = $lsbdistid ? {
         | 
| 20 | 
            +
                    "Debian": "exim4-daemon-heavy"
         | 
| 21 | 
            +
                }
         | 
| 22 | 
            +
            }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            class smailr::mx::common
         | 
| 25 | 
            +
            {
         | 
| 26 | 
            +
                user { "vmail":
         | 
| 27 | 
            +
                    ensure => present,
         | 
| 28 | 
            +
                }
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                group { "vmail":
         | 
| 31 | 
            +
                    ensure => present,
         | 
| 32 | 
            +
                }
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                file {
         | 
| 35 | 
            +
                    $smailr_mailstorage:
         | 
| 36 | 
            +
                        ensure  => direcotry,
         | 
| 37 | 
            +
                        owner   => "vmail",
         | 
| 38 | 
            +
                        group   => "vmail",
         | 
| 39 | 
            +
                        mode    => 0660,
         | 
| 40 | 
            +
                        require => User["vmail"];
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    "${smailr_mailstorage}/users":
         | 
| 43 | 
            +
                        ensure  => directory,
         | 
| 44 | 
            +
                        owner   => "vmail",
         | 
| 45 | 
            +
                        group   => "vmail",
         | 
| 46 | 
            +
                        mode    => "0660",
         | 
| 47 | 
            +
                        require => File["/srv/mail"];
         | 
| 48 | 
            +
                }
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            }
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            class smailr::mx::exim
         | 
| 53 | 
            +
            {
         | 
| 54 | 
            +
                package { "exim4-daemon-heavy":
         | 
| 55 | 
            +
                    name   => $smailr::params::exim_package_name
         | 
| 56 | 
            +
                    ensure => present,
         | 
| 57 | 
            +
                }
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                file {
         | 
| 60 | 
            +
                    "/etc/exim4/exim4.conf":
         | 
| 61 | 
            +
                        ensure  => present,
         | 
| 62 | 
            +
                        source  => "file:///${smailr_contrib}/exim4.conf"
         | 
| 63 | 
            +
                        require => Package["exim4-daemon-heavy"];
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    "/etc/default/exim4":
         | 
| 66 | 
            +
                        ensure  => present,
         | 
| 67 | 
            +
                        owner   => "root",
         | 
| 68 | 
            +
                        group   => "root",
         | 
| 69 | 
            +
                        source  => "file:///${smailr_contrib}/exim4.defaults",
         | 
| 70 | 
            +
                        require => Package["exim4-daemon-heavy"];
         | 
| 71 | 
            +
                }
         | 
| 72 | 
            +
            }
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            class smailr::mx::dovecot
         | 
| 75 | 
            +
            {
         | 
| 76 | 
            +
                package { "dovecot-imapd":
         | 
| 77 | 
            +
                    ensure => present,
         | 
| 78 | 
            +
                }
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                package { "dovecot-pop3d":
         | 
| 81 | 
            +
                    ensure => present,
         | 
| 82 | 
            +
                }
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                file {
         | 
| 85 | 
            +
                    "/etc/dovecot/dovecot.conf":
         | 
| 86 | 
            +
                        ensure  => present,
         | 
| 87 | 
            +
                        source  => "file:///${smailr_contrib}/dovecot.conf"
         | 
| 88 | 
            +
                        require => Package["dovecot-imapd"];
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                    "/etc/dovecot/dovecot.conf":
         | 
| 91 | 
            +
                        ensure  => present,
         | 
| 92 | 
            +
                        source  => "file:///${smailr_contrib}/dovecot-sql.conf"
         | 
| 93 | 
            +
                        require => Package["dovecot-imapd"];
         | 
| 94 | 
            +
                }
         | 
| 95 | 
            +
            }
         | 
    
        data/lib/smailr/dkim.rb
    CHANGED
    
    | @@ -3,24 +3,26 @@ require 'openssl' | |
| 3 3 |  | 
| 4 4 | 
             
            module Smailr
         | 
| 5 5 | 
             
                module Dkim
         | 
| 6 | 
            -
                    def self.add(fqdn,  | 
| 7 | 
            -
                        options.testing ||= true
         | 
| 8 | 
            -
             | 
| 6 | 
            +
                    def self.add(fqdn, selector)
         | 
| 9 7 | 
             
                        if not Model::Domain[:fqdn => fqdn]
         | 
| 10 8 | 
             
                            say_error "You trying to add a DKIM key for a non existing domain: #{fqdn}"
         | 
| 11 9 | 
             
                            exit 1
         | 
| 12 10 | 
             
                        end
         | 
| 13 11 |  | 
| 14 12 | 
             
                        private_key, public_key = generate_rsa_key
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                        dkim. | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 13 | 
            +
             | 
| 14 | 
            +
                        dkim = Model::Dkim.for_domain!(fqdn, selector)
         | 
| 15 | 
            +
                        dkim.private_key = private_key
         | 
| 16 | 
            +
                        dkim.public_key  = public_key
         | 
| 17 | 
            +
                        dkim.selector    = selector
         | 
| 19 18 | 
             
                        dkim.save
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                        # Return the key so it can be used for automation
         | 
| 21 | 
            +
                        dkim.public_key
         | 
| 20 22 | 
             
                    end
         | 
| 21 23 |  | 
| 22 | 
            -
                    def self.rm(fqdn,  | 
| 23 | 
            -
                        dkim = Model::Dkim.for_domain(fqdn)
         | 
| 24 | 
            +
                    def self.rm(fqdn, selector)
         | 
| 25 | 
            +
                        dkim = Model::Dkim.for_domain(fqdn, selector)
         | 
| 24 26 | 
             
                        dkim.destroy
         | 
| 25 27 | 
             
                    end
         | 
| 26 28 |  | 
    
        data/lib/smailr/mailbox.rb
    CHANGED
    
    | @@ -13,6 +13,12 @@ module Smailr | |
| 13 13 | 
             
                        mbox.save
         | 
| 14 14 | 
             
                    end
         | 
| 15 15 |  | 
| 16 | 
            +
                    def self.update_password(address, password)
         | 
| 17 | 
            +
                        mbox = Model::Mailbox.for_address(address)
         | 
| 18 | 
            +
                        mbox.password = password
         | 
| 19 | 
            +
                        mbox.save
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
             | 
| 16 22 | 
             
                    def self.rm(address, options)
         | 
| 17 23 | 
             
                        mbox = Model::Mailbox.for_address(address)
         | 
| 18 24 | 
             
                        mbox.rm_related
         | 
    
        data/lib/smailr/model.rb
    CHANGED
    
    | @@ -17,14 +17,13 @@ module Smailr | |
| 17 17 | 
             
                    class Dkim < Sequel::Model
         | 
| 18 18 | 
             
                        many_to_one :domain
         | 
| 19 19 |  | 
| 20 | 
            -
                        def self.for_domain(fqdn)
         | 
| 21 | 
            -
                            self[:domain => Domain[:fqdn => fqdn]]
         | 
| 20 | 
            +
                        def self.for_domain(fqdn, selector)
         | 
| 21 | 
            +
                            self[:domain => Domain[:fqdn => fqdn], :selector => selector]
         | 
| 22 22 | 
             
                        end
         | 
| 23 23 |  | 
| 24 | 
            -
                        def self.for_domain!(fqdn)
         | 
| 25 | 
            -
                            find_or_create(:domain => Domain[:fqdn => fqdn])
         | 
| 24 | 
            +
                        def self.for_domain!(fqdn, selector)
         | 
| 25 | 
            +
                            find_or_create(:domain => Domain[:fqdn => fqdn], :selector => selector)
         | 
| 26 26 | 
             
                        end
         | 
| 27 | 
            -
                        one_to_many :aliases
         | 
| 28 27 | 
             
                     end
         | 
| 29 28 |  | 
| 30 29 | 
             
                    class Mailbox < Sequel::Model
         | 
    
        data/lib/smailr.rb
    CHANGED
    
    | @@ -1,9 +1,13 @@ | |
| 1 1 | 
             
            require 'rubygems'
         | 
| 2 | 
            +
            require 'yaml'
         | 
| 2 3 | 
             
            require 'sqlite3'
         | 
| 3 4 | 
             
            require 'sequel'
         | 
| 4 5 | 
             
            require 'commander/import'
         | 
| 6 | 
            +
            require 'fileutils'
         | 
| 5 7 |  | 
| 6 8 | 
             
            module Smailr
         | 
| 9 | 
            +
                VERSION = '0.5.0'
         | 
| 10 | 
            +
             | 
| 7 11 | 
             
                autoload :Model,   'smailr/model'
         | 
| 8 12 | 
             
                autoload :Domain,  'smailr/domain'
         | 
| 9 13 | 
             
                autoload :Mailbox, 'smailr/mailbox'
         | 
| @@ -11,12 +15,66 @@ module Smailr | |
| 11 15 | 
             
                autoload :Dkim,    'smailr/dkim'
         | 
| 12 16 |  | 
| 13 17 | 
             
                class << self;
         | 
| 18 | 
            +
                    attr_accessor :config
         | 
| 19 | 
            +
                    attr_accessor :load_config
         | 
| 14 20 | 
             
                    attr_accessor :contrib_directory
         | 
| 15 21 | 
             
                    attr_accessor :migrations_directory
         | 
| 16 22 | 
             
                end
         | 
| 17 23 |  | 
| 18 | 
            -
                 | 
| 24 | 
            +
                def self.load_config=(files)
         | 
| 25 | 
            +
                    config = {}
         | 
| 26 | 
            +
                    files.each do |f|
         | 
| 27 | 
            +
                        if File.readable?(f)
         | 
| 28 | 
            +
                            config.merge!(YAML.load_file(f))
         | 
| 29 | 
            +
                        end
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
                    self.config = config
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def self.db_connect
         | 
| 35 | 
            +
                    Sequel.connect(self.config['database'])
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
             | 
| 39 | 
            +
                def self.setup
         | 
| 40 | 
            +
                    prefix = self.contrib_directory
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    FileUtils.mkdir_p "smailr-etc/exim4"
         | 
| 43 | 
            +
                    FileUtils.mkdir_p "smailr-etc/dovecot"
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                    FileUtils.cp File.expand_path("../README.md", prefix),    "smailr-etc/"
         | 
| 46 | 
            +
                    FileUtils.cp File.expand_path("../smailr.yml", prefix),   "smailr-etc/"
         | 
| 47 | 
            +
                    FileUtils.cp File.expand_path("exim4.conf", prefix),      "smailr-etc/exim4"
         | 
| 48 | 
            +
                    FileUtils.cp File.expand_path("dovecot.conf", prefix),    "smailr-etc/dovecot"
         | 
| 49 | 
            +
                    FileUtils.cp File.expand_path("dovecot-sql.conf", prefix),"smailr-etc/dovecot"
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    say "*****************************************************************"
         | 
| 52 | 
            +
                    say "All needed configuration files are in ./smailr-etc for review."
         | 
| 53 | 
            +
                    say "\n"
         | 
| 54 | 
            +
                    say "Please install exim4, dovecot and then run the commands below, or"
         | 
| 55 | 
            +
                    say "adjust the file locations according to your environment."
         | 
| 56 | 
            +
                    say "\n"
         | 
| 57 | 
            +
                    say "Also make sure to configure a location for the SQLite database"
         | 
| 58 | 
            +
                    say "file in smailr.yml."
         | 
| 59 | 
            +
                    say "\n"
         | 
| 60 | 
            +
                    say "Then run 'smailr migrate' to initialize the database."
         | 
| 61 | 
            +
                    say "*****************************************************************"
         | 
| 62 | 
            +
                    say "\n"
         | 
| 63 | 
            +
                    say "cp smailr-etc/smailr.yml /etc/smailr.yml"
         | 
| 64 | 
            +
                    say "cp smailr-etc/dovecot.conf /etc/dovecot/"
         | 
| 65 | 
            +
                    say "cp smailr-etc/dovecot-sql.conf /etc/dovecot/"
         | 
| 66 | 
            +
                    say "cp smailr-etc/exim4/"
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                    # Future version could maybe launch puppet here?
         | 
| 69 | 
            +
                    #
         | 
| 70 | 
            +
                    #instalpp = File.expand_path('/install.pp', self.contrib_directory)
         | 
| 71 | 
            +
                    #if agree("Shall we launch puppet with the manifest from #{installpp}? (yes/no) ")
         | 
| 72 | 
            +
                    #    exec "puppet apply #{installpp}"
         | 
| 73 | 
            +
                    #end
         | 
| 74 | 
            +
                end
         | 
| 19 75 | 
             
            end
         | 
| 20 76 |  | 
| 21 | 
            -
            Smailr.contrib_directory    ||= | 
| 22 | 
            -
            Smailr.migrations_directory ||= | 
| 77 | 
            +
            Smailr.contrib_directory    ||=   File.expand_path('../../contrib', __FILE__)
         | 
| 78 | 
            +
            Smailr.migrations_directory ||=   File.expand_path('../../migrations', __FILE__)
         | 
| 79 | 
            +
            Smailr.load_config          ||= [ File.expand_path('../../smailr.yml', __FILE__),  '/etc/smailr.yml' ]
         | 
| 80 | 
            +
            Smailr::DB = Smailr::db_connect
         | 
    
        data/migrations/004_dkims.rb
    CHANGED
    
    | @@ -5,8 +5,9 @@ Sequel.migration do | |
| 5 5 | 
             
                        foreign_key :domain_id
         | 
| 6 6 | 
             
                        String  :private_key, :required => true
         | 
| 7 7 | 
             
                        String  :public_key,  :required => true
         | 
| 8 | 
            -
                        String  : | 
| 9 | 
            -
             | 
| 8 | 
            +
                        String  :selector,    :required => true
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                        index [:domain_id, :selector], :unique => true
         | 
| 10 11 | 
             
                    end
         | 
| 11 12 | 
             
                end
         | 
| 12 13 | 
             
            end
         | 
    
        data/smailr.yml
    ADDED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: smailr
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 4 | 
            +
              hash: 11
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 0
         | 
| 8 | 
            -
              -  | 
| 8 | 
            +
              - 5
         | 
| 9 9 | 
             
              - 0
         | 
| 10 | 
            -
              version: 0. | 
| 10 | 
            +
              version: 0.5.0
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - Stefan Schlesinger
         | 
| @@ -80,10 +80,13 @@ files: | |
| 80 80 | 
             
            - contrib/dovecot-sql.conf
         | 
| 81 81 | 
             
            - contrib/dovecot.conf
         | 
| 82 82 | 
             
            - contrib/exim4.conf
         | 
| 83 | 
            +
            - contrib/install.pp
         | 
| 83 84 | 
             
            - migrations/001_domains.rb
         | 
| 84 85 | 
             
            - migrations/002_mailboxes.rb
         | 
| 85 86 | 
             
            - migrations/003_aliases.rb
         | 
| 86 87 | 
             
            - migrations/004_dkims.rb
         | 
| 88 | 
            +
            - README.md
         | 
| 89 | 
            +
            - smailr.yml
         | 
| 87 90 | 
             
            homepage: http://github.com/sts/smailr
         | 
| 88 91 | 
             
            licenses: []
         | 
| 89 92 |  |