diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kiki.hs | 78 | ||||
-rw-r--r-- | lib/ProcessUtils.hs | 2 |
2 files changed, 59 insertions, 21 deletions
diff --git a/lib/Kiki.hs b/lib/Kiki.hs index d5b3457..468394f 100644 --- a/lib/Kiki.hs +++ b/lib/Kiki.hs | |||
@@ -19,7 +19,7 @@ import Data.OpenPGP | |||
19 | import Data.OpenPGP.Util | 19 | import Data.OpenPGP.Util |
20 | import Data.Ord | 20 | import Data.Ord |
21 | import System.Directory | 21 | import System.Directory |
22 | import System.FilePath.Posix | 22 | import System.FilePath.Posix as FilePath |
23 | import System.IO | 23 | import System.IO |
24 | import System.IO.Temp | 24 | import System.IO.Temp |
25 | import System.IO.Error | 25 | import System.IO.Error |
@@ -38,6 +38,8 @@ import qualified Data.ByteString.Lazy as L | |||
38 | import qualified Data.ByteString.Lazy.Char8 as Char8 | 38 | import qualified Data.ByteString.Lazy.Char8 as Char8 |
39 | import qualified Data.Map.Strict as Map | 39 | import qualified Data.Map.Strict as Map |
40 | import qualified SSHKey as SSH | 40 | import qualified SSHKey as SSH |
41 | import Network.Socket -- (SockAddr) | ||
42 | import ProcessUtils | ||
41 | 43 | ||
42 | import GnuPGAgent (Query(..)) | 44 | import GnuPGAgent (Query(..)) |
43 | import CommandLine | 45 | import CommandLine |
@@ -323,7 +325,7 @@ refreshCache rt rootdir = do | |||
323 | timeout = -1 -- TODO: set milisecond timeout on dotlock | 325 | timeout = -1 -- TODO: set milisecond timeout on dotlock |
324 | createDirectoryIfMissing True cachedir | 326 | createDirectoryIfMissing True cachedir |
325 | tmpdir <- createTempDirectory cachedir ("transaction." ++ takeBaseName destdir) | 327 | tmpdir <- createTempDirectory cachedir ("transaction." ++ takeBaseName destdir) |
326 | createSymbolicLink tmpdir (tmpdir ++ ".link") | 328 | createSymbolicLink (makeRelative cachedir tmpdir) (tmpdir ++ ".link") |
327 | lock <- dotlock_create destdir 0 | 329 | lock <- dotlock_create destdir 0 |
328 | T.mapM (flip dotlock_take timeout) lock | 330 | T.mapM (flip dotlock_take timeout) lock |
329 | let mkpath pth = tmpdir </> unslash (makeRelative destdir pth) | 331 | let mkpath pth = tmpdir </> unslash (makeRelative destdir pth) |
@@ -336,7 +338,7 @@ refreshCache rt rootdir = do | |||
336 | -- otherwise call readyReadBeforeWrite on them. | 338 | -- otherwise call readyReadBeforeWrite on them. |
337 | rename (tmpdir ++ ".link") destdir | 339 | rename (tmpdir ++ ".link") destdir |
338 | er <- T.mapM dotlock_release lock | 340 | er <- T.mapM dotlock_release lock |
339 | void $ T.mapM removeDirectoryRecursive oldcommit | 341 | void $ T.mapM removeDirectoryRecursive (FilePath.combine cachedir <$> oldcommit) |
340 | -- Present transaction is Write only (or Write-Before-Read) which is fine. | 342 | -- Present transaction is Write only (or Write-Before-Read) which is fine. |
341 | -- If ever Read-Before-Write is required, uncomment and use: | 343 | -- If ever Read-Before-Write is required, uncomment and use: |
342 | -- let readyReadBeforeWrite pth = do | 344 | -- let readyReadBeforeWrite pth = do |
@@ -367,6 +369,10 @@ refreshCache rt rootdir = do | |||
367 | wr f bs | 369 | wr f bs |
368 | write = write' writeFile | 370 | write = write' writeFile |
369 | writeL = write' L.writeFile | 371 | writeL = write' L.writeFile |
372 | writeL077 f bs = do | ||
373 | old_umask <- setFileCreationMask 0o077 | ||
374 | writeL f bs | ||
375 | setFileCreationMask old_umask | ||
370 | 376 | ||
371 | let names = do wk <- rtWorkingKey rt | 377 | let names = do wk <- rtWorkingKey rt |
372 | -- XXX unnecessary signature check | 378 | -- XXX unnecessary signature check |
@@ -436,6 +442,11 @@ refreshCache rt rootdir = do | |||
436 | (mkpath "ipsec.d/private/" ++ Char8.unpack oname++".pem") | 442 | (mkpath "ipsec.d/private/" ++ Char8.unpack oname++".pem") |
437 | "missing ipsec key?" | 443 | "missing ipsec key?" |
438 | 444 | ||
445 | -- TODO: probably we should add multiple entries for the case that there | ||
446 | -- are multiple secret master-keys each with distinct tor and ipsec keys. | ||
447 | writeL077 (mkpath "ipsec.secrets") | ||
448 | $ ": RSA /var/cache/kiki/config/ipsec.d/private/" <> oname <> ".pem" | ||
449 | |||
439 | writeSecret "ssh-client" | 450 | writeSecret "ssh-client" |
440 | (mkpath "root/.ssh/id_rsa") | 451 | (mkpath "root/.ssh/id_rsa") |
441 | "missing ssh-client key?" | 452 | "missing ssh-client key?" |
@@ -457,32 +468,57 @@ refreshCache rt rootdir = do | |||
457 | either warn (write $ mkpath "ipsec.d/certs/" ++ Char8.unpack oname++".pem") | 468 | either warn (write $ mkpath "ipsec.d/certs/" ++ Char8.unpack oname++".pem") |
458 | $ show_pem' "ipsec" grip (rtKeyDB rt) pemFromPacket | 469 | $ show_pem' "ipsec" grip (rtKeyDB rt) pemFromPacket |
459 | 470 | ||
460 | let cs = filter notme (Map.elems $ rtKeyDB rt) | 471 | let onionkeys = mapMaybe namedContact $ Map.elems $ rtKeyDB rt |
472 | cs = filter (\(_,_,kd) -> notme kd) onionkeys | ||
461 | kk = keykey (fromJust $ rtWorkingKey rt) | 473 | kk = keykey (fromJust $ rtWorkingKey rt) |
462 | notme kd = keykey (keyPacket kd) /= kk | 474 | notme kd = keykey (keyPacket kd) /= kk |
463 | 475 | ||
464 | installConctact :: KeyData -> IO Char8.ByteString | 476 | namedContact kd = do |
465 | installConctact kd = do | ||
466 | -- The getHostnames command requires a valid cross-signed tor key | 477 | -- The getHostnames command requires a valid cross-signed tor key |
467 | -- for each onion name returned in (_,(ns,_)). | 478 | -- for each onion name returned in (_,(ns,_)). |
468 | let (addr,(ns,_)) = getHostnames kd | 479 | let (addr,(ns,_)) = getHostnames kd |
469 | contactname = fmap Char8.unpack $ listToMaybe ns -- only first onion name. | 480 | fmap (\n -> (n,addr, kd)) $ listToMaybe ns -- only first onion name. |
470 | flip (maybe $ return Char8.empty) contactname $ \contactname -> do | 481 | |
482 | installConctact :: (L.ByteString, SockAddr, KeyData) -> IO Char8.ByteString | ||
483 | installConctact (contactname,addr,kd) = do | ||
471 | 484 | ||
472 | let cpath = interp (Map.singleton "onion" contactname) "ipsec.d/certs/%(onion).pem" | 485 | let cpath = interp (Map.singleton "onion" (Char8.unpack contactname)) "ipsec.d/certs/%(onion).pem" |
473 | their_master = packet $ keyMappedPacket kd | 486 | their_master = packet $ keyMappedPacket kd |
474 | -- We find all cross-certified ipsec keys for the given cross-certified onion name. | 487 | -- We find all cross-certified ipsec keys for the given cross-certified onion name. |
475 | ipsecs :: [Packet] | 488 | ipsecs :: [Packet] |
476 | ipsecs = sortOn (Down . timestamp) | 489 | ipsecs = sortOn (Down . timestamp) |
477 | $ getSubkeys CrossSigned their_master (keySubKeys kd) "ipsec" | 490 | $ getSubkeys CrossSigned their_master (keySubKeys kd) "ipsec" |
478 | ++ getSubkeys CrossSigned their_master (keySubKeys kd) "strongswan" | 491 | -- ++ getSubkeys CrossSigned their_master (keySubKeys kd) "strongswan" |
492 | sshs :: [Packet] | ||
493 | sshs = sortOn (Down . timestamp) | ||
494 | $ getSubkeys CrossSigned their_master (keySubKeys kd) "ssh-server" | ||
479 | bss <- forM (take 1 ipsecs) $ \k -> do | 495 | bss <- forM (take 1 ipsecs) $ \k -> do |
480 | let warn' x = warn x >> return Char8.empty | 496 | let warn' x = warn x >> return Char8.empty |
481 | flip (either warn') (pemFromPacket k :: Either String String) $ \pem -> do | 497 | flip (either warn') (pemFromPacket k :: Either String String) $ \pem -> do |
482 | write (mkpath cpath) pem | 498 | write (mkpath cpath) pem |
483 | return $ strongswanForContact addr contactname | 499 | case take 1 sshs of |
500 | [sshkey] -> do | ||
501 | (_,(sout,serr)) <- runExternal "(f=$(mktemp); cat > \"$f\"; ssh-keygen -l -f \"$f\" | (read _ hash _; echo -n $hash.ssh.cryptonomic.net) | tr -d ':')" | ||
502 | (Just $ sshblobFromPacket sshkey) | ||
503 | -- ssh-keygen -l -f /dev/stdin | ||
504 | -- putStrLn $ "wtf="++show(sout,serr, sshblobFromPacket sshkey) | ||
505 | return $ strongswanForContact addr contactname (Char8.fromChunks [sout]) | ||
506 | [] -> error "fuck." | ||
484 | return $ Char8.concat bss | 507 | return $ Char8.concat bss |
485 | 508 | ||
509 | known_hosts = L.concat $ map getssh onionkeys | ||
510 | |||
511 | getssh (contactname,addr,kd) = do | ||
512 | let their_master = packet $ keyMappedPacket kd | ||
513 | sshs :: [Packet] | ||
514 | sshs = sortOn (Down . timestamp) | ||
515 | $ getSubkeys CrossSigned their_master (keySubKeys kd) "ssh-server" | ||
516 | blobs = mapMaybe sshblobFromPacketL sshs | ||
517 | taggedblobs = map (\b -> contactname <> " " <> b) blobs | ||
518 | Char8.unlines taggedblobs | ||
519 | |||
520 | writeL (mkpath "ssh_known_hosts") known_hosts | ||
521 | |||
486 | cons <- mapM installConctact cs | 522 | cons <- mapM installConctact cs |
487 | writeL (mkpath "ipsec.conf") . Char8.unlines | 523 | writeL (mkpath "ipsec.conf") . Char8.unlines |
488 | $ [ "conn %default" | 524 | $ [ "conn %default" |
@@ -497,7 +533,7 @@ refreshCache rt rootdir = do | |||
497 | , " leftsubnet=" <> Char8.pack (showA wkaddr) <> "/128" | 533 | , " leftsubnet=" <> Char8.pack (showA wkaddr) <> "/128" |
498 | , " leftauth=pubkey" | 534 | , " leftauth=pubkey" |
499 | , " leftid=" <> Char8.pack (showA wkaddr) | 535 | , " leftid=" <> Char8.pack (showA wkaddr) |
500 | , " leftrsasigkey=" <> oname | 536 | , " leftrsasigkey=" <> oname <> ".pem" |
501 | , " leftikeport=4500" | 537 | , " leftikeport=4500" |
502 | , " rightikeport=4500" | 538 | , " rightikeport=4500" |
503 | , " right=%any" | 539 | , " right=%any" |
@@ -508,13 +544,13 @@ refreshCache rt rootdir = do | |||
508 | ] ++ filter (not . Char8.null) cons | 544 | ] ++ filter (not . Char8.null) cons |
509 | commit | 545 | commit |
510 | 546 | ||
511 | strongswanForContact addr oname = Char8.unlines | 547 | strongswanForContact addr oname rightip = Char8.unlines |
512 | [ "conn " <> p oname | 548 | [ "conn " <> oname |
513 | , " right=%" <> p oname <> ".ipv4" | 549 | , " right=lan." <> rightip |
514 | , " rightsubnet=" <> p (showA addr) <> "/128" | 550 | , " rightsubnet=" <> p (showA addr) <> "/128" |
515 | , " rightauth=pubkey" | 551 | , " rightauth=pubkey" |
516 | , " rightid=" <> p (showA addr) | 552 | , " rightid=" <> p (showA addr) |
517 | , " rightrsasigkey=" <> p (oname) <> ".pem" | 553 | , " rightrsasigkey=" <> oname <> ".pem" |
518 | ] | 554 | ] |
519 | where p = Char8.pack | 555 | where p = Char8.pack |
520 | 556 | ||
@@ -578,11 +614,11 @@ interp vars raw = es >>= interp1 | |||
578 | where (key,rest) = break (==')') str | 614 | where (key,rest) = break (==')') str |
579 | interp1 plain = plain | 615 | interp1 plain = plain |
580 | 616 | ||
581 | sshblobFromPacket k = blob | 617 | sshblobFromPacket k = Char8.unpack $ fromJust $ sshblobFromPacketL k |
582 | where | 618 | |
583 | Just (RSAKey (MPI n) (MPI e)) = rsaKeyFromPacket k | 619 | sshblobFromPacketL k = do |
584 | bs = SSH.keyblob (n,e) | 620 | RSAKey (MPI n) (MPI e) <- rsaKeyFromPacket k |
585 | blob = Char8.unpack bs | 621 | return $ SSH.keyblob (n,e) |
586 | 622 | ||
587 | {- | 623 | {- |
588 | replaceSshServerKeys root cmn = do | 624 | replaceSshServerKeys root cmn = do |
diff --git a/lib/ProcessUtils.hs b/lib/ProcessUtils.hs index b89edb9..1a9cc04 100644 --- a/lib/ProcessUtils.hs +++ b/lib/ProcessUtils.hs | |||
@@ -126,10 +126,12 @@ readProcessWithErrorH cmd args stdin erH = do | |||
126 | runExternal :: String -> Maybe String -> IO (Int,(S.ByteString,S.ByteString)) | 126 | runExternal :: String -> Maybe String -> IO (Int,(S.ByteString,S.ByteString)) |
127 | runExternal cmd input = do | 127 | runExternal cmd input = do |
128 | cwd <- getCurrentDirectory | 128 | cwd <- getCurrentDirectory |
129 | {- | ||
129 | putStr $ takeFileName cwd ++ "> " ++ cmd | 130 | putStr $ takeFileName cwd ++ "> " ++ cmd |
130 | ++ case input of | 131 | ++ case input of |
131 | Nothing -> "\n" | 132 | Nothing -> "\n" |
132 | Just s -> " <<EOF\n" ++ s ++ "EOF\n" | 133 | Just s -> " <<EOF\n" ++ s ++ "EOF\n" |
134 | -} | ||
133 | let p = (shell cmd) { std_in = maybe Inherit (const CreatePipe) input | 135 | let p = (shell cmd) { std_in = maybe Inherit (const CreatePipe) input |
134 | , std_out = CreatePipe | 136 | , std_out = CreatePipe |
135 | , std_err = CreatePipe } | 137 | , std_err = CreatePipe } |