summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kiki.hs78
-rw-r--r--lib/ProcessUtils.hs2
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
19import Data.OpenPGP.Util 19import Data.OpenPGP.Util
20import Data.Ord 20import Data.Ord
21import System.Directory 21import System.Directory
22import System.FilePath.Posix 22import System.FilePath.Posix as FilePath
23import System.IO 23import System.IO
24import System.IO.Temp 24import System.IO.Temp
25import System.IO.Error 25import System.IO.Error
@@ -38,6 +38,8 @@ import qualified Data.ByteString.Lazy as L
38import qualified Data.ByteString.Lazy.Char8 as Char8 38import qualified Data.ByteString.Lazy.Char8 as Char8
39import qualified Data.Map.Strict as Map 39import qualified Data.Map.Strict as Map
40import qualified SSHKey as SSH 40import qualified SSHKey as SSH
41import Network.Socket -- (SockAddr)
42import ProcessUtils
41 43
42import GnuPGAgent (Query(..)) 44import GnuPGAgent (Query(..))
43import CommandLine 45import 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
511strongswanForContact addr oname = Char8.unlines 547strongswanForContact 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
581sshblobFromPacket k = blob 617sshblobFromPacket k = Char8.unpack $ fromJust $ sshblobFromPacketL k
582 where 618
583 Just (RSAKey (MPI n) (MPI e)) = rsaKeyFromPacket k 619sshblobFromPacketL 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{-
588replaceSshServerKeys root cmn = do 624replaceSshServerKeys 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
126runExternal :: String -> Maybe String -> IO (Int,(S.ByteString,S.ByteString)) 126runExternal :: String -> Maybe String -> IO (Int,(S.ByteString,S.ByteString))
127runExternal cmd input = do 127runExternal 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 }