7SNXCC5KSDXU3MBJT2FBEPAISWPY62DHPC2RLEYXC2WVTWX5TKKQC
FITNBSMMJCQIFJGUMVSZYHJM4OSBXEZO5YWYEJ4CXGMFPBSIT5WAC
TFWMUQZSR25B6CLXFNFN56JFH3PJRHDFW7DYTGDOFCVKW4KC43NAC
UW27LKXM2BJ77FQLTY4WPKDSSWI2RFNFRJ7CB4U3TS7KYVIV72LQC
JDZASPALXSFZOL3MXCKBPX74CUD3W743ZJ6W2422FIJ7NJOD67ZAC
VSQGRPJ7PDH3MOC7GFVX5YONUZTLFRXU2O6CFT5MRGBGOO7PO6GAC
A2JAXDJWT2FAKADYOY6QOQ7LQRMTTCDIOYT7STSESVHLZQEQJBMAC
5XO7IKBGCVXGVWMDJDE5MELS4FWRITKAU6NNV36NQ4TOZRR7UQ7QC
RCUBQKTURAMSYYFNNI4JPXDBZDGF6ZGWVGQYTDEKA6EOMG4QUZOAC
MPN7OJSZD5CS5N7WWS3ZSOYE7ZRCABIBHZDMHVS6IT25EO2INK7AC
PXI442CY2KQHHAIJ3UNCWKTAI4IFYNGYEBRQMDR6T53YZTY2VMMQC
K3OVRFE3Y23DN47XNAISH6XM5JGSCNRR6TOEO5KAKBNB54MFO27AC
6XHALMLUA5B5BBYFSWIFHSJ2BXCL6RSAW5TCKRGJEI2LURH2TQ4AC
lisp_eval_should_be '(shellquote "foo")' '"'\''foo'\''"' 'shellquote, trivial'
lisp_eval_should_be '(shellquote "foo'\''s")' '"'\''foo'\'\\\'\''s'\''"' 'shellquote, single single quote'
lisp_eval_should_be '(shellquote "c d")' '"'\''c d'\''"' 'shellquote, space'
lisp_eval_should_be '(shellquote "$foo")' '"'\''$foo'\''"' 'shellquote, dollarsign'
lisp_eval_should_be '(shellquote "a\\nb")' '"'\''a\nb'\''"' 'shellquote, newline'
lisp_eval_should_be '(unsafe-system "echo hi; echo ho")' 'hi
ho' 'unsafe-system vulnerable to command injection'
lisp_eval_should_be '(system "echo" "hi;" "echo" "ho")' 'hi; echo ho' 'system properly escapes arguments'
lisp_eval_should_be '(let ((a '\''(1 2 3))) (apply + 6 a))' '12' 'apply'
if(car == _symbol("system"))
return _system(_eval3(_cadr(form), env, env, d+1))
if(car == _symbol("shellquote"))
return _shellquote(_eval3(_cadr(form), env, env, d+1))
if(car == _symbol("unsafe-system"))
return _unsafe_system(_eval3(_cadr(form), env, env, d+1))
return _system(_STRING[s])
subber = _STRING[s]
# This lisp is aimed at system administration, where it might
# run as root, and unquoted control characters output to a
# terminal may have ill effects. Rather nerf the control
# characters than pass them through. But we'll let \011, HT;
# \012, LF; and \015, CR, through.
gsub(/[\001-\010\013-\014\016-\037]/, "[GlotawkNerfedCtrl]", subber)
gsub(/'/, "'\\''", subber)
sub(/^/, "'", subber)
sub(/$/, "'", subber)
return _string(subber)
logg_err("_system", "non-string operand " _repr(s))
logg_err("_shellquote", "non-string operand " _repr(s))
return _nil()
}
}
# This is unsafe because you pass in a single string, which is passed
# straight to the shell. If the string contains any user-controlled
# input, calling unsafe-system with it introduces a command injection
# vulnerability, CWE-78.
function _unsafe_system(s) {
if(_TYPE[s] == "s") {
return system(_STRING[s])
} else {
logg_err("_unsafe_system", "non-string operand " _repr(s))
(setq system (lambda (x) (system x))) \
(setq unsafe-system (lambda (x) (system x))) \
(setq shellquote (lambda (x) (shellquote x))) \
(setq intercalate (lambda (it them) \
(cond ((null them)) \
((null (cdr them)) them) \
(true (cons (car them) \
(cons it \
(intercalate it (cdr them)))))))) \
(setq string-join (lambda args (apply strcat (intercalate (car args) (cdr args))))) \
(setq system (lambda argv (unsafe-system (apply string-join \" \" (mapcar shellquote argv)))))\
function _apply(args, env, depth, last, butlast) {
# logg_dbg("apply", _repr(args), depth)
if(_is_null(args)) # (apply)
return _nil()
else if(_is_null(_cdr(args))) # (apply just-a-function-no-args)
return _eval3(args, env, env, depth)
else {
butlast = _nil()
for(last=args; !_is_null(_cdr(last)); last=_cdr(last)) {
butlast = _cons(_car(last), butlast)
}
# now, butlast is a reversed copy of everything but the last.
# last is the (unevaluated) last cdr in args. is last a list?
# logg_dbg("apply", "butlast is " butlast " with " _repr(butlast), depth)
# logg_dbg("apply", "last is " last " with " _repr(last) ". evalling", depth)
last = _eval3(_car(last), env, env, depth+1)
# logg_dbg("apply", "last is now " last " with " _repr(last), depth)
if(_TYPE[last] == "(") {
args = _nconc(_nreverse(butlast), last)
# logg_dbg("apply", "now we shall evaluate " _repr(args), depth)
return _eval3(args, env, env, depth)
} else {
# last is an atom. why'd you use apply? oh well.
# logg_dbg("apply", "last is not a list. oh well, evaluating " _repr(args), depth)
return _eval3(args, env, env, depth)
}
}
}