| 1 |
<?php
|
| 2 |
// $Id$
|
| 3 |
|
| 4 |
//////////////////////////////////////////////////////////////////////////////
|
| 5 |
// Module settings
|
| 6 |
|
| 7 |
define('GNUPG_PATH', drupal_get_path('module', 'gnupg'));
|
| 8 |
define('GNUPG_HOMEDIR', variable_get('gnupg_homedir', GNUPG_PATH . '/.gnupg'));
|
| 9 |
define('GNUPG_KEYID', variable_get('gnupg_keyid', ''));
|
| 10 |
|
| 11 |
//////////////////////////////////////////////////////////////////////////////
|
| 12 |
// Core API hooks
|
| 13 |
|
| 14 |
/**
|
| 15 |
* Implementation of hook_perm().
|
| 16 |
*/
|
| 17 |
function gnupg_perm() {
|
| 18 |
return array('administer GnuPG configuration');
|
| 19 |
}
|
| 20 |
|
| 21 |
/**
|
| 22 |
* Implementation of hook_menu().
|
| 23 |
*/
|
| 24 |
function gnupg_menu() {
|
| 25 |
return array(
|
| 26 |
// Administer >> Site configuration >> Cryptography
|
| 27 |
'admin/settings/gnupg' => array(
|
| 28 |
'title' => 'Cryptography',
|
| 29 |
'description' => 'Settings for GNU Privacy Guard cryptography.',
|
| 30 |
'access arguments' => array('administer GnuPG configuration'),
|
| 31 |
'page callback' => 'drupal_get_form',
|
| 32 |
'page arguments' => array('gnupg_admin_settings'),
|
| 33 |
'file' => 'gnupg.admin.inc',
|
| 34 |
),
|
| 35 |
// Administer >> User management >> Public keys
|
| 36 |
'admin/user/gnupg' => array(
|
| 37 |
'title' => 'Public keys',
|
| 38 |
'description' => 'Manage the OpenPGP public keys for your users.',
|
| 39 |
'access arguments' => array('administer users'),
|
| 40 |
'page callback' => 'gnupg_admin_users',
|
| 41 |
'file' => 'gnupg.admin.inc',
|
| 42 |
),
|
| 43 |
// User profiles >> Public key
|
| 44 |
'user/%user/public-key' => array(
|
| 45 |
'title' => 'Public key',
|
| 46 |
'type' => MENU_LOCAL_TASK,
|
| 47 |
'access callback' => 'gnupg_user_page_access',
|
| 48 |
'access arguments' => array(1),
|
| 49 |
'page callback' => 'gnupg_user_page',
|
| 50 |
'page arguments' => array(1),
|
| 51 |
'weight' => 3,
|
| 52 |
),
|
| 53 |
);
|
| 54 |
}
|
| 55 |
|
| 56 |
/**
|
| 57 |
* Implementation of hook_cron().
|
| 58 |
*/
|
| 59 |
function gnupg_cron() {
|
| 60 |
$keys = db_query("SELECT uri, key_id AS id, key_data AS data FROM {gnupg_keys} WHERE key_id IS NULL ORDER BY timestamp ASC");
|
| 61 |
while ($key = db_fetch_object($keys)) {
|
| 62 |
if (($key->id = gnupg_import_key($key->data))) {
|
| 63 |
db_query("UPDATE {gnupg_keys} SET key_id = '%s' WHERE uri = '%s'", $key->id, $key->uri);
|
| 64 |
}
|
| 65 |
else {
|
| 66 |
watchdog('gnupg', 'Failed to import public key for !link into pubring.gpg.', array('!link' => l($key->uri, $key->uri)), WATCHDOG_ERROR); // TODO: improve this error message.
|
| 67 |
}
|
| 68 |
}
|
| 69 |
}
|
| 70 |
|
| 71 |
//////////////////////////////////////////////////////////////////////////////
|
| 72 |
// User API hooks
|
| 73 |
|
| 74 |
/**
|
| 75 |
* Implementation of hook_user().
|
| 76 |
*/
|
| 77 |
function gnupg_user($op, &$edit, &$account, $category = NULL) {
|
| 78 |
switch ($op) {
|
| 79 |
case 'categories':
|
| 80 |
return array(array('name' => 'gnupg', 'title' => t('Cryptography'), 'weight' => 10));
|
| 81 |
|
| 82 |
case 'load':
|
| 83 |
$edit['gnupg_key_id'] = $account->gnupg_key_id = gnupg_get_user_key_id($account->uid);
|
| 84 |
break;
|
| 85 |
|
| 86 |
case 'form':
|
| 87 |
switch ($category) {
|
| 88 |
case 'gnupg':
|
| 89 |
$form['gnupg'] = array('#type' => 'fieldset', '#title' => t('OpenPGP public key'), '#weight' => -10);
|
| 90 |
$form['gnupg']['gnupg_key'] = array(
|
| 91 |
'#type' => 'textarea',
|
| 92 |
'#title' => t('Public key'),
|
| 93 |
'#default_value' => isset($edit['gnupg_key']) ? $edit['gnupg_key'] : gnupg_get_user_key_data($account->uid),
|
| 94 |
'#description' => t('Your public key can be used to, for example, securely e-mail you.'),
|
| 95 |
'#rows' => 12,
|
| 96 |
);
|
| 97 |
|
| 98 |
$form['gnupg']['gnupg_display_key'] = array(
|
| 99 |
'#type' => 'checkbox',
|
| 100 |
'#title' => t('Display my public key on my user profile'),
|
| 101 |
'#default_value' => isset($edit['gnupg_display_key']) ? $edit['gnupg_display_key'] : 1,
|
| 102 |
'#description' => t(''), // TODO
|
| 103 |
);
|
| 104 |
|
| 105 |
if (variable_get('gnupg_mail_encrypt', '') != '') {
|
| 106 |
$form['gnupg']['gnupg_encrypt_mail'] = array(
|
| 107 |
'#type' => 'checkbox',
|
| 108 |
'#title' => t('Encrypt e-mail sent to me (when possible)'),
|
| 109 |
'#default_value' => isset($edit['gnupg_encrypt_mail']) ? $edit['gnupg_encrypt_mail'] : 1,
|
| 110 |
'#description' => t(''), // TODO
|
| 111 |
);
|
| 112 |
if (variable_get('gnupg_mail_encrypt', '') == 'always') {
|
| 113 |
$form['gnupg']['gnupg_encrypt_mail']['#disabled'] = 'disabled';
|
| 114 |
$form['gnupg']['gnupg_encrypt_mail']['#default_value'] = 1;
|
| 115 |
}
|
| 116 |
}
|
| 117 |
return $form;
|
| 118 |
}
|
| 119 |
break;
|
| 120 |
|
| 121 |
case 'validate':
|
| 122 |
if (!empty($edit['gnupg_key'])) {
|
| 123 |
if (strpos($edit['gnupg_key'], '-----BEGIN PGP PUBLIC KEY BLOCK-----') === FALSE ||
|
| 124 |
strpos($edit['gnupg_key'], '-----END PGP PUBLIC KEY BLOCK-----') === FALSE) {
|
| 125 |
form_set_error('gnupg_key', t('Invalid OpenPGP public key. You must paste in an ASCII-armored key block that begins with a <tt>BEGIN PGP PUBLIC KEY BLOCK</tt> marker and ends with a <tt>END PGP PUBLIC KEY BLOCK</tt> marker. Provided you have the GNU Privacy Guard installed on your computer, you can obtain this key by executing the terminal command <tt>gpg --export --armor your.email@example.com</tt>. For other OpenPGP-compatible software such as the commercial PGP suite, please refer to the user documentation provided by the vendor.'));
|
| 126 |
}
|
| 127 |
}
|
| 128 |
break;
|
| 129 |
|
| 130 |
case 'insert':
|
| 131 |
case 'update':
|
| 132 |
gnupg_del_user_key($account->uid);
|
| 133 |
if (!empty($edit['gnupg_key']) && ($key_data = trim($edit['gnupg_key']))) {
|
| 134 |
gnupg_set_user_key($account->uid, $key_data);
|
| 135 |
}
|
| 136 |
$edit['gnupg_key'] = NULL;
|
| 137 |
break;
|
| 138 |
|
| 139 |
case 'delete':
|
| 140 |
gnupg_del_user_key($account->uid);
|
| 141 |
break;
|
| 142 |
}
|
| 143 |
}
|
| 144 |
|
| 145 |
//////////////////////////////////////////////////////////////////////////////
|
| 146 |
// Mail API hooks
|
| 147 |
|
| 148 |
/**
|
| 149 |
* Implementation of hook_mail_alter().
|
| 150 |
*/
|
| 151 |
function gnupg_mail_alter(&$message) {
|
| 152 |
if (($encrypt = variable_get('gnupg_mail_encrypt', '')) != '') {
|
| 153 |
if (is_object($account = $message['params']['recipient'])) {
|
| 154 |
|
| 155 |
if ($encrypt == 'always' || !empty($account->gnupg_encrypt_mail)) {
|
| 156 |
if (($key_id = gnupg_get_user_key_id($account->uid))) {
|
| 157 |
|
| 158 |
$options = ($comment = variable_get('gnupg_mail_comment', '')) ? array('comment' => $comment) : array();
|
| 159 |
if (($ciphertext = gnupg_encrypt(implode("\n\n", $message['body']), $key_id, $options))) {
|
| 160 |
$message['body'] = $ciphertext;
|
| 161 |
|
| 162 |
if (($header = variable_get('gnupg_mail_header', ''))) {
|
| 163 |
$message['body'] = $header . "\n\n" . $message['body'];
|
| 164 |
}
|
| 165 |
|
| 166 |
if (($footer = variable_get('gnupg_mail_footer', ''))) {
|
| 167 |
$message['body'] .= "\n" . $footer;
|
| 168 |
}
|
| 169 |
}
|
| 170 |
}
|
| 171 |
}
|
| 172 |
}
|
| 173 |
}
|
| 174 |
}
|
| 175 |
|
| 176 |
//////////////////////////////////////////////////////////////////////////////
|
| 177 |
// GnuPG API implementation
|
| 178 |
|
| 179 |
function gnupg_get_user_key($uid) {
|
| 180 |
return ($key = db_fetch_object(db_query("SELECT key_id AS id, key_data AS data FROM {gnupg_keys} WHERE uri = '%s'", 'user/' . $uid))) ? $key : NULL;
|
| 181 |
}
|
| 182 |
|
| 183 |
function gnupg_get_user_key_id($uid) {
|
| 184 |
return ($key = gnupg_get_user_key($uid)) ? $key->id : NULL;
|
| 185 |
}
|
| 186 |
|
| 187 |
function gnupg_get_user_key_data($uid) {
|
| 188 |
return ($key = gnupg_get_user_key($uid)) ? $key->data : NULL;
|
| 189 |
}
|
| 190 |
|
| 191 |
function gnupg_set_user_key($uid, $key_data, $key_id = NULL) {
|
| 192 |
$key_id = $key_id ? $key_id : gnupg_import_key($key_data);
|
| 193 |
if (!$key_id) {
|
| 194 |
db_query("INSERT INTO {gnupg_keys} (uri, timestamp, key_id, key_data) VALUES ('%s', %d, NULL, '%s')", 'user/' . $uid, time(), $key_data);
|
| 195 |
}
|
| 196 |
else {
|
| 197 |
db_query("INSERT INTO {gnupg_keys} (uri, timestamp, key_id, key_data) VALUES ('%s', %d, '%s', '%s')", 'user/' . $uid, time(), $key_id, $key_data);
|
| 198 |
}
|
| 199 |
}
|
| 200 |
|
| 201 |
function gnupg_del_user_key($uid) {
|
| 202 |
if (($key_id = gnupg_get_user_key_id($uid))) {
|
| 203 |
gnupg_delete_key($key_id); // also delete key from pubring.gpg
|
| 204 |
}
|
| 205 |
db_query("DELETE FROM {gnupg_keys} WHERE uri = '%s'", 'user/' . $uid);
|
| 206 |
}
|
| 207 |
|
| 208 |
/**
|
| 209 |
* Returns TRUE if GnuPG is installed and the GnuPG module has been
|
| 210 |
* correctly configured.
|
| 211 |
*/
|
| 212 |
function gnupg_is_available() {
|
| 213 |
return is_dir(GNUPG_HOMEDIR) && is_executable(variable_get('gnupg_exec', gnupg_guess_binpath()));
|
| 214 |
}
|
| 215 |
|
| 216 |
/**
|
| 217 |
* Returns the GnuPG version number.
|
| 218 |
*/
|
| 219 |
function gnupg_version() {
|
| 220 |
if (($output = gnupg_exec(array('version' => TRUE))) && !empty($output)) {
|
| 221 |
if (preg_match('!^gpg \(GnuPG\) (.*)$!', $output[0], $matches)) {
|
| 222 |
return $matches[1];
|
| 223 |
}
|
| 224 |
}
|
| 225 |
}
|
| 226 |
|
| 227 |
/**
|
| 228 |
* Returns the record types used in GnuPG's key listings.
|
| 229 |
*/
|
| 230 |
function gnupg_get_record_types() {
|
| 231 |
static $types = array('pub', 'crt', 'crs', 'sub', 'sec', 'ssb', 'uid', 'uat', 'sig', 'rev', 'fpr', 'pkd', 'grp', 'rvk', 'tru', 'spk');
|
| 232 |
return array_combine($types, $types);
|
| 233 |
}
|
| 234 |
|
| 235 |
/**
|
| 236 |
* Returns the key algorithms supported by GnuPG.
|
| 237 |
*/
|
| 238 |
function gnupg_get_key_algorithms() {
|
| 239 |
return array(1 => t('RSA'), 16 => t('ElGamal (encrypt)'), 17 => t('DSA (sign)'), 20 => t('ElGamal (sign/encrypt)'));
|
| 240 |
}
|
| 241 |
|
| 242 |
/**
|
| 243 |
* Returns an array of key IDs/titles of the keys in the public keyring.
|
| 244 |
*/
|
| 245 |
function gnupg_get_keys($op = 'titles', $key_id = '') {
|
| 246 |
static $columns = array('type', 'validity', 'length', 'algorithm', 'id', 'created_at', 'expires_at', 'local_id', 'trust', 'user_id', 'signature_class', 'capabilities', '..');
|
| 247 |
|
| 248 |
$keys = array();
|
| 249 |
if (($output = gnupg_exec(array('list-public-keys' => TRUE, 'with-colons' => TRUE, $key_id))) && is_array($output)) {
|
| 250 |
foreach ($output as $key) {
|
| 251 |
$key = explode(':', $key);
|
| 252 |
if ($key[0] == 'pub') { // public keys only
|
| 253 |
$key = (object)array_combine($columns, $key);
|
| 254 |
$keys[$key->id] = ($op == 'titles' ? (substr($key->id, -8) . ' ' . $key->user_id . ' (' . $key->created_at . ')') : $key);
|
| 255 |
}
|
| 256 |
}
|
| 257 |
}
|
| 258 |
return $keys;
|
| 259 |
}
|
| 260 |
|
| 261 |
function gnupg_delete_key($key_id, array $options = array()) {
|
| 262 |
// TODO
|
| 263 |
}
|
| 264 |
|
| 265 |
function gnupg_export_key($key_id, array $options = array()) {
|
| 266 |
if (($output = gnupg_exec(array('armor' => TRUE, 'export' => $key_id))) && !empty($output)) {
|
| 267 |
return implode("\n", $output);
|
| 268 |
}
|
| 269 |
}
|
| 270 |
|
| 271 |
function gnupg_import_key($key_data, array $options = array()) {
|
| 272 |
if (($key_ids = gnupg_import_keys($key_data, $options)) && is_array($key_ids) && !empty($key_ids)) {
|
| 273 |
list($key_id) = array_keys($key_ids);
|
| 274 |
return $key_id;
|
| 275 |
}
|
| 276 |
}
|
| 277 |
|
| 278 |
function gnupg_import_keys($key_data, array $options = array()) {
|
| 279 |
$options = array_merge(array('quiet' => FALSE, 'import' => TRUE), $options);
|
| 280 |
if (($process = gnupg_exec($options, TRUE, $pipes)) && is_resource($process)) {
|
| 281 |
list($stdin, $stdout, $stderr) = $pipes;
|
| 282 |
|
| 283 |
foreach (!is_array($key_data) ? array($key_data) : $key_data as $key_text) {
|
| 284 |
fwrite($stdin, $key_text);
|
| 285 |
fwrite($stdin, "\n");
|
| 286 |
}
|
| 287 |
fclose($stdin);
|
| 288 |
$out = stream_get_contents($stdout);
|
| 289 |
fclose($stdout);
|
| 290 |
$err = stream_get_contents($stderr);
|
| 291 |
fclose($stderr);
|
| 292 |
|
| 293 |
if (($result = proc_close($process)) === 0) {
|
| 294 |
$key_ids = array();
|
| 295 |
foreach (explode("\n", $err) as $line) {
|
| 296 |
if (preg_match('/^\w+: key ([0-9A-Fa-f]+):[^"]+"([^"]*)"/', $err, $match)) {
|
| 297 |
list(, $key_id, $user_id) = $match;
|
| 298 |
|
| 299 |
// Attempt to expand the returned 64-bit key IDs to the full key fingerprints:
|
| 300 |
if (($keys = gnupg_get_keys(NULL, $key_id))) {
|
| 301 |
foreach ($keys as $key_fp => $key) {
|
| 302 |
if ((strpos($key_fp, $key_id) === strlen($key_fp) - strlen($key_id)) && $key->user_id == $user_id) {
|
| 303 |
$key_id = $key_fp;
|
| 304 |
break;
|
| 305 |
}
|
| 306 |
}
|
| 307 |
}
|
| 308 |
|
| 309 |
$key_ids[$key_id] = $user_id;
|
| 310 |
}
|
| 311 |
}
|
| 312 |
return $key_ids;
|
| 313 |
}
|
| 314 |
|
| 315 |
return FALSE;
|
| 316 |
}
|
| 317 |
}
|
| 318 |
|
| 319 |
/**
|
| 320 |
* Encrypts the given plaintext using the specified public key ID(s).
|
| 321 |
*/
|
| 322 |
function gnupg_encrypt($plaintext, $key_id = GNUPG_KEYID, array $options = array()) {
|
| 323 |
if (!gnupg_is_available()) {
|
| 324 |
return FALSE;
|
| 325 |
}
|
| 326 |
|
| 327 |
// Our trust database is not going to be much use, so tell GnuPG to
|
| 328 |
// always trust. The way to do this changed around version 1.2.3.
|
| 329 |
$options = array_merge(version_compare(gnupg_version(), '1.2.3', '<') ? array('always-trust' => TRUE) : array('trust-model' => 'always'), $options);
|
| 330 |
|
| 331 |
// Encrypt for one or multiple recipients:
|
| 332 |
if ($key_id) {
|
| 333 |
$options['recipient'] = $key_id;
|
| 334 |
}
|
| 335 |
|
| 336 |
$options = array_merge(array('armor' => TRUE, 'encrypt' => TRUE), $options);
|
| 337 |
if (($process = gnupg_exec($options, TRUE, $pipes)) && is_resource($process)) {
|
| 338 |
list($stdin, $stdout, $stderr) = $pipes;
|
| 339 |
|
| 340 |
fwrite($stdin, $plaintext);
|
| 341 |
fclose($stdin);
|
| 342 |
$ciphertext = stream_get_contents($stdout);
|
| 343 |
fclose($stdout);
|
| 344 |
$GLOBALS['gnupg_output'] = stream_get_contents($stderr);
|
| 345 |
fclose($stderr);
|
| 346 |
|
| 347 |
$result = proc_close($process);
|
| 348 |
return $result === 0 ? $ciphertext : FALSE;
|
| 349 |
}
|
| 350 |
}
|
| 351 |
|
| 352 |
/**
|
| 353 |
* Decrypts the given ciphertext using the specified key ID.
|
| 354 |
*/
|
| 355 |
function gnupg_decrypt($ciphertext, $key_id = GNUPG_KEYID, array $options = array()) {
|
| 356 |
if (!gnupg_is_available()) {
|
| 357 |
return FALSE;
|
| 358 |
}
|
| 359 |
|
| 360 |
$options = array_merge(array('armor' => TRUE, 'decrypt' => TRUE), $options);
|
| 361 |
if (($process = gnupg_exec($options, TRUE, $pipes)) && is_resource($process)) {
|
| 362 |
list($stdin, $stdout, $stderr) = $pipes;
|
| 363 |
|
| 364 |
fwrite($stdin, $ciphertext);
|
| 365 |
fclose($stdin);
|
| 366 |
$plaintext = stream_get_contents($stdout);
|
| 367 |
fclose($stdout);
|
| 368 |
$GLOBALS['gnupg_output'] = stream_get_contents($stderr);
|
| 369 |
fclose($stderr);
|
| 370 |
|
| 371 |
$result = proc_close($process);
|
| 372 |
return $result === 0 ? $plaintext : FALSE;
|
| 373 |
}
|
| 374 |
}
|
| 375 |
|
| 376 |
//////////////////////////////////////////////////////////////////////////////
|
| 377 |
// GnuPG API internals
|
| 378 |
|
| 379 |
/**
|
| 380 |
* Invokes the 'gpg' executable using exec()/proc_open().
|
| 381 |
*/
|
| 382 |
function gnupg_exec(array $options, $proc_open = FALSE, array &$pipes = NULL) {
|
| 383 |
$options = array_merge(array('no-verbose' => TRUE, 'batch' => TRUE, 'quiet' => TRUE, 'no-permission-warning' => TRUE, 'homedir' => GNUPG_HOMEDIR), $options);
|
| 384 |
|
| 385 |
if (!is_writable(GNUPG_HOMEDIR)) {
|
| 386 |
$options['no-random-seed-file'] = TRUE; // prevent the need to write .gnupg/random_seed
|
| 387 |
}
|
| 388 |
|
| 389 |
// Assemble the full command line to be invoked:
|
| 390 |
$command = variable_get('gnupg_exec', gnupg_guess_binpath());
|
| 391 |
foreach ($options as $k => $vs) {
|
| 392 |
foreach (is_array($vs) ? $vs : array($vs) as $v) {
|
| 393 |
if ($v !== FALSE) {
|
| 394 |
$command .= !is_numeric($k) ?
|
| 395 |
' --'. $k . ($v === TRUE ? '' : ' ' . escapeshellarg((string)$v)) :
|
| 396 |
' ' . escapeshellarg((string)$v);
|
| 397 |
}
|
| 398 |
}
|
| 399 |
}
|
| 400 |
$arguments = array_slice(func_get_args(), 3);
|
| 401 |
$command = trim($command .' '. implode(' ', array_map('escapeshellarg', $arguments)));
|
| 402 |
|
| 403 |
unset($GLOBALS['gnupg_output']);
|
| 404 |
if (!$proc_open) {
|
| 405 |
exec($command, $output, $result);
|
| 406 |
$GLOBALS['gnupg_output'] = implode("\n", $output);
|
| 407 |
return $result === 0 ? $output : FALSE;
|
| 408 |
}
|
| 409 |
else {
|
| 410 |
return proc_open($command, array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
|
| 411 |
}
|
| 412 |
}
|
| 413 |
|
| 414 |
/**
|
| 415 |
* Attempts to locate the 'gpg' binary in $PATH and, failing that, in
|
| 416 |
* various well-known locations.
|
| 417 |
*/
|
| 418 |
function gnupg_guess_binpath($binary = 'gpg') {
|
| 419 |
if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
|
| 420 |
return $binary; // let's not even go there
|
| 421 |
}
|
| 422 |
else {
|
| 423 |
$path = exec('type -P '. escapeshellarg($binary), $output, $result);
|
| 424 |
if ($result === 0) {
|
| 425 |
return $path;
|
| 426 |
}
|
| 427 |
else {
|
| 428 |
foreach (array('/opt/local/bin', '/usr/bin', '/usr/local/bin') as $location) {
|
| 429 |
if (@is_executable($path = $location . '/' . $binary)) {
|
| 430 |
return $path;
|
| 431 |
}
|
| 432 |
}
|
| 433 |
return $binary;
|
| 434 |
}
|
| 435 |
}
|
| 436 |
}
|
| 437 |
|
| 438 |
/**
|
| 439 |
* Attempts to make secure the GnuPG home directory by setting access
|
| 440 |
* permissions and writing a .htaccess file.
|
| 441 |
*/
|
| 442 |
function gnupg_secure_homedir($directory = GNUPG_HOMEDIR, $form_item = NULL) {
|
| 443 |
// Check if the directory exists, and attempt to automatically create if it doesn't:
|
| 444 |
if (!is_dir($directory)) {
|
| 445 |
if (@mkdir($directory)) {
|
| 446 |
drupal_set_message(t('The GnuPG home directory %directory has been created.', array('%directory' => $directory)));
|
| 447 |
}
|
| 448 |
else {
|
| 449 |
if ($form_item) {
|
| 450 |
form_set_error($form_item, t('The GnuPG home directory %directory does not exist and could not be created.', array('%directory' => $directory)));
|
| 451 |
}
|
| 452 |
return FALSE;
|
| 453 |
}
|
| 454 |
}
|
| 455 |
|
| 456 |
// Prevent world-readability of the directory, if possible:
|
| 457 |
if (!@chmod($directory, 0770)) { // TODO: should probably shell out to 'chmod' to just do an 'o-rwx'
|
| 458 |
$warning = "Security warning: Couldn't set access permissions on the GnuPG home directory %directory. Please secure it manually to prevent access by any other user than the web server process.";
|
| 459 |
drupal_set_message(t($warning, array('%directory' => $directory)), 'warning');
|
| 460 |
watchdog('security', $warning, array('%directory' => $directory), WATCHDOG_WARNING);
|
| 461 |
}
|
| 462 |
|
| 463 |
// Check if the directory is writable. Since GnuPG is executed using our
|
| 464 |
// uid, things will fail if GnuPG can't create the keyring files. On the
|
| 465 |
// other hand, the necessary files may already exist and the administrator
|
| 466 |
// has simply decided to be cautious and let the web server process have
|
| 467 |
// only read access to the directory. This would not be a show-stopper,
|
| 468 |
// and simply means showing an unnecessary warning.
|
| 469 |
if (!is_writable($directory)) {
|
| 470 |
$warning = "Security notice: The GnuPG home directory %directory is not writable by the web server process. Unless all the keyring files required by GnuPG already exist, this may prevent some GnuPG API operations from functioning correctly.";
|
| 471 |
drupal_set_message(t($warning, array('%directory' => $directory)), 'warning');
|
| 472 |
}
|
| 473 |
|
| 474 |
// Attempt to create a .htaccess file to prevent any web access to the
|
| 475 |
// directory. Any prudent administrator will have placed the GnuPG home
|
| 476 |
// directory outside the web root, in which case this isn't necessary and
|
| 477 |
// may produce an unnecessary warning. However, to every savvy user
|
| 478 |
// there will be a correspondingly larger number of careless ones.
|
| 479 |
if (!is_file($directory .'/.htaccess')) {
|
| 480 |
$htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove\nOptions None\nOptions +FollowSymLinks\nDeny from all\n";
|
| 481 |
if (is_writable($directory) && @file_put_contents($directory .'/.htaccess', $htaccess_lines) > 0) {
|
| 482 |
@chmod($directory .'/.htaccess', 0660);
|
| 483 |
}
|
| 484 |
else {
|
| 485 |
$warning = "Security warning: Couldn't write a <code>.htaccess</code> file in the GnuPG home directory. Please create a %htaccess file with the following contents: <code>!htaccess</code>";
|
| 486 |
$variables = array('%directory' => $directory, '%htaccess' => $directory .'/.htaccess', '!htaccess' => '<br/>'. nl2br(check_plain($htaccess_lines)));
|
| 487 |
drupal_set_message(t($warning, $variables), 'warning');
|
| 488 |
watchdog('security', $warning, $variables, WATCHDOG_WARNING);
|
| 489 |
}
|
| 490 |
}
|
| 491 |
|
| 492 |
return TRUE;
|
| 493 |
}
|
| 494 |
|
| 495 |
//////////////////////////////////////////////////////////////////////////////
|
| 496 |
// Menu callbacks
|
| 497 |
|
| 498 |
function gnupg_user_page_access($account) {
|
| 499 |
return user_access('access user profiles') && !empty($account->gnupg_display_key) && gnupg_get_user_key_data($account->uid);
|
| 500 |
}
|
| 501 |
|
| 502 |
function gnupg_user_page($account) {
|
| 503 |
drupal_set_title(t("@name's public key", array('@name' => $account->name)));
|
| 504 |
return '<div class="gnupg public-key"><pre>' . gnupg_get_user_key_data($account->uid) . '</pre></div>';
|
| 505 |
}
|