pastebin - collaborative debugging tool
rovema.kpaste.net RSS


msnfs41client: Patch for UNC custom port numbers
Posted by Anonymous on Mon 25th Sep 2023 14:31
raw | new post

  1. From 2fb49b2fc23545fe7c1e9c3a25904ab6daef6688 Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Mon, 25 Sep 2023 15:09:51 +0200
  4. Subject: [PATCH] Add support for NFS port number in UNC paths
  5.  
  6. Add support for NFS port numberrs in UNC paths, e.g.
  7. \\server@port\nfs4\path
  8.  
  9. This required a bit of rework of the original patch for non-standard
  10. NFS port numbers. We now pass the information via RFC 1738-style
  11. "hostport" values ("hostname@portnumber", instead of seperate
  12. "hostname" and "port" values), since the port is actually a part of
  13. the NFS server's location.
  14.  
  15. This also removes the limitation of the original patch that we
  16. can only have one NFS port number per machine, now the NFS port
  17. number is really per mount/UNC path.
  18.  
  19. ** Example usage:
  20. $ nfs_mount.exe -o sec=sys,port=2049 Z 'chickenmonster:/export/home/gisburn' #
  21. $ nfs_mount.exe -o sec=sys,port=49000 Z 'evilcorp66:/export/home/heistplanning' #
  22.  
  23. ** References:
  24. - How to specify ports in an UNC path:
  25. https://learn.microsoft.com/en-gb/windows/win32/api/davclnt/nf-davclnt-davgethttpfromuncpath
  26.  
  27. ** ToDo:
  28. - nfs_mount.exe should support nfs://-URLS per RFC 2224 ("NFS URL
  29. SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
  30. including port support (nfs://hostname@port/path/..., as
  31. Solaris/Illumos mount.nfs does.
  32.  
  33. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  34. ---
  35.  daemon/mount.c     | 45 ++++++++++++++++++++++++--------
  36.  daemon/upcall.h    |  3 +--
  37.  mount/mount.c      | 64 ++++++++++++++++++++++++++++++++++++++++++++--
  38.  mount/options.c    |  2 +-
  39.  mount/options.h    |  5 ++++
  40.  sys/nfs41_driver.c | 49 ++++++++++-------------------------
  41.  6 files changed, 118 insertions(+), 50 deletions(-)
  42.  
  43. diff --git a/daemon/mount.c b/daemon/mount.c
  44. index 3b18cba..fc6ec47 100644
  45. --- a/daemon/mount.c
  46. +++ b/daemon/mount.c
  47. @@ -35,10 +35,8 @@ static int parse_mount(unsigned char *buffer, uint32_t length, nfs41_upcall *upc
  48.      int status;
  49.      mount_upcall_args *args = &upcall->args.mount;
  50.  
  51. -    status = get_name(&buffer, &length, &args->hostname);
  52. +    status = get_name(&buffer, &length, &args->hostport);
  53.      if(status) goto out;
  54. -    status = safe_read(&buffer, &length, &args->port, sizeof(DWORD));
  55. -    if (status) goto out;
  56.      status = get_name(&buffer, &length, &args->path);
  57.      if(status) goto out;
  58.      status = safe_read(&buffer, &length, &args->sec_flavor, sizeof(DWORD));
  59. @@ -48,9 +46,10 @@ static int parse_mount(unsigned char *buffer, uint32_t length, nfs41_upcall *upc
  60.      status = safe_read(&buffer, &length, &args->wsize, sizeof(DWORD));
  61.      if (status) goto out;
  62.  
  63. -    dprintf(1, "parsing NFS41_MOUNT: srv_name=%s port=%d root=%s "
  64. -        "sec_flavor=%s rsize=%d wsize=%d\n", args->hostname, args->port, args->path,
  65. -        secflavorop2name(args->sec_flavor), args->rsize, args->wsize);
  66. +    dprintf(1, "parsing NFS41_MOUNT: hostport='%s' root='%s' "
  67. +        "sec_flavor='%s' rsize=%d wsize=%d\n",
  68. +        args->hostport, args->path, secflavorop2name(args->sec_flavor),
  69. +        args->rsize, args->wsize);
  70.      return status;
  71.  out:
  72.      dprintf(1, "parsing NFS41_MOUNT: failed %d\n", status);
  73. @@ -61,16 +60,41 @@ static int handle_mount(nfs41_upcall *upcall)
  74.  {
  75.      int status;
  76.      mount_upcall_args *args = &upcall->args.mount;
  77. +    char hostname[NFS41_HOSTNAME_LEN+1+32]; /* sizeof(hostname+'@'+integer) */
  78. +    char *s;
  79. +    int port = 0;
  80.      nfs41_abs_path path;
  81.      multi_addr4 addrs;
  82.      nfs41_root *root;
  83.      nfs41_client *client;
  84.      nfs41_path_fh file;
  85.  
  86. +    (void)strcpy_s(hostname, sizeof(hostname), args->hostport);
  87. +    if (s = strchr(hostname, '@')) {
  88. +        *s++ = '\0';
  89. +       port = atoi(s);
  90. +       if ((port < 1) || (port > 65535)) {
  91. +            status = ERROR_BAD_ARGUMENTS;
  92. +            eprintf("handle_mount: bad port number %d specified in "
  93. +                "hostport '%s'\n",
  94. +                port, args->hostport);
  95. +            goto out;
  96. +       }
  97. +
  98. +       dprintf(1, "handle_mount: hostname='%s', port=%d\n",
  99. +            hostname, port);
  100. +    } else {
  101. +        eprintf("handle_mount: port not specified in hostport '%s'\n",
  102. +            args->hostport);
  103. +        status = ERROR_BAD_NETPATH;
  104. +        goto out;
  105. +    }
  106. +
  107.      // resolve hostname,port
  108. -    status = nfs41_server_resolve(args->hostname, (unsigned short)args->port, &addrs);
  109. +    status = nfs41_server_resolve(hostname, (unsigned short)port, &addrs);
  110.      if (status) {
  111. -        eprintf("nfs41_server_resolve() failed with %d\n", status);
  112. +        eprintf("nfs41_server_resolve(hostname='%s', port=%d) failed with %d\n",
  113. +            hostname, port, status);
  114.          goto out;
  115.      }
  116.  
  117. @@ -80,10 +104,11 @@ static int handle_mount(nfs41_upcall *upcall)
  118.          root = upcall->root_ref;
  119.      } else {
  120.          // create root
  121. -        status = nfs41_root_create(args->hostname, args->port, args->sec_flavor,
  122. +        status = nfs41_root_create(hostname, port, args->sec_flavor,
  123.              args->wsize + WRITE_OVERHEAD, args->rsize + READ_OVERHEAD, &root);
  124.          if (status) {
  125. -            eprintf("nfs41_root_create() failed %d\n", status);
  126. +            eprintf("nfs41_root_create(hostname='%s', port=%d) failed %d\n",
  127. +                hostname, port, status);
  128.              goto out;
  129.          }
  130.          root->uid = upcall->uid;
  131. diff --git a/daemon/upcall.h b/daemon/upcall.h
  132. index 9cdc0a1..d224a6d 100644
  133. --- a/daemon/upcall.h
  134. +++ b/daemon/upcall.h
  135. @@ -29,8 +29,7 @@
  136.  
  137.  /* structures for upcall arguments */
  138.  typedef struct __mount_upcall_args {
  139. -    const char *hostname;
  140. -    DWORD       port;
  141. +    const char *hostport; /* hostname, or hostname@port */
  142.      const char *path;
  143.      DWORD       sec_flavor;
  144.      DWORD       rsize;
  145. diff --git a/mount/mount.c b/mount/mount.c
  146. index 6d8c8ee..48c7c88 100644
  147. --- a/mount/mount.c
  148. +++ b/mount/mount.c
  149. @@ -29,6 +29,7 @@
  150.  #include "nfs41_driver.h" /* NFS41_PROVIDER_NAME_A */
  151.  #include "options.h"
  152.  
  153. +#define MOUNT_CONFIG_NFS_PORT_DEFAULT   2049
  154.  
  155.  DWORD EnumMounts(
  156.      IN LPNETRESOURCE pContainer);
  157. @@ -214,9 +215,49 @@ static DWORD ParseRemoteName(
  158.  {
  159.      DWORD result = NO_ERROR;
  160.      LPTSTR pEnd;
  161. +    int port = 0;
  162. +    PFILE_FULL_EA_INFORMATION port_option_val;
  163. +    wchar_t srvname[MAX_PATH+1+32]; /* sizeof(hostname+'@'+integer) */
  164.      
  165. +    /*
  166. +     * gisburn: Fixme: Implement nfs://-URLS per RFC 2224 ("NFS URL
  167. +     * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
  168. +     * including port support (nfs://hostname@port/path/...)
  169. +     */
  170. +    if (!wcsncmp(pRemoteName, TEXT("nfs://"), 6)) {
  171. +        _ftprintf(stderr, TEXT("nfs://-URLs not supported yet.\n"));
  172. +        result = ERROR_NOT_SUPPORTED;
  173. +        goto out;
  174. +    }
  175. +
  176.      ConvertUnixSlashes(pRemoteName);
  177.  
  178. +    /*
  179. +     * Remote hostname should not contain a '@' since we use this
  180. +     * to communicate the NFSv4 port number below
  181. +     * Use $ nfs_mount.exe -o port=portnumber ... # instead
  182. +     */
  183. +    if (_tcsrchr(pRemoteName, TEXT('@'))) {
  184. +        _ftprintf(stderr, TEXT("Remote path should not contain '@', ")
  185. +           TEXT("use -o port=tcpportnum.\n"));
  186. +        result = ERROR_BAD_ARGUMENTS;
  187. +        goto out;
  188. +    }
  189. +
  190. +    if (FindOptionByName(TEXT("port"), pOptions, &port_option_val)) {
  191. +        wchar_t *port_value_wstr = (PTCH)(port_option_val->EaName + port_option_val->EaNameLength + sizeof(TCHAR));
  192. +
  193. +       port = _wtoi(port_value_wstr);
  194. +       if ((port < 1) || (port > 65535)) {
  195. +            result = ERROR_BAD_ARGUMENTS;
  196. +            goto out;
  197. +       }
  198. +    }
  199. +    else
  200. +    {
  201. +        port = MOUNT_CONFIG_NFS_PORT_DEFAULT;
  202. +    }
  203. +
  204.      /* fail if the server name doesn't end with :\ */
  205.      pEnd = _tcsrchr(pRemoteName, TEXT(':'));
  206.      if (pEnd == NULL || pEnd[1] != TEXT('\\')) {
  207. @@ -228,7 +269,12 @@ static DWORD ParseRemoteName(
  208.      *pEnd = TEXT('\0');
  209.      ++pEnd;
  210.  
  211. -    if (!InsertOption(TEXT("srvname"), pRemoteName, pOptions) ||
  212. +    /*
  213. +     * ALWAYS add port number to hostname, so UNC paths use it too
  214. +     */
  215. +    (void)swprintf(srvname, sizeof(srvname), TEXT("%s@%d"), pRemoteName, port);
  216. +
  217. +    if (!InsertOption(TEXT("srvname"), srvname, pOptions) ||
  218.          !InsertOption(TEXT("mntpt"), *pEnd ? pEnd : TEXT("\\"), pOptions)) {
  219.          result = ERROR_BAD_ARGUMENTS;
  220.          goto out;
  221. @@ -237,9 +283,23 @@ static DWORD ParseRemoteName(
  222.      result = StringCchCopy(pConnectionName, cchConnectionLen, TEXT("\\\\"));
  223.      if (FAILED(result))
  224.          goto out;
  225. -    result = StringCbCat(pConnectionName, cchConnectionLen, pRemoteName);
  226. +    result = StringCbCat(pConnectionName, cchConnectionLen, srvname);
  227. +    if (FAILED(result))
  228. +        goto out;
  229. +#ifdef FIXME_NOT_WORKING_YET
  230. +    /*
  231. +     * gisurn: fixme: why does this not work ?
  232. +     *
  233. +     * nfs_mount.exe should list UNC paths with \nfs4\ to distinguish
  234. +     * them from default SMB UNC paths
  235. +     *
  236. +     * $ nfs_mount.exe -o sec=sys,port=2049 Z 'derfwpc5131:/export/home/rmainz'
  237. +     * WNetUseConnection(Z:, \nfs4\export\home\rmainz) failed with error code 67.
  238. +     */
  239. +    result = StringCchCopy(pConnectionName, cchConnectionLen, TEXT("\\nfs4"));
  240.      if (FAILED(result))
  241.          goto out;
  242. +#endif /* FIXME_NOT_WORKING_YET */
  243.      if (*pEnd)
  244.          result = StringCchCat(pConnectionName, cchConnectionLen, pEnd);
  245.  
  246. diff --git a/mount/options.c b/mount/options.c
  247. index 2a2166f..73649cc 100644
  248. --- a/mount/options.c
  249. +++ b/mount/options.c
  250. @@ -53,7 +53,7 @@ void FreeMountOptions(
  251.      }
  252.  }
  253.  
  254. -static BOOL FindOptionByName(
  255. +BOOL FindOptionByName(
  256.      IN LPCTSTR Name,
  257.      IN PMOUNT_OPTION_LIST Options,
  258.      OUT PFILE_FULL_EA_INFORMATION* ppOption)
  259. diff --git a/mount/options.h b/mount/options.h
  260. index 29bc0fe..e23e986 100644
  261. --- a/mount/options.h
  262. +++ b/mount/options.h
  263. @@ -75,6 +75,11 @@ DWORD InitializeMountOptions(
  264.  void FreeMountOptions(
  265.      IN OUT PMOUNT_OPTION_LIST Options);
  266.  
  267. +BOOL FindOptionByName(
  268. +    IN LPCTSTR Name,
  269. +    IN PMOUNT_OPTION_LIST Options,
  270. +    OUT PFILE_FULL_EA_INFORMATION* ppOption);
  271. +
  272.  BOOL ParseMountOptions(
  273.      IN LPTSTR Arg,
  274.      IN OUT PMOUNT_OPTION_LIST Options);
  275. diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c
  276. index 01c0cd3..07e5b27 100644
  277. --- a/sys/nfs41_driver.c
  278. +++ b/sys/nfs41_driver.c
  279. @@ -165,8 +165,7 @@ typedef struct _updowncall_entry {
  280.      ULONGLONG ChangeTime;
  281.      union {
  282.          struct {
  283. -            PUNICODE_STRING srv_name;
  284. -           DWORD port;
  285. +            PUNICODE_STRING srv_name; /* hostname, or hostname@port */
  286.              PUNICODE_STRING root;
  287.              PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
  288.              DWORD sec_flavor;
  289. @@ -315,7 +314,6 @@ DECLARE_CONST_UNICODE_STRING(SLASH, L"\\");
  290.  DECLARE_CONST_UNICODE_STRING(EMPTY_STRING, L"");
  291.  
  292.  #define SERVER_NAME_BUFFER_SIZE         1024
  293. -#define MOUNT_CONFIG_NFS_PORT_DEFAULT   2049
  294.  #define MOUNT_CONFIG_RW_SIZE_MIN        1024
  295.  #define MOUNT_CONFIG_RW_SIZE_DEFAULT    1048576
  296.  #define MOUNT_CONFIG_RW_SIZE_MAX        1048576
  297. @@ -329,8 +327,7 @@ typedef struct _NFS41_MOUNT_CONFIG {
  298.      BOOLEAN write_thru;
  299.      BOOLEAN nocache;
  300.      WCHAR srv_buffer[SERVER_NAME_BUFFER_SIZE];
  301. -    UNICODE_STRING SrvName;
  302. -    DWORD Port;
  303. +    UNICODE_STRING SrvName; /* hostname, or hostname@port */
  304.      WCHAR mntpt_buffer[MAX_PATH];
  305.      UNICODE_STRING MntPt;
  306.      WCHAR sec_flavor[MAX_SEC_FLAVOR_LEN];
  307. @@ -625,8 +622,6 @@ NTSTATUS marshal_nfs41_mount(
  308.      }
  309.      status = marshall_unicode_as_utf8(&tmp, entry->u.Mount.srv_name);
  310.      if (status) goto out;
  311. -    RtlCopyMemory(tmp, &entry->u.Mount.port, sizeof(DWORD));
  312. -    tmp += sizeof(DWORD);
  313.      status = marshall_unicode_as_utf8(&tmp, entry->u.Mount.root);
  314.      if (status) goto out;
  315.      RtlCopyMemory(tmp, &entry->u.Mount.sec_flavor, sizeof(DWORD));
  316. @@ -638,9 +633,9 @@ NTSTATUS marshal_nfs41_mount(
  317.      *len = header_len;
  318.  
  319.  #ifdef DEBUG_MARSHAL_DETAIL
  320. -    DbgP("marshal_nfs41_mount: server name=%wZ port=%d mount point=%wZ "
  321. +    DbgP("marshal_nfs41_mount: server name=%wZ mount point=%wZ "
  322.           "sec_flavor=%s rsize=%d wsize=%d\n",
  323. -        entry->u.Mount.srv_name, entry->u.Mount.port, entry->u.Mount.root,
  324. +        entry->u.Mount.srv_name, entry->u.Mount.root,
  325.           secflavorop2name(entry->u.Mount.sec_flavor), entry->u.Mount.rsize,
  326.           entry->u.Mount.wsize);
  327.  #endif
  328. @@ -2572,15 +2567,14 @@ NTSTATUS nfs41_mount(
  329.  
  330.  #ifdef DEBUG_MOUNT
  331.      DbgEn();
  332. -    DbgP("Server Name %wZ Port %d Mount Point %wZ SecFlavor %d\n",
  333. -        &config->SrvName, config->Port, &config->MntPt, sec_flavor);
  334. +    DbgP("Server Name %wZ Mount Point %wZ SecFlavor %d\n",
  335. +        &config->SrvName, &config->MntPt, sec_flavor);
  336.  #endif
  337.      status = nfs41_UpcallCreate(NFS41_MOUNT, NULL, *session,
  338.          INVALID_HANDLE_VALUE, *version, &config->MntPt, &entry);
  339.      if (status) goto out;
  340.  
  341.      entry->u.Mount.srv_name = &config->SrvName;
  342. -    entry->u.Mount.port = config->Port;
  343.      entry->u.Mount.root = &config->MntPt;
  344.      entry->u.Mount.rsize = config->ReadSize;
  345.      entry->u.Mount.wsize = config->WriteSize;
  346. @@ -2613,7 +2607,6 @@ void nfs41_MountConfig_InitDefaults(
  347.  {
  348.      RtlZeroMemory(Config, sizeof(NFS41_MOUNT_CONFIG));
  349.  
  350. -    Config->Port = MOUNT_CONFIG_NFS_PORT_DEFAULT;
  351.      Config->ReadSize = MOUNT_CONFIG_RW_SIZE_DEFAULT;
  352.      Config->WriteSize = MOUNT_CONFIG_RW_SIZE_DEFAULT;
  353.      Config->ReadOnly = FALSE;
  354. @@ -2732,10 +2725,16 @@ NTSTATUS nfs41_MountConfig_ParseOptions(
  355.              else
  356.                  RtlCopyUnicodeString(&Config->SrvName, &usValue);
  357.          }
  358. +       /*
  359. +        * gisburn: fixme: for now we accept "port=" as dummy here
  360. +        * Technically nfs_mount.exe should filter this out. We leave
  361. +        * this in for backwards-compatibilty with our internal test
  362. +        * suite
  363. +        */
  364.          else if (wcsncmp(L"port", Name, NameLen) == 0) {
  365. +           DWORD dummy;
  366.              status = nfs41_MountConfig_ParseDword(Option, &usValue,
  367. -                &Config->Port, 1,
  368. -                65535);
  369. +                &dummy, 1, 65535);
  370.          }
  371.          else if (wcsncmp(L"mntpt", Name, NameLen) == 0) {
  372.              if (usValue.Length > Config->MntPt.MaximumLength)
  373. @@ -2922,10 +2921,6 @@ NTSTATUS nfs41_CreateVNetRoot(
  374.      }
  375.      nfs41_MountConfig_InitDefaults(Config);
  376.  
  377. -#define SAVE_PORT_HACK 1
  378. -#ifdef SAVE_PORT_HACK
  379. -    static DWORD saved_port = 0;
  380. -#endif /* SAVE_PORT_HACK */
  381.      if (pCreateNetRootContext->RxContext->Create.EaLength) {
  382.          /* Codepath for nfs_mount.exe */
  383.  
  384. @@ -2939,9 +2934,6 @@ NTSTATUS nfs41_CreateVNetRoot(
  385.          pVNetRootContext->read_only = Config->ReadOnly;
  386.          pVNetRootContext->write_thru = Config->write_thru;
  387.          pVNetRootContext->nocache = Config->nocache;        
  388. -#ifdef SAVE_PORT_HACK
  389. -       saved_port = Config->Port;
  390. -#endif /* SAVE_PORT_HACK */
  391.      } else {
  392.          /* Codepath for \\server:port\nfs4\path */
  393.  
  394. @@ -2951,19 +2943,6 @@ NTSTATUS nfs41_CreateVNetRoot(
  395.              pSrvCall->pSrvCallName->Length - sizeof(WCHAR);
  396.          Config->SrvName.MaximumLength =
  397.              pSrvCall->pSrvCallName->MaximumLength - sizeof(WCHAR);
  398. -        /*
  399. -         * gisburn: FIXME: Using |saved_port| here is wrong:
  400. -         * TCP port information should be encoded in the server name
  401. -         * (e.g. \\server@port\nfs4\path, to make sure we do not get
  402. -         * conflicts in case of (ssh) port forwarding
  403. -        * (see https://learn.microsoft.com/en-gb/windows/win32/api/davclnt/nf-davclnt-davgethttpfromuncpath
  404. -        * how to specify ports in an UNC path)
  405. -         */
  406. -#ifdef SAVE_PORT_HACK
  407. -       Config->Port = saved_port;
  408. -#else
  409. -#error Getting Config->Port information from UNC server name not implemented yet
  410. -#endif /* SAVE_PORT_HACK */
  411.      }
  412.      pVNetRootContext->MountPathLen = Config->MntPt.Length;
  413.      pVNetRootContext->timeout = Config->timeout;
  414. --
  415. 2.39.0

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.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at