Exim Email Control Specification
From Computer Tyme Support Wiki
m (→Feature Expansion) |
m (Protected "Exim Email Control Specification" [edit=sysop:move=sysop]) |
||
(10 intermediate revisions not shown) | |||
Line 1: | Line 1: | ||
+ | viricpasr | ||
This is a specification for an email control program I'd like to have written for [http://www.exim.org Exim]. I want to make this project public domain so that others can share in it. I want to keep it simple and flexible. Looking for some volunteers to work on it. I can trade significant web hosting for people who will make this happen. | This is a specification for an email control program I'd like to have written for [http://www.exim.org Exim]. I want to make this project public domain so that others can share in it. I want to keep it simple and flexible. Looking for some volunteers to work on it. I can trade significant web hosting for people who will make this happen. | ||
Line 63: | Line 64: | ||
Email Users would have control of their account. They can change their personal settings, vacation messages, forwarding, password, etc. | Email Users would have control of their account. They can change their personal settings, vacation messages, forwarding, password, etc. | ||
- | = User / Password Files = | + | == User / Password Files == |
Currently the User Password and Alias files are stored in a directory named /etc/vmail and are just like the Unix passwd and shadow files. | Currently the User Password and Alias files are stored in a directory named /etc/vmail and are just like the Unix passwd and shadow files. | ||
- | /etc/vmail/alias.domain | + | * /etc/vmail/alias.domain |
- | /etc/vmail/passwd.domain | + | * /etc/vmail/passwd.domain |
- | /etc/vmail/shadow.domain | + | * /etc/vmail/shadow.domain |
== Feature Expansion == | == Feature Expansion == | ||
Line 79: | Line 80: | ||
Exim is very powerful. It's trivial to write a backend that runs off this structure. Dovecot can be easily configured to access this structure as well. However I think if this were done right it should be generic enough to work with other MTAs and a variety of configurations. The backend assumes that if the files don't exist then nothing happens. If they do exist then they are read and processed. | Exim is very powerful. It's trivial to write a backend that runs off this structure. Dovecot can be easily configured to access this structure as well. However I think if this were done right it should be generic enough to work with other MTAs and a variety of configurations. The backend assumes that if the files don't exist then nothing happens. If they do exist then they are read and processed. | ||
- | == So - who | + | == Parts I have Written == |
+ | |||
+ | I have several pieces of this written. I have the PHP code to authenticate users against the passwd/shadow files and to generate new passwords. I also have some PHP squirrelmail modules that edit these files. Mostly wat I need is someone to tie it all together into one interface and add some management to it so that people have access to the domains they control. | ||
+ | |||
+ | Here's the code to authenticate against the passwd/shadow files. | ||
+ | |||
+ | <?php | ||
+ | |||
+ | if ($_POST["checkpass"]) | ||
+ | { | ||
+ | |||
+ | $login = $_POST["username"]; | ||
+ | $passwd = $_POST["password"]; | ||
+ | $newpass = $_POST["newpassword"]; | ||
+ | $newpass2 = $_POST["newpassword2"]; | ||
+ | list ($user, $domain) = explode('@', $login); | ||
+ | $pass_file = "/etc/vmail/shadow.".$domain; | ||
+ | |||
+ | // Sanity Checks | ||
+ | |||
+ | if ($login == "") | ||
+ | { | ||
+ | $badInput = 1; | ||
+ | } | ||
+ | |||
+ | if (!$badInput and ($user == "" or $domain == "")) | ||
+ | { | ||
+ | echo "<b><font color='red'>Error: Bad Email Address</b></font><br>"; | ||
+ | $badInput = 1; | ||
+ | } | ||
+ | |||
+ | if (!$badInput and ($passwd == "" or $newpass == "")) | ||
+ | { | ||
+ | echo "<b><font color='red'>Error: Password Missing</b></font><br>"; | ||
+ | $badInput = 1; | ||
+ | } | ||
+ | |||
+ | if (!$badInput and strlen($newpass) < 6) | ||
+ | { | ||
+ | echo "<b><font color='red'>Error: Password must be at least 6 characters</b></font><br>"; | ||
+ | $badInput = 1; | ||
+ | } | ||
+ | |||
+ | if ($newpass != $newpass2) | ||
+ | { | ||
+ | echo "<b><font color='red'>Error: New Passwords Don't Match</b></font><br>"; | ||
+ | $badInput = 1; | ||
+ | } | ||
+ | |||
+ | if (!$badInput) { | ||
+ | |||
+ | $fp = fopen( $pass_file, "r" ); | ||
+ | if ($fp == false) | ||
+ | { | ||
+ | echo "<b><font color='red'>Error: Domain ".$domain." Doesn't Exist</b></font><br>"; | ||
+ | } else { | ||
+ | |||
+ | while ( !feof( $fp ) ) | ||
+ | { | ||
+ | $line = trim( fgets( $fp, 1000 ) ); | ||
+ | list( $f_user, $f_password, $f_last_password_changed, $two, $three, $four, $five, $six ) = explode( ':', $line ); | ||
+ | if ($f_user == $user) | ||
+ | { | ||
+ | |||
+ | $userFound = 1; | ||
+ | if ( substr($f_password, 0, 1) == "$" ) | ||
+ | { | ||
+ | $seed = substr($f_password, 0, 12); | ||
+ | $epassword = substr($f_password, 12, strlen($f_password)); | ||
+ | $epassword = $seed.$epassword; | ||
+ | $npassword = crypt($passwd, $seed); | ||
+ | } else { | ||
+ | $seed = substr($f_password, 0, 2); | ||
+ | $epassword = substr($f_password, 2, strlen($f_password)); | ||
+ | $epassword = $seed.$epassword; | ||
+ | $npassword = crypt($passwd, $seed); | ||
+ | } | ||
+ | |||
+ | if ($npassword == $epassword) { | ||
+ | $success = 1; | ||
+ | for ($n = 0; $n < 9; $n++) | ||
+ | { | ||
+ | $s .= chr(rand(64,126)); | ||
+ | } | ||
+ | $seed = "$1$".$s."$"; | ||
+ | $line = $f_user.":".crypt($_POST["newpassword"], $seed).":".floor(time()/86400).":".$two.":".$three.":".$four.":".$five.":".$six.":"; | ||
+ | } else { | ||
+ | echo "<b><font color='red'>Error: Wrong Password</b></font><br>"; | ||
+ | } | ||
+ | } | ||
+ | if ($line > "") | ||
+ | { | ||
+ | $write .= $line."\n"; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | fclose($fp); | ||
+ | |||
+ | if ($success) | ||
+ | { | ||
+ | $fp = fopen( $pass_file, "w" ); | ||
+ | fwrite($fp, $write); | ||
+ | fclose($fp); | ||
+ | echo "<b><font color='Blue'>Password Change Succeeded</font></b><br>"; | ||
+ | } | ||
+ | |||
+ | if (!$userFound) | ||
+ | { | ||
+ | echo "<b><font color='red'>Error: Invalid Email Address</font></b><br>"; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ?> | ||
+ | |||
+ | == So - who wants to make it happen? == | ||
A good programmer should be able to whip this up in a few days. I'm not much of a programmer anymore so I need someone to get it started and I can finish it. So - who wants to help get this going. The results will be GPL'd and everyone gets to share in the finished product. Email me if you want to do it. [mailto:marc@perkel.com marc@perkel.com] | A good programmer should be able to whip this up in a few days. I'm not much of a programmer anymore so I need someone to get it started and I can finish it. So - who wants to help get this going. The results will be GPL'd and everyone gets to share in the finished product. Email me if you want to do it. [mailto:marc@perkel.com marc@perkel.com] |
Latest revision as of 16:01, 23 January 2009
viricpasr This is a specification for an email control program I'd like to have written for Exim. I want to make this project public domain so that others can share in it. I want to keep it simple and flexible. Looking for some volunteers to work on it. I can trade significant web hosting for people who will make this happen.
Contents |
Overview
The idea behind this project is to create a PHP front end to text files on the back end that control Exim allowing users to have a high degree of personalization over feature that primarily control spam. This would include personal white lists, personal black lists, forwarding, etc. The backend might also be a database but I'm leaning towards text files for simplicity and if done right should be very scalable. Once the structure is in place it should be easy to add a lot of customizations to give users every toy they ever dreamed of.
Authentication - IMAP Login
The idea is you use IMAP for authentication. All users and managers will use an email address and password to authenticate. It will attempt to log in to the email account and if successful, the user is considered logged in. Once logged in the user will be able to set all the features of their own account. If the user is a manager they well see additional choices to manage the things they are allowed to manage.
Control Files
Here is what I'm proposing for a control file structure. All of these files are test files. The directory structure is designed to be fast not having a lot of files in any one directory.
/etc/exim/control /etc/exim/control/config /etc/exim/control/managers /etc/exim/control/domains /etc/exim/control/domains/example.com /etc/exim/control/domains/example.com/passwd /etc/exim/control/domains/example.com/shadow /etc/exim/control/domains/example.com/alias /etc/exim/control/domains/example.com/config /etc/exim/control/domains/example.com/managers /etc/exim/control/domains/example.com/blocked-from /etc/exim/control/domains/example.com/blocked-hosts /etc/exim/control/domains/example.com/white-from /etc/exim/control/domains/example.com/white-hosts /etc/exim/control/domains/example.com/users /etc/exim/control/domains/example.com/users/joe /etc/exim/control/domains/example.com/users/joe/config /etc/exim/control/domains/example.com/users/joe/vacation /etc/exim/control/domains/example.com/users/joe/forward /etc/exim/control/domains/example.com/users/joe/blocked-from /etc/exim/control/domains/example.com/users/joe/blocked-hosts /etc/exim/control/domains/example.com/users/joe/white-from /etc/exim/control/domains/example.com/users/joe/white-hosts
The base director contains the master control files for the entire system. Booleans and settings in the config files. The managers file contains a list of email addresses of system managers.
Under each domain is the master files that control that entire domain. This includes the passwd, shadow, and alias files that mimic the Unix passwd, shadow, and alias files. I've used a few examples of master white list and block lists but any number of files can be added for greater customization.
Each domain has a users folder which contains the user's accounts and personal settings. This allows the user to customize their own experience just the way they want. A few examples are given here but there's no limit to what you can add.
MySQL
Instead of the file structure it might be better to do it all with MySQL. I do however like the simplicity of these pure text files but I could be persuaded by a good programmer and really clean code that makes it easy for people to add new features. I'd like to start with the text file interface and make database backends optional.
Administration
There are several levels of privileges in this system. When the user is authenticated the system knows who they are and gives them the menus they should have access to. Three levels that need to be set up are Administrators, Domain Owners, and users.
Master Admins
Master admins control the system and can set anything else. They need to be able to create new domains, grant privileges to other users, and config the system.
Domain Owners
Domain owners need dominion over their domain(s). Once they log in they can create and delete users, create aliases, manage block lists and white lists and any other settings that affect their domain. They would also have full control of all the users setting under their domains.
Email Users
Email Users would have control of their account. They can change their personal settings, vacation messages, forwarding, password, etc.
User / Password Files
Currently the User Password and Alias files are stored in a directory named /etc/vmail and are just like the Unix passwd and shadow files.
- /etc/vmail/alias.domain
- /etc/vmail/passwd.domain
- /etc/vmail/shadow.domain
Feature Expansion
Once this structure is in place it should be easy to add new features. All you have to do to the front end is create a new text file to store the feature in and an Exim backend to run it. Both should be really easy. Menus can be created to allow users to block all 8 bit Asian email, Block entire continents. Block words in subject lines. Personal blackhole (rather than bounce), forward email from specific users to server side imap folders, the sky is the limit. All we have to do is do it right in the first place, keep it simple, and we all win.
Exim Backend
Exim is very powerful. It's trivial to write a backend that runs off this structure. Dovecot can be easily configured to access this structure as well. However I think if this were done right it should be generic enough to work with other MTAs and a variety of configurations. The backend assumes that if the files don't exist then nothing happens. If they do exist then they are read and processed.
Parts I have Written
I have several pieces of this written. I have the PHP code to authenticate users against the passwd/shadow files and to generate new passwords. I also have some PHP squirrelmail modules that edit these files. Mostly wat I need is someone to tie it all together into one interface and add some management to it so that people have access to the domains they control.
Here's the code to authenticate against the passwd/shadow files.
<?php if ($_POST["checkpass"]) { $login = $_POST["username"]; $passwd = $_POST["password"]; $newpass = $_POST["newpassword"]; $newpass2 = $_POST["newpassword2"]; list ($user, $domain) = explode('@', $login); $pass_file = "/etc/vmail/shadow.".$domain; // Sanity Checks if ($login == "") { $badInput = 1; } if (!$badInput and ($user == "" or $domain == "")) { echo "Error: Bad Email Address</b>
"; $badInput = 1; } if (!$badInput and ($passwd == "" or $newpass == "")) { echo "<b>Error: Password Missing</b>
"; $badInput = 1; } if (!$badInput and strlen($newpass) < 6) { echo "<b>Error: Password must be at least 6 characters</b>
"; $badInput = 1; } if ($newpass != $newpass2) { echo "<b>Error: New Passwords Don't Match</b>
"; $badInput = 1; } if (!$badInput) { $fp = fopen( $pass_file, "r" ); if ($fp == false) { echo "<b>Error: Domain ".$domain." Doesn't Exist</b>
"; } else { while ( !feof( $fp ) ) { $line = trim( fgets( $fp, 1000 ) ); list( $f_user, $f_password, $f_last_password_changed, $two, $three, $four, $five, $six ) = explode( ':', $line ); if ($f_user == $user) { $userFound = 1; if ( substr($f_password, 0, 1) == "$" ) { $seed = substr($f_password, 0, 12); $epassword = substr($f_password, 12, strlen($f_password)); $epassword = $seed.$epassword; $npassword = crypt($passwd, $seed); } else { $seed = substr($f_password, 0, 2); $epassword = substr($f_password, 2, strlen($f_password)); $epassword = $seed.$epassword; $npassword = crypt($passwd, $seed); } if ($npassword == $epassword) { $success = 1; for ($n = 0; $n < 9; $n++) { $s .= chr(rand(64,126)); } $seed = "$1$".$s."$"; $line = $f_user.":".crypt($_POST["newpassword"], $seed).":".floor(time()/86400).":".$two.":".$three.":".$four.":".$five.":".$six.":"; } else { echo "<b>Error: Wrong Password</b>
"; } } if ($line > "") { $write .= $line."\n"; } } } fclose($fp); if ($success) { $fp = fopen( $pass_file, "w" ); fwrite($fp, $write); fclose($fp); echo "<b>Password Change Succeeded
"; } if (!$userFound) { echo "Error: Invalid Email Address
"; } } } ?>
So - who wants to make it happen?
A good programmer should be able to whip this up in a few days. I'm not much of a programmer anymore so I need someone to get it started and I can finish it. So - who wants to help get this going. The results will be GPL'd and everyone gets to share in the finished product. Email me if you want to do it. marc@perkel.com