- From 2fb49b2fc23545fe7c1e9c3a25904ab6daef6688 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Mon, 25 Sep 2023 15:09:51 +0200
- Subject: [PATCH] Add support for NFS port number in UNC paths
- Add support for NFS port numberrs in UNC paths, e.g.
- \\server@port\nfs4\path
- This required a bit of rework of the original patch for non-standard
- NFS port numbers. We now pass the information via RFC 1738-style
- "hostport" values ("hostname@portnumber", instead of seperate
- "hostname" and "port" values), since the port is actually a part of
- the NFS server's location.
- This also removes the limitation of the original patch that we
- can only have one NFS port number per machine, now the NFS port
- number is really per mount/UNC path.
- ** Example usage:
- $ nfs_mount.exe -o sec=sys,port=2049 Z 'chickenmonster:/export/home/gisburn' #
- $ nfs_mount.exe -o sec=sys,port=49000 Z 'evilcorp66:/export/home/heistplanning' #
- ** References:
- - How to specify ports in an UNC path:
- https://learn.microsoft.com/en-gb/windows/win32/api/davclnt/nf-davclnt-davgethttpfromuncpath
- ** ToDo:
- - nfs_mount.exe should support nfs://-URLS per RFC 2224 ("NFS URL
- SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
- including port support (nfs://hostname@port/path/..., as
- Solaris/Illumos mount.nfs does.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/mount.c | 45 ++++++++++++++++++++++++--------
- daemon/upcall.h | 3 +--
- mount/mount.c | 64 ++++++++++++++++++++++++++++++++++++++++++++--
- mount/options.c | 2 +-
- mount/options.h | 5 ++++
- sys/nfs41_driver.c | 49 ++++++++++-------------------------
- 6 files changed, 118 insertions(+), 50 deletions(-)
- diff --git a/daemon/mount.c b/daemon/mount.c
- index 3b18cba..fc6ec47 100644
- --- a/daemon/mount.c
- +++ b/daemon/mount.c
- @@ -35,10 +35,8 @@ static int parse_mount(unsigned char *buffer, uint32_t length, nfs41_upcall *upc
- int status;
- mount_upcall_args *args = &upcall->args.mount;
- - status = get_name(&buffer, &length, &args->hostname);
- + status = get_name(&buffer, &length, &args->hostport);
- if(status) goto out;
- - status = safe_read(&buffer, &length, &args->port, sizeof(DWORD));
- - if (status) goto out;
- status = get_name(&buffer, &length, &args->path);
- if(status) goto out;
- status = safe_read(&buffer, &length, &args->sec_flavor, sizeof(DWORD));
- @@ -48,9 +46,10 @@ static int parse_mount(unsigned char *buffer, uint32_t length, nfs41_upcall *upc
- status = safe_read(&buffer, &length, &args->wsize, sizeof(DWORD));
- if (status) goto out;
- - dprintf(1, "parsing NFS41_MOUNT: srv_name=%s port=%d root=%s "
- - "sec_flavor=%s rsize=%d wsize=%d\n", args->hostname, args->port, args->path,
- - secflavorop2name(args->sec_flavor), args->rsize, args->wsize);
- + dprintf(1, "parsing NFS41_MOUNT: hostport='%s' root='%s' "
- + "sec_flavor='%s' rsize=%d wsize=%d\n",
- + args->hostport, args->path, secflavorop2name(args->sec_flavor),
- + args->rsize, args->wsize);
- return status;
- out:
- dprintf(1, "parsing NFS41_MOUNT: failed %d\n", status);
- @@ -61,16 +60,41 @@ static int handle_mount(nfs41_upcall *upcall)
- {
- int status;
- mount_upcall_args *args = &upcall->args.mount;
- + char hostname[NFS41_HOSTNAME_LEN+1+32]; /* sizeof(hostname+'@'+integer) */
- + char *s;
- + int port = 0;
- nfs41_abs_path path;
- multi_addr4 addrs;
- nfs41_root *root;
- nfs41_client *client;
- nfs41_path_fh file;
- + (void)strcpy_s(hostname, sizeof(hostname), args->hostport);
- + if (s = strchr(hostname, '@')) {
- + *s++ = '\0';
- + port = atoi(s);
- + if ((port < 1) || (port > 65535)) {
- + status = ERROR_BAD_ARGUMENTS;
- + eprintf("handle_mount: bad port number %d specified in "
- + "hostport '%s'\n",
- + port, args->hostport);
- + goto out;
- + }
- +
- + dprintf(1, "handle_mount: hostname='%s', port=%d\n",
- + hostname, port);
- + } else {
- + eprintf("handle_mount: port not specified in hostport '%s'\n",
- + args->hostport);
- + status = ERROR_BAD_NETPATH;
- + goto out;
- + }
- +
- // resolve hostname,port
- - status = nfs41_server_resolve(args->hostname, (unsigned short)args->port, &addrs);
- + status = nfs41_server_resolve(hostname, (unsigned short)port, &addrs);
- if (status) {
- - eprintf("nfs41_server_resolve() failed with %d\n", status);
- + eprintf("nfs41_server_resolve(hostname='%s', port=%d) failed with %d\n",
- + hostname, port, status);
- goto out;
- }
- @@ -80,10 +104,11 @@ static int handle_mount(nfs41_upcall *upcall)
- root = upcall->root_ref;
- } else {
- // create root
- - status = nfs41_root_create(args->hostname, args->port, args->sec_flavor,
- + status = nfs41_root_create(hostname, port, args->sec_flavor,
- args->wsize + WRITE_OVERHEAD, args->rsize + READ_OVERHEAD, &root);
- if (status) {
- - eprintf("nfs41_root_create() failed %d\n", status);
- + eprintf("nfs41_root_create(hostname='%s', port=%d) failed %d\n",
- + hostname, port, status);
- goto out;
- }
- root->uid = upcall->uid;
- diff --git a/daemon/upcall.h b/daemon/upcall.h
- index 9cdc0a1..d224a6d 100644
- --- a/daemon/upcall.h
- +++ b/daemon/upcall.h
- @@ -29,8 +29,7 @@
- /* structures for upcall arguments */
- typedef struct __mount_upcall_args {
- - const char *hostname;
- - DWORD port;
- + const char *hostport; /* hostname, or hostname@port */
- const char *path;
- DWORD sec_flavor;
- DWORD rsize;
- diff --git a/mount/mount.c b/mount/mount.c
- index 6d8c8ee..48c7c88 100644
- --- a/mount/mount.c
- +++ b/mount/mount.c
- @@ -29,6 +29,7 @@
- #include "nfs41_driver.h" /* NFS41_PROVIDER_NAME_A */
- #include "options.h"
- +#define MOUNT_CONFIG_NFS_PORT_DEFAULT 2049
- DWORD EnumMounts(
- IN LPNETRESOURCE pContainer);
- @@ -214,9 +215,49 @@ static DWORD ParseRemoteName(
- {
- DWORD result = NO_ERROR;
- LPTSTR pEnd;
- + int port = 0;
- + PFILE_FULL_EA_INFORMATION port_option_val;
- + wchar_t srvname[MAX_PATH+1+32]; /* sizeof(hostname+'@'+integer) */
- + /*
- + * gisburn: Fixme: Implement nfs://-URLS per RFC 2224 ("NFS URL
- + * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
- + * including port support (nfs://hostname@port/path/...)
- + */
- + if (!wcsncmp(pRemoteName, TEXT("nfs://"), 6)) {
- + _ftprintf(stderr, TEXT("nfs://-URLs not supported yet.\n"));
- + result = ERROR_NOT_SUPPORTED;
- + goto out;
- + }
- +
- ConvertUnixSlashes(pRemoteName);
- + /*
- + * Remote hostname should not contain a '@' since we use this
- + * to communicate the NFSv4 port number below
- + * Use $ nfs_mount.exe -o port=portnumber ... # instead
- + */
- + if (_tcsrchr(pRemoteName, TEXT('@'))) {
- + _ftprintf(stderr, TEXT("Remote path should not contain '@', ")
- + TEXT("use -o port=tcpportnum.\n"));
- + result = ERROR_BAD_ARGUMENTS;
- + goto out;
- + }
- +
- + if (FindOptionByName(TEXT("port"), pOptions, &port_option_val)) {
- + wchar_t *port_value_wstr = (PTCH)(port_option_val->EaName + port_option_val->EaNameLength + sizeof(TCHAR));
- +
- + port = _wtoi(port_value_wstr);
- + if ((port < 1) || (port > 65535)) {
- + result = ERROR_BAD_ARGUMENTS;
- + goto out;
- + }
- + }
- + else
- + {
- + port = MOUNT_CONFIG_NFS_PORT_DEFAULT;
- + }
- +
- /* fail if the server name doesn't end with :\ */
- pEnd = _tcsrchr(pRemoteName, TEXT(':'));
- if (pEnd == NULL || pEnd[1] != TEXT('\\')) {
- @@ -228,7 +269,12 @@ static DWORD ParseRemoteName(
- *pEnd = TEXT('\0');
- ++pEnd;
- - if (!InsertOption(TEXT("srvname"), pRemoteName, pOptions) ||
- + /*
- + * ALWAYS add port number to hostname, so UNC paths use it too
- + */
- + (void)swprintf(srvname, sizeof(srvname), TEXT("%s@%d"), pRemoteName, port);
- +
- + if (!InsertOption(TEXT("srvname"), srvname, pOptions) ||
- !InsertOption(TEXT("mntpt"), *pEnd ? pEnd : TEXT("\\"), pOptions)) {
- result = ERROR_BAD_ARGUMENTS;
- goto out;
- @@ -237,9 +283,23 @@ static DWORD ParseRemoteName(
- result = StringCchCopy(pConnectionName, cchConnectionLen, TEXT("\\\\"));
- if (FAILED(result))
- goto out;
- - result = StringCbCat(pConnectionName, cchConnectionLen, pRemoteName);
- + result = StringCbCat(pConnectionName, cchConnectionLen, srvname);
- + if (FAILED(result))
- + goto out;
- +#ifdef FIXME_NOT_WORKING_YET
- + /*
- + * gisurn: fixme: why does this not work ?
- + *
- + * nfs_mount.exe should list UNC paths with \nfs4\ to distinguish
- + * them from default SMB UNC paths
- + *
- + * $ nfs_mount.exe -o sec=sys,port=2049 Z 'derfwpc5131:/export/home/rmainz'
- + * WNetUseConnection(Z:, \nfs4\export\home\rmainz) failed with error code 67.
- + */
- + result = StringCchCopy(pConnectionName, cchConnectionLen, TEXT("\\nfs4"));
- if (FAILED(result))
- goto out;
- +#endif /* FIXME_NOT_WORKING_YET */
- if (*pEnd)
- result = StringCchCat(pConnectionName, cchConnectionLen, pEnd);
- diff --git a/mount/options.c b/mount/options.c
- index 2a2166f..73649cc 100644
- --- a/mount/options.c
- +++ b/mount/options.c
- @@ -53,7 +53,7 @@ void FreeMountOptions(
- }
- }
- -static BOOL FindOptionByName(
- +BOOL FindOptionByName(
- IN LPCTSTR Name,
- IN PMOUNT_OPTION_LIST Options,
- OUT PFILE_FULL_EA_INFORMATION* ppOption)
- diff --git a/mount/options.h b/mount/options.h
- index 29bc0fe..e23e986 100644
- --- a/mount/options.h
- +++ b/mount/options.h
- @@ -75,6 +75,11 @@ DWORD InitializeMountOptions(
- void FreeMountOptions(
- IN OUT PMOUNT_OPTION_LIST Options);
- +BOOL FindOptionByName(
- + IN LPCTSTR Name,
- + IN PMOUNT_OPTION_LIST Options,
- + OUT PFILE_FULL_EA_INFORMATION* ppOption);
- +
- BOOL ParseMountOptions(
- IN LPTSTR Arg,
- IN OUT PMOUNT_OPTION_LIST Options);
- diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c
- index 01c0cd3..07e5b27 100644
- --- a/sys/nfs41_driver.c
- +++ b/sys/nfs41_driver.c
- @@ -165,8 +165,7 @@ typedef struct _updowncall_entry {
- ULONGLONG ChangeTime;
- union {
- struct {
- - PUNICODE_STRING srv_name;
- - DWORD port;
- + PUNICODE_STRING srv_name; /* hostname, or hostname@port */
- PUNICODE_STRING root;
- PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
- DWORD sec_flavor;
- @@ -315,7 +314,6 @@ DECLARE_CONST_UNICODE_STRING(SLASH, L"\\");
- DECLARE_CONST_UNICODE_STRING(EMPTY_STRING, L"");
- #define SERVER_NAME_BUFFER_SIZE 1024
- -#define MOUNT_CONFIG_NFS_PORT_DEFAULT 2049
- #define MOUNT_CONFIG_RW_SIZE_MIN 1024
- #define MOUNT_CONFIG_RW_SIZE_DEFAULT 1048576
- #define MOUNT_CONFIG_RW_SIZE_MAX 1048576
- @@ -329,8 +327,7 @@ typedef struct _NFS41_MOUNT_CONFIG {
- BOOLEAN write_thru;
- BOOLEAN nocache;
- WCHAR srv_buffer[SERVER_NAME_BUFFER_SIZE];
- - UNICODE_STRING SrvName;
- - DWORD Port;
- + UNICODE_STRING SrvName; /* hostname, or hostname@port */
- WCHAR mntpt_buffer[MAX_PATH];
- UNICODE_STRING MntPt;
- WCHAR sec_flavor[MAX_SEC_FLAVOR_LEN];
- @@ -625,8 +622,6 @@ NTSTATUS marshal_nfs41_mount(
- }
- status = marshall_unicode_as_utf8(&tmp, entry->u.Mount.srv_name);
- if (status) goto out;
- - RtlCopyMemory(tmp, &entry->u.Mount.port, sizeof(DWORD));
- - tmp += sizeof(DWORD);
- status = marshall_unicode_as_utf8(&tmp, entry->u.Mount.root);
- if (status) goto out;
- RtlCopyMemory(tmp, &entry->u.Mount.sec_flavor, sizeof(DWORD));
- @@ -638,9 +633,9 @@ NTSTATUS marshal_nfs41_mount(
- *len = header_len;
- #ifdef DEBUG_MARSHAL_DETAIL
- - DbgP("marshal_nfs41_mount: server name=%wZ port=%d mount point=%wZ "
- + DbgP("marshal_nfs41_mount: server name=%wZ mount point=%wZ "
- "sec_flavor=%s rsize=%d wsize=%d\n",
- - entry->u.Mount.srv_name, entry->u.Mount.port, entry->u.Mount.root,
- + entry->u.Mount.srv_name, entry->u.Mount.root,
- secflavorop2name(entry->u.Mount.sec_flavor), entry->u.Mount.rsize,
- entry->u.Mount.wsize);
- #endif
- @@ -2572,15 +2567,14 @@ NTSTATUS nfs41_mount(
- #ifdef DEBUG_MOUNT
- DbgEn();
- - DbgP("Server Name %wZ Port %d Mount Point %wZ SecFlavor %d\n",
- - &config->SrvName, config->Port, &config->MntPt, sec_flavor);
- + DbgP("Server Name %wZ Mount Point %wZ SecFlavor %d\n",
- + &config->SrvName, &config->MntPt, sec_flavor);
- #endif
- status = nfs41_UpcallCreate(NFS41_MOUNT, NULL, *session,
- INVALID_HANDLE_VALUE, *version, &config->MntPt, &entry);
- if (status) goto out;
- entry->u.Mount.srv_name = &config->SrvName;
- - entry->u.Mount.port = config->Port;
- entry->u.Mount.root = &config->MntPt;
- entry->u.Mount.rsize = config->ReadSize;
- entry->u.Mount.wsize = config->WriteSize;
- @@ -2613,7 +2607,6 @@ void nfs41_MountConfig_InitDefaults(
- {
- RtlZeroMemory(Config, sizeof(NFS41_MOUNT_CONFIG));
- - Config->Port = MOUNT_CONFIG_NFS_PORT_DEFAULT;
- Config->ReadSize = MOUNT_CONFIG_RW_SIZE_DEFAULT;
- Config->WriteSize = MOUNT_CONFIG_RW_SIZE_DEFAULT;
- Config->ReadOnly = FALSE;
- @@ -2732,10 +2725,16 @@ NTSTATUS nfs41_MountConfig_ParseOptions(
- else
- RtlCopyUnicodeString(&Config->SrvName, &usValue);
- }
- + /*
- + * gisburn: fixme: for now we accept "port=" as dummy here
- + * Technically nfs_mount.exe should filter this out. We leave
- + * this in for backwards-compatibilty with our internal test
- + * suite
- + */
- else if (wcsncmp(L"port", Name, NameLen) == 0) {
- + DWORD dummy;
- status = nfs41_MountConfig_ParseDword(Option, &usValue,
- - &Config->Port, 1,
- - 65535);
- + &dummy, 1, 65535);
- }
- else if (wcsncmp(L"mntpt", Name, NameLen) == 0) {
- if (usValue.Length > Config->MntPt.MaximumLength)
- @@ -2922,10 +2921,6 @@ NTSTATUS nfs41_CreateVNetRoot(
- }
- nfs41_MountConfig_InitDefaults(Config);
- -#define SAVE_PORT_HACK 1
- -#ifdef SAVE_PORT_HACK
- - static DWORD saved_port = 0;
- -#endif /* SAVE_PORT_HACK */
- if (pCreateNetRootContext->RxContext->Create.EaLength) {
- /* Codepath for nfs_mount.exe */
- @@ -2939,9 +2934,6 @@ NTSTATUS nfs41_CreateVNetRoot(
- pVNetRootContext->read_only = Config->ReadOnly;
- pVNetRootContext->write_thru = Config->write_thru;
- pVNetRootContext->nocache = Config->nocache;
- -#ifdef SAVE_PORT_HACK
- - saved_port = Config->Port;
- -#endif /* SAVE_PORT_HACK */
- } else {
- /* Codepath for \\server:port\nfs4\path */
- @@ -2951,19 +2943,6 @@ NTSTATUS nfs41_CreateVNetRoot(
- pSrvCall->pSrvCallName->Length - sizeof(WCHAR);
- Config->SrvName.MaximumLength =
- pSrvCall->pSrvCallName->MaximumLength - sizeof(WCHAR);
- - /*
- - * gisburn: FIXME: Using |saved_port| here is wrong:
- - * TCP port information should be encoded in the server name
- - * (e.g. \\server@port\nfs4\path, to make sure we do not get
- - * conflicts in case of (ssh) port forwarding
- - * (see https://learn.microsoft.com/en-gb/windows/win32/api/davclnt/nf-davclnt-davgethttpfromuncpath
- - * how to specify ports in an UNC path)
- - */
- -#ifdef SAVE_PORT_HACK
- - Config->Port = saved_port;
- -#else
- -#error Getting Config->Port information from UNC server name not implemented yet
- -#endif /* SAVE_PORT_HACK */
- }
- pVNetRootContext->MountPathLen = Config->MntPt.Length;
- pVNetRootContext->timeout = Config->timeout;
- --
- 2.39.0
msnfs41client: Patch for UNC custom port numbers
Posted by Anonymous on Mon 25th Sep 2023 14:31
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.