Skip to content

Commit bb0f50e

Browse files
committed
Implement setting environment variables for exec.
This only works if the remote sshd permits it. By default, most do not. Fixes: #11
1 parent 09d6d32 commit bb0f50e

File tree

4 files changed

+58
-0
lines changed

4 files changed

+58
-0
lines changed

src/clj_libssh2/channel.clj

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,40 @@
138138
[session channel]
139139
(block session (handle-errors session (libssh2-channel/send-eof channel))))
140140

141+
(defn setenv
142+
"Set a selection of environment variables on the channel. These will be
143+
visible to the next exec command. Setting environment variables may be
144+
prohibited by the remote sshd based on the value of the AcceptEnv
145+
configuration value.
146+
147+
Arguments:
148+
149+
channel
150+
env A map where the keys are environment variable names and the values
151+
are the values for those environment variables. If either the name
152+
or value is a keyword, they will be stringified using the name
153+
function. Everything else will be stringified using str. Nil values
154+
will be converted to empty strings. For maximum predictability, you
155+
should provide a map of String -> String only.
156+
157+
Return:
158+
159+
0 on success. Errors will result in exceptions."
160+
[session channel env]
161+
(let [->str (fn [v]
162+
(cond (nil? v) ""
163+
(keyword? v) (name v)
164+
:else (str v)))
165+
fail-if-forbidden (fn [ret]
166+
(if (= libssh2/ERROR_CHANNEL_REQUEST_DENIED ret)
167+
(throw (Exception. "Setting environment variables is not permitted."))
168+
ret))]
169+
(doseq [[k v] env]
170+
(block session
171+
(handle-errors session
172+
(fail-if-forbidden
173+
(libssh2-channel/setenv channel (->str k) (->str v))))))))
174+
141175
(defn pull
142176
"Read some output from a given stream on a channel.
143177

src/clj_libssh2/ssh.clj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@
5050
If this is not provided, then the output will be returned as a String.
5151
:err An OutputStream which will be connected to the standard error of the
5252
remote process and in every other way behaves like :out.
53+
:env A map of environment variables which will be set before the command is
54+
executed. The keys are the environment variable names. The values are
55+
the values for those variables. The setting of environment variables is
56+
controlled by the remote sshd and the value of its AcceptEnv
57+
configuration variable.
5358
5459
Return:
5560
@@ -78,6 +83,7 @@
7883
inputs (if stdin {0 stdin} {})
7984
outputs {0 stdout 1 stderr}]
8085
(channel/with-channel session channel
86+
(channel/setenv session channel (:env io))
8187
(channel/exec session channel commandline)
8288
(let [streams (channel/pump session channel inputs outputs)
8389
out (:stream (get streams 0))

test/clj_libssh2/test_ssh.clj

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,23 @@
6565
(is (= "" (:err result)))
6666
(is (= 0 (:exit result))))))))
6767

68+
(deftest exec-can-be-given-environment-variables
69+
(testing "Exec can be given environment variables."
70+
(ssh/with-session session {:port 2222}
71+
(let [env {:FOO "foo" :BAR :bar :BAZ 1 :QUUX nil}
72+
result (ssh/exec session "env" :env env)
73+
out-env (->> result
74+
:out
75+
str/split-lines
76+
(map #(str/split % #"=" 2))
77+
(into {}))]
78+
(is (= "foo" (get out-env "FOO")))
79+
(is (= "bar" (get out-env "BAR")))
80+
(is (= "1" (get out-env "BAZ")))
81+
(is (= "" (get out-env "QUUX")))
82+
(is (= "" (:err result)))
83+
(is (= 0 (:exit result)))))))
84+
6885
(deftest exec-times-out-when-commands-take-too-long
6986
(testing "Commands that take too long result in a timeout"
7087
(is (thrown? Exception (ssh/exec {:port 2222 :read-timeout 500}

test/script/setup.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ launch_sshd() {
104104
-h "${TMP_DIR}/ssh_host_key" \
105105
-h "${TMP_DIR}/ssh_host_dsa_key" \
106106
-h "${TMP_DIR}/ssh_host_rsa_key" \
107+
-o "AcceptEnv=*" \
107108
-o "AuthorizedKeysFile=${TMP_DIR}/authorized_keys" \
108109
-o "ListenAddress=${host}:${port}"
109110
SSHD_PID=$(pgrep -f "${TMP_DIR}/ssh_host_dsa_key")

0 commit comments

Comments
 (0)