1
0
mirror of https://github.com/winfsp/sshfs-win.git synced 2025-04-18 23:04:01 +03:00
sshfs-win/sshfs-win.c
LeadroyaL ace9c17561
Remove default ssh port
reformat code style
2023-03-14 21:02:11 +08:00

358 lines
9.2 KiB
C

/**
* sshfs-win.c
*
* Copyright 2015-2021 Bill Zissimopoulos
*/
/*
* This file is part of SSHFS-Win.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <assert.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static char *sshfs = "/usr/bin/sshfs.exe";
#if 0
#define execve pr_execv
static void pr_execv(const char *path, char *argv[], ...)
{
fprintf(stderr, "%s\n", path);
for (; 0 != *argv; argv++)
fprintf(stderr, " %s\n", *argv);
}
#endif
static void usage(void)
{
fprintf(stderr,
"usage: sshfs-win cmd SSHFS_COMMAND_LINE\n"
" SSHFS_COMMAND_LINE command line to pass to sshfs\n"
"\n"
"usage: sshfs-win svc PREFIX X: [LOCUSER] [SSHFS_OPTIONS]\n"
" PREFIX Windows UNC prefix (note single backslash)\n"
" \\sshfs[.SUFFIX]\\[LOCUSER=]REMUSER@HOST[!PORT][\\PATH]\n"
" \\sshfs[.SUFFIX]\\alias[\\PATH]\n"
" sshfs: remote user home dir\n"
" sshfs.r: remote root dir\n"
" sshfs.k: remote user home dir with key authentication\n"
" sshfs.kr: remote root dir with key authentication\n"
" LOCUSER local user (DOMAIN+USERNAME)\n"
" REMUSER remote user\n"
" HOST remote host\n"
" PORT remote port\n"
" PATH remote path (relative to remote home or root)\n"
" X: mount drive\n"
" SSHFS_OPTIONS additional options to pass to SSHFS\n");
exit(2);
}
static void concat_argv(char *dst[], char *src[])
{
for (; 0 != *dst; dst++)
;
for (; 0 != (*dst = *src); dst++, src++)
;
}
static void opt_escape(const char *opt, char *escaped, size_t size)
{
const char *p = opt;
char *q = escaped, *endq = escaped + size;
for (; *p && endq > q + 1; p++, q++)
{
if (',' == *p || '\\' == *p)
*q++ = '\\';
*q = *p;
}
*q = '\0';
}
static uint32_t reg_get(const char *cls, const char *name)
{
char regpath[256];
int regfd;
uint32_t value = -1;
snprintf(regpath, sizeof regpath,
"/proc/registry32/HKEY_LOCAL_MACHINE/Software/WinFsp/Services/%s/%s", cls, name);
regfd = open(regpath, O_RDONLY);
if (-1 != regfd)
{
if (sizeof value != read(regfd, &value, sizeof value))
value = -1;
close(regfd);
}
return value;
}
static int fixenv_and_execv(const char *path, char **argv)
{
static char *default_environ[] = { "PATH=/bin", 0 };
extern char **environ;
char **oldenv, **oldp;
char **newenv, **newp;
size_t len, siz;
int res;
oldenv = environ;
siz = 0;
for (oldp = oldenv; *oldp; oldp++)
{
if (0 == strncmp(*oldp, "PATH=", 5))
{
len = strlen(*oldp + 5);
siz += len + sizeof "PATH=/usr/bin:";
}
else
{
len = strlen(*oldp);
siz += len + 1;
}
}
oldp++;
newenv = malloc((oldp - oldenv) * sizeof(char *) + siz);
if (0 != newenv)
{
siz = (oldp - oldenv) * sizeof(char *);
for (oldp = oldenv, newp = newenv; *oldp; oldp++, newp++)
{
*newp = (char *)newenv + siz;
if (0 == strncmp(*oldp, "PATH=", 5))
{
len = strlen(*oldp + 5);
siz += len + sizeof "PATH=/usr/bin:";
memcpy(*newp, "PATH=/usr/bin:", sizeof "PATH=/usr/bin:" - 1);
memcpy(*newp + sizeof "PATH=/usr/bin:" - 1, *oldp + 5, len + 1);
}
else
{
len = strlen(*oldp);
siz += len + 1;
memcpy(*newp, *oldp, len + 1);
}
}
*newp = 0;
}
else
{
newenv = default_environ;
newp = newenv + 1;
}
#if 1
res = execve(path, argv, newenv);
#else
char **p;
for (p = newenv; *p; p++)
printf("%s\n", *p);
assert(newp == p);
#endif
if (newenv != default_environ)
free(newenv);
return res;
}
static int do_cmd(int argc, char *argv[])
{
if (200 < argc)
usage();
char *sshfs_argv[256] =
{
sshfs, 0,
};
concat_argv(sshfs_argv, argv + 1);
fixenv_and_execv(sshfs, sshfs_argv);
return 1;
}
static int do_svc(int argc, char *argv[])
{
#define SSHFS_ARGS \
"-f", \
"-orellinks", \
"-ofstypename=SSHFS", \
"-o ssh_command=/usr/bin/ssh.exe", \
"-oUserKnownHostsFile=/dev/null", \
"-oStrictHostKeyChecking=no"
if (3 > argc || 200 < argc)
usage();
struct passwd *passwd = 0;
char idmap[64], authmeth[64 + 1024], volpfx[256], portopt[256], remote[256];
char escaped[1024];
char *cls, *locuser, *locuser_nodom, *userhost, *port, *root, *path, *p;
snprintf(volpfx, sizeof volpfx, "--VolumePrefix=%s", argv[1]);
/* translate backslash to forward slash */
for (p = argv[1]; *p; p++)
if ('\\' == *p)
*p = '/';
/* skip class name */
p = argv[1];
while ('/' == *p)
p++;
cls = p;
while (*p && '/' != *p)
p++;
if (*p)
*p++ = '\0';
while ('/' == *p)
p++;
root = 1 == reg_get(cls, "sshfs.rootdir") ? "/" : "";
/* parse instance name (syntax: [locuser=]user@host[!port]) */
locuser = locuser_nodom = 0;
userhost = p;
port = 0;
while (*p && '/' != *p)
{
if ('=' == *p)
{
*p = '\0';
locuser = userhost;
userhost = p + 1;
}
else if ('!' == *p)
{
*p = '\0';
port = p + 1;
}
p++;
}
if (*p)
*p++ = '\0';
path = p;
if (port != 0)
{
opt_escape(port, escaped, sizeof escaped);
snprintf(portopt, sizeof portopt, "-oPort=%s", escaped);
}
else
{
portopt[0] = '\0';
}
snprintf(remote, sizeof remote, "%s:%s%s", userhost, root, path);
/* get local user name */
if (0 == locuser)
{
if (3 >= argc)
{
p = userhost;
while (*p && '@' != *p)
p++;
if (*p)
{
*p = '\0';
locuser = userhost;
}
}
else
{
locuser = argv[3];
/* the Cygwin runtime does not remove double quotes around args with non-ASCII chars */
if (locuser[0] == '"')
{
size_t len = strlen(locuser);
if (len >= 2 && locuser[len - 1] == '"')
{
locuser[len - 1] = '\0'; /* remove the trailing quote... */
++locuser; /* ...and the heading one */
}
}
/* translate backslash to '+' */
for (p = locuser; *p; p++)
if ('\\' == *p)
{
*p = '+';
locuser_nodom = p + 1;
}
}
}
snprintf(idmap, sizeof idmap, "-ouid=-1,gid=-1");
if (0 != locuser)
{
/* get uid/gid from local user name */
passwd = getpwnam(locuser);
if (0 == passwd && 0 != locuser_nodom)
passwd = getpwnam(locuser_nodom);
if (0 != passwd)
snprintf(idmap, sizeof idmap, "-ouid=%d,gid=%d", passwd->pw_uid, passwd->pw_gid);
}
if (1 == reg_get(cls, "Credentials"))
snprintf(authmeth, sizeof authmeth,
"-opassword_stdin,password_stdout");
else if (0 != passwd)
{
opt_escape(passwd->pw_dir, escaped, sizeof escaped);
snprintf(authmeth, sizeof authmeth,
"-oPreferredAuthentications=publickey,IdentityFile=\"%s/.ssh/id_rsa\"", escaped);
}
else
snprintf(authmeth, sizeof authmeth,
"-oPreferredAuthentications=publickey");
char *sshfs_argv[256] =
{
sshfs, SSHFS_ARGS, idmap, authmeth, volpfx, portopt, remote, argv[2], 0,
};
if ('\0' == portopt[0])
{
/* if not passing a port option, remove it from sshfs_argv */
int portopt_idx = 0;
while (sshfs_argv[portopt_idx] != portopt)
portopt_idx++;
while (sshfs_argv[portopt_idx] != 0)
{
sshfs_argv[portopt_idx] = sshfs_argv[portopt_idx + 1];
portopt_idx++;
}
}
if (4 <= argc)
concat_argv(sshfs_argv, argv + 4);
fixenv_and_execv(sshfs, sshfs_argv);
return 1;
#undef SSHFS_ARGS
}
int main(int argc, char *argv[])
{
const char *mode = argv[1];
if (0 != mode && 0 == strcmp("cmd", mode))
return do_cmd(argc - 1, argv + 1);
if (0 != mode && 0 == strcmp("svc", mode))
return do_svc(argc - 1, argv + 1);
usage();
return 1;
}