Initial revision
[exim-website.git] / config.samples / C034
1 From: Mark Morley <mark@islandnet.com>
2 Date: Sat, 11 Dec 1999 10:45:38 -0800 (PST)
3
4 This is a HOW-TO for setting up Exim to support SMTP authentication under
5 different environments, including regular password files, PAM and NIS.
6
7 The goal is to allow local users to relay without requiring authentication,
8 and disallow relaying by remote users UNLESS they authenticate.  If a user
9 authenticates then their username is included in the log file entries so
10 they can't abuse your server without incurring your wrath.
11
12 The first thing you need to do is make sure you enabled the right things in
13 the Local/Makefile before compiling.  You will need the following line:
14
15    AUTH_PLAINTEXT=yes
16
17 And possibly this line:
18
19    AUTH_CRAM_MD5=yes
20
21 If your server uses PAM then you will also need this line:
22
23    SUPPORT_PAM=yes
24
25 Next you need to edit your configure file.  To achieve our goals we need
26 to set three entries:
27
28    host_accept_relay should list those hosts that are allowed to relay
29    without needing to authenticate.  This is normally a list of your
30    local IP numbers.
31
32    host_auth_accept_relay should list those hosts that are allowed to
33    relay so long as they authenticate first.  We just set this to "*"
34    to allow authentication from anywhere.
35
36    If there are any hosts that you REQUIRE authentication from, even if
37    they are listed in host_accept_relay, then list them in the auth_hosts
38    setting.  In my case I only have one IP listed, and that's the one I'm
39    using to test authentication with (ie: my personal static IP number).
40
41 Next comes the potentially tricky part.  You need to edit the AUTH section
42 of the configure file (it's the section right after REWRITE).  You need to
43 create an entry for each authentication method you wish to support.
44
45 The first authentication method we'll create is called AUTH PLAIN.  It is
46 the method used by Netscape Messenger for example.  With the PLAIN method
47 the client sends a command like this:
48
49    AUTH PLAIN AHVzZXJuYW1lAHBhc3N3b3Jk
50
51 That third item there is actually three strings, separated by nul characters,
52 and then base64 encoded.  The first string is not used here.  The second
53 string will be the username, and the third string will be the password.
54
55 The entry for AUTH PLAIN will look something like this:
56
57 plain:
58   driver = plaintext
59   public_name = PLAIN
60   server_condition = ????
61   server_set_id = $2
62
63 The tricky bit is deciding what the server_condition should be, and that
64 depends on whether you are using PAM, NIS, plain password files, etc.  The
65 server_condition string will be expanded, and if the result is "1" then
66 authentication is successful - if it's "0" then authentication failed.
67
68 At the point where the string is expanded, the username is stored in $2
69 and the password in $3, so we just need to perform whatever lookups and
70 comparisons are necessary to validate the user.
71
72 For example, here's a server_condition that works for a specific user
73 named "bloggs" with the password "freddy":
74
75   server_condition = "${if and{ {eq{$2}{bloggs}} {eq{$3}{freddy}} } {1}{0}}"
76
77 But a single hardcoded example isn't all that useful (unless you only want
78 a specific user to be able to authenticate).  Here's one that works with a
79 non-shadowed NIS based password file:
80
81   server_condition = "${if and {{!eq{$2}{}}{!eq{$3}{}} \
82   {crypteq{$3}{${extract{2}{:} \
83   {${lookup{$2}nis{passwd.byname}{$value}{*:*}}}}}}}{1}{0}}"
84
85 That's a tad more complicated!  At the heart of it it performs an NIS lookup
86 on the "passwd.byname" map using $2 (the username) as the key.  If the
87 lookup is successful then we get a typical passwd file entry, otherwise
88 we get the bogus entry "*:*".  From the result it extracts the second field
89 using a colon as the delimiter.  This results in either the user's encrypted
90 password or "*".  It then encrypts $3 (the plaintext password) and compares
91 that against the extracted value.  It also checks both $2 and $3 to ensure
92 that neither is a null string.  If the whole condition is true then it
93 resolves to "1", otherwise it resolves to "0".
94
95 If your server uses a shadow passwd file with NIS, then you simply need to
96 change the map from "passwd.byname" to "passwd.adjunct.byname" or whatever
97 name your system uses.
98
99 If your mail server uses a traditional passwd file, you could probably do
100 something like this (untested):
101
102   server_condition = "${if and {{!eq{$2}{}}{!eq{$3}{}} \
103   {crypteq{$3}{${extract{2}{:} \
104   {${lookup{$2}lsearch{/etc/passwd}{$value}{*:*}}}}}}}{1}{0}}"
105
106 If you use shadow passwords you could change the "/etc/passwd" to
107 "/etc/shadow" or "/etc/security/passwd.adjunct", etc.
108
109 If your mail server uses PAM, then the condition is much simpler:
110
111   server_condition = "${if pam{$2:$3}{1}{0}}"
112
113 Since Exim has built-in PAM support you don't need such a complicated
114 string expansion.
115
116 So now we want to add a second authentication method.  This one is called
117 AUTH LOGIN and is used by Outlook Express, among others.  This is similar
118 to the PLAIN method, except that the client expects the server to prompt
119 it for the username and password one at a time.
120
121 Here's the basic entry:
122
123 login:
124   driver = plaintext
125   public_name = LOGIN
126   server_prompts = "Username:: : Password::"
127   server_condition = ????
128   server_set_id = $1
129
130 The primary difference from the PLAIN method is the server_prompts setting,
131 which is a colon-separated list of prompts to issue to the client.  According
132 to the AUTH LOGIN specification, there should be two prompts and they should
133 always be "User Name" and "Password".  But Microsoft is never content to
134 leave things be and this will only work with Outlook Express if you use
135 "Username:" and "Password:".  The double "::" is needed to escape the
136 trailing colons.
137
138 After the prompts are issued and the client has submitted it's responses,
139 the username will be stored in $1 and the password in $2.  You can use the
140 same server condition that you used for the PLAIN method, just change the
141 $2's to $1's, and the $3's to $2's.
142
143 Both the PLAIN and LOGIN methods transfer unencrypted copies of the username
144 and password over the 'net.  This is not the most secure way of doing things
145 (although the fact that it's base64 encoded makes it a bit more secure than
146 the way the same data is sent for a standard POP session).  So there is a
147 third method you may want to support called CRAM-MD5.  This is the method
148 used by Eudora for example.
149
150 CRAM-MD5 never sends the password at all.  The server issues a challenge,
151 which the client encrypts using the user's password, and returns to the
152 server.  The server performs the same encryption.  If the two strings
153 match then the client must have used the same password and therefore it's
154 safe to authenticate them.
155
156 The problem with CRAM-MD5 is that in order for it to work, the server must
157 have an UNENCRYPTED copy of the user's password.  With most typical servers
158 this isn't possible, since the passwords in a UNIX passwd file are normally
159 one-way encrypted.
160
161 So unless you are willing to maintain a separate database of plaintext
162 username/password pairs for those users who want to use CRAM-MD5, it's
163 of little value.
164
165 In our case we use Qualcomm's POP server software which allows Eudora
166 users to send email via the POP server itself (via the POP XMIT command),
167 so SMTP authentication isn't really needed for them anyway.
168
169 So that's that.  Whether it's via SMTP authentication or POP XMIT, the
170 majority of our users can now relay through our mail server regardless
171 of where they are connecting from.
172
173 Now there is one problem, in my opinion, with this whole setup.  Certain
174 email clients (eg: Netscape Messenger) will notice that your server now
175 accepts authentication, and will assume that it's required.  That means
176 that even users on your local network will suddenly have to enter their
177 password whenever they send a message.
178
179 While this works, it causes a lot of confusion for people who have never
180 had to do that before.  To my way of thinking it would be better to hide
181 the fact that authentication is supported when the client is connecting
182 from a local IP number.
183
184 To do this you must make a simple modification to the Exim source code.
185 On line 1943 of src/smtp_in.c (Exim 3.12) you will find the following
186 condition:
187
188    if (auths != NULL)
189
190 Change it to this:
191
192    if (auths != NULL && (host_must_authenticate ||
193                         !verify_check_host(&host_accept_relay, FALSE)))
194
195 And recompile.  Your server will now only advertise the AUTH capability
196 to clients that are required to authenticate (ie: they are listed in
197 the auth_hosts setting) or those that are NOT listed in host_accept_relay.
198
199 mark@islandnet.com