summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--doc/api-sessions.texi28
-rw-r--r--libguile-ssh/session-func.c39
-rw-r--r--modules/ssh/session.scm23
-rw-r--r--tests/common.scm3
-rw-r--r--tests/config4
-rw-r--r--tests/session.scm8
7 files changed, 108 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index ad6923c..0f38913 100644
--- a/NEWS
+++ b/NEWS
@@ -36,6 +36,10 @@ Copyright (C) Artyom V. Poptsov <poptsov.artyom@gmail.com>
** New procedures
*** New procedure 'node-server-running?' in (ssh dist node)
*** New procedure 'node-run-server' in (ssh dist node)
+*** New procedure 'session-parse-config!' in (ssh session)
+** 'make-session' now takes 'config' option
+ that allows to specify whether the SSH config should be parsed or not, and
+ optionally the path to the config.
** Unit tests
*** Expand the test suite for distributed forms
*** Expand the test suite for tunnels
diff --git a/doc/api-sessions.texi b/doc/api-sessions.texi
index b150f64..7330d92 100644
--- a/doc/api-sessions.texi
+++ b/doc/api-sessions.texi
@@ -223,10 +223,38 @@ slower.
Set callbacks that will be called on related events (@pxref{Callbacks}.)
Expected type of @var{value}: an association list (alist).
+
+@item config
+The option specifies whether an SSH config should be parsed or not, and
+optionally the path to a config file.
+
+Setting the @var{value} to @code{#t} means that the default
+@file{~/.ssh/config} should be parsed; in turn, setting the option to
+@code{#f} (the default value) means that the config should not be parsed at
+all. If the value is a string, then the string is expected to be a path to
+config file.
+
+The procedure reads the config file after all other specified options are set.
+When the config file is read, the options for @var{session} are set,
+overwriting those that were passed to the procedure.
+
+You @emph{must} specify at least a host name when using this option, otherwise
+the procedure will fail.
+
+Optionally you could use @code{session-parse-config!} procedure explicitly to
+read the config (see below.)
+
+Expected types of @var{value}: Either a string or a boolean value.
@end table
@end deffn
+@deffn {Scheme Procedure} session-parse-config! session [file-name]
+Parse an SSH config @var{file-name} and set @var{session} options. If
+@var{file-name} is not set, the default SSH @file{~/.ssh/config} is used.
+Throw @code{guile-ssh-error} on an error. Return value is undefined.
+@end deffn
+
@deffn {Scheme Procedure} session-get session option
Get value of the @var{option} for @var{session}. The @var{option} is expected
to be a symbol.
diff --git a/libguile-ssh/session-func.c b/libguile-ssh/session-func.c
index 8f4d115..86ee60a 100644
--- a/libguile-ssh/session-func.c
+++ b/libguile-ssh/session-func.c
@@ -464,6 +464,45 @@ Get value of the OPTION. Throw `guile-ssh-error' on an error.\
}
#undef FUNC_NAME
+/* Asserts:
+ - SESSION is a Guile-SSH session object.
+ - FILE_NAME either a string or '#f' */
+SCM_GSSH_DEFINE (gssh_session_parse_config, "%gssh-session-parse-config!", 2,
+ (SCM session, SCM file_name))
+#define FUNC_NAME s_gssh_session_parse_config
+{
+ struct session_data *sd = _scm_to_session_data (session);
+ int res;
+ char* c_file_name = NULL;
+
+ SCM_ASSERT (scm_is_string (file_name)
+ || (scm_is_bool (file_name) && scm_is_false (file_name)),
+ file_name, SCM_ARG2, FUNC_NAME);
+
+ scm_dynwind_begin (0);
+
+ if (scm_is_string (file_name))
+ {
+ c_file_name = scm_to_locale_string (file_name);
+ scm_dynwind_free (c_file_name);
+ }
+
+ res = ssh_options_parse_config (sd->ssh_session,
+ /* 'NULL' means that we should read the
+ default '~/.ssh/config' file. */
+ c_file_name);
+ if (res != SSH_OK)
+ {
+ guile_ssh_error1 (FUNC_NAME, "Could not read the configuration file",
+ scm_list_2 (session, file_name));
+ }
+
+ scm_dynwind_end ();
+
+ return SCM_UNDEFINED;
+}
+#undef FUNC_NAME
+
/* Connect to the SSH server.
Return one of the following symbols: 'ok, 'again, 'error
diff --git a/modules/ssh/session.scm b/modules/ssh/session.scm
index 912b220..96d0f91 100644
--- a/modules/ssh/session.scm
+++ b/modules/ssh/session.scm
@@ -27,6 +27,7 @@
;; session?
;; %make-session
;; make-session
+;; session-parse-config!
;; blocking-flush!
;; session-set!
;; session-get
@@ -49,6 +50,7 @@
session?
%make-session
make-session
+ session-parse-config!
blocking-flush!
session-set!
session-get
@@ -72,7 +74,7 @@
knownhosts timeout timeout-usec ssh1 ssh2 log-verbosity
ciphers-c-s ciphers-s-c compression-c-s compression-s-c
proxycommand stricthostkeycheck compression
- compression-level callbacks)
+ compression-level callbacks config)
"Make a new SSH session with specified configuration.\n
Return a new SSH session."
(let ((session (%make-session)))
@@ -97,8 +99,27 @@ Return a new SSH session."
(session-set-if-specified! compression)
(session-set-if-specified! compression-level)
(session-set-if-specified! callbacks)
+
+ (when config
+ (or host
+ (throw 'guile-ssh-error
+ "'config' is specified, but 'host' option is missed."))
+ (cond
+ ((string? config)
+ (%gssh-session-parse-config! session config))
+ ((boolean? config)
+ (%gssh-session-parse-config! session #f))
+ (else
+ (throw 'guile-ssh-error "Wrong 'config' value" config))))
+
session))
+(define* (session-parse-config! session #:optional file-name)
+ "Parse an SSH config FILE-NAME and set SESSION options. If FILE-NAME is not
+set, the default SSH '~/.ssh/config' is used. Throw 'guile-ssh-error' on an
+error. Return value is undefined."
+ (%gssh-session-parse-config! session file-name))
+
(load-extension "libguile-ssh" "init_session")
;;; session.scm ends here
diff --git a/tests/common.scm b/tests/common.scm
index 56016fa..82e0e1e 100644
--- a/tests/common.scm
+++ b/tests/common.scm
@@ -28,6 +28,7 @@
#:export (;; Variables
%topdir
%knownhosts
+ %config
%addr
%rsakey
%rsakey-pub
@@ -70,6 +71,8 @@
(define %knownhosts (format #f "~a/tests/knownhosts"
(getenv "abs_top_builddir")))
+(define %config (format #f "~a/tests/config" %topdir))
+
;; Pass the test case NAME as the userdata to the libssh log
(define-syntax test-assert-with-log
diff --git a/tests/config b/tests/config
new file mode 100644
index 0000000..078d2f8
--- /dev/null
+++ b/tests/config
@@ -0,0 +1,4 @@
+Host example
+ Hostname example.org
+ Port 2222
+ User alice
diff --git a/tests/session.scm b/tests/session.scm
index e5c054c..c436881 100644
--- a/tests/session.scm
+++ b/tests/session.scm
@@ -128,6 +128,14 @@
;; Make sure that default callbacks value is '#f'.
(equal? (session-get (%make-session) 'callbacks) #f))))
+(test-assert "session-parse-config!"
+ (let ((session (make-session #:host "example")))
+ (session-parse-config! session %config)
+ (format (current-error-port) "session: ~a~%" session)
+ (and (string=? (session-get session 'host) "example.org")
+ (string=? (session-get session 'user) "alice")
+ (= (session-get session 'port) 2222))))
+
(test-assert "make-session"
(make-session #:host "localhost"
#:port 22