From a464d3ec2c93e65da4ae752ac126c30e9897d63b Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 8 Feb 2005 16:15:58 +0000 Subject: option parsing --- ChangeLog | 5 +++ Makefile.am | 2 +- README | 4 ++ opts.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ opts.h | 16 ++++++++ sshfs.c | 120 +++++++++++++++++++++++++++++++++++++++++++++--------------- 6 files changed, 216 insertions(+), 30 deletions(-) create mode 100644 opts.c create mode 100644 opts.h diff --git a/ChangeLog b/ChangeLog index e5a92dc..b014217 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,11 @@ 2005-02-08 Miklos Szeredi * Add caching of symlinks + + * Add support for many ssh options to be passed to ssh + + * Port number can now actually be specified with "-o port=PORT", + bug spotted by Nadia Maksymiw 2005-02-07 Miklos Szeredi diff --git a/Makefile.am b/Makefile.am index 1c894e5..fe3b4a3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ ## Process this file with automake to produce Makefile.in bin_PROGRAMS = sshfs -sshfs_SOURCES = sshfs.c cache.c +sshfs_SOURCES = sshfs.c cache.c opts.c sshfs_CPPFLAGS = -DFUSE_USE_VERSION=22 diff --git a/README b/README index fd2bad0..498f836 100644 --- a/README +++ b/README @@ -36,6 +36,10 @@ for it (actually it just runs ssh which ask for the password if needed). You can also specify a directory after the ":". The default is the home directory. +Also many ssh options can be specified (see the manual pages for +sftp(1) and ssh_config(5)), including the remote port number +('-oport=PORT') + Installing ========== diff --git a/opts.c b/opts.c new file mode 100644 index 0000000..3976d3a --- /dev/null +++ b/opts.c @@ -0,0 +1,99 @@ +/* + Mount option parsing + Copyright (C) 2004 Miklos Szeredi + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include "opts.h" +#include +#include + +static int process_option(char *arg, struct opt opts[], int case_sensitive) +{ + int i; + char *eq = strchr(arg, '='); + if (eq) + *eq = '\0'; + + for (i = 0; opts[i].optname != NULL; i++) { + if (case_sensitive) { + if (strcmp(opts[i].optname, arg) == 0) + break; + } else if (strcasecmp(opts[i].optname, arg) == 0) + break; + } + if (opts[i].optname == NULL) { + if (eq) + *eq = '='; + return 0; + } + opts[i].present = 1; + if (eq) { + if (opts[i].value) + free(opts[i].value); + opts[i].value = strdup(eq+1); + } + return 1; +} + +static int process_option_group(char *arg, struct opt opts[], + int case_sensitive) +{ + int remove = 1; + char *prevcomma = NULL; + while (1) { + int remove_one; + char *comma = strchr(arg, ','); + if (comma) + *comma = '\0'; + remove_one = process_option(arg, opts, case_sensitive); + if (remove_one) { + if (comma) + memmove(arg, comma + 1, strlen(comma + 1)); + } else { + remove = 0; + if (comma) + arg = comma + 1; + } + if (!remove_one && prevcomma) + *prevcomma = ','; + if (!comma) + break; + prevcomma = comma; + } + return remove; +} + +void process_options(int *argcp, char *argv[], struct opt opts[], + int case_sensitive) +{ + int argctr; + int newargctr; + + for (argctr = 1, newargctr = 1; argctr < *argcp; argctr++) { + char *arg = argv[argctr]; + int removed = 0; + if (arg[0] == '-' && arg[1] == 'o') { + if (arg[2]) + removed = process_option_group(arg+2, opts, case_sensitive); + else { + if (argctr + 1 < *argcp) { + argctr++; + arg = argv[argctr]; + removed = process_option_group(arg, opts, case_sensitive); + if (!removed && argctr != newargctr) + argv[newargctr++] = argv[argctr-1]; + } + } + } + if (!removed) { + if(argctr != newargctr) + argv[newargctr] = arg; + newargctr++; + } + } + *argcp = newargctr; +} + diff --git a/opts.h b/opts.h new file mode 100644 index 0000000..b5c8729 --- /dev/null +++ b/opts.h @@ -0,0 +1,16 @@ +/* + Mount option parsing + Copyright (C) 2004 Miklos Szeredi + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +struct opt { + const char *optname; + int present; + char *value; +}; + +void process_options(int *argcp, char *argv[], struct opt opts[], + int case_sensitive); diff --git a/sshfs.c b/sshfs.c index 9f6a82c..ae65107 100644 --- a/sshfs.c +++ b/sshfs.c @@ -23,6 +23,7 @@ #include #include "cache.h" +#include "opts.h" #define SSH_FXP_INIT 1 #define SSH_FXP_VERSION 2 @@ -116,6 +117,60 @@ static GHashTable *reqtab; static pthread_mutex_t lock; static int processing_thread_started; +static struct opt ssh_opts[] = { + { .optname = "AddressFamily" }, + { .optname = "BatchMode" }, + { .optname = "BindAddress" }, + { .optname = "ChallengeResponseAuthentication" }, + { .optname = "CheckHostIP" }, + { .optname = "Cipher" }, + { .optname = "Ciphers" }, + { .optname = "Compression" }, + { .optname = "CompressionLevel" }, + { .optname = "ConnectionAttempts" }, + { .optname = "ConnectionTimeout" }, + { .optname = "GlobalKnownHostsFile" }, + { .optname = "GSSAPIAuthentication" }, + { .optname = "GSSAPIDelegateCredentials" }, + { .optname = "HostbasedAuthentication" }, + { .optname = "HostKeyAlgorithms" }, + { .optname = "HostKeyAlias" }, + { .optname = "HostName" }, + { .optname = "IdentityFile" }, + { .optname = "IdentitiesOnly" }, + { .optname = "LogLevel" }, + { .optname = "MACs" }, + { .optname = "NoHostAuthenticationForLocalhost" }, + { .optname = "NumberOfPasswordPrompts" }, + { .optname = "PasswordAuthentication" }, + { .optname = "Port" }, + { .optname = "PreferredAuthentications" }, + { .optname = "Protocol" }, + { .optname = "ProxyCommand" }, + { .optname = "PubkeyAuthentication" }, + { .optname = "RhostsRSAAuthentication" }, + { .optname = "RSAAuthentication" }, + { .optname = "ServerAliveInterval" }, + { .optname = "ServerAliveCountMax" }, + { .optname = "SmartcardDevice" }, + { .optname = "StrictHostKeyChecking" }, + { .optname = "TCPKeepAlive" }, + { .optname = "UsePrivilegedPort" }, + { .optname = "UserKnownHostsFile" }, + { .optname = "VerifyHostKeyDNS" }, + { .optname = NULL } +}; + +enum { + SOPT_DIRECTPORT, + SOPT_LAST /* Last entry in this list! */ +}; + +static struct opt sshfs_opts[] = { + [SOPT_DIRECTPORT] = { .optname = "directport" }, + [SOPT_LAST] = { .optname = NULL } +}; + #define DEBUG(format, args...) \ do { if (debug) fprintf(stderr, format, args); } while(0) @@ -400,10 +455,11 @@ static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h, return 0; } -static int start_ssh(const char *host, const char *port) +static int start_ssh(char *host) { int inpipe[2]; int outpipe[2]; + int i; int pid; if (pipe(inpipe) == -1 || pipe(outpipe) == -1) { @@ -418,6 +474,9 @@ static int start_ssh(const char *host, const char *port) perror("failed to fork"); return -1; } else if (pid == 0) { + int argctr = 0; + char *ssh_args[sizeof(ssh_opts)/sizeof(struct opt) + 32]; + if (dup2(outpipe[0], 0) == -1 || dup2(inpipe[1], 1) == -1) { perror("failed to redirect input/output"); exit(1); @@ -426,8 +485,26 @@ static int start_ssh(const char *host, const char *port) close(inpipe[1]); close(outpipe[0]); close(outpipe[1]); - execlp("ssh", "ssh", "-2", "-x", "-a", "-oClearAllForwardings=yes", - host, "-s", "sftp", port ? "-p" : NULL, port, NULL); + + ssh_args[argctr++] = "ssh"; + ssh_args[argctr++] = "-2"; + ssh_args[argctr++] = "-x"; + ssh_args[argctr++] = "-a"; + ssh_args[argctr++] = "-oClearAllForwardings=yes"; + for (i = 0; ssh_opts[i].optname != NULL; i++) { + if (ssh_opts[i].present) { + char *val = ssh_opts[i].value; + char *sopt = g_strdup_printf("-o%s=%s", ssh_opts[i].optname, + val ? val : ""); + ssh_args[argctr++] = sopt; + } + } + ssh_args[argctr++] = host; + ssh_args[argctr++] = "-s"; + ssh_args[argctr++] = "sftp"; + ssh_args[argctr++] = NULL; + + execvp("ssh", ssh_args); exit(1); } close(inpipe[1]); @@ -1080,22 +1157,20 @@ static void usage(const char *progname) fprintf(stderr, "usage: %s [user@]host:[dir]] mountpoint [options]\n" "\n" - "SSH Options:\n" - " -p port remote port\n" - " -c port directly connect to port bypassing ssh\n" + "SSHFS Options:\n" + " -o directport=PORT directly connect to port bypassing ssh\n" + " -o SSHOPT=VAL ssh options (see man ssh_config(5))\n" "\n", progname); - fuse_main(2, (char **) fusehelp, NULL); + fuse_main(2, (char **) fusehelp, &sshfs_oper.oper); exit(1); } int main(int argc, char *argv[]) { char *host = NULL; - char *port = NULL; char *fsname; int res; int argctr; - int direct = 0; int newargc = 0; char **newargv = (char **) malloc((argc + 10) * sizeof(char *)); newargv[newargc++] = argv[0]; @@ -1104,22 +1179,6 @@ int main(int argc, char *argv[]) char *arg = argv[argctr]; if (arg[0] == '-') { switch (arg[1]) { - case 'c': - direct = 1; - /* fallthrough */ - - case 'p': - if (arg[2]) - port = &arg[2]; - else if (argctr + 1 < argc) - port = argv[++argctr]; - else { - fprintf(stderr, "missing argument to %s option\n", arg); - fprintf(stderr, "see `%s -h' for usage\n", argv[0]); - exit(1); - } - break; - case 'h': usage(argv[0]); break; @@ -1146,10 +1205,13 @@ int main(int argc, char *argv[]) else base_path = g_strdup(base_path); - if (!direct) - res = start_ssh(host, port); - else - res = connect_to(host, port); + process_options(&newargc, newargv, sshfs_opts, 1); + if (sshfs_opts[SOPT_DIRECTPORT].present) + res = connect_to(host, sshfs_opts[SOPT_DIRECTPORT].value); + else { + process_options(&newargc, newargv, ssh_opts, 0); + res = start_ssh(host); + } if (res == -1) exit(1); -- cgit v1.2.3