1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.apache.james.smtpserver.core.filter.fastfail;
24
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Iterator;
28 import java.util.StringTokenizer;
29
30 import org.apache.avalon.framework.configuration.Configurable;
31 import org.apache.avalon.framework.configuration.Configuration;
32 import org.apache.avalon.framework.configuration.ConfigurationException;
33 import org.apache.avalon.framework.logger.AbstractLogEnabled;
34 import org.apache.avalon.framework.service.ServiceException;
35 import org.apache.avalon.framework.service.ServiceManager;
36 import org.apache.avalon.framework.service.Serviceable;
37 import org.apache.james.api.vut.ErrorMappingException;
38 import org.apache.james.api.vut.VirtualUserTable;
39 import org.apache.james.api.vut.VirtualUserTableStore;
40 import org.apache.james.dsn.DSNStatus;
41 import org.apache.james.smtpserver.CommandHandler;
42 import org.apache.james.smtpserver.SMTPSession;
43 import org.apache.mailet.MailAddress;
44 import org.apache.oro.text.regex.MalformedPatternException;
45 import org.apache.oro.text.regex.Pattern;
46 import org.apache.oro.text.regex.Perl5Compiler;
47 import org.apache.oro.text.regex.Perl5Matcher;
48
49
50
51
52 public class ValidRcptHandler extends AbstractLogEnabled implements CommandHandler, Configurable, Serviceable {
53
54 private Collection recipients = new ArrayList();
55 private Collection domains = new ArrayList();
56 private Collection regex = new ArrayList();
57 private boolean vut = true;
58 private VirtualUserTable table;
59 private String tableName = null;
60
61
62
63
64 public void service(ServiceManager arg0) throws ServiceException {
65 if (tableName == null || tableName.equals("")) {
66 table = (VirtualUserTable) arg0.lookup(VirtualUserTable.ROLE);
67 } else {
68 table = ((VirtualUserTableStore) arg0.lookup(VirtualUserTableStore.ROLE)).getTable(tableName);
69 }
70 }
71
72
73
74
75 public void configure(Configuration arg0) throws ConfigurationException {
76 Configuration recipientsConfig = arg0.getChild("validRecipients");
77 if (recipientsConfig != null) {
78 setValidRecipients(recipientsConfig.getValue());
79 }
80
81 Configuration domainConfig = arg0.getChild("validDomains");
82 if (domainConfig != null) {
83 setValidDomains(domainConfig.getValue());
84 }
85
86 Configuration regexConfig = arg0.getChild("validRegexPattern");
87 if (regexConfig != null) {
88 try {
89 setValidRegex(regexConfig.getValue());
90 } catch(MalformedPatternException mpe) {
91 throw new ConfigurationException("Malformed pattern: ", mpe);
92 }
93 }
94 Configuration vutConfig = arg0.getChild("enableVirtualUserTable");
95
96 if (vutConfig != null) {
97 vut = vutConfig.getValueAsBoolean(true);
98 }
99 Configuration tableConfig = arg0.getChild("table");
100
101 if (tableConfig != null) {
102 tableName = tableConfig.getValue(null);
103 }
104 }
105
106
107
108
109
110
111 public void setValidRecipients(String recip) {
112 StringTokenizer st = new StringTokenizer(recip, ", ", false);
113
114 while (st.hasMoreTokens()) {
115 String recipient = st.nextToken().toLowerCase();
116
117 getLogger().debug("Add recipient to valid recipients: " + recipient);
118 recipients.add(recipient);
119 }
120 }
121
122
123
124
125
126
127 public void setValidDomains(String dom) {
128 StringTokenizer st = new StringTokenizer(dom, ", ", false);
129
130 while (st.hasMoreTokens()) {
131 String domain = st.nextToken().toLowerCase();
132 getLogger().debug("Add domain to valid domains: " + domain);
133 domains.add(domain);
134 }
135 }
136
137
138
139
140
141
142 public void setValidRegex(String reg) throws MalformedPatternException {
143 Perl5Compiler compiler = new Perl5Compiler();
144
145 StringTokenizer st = new StringTokenizer(reg, ", ", false);
146
147 while (st.hasMoreTokens()) {
148 String patternString = st.nextToken().trim();
149
150 getLogger().debug("Add regex to valid regex: " + patternString);
151
152 Pattern pattern = compiler.compile(patternString, Perl5Compiler.READ_ONLY_MASK);
153 regex.add(pattern);
154
155 }
156 }
157
158 public void setVirtualUserTableSupport(boolean vut) {
159 this.vut = vut;
160 }
161
162
163
164
165 public Collection getImplCommands() {
166 Collection c = new ArrayList();
167 c.add("RCPT");
168
169 return c;
170 }
171
172
173
174
175 public void onCommand(SMTPSession session) {
176 if (!session.isRelayingAllowed() && !(session.isAuthRequired() && session.getUser() != null)) {
177 checkValidRcpt(session);
178 } else {
179 getLogger().debug("Sender allowed");
180 }
181 }
182
183
184
185
186
187
188
189
190 private void checkValidRcpt(SMTPSession session) {
191 MailAddress rcpt = (MailAddress) session.getState().get(SMTPSession.CURRENT_RECIPIENT);
192 boolean invalidUser = true;
193
194 if (session.getConfigurationData().getUsersRepository().contains(rcpt.getUser()) == true || recipients.contains(rcpt.toString().toLowerCase()) || domains.contains(rcpt.getHost().toLowerCase())) {
195 invalidUser = false;
196 }
197
198
199 if (invalidUser == true && vut == true) {
200 try {
201 Collection targetString = table.getMappings(rcpt.getUser(), rcpt.getHost());
202
203 if (targetString != null && targetString.isEmpty() == false) {
204 invalidUser = false;
205 }
206 } catch (ErrorMappingException e) {
207
208 String responseString = e.getMessage();
209
210 getLogger().info("Rejected message. Reject Message: " + responseString);
211
212 session.writeResponse(responseString);
213 session.setStopHandlerProcessing(true);
214 }
215 }
216
217 if (invalidUser == true && !regex.isEmpty()) {
218 Iterator reg = regex.iterator();
219 Perl5Matcher matcher = new Perl5Matcher();
220
221 while (reg.hasNext()) {
222 if (matcher.matches(rcpt.toString(), (Pattern) reg.next())) {
223
224 invalidUser = false;
225 break;
226 }
227 }
228 }
229
230 if (invalidUser == true) {
231
232 String responseString = "554 " + DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_MAILBOX) + " Unknown user: " + rcpt.toString();
233
234 getLogger().info("Rejected message. Unknown user: " + rcpt.toString());
235
236 session.writeResponse(responseString);
237 session.setStopHandlerProcessing(true);
238 }
239 }
240 }