Index: trunk/extensions/OpenStackManager/special/SpecialNovaKey.php |
— | — | @@ -180,7 +180,90 @@ |
181 | 181 | |
182 | 182 | $this->getOutput()->addHTML( $out ); |
183 | 183 | } |
| 184 | + |
| 185 | + /** |
| 186 | + * Converts a public ssh key to openssh format, using puttygen. |
| 187 | + * @param $keydata SSH public/private key in some format |
| 188 | + * @return mixed Public key in openssh format or false |
| 189 | + */ |
| 190 | + static function opensshFormatKey($keydata) { |
| 191 | + global $wgPuttygen; |
| 192 | + if ( wfIsWindows() || !$wgPuttygen ) |
| 193 | + return false; |
| 194 | + |
| 195 | + // We need to store the key in a file, as puttygen opens it several times. |
| 196 | + $tmpfile = tmpfile(); |
| 197 | + if (!$tmpfile) |
| 198 | + return false; |
| 199 | + |
| 200 | + fwrite( $tmpfile, $keydata ); |
| 201 | + |
| 202 | + $descriptorspec = array( |
| 203 | + 0 => $tmpfile, |
| 204 | + 1 => array("pipe", "w"), |
| 205 | + 2 => array("file", wfGetNull(), "a") |
| 206 | + ); |
| 207 | + |
| 208 | + $process = proc_open( escapeshellcmd( $wgPuttygen ) . ' -O public-openssh -o /dev/stdout /dev/stdin', $descriptorspec, $pipes ); |
| 209 | + if ( $process === false ) |
| 210 | + return false; |
| 211 | + |
| 212 | + $data = stream_get_contents( $pipes[1] ); |
| 213 | + fclose( $pipes[1] ); |
| 214 | + proc_close( $process ); |
| 215 | + |
| 216 | + /* Overwrite the file with nulls, padded to the next 4KB boundary. |
| 217 | + * This shouldn't be needed, as it is a public key material, and |
| 218 | + * it's going to be stored in a place from which it's probably |
| 219 | + * easier to retrieve than a deleted file. |
| 220 | + * However, there's no reason to have it innecesary copies, in |
| 221 | + * some cases (certain DSA keys) the private key can be extracted |
| 222 | + * from public one, and there could be worse attacks in the future. |
| 223 | + * Moreover, if someone provided the private key to Special:NovaKey, |
| 224 | + * this function would strip it to the public part, but we'd still |
| 225 | + * need not to keep such information we should have never been given. |
| 226 | + */ |
| 227 | + rewind( $tmpfile ); |
| 228 | + fwrite( $tmpfile, str_repeat( "\0", strlen( $keydata ) + 4096 - strlen( $keydata ) % 4096 ) ); |
| 229 | + fclose( $tmpfile ); |
| 230 | + |
| 231 | + if ( $data === false || !preg_match( '/(^| )ssh-(rsa|dss) /', $data ) ) |
| 232 | + return false; |
| 233 | + |
| 234 | + return $data; |
| 235 | + } |
184 | 236 | |
| 237 | + /* |
| 238 | + // This alternative function uses only pipes, but doesn't work due to puttygen opening the input file several times. |
| 239 | + static function opensshFormatKey($keydata) { |
| 240 | + global $wgPuttygen; |
| 241 | + if ( wfIsWindows() || !$wgPuttygen ) |
| 242 | + return false; |
| 243 | + |
| 244 | + $descriptorspec = array( |
| 245 | + 0 => array("pipe", "r"), |
| 246 | + 1 => array("pipe", "w"), |
| 247 | + 2 => array("file", wfGetNull(), "a") |
| 248 | + ); |
| 249 | + |
| 250 | + $process = proc_open( escapeshellcmd( $wgPuttygen ) . ' -O public-openssh -o /dev/stdout /dev/stdin', $descriptorspec, $pipes ); |
| 251 | + if ( $process === false ) |
| 252 | + return false; |
| 253 | + |
| 254 | + fwrite( $pipes[0], $keydata ); |
| 255 | + fclose( $pipes[0] ); |
| 256 | + $data = stream_get_contents( $pipes[1] ); |
| 257 | + var_dump($data); |
| 258 | + fclose( $pipes[1] ); |
| 259 | + proc_close( $process ); |
| 260 | + |
| 261 | + if ( $data === false || !preg_match( '/(^| )ssh-(rsa|dss) /', $data ) ) |
| 262 | + return false; |
| 263 | + |
| 264 | + return $data; |
| 265 | + } |
| 266 | + */ |
| 267 | + |
185 | 268 | /** |
186 | 269 | * @param $formData |
187 | 270 | * @param string $entryPoint |
— | — | @@ -189,8 +272,20 @@ |
190 | 273 | function tryImportSubmit( $formData, $entryPoint = 'internal' ) { |
191 | 274 | global $wgOpenStackManagerNovaKeypairStorage; |
192 | 275 | |
| 276 | + $key = $formData['key']; |
| 277 | + if ( !preg_match( '/(^| )ssh-(rsa|dss) /', $key ) ) { |
| 278 | + # This doesn't look like openssh format, it's probably a |
| 279 | + # Windows user providing it in PuTTY format. |
| 280 | + $key = self::opensshFormatKey( $key ); |
| 281 | + if ( $key === false ) { |
| 282 | + $this->getOutput()->addWikiMsg( 'openstackmanager-keypairwrongformat' ); |
| 283 | + return false; |
| 284 | + } |
| 285 | + $this->getOutput()->addWikiMsg( 'openstackmanager-keypairformatconverted' ); |
| 286 | + } |
| 287 | + |
193 | 288 | if ( $wgOpenStackManagerNovaKeypairStorage == 'ldap' ) { |
194 | | - $success = $this->userLDAP->importKeypair( $formData['key'] ); |
| 289 | + $success = $this->userLDAP->importKeypair( $key ); |
195 | 290 | if ( ! $success ) { |
196 | 291 | $this->getOutput()->addWikiMsg( 'openstackmanager-keypairimportfailed' ); |
197 | 292 | return false; |
Index: trunk/extensions/OpenStackManager/OpenStackManager.i18n.php |
— | — | @@ -162,6 +162,8 @@ |
163 | 163 | 'openstackmanager-keypairimportfailed' => 'Failed to import keypair.', |
164 | 164 | 'openstackmanager-keypairimported' => 'Imported keypair.', |
165 | 165 | 'openstackmanager-keypairimportedfingerprint' => 'Imported keypair $1 with fingerprint $2.', |
| 166 | + 'openstackmanager-keypairformatwrong' => 'The provided SSH key was wrong or in unknown format.', |
| 167 | + 'openstackmanager-keypairformatconverted' => 'The format of the SSH key has been automatically converted.', |
166 | 168 | 'openstackmanager-backkeylist' => 'Back to key list', |
167 | 169 | 'openstackmanager-addadditionalkey' => 'Add another key.', |
168 | 170 | 'openstackmanager-deletedkey' => 'Successfully deleted key.', |
Index: trunk/extensions/OpenStackManager/OpenStackManager.php |
— | — | @@ -82,6 +82,11 @@ |
83 | 83 | $wgOpenStackManagerLDAPUseUidAsNamingAttribute = false; |
84 | 84 | $wgOpenStackManagerNovaDefaultProject = ""; |
85 | 85 | |
| 86 | +/** |
| 87 | + * Path to the puttygen utility. Used for converting ssh key formats. False to disable its use. |
| 88 | + */ |
| 89 | +$wgPuttygen = 'puttygen'; |
| 90 | + |
86 | 91 | $dir = dirname( __FILE__ ) . '/'; |
87 | 92 | |
88 | 93 | $wgExtensionMessagesFiles['OpenStackManager'] = $dir . 'OpenStackManager.i18n.php'; |