summaryrefslogtreecommitdiff
path: root/CommModule
diff options
context:
space:
mode:
authorMarkus Warg <mw@it-sls.de>2010-03-29 09:54:06 +0200
committerMarkus Warg <mw@it-sls.de>2010-03-29 09:54:06 +0200
commit9dceece06fbdc98add6f76f0b1aec05891a394c4 (patch)
treef7227c28ca5f79f30c2ec81ba1a09a4fe3972436 /CommModule
parent5b68967def224a00f54eb54946ff17301bbd3cdb (diff)
downloadcacert-devel-9dceece06fbdc98add6f76f0b1aec05891a394c4.tar.gz
cacert-devel-9dceece06fbdc98add6f76f0b1aec05891a394c4.tar.xz
cacert-devel-9dceece06fbdc98add6f76f0b1aec05891a394c4.zip
remove cacert/ prefix
Diffstat (limited to 'CommModule')
-rw-r--r--CommModule/CVS/Entries8
-rw-r--r--CommModule/CVS/Repository1
-rw-r--r--CommModule/CVS/Root1
-rwxr-xr-xCommModule/client.pl1150
-rwxr-xr-xCommModule/clientloop.sh12
-rwxr-xr-xCommModule/commdaemon45
-rwxr-xr-xCommModule/commmodule166
-rw-r--r--CommModule/error.txt1
-rwxr-xr-xCommModule/logclean.sh57
-rw-r--r--CommModule/readme.txt6
-rwxr-xr-xCommModule/serial.conf32
-rwxr-xr-xCommModule/usbclient.pl1019
12 files changed, 2498 insertions, 0 deletions
diff --git a/CommModule/CVS/Entries b/CommModule/CVS/Entries
new file mode 100644
index 0000000..b156d1e
--- /dev/null
+++ b/CommModule/CVS/Entries
@@ -0,0 +1,8 @@
+/clientloop.sh/1.1/Sun Jan 13 00:05:44 2008//
+/error.txt/1.1/Sun Jan 13 00:05:44 2008//
+/readme.txt/1.1/Sun Jan 13 00:05:44 2008//
+/usbclient.pl/1.3/Fri Jul 18 16:37:02 2008//
+/logclean.sh/1.2/Sun May 24 18:08:23 2009//
+/client.pl/1.12/Sat Sep 19 23:32:57 2009//
+/serial.conf/1.3/Sat Sep 19 23:32:57 2009//
+D
diff --git a/CommModule/CVS/Repository b/CommModule/CVS/Repository
new file mode 100644
index 0000000..4e4c1e9
--- /dev/null
+++ b/CommModule/CVS/Repository
@@ -0,0 +1 @@
+cacert/CommModule
diff --git a/CommModule/CVS/Root b/CommModule/CVS/Root
new file mode 100644
index 0000000..a363882
--- /dev/null
+++ b/CommModule/CVS/Root
@@ -0,0 +1 @@
+/var/lib/cvs
diff --git a/CommModule/client.pl b/CommModule/client.pl
new file mode 100755
index 0000000..7b417d1
--- /dev/null
+++ b/CommModule/client.pl
@@ -0,0 +1,1150 @@
+#!/usr/bin/perl -w
+
+# CommModule - CAcert Communication Module
+# Copyright (C) 2006-2009 CAcert Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+# Production Client / CommModule
+
+use strict;
+use Device::SerialPort qw( :PARAM :STAT 0.07 );
+use POSIX;
+use IO::Select;
+use Time::HiRes q(usleep);
+use File::CounterFile;
+use IPC::Open3;
+use File::Copy;
+use DBI;
+use Locale::gettext;
+use IO::Socket;
+use MIME::Base64;
+use Digest::SHA1 qw(sha1_hex);
+
+#Protocol version:
+my $ver=1;
+
+my $paranoid=1;
+
+my $debug=0;
+
+#my $serialport="/dev/ttyS0";
+my $serialport="/dev/ttyUSB0";
+
+my $gpgbin="/usr/bin/gpg";
+
+my $opensslbin="/usr/bin/openssl";
+
+
+my $mysqlphp="/home/cacert/www/includes/mysql.php";
+
+my %revokefile=(2=>"../www/class3-revoke.crl",1=>"../www/revoke.crl");
+
+my $newlayout=1;
+
+#End of configurations
+
+########################################################
+
+
+my %monarr = ("Jan" => 1, "Feb" => 2, "Mar" => 3, "Apr" => 4, "May" => 5, "Jun" => 6, "Jul" => 7, "Aug" => 8, "Sep" => 9, "Oct" => 10, "Nov" => 11, "Dec" => 12);
+
+
+my $password="";
+if(open IN,"<$mysqlphp")
+{
+ my $content="";
+undef $/;
+$content=<IN>;
+$password=$1 if($content=~m/mysql_connect\s*\("[^"]+",\s*"\w+",\s*"(\w+)"/);
+close IN;
+$/="\n";
+
+}
+else
+{
+ die "Could not read file: $!\n";
+}
+
+
+my $dbh = DBI->connect("DBI:mysql:cacert:localhost","cacert",$password, { RaiseError => 1, AutoCommit => 1 }) || die ("Error with the database connection.\n");
+
+sub readfile($)
+{
+ my $save=$/;
+ undef $/;
+ open READIN,"<$_[0]";
+ my $content=<READIN>;
+ close READIN;
+ $/=$save;
+ return $content;
+}
+
+
+
+#Logging functions:
+my $lastdate = "";
+
+sub SysLog($)
+{
+ return if(not defined($_[0]));
+ my $timestamp = strftime("%Y-%m-%d %H:%M:%S", localtime);
+ my $currdate = substr($timestamp, 0, 10);
+ if ($lastdate ne $currdate) {
+ close LOG if ($lastdate ne "");
+ $lastdate = $currdate;
+ open LOG,">>logfile$lastdate.txt";
+ }
+ print LOG "$timestamp $_[0]";
+ flush LOG;
+}
+
+sub Error($)
+{
+SysLog($_[0]);
+if($paranoid)
+{
+die $_[0];
+}
+}
+
+
+my $timestamp=strftime("%Y-%m-%d %H:%M:%S",localtime);
+
+#mkdir "revokehashes";
+foreach (keys %revokefile)
+{
+ next unless (-f $revokefile{$_});
+ my $revokehash=sha1_hex(readfile($revokefile{$_}));
+ SysLog "Root $_: Hash $revokefile{$_} = $revokehash\n";
+}
+
+
+
+sub mysql_query($)
+{
+$dbh->do($_[0]);
+}
+
+sub trim($)
+{
+my $new=$_[0];
+$new=~s/^\s*//;
+$new=~s/\s*$//;
+return($new);
+}
+sub addslashes($)
+{
+my $new=$_[0];
+$new=~s/['"\\]/\\$1/g;
+return($new);
+}
+
+sub recode
+{
+return $_[1];
+}
+
+
+
+SysLog("Opening Serial interface:\n");
+sub SerialSettings($)
+{
+my $PortObj=$_[0];
+if(!defined($PortObj))
+{
+Error "Could not open Serial Port!\n" ;
+}
+else
+{
+$PortObj->baudrate(115200);
+$PortObj->parity("none");
+$PortObj->databits(8);
+$PortObj->stopbits(1);
+}
+}
+
+#We have to open the SerialPort and close it again, so that we can bind it to a Handle
+if(! -f "serial.conf")
+{
+my $PortObj = new Device::SerialPort($serialport);
+SerialSettings($PortObj);
+$PortObj->save("serial.conf");
+undef $PortObj;
+}
+
+my $PortObj = tie (*SER, 'Device::SerialPort', "serial.conf") || Error "Can't tie using Configuration_File_Name: $!\n";
+
+Error "Could not open Serial Interface!\n" if(not defined($PortObj));
+SerialSettings($PortObj);
+#open SER,">$serialport";
+
+SysLog("Serial interface opened: $PortObj\n");
+
+my $sel = new IO::Select( \*SER );
+
+
+
+#Hexdump function: Returns the hexdump representation of a string
+sub hexdump($)
+{
+return "" if(not defined($_[0]));
+my $content="";
+$content.=sprintf("%02X ",unpack("C",substr($_[0],$_,1))) foreach (0 .. length($_[0])-1);
+return $content;
+}
+
+#pack3 packs together the length of the data in 3 bytes and the data itself, size limited to 16MB. In case the data is more than 16 MB, it is ignored, and a 0 Byte block is transferred
+sub pack3
+{
+ return "\x00\x00\x00" if(!defined($_[0]));
+ my $data=(length($_[0]) >= 2**24)? "":$_[0];
+ my $len=pack("N",length($data));
+ SysLog "len: ".length($data)."\n" if($debug);
+ return substr($len,1,3).$data;
+}
+
+
+#unpack3 unpacks packed data.
+sub unpack3($)
+{
+return undef if((not defined($_[0])) or length($_[0])<3);
+#SysLog "hexdump: ".hexdump("\x00".substr($_[0],0,3))."\n";
+my $len=unpack("N","\x00".substr($_[0],0,3));
+#SysLog "len3: $len length(): ".length($_[0])." length()-3: ".(length($_[0])-3)."\n";
+return undef if(length($_[0])-3 != $len);
+return substr($_[0],3);
+}
+
+
+#unpack3array extracts a whole array of concatented pack3ed data.
+sub unpack3array($)
+{
+my @retarr=();
+if((not defined($_[0])) or length($_[0])<3)
+{
+SysLog "Begin of structure corrupt\n";
+return ();
+}
+my $dataleft=$_[0];
+while(length($dataleft)>=3)
+{
+#SysLog "hexdump: ".hexdump("\x00".substr($dataleft,0,3))."\n";
+my $len=unpack("N","\x00".substr($dataleft,0,3));
+#SysLog "len3: $len length(): ".length($dataleft)." length()-3: ".(length($dataleft)-3)."\n";
+if(length($dataleft)-3 < $len)
+{
+SysLog "Structure cut off\n";
+return ();
+}
+push @retarr, substr($dataleft,3,$len);
+$dataleft=substr($dataleft,3+$len);
+}
+if(length($dataleft)!=0)
+{
+SysLog "End of structure cut off\n";
+return ();
+}
+return @retarr;
+}
+
+
+#Raw send function over the Serial Interface (+debugging)
+sub SendIt($)
+{
+ return unless defined($_[0]);
+ SysLog "Sending ".length($_[0])."\n"; #hexdump($_[0])."\n" if($debug);
+ my $data=$_[0];
+ my $runcount=0;
+ my $total=0;
+ my $mtu=30;
+ while(length($data))
+ {
+ my $iwrote=scalar($PortObj->write(substr($data,0,$mtu)))||0;
+ #usleep(270*$iwrote+9000); # On Linux, we have to wait to make sure it is being sent, and we dont loose any data.
+ $total+=$iwrote;
+ $data=substr($data,$iwrote);
+ if ($debug) {
+ print "i wrote: $iwrote total: $total left: ".length($data)."\n" if(!($runcount++ %10));
+ }
+ }
+ SysLog "Sent message.\n" if($debug);
+ # print "Sending ".length($_[0])."\n"; #hexdump($_[0])."\n";
+ # foreach(0 .. length($_[0]))
+ # {
+ # $PortObj->write(substr($_[0],$_,1));
+ # }
+
+}
+
+
+my $modus=0;
+my $cnt=0;
+
+
+#Send data over the Serial Interface with handshaking:
+sub SendHandshaked($)
+{
+ SysLog "Shaking hands ...\n" if($debug);
+ SendIt("\x02");
+
+ Error "Handshake uncompleted. Connection lost2! $!\n" if(!scalar($sel->can_read(20)));
+ my $data="";
+ my $length=read SER,$data,1;
+ if($length && $data eq "\x10")
+ {
+ #print "OK ...\n";
+ my $xor=0;
+ foreach(0 .. length($_[0])-1)
+ {
+ #print "xor mit ".unpack("C",substr($_[0],$_,1))."\n";
+ $xor ^= unpack("C",substr($_[0],$_,1));
+ }
+ #print "XOR: $xor\n";
+
+ my $tryagain=1;
+ while($tryagain)
+ {
+ SendIt($_[0].pack("C",$xor)."rie4Ech7");
+
+ Error "Packet receipt was not confirmed in 5 seconds. Connection lost!\n" if(!scalar($sel->can_read(5)));
+
+ $data="";
+ $length=read SER,$data,1;
+
+ if($length && $data eq "\x10")
+ {
+ SysLog "Sent successfully!...\n";
+ $tryagain=0;
+ }
+ elsif($length && $data eq "\x11")
+ {
+ $tryagain=1;
+ }
+ else
+ {
+ Error "I cannot send! $length ".unpack("C",$data)."\n";
+ }
+ }
+
+ }
+ else
+ {
+ print "!Cannot send! $length \n";
+ Error "!Stopped sending.\n";
+ }
+}
+
+
+
+sub Receive
+{
+my $data="";
+my @ready = $sel->can_read(120);
+
+my $length=read SER,$data,1,0;
+
+#SysLog "Data: ".hexdump($data)."\n";
+
+if($data eq "\x02")
+{
+$modus=1;
+SysLog "Start received, sending OK\n" if($debug);
+SendIt("\x10");
+
+my $block="";
+my $blockfinished=0;
+my $tries=100000;
+
+while(!$blockfinished)
+{
+Error("Tried reading too often\n") if(($tries--)<=0);
+# SysLog ("tries: $tries") if(!($tries%10));
+
+$data="";
+if(!scalar($sel->can_read(5)))
+{
+Error "Handshake uncompleted. Connection lost variant3! $!\n" ;
+return;
+}
+$length=read SER,$data,100,0;
+if($length)
+{
+$block.=$data;
+}
+#SysLog("Received: $length ".length($block)."\n");
+$blockfinished=defined(unpack3(substr($block,0,-9)))?1:0;
+
+if(!$blockfinished and substr($block,-8,8) eq "rie4Ech7")
+{
+SysLog "BROKEN Block detected!\n";
+SendIt("\x11");
+$block="";
+$blockfinished=0;
+$tries=100000;
+}
+
+}
+SysLog "Block done: ".hexdump($block)."\n" if($debug);
+SendIt("\x10");
+return($block);
+}
+else
+{
+Error("Error: No Answer received, Timeout.\n") if(length($data)==0);
+Error("Error: Wrong Startbyte: ".hexdump($data)." !\n");
+}
+
+SysLog "Waiting on next request ...\n";
+
+}
+
+
+
+# @result(Version,Action,Errorcode,Response)=Request(Version=1,Action=1,System=1,Root=1,Configuration="...",Parameter="...",Request="...");
+sub Request($$$$$$$$$$$)
+{
+ SysLog "Version: $_[0] Action: $_[1] System: $_[2] Root: $_[3] Config: $_[4]\n";
+ $_[3]=0 if($_[3]<0);
+ SendHandshaked(pack3(pack3(pack("C*",$_[0],$_[1],$_[2],$_[3],$_[4],$_[5],$_[6]>>8,$_[6]&255,$_[7])).pack3($_[8]).pack3($_[9]).pack3($_[10])));
+ my $data=Receive();
+ my @fields=unpack3array(substr($data,3,-9));
+
+ SysLog "Answer from Server: ".hexdump($data)."\n" if($debug);
+
+ #if(open OUT,">result.dat")
+ #{
+ # print OUT $data;
+ # close OUT;
+ #}
+ #else
+ #{
+ # SysLog "Could not write result: $!\n";
+ #}
+ return $fields[1];
+}
+
+
+sub calculateDays($)
+{
+ if($_[0])
+ {
+ my @sum = $dbh->selectrow_array("select sum(`points`) as `total` from `notary` where `to`='".$_[0]."' group by `to`");
+ SysLog("Summe: $sum[0]\n") if($debug);
+
+ return ($sum[0]>=50)?730:180;
+ }
+ return 180;
+}
+
+sub X509extractSAN($)
+{
+ my @bits = split("/", $_[0]);
+ my $SAN="";
+ my $newsubject="";
+ foreach my $val(@bits)
+ {
+ my @bit=split("=",$val);
+ if($bit[0] eq "subjectAltName")
+ {
+ $SAN.="," if($SAN ne "");
+ $SAN.= trim($bit[1]);
+ }
+ else
+ {
+ $newsubject .= "/".$val;
+ }
+ }
+ $newsubject=~s{^//}{/};
+ $newsubject=~s/[\n\r\t\x00"\\']//g;
+ $SAN=~s/[ \n\r\t\x00"\\']//g;
+ return($SAN,$newsubject);
+}
+
+sub X509extractExpiryDate($)
+{
+ # TIMEZONE ?!?
+ my $data=`$opensslbin x509 -in "$_[0]" -noout -enddate`;
+
+ #notAfter=Aug 8 10:26:34 2007 GMT
+ if($data=~m/notAfter=(\w{2,4}) *(\d{1,2}) *(\d{1,2}:\d{1,2}:\d{1,2}) (\d{4}) GMT/)
+ {
+ my $date="$4-".$monarr{$1}."-$2 $3";
+ SysLog "Expiry Date found: $date\n" if($debug);
+ return $date;
+ }
+ else
+ {
+ SysLog "Expiry Date not found: $data\n";
+ }
+ return "";
+}
+
+sub CRLuptodate($)
+{
+ return 0 unless(-f $_[0]);
+ my $data=`$opensslbin crl -in "$_[0]" -noout -lastupdate -inform der`;
+ SysLog "CRL: $data\n";
+ #lastUpdate=Aug 8 10:26:34 2007 GMT
+ # Is the timezone handled properly?
+ if($data=~m/lastUpdate=(\w{2,4}) *(\d{1,2}) *(\d{1,2}:\d{1,2}:\d{1,2}) (\d{4}) GMT/)
+ {
+ my $date=sprintf("%04d-%02d-%02d",$4,$monarr{$1},$2);
+ SysLog "CRL Issueing Date found: $date\n" if($debug);
+ my $compare = strftime("%Y-%m-%d", localtime);
+ SysLog "Comparing $date with $compare\n" if($debug);
+ return $date eq $compare;
+ }
+ else
+ {
+ SysLog "Expiry Date not found. Perhaps DER format is necessary? Hint: $data\n";
+ }
+ return 0;
+}
+
+
+sub X509extractSerialNumber($)
+{
+ # TIMEZONE ?!?
+ my $data=`$opensslbin x509 -in "$_[0]" -noout -serial`;
+ if($data=~m/serial=([0-9A-F]+)/)
+ {
+ return $1;
+ }
+ return "";
+}
+
+sub OpenPGPextractExpiryDate ($)
+{
+ my $r="";
+ my $cts;
+ my @date;
+
+ open(RGPG, $gpgbin.' -vv '.$_[0].' 2>&1 |') or Error('Can\'t start GnuPG($gpgbin): '.$!."\n");
+ open(OUT, '> infogpg.txt' ) or Error('Can\'t open output file: infogpg.txt: '.$!);
+ $/="\n";
+ while (<RGPG>)
+ {
+ print OUT $_;
+ unless ($r)
+ {
+ if ( /^\s*version \d+, created (\d+), md5len 0, sigclass \d+\s*$/ )
+ {
+ SysLog "Detected CTS: $1\n";
+ $cts = int($1);
+ } elsif ( /^\s*critical hashed subpkt \d+ len \d+ \(sig expires after ((\d+)y)?((\d+)d)?((\d+)h)?(\d+)m\)\s*$/ )
+ {
+ SysLog "Detected FRAME $2 $4 $6 $8\n";
+ $cts += $2 * 31536000; # secs per year (60 * 60 * 24 * 365)
+ $cts += $4 * 86400; # secs per day (60 * 60 * 24)
+ $cts += $6 * 3600; # secs per hour (60 * 60)
+ $cts += $8 * 60; # secs per min (60)
+ $r = $cts;
+ }
+ elsif(/version/)
+ {
+ SysLog "Detected VERSION\n";
+ }
+ }
+ }
+
+ close(OUT );
+ close(RGPG);
+
+ SysLog "CTS: $cts R: $r\n";
+
+ if ( $r )
+ {
+ @date = gmtime($r);
+ $r = sprintf('%.4i-%.2i-%.2i %.2i:%.2i:%.2i', # date format
+ $date[5] + 1900, $date[4] + 1, $date[3], # day
+ $date[2], $date[1], $date[0], # time
+ );
+
+ }
+ SysLog "$r\n";
+ return $r;
+}
+
+#sub OpenPGPextractExpiryDate($)
+#{
+# my $data=`$gpgbin -v $_[0]`;
+# open OUT,">infogpg.txt";
+# print OUT $data;
+# close OUT;
+# if($data=~m/^sig\s+[0-9A-F]{8} (\d{4}-\d\d-\d\d) [^\[]/)
+# {
+# return "$1 00:00:00";
+# }
+# return "";
+#}
+
+
+# Sets the locale according to the users preferred language
+sub setUsersLanguage($)
+{
+ my $lang="de_DE";
+ print "Searching for the language of the user $_[0]\n";
+ my @a=$dbh->selectrow_array("select language from users where id='".int($_[0])."'");
+ $lang = $1 if($a[0]=~m/(\w+_[\w.@]+)/);
+
+ SysLog "The users preferred language: $lang\n";
+
+ if($lang ne "")
+ {
+ $ENV{"LANG"}=$lang;
+ setlocale(LC_ALL, $lang);
+ } else {
+ $ENV{"LANG"}="en_AU";
+ setlocale(LC_ALL, "en_AU");
+ }
+}
+
+
+sub getUserData($)
+{
+ return() unless($_[0]=~m/^\d+$/);
+ my $sth = $dbh->prepare("select * from users where id='$_[0]'");
+ $sth->execute();
+ #SysLog "USER DUMP:\n";
+ while ( my $rowdata = $sth->fetchrow_hashref() )
+ {
+ my %tmp=%{$rowdata};
+ #foreach (sort keys %tmp)
+ #{
+ #SysLog " $_ -> $tmp{$_}\n";
+ #}
+ return %tmp;
+ }
+ return ();
+}
+
+
+sub _($)
+{
+ return gettext($_[0]);
+}
+
+sub sendmail($$$$$$$)
+{
+ my ($to, $subject, $message, $from, $replyto, $toname, $fromname)=@_;
+ my $errorsto="returns\@cacert.org";
+ my $extra="";
+
+
+ # sendmail($user{email}, "[CAcert.org] Your GPG/PGP Key", $body, "support\@cacert.org", "", "", "CAcert Support");
+ my @lines=split("\n",$message);
+ $message = "";
+ foreach my $line (@lines)
+ {
+ $line = trim($line);
+ if($line eq ".")
+ {
+ $message .= " .\n";
+ } else
+ {
+ $message .= $line."\n";
+ }
+ }
+
+ $fromname = $from if($fromname eq "");
+
+ my @bits = split(",", $from);
+ $from = addslashes($bits['0']);
+ $fromname = addslashes($fromname);
+
+ my $smtp = IO::Socket::INET->new(PeerAddr => 'localhost:25');
+ $/="\n";
+ SysLog "SMTP: ".<$smtp>;
+ print $smtp "HELO hlin.cacert.org\r\n";
+ SysLog "SMTP: ".<$smtp>;
+ print $smtp "MAIL FROM: <returns\@cacert.org>\r\n";
+ SysLog "MAIL FROM: ".<$smtp>;
+
+ @bits = split(",", $to);
+ foreach my $user (@bits)
+ {
+ print $smtp "RCPT TO: <".trim($user).">\r\n";
+ SysLog "RCPT TO: ".<$smtp>;
+ }
+ print $smtp "DATA\r\n";
+ SysLog "DATA: ".<$smtp>;
+
+ print $smtp "X-Mailer: CAcert.org Website\r\n";
+ print $smtp "X-OriginatingIP: ".$ENV{"REMOTE_ADDR"}."\r\n";
+ print $smtp "Sender: $errorsto\r\n";
+ print $smtp "Errors-To: $errorsto\r\n";
+ if($replyto ne "")
+ {
+ print $smtp "Reply-To: $replyto\r\n";
+ }
+ else
+ {
+ print $smtp "Reply-To: $from\r\n";
+ }
+ print $smtp "From: $from ($fromname)\r\n";
+ print $smtp "To: $to\r\n";
+ my $newsubj=encode_base64(recode("html..utf-8", trim($subject)));
+ #SysLog("NewSubj: --".$newsubj."--\n") if($debug);
+ $newsubj=~s/\n*$//;
+ #SysLog("NewSubj: --".$newsubj."--\n") if($debug);
+ print $smtp trim($subject)=~m/[^a-zA-Z0-9 ,.\[\]\/-]/?"Subject: =?utf-8?B?$newsubj?=\r\n":"Subject: $subject\r\n";
+ print $smtp "Mime-Version: 1.0\r\n";
+ if($extra eq "")
+ {
+ print $smtp "Content-Type: text/plain; charset=\"utf-8\"\r\n";
+ print $smtp "Content-Transfer-Encoding: 8bit\r\n";
+ }
+ else
+ {
+ print $smtp "Content-Type: text/plain; charset=\"iso-8859-1\"\r\n";
+ print $smtp "Content-Transfer-Encoding: quoted-printable\r\n";
+ print $smtp "Content-Disposition: inline\r\n";
+ };
+# print $smtp "Content-Transfer-Encoding: BASE64\r\n";
+ print $smtp "\r\n";
+# print $smtp chunk_split(encode_base64(recode("html..utf-8", $message)))."\r\n.\r\n";
+ print $smtp recode("html..utf-8", $message)."\r\n.\r\n";
+ SysLog "ENDOFTEXT: ".<$smtp>;
+ print $smtp "QUIT\n";
+ SysLog "QUIT: ".<$smtp>;
+ close($smtp);
+}
+
+
+sub HandleCerts($$)
+{
+ my $org=$_[0]?"org":"";
+ my $server=$_[1];
+
+
+ my $table=$org.($server?"domaincerts":"emailcerts");
+
+ SysLog "HandleCerts $table\n";
+
+ my $sth = $dbh->prepare("select * from $table where crt_name='' and csr_name!='' and warning<3");
+ $sth->execute();
+ #$rowdata;
+ while ( my $rowdata = $sth->fetchrow_hashref() )
+ {
+ my %row=%{$rowdata};
+ my $prefix=$org.($server?"server":"client");
+ my $short=int($row{'id'}/1000);
+ my $csrname = "../csr/$prefix-".$row{'id'}.".csr";
+ $csrname = "../csr/$prefix/$short/$prefix-".$row{'id'}.".csr" if($newlayout);
+ SysLog("New Layout: "."../csr/$prefix/$short/$prefix-".$row{'id'}.".csr\n");
+
+ #my $crtname = "../crt/$prefix-".$row{'id'}.".crt";
+ my $crtname=$csrname; $crtname=~s/^\.\.\/csr/..\/crt/; $crtname=~s/\.csr$/.crt/;
+ my $dirname=$crtname; $dirname=~s/\/[^\/]*\.crt//;
+ mkdir $dirname,0777;
+ SysLog("New Layout: $crtname\n");
+
+ if($server)
+ {
+ #Weird SQL structure ...
+ my @sqlres=$dbh->selectrow_array("select memid from domains where id='".int($row{'domid'})."'");
+ $row{'memid'}=$sqlres[0];
+ SysLog("Fetched memid: $row{'memid'}\n") if($debug);
+ }
+
+ SysLog "Opening $csrname\n";
+
+ my $crt="";
+
+ my $profile=0;
+
+ # "0"=>"client.cnf",
+ # "1"=>"client-org.cnf",
+ # "2"=>"client-codesign.cnf",
+ # "3"=>"client-machine.cnf",
+ # "4"=>"client-ads.cnf",
+ # "5"=>"server.cnf",
+ # "6"=>"server-org.cnf",
+ # "7"=>"server-jabber.cnf",
+ # "8"=>"server-ocsp.cnf",
+ # "9"=>"server-timestamp.cnf",
+ # "10"=>"proxy.cnf",
+ # "11"=>"subca.cnf"
+
+
+ if($row{"type"} =~ m/^(8|9)$/)
+ {
+ $profile=$row{"type"};
+ }
+ elsif($org)
+ {
+ if($row{'codesign'})
+ {
+ $profile=2; ## TODO!
+ }
+ elsif($server)
+ {
+ $profile=6;
+ }
+ else
+ {
+ $profile=1;
+ }
+ }
+ else
+ {
+ if($row{'codesign'})
+ {
+ $profile=2;
+ }
+ elsif($server)
+ {
+ $profile=5;
+ }
+ else
+ {
+ $profile=0;
+ }
+
+
+ }
+
+
+
+ if(open(IN,"<$csrname"))
+ {
+ undef $/;
+ my $content=<IN>;
+ close IN;
+ SysLog "Read $csrname.\n" if($debug);
+ SysLog "Subject: --$row{'subject'}--\n" if($debug);
+
+ my ($SAN,$subject)=X509extractSAN($row{'subject'});
+ SysLog "Subject: --$subject--\n" if($debug);
+ SysLog "SAN: --$SAN--\n" if($debug);
+ SysLog "memid: $row{'memid'}\n" if($debug);
+
+ my $days=$org?($server?(365*2):365):calculateDays($row{"memid"});
+
+
+ $crt=Request($ver,1,1,$row{'rootcert'}-1,$profile,$row{'md'}eq"sha1"?2:0,$days,$row{'keytype'}eq"NS"?1:0,$content,$SAN,$subject);
+ if(length($crt))
+ {
+ if($crt=~m/^-----BEGIN CERTIFICATE-----/)
+ {
+ open OUT,">$crtname";
+ print OUT $crt;
+ close OUT;
+ }
+ else
+ {
+ open OUT,">$crtname.der";
+ print OUT $crt;
+ close OUT;
+ system "$opensslbin x509 -in $crtname.der -inform der -out $crtname";
+ }
+ }
+ else
+ {
+ SysLog "ZERO Length certificate received.\n";
+ }
+ }
+ else
+ {
+ print "Error: $! Konnte $csrname nicht laden\n";
+ }
+
+
+
+ if(-s $crtname)
+ {
+ SysLog "Opening $crtname\n";
+
+ my $date=X509extractExpiryDate($crtname);
+ my $serial=X509extractSerialNumber($crtname);
+
+ setUsersLanguage($row{memid});
+
+ my %user=getUserData($row{memid});
+
+ foreach (sort keys %user)
+ {
+ SysLog " $_ -> $user{$_}\n" if($debug);
+ }
+
+ SysLog("update `$table` set `crt_name`='$crtname', modified=now(), serial='$serial', `expire`='$date' where `id`='".$row{'id'}."'\n");
+
+ $dbh->do("update `$table` set `crt_name`='$crtname', modified=now(), serial='$serial', `expire`='$date' where `id`='".$row{'id'}."'");
+
+ my $body = _("Hi")." $user{fname},\n\n";
+ $body .= sprintf(_("You can collect your certificate for %s by going to the following location:")."\n\n", $row{'email'}.$row{'CN'});
+ $body .= "https://www.cacert.org/account.php?id=".($server?"15":"6")."&cert=$row{id}\n\n";
+ $body .= _("If you have not imported CAcert´s root certificate, please go to:")."\n";
+ $body .= "https://www.cacert.org/index.php?id=3\n";
+ $body .= "Root cert fingerprint = A6:1B:37:5E:39:0D:9C:36:54:EE:BD:20:31:46:1F:6B\n";
+ $body .= "Root cert fingerprint = 135C EC36 F49C B8E9 3B1A B270 CD80 8846 76CE 8F33\n\n";
+ $body .= _("Best regards")."\n"._("CAcert.org Support!")."\n\n";
+ sendmail($user{email}, "[CAcert.org] "._("Your certificate"), $body, "support\@cacert.org", "", "", "CAcert Support");
+ }
+ else
+ {
+ SysLog("Could not find the issued certificate. $crtname ".$row{"id"}."\n");
+ $dbh->do("update `$table` set warning=warning+1 where `id`='".$row{'id'}."'");
+ }
+ }
+}
+
+
+sub DoCRL($$)
+{
+ my $crl=$_[0];
+ my $crlname=$_[1];
+
+ if(length($crl))
+ {
+ if($crl=~m/^-----BEGIN X509 CRL-----/)
+ {
+ open OUT,">$crlname.pem";
+ print OUT $crl;
+ close OUT;
+ system "$opensslbin crl -in $crlname.pem -outform der -out $crlname.tmp";
+ }
+ else
+ {
+ open OUT,">$crlname.patch";
+ print OUT $crl;
+ close OUT;
+ my $res=system "xdelta patch $crlname.patch $crlname $crlname.tmp";
+ #print "xdelta res: $res\n";
+ if($res==512)
+ {
+ open OUT,">$crlname.tmp";
+ print OUT $crl;
+ close OUT;
+ }
+ }
+
+ my $res=`openssl crl -verify -in $crlname.tmp -inform der -noout 2>&1`;
+ SysLog "verify: $res\n";
+ if($res=~m/verify OK/)
+ {
+ rename "$crlname.tmp","$crlname";
+ }
+ else
+ {
+ SysLog "VERIFICATION OF NEW CRL DID NOT SUCCEED! PLEASE REPAIR!\n";
+ SysLog "Broken CRL is available as $crlname.tmp\n";
+ #Override for testing:
+ rename "$crlname.tmp","$crlname";
+ }
+ return 1;
+ }
+ else
+ {
+ SysLog("RECEIVED AN EMPTY CRL!\n");
+ }
+ return 0;
+}
+
+
+sub RefreshCRLs()
+{
+ foreach my $rootcert (keys %revokefile)
+ {
+ if(!CRLuptodate($revokefile{$rootcert}))
+ {
+ SysLog "Update of the CRL $rootcert is necessary!\n";
+ my $crlname = $revokefile{$rootcert};
+ my $revokehash=sha1_hex(readfile($crlname));
+ my $crl=Request($ver,2,1,$rootcert-1,0,0,365,0,"","",$revokehash);
+ #print "Received ".length($crl)." ".hexdump($crl)."\n";
+ DoCRL($crl,$crlname);
+ }
+ }
+}
+
+
+sub RevokeCerts($$)
+{
+ my $org=$_[0]?"org":"";
+ my $server=$_[1];
+
+ my $table=$org.($server?"domaincerts":"emailcerts");
+
+ my $sth = $dbh->prepare("select * from $table where revoked='1970-01-01 10:00:01'"); # WHICH TIMEZONE?
+ $sth->execute();
+ #$rowdata;
+ while ( my $rowdata = $sth->fetchrow_hashref() )
+ {
+ my %row=%{$rowdata};
+
+ my $prefix=$org.($server?"server":"client");
+ my $short=int($row{'id'}/1000);
+
+ my $csrname = "../csr/$prefix-".$row{'id'}.".csr";
+ $csrname = "../csr/$prefix/$short/$prefix-".$row{'id'}.".csr" if($newlayout);
+ SysLog("New Layout: "."../csr/$prefix/$short/$prefix-".$row{'id'}.".csr\n");
+
+ #my $crtname = "../crt/$prefix-".$row{'id'}.".crt";
+ my $crtname=$csrname; $crtname=~s/^\.\.\/csr/..\/crt/; $crtname=~s/\.csr$/.crt/;
+ SysLog("New Layout: $crtname\n");
+
+ #my $csrname = "../csr/".$org.($server?"server-":"client-").$row{'id'}.".csr";
+ #my $crtname = "../crt/".$org.($server?"server-":"client-").$row{'id'}.".crt";
+ my $crlname = $revokefile{$row{'rootcert'}};
+
+ my $crt="";
+
+
+ if(open(IN,"<$crtname"))
+ {
+ undef $/;
+ my $content=<IN>;
+ close IN;
+ my $revokehash=sha1_hex(readfile($crlname));
+
+ my $crl=Request($ver,2,1,$row{'rootcert'}-1,0,0,365,0,$content,"",$revokehash);
+ my $result=DoCRL($crl,$crlname);
+
+ if($result)
+ {
+ setUsersLanguage($row{memid});
+
+ my %user=getUserData($row{memid});
+
+ $dbh->do("update `$table` set `revoked`=now() where `id`='".$row{'id'}."'");
+
+ my $body = _("Hi")." $user{fname},\n\n";
+ $body .= sprintf(_("Your certificate for %s has been revoked, as per request.")."\n\n", $row{'CN'});
+ $body .= _("Best regards")."\n"._("CAcert.org Support!")."\n\n";
+ SysLog("Sending email to ".$user{"email"}."\n") if($debug);
+ sendmail($user{email}, "[CAcert.org] "._("Your certificate"), $body, "support\@cacert.org", "", "", "CAcert Support");
+ }
+
+ }
+ else
+ {
+ SysLog("Error in RevokeCerts: $crtname $!\n") if($debug);
+ }
+
+ }
+
+}
+
+
+
+
+sub HandleGPG()
+{
+ my $sth = $dbh->prepare("select * from gpg where crt='' and csr!='' ");
+ $sth->execute();
+ my $rowdata;
+ while ( $rowdata = $sth->fetchrow_hashref() )
+ {
+ my %row=%{$rowdata};
+
+ my $prefix="gpg";
+ my $short=int($row{'id'}/1000);
+ my $csrname = "../csr/$prefix-".$row{'id'}.".csr";
+ $csrname = "../csr/$prefix/$short/$prefix-".$row{'id'}.".csr" if($newlayout);
+ SysLog("New Layout: "."../csr/$prefix/$short/$prefix-".$row{'id'}.".csr\n");
+
+ #my $crtname = "../crt/$prefix-".$row{'id'}.".crt";
+ my $crtname=$csrname; $crtname=~s/^\.\.\/csr/..\/crt/; $crtname=~s/\.csr$/.crt/;
+ SysLog("New Layout: $crtname\n");
+
+
+ #my $csrname = "../csr/gpg-".$row{'id'}.".csr";
+ #my $crtname = "../crt/gpg-".$row{'id'}.".crt";
+
+ SysLog "Opening $csrname\n";
+
+ my $crt="";
+
+ if(-s $csrname && open(IN,"<$csrname"))
+ {
+ undef $/;
+ my $content=<IN>;
+ close IN;
+ SysLog "Read $csrname.\n";
+ $crt=Request($ver,1,2,0,0,2,366,0,$content,"","");
+ if(length($crt))
+ {
+ open OUT,">$crtname";
+ print OUT $crt;
+ close OUT;
+ }
+
+ }
+ else
+ {
+ #Error("Error: $!\n");
+ next;
+ }
+
+ if(-s $crtname)
+ {
+ SysLog "Opening $crtname\n";
+ setUsersLanguage($row{memid});
+
+ my $date=OpenPGPextractExpiryDate($crtname);
+ my %user=getUserData($row{memid});
+
+ $dbh->do("update `gpg` set `crt`='$crtname', issued=now(), `expire`='$date' where `id`='".$row{'id'}."'");
+
+ my $body = _("Hi")." $user{fname},\n\n";
+ $body .= sprintf(_("Your CAcert signed key for %s is available online at:")."\n\n", $row{'email'});
+ $body .= "https://www.cacert.org/gpg.php?id=3&cert=$row{id}\n\n";
+ $body .= _("To help improve the trust of CAcert in general, it's appreciated if you could also sign our key and upload it to a key server. Below is a copy of our primary key details:")."\n\n";
+ $body .= "pub 1024D/65D0FD58 2003-07-11 CA Cert Signing Authority (Root CA) <gpg\@cacert.org>\n";
+ $body .= "Key fingerprint = A31D 4F81 EF4E BD07 B456 FA04 D2BB 0D01 65D0 FD58\n\n";
+ $body .= _("Best regards")."\n"._("CAcert.org Support!")."\n\n";
+ sendmail($user{email}, "[CAcert.org] Your GPG/PGP Key", $body, "support\@cacert.org", "", "", "CAcert Support");
+ } else {
+ SysLog("Could not find the issued gpg key. ".$row{"id"}."\n");
+ #$dbh->do("delete from `gpg` where `id`='".$row{'id'}."'");
+ }
+ }
+}
+
+
+# Main program loop
+
+my $crlcheck=0;
+
+while ( -f "./client.pl-active" )
+{
+ SysLog("Handling GPG database ...\n");
+ HandleGPG();
+ SysLog("Issueing certs ...\n");
+ HandleCerts(0,0); #personal client certs
+ HandleCerts(0,1); #personal server certs
+ HandleCerts(1,0); #org client certs
+ HandleCerts(1,1); #org server certs
+ SysLog("Revoking certs ...\n");
+ RevokeCerts(0,0); #personal client certs
+ RevokeCerts(0,1); #personal server certs
+ RevokeCerts(1,0); #org client certs
+ RevokeCerts(1,1); #org server certs
+
+ $crlcheck++;
+ RefreshCRLs() if(($crlcheck%100) == 1);
+
+ #print "Sign Request X.509, Root0\n";
+ #my $reqcontent="";
+ #Request($ver,1,1,0,5,2,365,0,$reqcontent,"","/CN=supertest.cacert.at");
+
+ SysLog("NUL Request:\n");
+ my $timestamp=strftime("%m%d%H%M%Y.%S",gmtime);
+ Request($ver,0,0,0,0,0,0,0,$timestamp,"","");
+ sleep(1);
+ usleep(1700000);
+}
diff --git a/CommModule/clientloop.sh b/CommModule/clientloop.sh
new file mode 100755
index 0000000..c1254f2
--- /dev/null
+++ b/CommModule/clientloop.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+while true
+do
+perl ./client.pl
+#mail -s CAcert-Alert pg@futureware.at <error.txt
+echo ******************************************************************
+echo ******************************************************************
+echo ******************************************************************
+sleep 1
+done
+
diff --git a/CommModule/commdaemon b/CommModule/commdaemon
new file mode 100755
index 0000000..d07495a
--- /dev/null
+++ b/CommModule/commdaemon
@@ -0,0 +1,45 @@
+#! /bin/bash
+# @(#)(CAcert) $Id: commdaemon,v 1.2 2009-12-28 15:14:40 wytze Exp $
+# commdaemon - script to run CommModule script in a loop,
+# while checking for removal of activation by external script
+
+NAME=CommModule/commdaemon
+PID=$$
+TAG=${NAME}\[${PID}]
+
+case $# in
+ 1) SCRIPT=$1
+ ACTIVE=${SCRIPT}-active
+ ;;
+ *) echo "Usage: $0 <script>" 1>&2
+ exit 1
+ ;;
+esac
+
+syslog_error()
+{
+ logger -t ${TAG} -p user.err $1
+}
+
+syslog_notice()
+{
+ logger -t ${TAG} -p user.notice $1
+}
+
+if [ ! -x ${SCRIPT} ]
+then
+ syslog_error "${SCRIPT} not found or not executable"
+ exit 1
+fi
+
+(echo -n "${TAG}: "; date) >${ACTIVE}
+
+syslog_notice "main loop started"
+while [ -f ${ACTIVE} ]
+do
+ syslog_notice "${SCRIPT} started"
+ ${SCRIPT} >>nohup.out 2>&1
+ syslog_notice "${SCRIPT} ended"
+ sleep 1
+done
+syslog_notice "main loop stopped"
diff --git a/CommModule/commmodule b/CommModule/commmodule
new file mode 100755
index 0000000..f003f30
--- /dev/null
+++ b/CommModule/commmodule
@@ -0,0 +1,166 @@
+#! /bin/sh
+# @(#)(CAcert) $Id: commmodule,v 1.1 2009-12-28 15:09:24 wytze Exp $
+### BEGIN INIT INFO
+# Provides: commmodule
+# Required-Start: $local_fs $remote_fs $syslog mysql
+# Required-Stop: $local_fs $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Start and stop the CAcert CommModule processes
+# Description: This file should be used to start and stop the CAcert
+# CommModule processes from /etc/init.d.
+### END INIT INFO
+
+# Author: Wytze van der Raay <wytze@cacert.org>
+#
+# Please remove the "Author" lines above and replace them
+# with your own name if you copy and modify this script.
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="CAcert CommModule processes start/stop"
+NAME=commmodule
+PIDFILE=/var/run/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
+. /lib/lsb/init-functions
+
+if [ "$1" != "setup" ]
+then
+ if [ "${COMMROOT}" = "" ]
+ then
+ echo "$0: COMMROOT not set"
+ exit 1
+ fi
+ if [ "${COMMROLE}" = "" ]
+ then
+ echo "$0: COMMROLE not set"
+ exit 1
+ fi
+ if [ ! -d ${COMMROOT} ]
+ then
+ echo "$0: ${COMMROOT} is not a directory"
+ exit 1
+ fi
+ if [ ! -x ${COMMROOT}/commdaemon ]
+ then
+ echo "$0: ${COMMROOT}/commdaemon not present or non-executable"
+ exit 1
+ fi
+ if [ ! -x ${COMMROOT}/${COMMROLE}.pl ]
+ then
+ echo "$0: ${COMMROOT}/${COMMROLE}.pl not present or non executable"
+ exit 1
+ fi
+
+ DAEMON=${COMMROOT}/commdaemon
+ DAEMON_ARGS="${COMMROOT}/${COMMROLE}.pl"
+ ACTIVE=${COMMROOT}/${COMMROLE}.pl-active
+fi
+
+# Load usbserial module with proper parameters
+/sbin/modprobe usbserial vendor=0x067b product=0x2501
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+ start-stop-daemon --start --quiet --pidfile $PIDFILE \
+ --chdir ${COMMROOT} --background --exec $DAEMON --test \
+ > /dev/null \
+ || return 1
+ start-stop-daemon --start --quiet --pidfile $PIDFILE \
+ --chdir ${COMMROOT} --background --exec $DAEMON -- \
+ $DAEMON_ARGS \
+ || return 2
+ # Add code here, if necessary, that waits for the process to be ready
+ # to handle requests from services started subsequently which depend
+ # on this one. As a last resort, sleep for some time.
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ rm -f ${ACTIVE}
+ sleep 5
+ start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
+ RETVAL="$?"
+ [ "$RETVAL" = 2 ] && return 2
+ # Many daemons don't delete their pidfiles when they exit.
+ rm -f $PIDFILE
+ return "$RETVAL"
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ restart|force-reload)
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ setup)
+ # setup default installation of commmodule scripts
+ cp ${NAME} /etc/init.d
+ chown root.root /etc/init.d/${NAME}
+ update-rc.d -f ${NAME} remove
+ update-rc.d ${NAME} defaults 90 20
+ (echo "COMMROOT=/home/cacert/www/CommModule";
+ echo "COMMROLE=client") >/etc/default/${NAME}
+ ;;
+ *)
+ echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|setup}" >&2
+ exit 3
+ ;;
+esac
+
+:
diff --git a/CommModule/error.txt b/CommModule/error.txt
new file mode 100644
index 0000000..7224707
--- /dev/null
+++ b/CommModule/error.txt
@@ -0,0 +1 @@
+The CommModule has a problem.
diff --git a/CommModule/logclean.sh b/CommModule/logclean.sh
new file mode 100755
index 0000000..99963ee
--- /dev/null
+++ b/CommModule/logclean.sh
@@ -0,0 +1,57 @@
+#! /bin/sh
+# logclean.sh - maintenance script for logfiles generated by CommModule
+# run this daily or weekly from cron
+
+syslog_error()
+{
+ logger -i -t CommModule/logclean.sh -p user.err $1
+}
+
+syslog_notice()
+{
+ logger -i -t CommModule/logclean.sh -p user.notice $1
+}
+
+# determine location of CommModule
+if [ -d /home/cacert/www/CommModule ]
+then # webdb server
+ cd /home/cacert/www/CommModule
+elif [ -d /root/CommModule ]
+then # signing server
+ cd /root/CommModule
+else
+ echo "$0: cannot find CommModule directory" 1>&2
+ syslog_error "cannot find CommModule directory"
+ exit 1
+fi
+
+# compress logfiles which have not been modified in at least 48 hours
+FILES=`find logfile20*.txt -mtime +1 -print`
+if [ -n "${FILES}" ]
+then
+ for F in ${FILES}
+ do
+ syslog_notice "Compressing ${F}" && bzip2 ${F}
+ done
+fi
+
+# move compressed logfiles to oldlogs directory
+FILES=`find logfile20*.txt.bz2 -print`
+if [ -n "${FILES}" ]
+then
+ mkdir -p oldlogs
+ for F in ${FILES}
+ do
+ syslog_notice "Moving ${F} to oldlogs" && mv ${F} oldlogs
+ done
+fi
+
+# delete old logfiles which have not been modified in at least 2.5+ years
+FILES=`find oldlogs/logfile20*.txt.bz2 -mtime +913 -print`
+if [ -n "${FILES}" ]
+then
+ for F in ${FILES}
+ do
+ syslog_notice "Deleting ${F}" && rm -f ${F}
+ done
+fi
diff --git a/CommModule/readme.txt b/CommModule/readme.txt
new file mode 100644
index 0000000..d832491
--- /dev/null
+++ b/CommModule/readme.txt
@@ -0,0 +1,6 @@
+client.pl The real client, running on the webserver
+commdaemon Script to run client.pl or server.pl
+commmodule Script for startup/shutdown of CommModule from /etc/init.d
+logclean.sh Maintenance script for logfiles generated by CommModule
+serial.conf Serial Port configuration file
+usbclient.pl Obsoleted USB version of client.pl above
diff --git a/CommModule/serial.conf b/CommModule/serial.conf
new file mode 100755
index 0000000..bd9980c
--- /dev/null
+++ b/CommModule/serial.conf
@@ -0,0 +1,32 @@
+Device::SerialPort_Configuration_File -- DO NOT EDIT --
+/dev/ttyUSB0
+
+C_CFLAG,7346
+C_IFLAG,0
+C_ISPEED,4098
+C_LFLAG,2608
+C_OFLAG,4
+C_OSPEED,4098
+C_VERASE,127
+C_VQUIT,28
+C_VSUSP,26
+C_VINTR,3
+C_VSTOP,19
+C_VSTART,17
+C_VKILL,21
+C_VMIN,0
+C_VEOF,4
+C_VEOL,0
+C_VTIME,0
+CFG_1,none
+RCONST,0
+CFG_2,none
+HNAME,localhost
+ALIAS,/dev/ttyUSB0
+CFG_3,none
+U_MSG,0
+DATYPE,raw
+E_MSG,0
+HADDR,0
+RTOT,0
+DVTYPE,none
diff --git a/CommModule/usbclient.pl b/CommModule/usbclient.pl
new file mode 100755
index 0000000..3cbe2c3
--- /dev/null
+++ b/CommModule/usbclient.pl
@@ -0,0 +1,1019 @@
+#!/usr/bin/perl -w
+
+# CommModule - CAcert Communication module
+# Copyright (C) 2004-2008 CAcert Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Production Client / CommModule
+
+use strict;
+use Device::USB;
+use POSIX;
+use Time::HiRes q(usleep);
+use File::CounterFile;
+use File::Copy;
+use DBI;
+use Locale::gettext;
+use IO::Socket;
+use MIME::Base64;
+use Digest::SHA1 qw(sha1_hex sha1);
+
+#Protocol version:
+my $ver=1;
+
+#Debugging does not delete work-files for later inspection
+my $debug=0;
+
+#Paranoid exists the program on a malicious request
+my $paranoid=1;
+
+#Location of the openssl and gpg binaries
+my $gpgbin="/usr/bin/gpg";
+my $opensslbin="/usr/bin/openssl";
+
+my $mysqlphp="/home/cacert/www/includes/mysql.php";
+
+my %revokefile=(2=>"../www/class3-revoke.crl",1=>"../www/revoke.crl",0=>"../www/revoke.crl");
+
+#USB-Link settings
+my $PACKETSIZE=0x100;
+my $SALT="Salz";
+my $HASHSIZE=20;
+
+#End of configurations
+
+########################################################
+
+
+#Reads a while file and returns the content
+#Returns undef on failure
+sub readfile($)
+{
+ my $olds=$/;
+ my $content=undef;
+ if(open READIN,"<$_[0]")
+ {
+ binmode READIN;
+ undef $/;
+ $content=<READIN>;
+ close READIN;
+ $/=$olds;
+ }
+ return $content;
+}
+
+#Writes/Overwrites a file with content.
+#Returns 1 on success, 0 on failure.
+sub writefile($$)
+{
+ if(open WRITEOUT,">$_[0]")
+ {
+ binmode WRITEOUT;
+ print WRITEOUT $_[1];
+ close WRITEOUT;
+ return 1;
+ }
+ return 0;
+}
+
+#mkdir "revokehashes";
+foreach (keys %revokefile)
+{
+ my $revokehash=sha1_hex(readfile($revokefile{$_}));
+ print "Root $_: Hash $revokefile{$_} = $revokehash\n";
+}
+
+my %monarr = ("Jan" => 1, "Feb" => 2, "Mar" => 3, "Apr" => 4, "May" => 5, "Jun" => 6, "Jul" => 7, "Aug" => 8, "Sep" => 9, "Oct" => 10, "Nov" => 11, "Dec" => 12);
+
+my $content=readfile($mysqlphp);
+my $password="";$password=$1 if($content=~m/mysql_connect\("[^"]+",\s*"\w+",\s*"(\w+)"/);
+$content="";
+
+my $dbh = DBI->connect("DBI:mysql:cacert:localhost",$password?"cacert":"",$password, { RaiseError => 1, AutoCommit => 1 }) || die ("Error with the database connection.\n");
+
+
+#Logging functions:
+sub SysLog($)
+{
+ my @ltime=localtime;
+ my $date=strftime("%Y-%m-%d",@ltime);
+ open LOG,">>logfile$date.txt";
+ return if(not defined($_[0]));
+ my $timestamp=strftime("%Y-%m-%d %H:%M:%S",@ltime);
+ #$syslog->write($_[0]."\x00");
+ print LOG "$timestamp $_[0]";
+ print "$timestamp $_[0]";
+ flush LOG;
+ close LOG;
+}
+
+
+sub Error($)
+{
+ SysLog($_[0]);
+ if($paranoid)
+ {
+ die $_[0];
+ }
+}
+
+
+my $timestamp=strftime("%Y-%m-%d %H:%M:%S",localtime);
+
+
+sub mysql_query($)
+{
+ $dbh->do($_[0]);
+}
+
+sub trim($)
+{
+ my $new=$_[0];
+ $new=~s/^\s*//;
+ $new=~s/\s*$//;
+ return($new);
+}
+
+sub addslashes($)
+{
+ my $new=$_[0];
+ $new=~s/['"\\]/\\$1/g;
+ return($new);
+}
+
+sub recode
+{
+ return $_[1];
+}
+
+
+#Hexdump function: Returns the hexdump representation of a string
+sub hexdump($)
+{
+ return "" if(not defined($_[0]));
+ my $content="";
+ $content.=sprintf("%02X ",unpack("C",substr($_[0],$_,1))) foreach (0 .. length($_[0])-1);
+ return $content;
+}
+
+#pack3 packs together the length of the data in 3 bytes and the data itself, size limited to 16MB. In case the data is more than 16 MB, it is ignored, and a 0 Byte block is transferred
+sub pack3
+{
+ return "\x00\x00\x00" if(!defined($_[0]));
+ my $data=(length($_[0]) >= 2**24)? "":$_[0];
+ my $len=pack("N",length($data));
+ #print "len: ".length($data)."\n";
+ return substr($len,1,3).$data;
+}
+
+
+#unpack3 unpacks packed data.
+sub unpack3($)
+{
+ return undef if((not defined($_[0])) or length($_[0])<3);
+ #print "hexdump: ".hexdump("\x00".substr($_[0],0,3))."\n";
+ my $len=unpack("N","\x00".substr($_[0],0,3));
+ #print "len3: $len length(): ".length($_[0])." length()-3: ".(length($_[0])-3)."\n";
+ return undef if(length($_[0])-3 != $len);
+ return substr($_[0],3);
+}
+
+
+#unpack3array extracts a whole array of concatented packed data.
+sub unpack3array($)
+{
+ my @retarr=();
+ if((not defined($_[0])) or length($_[0])<3)
+ {
+ SysLog "Datenanfang kaputt\n";
+ return ();
+ }
+ my $dataleft=$_[0];
+ while(length($dataleft)>=3)
+ {
+ #print "hexdump: ".hexdump("\x00".substr($dataleft,0,3))."\n";
+ my $len=unpack("N","\x00".substr($dataleft,0,3));
+ #print "len3: $len length(): ".length($dataleft)." length()-3: ".(length($dataleft)-3)."\n";
+ if(length($dataleft)-3 < $len)
+ {
+ SysLog "Datensatz abgeschnitten\n";
+ return ();
+ }
+ push @retarr, substr($dataleft,3,$len);
+ $dataleft=substr($dataleft,3+$len);
+ }
+ if(length($dataleft)!=0)
+ {
+ SysLog "Ende abgeschnitten\n";
+ return ();
+ }
+ return @retarr;
+}
+
+#Pack4 packs and secret-key signs some data.
+sub pack4($)
+{
+ return pack("N",length($_[0])).$_[0].sha1($SALT.$_[0]);
+}
+
+
+
+
+
+$timestamp=strftime("%Y-%m-%d %H:%M:%S",localtime);
+
+SysLog("Starting Server at $timestamp\n");
+
+$SALT=readfile(".salt.key");
+
+SysLog("Opening USB-Link interface:\n");
+
+#Opening USB device:
+my $usb = Device::USB->new();
+my @list=$usb->list_devices(0x067b,0x2501);
+my $dev = $list[0];
+if(defined($dev))
+{
+ #print "USB-Link Device found: ", $dev->filename(), "\n";
+ if($dev->open())
+ {
+ #print "\t", $dev->manufacturer(), ": ", $dev->product(), "\n";
+ $dev->claim_interface(0);
+
+ my $buffer=" ";
+
+ $dev->control_msg(0xc0 , 0xfb, 0, 0, $buffer, 2, 1000);
+
+ if($buffer ne "\x04\x08" and $buffer ne "\x0c\x04" and $buffer ne "\x00\x0c" and $buffer ne "\x04\x0c")
+ {
+ print "Please plug the USB-Link cable into the other computer.\n";
+ }
+ else
+ {
+ print "USB-Link ok.\n";
+ }
+ }
+ else
+ {
+ print "Unable to work with USB-Link device: $!\n";
+ }
+}
+else
+{
+ print "USB-Link Device not found. Please plug the cable into this computer.\n";
+}
+
+
+
+
+
+
+#sends a single packet (pack4 encoded). Returns the returncode
+sub send_packet($)
+{
+ if((14+length($_[0])+$HASHSIZE) > $PACKETSIZE)
+ {
+ return -1;
+ }
+ # 4 Bytes Length, N Bytes Data, 20 Bytes SHA1 Hash, 0 Padding
+ my $data="CommModule".pack4($_[0]);
+ $data.=("\x00"x($PACKETSIZE-length($data)));
+ my $ret=$dev->bulk_write(0x2,$data,length($data),1000);
+ print "Send-result: $ret\n";
+ return $ret;
+}
+
+#Receives several consecutive packets. Returns the concatenated payload
+sub receive_packets()
+{
+ print "Receiving packets ...\n";
+ my $collectedpayload="";
+ my $done=0;
+ while(!$done)
+ {
+ my $data=" "x$PACKETSIZE;
+ my $re=$dev->bulk_read(0x83,$data,length($data),10000);
+ writefile("usbpacket.dat",$data);
+ print "Read: $re Bytes: ".length($data)."\n";
+ if($re > 0)
+ {
+ $data=~s/^.*?CommModule//s;
+ my $len=unpack("N",substr($data,0,4));
+ print "len: $len\n";
+ if($len>=0 and $len<=$PACKETSIZE-$HASHSIZE-4)
+ {
+ my $payload=substr($data,4,$len);
+ if(sha1($SALT.$payload) eq substr($data,4+$len,$HASHSIZE))
+ {
+ print "Hash OK!\n";
+ $collectedpayload.=substr($payload,1);
+ $done=1 if(substr($payload,0,1)eq "0");
+ }
+ else
+ {
+ print "Hash NOT OK: ".sha1_hex($SALT.$payload)." vs. ".hexdump(substr($data,4+$len,$HASHSIZE))." !\n";
+ return "";
+ }
+ }
+ }
+ elsif($re == 0)
+ {
+ print "USB-Link cable disconnected?\n";
+ #return "";
+ }
+ }
+ print "Receiving done.\n";
+ return $collectedpayload;
+}
+
+
+
+
+my $MAXCHUNK=$PACKETSIZE-100;
+
+#Sends data over the USB-Link, without handshaking
+sub SendPackets($)
+{
+ print "Sending Packets ...\n";
+ my $data=pack4($_[0]);
+ my $done=0;
+ return if(!defined($data) or !length($data));
+
+ while(!$done)
+ {
+ while(length($data)>0)
+ {
+ my $d=substr($data,0,$MAXCHUNK);
+ if(length($data)>$MAXCHUNK)
+ {
+ send_packet("1".$d);
+ $data=substr($data,$MAXCHUNK);
+ }
+ else
+ {
+ send_packet("0".$d);
+ $data="";
+ }
+ }
+ $done=1;
+ }
+ print "Sending Packets done.\n";
+}
+
+#Receives several packets, verifies the secret key signature and extracts the payload
+#Returns the payload
+sub Receive
+{
+ my $data=receive_packets();
+ if (!defined($data) or length($data)<4)
+ {
+ print "Received data too short!\n";
+ return "";
+ }
+ my $len=unpack("N",substr($data,0,4));
+ if($len != (length($data)-$HASHSIZE-4))
+ {
+ print "Length field does not match data on Receive!\n";
+ return "";
+ }
+ my $payload=substr($data,4,$len);
+ if(sha1($SALT.$payload) ne substr($data,4+$len,$HASHSIZE))
+ {
+ print "Hash on Receive is BROKEN!\n";
+ return "";
+ }
+ return $payload;
+}
+
+
+
+
+# @result(Version,Action,Errorcode,Response)=Request(Version=1,Action=1,System=1,Root=1,Configuration="...",Parameter="...",Request="...");
+sub Request($$$$$$$$$$$)
+{
+ print "Version: $_[0] Action: $_[1] System: $_[2] Root: $_[3] Config: $_[4]\n";
+ $_[3]=0 if($_[3]<0);
+ SendPackets(pack3(pack3(pack("C*",$_[0],$_[1],$_[2],$_[3],$_[4],$_[5],$_[6]>>8,$_[6]&255,$_[7])).pack3($_[8]).pack3($_[9]).pack3($_[10])));
+ my $data=Receive();
+ if(defined($data) and length($data)>6)
+ {
+ my @fields=unpack3array(substr($data,3));
+
+ SysLog "Answer from Server: ".hexdump($data)."\n" if($debug);
+
+ #writefile("result.dat",$data);
+
+ return $fields[1];
+ }
+ return "";
+}
+
+
+sub calculateDays($)
+{
+ if($_[0])
+ {
+ my @sum = $dbh->selectrow_array("select sum(`points`) as `total` from `notary` where `to`='".$_[0]."' group by `to`");
+ SysLog("Summe: $sum[0]\n") if($debug);
+
+ return ($sum[0]>=50)?730:180;
+ }
+ return 180;
+}
+
+sub X509extractSAN($)
+{
+ my @bits = split("/", $_[0]);
+ my $SAN="";
+ my $newsubject="";
+ foreach my $val(@bits)
+ {
+ my @bit=split("=",$val);
+ if($bit[0] eq "subjectAltName")
+ {
+ $SAN.="," if($SAN ne "");
+ $SAN.= trim($bit[1]);
+ }
+ else
+ {
+ $newsubject .= "/".$val;
+ }
+ }
+ $newsubject=~s{^//}{/};
+ $newsubject=~s/[\n\r\t\x00"\\']//g;
+ $SAN=~s/[ \n\r\t\x00"\\']//g;
+ return($SAN,$newsubject);
+}
+
+sub X509extractExpiryDate($)
+{
+ # TIMEZONE ?!?
+ my $data=`$opensslbin x509 -in "$_[0]" -noout -enddate`;
+
+ #notAfter=Aug 8 10:26:34 2007 GMT
+ if($data=~m/notAfter=(\w{2,4}) *(\d{1,2}) *(\d{1,2}:\d{1,2}:\d{1,2}) (\d{4}) GMT/)
+ {
+ my $date="$4-".$monarr{$1}."-$2 $3";
+ SysLog "Expiry Date found: $date\n" if($debug);
+ return $date;
+ }
+ else
+ {
+ SysLog "Expiry Date not found: $data\n";
+ }
+ return "";
+}
+sub X509extractSerialNumber($)
+{
+ # TIMEZONE ?!?
+ my $data=`$opensslbin x509 -in "$_[0]" -noout -serial`;
+ if($data=~m/serial=([0-9A-F]+)/)
+ {
+ return $1;
+ }
+ return "";
+}
+
+sub OpenPGPextractExpiryDate ($)
+{
+ my $r="";
+ my $cts;
+ my @date;
+
+ open(RGPG, $gpgbin.' -vv '.$_[0].' 2>&1 |') or Error('Can\'t start GnuPG($gpgbin): '.$!."\n");
+ open(OUT, '> infogpg.txt' ) or Error('Can\'t open output file: infogpg.txt: '.$!);
+ $/="\n";
+ while (<RGPG>)
+ {
+ print OUT $_;
+ unless ($r)
+ {
+ if ( /^\s*version \d+, created (\d+), md5len 0, sigclass \d+\s*$/ )
+ {
+ SysLog "Detected CTS: $1\n";
+ $cts = int($1);
+ } elsif ( /^\s*critical hashed subpkt \d+ len \d+ \(sig expires after ((\d+)y)?((\d+)d)?((\d+)h)?(\d+)m\)\s*$/ )
+ {
+ SysLog "Detected FRAME $2 $4 $6 $8\n";
+ $cts += $2 * 31536000; # secs per year (60 * 60 * 24 * 365)
+ $cts += $4 * 86400; # secs per day (60 * 60 * 24)
+ $cts += $6 * 3600; # secs per hour (60 * 60)
+ $cts += $8 * 60; # secs per min (60)
+ $r = $cts;
+ }
+ elsif(/version/)
+ {
+ SysLog "Detected VERSION\n";
+ }
+ }
+ }
+
+ close(OUT );
+ close(RGPG);
+
+ SysLog "CTS: $cts R: $r\n";
+
+ if ( $r )
+ {
+ @date = gmtime($r);
+ $r = sprintf('%.4i-%.2i-%.2i %.2i:%.2i:%.2i', # date format
+ $date[5] + 1900, $date[4] + 1, $date[3], # day
+ $date[2], $date[1], $date[0], # time
+ );
+
+ }
+ SysLog "$r\n";
+ return $r;
+}
+
+
+# Sets the locale according to the users preferred language
+sub setUsersLanguage($)
+{
+ my $lang="de_DE";
+ print "Searching for the language of the user $_[0]\n";
+ my @a=$dbh->selectrow_array("select language from users where id='".int($_[0])."'");
+ $lang = $1 if($a[0]=~m/(\w+_[\w.@]+)/);
+
+ SysLog "The users preferred language: $lang\n";
+
+ if($lang ne "")
+ {
+ $ENV{"LANG"}=$lang;
+ setlocale(LC_ALL, $lang);
+ } else {
+ $ENV{"LANG"}="en_AU";
+ setlocale(LC_ALL, "en_AU");
+ }
+}
+
+
+sub getUserData($)
+{
+ my $sth = $dbh->prepare("select * from users where id='$_[0]'");
+ $sth->execute();
+ #SysLog "USER DUMP:\n";
+ while ( my $rowdata = $sth->fetchrow_hashref() )
+ {
+ my %tmp=%{$rowdata};
+ #foreach (sort keys %tmp)
+ #{
+ #SysLog " $_ -> $tmp{$_}\n";
+ #}
+ return %tmp;
+ }
+ return ();
+}
+
+
+sub _($)
+{
+ return gettext($_[0]);
+}
+
+sub sendmail($$$$$$$)
+{
+ my ($to, $subject, $message, $from, $replyto, $toname, $fromname)=@_;
+ my $errorsto="returns\@cacert.org";
+ my $extra="";
+
+
+ # sendmail($user{email}, "[CAcert.org] Your GPG/PGP Key", $body, "support\@cacert.org", "", "", "CAcert Support");
+ my @lines=split("\n",$message);
+ $message = "";
+ foreach my $line (@lines)
+ {
+ $line = trim($line);
+ if($line eq ".")
+ {
+ $message .= " .\n";
+ } else
+ {
+ $message .= $line."\n";
+ }
+ }
+
+ $fromname = $from if($fromname eq "");
+
+ my @bits = split(",", $from);
+ $from = addslashes($bits['0']);
+ $fromname = addslashes($fromname);
+
+ my $smtp = IO::Socket::INET->new(PeerAddr => 'localhost:25');
+ $/="\n";
+ SysLog "SMTP: ".<$smtp>."\n";
+ print $smtp "HELO hlin.cacert.org\r\n";
+ SysLog "SMTP: ".<$smtp>."\n";
+ print $smtp "MAIL FROM: <returns\@cacert.org>\r\n";
+ SysLog "MAIL FROM: ".<$smtp>."\n";
+
+ @bits = split(",", $to);
+ foreach my $user (@bits)
+ {
+ print $smtp "RCPT TO: <".trim($user).">\r\n";
+ SysLog "RCPT TO: ".<$smtp>."\n";
+ }
+ print $smtp "DATA\r\n";
+ SysLog "DATA: ".<$smtp>."\n";
+
+ print $smtp "X-Mailer: CAcert.org Website\r\n";
+ print $smtp "X-OriginatingIP: ".$ENV{"REMOTE_ADDR"}."\r\n";
+ print $smtp "Sender: $errorsto\r\n";
+ print $smtp "Errors-To: $errorsto\r\n";
+ if($replyto ne "")
+ {
+ print $smtp "Reply-To: $replyto\r\n";
+ }
+ else
+ {
+ print $smtp "Reply-To: $from\r\n";
+ }
+ print $smtp "From: $from ($fromname)\r\n";
+ print $smtp "To: $to\r\n";
+ my $newsubj=encode_base64(recode("html..utf-8", trim($subject)));
+ #SysLog("NewSubj: --".$newsubj."--\n") if($debug);
+ $newsubj=~s/\n*$//;
+ #SysLog("NewSubj: --".$newsubj."--\n") if($debug);
+ print $smtp "Subject: =?utf-8?B?$newsubj?=\r\n";
+ print $smtp "Mime-Version: 1.0\r\n";
+ if($extra eq "")
+ {
+ print $smtp "Content-Type: text/plain; charset=\"utf-8\"\r\n";
+ print $smtp "Content-Transfer-Encoding: 8bit\r\n";
+ } else {
+ print $smtp "Content-Type: text/plain; charset=\"iso-8859-1\"\r\n";
+ print $smtp "Content-Transfer-Encoding: quoted-printable\r\n";
+ print $smtp "Content-Disposition: inline\r\n";
+ };
+# print $smtp "Content-Transfer-Encoding: BASE64\r\n";
+ print $smtp "\r\n";
+# print $smtp chunk_split(encode_base64(recode("html..utf-8", $message)))."\r\n.\r\n";
+ print $smtp recode("html..utf-8", $message)."\r\n.\r\n";
+ SysLog "ENDOFTEXT: ".<$smtp>."\n";
+ print $smtp "QUIT\n";
+ SysLog "QUIT: ".<$smtp>."\n";
+ close($smtp);
+}
+
+
+sub HandleCerts($$)
+{
+ my $org=$_[0]?"org":"";
+ my $server=$_[1];
+
+ my $table=$org.($server?"domaincerts":"emailcerts");
+
+ my $sth = $dbh->prepare("select * from $table where crt_name='' and csr_name!='' ");
+ $sth->execute();
+ #$rowdata;
+ while ( my $rowdata = $sth->fetchrow_hashref() )
+ {
+ my %row=%{$rowdata};
+
+ my $csrname = "../csr/".$org.($server?"server-":"client-").$row{'id'}.".csr";
+ my $crtname = "../crt/".$org.($server?"server-":"client-").$row{'id'}.".crt";
+
+
+ if($server)
+ {
+ #Weird SQL structure ...
+ my @sqlres=$dbh->selectrow_array("select memid from domains where id='".int($row{'domid'})."'");
+ $row{'memid'}=$sqlres[0];
+ SysLog("Fetched memid: $row{'memid'}\n") if($debug);
+ }
+
+ SysLog "Opening $csrname\n";
+
+ my $crt="";
+
+ my $profile=0;
+
+ # "0"=>"client.cnf",
+ # "1"=>"client-org.cnf",
+ # "2"=>"client-codesign.cnf",
+ # "3"=>"client-machine.cnf",
+ # "4"=>"client-ads.cnf",
+ # "5"=>"server.cnf",
+ # "6"=>"server-org.cnf",
+ # "7"=>"server-jabber.cnf",
+ # "8"=>"server-ocsp.cnf",
+ # "9"=>"server-timestamp.cnf",
+ # "10"=>"proxy.cnf",
+ # "11"=>"subca.cnf"
+
+
+ if($row{"type"} =~ m/^(8|9)$/)
+ {
+ $profile=$row{"type"};
+ }
+ elsif($org)
+ {
+ if($row{'codesign'})
+ {
+ $profile=2; ## TODO!
+ }
+ elsif($server)
+ {
+ $profile=6;
+ }
+ else
+ {
+ $profile=1;
+ }
+ }
+ else
+ {
+ if($row{'codesign'})
+ {
+ $profile=2;
+ }
+ elsif($server)
+ {
+ $profile=5;
+ }
+ else
+ {
+ $profile=0;
+ }
+
+
+ }
+
+
+
+ if(open(IN,"<$csrname"))
+ {
+ undef $/;
+ my $content=<IN>;
+ close IN;
+ SysLog "Read.\n" if($debug);
+ SysLog "Subject: --$row{'subject'}--\n" if($debug);
+
+ my ($SAN,$subject)=X509extractSAN($row{'subject'});
+ SysLog "Subject: --$subject--\n" if($debug);
+ SysLog "SAN: --$SAN--\n" if($debug);
+ SysLog "memid: $row{'memid'}\n" if($debug);
+
+ my $days=$org?($server?(365*2):365):calculateDays($row{"memid"});
+
+
+ $crt=Request($ver,1,1,$row{'rootcert'}-1,$profile,$row{'md'}eq"sha1"?2:0,$days,$row{'keytype'}eq"NS"?1:0,$content,$SAN,$subject);
+ if(length($crt))
+ {
+ if($crt=~m/^-----BEGIN CERTIFICATE-----/)
+ {
+ open OUT,">$crtname";
+ print OUT $crt;
+ close OUT;
+ }
+ else
+ {
+ open OUT,">$crtname.der";
+ print OUT $crt;
+ close OUT;
+ system "$opensslbin x509 -in $crtname.der -inform der -out $crtname";
+ }
+ }
+
+ }
+ else
+ {
+ print "Error: $! Konnte $csrname nicht laden\n";
+ }
+
+
+
+ if(-s $crtname)
+ {
+ SysLog "Opening $crtname\n";
+
+ my $date=X509extractExpiryDate($crtname);
+ my $serial=X509extractSerialNumber($crtname);
+
+ setUsersLanguage($row{memid});
+
+ my %user=getUserData($row{memid});
+
+ foreach (sort keys %user)
+ {
+ SysLog " $_ -> $user{$_}\n" if($debug);
+ }
+
+ SysLog("update `$table` set `crt_name`='$crtname', modified=now(), serial='$serial', `expire`='$date' where `id`='".$row{'id'}."'\n");
+
+ $dbh->do("update `$table` set `crt_name`='$crtname', modified=now(), serial='$serial', `expire`='$date' where `id`='".$row{'id'}."'");
+
+ my $body = _("Hi")." $user{fname},\n\n";
+ $body .= sprintf(_("You can collect your certificate for %s by going to the following location:")."\n\n", $row{'email'});
+ $body .= "https://www.cacert.org/account.php?id=".($server?"15":"6")."&cert=$row{id}\n\n";
+ $body .= _("If you havent imported CAcert´s root certificate, please go to:")."\n";
+ $body .= "https://www.cacert.org/index.php?id=3\n";
+ $body .= "Root cert fingerprint = A6:1B:37:5E:39:0D:9C:36:54:EE:BD:20:31:46:1F:6B\n";
+ $body .= "Root cert fingerprint = 135C EC36 F49C B8E9 3B1A B270 CD80 8846 76CE 8F33\n\n";
+ $body .= _("Best regards")."\n"._("CAcert.org Support!")."\n\n";
+ sendmail($user{email}, "[CAcert.org] "._("Your certificate"), $body, "support\@cacert.org", "", "", "CAcert Support");
+ } else {
+ $dbh->do("delete from `$table` where `id`='".$row{'id'}."'");
+ }
+ }
+}
+
+sub HandleNewCRL($$)
+{
+ my ($crl,$crlname)=@_;
+ if(length($crl))
+ {
+ if($crl=~m/^\%XD/)
+ {
+ writefile("$crlname.patch",$crl);
+ system "xdelta patch $crlname.patch $crlname $crlname.tmp";
+ }
+ elsif($crl=~m/^-----BEGIN X509 CRL-----/)
+ {
+ writefile("$crlname.pem",$crl);
+ system "$opensslbin crl -in $crlname.pem -outform der -out $crlname.tmp";
+ }
+ elsif($crl=~m/^\x30/)
+ {
+ writefile("$crlname.tmp",$crl);
+ }
+ else
+ {
+ Error "Unknown CRL format!".(substr($crl,0,5))."\n";
+ }
+ rename "$crlname.tmp","$crlname"; # Atomic move
+ }
+}
+
+
+sub RevokeCerts($$)
+{
+ my $org=$_[0]?"org":"";
+ my $server=$_[1];
+
+ my $table=$org.($server?"domaincerts":"emailcerts");
+
+ my $sth = $dbh->prepare("select * from $table where revoked='1970-01-01 10:00:01'"); # WHICH TIMEZONE?
+ $sth->execute();
+ #$rowdata;
+ while ( my $rowdata = $sth->fetchrow_hashref() )
+ {
+ my %row=%{$rowdata};
+
+ my $csrname = "../csr/".$org.($server?"server-":"client-").$row{'id'}.".csr";
+ my $crtname = "../crt/".$org.($server?"server-":"client-").$row{'id'}.".crt";
+ my $crlname = $revokefile{$row{'rootcert'}};
+
+ my $crt="";
+
+
+ if(open(IN,"<$crtname"))
+ {
+ undef $/;
+ my $content=<IN>;
+ close IN;
+ my $revokehash=sha1_hex(readfile($crlname));
+
+ my $crl=Request($ver,2,1,$row{'rootcert'}-1,0,0,365,0,$content,"",$revokehash);
+ HandleNewCRL($crl,$crlname);
+
+ if(-s $crlname)
+ {
+ setUsersLanguage($row{memid});
+
+ my %user=getUserData($row{memid});
+
+ $dbh->do("update `$table` set `revoked`=now() where `id`='".$row{'id'}."'");
+
+ my $body = _("Hi")." $user{fname},\n\n";
+ $body .= sprintf(_("Your certificate for %s has been revoked, as per request.")."\n\n", $row{'CN'});
+ $body .= _("Best regards")."\n"._("CAcert.org Support!")."\n\n";
+ sendmail($user{email}, "[CAcert.org] "._("Your certificate"), $body, "support\@cacert.org", "", "", "CAcert Support");
+ }
+
+ }
+ else
+ {
+ SysLog("Error: $crtname $!\n") if($debug);
+ }
+
+ }
+
+}
+
+
+
+
+
+sub HandleGPG()
+{
+ my $sth = $dbh->prepare("select * from gpg where crt='' and csr!='' ");
+ $sth->execute();
+ my $rowdata;
+ while ( $rowdata = $sth->fetchrow_hashref() )
+ {
+ my %row=%{$rowdata};
+
+ my $csrname = "../csr/gpg-".$row{'id'}.".csr";
+ my $crtname = "../crt/gpg-".$row{'id'}.".crt";
+
+ SysLog "Opening $csrname\n";
+
+ my $crt="";
+
+ if(-s $csrname && open(IN,"<$csrname"))
+ {
+ undef $/;
+ my $content=<IN>;
+ close IN;
+ SysLog "Read.\n";
+ $crt=Request($ver,1,2,0,0,2,366,0,$content,"","");
+ if(length($crt))
+ {
+ open OUT,">$crtname";
+ print OUT $crt;
+ close OUT;
+ }
+
+ }
+ else
+ {
+ #Error("Error: $!\n");
+ next;
+ }
+
+ if(-s $crtname)
+ {
+ SysLog "Opening $crtname\n";
+ setUsersLanguage($row{memid});
+
+ my $date=OpenPGPextractExpiryDate($crtname);
+ my %user=getUserData($row{memid});
+
+ $dbh->do("update `gpg` set `crt`='$crtname', issued=now(), `expire`='$date' where `id`='".$row{'id'}."'");
+
+ my $body = _("Hi")." $user{fname},\n\n";
+ $body .= sprintf(_("Your CAcert signed key for %s is available online at:")."\n\n", $row{'email'});
+ $body .= "https://www.cacert.org/gpg.php?id=3&cert=$row{id}\n\n";
+ $body .= _("To help improve the trust of CAcert in general, it's appreciated if you could also sign our key and upload it to a key server. Below is a copy of our primary key details:")."\n\n";
+ $body .= "pub 1024D/65D0FD58 2003-07-11 CA Cert Signing Authority (Root CA) <gpg\@cacert.org>\n";
+ $body .= "Key fingerprint = A31D 4F81 EF4E BD07 B456 FA04 D2BB 0D01 65D0 FD58\n\n";
+ $body .= _("Best regards")."\n"._("CAcert.org Support!")."\n\n";
+ sendmail($user{email}, "[CAcert.org] Your GPG/PGP Key", $body, "support\@cacert.org", "", "", "CAcert Support");
+ } else {
+ $dbh->do("delete from `gpg` where `id`='".$row{'id'}."'");
+ }
+ }
+}
+
+
+# Main program loop
+
+while(1)
+{
+ SysLog("Handling GPG database ...\n");
+# HandleGPG();
+ SysLog("Issueing certs ...\n");
+# HandleCerts(0,0); #personal client certs
+# HandleCerts(0,1); #personal server certs
+# HandleCerts(1,0); #org client certs
+# HandleCerts(1,1); #org server certs
+# SysLog("Revoking certs ...\n");
+# RevokeCerts(0,0); #personal client certs
+# RevokeCerts(0,1); #personal server certs
+# RevokeCerts(1,0); #org client certs
+# RevokeCerts(1,1); #org server certs
+
+ #print "Sign Request X.509, Root0\n";
+ #my $reqcontent="";
+ #Request($ver,1,1,0,5,2,365,0,$reqcontent,"","/CN=supertest.cacert.at");
+
+ SysLog("NUL Request:\n");
+ my $timestamp=strftime("%m%d%H%M%Y.%S",gmtime);
+ my $ret=Request($ver,0,0,0,0,0,0,0,$timestamp,"","");
+ print "RET: $ret\n";
+
+ SysLog("Generate regular CRLs:\n");
+ foreach my $root ((1,2))
+ {
+ my $crlname = $revokefile{$root};
+ my $revokehash=sha1_hex(readfile($crlname));
+ print "Aktueller Hash am Webserver: $revokehash\n";
+ my $crl=Request($ver,2,1,$root-1,0,0,365,0,"","",$revokehash);
+ HandleNewCRL($crl,$crlname);
+ }
+
+ usleep(700000);
+}