X-Git-Url: https://code.wpia.club/?p=gigi.git;a=blobdiff_plain;f=src%2Forg%2Fcacert%2Fgigi%2Femail%2FEmailProvider.java;h=49a27356061062cc06f2d58f7eaba0dabee0eb5c;hp=b5ac8d5ca88f1b58322e018dd1fb15ab54d0b718;hb=06860e55306d268f5db3c49ac9090c4455752cc0;hpb=634b7f75c8fc2ed8799bad74731278fb59198c48 diff --git a/src/org/cacert/gigi/email/EmailProvider.java b/src/org/cacert/gigi/email/EmailProvider.java index b5ac8d5c..49a27356 100644 --- a/src/org/cacert/gigi/email/EmailProvider.java +++ b/src/org/cacert/gigi/email/EmailProvider.java @@ -1,23 +1,180 @@ package org.cacert.gigi.email; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Comparator; import java.util.Properties; +import java.util.regex.Pattern; + +import javax.naming.NamingException; +import javax.net.ssl.SSLSocketFactory; + +import org.cacert.gigi.crypto.SMIME; +import org.cacert.gigi.database.DatabaseConnection; +import org.cacert.gigi.database.GigiPreparedStatement; +import org.cacert.gigi.util.DNSUtil; public abstract class EmailProvider { - public abstract void sendmail(String to, String subject, String message, - String from, String replyto, String toname, String fromname, - String errorsto, boolean extra) throws IOException; - private static EmailProvider instance; - public static EmailProvider getInstance() { - return instance; - } - public static void init(Properties conf) { - try { - Class c = Class.forName(conf.getProperty("emailProvider")); - instance = (EmailProvider) c.getDeclaredConstructor( - Properties.class).newInstance(conf); - } catch (ReflectiveOperationException e) { - e.printStackTrace(); - } - } + + public abstract void sendmail(String to, String subject, String message, String from, String replyto, String toname, String fromname, String errorsto, boolean extra) throws IOException; + + private static EmailProvider instance; + + private X509Certificate c; + + private PrivateKey k; + + protected final void init(Certificate c, Key k) { + this.c = (X509Certificate) c; + this.k = (PrivateKey) k; + } + + protected final void sendSigned(String contents, PrintWriter output) throws IOException, GeneralSecurityException { + SMIME.smime(contents, k, c, output); + } + + public static EmailProvider getInstance() { + return instance; + } + + protected static void setInstance(EmailProvider instance) { + EmailProvider.instance = instance; + } + + public static void initSystem(Properties conf, Certificate cert, Key pk) { + try { + Class c = Class.forName(conf.getProperty("emailProvider")); + EmailProvider ep = (EmailProvider) c.getDeclaredConstructor(Properties.class).newInstance(conf); + ep.init(cert, pk); + instance = ep; + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + } + } + + public static final String OK = "OK"; + + public static final String FAIL = "FAIL"; + + public static final Pattern MAIL = Pattern.compile("^([a-zA-Z0-9])+([a-zA-Z0-9\\+\\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\\._-]+)+$"); + + public String checkEmailServer(int forUid, String address) throws IOException { + if (MAIL.matcher(address).matches()) { + String[] parts = address.split("@", 2); + String domain = parts[1]; + + String[] mxhosts; + try { + mxhosts = DNSUtil.getMXEntries(domain); + } catch (NamingException e1) { + return "MX lookup for your hostname failed."; + } + sortMX(mxhosts); + + for (String host : mxhosts) { + host = host.split(" ", 2)[1]; + if (host.endsWith(".")) { + host = host.substring(0, host.length() - 1); + } else { + return "Strange MX records."; + } + try (Socket s = new Socket(host, 25); BufferedReader br0 = new BufferedReader(new InputStreamReader(s.getInputStream())); PrintWriter pw0 = new PrintWriter(s.getOutputStream())) { + BufferedReader br = br0; + PrintWriter pw = pw0; + String line; + if ( !Sendmail.readSMTPResponse(br, 220)) { + continue; + } + + pw.print("EHLO www.cacert.org\r\n"); + pw.flush(); + boolean starttls = false; + do { + line = br.readLine(); + if (line == null) + break; + starttls |= line.substring(4).equals("STARTTLS"); + } while (line.startsWith("250-")); + if (line == null || !line.startsWith("250 ")) { + continue; + } + + if (starttls) { + pw.print("STARTTLS\r\n"); + pw.flush(); + if ( !Sendmail.readSMTPResponse(br, 220)) { + continue; + } + Socket s1 = ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(s, host, 25, true); + br = new BufferedReader(new InputStreamReader(s1.getInputStream())); + pw = new PrintWriter(s1.getOutputStream()); + pw.print("EHLO www.cacert.org\r\n"); + pw.flush(); + if ( !Sendmail.readSMTPResponse(br, 250)) { + continue; + } + } + + pw.print("MAIL FROM: \r\n"); + pw.flush(); + + if ( !Sendmail.readSMTPResponse(br, 250)) { + continue; + } + pw.print("RCPT TO: <" + address + ">\r\n"); + pw.flush(); + + if ( !Sendmail.readSMTPResponse(br, 250)) { + continue; + } + pw.print("QUIT\r\n"); + pw.flush(); + if ( !Sendmail.readSMTPResponse(br, 221)) { + continue; + } + + GigiPreparedStatement statmt = DatabaseConnection.getInstance().prepare("insert into `emailPinglog` set `when`=NOW(), `email`=?, `result`=?, `uid`=?"); + statmt.setString(1, address); + statmt.setString(2, line); + statmt.setInt(3, forUid); + statmt.execute(); + + if (line == null || !line.startsWith("250")) { + return line; + } else { + return OK; + } + } + + } + } + GigiPreparedStatement statmt = DatabaseConnection.getInstance().prepare("insert into `emailPinglog` set `when`=NOW(), `email`=?, `result`=?, `uid`=?"); + statmt.setString(1, address); + statmt.setString(2, "Failed to make a connection to the mail server"); + statmt.setInt(3, forUid); + statmt.execute(); + return FAIL; + } + + private static void sortMX(String[] mxhosts) { + Arrays.sort(mxhosts, new Comparator() { + + @Override + public int compare(String o1, String o2) { + int i1 = Integer.parseInt(o1.split(" ")[0]); + int i2 = Integer.parseInt(o2.split(" ")[0]); + return Integer.compare(i1, i2); + } + }); + } + }