follow up to mantis bug #814
[cacert.git] / 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_gpgcsr($CSR);
86 #$debugpg = $gpg = trim(`echo "$gpgkey"|gpg --with-colons --homedir /tmp 2>&1`);
87
88 $tnam = tempnam('/tmp/', '__gpg');
89 $fp = fopen($tnam, 'w');
90 fwrite($fp, $gpgkey);
91 fclose($fp);
92 $debugpg = $gpg = trim(`gpg --with-colons --homedir /tmp 2>&1 < $tnam`);
93 unlink($tnam);
94
95 $lines = "";
96 $gpgarr = explode("\n", $gpg);
97 foreach($gpgarr as $line)
98 {
99 #echo "Line[]: $line <br/>\n";
100 if(substr($line, 0, 3) == "pub" || substr($line, 0, 3) == "uid")
101 {
102 if($lines != "")
103 $lines .= "\n";
104 $lines .= $line;
105 }
106 }
107 $gpg = $lines;
108 $expires = 0;
109 $nerr=0; $nok=0;
110 $multiple = 0;
111
112 $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>";
113 $i=0;
114 $lastvalidemail="";
115 $npubs=0;
116 foreach(explode("\n", $gpg) as $line)
117 {
118 $bits = explode(":", $line);
119 $resulttable.="<tr><td>".++$i."</td>";
120 $name = $comment = "";
121 if($bits[0] == "pub")
122 {
123 $npubs++;
124 }
125 if($npubs>1)
126 {
127 showheader(_("Welcome to CAcert.org"));
128 echo "<font color='#ff0000'>"._("Please upload only one key at a time.")."</font>";
129 unset($_REQUEST['process']);
130 $id = $oldid;
131 unset($oldid);
132 exit();
133 }
134 if($bits[0] == "pub" && (!$keyid || !$when))
135 {
136 $keyid = $bits[4];
137 $when = $bits[5];
138 if($bits[6] != "")
139 $expires = 1;
140 }
141 $name="";
142 $comm="";
143 $mail="";
144 $uidformatwrong=0;
145
146 if(sizeof($bits)<10) $uidformatwrong=1;
147
148 if(preg_match("/\@.*\@/",$bits[9]))
149 {
150 showheader(_("Welcome to CAcert.org"));
151
152 echo "<font color='#ff0000'>"._("Multiple Email Adresses per UID are not allowed.")."</font>";
153 unset($_REQUEST['process']);
154 $id = $oldid;
155 unset($oldid);
156 exit();
157 }
158
159 // Name (Comment) <Email>
160 if(preg_match("/^([^\(\)\[@<>]+) \(([^\(\)@<>]*)\) <([\w=\/%.-]*\@[\w.-]*|[\w.-]*\![\w=\/%.-]*)>/",$bits[9],$matches))
161 {
162 $name=trim(hex2bin($matches[1]));
163 $nocomment=0;
164 $comm=trim(hex2bin($matches[2]));
165 $mail=trim(hex2bin($matches[3]));
166 }
167 // Name <EMail>
168 elseif(preg_match("/^([^\(\)\[@<>]+) <([\w=\/%.-]*\@[\w.-]*|[\w.-]*\![\w=\/%.-]*)>/",$bits[9],$matches))
169 {
170 $name=trim(hex2bin($matches[1]));
171 $nocomment=1;
172 $comm="";
173 $mail=trim(hex2bin($matches[2]));
174 }
175 // Unrecognized format
176 else
177 {
178 $nocomment=1;
179 $uidformatwrong=1;
180 }
181 $nameok=verifyName($name);
182 $emailok=verifyEmail($mail);
183
184
185 if($comm != "")
186 $comment[] = $comm;
187
188 $resulttable.="<td bgcolor='#".($nameok?"c0ffc0":"ffc0c0")."'>".sanitizeHTML($name)."</td>";
189 $resulttable.="<td bgcolor='#".($emailok?"c0ffc0":"ffc0c0")."'>".sanitizeHTML($mail)."</td>";
190
191 $uidok=0;
192 if($bits[1]=="r")
193 {
194 $rmessage=_("Error: UID is revoked");
195 }
196 elseif($uidformatwrong==1)
197 {
198 $rmessage=_("The format of the UID was not recognized. Please use 'Name (comment) &lt;email@domain>'");
199 }
200 elseif($mail=="" and $name=="")
201 {
202 $rmessage=_("Error: Both Name and Email address are empty");
203 }
204 elseif($emailok and $nameok)
205 {
206 $uidok=1;
207 $rmessage=_("Name and Email OK.");
208 }
209 elseif(!$emailok and !$nameok)
210 {
211 $rmessage=_("Name and Email both cannot be matched with your account.");
212 }
213 elseif($emailok and $name=="")
214 {
215 $uidok=1;
216 $rmessage=_("The email is OK. The name is empty.");
217 }
218 elseif($nameok and $mail=="")
219 {
220 $uidok=1;
221 $rmessage=_("The name is OK. The email is empty.");
222 }
223 elseif(!$emailok)
224 {
225 $rmessage=_("The email address has not been registered and verified in your account. Please add the email address to your account first.");
226 }
227 elseif(!$nameok)
228 {
229 $rmessage=_("The name in the UID does not match the name in your account. Please verify the name.");
230 }
231
232 else
233 {
234 $rmessage=_("Error");
235 }
236 if($uidok)
237 {
238 $nok++;
239 $resulttable.="<td>$rmessage</td>";
240 $lastvalidemail=$mail;
241 }
242 else
243 {
244 $nerr++;
245 //$ToBeDeleted[]=$i;
246 //echo "Adding UID $i\n";
247 $resulttable.="<td bgcolor='#ffc0c0'>$rmessage</td>";
248 }
249 $resulttable.="</tr>\n";
250
251 if($emailok) $multiple++;
252 }
253 $resulttable.="</table>";
254
255
256 if($nok==0)
257 {
258 showheader(_("Welcome to CAcert.org"));
259 echo $resulttable;
260
261 echo "<font color='#ff0000'>"._("No valid UIDs found on your key")."</font>";
262 unset($_REQUEST['process']);
263 $id = $oldid;
264 unset($oldid);
265 $do = `echo "$debugkey\n--\n$debugpg\n--" >> /www/tmp/gpg.debug`;
266 exit();
267 }
268 elseif($nerr)
269 {
270 $resulttable.=_("The unverified UIDs have been removed, the verified UIDs have been signed.");
271 }
272
273
274 }
275
276
277 if($oldid == "0" && $CSR != "")
278 {
279 $query = "insert into `gpg` set `memid`='".intval($_SESSION['profile']['id'])."',
280 `email`='".mysql_real_escape_string($lastvalidemail)."',
281 `level`='1',
282 `expires`='".mysql_real_escape_string($expires)."',
283 `multiple`='".mysql_real_escape_string($multiple)."',
284 `keyid`='".mysql_real_escape_string($keyid)."'";
285 mysql_query($query);
286 $id = mysql_insert_id();
287
288
289 $cwd = '/tmp/gpgspace'.$id;
290 mkdir($cwd,0755);
291
292 $fp = fopen("$cwd/gpg.csr", "w");
293 fputs($fp, clean_gpgcsr($CSR));
294 fclose($fp);
295
296
297 system("gpg --homedir $cwd --import $cwd/gpg.csr");
298
299
300 $debugpg = $gpg = trim(`gpg --homedir $cwd --with-colons --fixed-list-mode --list-keys $keyid 2>&1`);
301 $lines = "";
302 $gpgarr = explode("\n", $gpg);
303 foreach($gpgarr as $line)
304 {
305 //echo "Line[]: $line <br/>\n";
306 if(substr($line, 0, 4) == "uid:")
307 {
308 $name = $comment = "";
309 $bits = explode(":", $line);
310
311 $pos = strpos($bits[9], "(") - 1;
312 $nocomment = 0;
313 if($pos < 0)
314 {
315 $nocomment = 1;
316 $pos = strpos($bits[9], "<") - 1;
317 }
318 if($pos < 0)
319 {
320 $pos = strlen($bits[9]);
321 }
322
323 $name = trim(hex2bin(trim(substr($bits[9], 0, $pos))));
324 $nameok=verifyName($name);
325 if($nocomment == 0)
326 {
327 $pos += 2;
328 $pos2 = strpos($bits[9], ")");
329 $comm = trim(hex2bin(trim(substr($bits[9], $pos, $pos2 - $pos))));
330 if($comm != "")
331 $comment[] = $comm;
332 $pos = $pos2 + 3;
333 } else {
334 $pos = strpos($bits[9], "<") + 1;
335 }
336
337 $mail="";
338 if (preg_match("/<([\w.-]*\@[\w.-]*)>/", $bits[9],$match)) {
339 //echo "Found: ".$match[1];
340 $mail = trim(hex2bin($match[1]));
341 }
342 else
343 {
344 //echo "Not found!\n";
345 }
346
347 $emailok=verifyEmail($mail);
348
349 $uidid=$bits[7];
350
351 if($bits[1]=="r")
352 {
353 $ToBeDeleted[]=$uidid;
354 }
355 elseif($mail=="" and $name=="")
356 {
357 //echo "$uidid will be deleted\n";
358 $ToBeDeleted[]=$uidid;
359 }
360 elseif($emailok and $nameok)
361 {
362 }
363 elseif($emailok and $name=="")
364 {
365 }
366 elseif($nameok and $mail=="")
367 {
368 }
369 elseif(!$emailok and !$nameok)
370 {
371 //echo "$uidid will be deleted\n";
372 $ToBeDeleted[]=$uidid;
373 }
374 elseif(!$emailok)
375 {
376 //echo "$uidid will be deleted\n";
377 $ToBeDeleted[]=$uidid;
378 }
379 elseif(!$nameok)
380 {
381 //echo "$uidid will be deleted\n";
382 $ToBeDeleted[]=$uidid;
383 }
384
385 }
386 }
387
388
389
390
391 if(count($ToBeDeleted)>0)
392 {
393
394
395 $descriptorspec = array(
396 0 => array("pipe", "r"), // stdin is a pipe that the child will read from
397 1 => array("pipe", "w"), // stdout is a pipe that the child will write to
398 2 => array("pipe", "w") // stderr is a file to write to
399 );
400
401 $stderr = fopen('php://stderr', 'w');
402
403
404 //echo "Keyid: $keyid\n";
405
406 $process = proc_open("/usr/bin/gpg --homedir $cwd --no-tty --command-fd 0 --status-fd 1 --logger-fd 2 --edit-key $keyid", $descriptorspec, $pipes);
407
408 //echo "Process: $process\n";
409 //fputs($stderr,"Process: $process\n");
410
411 if (is_resource($process)) {
412 //echo("it is a resource\n");
413 // $pipes now looks like this:
414 // 0 => writeable handle connected to child stdin
415 // 1 => readable handle connected to child stdout
416 // Any error output will be appended to /tmp/error-output.txt
417 while (!feof($pipes[1]))
418 {
419 $buffer = fgets($pipes[1], 4096);
420 //echo $buffer;
421
422 if($buffer == "[GNUPG:] GET_BOOL keyedit.sign_all.okay\n")
423 {
424 fputs($pipes[0],"yes\n");
425 }
426 elseif($buffer == "[GNUPG:] GOT_IT\n")
427 {
428 }
429 elseif(ereg("^\[GNUPG:\] GET_BOOL keyedit\.remove\.uid\.okay\s*",$buffer))
430 {
431 fputs($pipes[0],"yes\n");
432 }
433 elseif(ereg("^\[GNUPG:\] GET_LINE keyedit\.prompt\s*",$buffer))
434 {
435 if(count($ToBeDeleted)>0)
436 {
437 $delthisuid=array_pop($ToBeDeleted);
438 //echo "Deleting an UID $delthisuid\n";
439 fputs($pipes[0],"uid ".$delthisuid."\n");
440 }
441 else
442 {
443 //echo "Saving\n";
444 fputs($pipes[0],$state?"save\n":"deluid\n");
445 $state++;
446 }
447 }
448 elseif($buffer == "[GNUPG:] GOOD_PASSPHRASE\n")
449 {
450 }
451 elseif(ereg("^\[GNUPG:\] KEYEXPIRED ",$buffer))
452 {
453 echo "Key expired!\n";
454 exit;
455 }
456 elseif($buffer == "")
457 {
458 //echo "Empty!\n";
459 }
460 else
461 {
462 echo "ERROR: UNKNOWN $buffer\n";
463 }
464
465
466 }
467 //echo "Fertig\n";
468 fclose($pipes[0]);
469
470 //echo stream_get_contents($pipes[1]);
471 fclose($pipes[1]);
472
473 // It is important that you close any pipes before calling
474 // proc_close in order to avoid a deadlock
475 $return_value = proc_close($process);
476
477 //echo "command returned $return_value\n";
478 }
479 else
480 {
481 echo "Keine ressource!\n";
482 }
483
484
485 }
486
487
488 $csrname=generatecertpath("csr","gpg",$id);
489 $do=`gpg --homedir $cwd --batch --export-options export-minimal --export $keyid >$csrname`;
490
491 mysql_query("update `gpg` set `csr`='$csrname' where `id`='$id'");
492 waitForResult('gpg', $id);
493
494 showheader(_("Welcome to CAcert.org"));
495 echo $resulttable;
496 $query = "select * from `gpg` where `id`='$id' and `crt`!=''";
497 $res = mysql_query($query);
498 if(mysql_num_rows($res) <= 0)
499 {
500 echo _("Your certificate request has failed to be processed correctly, please try submitting it again.")."<br>\n";
501 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.");
502 } else {
503 echo "<pre>";
504 readfile(generatecertpath("crt","gpg",$id));
505 echo "</pre>";
506 }
507
508 showfooter();
509 exit;
510 }
511
512 $id = intval($id);
513
514 showheader(_("Welcome to CAcert.org"));
515 includeit($id, "gpg");
516 showfooter();
517 ?>