Make git-annex-shell call the command with its (safe) options.
This commit is contained in:
parent
f5942eba7a
commit
3bfe011867
4 changed files with 61 additions and 29 deletions
|
@ -11,6 +11,7 @@ import Common.Annex
|
|||
import Command
|
||||
import CmdLine
|
||||
import Annex.Content
|
||||
import Annex
|
||||
import Utility.Rsync
|
||||
import Logs.Transfer
|
||||
import Command.SendKey (fieldTransfer)
|
||||
|
@ -19,6 +20,8 @@ import qualified Types.Key
|
|||
import qualified Types.Backend
|
||||
import qualified Backend
|
||||
|
||||
import System.Console.GetOpt
|
||||
|
||||
def :: [Command]
|
||||
def = [noCommit $ command "recvkey" paramKey seek
|
||||
SectionPlumbing "runs rsync in server mode to receive content"]
|
||||
|
@ -40,7 +43,10 @@ start key = ifM (inAnnex key)
|
|||
)
|
||||
)
|
||||
where
|
||||
go tmp = ifM (liftIO $ rsyncServerReceive tmp)
|
||||
go tmp = do
|
||||
(opts,_,_) <- getOpt Permute rsyncSafeOptions <$>
|
||||
maybe [] (split " ") <$> getField "RsyncOptions"
|
||||
ifM (liftIO $ rsyncServerReceive (map Param opts) tmp)
|
||||
( ifM (isJust <$> Fields.getField Fields.direct)
|
||||
( directcheck tmp
|
||||
, return True
|
||||
|
|
|
@ -10,11 +10,14 @@ module Command.SendKey where
|
|||
import Common.Annex
|
||||
import Command
|
||||
import Annex.Content
|
||||
import Annex
|
||||
import Utility.Rsync
|
||||
import Logs.Transfer
|
||||
import qualified Fields
|
||||
import Utility.Metered
|
||||
|
||||
import System.Console.GetOpt
|
||||
|
||||
def :: [Command]
|
||||
def = [noCommit $ command "sendkey" paramKey seek
|
||||
SectionPlumbing "runs rsync in server mode to send content"]
|
||||
|
@ -23,9 +26,12 @@ seek :: [CommandSeek]
|
|||
seek = [withKeys start]
|
||||
|
||||
start :: Key -> CommandStart
|
||||
start key = ifM (inAnnex key)
|
||||
start key = do
|
||||
(opts,_,_) <- getOpt Permute rsyncSafeOptions <$>
|
||||
maybe [] (split " ") <$> getField "RsyncOptions"
|
||||
ifM (inAnnex key)
|
||||
( fieldTransfer Upload key $ \_p ->
|
||||
sendAnnex key rollback $ liftIO . rsyncServerSend
|
||||
sendAnnex key rollback $ liftIO . rsyncServerSend (map Param opts)
|
||||
, do
|
||||
warning "requested key is not present"
|
||||
liftIO exitFailure
|
||||
|
|
|
@ -15,6 +15,7 @@ import qualified Git.Construct
|
|||
import CmdLine
|
||||
import Command
|
||||
import Annex.UUID
|
||||
import Annex (setField)
|
||||
import qualified Option
|
||||
import Fields
|
||||
import Utility.UserInfo
|
||||
|
@ -86,32 +87,38 @@ builtin :: String -> String -> [String] -> IO ()
|
|||
builtin cmd dir params = do
|
||||
checkNotReadOnly cmd
|
||||
checkDirectory $ Just dir
|
||||
let (params', fieldparams) = partitionParams params
|
||||
let fields = filter checkField $ parseFields fieldparams
|
||||
dispatch False (cmd : params') cmds options fields header $
|
||||
let (params', fieldparams, opts) = partitionParams params
|
||||
fields = filter checkField $ parseFields fieldparams
|
||||
cmds' = map (newcmd $ intercalate " " opts) cmds
|
||||
dispatch False (cmd : params') cmds' options fields header $
|
||||
Git.Construct.repoAbsPath dir >>= Git.Construct.fromAbsPath
|
||||
where
|
||||
newseek opts seek k = setField "RsyncOptions" opts >> seek k
|
||||
newcmd opts c = c { cmdseek = map (newseek opts) (cmdseek c) }
|
||||
|
||||
external :: [String] -> IO ()
|
||||
external params = do
|
||||
{- Normal git-shell commands all have the directory as their last
|
||||
- parameter. -}
|
||||
let lastparam = lastMaybe =<< shellUnEscape <$> lastMaybe params
|
||||
(params', _, _) = partitionParams params
|
||||
checkDirectory lastparam
|
||||
checkNotLimited
|
||||
unlessM (boolSystem "git-shell" $ map Param $ "-c":fst (partitionParams params)) $
|
||||
unlessM (boolSystem "git-shell" $ map Param $ "-c":params') $
|
||||
error "git-shell failed"
|
||||
|
||||
{- Parameters between two -- markers are field settings, in the form:
|
||||
{- Split the input list into 3 groups separated with a double dash --.
|
||||
- Parameters between two -- markers are field settings, in the form:
|
||||
- field=value field=value
|
||||
-
|
||||
- Parameters after the last -- are ignored, these tend to be passed by
|
||||
- rsync and not be useful.
|
||||
- Parameters after the last -- are the command itself and its arguments e.g.,
|
||||
- rsync --bandwidth=100.
|
||||
-}
|
||||
partitionParams :: [String] -> ([String], [String])
|
||||
partitionParams :: [String] -> ([String], [String], [String])
|
||||
partitionParams ps = case segment (== "--") ps of
|
||||
params:fieldparams:_ -> (params, fieldparams)
|
||||
[params] -> (params, [])
|
||||
_ -> ([], [])
|
||||
params:fieldparams:rest -> ( params, fieldparams, intercalate ["--"] rest )
|
||||
[params] -> (params, [], [])
|
||||
_ -> ([], [], [])
|
||||
|
||||
parseFields :: [String] -> [(String, String)]
|
||||
parseFields = map (separate (== '='))
|
||||
|
|
|
@ -11,6 +11,7 @@ import Common
|
|||
import Utility.Metered
|
||||
|
||||
import Data.Char
|
||||
import System.Console.GetOpt
|
||||
|
||||
{- Generates parameters to make rsync use a specified command as its remote
|
||||
- shell. -}
|
||||
|
@ -23,13 +24,14 @@ rsyncShell command = [Param "-e", Param $ unwords $ map escape (toCommand comman
|
|||
escape s = "'" ++ join "''" (split "'" s) ++ "'"
|
||||
|
||||
{- Runs rsync in server mode to send a file. -}
|
||||
rsyncServerSend :: FilePath -> IO Bool
|
||||
rsyncServerSend file = rsync $
|
||||
rsyncServerParams ++ [Param "--sender", File file]
|
||||
rsyncServerSend :: [CommandParam] -> FilePath -> IO Bool
|
||||
rsyncServerSend options file = rsync $
|
||||
rsyncServerParams ++ Param "--sender" : options ++ [File file]
|
||||
|
||||
{- Runs rsync in server mode to receive a file. -}
|
||||
rsyncServerReceive :: FilePath -> IO Bool
|
||||
rsyncServerReceive file = rsync $ rsyncServerParams ++ [File file]
|
||||
rsyncServerReceive :: [CommandParam] -> FilePath -> IO Bool
|
||||
rsyncServerReceive options file = rsync $
|
||||
rsyncServerParams ++ options ++ [File file]
|
||||
|
||||
rsyncServerParams :: [CommandParam]
|
||||
rsyncServerParams =
|
||||
|
@ -127,3 +129,14 @@ parseRsyncProgress = go [] . reverse . progresschunks
|
|||
([], _) -> Nothing
|
||||
(_, []) -> Nothing
|
||||
(b, _) -> readish b
|
||||
|
||||
{- To prevent an evil client to run harmful options on the server, we
|
||||
- cherry-pick those that are harmless. Them only are passed to rsync
|
||||
- when executed through 'git-annex-shell'.
|
||||
- Note: Ensure that when calling getopt, the first component of the
|
||||
- outupt is a subset of the input.
|
||||
-}
|
||||
rsyncSafeOptions :: [OptDescr String]
|
||||
rsyncSafeOptions = [ Option [] ["bwlimit"] (reqArgLong "bwlimit") "" ]
|
||||
where
|
||||
reqArgLong x = ReqArg (\v -> "--" ++ x ++ "=" ++ v) ""
|
||||
|
|
Loading…
Reference in a new issue