1#!/usr/bin/env php 2<?php 3/* 4 +-----------------------------------------------------------------------+ 5 | This file is part of the Roundcube Webmail client | 6 | | 7 | Copyright (C) The Roundcube Dev Team | 8 | Copyright (C) Kolab Systems AG | 9 | | 10 | Licensed under the GNU General Public License version 3 or | 11 | any later version with exceptions for skins & plugins. | 12 | See the README file for a full license statement. | 13 | | 14 | PURPOSE: | 15 | Import keys from Enigma's homedir into database for multihost | 16 | support. | 17 +-----------------------------------------------------------------------+ 18 | Author: Aleksander Machniak <alec@alec.pl> | 19 +-----------------------------------------------------------------------+ 20*/ 21 22define('INSTALL_PATH', realpath(__DIR__ . '/../../../') . '/'); 23 24require INSTALL_PATH . 'program/include/clisetup.php'; 25 26$rcmail = rcube::get_instance(); 27 28// get arguments 29$args = rcube_utils::get_opt([ 30 'u' => 'user', 31 'h' => 'host', 32 'd' => 'dir', 33 'x' => 'dry-run', 34]); 35 36if (!empty($_SERVER['argv'][1]) && $_SERVER['argv'][1] == 'help') { 37 print_usage(); 38 exit; 39} 40 41if (empty($args['dir'])) { 42 rcube::raise_error("--dir argument is required", true); 43} 44 45$host = get_host($args); 46$dirs = []; 47 48// Read the homedir and iterate over all subfolders (as users) 49if (empty($args['user'])) { 50 if ($dh = opendir($args['dir'])) { 51 while (($dir = readdir($dh)) !== false) { 52 if ($dir != '.' && $dir != '..') { 53 $dirs[$args['dir'] . '/' . $dir] = $dir; 54 } 55 } 56 closedir($dh); 57 } 58} 59// a single user 60else { 61 $dirs = [$args['dir'] => $args['user']]; 62} 63 64foreach ($dirs as $dir => $user) { 65 echo "Importing keys from $dir\n"; 66 67 if ($user_id = get_user_id($user, $host)) { 68 reset_state($user_id, !empty($args['dry-run'])); 69 import_dir($user_id, $dir, !empty($args['dry-run'])); 70 } 71} 72 73 74function print_usage() 75{ 76 print "Usage: import.sh [options]\n"; 77 print "Options:\n"; 78 print " --user=username User, if not set --dir subfolders will be iterated\n"; 79 print " --host=host The IMAP hostname or IP the given user is related to\n"; 80 print " --dir=path Location of the gpg homedir\n"; 81 print " --dry-run Do nothing, just list found user/files\n"; 82} 83 84function get_host($args) 85{ 86 global $rcmail; 87 88 if (empty($args['host'])) { 89 $hosts = $rcmail->config->get('default_host', ''); 90 if (is_string($hosts)) { 91 $args['host'] = $hosts; 92 } 93 else if (is_array($hosts) && count($hosts) == 1) { 94 $args['host'] = reset($hosts); 95 } 96 else { 97 rcube::raise_error("Specify a host name", true); 98 } 99 100 // host can be a URL like tls://192.168.12.44 101 $host_url = parse_url($args['host']); 102 if (!empty($host_url['host'])) { 103 $args['host'] = $host_url['host']; 104 } 105 } 106 107 return $args['host']; 108} 109 110function get_user_id($username, $host) 111{ 112 global $rcmail; 113 114 $db = $rcmail->get_dbh(); 115 116 // find user in local database 117 $user = rcube_user::query($username, $host); 118 119 if (empty($user)) { 120 rcube::raise_error("User does not exist: $username"); 121 } 122 123 return $user->ID; 124} 125 126function reset_state($user_id, $dry_run = false) 127{ 128 global $rcmail; 129 130 if ($dry_run) { 131 return; 132 } 133 134 $db = $rcmail->get_dbh(); 135 136 $db->query("DELETE FROM " . $db->table_name('filestore', true) 137 . " WHERE `user_id` = ? AND `context` = ?", 138 $user_id, 'enigma'); 139} 140 141function import_dir($user_id, $dir, $dry_run = false) 142{ 143 global $rcmail; 144 145 $db = $rcmail->get_dbh(); 146 $table = $db->table_name('filestore', true); 147 $db_files = ['pubring.gpg', 'secring.gpg', 'pubring.kbx']; 148 $maxsize = min($db->get_variable('max_allowed_packet', 1048500), 4*1024*1024) - 2000; 149 150 foreach (glob("$dir/private-keys-v1.d/*.key") as $file) { 151 $db_files[] = substr($file, strlen($dir) + 1); 152 } 153 154 foreach ($db_files as $file) { 155 if ($mtime = @filemtime("$dir/$file")) { 156 $data = file_get_contents("$dir/$file"); 157 $data = base64_encode($data); 158 $datasize = strlen($data); 159 160 if ($datasize > $maxsize) { 161 rcube::raise_error([ 162 'code' => 605, 'line' => __LINE__, 'file' => __FILE__, 163 'message' => "Enigma: Failed to save $file. Size exceeds max_allowed_packet." 164 ], true, false); 165 166 continue; 167 } 168 169 echo "* $file\n"; 170 171 if ($dry_run) { 172 continue; 173 } 174 175 $result = $db->query( 176 "INSERT INTO $table (`user_id`, `context`, `filename`, `mtime`, `data`)" 177 . " VALUES(?, 'enigma', ?, ?, ?)", 178 $user_id, $file, $mtime, $data); 179 180 if ($db->is_error($result)) { 181 rcube::raise_error([ 182 'code' => 605, 'line' => __LINE__, 'file' => __FILE__, 183 'message' => "Enigma: Failed to save $file into database." 184 ], true, false); 185 } 186 } 187 } 188} 189