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