source code taken from cacert-20100204.tar.bz2
[cacert.git] / cacert / www / gpg.php
1 <? /*
2 LibreSSL - CAcert web application
3 Copyright (C) 2004-2008 CAcert Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */ ?>
18 <?
19 require_once("../includes/loggedin.php");
20
21 $id = 0; if(array_key_exists('id',$_REQUEST)) $id=intval($_REQUEST['id']);
22 $oldid = $_REQUEST['oldid'] = array_key_exists('oldid',$_REQUEST) ? intval($_REQUEST['oldid']) : 0;
23
24 if($_SESSION['profile']['points'] < 50)
25 {
26 header("location: /account.php");
27 exit;
28 }
29
30 loadem("account");
31
32
33
34 $CSR=""; if(array_key_exists('CSR',$_REQUEST)) $CSR=stripslashes($_REQUEST['CSR']);
35
36
37 if($oldid == "0")
38 {
39 if(array_key_exists('process',$_REQUEST) && $_REQUEST['process'] != "" && $CSR == "")
40 {
41 $_SESSION['_config']['errmsg'] = _("You failed to paste a valid GPG/PGP key.");
42 $id = $oldid;
43 $oldid=0;
44 }
45 }
46
47 $keyid="";
48
49 if(0)
50 {
51 if($_SESSION["profile"]["id"] != 5897)
52 {
53 showheader(_("Welcome to CAcert.org"));
54 echo "The OpenPGP signing system is currently shutdown due to a maintenance. We hope to get it fixed within the next few hours. We are very sorry for the inconvenience.";
55
56 exit(0);
57 }
58 }
59
60
61 function verifyName($name)
62 {
63 if($name == "") return 0;
64 if($name == $_SESSION['profile']['fname']." ".$_SESSION['profile']['lname']) return 1;
65 if($name == $_SESSION['profile']['fname']." ".$_SESSION['profile']['mname']." ".$_SESSION['profile']['lname']) return 1;
66 if($name == $_SESSION['profile']['fname']." ".$_SESSION['profile']['lname']." ".$_SESSION['profile']['suffix']) return 1;
67 if($name == $_SESSION['profile']['fname']." ".$_SESSION['profile']['mname']." ".$_SESSION['profile']['lname']." ".$_SESSION['profile']['suffix']) return 1;
68 return 0;
69
70 }
71
72 function verifyEmail($email)
73 {
74 if($email == "") return 0;
75 if(mysql_num_rows(mysql_query("select * from `email` where `memid`='".$_SESSION['profile']['id']."' and `email`='".mysql_real_escape_string($email)."' and `deleted`=0 and `hash`=''")) > 0) return 1;
76 return 0;
77 }
78
79
80
81 $ToBeDeleted=array();
82 $state=0;
83 if($oldid == "0" && $CSR != "")
84 {
85 $debugkey = $gpgkey = clean_csr($CSR);
86 $debugpg = $gpg = trim(`echo "$gpgkey"|gpg --with-colons --homedir /tmp 2>&1`);
87 $lines = "";
88 $gpgarr = explode("\n", $gpg);
89 foreach($gpgarr as $line)
90 {
91 #echo "Line[]: $line <br/>\n";
92 if(substr($line, 0, 3) == "pub" || substr($line, 0, 3) == "uid")
93 {
94 if($lines != "")
95 $lines .= "\n";
96 $lines .= $line;
97 }
98 }
99 $gpg = $lines;
100 $expires = 0;
101 $nerr=0; $nok=0;
102 $multiple = 0;
103
104 $resulttable=_("The following UIDs were found in your key:")."<br/><table border='1'><tr><td>#</td><td>"._("Name")."</td><td>"._("Email")."</td><td>Result</td>";
105 $i=0;
106 $lastvalidemail="";
107 foreach(explode("\n", $gpg) as $line)
108 {
109 $bits = explode(":", $line);
110 $resulttable.="<tr><td>".++$i."</td>";
111 $name = $comment = "";
112 if($bits[0] == "pub" && (!$keyid || !$when))
113 {
114 $keyid = $bits[4];
115 $when = $bits[5];
116 if($bits[6] != "")
117 $expires = 1;
118 }
119 $name="";
120 $comm="";
121 $mail="";
122 $uidformatwrong=0;
123
124 if(sizeof($bits)<10) $uidformatwrong=1;
125
126 if(preg_match("/\@.*\@/",$bits[9]))
127 {
128 showheader(_("Welcome to CAcert.org"));
129
130 echo "<font color='#ff0000'>"._("Multiple Email Adresses per UID are not allowed.")."</font>";
131 unset($_REQUEST['process']);
132 $id = $oldid;
133 unset($oldid);
134 exit();
135 }
136
137 // Name (Comment) <Email>
138 if(preg_match("/^([^\(\)\[@<>]+) \(([^\(\)@<>]*)\) <([\w=\/%.-]*\@[\w.-]*|[\w.-]*\![\w=\/%.-]*)>/",$bits[9],$matches))
139 {
140 $name=trim(hex2bin($matches[1]));
141 $nocomment=0;
142 $comm=trim(hex2bin($matches[2]));
143 $mail=trim(hex2bin($matches[3]));
144 }
145 // Name <EMail>
146 elseif(preg_match("/^([^\(\)\[@<>]+) <([\w=\/%.-]*\@[\w.-]*|[\w.-]*\![\w=\/%.-]*)>/",$bits[9],$matches))
147 {
148 $name=trim(hex2bin($matches[1]));
149 $nocomment=1;
150 $comm="";
151 $mail=trim(hex2bin($matches[2]));
152 }
153 // Unrecognized format
154 else
155 {
156 $nocomment=1;
157 $uidformatwrong=1;
158 }
159 $nameok=verifyName($name);
160 $emailok=verifyEmail($mail);
161
162
163 if($comm != "")
164 $comment[] = $comm;
165
166 $resulttable.="<td bgcolor='#".($nameok?"c0ffc0":"ffc0c0")."'>".sanitizeHTML($name)."</td>";
167 $resulttable.="<td bgcolor='#".($emailok?"c0ffc0":"ffc0c0")."'>".sanitizeHTML($mail)."</td>";
168
169 $uidok=0;
170 if($bits[1]=="r")
171 {
172 $rmessage=_("Error: UID is revoked");
173 }
174 elseif($uidformatwrong==1)
175 {
176 $rmessage=_("The format of the UID was not recognized. Please use 'Name (comment) &lt;email@domain>'");
177 }
178 elseif($mail=="" and $name=="")
179 {
180 $rmessage=_("Error: Both Name and Email address are empty");
181 }
182 elseif($emailok and $nameok)
183 {
184 $uidok=1;
185 $rmessage=_("Name and Email OK.");
186 }
187 elseif(!$emailok and !$nameok)
188 {
189 $rmessage=_("Name and Email both cannot be matched with your account.");
190 }
191 elseif($emailok and $name=="")
192 {
193 $uidok=1;
194 $rmessage=_("The email is OK. The name is empty.");
195 }
196 elseif($nameok and $mail=="")
197 {
198 $uidok=1;
199 $rmessage=_("The name is OK. The email is empty.");
200 }
201 elseif(!$emailok)
202 {
203 $rmessage=_("The email address has not been registered and verified in your account. Please add the email address to your account first.");
204 }
205 elseif(!$nameok)
206 {
207 $rmessage=_("The name in the UID does not match the name in your account. Please verify the name.");
208 }
209
210 else
211 {
212 $rmessage=_("Error");
213 }
214 if($uidok)
215 {
216 $nok++;
217 $resulttable.="<td>$rmessage</td>";
218 $lastvalidemail=$mail;
219 }
220 else
221 {
222 $nerr++;
223 //$ToBeDeleted[]=$i;
224 //echo "Adding UID $i\n";
225 $resulttable.="<td bgcolor='#ffc0c0'>$rmessage</td>";
226 }
227 $resulttable.="</tr>\n";
228
229 if($emailok) $multiple++;
230 }
231 $resulttable.="</table>";
232
233
234 if($nok==0)
235 {
236 showheader(_("Welcome to CAcert.org"));
237 echo $resulttable;
238
239 echo "<font color='#ff0000'>"._("No valid UIDs found on your key")."</font>";
240 unset($_REQUEST['process']);
241 $id = $oldid;
242 unset($oldid);
243 $do = `echo "$debugkey\n--\n$debugpg\n--" >> /www/tmp/gpg.debug`;
244 exit();
245 }
246 elseif($nerr)
247 {
248 $resulttable.=_("The unverified UIDs have been removed, the verified UIDs have been signed.");
249 }
250
251
252 }
253
254
255 if($oldid == "0" && $CSR != "")
256 {
257 $query = "insert into `gpg` set `memid`='".intval($_SESSION['profile']['id'])."',
258 `email`='".mysql_real_escape_string($lastvalidemail)."',
259 `level`='1',
260 `expires`='".mysql_real_escape_string($expires)."',
261 `multiple`='".mysql_real_escape_string($multiple)."',
262 `keyid`='".mysql_real_escape_string($keyid)."'";
263 mysql_query($query);
264 $id = mysql_insert_id();
265
266
267 $cwd = '/tmp/gpgspace'.$id;
268 mkdir($cwd,0755);
269
270 $fp = fopen("$cwd/gpg.csr", "w");
271 fputs($fp, clean_csr($CSR));
272 fclose($fp);
273
274
275 system("gpg --homedir $cwd --import $cwd/gpg.csr");
276
277
278 $debugpg = $gpg = trim(`gpg --homedir $cwd --with-colons --fixed-list-mode --list-keys $keyid 2>&1`);
279 $lines = "";
280 $gpgarr = explode("\n", $gpg);
281 foreach($gpgarr as $line)
282 {
283 //echo "Line[]: $line <br/>\n";
284 if(substr($line, 0, 4) == "uid:")
285 {
286 $name = $comment = "";
287 $bits = explode(":", $line);
288
289 $pos = strpos($bits[9], "(") - 1;
290 $nocomment = 0;
291 if($pos < 0)
292 {
293 $nocomment = 1;
294 $pos = strpos($bits[9], "<") - 1;
295 }
296 if($pos < 0)
297 {
298 $pos = strlen($bits[9]);
299 }
300
301 $name = trim(hex2bin(trim(substr($bits[9], 0, $pos))));
302 $nameok=verifyName($name);
303 if($nocomment == 0)
304 {
305 $pos += 2;
306 $pos2 = strpos($bits[9], ")");
307 $comm = trim(hex2bin(trim(substr($bits[9], $pos, $pos2 - $pos))));
308 if($comm != "")
309 $comment[] = $comm;
310 $pos = $pos2 + 3;
311 } else {
312 $pos = strpos($bits[9], "<") + 1;
313 }
314
315 $mail="";
316 if (preg_match("/<([\w.-]*\@[\w.-]*)>/", $bits[9],$match)) {
317 //echo "Found: ".$match[1];
318 $mail = trim(hex2bin($match[1]));
319 }
320 else
321 {
322 //echo "Not found!\n";
323 }
324
325 $emailok=verifyEmail($mail);
326
327 $uidid=$bits[7];
328
329 if($bits[1]=="r")
330 {
331 $ToBeDeleted[]=$uidid;
332 }
333 elseif($mail=="" and $name=="")
334 {
335 //echo "$uidid will be deleted\n";
336 $ToBeDeleted[]=$uidid;
337 }
338 elseif($emailok and $nameok)
339 {
340 }
341 elseif($emailok and $name=="")
342 {
343 }
344 elseif($nameok and $mail=="")
345 {
346 }
347 elseif(!$emailok and !$nameok)
348 {
349 //echo "$uidid will be deleted\n";
350 $ToBeDeleted[]=$uidid;
351 }
352 elseif(!$emailok)
353 {
354 //echo "$uidid will be deleted\n";
355 $ToBeDeleted[]=$uidid;
356 }
357 elseif(!$nameok)
358 {
359 //echo "$uidid will be deleted\n";
360 $ToBeDeleted[]=$uidid;
361 }
362
363 }
364 }
365
366
367
368
369 if(count($ToBeDeleted)>0)
370 {
371
372
373 $descriptorspec = array(
374 0 => array("pipe", "r"), // stdin is a pipe that the child will read from
375 1 => array("pipe", "w"), // stdout is a pipe that the child will write to
376 2 => array("pipe", "w") // stderr is a file to write to
377 );
378
379 $stderr = fopen('php://stderr', 'w');
380
381
382 //echo "Keyid: $keyid\n";
383
384 $process = proc_open("/usr/bin/gpg --homedir $cwd --no-tty --command-fd 0 --status-fd 1 --logger-fd 2 --edit-key $keyid", $descriptorspec, $pipes);
385
386 //echo "Process: $process\n";
387 //fputs($stderr,"Process: $process\n");
388
389 if (is_resource($process)) {
390 //echo("it is a resource\n");
391 // $pipes now looks like this:
392 // 0 => writeable handle connected to child stdin
393 // 1 => readable handle connected to child stdout
394 // Any error output will be appended to /tmp/error-output.txt
395 while (!feof($pipes[1]))
396 {
397 $buffer = fgets($pipes[1], 4096);
398 //echo $buffer;
399
400 if($buffer == "[GNUPG:] GET_BOOL keyedit.sign_all.okay\n")
401 {
402 fputs($pipes[0],"yes\n");
403 }
404 elseif($buffer == "[GNUPG:] GOT_IT\n")
405 {
406 }
407 elseif(ereg("^\[GNUPG:\] GET_BOOL keyedit\.remove\.uid\.okay\s*",$buffer))
408 {
409 fputs($pipes[0],"yes\n");
410 }
411 elseif(ereg("^\[GNUPG:\] GET_LINE keyedit\.prompt\s*",$buffer))
412 {
413 if(count($ToBeDeleted)>0)
414 {
415 $delthisuid=array_pop($ToBeDeleted);
416 //echo "Deleting an UID $delthisuid\n";
417 fputs($pipes[0],"uid ".$delthisuid."\n");
418 }
419 else
420 {
421 //echo "Saving\n";
422 fputs($pipes[0],$state?"save\n":"deluid\n");
423 $state++;
424 }
425 }
426 elseif($buffer == "[GNUPG:] GOOD_PASSPHRASE\n")
427 {
428 }
429 elseif(ereg("^\[GNUPG:\] KEYEXPIRED ",$buffer))
430 {
431 echo "Key expired!\n";
432 exit;
433 }
434 elseif($buffer == "")
435 {
436 //echo "Empty!\n";
437 }
438 else
439 {
440 echo "ERROR: UNKNOWN $buffer\n";
441 }
442
443
444 }
445 //echo "Fertig\n";
446 fclose($pipes[0]);
447
448 //echo stream_get_contents($pipes[1]);
449 fclose($pipes[1]);
450
451 // It is important that you close any pipes before calling
452 // proc_close in order to avoid a deadlock
453 $return_value = proc_close($process);
454
455 //echo "command returned $return_value\n";
456 }
457 else
458 {
459 echo "Keine ressource!\n";
460 }
461
462
463 }
464
465
466 $csrname=generatecertpath("csr","gpg",$id);
467 $do=`gpg --homedir $cwd --batch --export-options export-minimal --export $keyid >$csrname`;
468
469 mysql_query("update `gpg` set `csr`='$csrname' where `id`='$id'");
470 waitForResult('gpg', $id);
471
472 showheader(_("Welcome to CAcert.org"));
473 echo $resulttable;
474 $query = "select * from `gpg` where `id`='$id' and `crt`!=''";
475 $res = mysql_query($query);
476 if(mysql_num_rows($res) <= 0)
477 {
478 echo _("Your certificate request has failed to be processed correctly, please try submitting it again.")."<br>\n";
479 echo _("If this is a re-occuring problem, please send a copy of the key you are trying to signed to support@cacert.org. Thank you.");
480 } else {
481 echo "<pre>";
482 readfile(generatecertpath("crt","gpg",$id));
483 echo "</pre>";
484 }
485
486 showfooter();
487 exit;
488 }
489
490 $id = intval($id);
491
492 showheader(_("Welcome to CAcert.org"));
493 includeit($id, "gpg");
494 showfooter();
495 ?>