pastebin - collaborative debugging tool
rovema.kpaste.net RSS


msnfs41client: Patches for Cygwin idmapper rework, 2023-11-28
Posted by Anonymous on Tue 28th Nov 2023 18:02
raw | new post

  1. From bc771d7a6dbc05549488846ad81d4185b56201f9 Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Tue, 28 Nov 2023 12:35:10 +0100
  4. Subject: [PATCH 1/2] daemon: Rework Cygwin idmapper code to use a script
  5.  instead of getent
  6.  
  7. Rework the Cygwin idmapper code to use a script instead of
  8. /usr/bin/getent, as this is much more flexible.
  9.  
  10. The feature is still work-in-progress, and requires that
  11. NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN is set in
  12. sys/nfs41_build_features.h
  13.  
  14. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  15. ---
  16. build.vc19/nfsd/nfsd.vcxproj         |   5 +
  17.  build.vc19/nfsd/nfsd.vcxproj.filters |  15 +
  18.  cygwin_idmapper.ksh                  | 124 +++++++
  19.  daemon/acl.c                         | 305 +---------------
  20.  daemon/cpvparser1.c                  | 361 +++++++++++++++++++
  21.  daemon/cpvparser1.h                  |  64 ++++
  22.  daemon/idmap.c                       | 247 +------------
  23.  daemon/idmap.h                       |   6 +
  24.  daemon/idmap_cygwin.c                | 261 ++++++++++++++
  25.  daemon/nfs41_daemon.c                |   2 +
  26.  daemon/sid.c                         | 500 +++++++++++++++++++++++++++
  27.  daemon/sid.h                         |  35 ++
  28.  12 files changed, 1382 insertions(+), 543 deletions(-)
  29.  create mode 100644 cygwin_idmapper.ksh
  30.  create mode 100644 daemon/cpvparser1.c
  31.  create mode 100644 daemon/cpvparser1.h
  32.  create mode 100644 daemon/idmap_cygwin.c
  33.  create mode 100644 daemon/sid.c
  34.  create mode 100644 daemon/sid.h
  35.  
  36. diff --git a/build.vc19/nfsd/nfsd.vcxproj b/build.vc19/nfsd/nfsd.vcxproj
  37. index 047f02d..e374d66 100644
  38. --- a/build.vc19/nfsd/nfsd.vcxproj
  39. +++ b/build.vc19/nfsd/nfsd.vcxproj
  40. @@ -153,11 +153,13 @@
  41.      <ClCompile Include="..\..\daemon\acl.c" />
  42.      <ClCompile Include="..\..\daemon\callback_server.c" />
  43.      <ClCompile Include="..\..\daemon\callback_xdr.c" />
  44. +    <ClCompile Include="..\..\daemon\cpvparser1.c" />
  45.      <ClCompile Include="..\..\daemon\daemon_debug.c" />
  46.      <ClCompile Include="..\..\daemon\delegation.c" />
  47.      <ClCompile Include="..\..\daemon\ea.c" />
  48.      <ClCompile Include="..\..\daemon\getattr.c" />
  49.      <ClCompile Include="..\..\daemon\idmap.c" />
  50. +    <ClCompile Include="..\..\daemon\idmap_cygwin.c" />
  51.      <ClCompile Include="..\..\daemon\lock.c" />
  52.      <ClCompile Include="..\..\daemon\lookup.c" />
  53.      <ClCompile Include="..\..\daemon\mount.c" />
  54. @@ -182,12 +184,14 @@
  55.      <ClCompile Include="..\..\daemon\recovery.c" />
  56.      <ClCompile Include="..\..\daemon\service.c" />
  57.      <ClCompile Include="..\..\daemon\setattr.c" />
  58. +    <ClCompile Include="..\..\daemon\sid.c" />
  59.      <ClCompile Include="..\..\daemon\symlink.c" />
  60.      <ClCompile Include="..\..\daemon\upcall.c" />
  61.      <ClCompile Include="..\..\daemon\util.c" />
  62.      <ClCompile Include="..\..\daemon\volume.c" />
  63.    </ItemGroup>
  64.    <ItemGroup>
  65. +    <ClInclude Include="..\..\daemon\cpvparser1.h" />
  66.      <ClInclude Include="..\..\daemon\daemon_debug.h" />
  67.      <ClInclude Include="..\..\daemon\delegation.h" />
  68.      <ClInclude Include="..\..\daemon\from_kernel.h" />
  69. @@ -204,6 +208,7 @@
  70.      <ClInclude Include="..\..\daemon\pnfs.h" />
  71.      <ClInclude Include="..\..\daemon\recovery.h" />
  72.      <ClInclude Include="..\..\daemon\service.h" />
  73. +    <ClInclude Include="..\..\daemon\sid.h" />
  74.      <ClInclude Include="..\..\daemon\tree.h" />
  75.      <ClInclude Include="..\..\daemon\upcall.h" />
  76.      <ClInclude Include="..\..\daemon\util.h" />
  77. diff --git a/build.vc19/nfsd/nfsd.vcxproj.filters b/build.vc19/nfsd/nfsd.vcxproj.filters
  78. index d0ebad9..995410e 100644
  79. --- a/build.vc19/nfsd/nfsd.vcxproj.filters
  80. +++ b/build.vc19/nfsd/nfsd.vcxproj.filters
  81. @@ -24,6 +24,9 @@
  82.      <ClCompile Include="..\..\daemon\callback_xdr.c">
  83.        <Filter>Source Files</Filter>
  84.      </ClCompile>
  85. +    <ClCompile Include="..\..\daemon\cpvparser1.c">
  86. +      <Filter>Source Files</Filter>
  87. +    </ClCompile>
  88.      <ClCompile Include="..\..\daemon\daemon_debug.c">
  89.        <Filter>Source Files</Filter>
  90.      </ClCompile>
  91. @@ -39,6 +42,9 @@
  92.      <ClCompile Include="..\..\daemon\idmap.c">
  93.        <Filter>Source Files</Filter>
  94.      </ClCompile>
  95. +    <ClCompile Include="..\..\daemon\idmap_cygwin.c">
  96. +      <Filter>Source Files</Filter>
  97. +    </ClCompile>
  98.      <ClCompile Include="..\..\daemon\lock.c">
  99.        <Filter>Source Files</Filter>
  100.      </ClCompile>
  101. @@ -111,6 +117,9 @@
  102.      <ClCompile Include="..\..\daemon\setattr.c">
  103.        <Filter>Source Files</Filter>
  104.      </ClCompile>
  105. +    <ClCompile Include="..\..\daemon\sid.c">
  106. +      <Filter>Source Files</Filter>
  107. +    </ClCompile>
  108.      <ClCompile Include="..\..\daemon\symlink.c">
  109.        <Filter>Source Files</Filter>
  110.      </ClCompile>
  111. @@ -125,6 +134,9 @@
  112.      </ClCompile>
  113.    </ItemGroup>
  114.    <ItemGroup>
  115. +    <ClInclude Include="..\..\daemon\cpvparser1.h">
  116. +      <Filter>Header Files</Filter>
  117. +    </ClInclude>
  118.      <ClInclude Include="..\..\daemon\daemon_debug.h">
  119.        <Filter>Header Files</Filter>
  120.      </ClInclude>
  121. @@ -173,6 +185,9 @@
  122.      <ClInclude Include="..\..\daemon\service.h">
  123.        <Filter>Header Files</Filter>
  124.      </ClInclude>
  125. +    <ClInclude Include="..\..\daemon\sid.h">
  126. +      <Filter>Header Files</Filter>
  127. +    </ClInclude>
  128.      <ClInclude Include="..\..\daemon\tree.h">
  129.        <Filter>Header Files</Filter>
  130.      </ClInclude>
  131. diff --git a/cygwin_idmapper.ksh b/cygwin_idmapper.ksh
  132. new file mode 100644
  133. index 0000000..4b96ecf
  134. --- /dev/null
  135. +++ b/cygwin_idmapper.ksh
  136. @@ -0,0 +1,124 @@
  137. +#!/bin/ksh93
  138. +
  139. +set -o nounset
  140. +typeset IFS=''
  141. +
  142. +#
  143. +# global variables
  144. +# (stored in compound variable so we
  145. +# can do a $ print -u2 -v c # for debugging)
  146. +#
  147. +compound c=(
  148. +        mode="$1"
  149. +        name="$2"
  150. +)
  151. +
  152. +compound -A localusers=(
  153. +       ["roland_mainz"]=(
  154. +               localaccoutname='roland_mainz'
  155. +               localuid=197608
  156. +               localgid=197121
  157. +       )
  158. +       ["siegfried_wulsch"]=(
  159. +               localaccoutname='siegfried_wulsch'
  160. +               localuid=197609
  161. +               localgid=197121
  162. +       )
  163. +       ["SYSTEM"]=(
  164. +               localaccoutname='SYSTEM'
  165. +               localuid=18
  166. +               localgid=18
  167. +       )
  168. +       ["rmainz"]=(
  169. +               localaccoutname='rmainz'
  170. +               localuid=1616
  171. +               localgid=1616
  172. +       )
  173. +       ["swulsch"]=(
  174. +               localaccoutname='swulsch'
  175. +               localuid=1818
  176. +               localgid=1818
  177. +       )
  178. +       ["root"]=(
  179. +               localaccoutname='root'
  180. +               localuid=0
  181. +               localgid=0
  182. +       )
  183. +       ["nobody"]=(
  184. +               localaccoutname='nobody'
  185. +               localuid=65534
  186. +               localgid=65534
  187. +       )
  188. +)
  189. +
  190. +compound -A localgroups=(
  191. +       ["Kein"]=(
  192. +               localaccoutname='Kein'
  193. +               localgid=197121
  194. +       )
  195. +       ["rmainz"]=(
  196. +               localaccoutname='rmainz'
  197. +               localuid=1616
  198. +               localgid=1616
  199. +       )
  200. +       ["swulsch"]=(
  201. +               localaccoutname='swulsch'
  202. +               localuid=1818
  203. +               localgid=1818
  204. +       )
  205. +       ["root"]=(
  206. +               localaccoutname='root'
  207. +               localuid=0
  208. +               localgid=0
  209. +       )
  210. +       ["nogroup"]=(
  211. +               localaccoutname='nogroup'
  212. +               localuid=65534
  213. +               localgid=65534
  214. +       )
  215. +)
  216. +
  217. +case "${c.mode}" in
  218. +       'nfsserveruser2localaccount')
  219. +               if [[ "${c.name}" == ~(Elr)[[:digit:]]+ ]] ; then
  220. +                       for s in "${!localusers[@]}" ; do
  221. +                               if (( localusers[$s].localuid == c.name )) ; then
  222. +                                       print -v localusers[$s]
  223. +                                       exit 0
  224. +                               fi
  225. +                       done
  226. +               fi
  227. +
  228. +               if [[ -v localusers["${c.name}"] ]] ; then
  229. +                       print -v localusers["${c.name}"]
  230. +                       exit 0
  231. +               else
  232. +                       print -u2 -f "cygwin_idmapper.ksh: Account '%s' not found.\n" "${c.name}"
  233. +                       exit 1
  234. +               fi
  235. +               ;;
  236. +       'nfsserveruser2localgroup')
  237. +               if [[ "${c.name}" == ~(Elr)[[:digit:]]+ ]] ; then
  238. +                       for s in "${!localgroups[@]}" ; do
  239. +                               if (( localgroups[$s].localgid == c.name )) ; then
  240. +                                       print -v localgroups[$s]
  241. +                                       exit 0
  242. +                               fi
  243. +                       done
  244. +               fi
  245. +
  246. +               if [[ -v localgroups["${c.name}"] ]] ; then
  247. +                       print -v localgroups["${c.name}"]
  248. +                       exit 0
  249. +               else
  250. +                       print -u2 -f "cygwin_idmapper.ksh: Account '%s' not found.\n" "${c.name}"
  251. +                       exit 1
  252. +               fi
  253. +               ;;
  254. +       *)
  255. +               print -u2 "cygwin_idmapper.ksh: Unknown mode"
  256. +               exit 1
  257. +               ;;
  258. +esac
  259. +
  260. +# EOF.
  261. diff --git a/daemon/acl.c b/daemon/acl.c
  262. index 1d1eac4..6c87f30 100644
  263. --- a/daemon/acl.c
  264. +++ b/daemon/acl.c
  265. @@ -3,6 +3,7 @@
  266.   *
  267.   * Olga Kornievskaia <aglo@umich.edu>
  268.   * Casey Bodley <cbodley@umich.edu>
  269. + * Roland Mainz <roland.mainz@nrubsig.org>
  270.   *
  271.   * This library is free software; you can redistribute it and/or modify it
  272.   * under the terms of the GNU Lesser General Public License as published by
  273. @@ -32,7 +33,7 @@
  274.  #include "util.h"
  275.  #include "upcall.h"
  276.  #include "nfs41_xdr.h"
  277. -#include "idmap.h"
  278. +#include "sid.h"
  279.  
  280.  //#define DEBUG_ACLS
  281.  #define ACLLVL 2 /* dprintf level for acl logging */
  282. @@ -51,41 +52,6 @@ out:
  283.      return status;
  284.  }
  285.  
  286. -static int create_unknownsid(WELL_KNOWN_SID_TYPE type, PSID *sid,
  287. -                             DWORD *sid_len)
  288. -{
  289. -    int status;
  290. -    *sid_len = 0;
  291. -    *sid = NULL;
  292. -
  293. -    status = CreateWellKnownSid(type, NULL, *sid, sid_len);
  294. -    dprintf(ACLLVL, "create_unknownsid: CreateWellKnownSid type %d returned %d "
  295. -            "GetLastError %d sid len %d needed\n", type, status,
  296. -            GetLastError(), *sid_len);
  297. -    if (status) {
  298. -        status = ERROR_INTERNAL_ERROR;
  299. -        goto err;
  300. -    }
  301. -    status = GetLastError();
  302. -    if (status != ERROR_INSUFFICIENT_BUFFER)
  303. -        goto err;
  304. -
  305. -    *sid = malloc(*sid_len);
  306. -    if (*sid == NULL) {
  307. -        status = ERROR_INSUFFICIENT_BUFFER;
  308. -        goto err;
  309. -    }
  310. -    status = CreateWellKnownSid(type, NULL, *sid, sid_len);
  311. -    if (status)
  312. -        return ERROR_SUCCESS;
  313. -    free(*sid);
  314. -    *sid = NULL;
  315. -    status = GetLastError();
  316. -err:
  317. -    eprintf("create_unknownsid: CreateWellKnownSid failed with %d\n", status);
  318. -    return status;
  319. -}
  320. -
  321.  static void convert_nfs4name_2_user_domain(LPSTR nfs4name,
  322.                                             LPSTR *domain)
  323.  {
  324. @@ -100,267 +66,6 @@ static void convert_nfs4name_2_user_domain(LPSTR nfs4name,
  325.      }
  326.  }
  327.  
  328. -#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
  329. -/*
  330. - * Allocate a SID from SECURITY_SAMBA_UNIX_AUTHORITY, which encodes an
  331. - * UNIX/POSIX uid directly into a SID.
  332. - *
  333. - * Examples:
  334. - * UID 1616 gets mapped to "Unix_User+1616", encoding the UID into the
  335. - * SID as "S-1-22-1-1616":
  336. - * $ getent passwd Unix_User+1616
  337. - * Unix_User+1616:*:4278191696:4278191696:U-Unix_User616,S-1-22-1-1616:/:/sbin/nologin
  338. - *
  339. - * GID 1984 gets mapped to "Unix_Group+1984", encoding the GID into the
  340. - * SID as "S-1-22-2-1984":
  341. - * $ getent group Unix_Group+1984
  342. - * Unix_Group+1984:S-1-22-2-1984:4278192064:
  343. - *
  344. - */
  345. -
  346. -#define SECURITY_SAMBA_UNIX_AUTHORITY { { 0,0,0,0,0,22 } }
  347. -SID_IDENTIFIER_AUTHORITY sid_id_auth = SECURITY_SAMBA_UNIX_AUTHORITY;
  348. -
  349. -static
  350. -BOOL allocate_unixuser_sid(unsigned long uid, PSID *pSid)
  351. -{
  352. -    PSID sid = NULL;
  353. -    PSID malloced_sid = NULL;
  354. -    DWORD sid_len;
  355. -
  356. -    if (AllocateAndInitializeSid(&sid_id_auth, 2, 1, (DWORD)uid,
  357. -        0, 0, 0, 0, 0, 0, &sid)) {
  358. -        sid_len = GetLengthSid(sid);
  359. -
  360. -        malloced_sid = malloc(sid_len);
  361. -
  362. -        if (malloced_sid) {
  363. -            /*
  364. -             * |AllocateAndInitializeSid()| has an own memory
  365. -             * allocator, but we need the sid in memory from
  366. -             * |malloc()|
  367. -             */
  368. -            if (CopySid(sid_len, malloced_sid, sid)) {
  369. -                FreeSid(sid);
  370. -                *pSid = malloced_sid;
  371. -                dprintf(ACLLVL, "allocate_unixuser_sid(): Allocated "
  372. -                    "Unix_User+%lu: success, len=%ld\n",
  373. -                    uid, (long)sid_len);
  374. -                return TRUE;
  375. -            }
  376. -        }
  377. -    }
  378. -
  379. -    FreeSid(sid);
  380. -    free(malloced_sid);
  381. -    dprintf(ACLLVL, "allocate_unixuser_sid(): Failed to allocate "
  382. -        "SID for Unix_User+%lu: error code %d\n",
  383. -        uid, GetLastError());
  384. -    return FALSE;
  385. -}
  386. -
  387. -static
  388. -BOOL allocate_unixgroup_sid(unsigned long gid, PSID *pSid)
  389. -{
  390. -    PSID sid = NULL;
  391. -    PSID malloced_sid = NULL;
  392. -    DWORD sid_len;
  393. -
  394. -    if (AllocateAndInitializeSid(&sid_id_auth, 2, 2, (DWORD)gid,
  395. -        0, 0, 0, 0, 0, 0, &sid)) {
  396. -        sid_len = GetLengthSid(sid);
  397. -
  398. -        malloced_sid = malloc(sid_len);
  399. -
  400. -        if (malloced_sid) {
  401. -            /*
  402. -             * |AllocateAndInitializeSid()| has an own memory
  403. -             * allocator, but we need the sid in memory from
  404. -             * |malloc()|
  405. -             */
  406. -            if (CopySid(sid_len, malloced_sid, sid)) {
  407. -                FreeSid(sid);
  408. -                *pSid = malloced_sid;
  409. -                dprintf(ACLLVL, "allocate_unixgroup_sid(): Allocated "
  410. -                    "Unix_Group+%lu: success, len=%ld\n",
  411. -                    gid, (long)sid_len);
  412. -                return TRUE;
  413. -            }
  414. -        }
  415. -    }
  416. -
  417. -    FreeSid(sid);
  418. -    free(malloced_sid);
  419. -    dprintf(ACLLVL, "allocate_unixgroup_sid(): Failed to allocate "
  420. -        "SID for Unix_Group+%lu: error code %d\n",
  421. -        gid, GetLastError());
  422. -    return FALSE;
  423. -}
  424. -#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
  425. -
  426. -static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_len, PSID *sid, LPCSTR name)
  427. -{
  428. -    int status = ERROR_INTERNAL_ERROR;
  429. -    SID_NAME_USE sid_type;
  430. -    LPSTR tmp_buf = NULL;
  431. -    DWORD tmp = 0;
  432. -#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
  433. -    signed long user_uid = -1;
  434. -    signed long group_gid = -1;
  435. -#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
  436. -
  437. -#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
  438. -    if (query & OWNER_SECURITY_INFORMATION) {
  439. -        if (!strcmp(name, "rmainz")) {
  440. -            name = "roland_mainz";
  441. -            dprintf(ACLLVL, "map_name_2_sid: remap rmainz --> roland_mainz\n");
  442. -        }
  443. -        else if (!strcmp(name, "197608")) {
  444. -            name = "roland_mainz";
  445. -            dprintf(ACLLVL, "map_name_2_sid: remap 197608 --> roland_mainz\n");
  446. -        }
  447. -        else if (!strcmp(name, "1616")) {
  448. -            name = "roland_mainz";
  449. -            dprintf(ACLLVL, "map_name_2_sid: remap 1616 --> roland_mainz\n");
  450. -        }
  451. -    }
  452. -#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
  453. -
  454. -    status = LookupAccountName(NULL, name, NULL, sid_len, NULL, &tmp, &sid_type);
  455. -    dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): LookupAccountName returned %d "
  456. -            "GetLastError %d name len %d domain len %d\n",
  457. -            query, name, status, GetLastError(), *sid_len, tmp);
  458. -    if (status)
  459. -        return ERROR_INTERNAL_ERROR;
  460. -
  461. -    status = GetLastError();
  462. -    switch(status) {
  463. -    case ERROR_INSUFFICIENT_BUFFER:
  464. -        *sid = malloc(*sid_len);
  465. -        if (*sid == NULL) {
  466. -            status = GetLastError();
  467. -            goto out;
  468. -        }
  469. -        tmp_buf = (LPSTR) malloc(tmp);
  470. -        if (tmp_buf == NULL)
  471. -            goto out_free_sid;
  472. -        status = LookupAccountName(NULL, name, *sid, sid_len, tmp_buf,
  473. -                                    &tmp, &sid_type);
  474. -        free(tmp_buf);
  475. -        if (!status) {
  476. -            eprintf("map_name_2_sid(query=%x,name='%s'): LookupAccountName failed "
  477. -                    "with %d\n", query, name, GetLastError());
  478. -            goto out_free_sid;
  479. -        } else {
  480. -#ifdef DEBUG_ACLS
  481. -            LPSTR ssid = NULL;
  482. -            if (IsValidSid(*sid))
  483. -                if (ConvertSidToStringSidA(*sid, &ssid))
  484. -                    dprintf(1, "map_name_2_sid: sid_type = %d SID %s\n",
  485. -                            sid_type, ssid);
  486. -                else
  487. -                    dprintf(1, "map_name_2_sid: ConvertSidToStringSidA failed "
  488. -                            "with %d\n", GetLastError());
  489. -            else
  490. -                dprintf(1, "map_name_2_sid: Invalid Sid ?\n");
  491. -            if (ssid) LocalFree(ssid);
  492. -#endif
  493. -        }
  494. -        status = ERROR_SUCCESS;
  495. -        break;
  496. -    case ERROR_NONE_MAPPED:
  497. -#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
  498. -        dprintf(1, "map_name_2_sid(query=%x,name='%s'): none mapped, "
  499. -            "trying Unix_User+/Unix_Group+ mapping\n",
  500. -            query, name);
  501. -
  502. -        if ((user_uid == -1) && (query & OWNER_SECURITY_INFORMATION)) {
  503. -            uid_t map_uid = -1;
  504. -            gid_t gid_dummy = -1;
  505. -
  506. -            if (nfs41_idmap_name_to_ids(
  507. -                nfs41dg->idmapper,
  508. -                name,
  509. -                &map_uid,
  510. -                &gid_dummy) == 0) {
  511. -                user_uid = map_uid;
  512. -            }
  513. -            else {
  514. -                dprintf(1, "map_name_2_sid(query=%x,name='%s'): nfs41_idmap_name_to_ids() failed\n",
  515. -                    query, name);
  516. -                /* fixme: try harder here, "1234" should to to |atol()| */
  517. -            }
  518. -        }
  519. -
  520. -        if ((group_gid == -1) && (query & GROUP_SECURITY_INFORMATION)) {
  521. -            gid_t map_gid = -1;
  522. -
  523. -            if (nfs41_idmap_group_to_gid(
  524. -                nfs41dg->idmapper,
  525. -                name,
  526. -                &map_gid) == 0) {
  527. -                group_gid = map_gid;
  528. -            }
  529. -            else {
  530. -                dprintf(1, "map_name_2_sid(query=%x,name='%s'): nfs41_idmap_group_to_gid() failed\n",
  531. -                    query, name);
  532. -                /* fixme: try harder here, "1234" should to to |atol()| */
  533. -            }
  534. -        }
  535. -
  536. -        if (user_uid != -1) {
  537. -            if (allocate_unixuser_sid(user_uid, sid)) {
  538. -                dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
  539. -                    "allocate_unixuser_sid(uid=%ld) success\n",
  540. -                    query, name, user_uid);
  541. -                return ERROR_SUCCESS;
  542. -            }
  543. -
  544. -            status = GetLastError();
  545. -            dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
  546. -                "allocate_unixuser_sid(uid=%ld) failed, error=%d\n",
  547. -                query, name, user_uid, status);
  548. -            return status;
  549. -        }
  550. -
  551. -        if (group_gid != -1) {
  552. -            if (allocate_unixgroup_sid(group_gid, sid)) {
  553. -                dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
  554. -                    "allocate_unixgroup_sid(gid=%ld) success\n",
  555. -                    query, name, group_gid);
  556. -                return ERROR_SUCCESS;
  557. -            }
  558. -
  559. -            status = GetLastError();
  560. -            dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
  561. -                "allocate_unixgroup_sid(gid=%ld) failed, error=%d\n",
  562. -                query, name, group_gid, status);
  563. -            return status;
  564. -        }
  565. -#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
  566. -
  567. -        dprintf(1, "map_name_2_sid(query=%x,name='%s'): none mapped, "
  568. -            "using WinNullSid mapping\n",
  569. -            query, name);
  570. -
  571. -        status = create_unknownsid(WinNullSid, sid, sid_len);
  572. -        if (status)
  573. -            goto out_free_sid;
  574. -        break;
  575. -    default:
  576. -        dprintf(1, "map_name_2_sid(query=%x,name='%s'): error %d not handled\n",
  577. -            query, name, GetLastError());
  578. -        break;
  579. -    }
  580. -out:
  581. -    return status;
  582. -out_free_sid:
  583. -    status = GetLastError();
  584. -    free(*sid);
  585. -    *sid = NULL;
  586. -    goto out;
  587. -}
  588. -
  589.  static void free_sids(PSID *sids, int count)
  590.  {
  591.      int i;
  592. @@ -417,7 +122,7 @@ static int convert_nfs4acl_2_dacl(nfs41_daemon_globals *nfs41dg,
  593.              goto out;
  594.          }
  595.          if (!flag) {
  596. -            status = map_name_2_sid(nfs41dg,
  597. +            status = map_nfs4servername_2_sid(nfs41dg,
  598.                  0xFFFF /* fixme: Unknown whether user or group */,
  599.                  &sid_len, &sids[i], acl->aces[i].who);
  600.              if (status) {
  601. @@ -534,7 +239,7 @@ static int handle_getacl(void *daemon_context, nfs41_upcall *upcall)
  602.          dprintf(ACLLVL, "handle_getacl: OWNER_SECURITY_INFORMATION: for user=%s "
  603.                  "domain=%s\n", info.owner, domain?domain:"<null>");
  604.          sid_len = 0;
  605. -        status = map_name_2_sid(nfs41dg,
  606. +        status = map_nfs4servername_2_sid(nfs41dg,
  607.              OWNER_SECURITY_INFORMATION, &sid_len, &osid, info.owner);
  608.          if (status)
  609.              goto out;
  610. @@ -552,7 +257,7 @@ static int handle_getacl(void *daemon_context, nfs41_upcall *upcall)
  611.          dprintf(ACLLVL, "handle_getacl: GROUP_SECURITY_INFORMATION: for %s "
  612.                  "domain=%s\n", info.owner_group, domain?domain:"<null>");
  613.          sid_len = 0;
  614. -        status = map_name_2_sid(nfs41dg,
  615. +        status = map_nfs4servername_2_sid(nfs41dg,
  616.              GROUP_SECURITY_INFORMATION, &sid_len, &gsid, info.owner_group);
  617.          if (status)
  618.              goto out;
  619. diff --git a/daemon/cpvparser1.c b/daemon/cpvparser1.c
  620. new file mode 100644
  621. index 0000000..285fc76
  622. --- /dev/null
  623. +++ b/daemon/cpvparser1.c
  624. @@ -0,0 +1,361 @@
  625. +
  626. +/*
  627. + * MIT License
  628. + *
  629. + * Copyright (c) 2023 Roland Mainz <roland.mainz@nrubsig.org>
  630. + *
  631. + * Permission is hereby granted, free of charge, to any person obtaining a copy
  632. + * of this software and associated documentation files (the "Software"), to deal
  633. + * in the Software without restriction, including without limitation the rights
  634. + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  635. + * copies of the Software, and to permit persons to whom the Software is
  636. + * furnished to do so, subject to the following conditions:
  637. + *
  638. + * The above copyright notice and this permission notice shall be included in all
  639. + * copies or substantial portions of the Software.
  640. + *
  641. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  642. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  643. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  644. + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FORalloca ANY CLAIM, DAMAGES OR OTHER
  645. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  646. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  647. + * SOFTWARE.
  648. + */
  649. +
  650. +/*
  651. + * cpvparser1.c - simple ksh93 compound variable parsing
  652. + *
  653. + * It basically reads the output of $ print -v ... # like this:
  654. + * ---- snip ----
  655. + * $ ksh93 -c 'compound c=( va=1 vb=hello ) ; print -v c'
  656. + * (
  657. + *        va=1
  658. + *        vb=hello
  659. + * )
  660. + * ---- snip ----
  661. + *
  662. + * ToDo:
  663. + * - arrays (indexed, sparse indexed and associative)
  664. + * - multibyte characters
  665. + *
  666. + * Written by Roland Mainz <roland.mainz@nrubsig.org>
  667. + */
  668. +
  669. +#include <stdlib.h>
  670. +#include <stdbool.h>
  671. +#include <string.h>
  672. +#include <stdio.h>
  673. +#include <ctype.h>
  674. +
  675. +#include "cpvparser1.h"
  676. +
  677. +#ifdef _WIN32
  678. +#define strdup(s) _strdup(s)
  679. +#endif
  680. +
  681. +/* private data! */
  682. +typedef struct cpv_parse_context {
  683. +       const char *start_string;
  684. +       const char *curr_string;
  685. +       size_t max_name_val_size;
  686. +       unsigned long flags;
  687. +} cpv_parse_context;
  688. +
  689. +
  690. +void *cpv_create_parser(const char *s, unsigned long flags, ...)
  691. +{
  692. +       cpv_parse_context *cpc;
  693. +
  694. +       cpc = calloc(1, sizeof(cpv_parse_context));
  695. +       if (!cpc)
  696. +               goto fail;
  697. +
  698. +       cpc->start_string = strdup(s);
  699. +       if (!cpc->start_string)
  700. +               goto fail;
  701. +
  702. +       cpc->curr_string = cpc->start_string;
  703. +       cpc->max_name_val_size = strlen(cpc->start_string);
  704. +       cpc->flags = flags;
  705. +
  706. +       return (cpc);
  707. +
  708. +fail:
  709. +       if (cpc) {
  710. +               free((void *)cpc->start_string);
  711. +               free(cpc);
  712. +       }
  713. +
  714. +       return NULL;
  715. +}
  716. +
  717. +void cpv_free_parser(void *v_cpc)
  718. +{
  719. +       cpv_parse_context *cpc = (cpv_parse_context *)v_cpc;
  720. +       if (cpc) {
  721. +               free((void *)cpc->start_string);
  722. +               free(cpc);
  723. +       }
  724. +}
  725. +
  726. +int cpv_read_cpv_header(void *v_cpc)
  727. +{
  728. +       cpv_parse_context *cpc = (cpv_parse_context *)v_cpc;
  729. +       const char *s = cpc->curr_string;
  730. +
  731. +skipspaces:
  732. +       while((*s != '\0') && isspace(*s))
  733. +               s++;
  734. +
  735. +       /*
  736. +        * skip POSIX-style '#' comments
  737. +        * (allowed since this is based on POSIX sh(1) syntax)
  738. +        */
  739. +       if (*s == '#') {
  740. +               s++;
  741. +               /* ignore everything until the end-of-line */
  742. +               while((*s != '\0') && (*s != '\n'))
  743. +                       s++;
  744. +               goto skipspaces;
  745. +       }
  746. +
  747. +       if (*s == '(') {
  748. +               cpc->curr_string=++s;
  749. +               if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
  750. +                       (void)fprintf(stderr, "cpv_read_cpv_header: begin-of-cpv\n");
  751. +               }
  752. +               return 0;
  753. +       }
  754. +
  755. +       if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
  756. +               (void)fprintf(stderr, "cpv_read_cpv_header: end-of-string, should not happen\n");
  757. +       }
  758. +       return 1;
  759. +}
  760. +
  761. +int cpv_parse_name_val(void *v_cpc, cpv_name_val *cpv_nv)
  762. +{
  763. +       cpv_parse_context *cpc = (cpv_parse_context *)v_cpc;
  764. +#ifdef _WIN32
  765. +       char *namebuff = _alloca(cpc->max_name_val_size+1);
  766. +       char *valbuff  = _alloca(cpc->max_name_val_size+1);
  767. +#else
  768. +       char namebuff[cpc->max_name_val_size+1];
  769. +       char valbuff[cpc->max_name_val_size+1];
  770. +#endif
  771. +
  772. +       const char *s = cpc->curr_string;
  773. +
  774. +       char *n; /* pointer in |namebuff| */
  775. +       char *v; /* pointer in |valbuff| */
  776. +
  777. +skipspaces:
  778. +       while((*s != '\0') && isspace(*s))
  779. +               s++;
  780. +
  781. +       /*
  782. +        * skip POSIX-style '#' comments
  783. +        * (allowed since this is based on POSIX sh(1) syntax)
  784. +        */
  785. +       if (*s == '#') {
  786. +               s++;
  787. +               /* ignore everything until the end-of-line */
  788. +               while((*s != '\0') && (*s != '\n'))
  789. +                       s++;
  790. +               goto skipspaces;
  791. +       }
  792. +
  793. +       if (*s == '\0') {
  794. +               if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
  795. +                       (void)fprintf(stderr, "cpv_parse_name_val: "
  796. +                               "error: end-of-string, should not happen\n");
  797. +               }
  798. +               return 1;
  799. +       }
  800. +
  801. +       /* cpv == "( foo=bar blabla=text )"*/
  802. +       if (*s == ')') {
  803. +               if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
  804. +                       (void)fprintf(stderr, "cpv_parse_name_val: end-of-cpv (OK)\n");
  805. +               }
  806. +               return 1;
  807. +       }
  808. +
  809. +parse_varname:
  810. +       /*
  811. +        * start parsing variable name
  812. +        */
  813. +
  814. +       /* variable names MUST start with a letter! */
  815. +       if (!isalpha(*s)) {
  816. +               if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
  817. +                       (void)fprintf(stderr,
  818. +                               "cpv_parse_name_val: parser error, first char "
  819. +                               "in variable name not isalpha(c=%c)\n",
  820. +                               *s);
  821. +               }
  822. +               return 1;
  823. +       }
  824. +
  825. +       n = namebuff;
  826. +       while((*s != '\0') && isalnum(*s))
  827. +               *n++ = *s++;
  828. +       *n = '\0';
  829. +
  830. +       /*
  831. +        * skip typed member varables
  832. +        * (e.g. "typeset ", "typeset -i ", "typeset -l -i2" etc.)
  833. +        */
  834. +       if (isspace(*s)) {
  835. +               if ((!strcmp(namebuff, "typeset")) ||
  836. +                       (!strcmp(namebuff, "integer")) ||
  837. +                       (!strcmp(namebuff, "float")) ||
  838. +                       (!strcmp(namebuff, "compound"))) {
  839. +skip_typeset_options:
  840. +                       while(isspace(*s))
  841. +                               s++;
  842. +                       if (*s == '-') {
  843. +                               s++;
  844. +                               while(isalnum(*s))
  845. +                                       s++;
  846. +                               goto skip_typeset_options;
  847. +                       }
  848. +
  849. +                       goto parse_varname;
  850. +               }
  851. +       }
  852. +
  853. +       /* handle '=' */
  854. +       if (*s != '=') {
  855. +               if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
  856. +                       (void)fprintf(stderr, "cpv_parse_name_val: "
  857. +                               "parser error, expected '=', got '%c'.\n",
  858. +                               *s);
  859. +               }
  860. +               return 1;
  861. +       }
  862. +
  863. +       s++; /* skip '=' */
  864. +
  865. +       /*
  866. +        * start parsing variable value
  867. +        */
  868. +       bool in_doublequotes=false;
  869. +       bool in_singlequotes=false;
  870. +       v = valbuff;
  871. +val_quotes:
  872. +       if (in_singlequotes) {
  873. +               while(*s != '\0') {
  874. +                       if (*s == '\'') {
  875. +                               in_singlequotes = false;
  876. +                               s++;
  877. +                               goto val_quotes;
  878. +                       }
  879. +
  880. +                       if ((*s == '\\') && (*(s+1) != '\0')) {
  881. +                               /*
  882. +                                * fixme: should support \ooo octals,
  883. +                                * \u[hex] unicode and \w[hex] wchar
  884. +                                */
  885. +                               s++;
  886. +                       }
  887. +                       *v++ = *s++;
  888. +               }
  889. +       }
  890. +       else if (in_doublequotes) {
  891. +               while(*s != '\0') {
  892. +                       if (*s == '"') {
  893. +                               in_doublequotes = false;
  894. +                               s++;
  895. +                               goto val_quotes;
  896. +                       }
  897. +
  898. +                       if ((*s == '\\') && (*(s+1) != '\0')) {
  899. +                               /*
  900. +                                * fixme: should support \ooo octals,
  901. +                                * \u[hex] unicode and \w[hex] wchar
  902. +                                */
  903. +                               s++;
  904. +                       }
  905. +
  906. +                       *v++ = *s++;
  907. +               }
  908. +       }
  909. +       else
  910. +       {
  911. +               while((*s != '\0') && (!isspace(*s))) {
  912. +                       if (*s == '"') {
  913. +                               in_doublequotes = true;
  914. +                               s++;
  915. +                               goto val_quotes;
  916. +                       }
  917. +
  918. +                       if (*s == '\'') {
  919. +                               in_singlequotes = true;
  920. +                               s++;
  921. +                               goto val_quotes;
  922. +                       }
  923. +
  924. +                       if ((*s == '\\') && (*(s+1) != '\0')) {
  925. +                               /*
  926. +                                * fixme: should support \ooo octals,
  927. +                                * \u[hex] unicode and \w[hex] wchar
  928. +                                */
  929. +                               s++;
  930. +                       }
  931. +                       *v++ = *s++;
  932. +               }
  933. +       }
  934. +
  935. +       if (in_singlequotes) {
  936. +               if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
  937. +                       (void)fprintf(stderr, "cpv_parse_name_val: "
  938. +                               "parsererror, still in single quotes "
  939. +                               "at the end\n");
  940. +               }
  941. +               return 1;
  942. +       }
  943. +       if (in_doublequotes) {
  944. +               if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
  945. +                       (void)fprintf(stderr, "cpv_parse_name_val: "
  946. +                               "parser error, still in double quotes "
  947. +                               "at the end\n");
  948. +               }
  949. +               return 1;
  950. +       }
  951. +
  952. +       *v = '\0';
  953. +
  954. +#if 0
  955. +       (void)printf("cpv_parse_name_val: name='%s', value='%s'\n",
  956. +               namebuff, valbuff);
  957. +#endif
  958. +
  959. +       cpv_nv->cpv_name   = strdup(namebuff);
  960. +       cpv_nv->cpv_value  = strdup(valbuff);
  961. +
  962. +       if ((cpv_nv->cpv_name == NULL) || (cpv_nv->cpv_value == NULL)) {
  963. +               cpv_free_name_val_data(cpv_nv);
  964. +               if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
  965. +                       (void)fprintf(stderr, "cpv_parse_name_val: "
  966. +                               "parser error, out of memory\n");
  967. +               }
  968. +               return 2;
  969. +       }
  970. +
  971. +       cpc->curr_string = s;
  972. +
  973. +       return 0;
  974. +}
  975. +
  976. +void cpv_free_name_val_data(cpv_name_val *cnv)
  977. +{
  978. +       if (!cnv)
  979. +               return;
  980. +
  981. +       free((void *)cnv->cpv_name);
  982. +       free((void *)cnv->cpv_value);
  983. +       cnv->cpv_name = NULL;
  984. +       cnv->cpv_value = NULL;
  985. +}
  986. diff --git a/daemon/cpvparser1.h b/daemon/cpvparser1.h
  987. new file mode 100644
  988. index 0000000..a6ed609
  989. --- /dev/null
  990. +++ b/daemon/cpvparser1.h
  991. @@ -0,0 +1,64 @@
  992. +
  993. +/*
  994. + * MIT License
  995. + *
  996. + * Copyright (c) 2023 Roland Mainz <roland.mainz@nrubsig.org>
  997. + *
  998. + * Permission is hereby granted, free of charge, to any person obtaining a copy
  999. + * of this software and associated documentation files (the "Software"), to deal
  1000. + * in the Software without restriction, including without limitation the rights
  1001. + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  1002. + * copies of the Software, and to permit persons to whom the Software is
  1003. + * furnished to do so, subject to the following conditions:
  1004. + *
  1005. + * The above copyright notice and this permission notice shall be included in all
  1006. + * copies or substantial portions of the Software.
  1007. + *
  1008. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1009. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1010. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1011. + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1012. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  1013. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  1014. + * SOFTWARE.
  1015. + */
  1016. +
  1017. +/*
  1018. + * cpvparser1.h - simple ksh93 compound variable parsing
  1019. + *
  1020. + * It basically reads the output of $ print -v ... # like this:
  1021. + * ---- snip ----
  1022. + * $ ksh93 -c 'compound c=( va=1 vb=hello ) ; print -v c'
  1023. + * (
  1024. + *        va=1
  1025. + *        vb=hello
  1026. + * )
  1027. + * ---- snip ----
  1028. + *
  1029. + * ToDo:
  1030. + * - arrays (indexed, sparse indexed and associative)
  1031. + * - multibyte characters
  1032. + *
  1033. + * Written by Roland Mainz <roland.mainz@nrubsig.org>
  1034. + */
  1035. +
  1036. +#ifndef CPV_PARSER_H
  1037. +#define CPV_PARSER_H 1
  1038. +
  1039. +typedef struct cpv_name_val
  1040. +{
  1041. +       const char *cpv_name;
  1042. +       const char *cpv_value;
  1043. +} cpv_name_val;
  1044. +
  1045. +/* Flags for |cpv_create_parser()| */
  1046. +#define CPVFLAG_DEBUG_OUTPUT (0x00000008L)
  1047. +
  1048. +/* prototypes */
  1049. +void *cpv_create_parser(const char *s, unsigned long flags, ...);
  1050. +void cpv_free_parser(void *);
  1051. +int cpv_read_cpv_header(void *);
  1052. +void cpv_free_name_val_data(cpv_name_val *);
  1053. +int cpv_parse_name_val(void *, cpv_name_val *);
  1054. +
  1055. +#endif /* !CPV_PARSER_H */
  1056. diff --git a/daemon/idmap.c b/daemon/idmap.c
  1057. index 00af1fe..46a234d 100644
  1058. --- a/daemon/idmap.c
  1059. +++ b/daemon/idmap.c
  1060. @@ -3,6 +3,7 @@
  1061.   *
  1062.   * Olga Kornievskaia <aglo@umich.edu>
  1063.   * Casey Bodley <cbodley@umich.edu>
  1064. + * Roland Mainz <roland.mainz@nrubsig.org>
  1065.   *
  1066.   * This library is free software; you can redistribute it and/or modify it
  1067.   * under the terms of the GNU Lesser General Public License as published by
  1068. @@ -133,7 +134,7 @@ static const struct config_option g_options[] = {
  1069.      OPT_ATTR("ldap_attr_gidNumber", "gidNumber", ATTR_GID),
  1070.  
  1071.      /* caching configuration */
  1072. -    OPT_INT("cache_ttl", "60", cache_ttl),
  1073. +    OPT_INT("cache_ttl", "6000", cache_ttl),
  1074.  };
  1075.  
  1076.  
  1077. @@ -376,246 +377,6 @@ out:
  1078.      return status;
  1079.  }
  1080.  
  1081. -#ifdef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
  1082. -int cygwin_getent_passwd(const char *name, char *res_loginname, uid_t *res_uid, gid_t *res_gid)
  1083. -{
  1084. -    char cmdbuff[1024];
  1085. -    char passwd_line[1024];
  1086. -    FILE* getent_pipe = NULL;
  1087. -    int res = 1;
  1088. -    unsigned long uid = -1;
  1089. -    unsigned long gid = -1;
  1090. -    struct _cypwent {
  1091. -        char* loginname;
  1092. -        char* passwd;
  1093. -        char* uidstr;
  1094. -        char* gidstr;
  1095. -        char* comment;
  1096. -        char* homedir;
  1097. -        char* shell;
  1098. -    } pwent = { 0 };
  1099. -#define PWENT_ENTRY(var, prevvar) \
  1100. -    (((var) = strchr((prevvar), ':'))?(*(var)++ = '\0',(var)):(NULL))
  1101. -
  1102. -    dprintf(CYGWINIDLVL, "--> cygwin_getent_passwd('%s')\n", name);
  1103. -
  1104. -#if 1
  1105. -    /* hack for testing, map "roland_mainz" to rmainz account */
  1106. -    if ((!strcmp(name, "rmainz")) || (!strcmp(name, "1616"))) {
  1107. -        uid = 1616;
  1108. -        gid = 1616;
  1109. -        pwent.loginname = "rmainz";
  1110. -        goto found;
  1111. -    }
  1112. -    if ((!strcmp(name, "nobody")) || (!strcmp(name, "no+body")) ||
  1113. -        (!strcmp(name, "65534"))) {
  1114. -        uid = 65534;
  1115. -        gid = 65534;
  1116. -        pwent.loginname = "no+body"; /* Cygwin-specific */
  1117. -        goto found;
  1118. -    }
  1119. -    if ((!strcmp(name, "root")) || (!strcmp(name, "0"))) {
  1120. -        uid = 0;
  1121. -        gid = 0;
  1122. -        pwent.loginname = "root";
  1123. -        goto found;
  1124. -    }
  1125. -    if ((!strcmp(name, "iam")) || (!strcmp(name, "2010"))) {
  1126. -        uid = 2010;
  1127. -        gid = 2010;
  1128. -        pwent.loginname = "iam";
  1129. -        goto found;
  1130. -    }
  1131. -    if ((!strcmp(name, "swulsch")) || (!strcmp(name, "1818"))) {
  1132. -        uid = 1818;
  1133. -        gid = 1818;
  1134. -        pwent.loginname = "swulsch";
  1135. -        goto found;
  1136. -    }
  1137. -    if ((!strcmp(name, "mwenzel")) || (!strcmp(name, "8239"))) {
  1138. -        uid = 8239;
  1139. -        gid = 8239;
  1140. -        pwent.loginname = "mwenzel";
  1141. -        goto found;
  1142. -    }
  1143. -#endif
  1144. -
  1145. -    /* fixme: better quoting for |name| needed */
  1146. -    (void)snprintf(cmdbuff, sizeof(cmdbuff), "%s passwd \"%s\"",
  1147. -        "C:\\cygwin64\\bin\\getent.exe",
  1148. -        name);
  1149. -    if ((getent_pipe = _popen(cmdbuff, "rt")) == NULL) {
  1150. -        dprintf(CYGWINIDLVL, "cygwin_getent_passwd: /usr/bin/getent failed, errno='%s'\n",
  1151. -            strerror(errno));
  1152. -        goto fail;
  1153. -    }
  1154. -
  1155. -    if (fgets(passwd_line, sizeof(passwd_line), getent_pipe)) {
  1156. -        pwent.loginname = passwd_line;
  1157. -        if (!PWENT_ENTRY(pwent.passwd, pwent.loginname)) goto fail;
  1158. -        if (!PWENT_ENTRY(pwent.uidstr, pwent.passwd)) goto fail;
  1159. -        if (!PWENT_ENTRY(pwent.gidstr, pwent.uidstr)) goto fail;
  1160. -        if (!PWENT_ENTRY(pwent.comment, pwent.gidstr)) goto fail;
  1161. -        if (!PWENT_ENTRY(pwent.homedir, pwent.comment)) goto fail;
  1162. -        PWENT_ENTRY(pwent.shell, pwent.homedir);
  1163. -
  1164. -        errno = 0;
  1165. -        uid = strtol(pwent.uidstr, NULL, 10);
  1166. -        if (errno != 0)
  1167. -            goto fail;
  1168. -
  1169. -        errno = 0;
  1170. -        gid = strtol(pwent.gidstr, NULL, 10);
  1171. -        if (errno != 0)
  1172. -            goto fail;
  1173. -
  1174. -#if 0
  1175. -        dprintf(CYGWINIDLVL, "cygwin_getent_passwd(): name='%s'\n", name);
  1176. -        dprintf(CYGWINIDLVL, "loginname\t='%s'\n", pwent.loginname);
  1177. -        dprintf(CYGWINIDLVL, "passwd\t='%s'\n", pwent.passwd);
  1178. -        dprintf(CYGWINIDLVL, "uidstr\t='%s' (%lu)\n", pwent.uidstr, (unsigned long)uid);
  1179. -        dprintf(CYGWINIDLVL, "gidstr\t='%s' (%lu)\n", pwent.gidstr, (unsigned long)gid);
  1180. -        dprintf(CYGWINIDLVL, "comment\t='%s'\n", pwent.comment);
  1181. -        dprintf(CYGWINIDLVL, "homedir\t='%s'\n", pwent.homedir);
  1182. -        dprintf(CYGWINIDLVL, "shell\t='%s'\n", pwent.shell);
  1183. -#endif
  1184. -
  1185. -found:
  1186. -        if (res_loginname)
  1187. -            (void)strcpy_s(res_loginname, VAL_LEN, pwent.loginname);
  1188. -        *res_uid = uid;
  1189. -        *res_gid = gid;
  1190. -        res = 0;
  1191. -    }
  1192. -
  1193. -fail:
  1194. -    if (getent_pipe)
  1195. -        (void)_pclose(getent_pipe);
  1196. -
  1197. -    if (res == 0) {
  1198. -        dprintf(CYGWINIDLVL, "<-- cygwin_getent_passwd('%s'): "
  1199. -            "returning res_uid=%lu, res_gid=%lu, res_loginname='%s'\n",
  1200. -            name,
  1201. -            (unsigned long)(*res_uid),
  1202. -            (unsigned long)(*res_gid),
  1203. -            res_loginname?res_loginname:"<NULL>");
  1204. -    }
  1205. -    else {
  1206. -        dprintf(CYGWINIDLVL, "<-- cygwin_getent_passwd('%s'): no match found\n",
  1207. -            name);
  1208. -    }
  1209. -
  1210. -    return res;
  1211. -}
  1212. -
  1213. -int cygwin_getent_group(const char* name, char* res_group_name, gid_t* res_gid)
  1214. -{
  1215. -    char cmdbuff[1024];
  1216. -    char group_line[1024];
  1217. -    FILE* getent_pipe = NULL;
  1218. -    int res = 1;
  1219. -    unsigned long gid = -1;
  1220. -    struct _cygrent
  1221. -    {
  1222. -        char* group_name;
  1223. -        char* passwd;
  1224. -        char* gidstr;
  1225. -        char* userlist;
  1226. -    } grent = { 0 };
  1227. -
  1228. -    dprintf(CYGWINIDLVL, "--> cygwin_getent_group('%s')\n", name);
  1229. -
  1230. -#if 1
  1231. -    if ((!strcmp(name, "rmainz")) || (!strcmp(name, "1616"))) {
  1232. -        gid = 1616;
  1233. -        grent.group_name = "rmainz";
  1234. -        goto found;
  1235. -    }
  1236. -    if ((!strcmp(name, "nogroup")) || (!strcmp(name, "no+body")) ||
  1237. -        (!strcmp(name, "65534"))) {
  1238. -        gid = 65534;
  1239. -        grent.group_name = "no+body"; /* Cygwin-specific */
  1240. -        goto found;
  1241. -    }
  1242. -    if ((!strcmp(name, "root")) || (!strcmp(name, "0"))) {
  1243. -        gid = 0;
  1244. -        grent.group_name = "root";
  1245. -        goto found;
  1246. -    }
  1247. -    if ((!strcmp(name, "iam")) || (!strcmp(name, "2010"))) {
  1248. -        gid = 2010;
  1249. -        grent.group_name = "iam";
  1250. -        goto found;
  1251. -    }
  1252. -    if ((!strcmp(name, "swulsch")) || (!strcmp(name, "1818"))) {
  1253. -        gid = 1818;
  1254. -        grent.group_name = "swulsch";
  1255. -        goto found;
  1256. -    }
  1257. -    if ((!strcmp(name, "mwenzel")) || (!strcmp(name, "8239"))) {
  1258. -        gid = 8239;
  1259. -        grent.group_name = "mwenzel";
  1260. -        goto found;
  1261. -    }
  1262. -#endif
  1263. -
  1264. -    /* fixme: better quoting for |name| needed */
  1265. -    (void)snprintf(cmdbuff, sizeof(cmdbuff), "%s group \"%s\"",
  1266. -        "C:\\cygwin64\\bin\\getent.exe",
  1267. -        name);
  1268. -    if ((getent_pipe = _popen(cmdbuff, "rt")) == NULL) {
  1269. -        dprintf(CYGWINIDLVL,
  1270. -            "cygwin_getent_group: /usr/bin/getent failed, errno='%s'\n",
  1271. -            strerror(errno));
  1272. -        goto fail;
  1273. -    }
  1274. -
  1275. -    if (fgets(group_line, sizeof(group_line), getent_pipe))
  1276. -    {
  1277. -        grent.group_name = group_line;
  1278. -        if (!PWENT_ENTRY(grent.passwd, grent.group_name)) goto fail;
  1279. -        if (!PWENT_ENTRY(grent.gidstr, grent.passwd)) goto fail;
  1280. -        PWENT_ENTRY(grent.userlist, grent.gidstr);
  1281. -
  1282. -        errno = 0;
  1283. -        gid = strtol(grent.gidstr, NULL, 10);
  1284. -        if (errno != 0)
  1285. -            goto fail;
  1286. -
  1287. -#if 0
  1288. -        dprintf(CYGWINIDLVL, "cygwin_getent_group(): name='%s'\n", name);
  1289. -        dprintf(CYGWINIDLVL, "group_name\t='%s'\n", grent.group_name);
  1290. -        dprintf(CYGWINIDLVL, "passwd\t='%s'\n", grent.passwd);
  1291. -        dprintf(CYGWINIDLVL, "gidstr\t='%s' (%lu)\n", grent.gidstr, (unsigned long)gid);
  1292. -        dprintf(CYGWINIDLVL, "userlist\t='%s'\n", grent.userlist);
  1293. -#endif
  1294. -
  1295. -found:
  1296. -        if (res_group_name)
  1297. -            (void)strcpy_s(res_group_name, VAL_LEN, grent.group_name);
  1298. -        *res_gid = gid;
  1299. -        res = 0;
  1300. -    }
  1301. -
  1302. -fail:
  1303. -    if (getent_pipe)
  1304. -        (void)_pclose(getent_pipe);
  1305. -
  1306. -    if (res == 0) {
  1307. -        dprintf(CYGWINIDLVL, "<-- cygwin_getent_group('%s'): "
  1308. -            "returning res_gid=%lu, res_group_name='%s'\n",
  1309. -            name, (unsigned long)(*res_gid),
  1310. -            res_group_name?res_group_name:"<NULL>");
  1311. -    }
  1312. -    else {
  1313. -        dprintf(CYGWINIDLVL,
  1314. -            "<-- cygwin_getent_group('%s'): no match found\n",
  1315. -            name);
  1316. -    }
  1317. -
  1318. -    return res;
  1319. -}
  1320. -#endif /* NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN */
  1321.  
  1322.  /* generic cache */
  1323.  typedef struct list_entry* (*entry_alloc_fn)();
  1324. @@ -906,7 +667,7 @@ static int idmap_lookup_user(
  1325.      if (status == NO_ERROR) {
  1326.          /* don't return expired entries; query new attributes
  1327.           * and overwrite the entry with cache_insert() */
  1328. -        if ((time(NULL) - user->last_updated) < context->config.cache_ttl)
  1329. +        if (difftime(time(NULL), user->last_updated) < (double)context->config.cache_ttl)
  1330.              goto out;
  1331.      }
  1332.  #ifndef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
  1333. @@ -1060,7 +821,7 @@ static int idmap_lookup_group(
  1334.      if (status == NO_ERROR) {
  1335.          /* don't return expired entries; query new attributes
  1336.           * and overwrite the entry with cache_insert() */
  1337. -        if ((time(NULL) - group->last_updated) < context->config.cache_ttl)
  1338. +        if (difftime(time(NULL), group->last_updated) < (double)context->config.cache_ttl)
  1339.              goto out;
  1340.      }
  1341.  #ifndef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
  1342. diff --git a/daemon/idmap.h b/daemon/idmap.h
  1343. index 6a78476..d729575 100644
  1344. --- a/daemon/idmap.h
  1345. +++ b/daemon/idmap.h
  1346. @@ -64,4 +64,10 @@ int nfs41_idmap_gid_to_group(
  1347.      char *name_out,
  1348.      size_t len);
  1349.  
  1350. +/* idmap_cygwin.c */
  1351. +#ifdef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
  1352. +int cygwin_getent_passwd(const char *name, char *res_loginname, uid_t *res_uid, gid_t *res_gid);
  1353. +int cygwin_getent_group(const char* name, char* res_group_name, gid_t* res_gid);
  1354. +#endif /* NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN */
  1355. +
  1356.  #endif /* !IDMAP_H */
  1357. diff --git a/daemon/idmap_cygwin.c b/daemon/idmap_cygwin.c
  1358. new file mode 100644
  1359. index 0000000..5f82f69
  1360. --- /dev/null
  1361. +++ b/daemon/idmap_cygwin.c
  1362. @@ -0,0 +1,261 @@
  1363. +/* NFSv4.1 client for Windows
  1364. + * Copyright x 2023 Roland Mainz <roland.mainz@nrubsig.org>
  1365. + *
  1366. + * Roland Mainz <roland.mainz@nrubsig.org>
  1367. + *
  1368. + * This library is free software; you can redistribute it and/or modify it
  1369. + * under the terms of the GNU Lesser General Public License as published by
  1370. + * the Free Software Foundation; either version 2.1 of the License, or (at
  1371. + * your option) any later version.
  1372. + *
  1373. + * This library is distributed in the hope that it will be useful, but
  1374. + * without any warranty; without even the implied warranty of merchantability
  1375. + * or fitness for a particular purpose.  See the GNU Lesser General Public
  1376. + * License for more details.
  1377. + *
  1378. + * You should have received a copy of the GNU Lesser General Public License
  1379. + * along with this library; if not, write to the Free Software Foundation,
  1380. + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  1381. + */
  1382. +
  1383. +#include <Windows.h>
  1384. +#include <strsafe.h>
  1385. +#include <Winldap.h>
  1386. +#include <stdlib.h> /* for strtoul() */
  1387. +#include <errno.h>
  1388. +#include <time.h>
  1389. +
  1390. +#include "nfs41_build_features.h"
  1391. +#include "idmap.h"
  1392. +#include "nfs41_const.h"
  1393. +#include "list.h"
  1394. +#include "daemon_debug.h"
  1395. +#ifdef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
  1396. +#include "cpvparser1.h"
  1397. +#endif /* NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN */
  1398. +
  1399. +#define CYGWINIDLVL 2   /* dprintf level for idmap logging */
  1400. +
  1401. +#define VAL_LEN 257
  1402. +
  1403. +#define CYGWIN_IDMAPPER_SCRIPT \
  1404. +    ("C:\\cygwin64\\bin\\ksh93.exe " \
  1405. +    "/home/roland_mainz/work/msnfs41_uidmapping/ms-nfs41-client/cygwin_idmapper.ksh")
  1406. +
  1407. +
  1408. +#ifdef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
  1409. +int cygwin_getent_passwd(const char *name, char *res_loginname, uid_t *res_uid, gid_t *res_gid)
  1410. +{
  1411. +    char cmdbuff[1024];
  1412. +    char buff[2048];
  1413. +    size_t num_buff_read;
  1414. +    FILE* script_pipe = NULL;
  1415. +    int res = 1;
  1416. +    unsigned long uid = -1;
  1417. +    unsigned long gid = -1;
  1418. +    void *cpvp = NULL;
  1419. +    int numcnv = 0;
  1420. +    int i = 0;
  1421. +    cpv_name_val cnv[256] = { 0 };
  1422. +    cpv_name_val *cnv_cur = NULL;
  1423. +    const char *localaccoutname = NULL;
  1424. +    int retries = 3;
  1425. +
  1426. +    dprintf(CYGWINIDLVL, "--> cygwin_getent_passwd('%s')\n", name);
  1427. +
  1428. +    /* fixme: better quoting for |name| needed */
  1429. +    (void)snprintf(cmdbuff, sizeof(cmdbuff),
  1430. +        "%s nfsserveruser2localaccount \"%s\"",
  1431. +        CYGWIN_IDMAPPER_SCRIPT,
  1432. +        name);
  1433. +retry:
  1434. +    if ((script_pipe = _popen(cmdbuff, "rt")) == NULL) {
  1435. +        int saved_errno = errno;
  1436. +        dprintf(0, "cygwin_getent_passwd: '%s' failed, errno='%s', retries=%d\n",
  1437. +            cmdbuff,
  1438. +            strerror(saved_errno),
  1439. +            retries);
  1440. +        if ((saved_errno == EINVAL) && (retries-- > 0)) {
  1441. +            (void)SwitchToThread();
  1442. +            goto retry;
  1443. +        }
  1444. +        goto fail;
  1445. +    }
  1446. +
  1447. +    num_buff_read = fread(buff, 1, sizeof(buff), script_pipe);
  1448. +    if (num_buff_read < 10) {
  1449. +        dprintf(0, "cygwin_getent_passwd: Could not read enough data, returned %d\n", (int)num_buff_read);
  1450. +        goto fail;
  1451. +    }
  1452. +
  1453. +    buff[num_buff_read] = '\0';
  1454. +
  1455. +    cpvp = cpv_create_parser(buff, 0/*CPVFLAG_DEBUG_OUTPUT*/);
  1456. +    if (!cpvp) {
  1457. +        dprintf(0, "cygwin_getent_passwd: Could not create parser\n");
  1458. +        goto fail;
  1459. +    }
  1460. +
  1461. +    if (cpv_read_cpv_header(cpvp)) {
  1462. +        dprintf(0, "cygwin_getent_passwd: cpv_read_cpv_header failed\n");
  1463. +        goto fail;
  1464. +    }
  1465. +
  1466. +    for (numcnv=0 ; cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0 ; numcnv++) {
  1467. +    }
  1468. +
  1469. +    for (i=0 ; i < numcnv ; i++) {
  1470. +        cnv_cur = &cnv[i];
  1471. +        if (!strcmp("localaccoutname", cnv_cur->cpv_name)) {
  1472. +            localaccoutname = cnv_cur->cpv_value;
  1473. +        }
  1474. +        else if (!strcmp("localuid", cnv_cur->cpv_name)) {
  1475. +            errno = 0;
  1476. +            uid = strtol(cnv_cur->cpv_value, NULL, 10);
  1477. +            if (errno != 0)
  1478. +                goto fail;
  1479. +        }
  1480. +        else if (!strcmp("localgid", cnv_cur->cpv_name)) {
  1481. +            errno = 0;
  1482. +            gid = strtol(cnv_cur->cpv_value, NULL, 10);
  1483. +            if (errno != 0)
  1484. +                goto fail;
  1485. +        }
  1486. +    }
  1487. +
  1488. +    if (res_loginname)
  1489. +        (void)strcpy_s(res_loginname, VAL_LEN, localaccoutname);
  1490. +    *res_uid = uid;
  1491. +    *res_gid = gid;
  1492. +    res = 0;
  1493. +
  1494. +fail:
  1495. +    if (script_pipe)
  1496. +        (void)_pclose(script_pipe);
  1497. +
  1498. +    for (i=0 ; i < numcnv ; i++) {
  1499. +        cpv_free_name_val_data(&cnv[i]);
  1500. +    }
  1501. +
  1502. +    cpv_free_parser(cpvp);
  1503. +
  1504. +    if (res == 0) {
  1505. +        dprintf(CYGWINIDLVL, "<-- cygwin_getent_passwd('%s'): "
  1506. +            "returning res_uid=%lu, res_gid=%lu, res_loginname='%s'\n",
  1507. +            name,
  1508. +            (unsigned long)(*res_uid),
  1509. +            (unsigned long)(*res_gid),
  1510. +            res_loginname?res_loginname:"<NULL>");
  1511. +    }
  1512. +    else {
  1513. +        dprintf(CYGWINIDLVL, "<-- cygwin_getent_passwd('%s'): no match found\n",
  1514. +            name);
  1515. +    }
  1516. +
  1517. +    return res;
  1518. +}
  1519. +
  1520. +int cygwin_getent_group(const char* name, char* res_group_name, gid_t* res_gid)
  1521. +{
  1522. +    char cmdbuff[1024];
  1523. +    char buff[2048];
  1524. +    size_t num_buff_read;
  1525. +    FILE* script_pipe = NULL;
  1526. +    int res = 1;
  1527. +    unsigned long gid = -1;
  1528. +    void *cpvp = NULL;
  1529. +    int numcnv = 0;
  1530. +    int i = 0;
  1531. +    cpv_name_val cnv[256] = { 0 };
  1532. +    cpv_name_val *cnv_cur = NULL;
  1533. +    int retries = 3;
  1534. +
  1535. +    const char *localgroupname = NULL;
  1536. +
  1537. +    dprintf(CYGWINIDLVL, "--> cygwin_getent_group('%s')\n", name);
  1538. +
  1539. +    /* fixme: better quoting for |name| needed */
  1540. +    (void)snprintf(cmdbuff, sizeof(cmdbuff),
  1541. +        "%s nfsserveruser2localgroup \"%s\"",
  1542. +        CYGWIN_IDMAPPER_SCRIPT,
  1543. +        name);
  1544. +retry:
  1545. +    if ((script_pipe = _popen(cmdbuff, "rt")) == NULL) {
  1546. +        int saved_errno = errno;
  1547. +        dprintf(0,
  1548. +            "cygwin_getent_group: '%s' failed, errno='%s', retries=%d\n",
  1549. +            cmdbuff,
  1550. +            strerror(saved_errno),
  1551. +            retries);
  1552. +        if ((saved_errno == EINVAL) && (retries-- > 0)) {
  1553. +            (void)SwitchToThread();
  1554. +            goto retry;
  1555. +        }
  1556. +        goto fail;
  1557. +    }
  1558. +
  1559. +    num_buff_read = fread(buff, 1, sizeof(buff), script_pipe);
  1560. +    if (num_buff_read < 10) {
  1561. +        dprintf(0, "cygwin_getent_group: Could not read enough data, returned %d\n", (int)num_buff_read);
  1562. +        goto fail;
  1563. +    }
  1564. +
  1565. +    buff[num_buff_read] = '\0';
  1566. +
  1567. +    cpvp = cpv_create_parser(buff, 0/*CPVFLAG_DEBUG_OUTPUT*/);
  1568. +    if (!cpvp) {
  1569. +        dprintf(0, "cygwin_getent_group: Could not create parser\n");
  1570. +        goto fail;
  1571. +    }
  1572. +
  1573. +    if (cpv_read_cpv_header(cpvp)) {
  1574. +        dprintf(0, "cygwin_getent_group: cpv_read_cpv_header failed\n");
  1575. +        goto fail;
  1576. +    }
  1577. +
  1578. +    for (numcnv=0 ; cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0 ; numcnv++) {
  1579. +    }
  1580. +
  1581. +    for (i=0 ; i < numcnv ; i++) {
  1582. +        cnv_cur = &cnv[i];
  1583. +        if (!strcmp("localgroupname", cnv_cur->cpv_name)) {
  1584. +            localgroupname = cnv_cur->cpv_value;
  1585. +        }
  1586. +        else if (!strcmp("localgid", cnv_cur->cpv_name)) {
  1587. +            errno = 0;
  1588. +            gid = strtol(cnv_cur->cpv_value, NULL, 10);
  1589. +            if (errno != 0)
  1590. +                goto fail;
  1591. +        }
  1592. +    }
  1593. +
  1594. +    if (res_group_name)
  1595. +        (void)strcpy_s(res_group_name, VAL_LEN, localgroupname);
  1596. +    *res_gid = gid;
  1597. +    res = 0;
  1598. +
  1599. +fail:
  1600. +    if (script_pipe)
  1601. +        (void)_pclose(script_pipe);
  1602. +
  1603. +    for (i=0 ; i < numcnv ; i++) {
  1604. +        cpv_free_name_val_data(&cnv[i]);
  1605. +    }
  1606. +
  1607. +    cpv_free_parser(cpvp);
  1608. +
  1609. +    if (res == 0) {
  1610. +        dprintf(CYGWINIDLVL, "<-- cygwin_getent_group('%s'): "
  1611. +            "returning res_gid=%lu, res_group_name='%s'\n",
  1612. +            name,
  1613. +            (unsigned long)(*res_gid),
  1614. +            res_group_name?res_group_name:"<NULL>");
  1615. +    }
  1616. +    else {
  1617. +        dprintf(CYGWINIDLVL, "<-- cygwin_getent_group('%s'): no match found\n",
  1618. +            name);
  1619. +    }
  1620. +
  1621. +    return res;
  1622. +}
  1623. +#endif /* NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN */
  1624. diff --git a/daemon/nfs41_daemon.c b/daemon/nfs41_daemon.c
  1625. index 12b7c55..047e468 100644
  1626. --- a/daemon/nfs41_daemon.c
  1627. +++ b/daemon/nfs41_daemon.c
  1628. @@ -33,6 +33,7 @@
  1629.  #include "nfs41_daemon.h"
  1630.  #include "daemon_debug.h"
  1631.  #include "upcall.h"
  1632. +#include "sid.h"
  1633.  #include "util.h"
  1634.  
  1635.  /* nfs41_dg.num_worker_threads sets the actual number of worker threads */
  1636. @@ -409,6 +410,7 @@ VOID ServiceStart(DWORD argc, LPTSTR *argv)
  1637.          exit(1);
  1638.      set_debug_level(cmd_args.debug_level);
  1639.      open_log_files();
  1640. +    sidcache_init();
  1641.  
  1642.  #ifdef _DEBUG
  1643.      /* dump memory leaks to stderr on exit; this requires the debug heap,
  1644. diff --git a/daemon/sid.c b/daemon/sid.c
  1645. new file mode 100644
  1646. index 0000000..21d9732
  1647. --- /dev/null
  1648. +++ b/daemon/sid.c
  1649. @@ -0,0 +1,500 @@
  1650. +/* NFSv4.1 client for Windows
  1651. + * Copyright x 2012 The Regents of the University of Michigan
  1652. + *
  1653. + * Olga Kornievskaia <aglo@umich.edu>
  1654. + * Casey Bodley <cbodley@umich.edu>
  1655. + * Roland Mainz <roland.mainz@nrubsig.org>
  1656. + *
  1657. + * This library is free software; you can redistribute it and/or modify it
  1658. + * under the terms of the GNU Lesser General Public License as published by
  1659. + * the Free Software Foundation; either version 2.1 of the License, or (at
  1660. + * your option) any later version.
  1661. + *
  1662. + * This library is distributed in the hope that it will be useful, but
  1663. + * without any warranty; without even the implied warranty of merchantability
  1664. + * or fitness for a particular purpose.  See the GNU Lesser General Public
  1665. + * License for more details.
  1666. + *
  1667. + * You should have received a copy of the GNU Lesser General Public License
  1668. + * along with this library; if not, write to the Free Software Foundation,
  1669. + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  1670. + */
  1671. +
  1672. +#include <Windows.h>
  1673. +#include <stdio.h>
  1674. +#include <time.h>
  1675. +#include <strsafe.h>
  1676. +#include <sddl.h>
  1677. +
  1678. +#include "nfs41_ops.h"
  1679. +#include "nfs41_build_features.h"
  1680. +#include "nfs41_daemon.h"
  1681. +#include "delegation.h"
  1682. +#include "daemon_debug.h"
  1683. +#include "util.h"
  1684. +#include "upcall.h"
  1685. +#include "nfs41_xdr.h"
  1686. +#include "idmap.h"
  1687. +#include "sid.h"
  1688. +
  1689. +//#define DEBUG_ACLS
  1690. +#define ACLLVL 2 /* dprintf level for acl logging */
  1691. +
  1692. +
  1693. +int create_unknownsid(WELL_KNOWN_SID_TYPE type, PSID *sid, DWORD *sid_len)
  1694. +{
  1695. +    int status;
  1696. +    *sid_len = 0;
  1697. +    *sid = NULL;
  1698. +
  1699. +    status = CreateWellKnownSid(type, NULL, *sid, sid_len);
  1700. +    dprintf(ACLLVL,
  1701. +        "create_unknownsid: CreateWellKnownSid(type=%d) returned %d "
  1702. +        "GetLastError %d sid len %d needed\n", (int)type, status,
  1703. +        GetLastError(), *sid_len);
  1704. +    if (status) {
  1705. +        status = ERROR_INTERNAL_ERROR;
  1706. +        goto err;
  1707. +    }
  1708. +    status = GetLastError();
  1709. +    if (status != ERROR_INSUFFICIENT_BUFFER)
  1710. +        goto err;
  1711. +
  1712. +    *sid = malloc(*sid_len);
  1713. +    if (*sid == NULL) {
  1714. +        status = ERROR_INSUFFICIENT_BUFFER;
  1715. +        goto err;
  1716. +    }
  1717. +    status = CreateWellKnownSid(type, NULL, *sid, sid_len);
  1718. +    if (status)
  1719. +        return ERROR_SUCCESS;
  1720. +    free(*sid);
  1721. +    *sid = NULL;
  1722. +    status = GetLastError();
  1723. +err:
  1724. +    eprintf("create_unknownsid: CreateWellKnownSid(type=%d) failed with %d\n",
  1725. +        (int)type, status);
  1726. +    return status;
  1727. +}
  1728. +
  1729. +#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
  1730. +/*
  1731. + * Allocate a SID from SECURITY_SAMBA_UNIX_AUTHORITY, which encodes an
  1732. + * UNIX/POSIX uid directly into a SID.
  1733. + *
  1734. + * Examples:
  1735. + * UID 1616 gets mapped to "Unix_User+1616", encoding the UID into the
  1736. + * SID as "S-1-22-1-1616":
  1737. + * $ getent passwd Unix_User+1616
  1738. + * Unix_User+1616:*:4278191696:4278191696:U-Unix_User616,S-1-22-1-1616:/:/sbin/nologin
  1739. + *
  1740. + * GID 1984 gets mapped to "Unix_Group+1984", encoding the GID into the
  1741. + * SID as "S-1-22-2-1984":
  1742. + * $ getent group Unix_Group+1984
  1743. + * Unix_Group+1984:S-1-22-2-1984:4278192064:
  1744. + *
  1745. + */
  1746. +
  1747. +#define SECURITY_SAMBA_UNIX_AUTHORITY { { 0,0,0,0,0,22 } }
  1748. +SID_IDENTIFIER_AUTHORITY sid_id_auth = SECURITY_SAMBA_UNIX_AUTHORITY;
  1749. +
  1750. +static
  1751. +BOOL allocate_unixuser_sid(unsigned long uid, PSID *pSid)
  1752. +{
  1753. +    PSID sid = NULL;
  1754. +    PSID malloced_sid = NULL;
  1755. +    DWORD sid_len;
  1756. +
  1757. +    if (AllocateAndInitializeSid(&sid_id_auth, 2, 1, (DWORD)uid,
  1758. +        0, 0, 0, 0, 0, 0, &sid)) {
  1759. +        sid_len = GetLengthSid(sid);
  1760. +
  1761. +        malloced_sid = malloc(sid_len);
  1762. +
  1763. +        if (malloced_sid) {
  1764. +            /*
  1765. +             * |AllocateAndInitializeSid()| has an own memory
  1766. +             * allocator, but we need the sid in memory from
  1767. +             * |malloc()|
  1768. +             */
  1769. +            if (CopySid(sid_len, malloced_sid, sid)) {
  1770. +                FreeSid(sid);
  1771. +                *pSid = malloced_sid;
  1772. +                dprintf(ACLLVL, "allocate_unixuser_sid(): Allocated "
  1773. +                    "Unix_User+%lu: success, len=%ld\n",
  1774. +                    uid, (long)sid_len);
  1775. +                return TRUE;
  1776. +            }
  1777. +        }
  1778. +    }
  1779. +
  1780. +    FreeSid(sid);
  1781. +    free(malloced_sid);
  1782. +    dprintf(ACLLVL, "allocate_unixuser_sid(): Failed to allocate "
  1783. +        "SID for Unix_User+%lu: error code %d\n",
  1784. +        uid, GetLastError());
  1785. +    return FALSE;
  1786. +}
  1787. +
  1788. +static
  1789. +BOOL allocate_unixgroup_sid(unsigned long gid, PSID *pSid)
  1790. +{
  1791. +    PSID sid = NULL;
  1792. +    PSID malloced_sid = NULL;
  1793. +    DWORD sid_len;
  1794. +
  1795. +    if (AllocateAndInitializeSid(&sid_id_auth, 2, 2, (DWORD)gid,
  1796. +        0, 0, 0, 0, 0, 0, &sid)) {
  1797. +        sid_len = GetLengthSid(sid);
  1798. +
  1799. +        malloced_sid = malloc(sid_len);
  1800. +
  1801. +        if (malloced_sid) {
  1802. +            /*
  1803. +             * |AllocateAndInitializeSid()| has an own memory
  1804. +             * allocator, but we need the sid in memory from
  1805. +             * |malloc()|
  1806. +             */
  1807. +            if (CopySid(sid_len, malloced_sid, sid)) {
  1808. +                FreeSid(sid);
  1809. +                *pSid = malloced_sid;
  1810. +                dprintf(ACLLVL, "allocate_unixgroup_sid(): Allocated "
  1811. +                    "Unix_Group+%lu: success, len=%ld\n",
  1812. +                    gid, (long)sid_len);
  1813. +                return TRUE;
  1814. +            }
  1815. +        }
  1816. +    }
  1817. +
  1818. +    FreeSid(sid);
  1819. +    free(malloced_sid);
  1820. +    dprintf(ACLLVL, "allocate_unixgroup_sid(): Failed to allocate "
  1821. +        "SID for Unix_Group+%lu: error code %d\n",
  1822. +        gid, GetLastError());
  1823. +    return FALSE;
  1824. +}
  1825. +#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
  1826. +
  1827. +
  1828. +/* fixme: should be in sys/nfs41_build_features.h */
  1829. +#define USE_SID_CACHE 1
  1830. +
  1831. +
  1832. +#ifdef USE_SID_CACHE
  1833. +#define SIDCACHE_SIZE 20
  1834. +#define SIDCACHE_TTL 600
  1835. +
  1836. +typedef struct _sidcache_entry
  1837. +{
  1838. +    char    name[128]; /* must fit something like "user@domain" */
  1839. +    PSID    sid;
  1840. +    DWORD   sid_len;
  1841. +    time_t  timestamp;
  1842. +} sidcache_entry;
  1843. +
  1844. +typedef struct _sidcache
  1845. +{
  1846. +    CRITICAL_SECTION    lock;
  1847. +    sidcache_entry      entries[SIDCACHE_SIZE];
  1848. +    ssize_t             cacheIndex;
  1849. +} sidcache;
  1850. +
  1851. +/* fixme: need function to deallocate this */
  1852. +sidcache user_sidcache = { 0 };
  1853. +
  1854. +
  1855. +void sidcache_init(void)
  1856. +{
  1857. +    dprintf(0, "SID cache init\n");
  1858. +    InitializeCriticalSection(&user_sidcache.lock);
  1859. +}
  1860. +
  1861. +/* copy SID |value| into cache */
  1862. +void sidcache_add(sidcache *cache, const char* name, PSID value)
  1863. +{
  1864. +    int i;
  1865. +    ssize_t freeEntryIndex;
  1866. +    time_t currentTimestamp;
  1867. +
  1868. +    EnterCriticalSection(&cache->lock);
  1869. +    currentTimestamp = time(NULL);
  1870. +
  1871. +    /* purge obsolete entries */
  1872. +    for (i = 0; i < SIDCACHE_SIZE; i++) {
  1873. +        sidcache_entry *e = &cache->entries[i];
  1874. +
  1875. +        if ((e->sid != NULL) &&
  1876. +            (e->timestamp < (currentTimestamp - SIDCACHE_TTL))) {
  1877. +            free(e->sid);
  1878. +            e->sid = NULL;
  1879. +            e->name[0] = '\0';
  1880. +        }
  1881. +    }
  1882. +
  1883. +    /* Find the oldest valid cache entry */
  1884. +    freeEntryIndex = -1;
  1885. +    for (i = 0; i < SIDCACHE_SIZE; i++) {
  1886. +        if (cache->entries[i].sid == NULL) {
  1887. +            freeEntryIndex = i;
  1888. +            break;
  1889. +        }
  1890. +    }
  1891. +
  1892. +    /* If no valid entry was found, overwrite the oldest entry */
  1893. +    if (freeEntryIndex == -1) {
  1894. +        freeEntryIndex = cache->cacheIndex;
  1895. +    }
  1896. +
  1897. +    /* Replace the cache entry */
  1898. +    DWORD sid_len = GetLengthSid(value);
  1899. +    PSID malloced_sid = malloc(sid_len);
  1900. +    if (!malloced_sid)
  1901. +        goto done;
  1902. +    if (!CopySid(sid_len, malloced_sid, value)) {
  1903. +        free(malloced_sid);
  1904. +        goto done;
  1905. +    }
  1906. +
  1907. +    sidcache_entry *e = &cache->entries[freeEntryIndex];
  1908. +
  1909. +    e->sid_len = sid_len;
  1910. +    if (e->sid)
  1911. +        free(e->sid);
  1912. +    e->sid = malloced_sid;
  1913. +    (void)strcpy_s(e->name, sizeof(e->name), name);
  1914. +    e->timestamp = currentTimestamp;
  1915. +
  1916. +    cache->cacheIndex = (cache->cacheIndex + 1) % SIDCACHE_SIZE;
  1917. +
  1918. +done:
  1919. +    LeaveCriticalSection(&cache->lock);
  1920. +}
  1921. +
  1922. +/* return |malloc()|'ed copy of SID from cache entry */
  1923. +PSID *sidcache_getcached(sidcache *cache, const char *name)
  1924. +{
  1925. +    int i;
  1926. +    time_t currentTimestamp;
  1927. +    sidcache_entry *e;
  1928. +    PSID *ret_sid = NULL;
  1929. +
  1930. +    EnterCriticalSection(&cache->lock);
  1931. +    currentTimestamp = time(NULL);
  1932. +
  1933. +    for (i = 0; i < SIDCACHE_SIZE; i++) {
  1934. +        e = &cache->entries[i];
  1935. +
  1936. +        if ((e->sid != NULL) &&
  1937. +            (!strcmp(e->name, name)) &&
  1938. +            ((currentTimestamp - e->timestamp) < SIDCACHE_TTL)) {
  1939. +            PSID malloced_sid = malloc(e->sid_len);
  1940. +            if (!malloced_sid)
  1941. +                goto done;
  1942. +
  1943. +            if (!CopySid(e->sid_len, malloced_sid, e->sid)) {
  1944. +                free(malloced_sid);
  1945. +                goto done;
  1946. +            }
  1947. +
  1948. +            ret_sid = malloced_sid;
  1949. +            goto done;
  1950. +        }
  1951. +    }
  1952. +
  1953. +done:
  1954. +    LeaveCriticalSection(&cache->lock);
  1955. +    return ret_sid;
  1956. +}
  1957. +#endif /* USE_SID_CACHE */
  1958. +
  1959. +
  1960. +int map_nfs4servername_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_len, PSID *sid, LPCSTR name)
  1961. +{
  1962. +    const char *orig_name = name;
  1963. +
  1964. +    int status = ERROR_INTERNAL_ERROR;
  1965. +    SID_NAME_USE sid_type;
  1966. +    char name_buff[256+2];
  1967. +    LPSTR tmp_buf = NULL;
  1968. +    DWORD tmp = 0;
  1969. +#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
  1970. +    signed long user_uid = -1;
  1971. +    signed long group_gid = -1;
  1972. +#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
  1973. +
  1974. +#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
  1975. +    /* use our own idmapper script to map nfsv4 owner string to local Windows account */
  1976. +    if (query & OWNER_SECURITY_INFORMATION) {
  1977. +        uid_t udummy = -1;
  1978. +        gid_t gdummy = -1;
  1979. +
  1980. +#ifdef USE_SID_CACHE
  1981. +        if (*sid = sidcache_getcached(&user_sidcache, name)) {
  1982. +            *sid_len = GetLengthSid(*sid);
  1983. +            dprintf(1, "map_nfs4servername_2_sid: returning cached sid for '%s'\n", name);
  1984. +            return 0;
  1985. +        }
  1986. +#endif /* USE_SID_CACHE */
  1987. +
  1988. +#ifndef USE_SID_CACHE
  1989. +        /* gisburn: fixme: We must cache this, or the performance impact will be devastating!! */
  1990. +#endif /* !USE_SID_CACHE */
  1991. +        if (!cygwin_getent_passwd(name, name_buff, &udummy, &gdummy)) {
  1992. +            if (strcmp(name, name_buff)) {
  1993. +                dprintf(1,
  1994. +                    "map_nfs4servername_2_sid: remap '%s' --> '%s'\n",
  1995. +                    name,
  1996. +                    name_buff);
  1997. +                name = name_buff;
  1998. +            }
  1999. +        }
  2000. +    }
  2001. +#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
  2002. +
  2003. +    status = LookupAccountName(NULL, name, NULL, sid_len, NULL, &tmp, &sid_type);
  2004. +    dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): LookupAccountName returned %d "
  2005. +        "GetLastError %d name len %d domain len %d\n",
  2006. +        query, name, status, GetLastError(), *sid_len, tmp);
  2007. +    if (status)
  2008. +        return ERROR_INTERNAL_ERROR;
  2009. +
  2010. +    status = GetLastError();
  2011. +    switch(status) {
  2012. +    case ERROR_INSUFFICIENT_BUFFER:
  2013. +        *sid = malloc(*sid_len);
  2014. +        if (*sid == NULL) {
  2015. +            status = GetLastError();
  2016. +            goto out;
  2017. +        }
  2018. +        tmp_buf = (LPSTR) malloc(tmp);
  2019. +        if (tmp_buf == NULL)
  2020. +            goto out_free_sid;
  2021. +        status = LookupAccountName(NULL, name, *sid, sid_len, tmp_buf,
  2022. +                                    &tmp, &sid_type);
  2023. +        free(tmp_buf);
  2024. +        if (!status) {
  2025. +            eprintf("map_nfs4servername_2_sid(query=%x,name='%s'): LookupAccountName failed "
  2026. +                    "with %d\n", query, name, GetLastError());
  2027. +            goto out_free_sid;
  2028. +        } else {
  2029. +#ifdef DEBUG_ACLS
  2030. +            LPSTR ssid = NULL;
  2031. +            if (IsValidSid(*sid))
  2032. +                if (ConvertSidToStringSidA(*sid, &ssid))
  2033. +                    dprintf(1, "map_nfs4servername_2_sid: sid_type = %d SID '%s'\n",
  2034. +                        sid_type, ssid);
  2035. +                else
  2036. +                    dprintf(1, "map_nfs4servername_2_sid: ConvertSidToStringSidA failed "
  2037. +                        "with %d\n", GetLastError());
  2038. +            else
  2039. +                dprintf(1, "map_nfs4servername_2_sid: Invalid Sid ?\n");
  2040. +            if (ssid)
  2041. +                LocalFree(ssid);
  2042. +#endif
  2043. +        }
  2044. +        status = ERROR_SUCCESS;
  2045. +        break;
  2046. +    case ERROR_NONE_MAPPED:
  2047. +#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
  2048. +        dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): "
  2049. +            "none mapped, "
  2050. +            "trying Unix_User+/Unix_Group+ mapping\n",
  2051. +            query, name);
  2052. +
  2053. +        if ((user_uid == -1) && (query & OWNER_SECURITY_INFORMATION)) {
  2054. +            uid_t map_uid = -1;
  2055. +            gid_t gid_dummy = -1;
  2056. +
  2057. +            if (nfs41_idmap_name_to_ids(
  2058. +                nfs41dg->idmapper,
  2059. +                name,
  2060. +                &map_uid,
  2061. +                &gid_dummy) == 0) {
  2062. +                user_uid = map_uid;
  2063. +            }
  2064. +            else {
  2065. +                dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): nfs41_idmap_name_to_ids() failed\n",
  2066. +                    query, name);
  2067. +                /* fixme: try harder here, "1234" should to to |atol()| */
  2068. +            }
  2069. +        }
  2070. +
  2071. +        if ((group_gid == -1) && (query & GROUP_SECURITY_INFORMATION)) {
  2072. +            gid_t map_gid = -1;
  2073. +
  2074. +            if (nfs41_idmap_group_to_gid(
  2075. +                nfs41dg->idmapper,
  2076. +                name,
  2077. +                &map_gid) == 0) {
  2078. +                group_gid = map_gid;
  2079. +            }
  2080. +            else {
  2081. +                dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): nfs41_idmap_group_to_gid() failed\n",
  2082. +                    query, name);
  2083. +                /* fixme: try harder here, "1234" should to to |atol()| */
  2084. +            }
  2085. +        }
  2086. +
  2087. +        if (user_uid != -1) {
  2088. +            if (allocate_unixuser_sid(user_uid, sid)) {
  2089. +                dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): "
  2090. +                    "allocate_unixuser_sid(uid=%ld) success\n",
  2091. +                    query, name, user_uid);
  2092. +                status = ERROR_SUCCESS;
  2093. +                goto out;
  2094. +            }
  2095. +
  2096. +            status = GetLastError();
  2097. +            dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): "
  2098. +                "allocate_unixuser_sid(uid=%ld) failed, error=%d\n",
  2099. +                query, name, user_uid, status);
  2100. +            return status;
  2101. +        }
  2102. +
  2103. +        if (group_gid != -1) {
  2104. +            if (allocate_unixgroup_sid(group_gid, sid)) {
  2105. +                dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): "
  2106. +                    "allocate_unixgroup_sid(gid=%ld) success\n",
  2107. +                    query, name, group_gid);
  2108. +                status = ERROR_SUCCESS;
  2109. +                goto out;
  2110. +            }
  2111. +
  2112. +            status = GetLastError();
  2113. +            dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): "
  2114. +                "allocate_unixgroup_sid(gid=%ld) failed, error=%d\n",
  2115. +                query, name, group_gid, status);
  2116. +            return status;
  2117. +        }
  2118. +#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
  2119. +
  2120. +        dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): none mapped, "
  2121. +            "using WinNullSid mapping\n",
  2122. +            query, name);
  2123. +
  2124. +        status = create_unknownsid(WinNullSid, sid, sid_len);
  2125. +        if (status)
  2126. +            goto out_free_sid;
  2127. +        break;
  2128. +    default:
  2129. +        dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): error %d not handled\n",
  2130. +            query, name, GetLastError());
  2131. +        break;
  2132. +    }
  2133. +out:
  2134. +#ifdef USE_SID_CACHE
  2135. +    if (*sid) {
  2136. +        /* fixme: No other flags in |query| must be set!! */
  2137. +        if (query & OWNER_SECURITY_INFORMATION) {
  2138. +            sidcache_add(&user_sidcache, orig_name, *sid);
  2139. +        }
  2140. +    }
  2141. +#endif /* USE_SID_CACHE */
  2142. +
  2143. +    return status;
  2144. +out_free_sid:
  2145. +    status = GetLastError();
  2146. +    free(*sid);
  2147. +    *sid = NULL;
  2148. +    goto out;
  2149. +}
  2150. diff --git a/daemon/sid.h b/daemon/sid.h
  2151. new file mode 100644
  2152. index 0000000..e6d87c5
  2153. --- /dev/null
  2154. +++ b/daemon/sid.h
  2155. @@ -0,0 +1,35 @@
  2156. +
  2157. +/* NFSv4.1 client for Windows
  2158. + * Copyright x 2012 The Regents of the University of Michigan
  2159. + *
  2160. + * Olga Kornievskaia <aglo@umich.edu>
  2161. + * Casey Bodley <cbodley@umich.edu>
  2162. + * Roland Mainz <roland.mainz@nrubsig.org>
  2163. + *
  2164. + * This library is free software; you can redistribute it and/or modify it
  2165. + * under the terms of the GNU Lesser General Public License as published by
  2166. + * the Free Software Foundation; either version 2.1 of the License, or (at
  2167. + * your option) any later version.
  2168. + *
  2169. + * This library is distributed in the hope that it will be useful, but
  2170. + * without any warranty; without even the implied warranty of merchantability
  2171. + * or fitness for a particular purpose.  See the GNU Lesser General Public
  2172. + * License for more details.
  2173. + *
  2174. + * You should have received a copy of the GNU Lesser General Public License
  2175. + * along with this library; if not, write to the Free Software Foundation,
  2176. + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  2177. + */
  2178. +
  2179. +#ifndef __NFS41_DAEMON_SID_H
  2180. +#define __NFS41_DAEMON_SID_H 1
  2181. +
  2182. +#include "nfs41_build_features.h"
  2183. +#include "nfs41_daemon.h"
  2184. +
  2185. +/* prototypes */
  2186. +int create_unknownsid(WELL_KNOWN_SID_TYPE type, PSID *sid, DWORD *sid_len);
  2187. +void sidcache_init(void);
  2188. +int map_nfs4servername_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_len, PSID *sid, LPCSTR name);
  2189. +
  2190. +#endif /* !__NFS41_DAEMON_SID_H */
  2191. --
  2192. 2.42.1
  2193.  
  2194. From 00ec1812f6e7ff3c918844f9e7f935978456cf11 Mon Sep 17 00:00:00 2001
  2195. From: Roland Mainz <roland.mainz@nrubsig.org>
  2196. Date: Tue, 28 Nov 2023 16:33:23 +0100
  2197. Subject: [PATCH 2/2] daemon: Fix Cygwin idmapper random |popen()| failure
  2198.  
  2199. Fix Cygwin idmapper random |popen()| failure by replacing Win32
  2200. |popen()| with our own code to read output from the idmapper
  2201. script.
  2202.  
  2203. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  2204. ---
  2205. cygwin_idmapper.ksh   |   4 +-
  2206.  daemon/idmap_cygwin.c |  85 +++++++++++++++---------------
  2207.  daemon/util.c         | 119 ++++++++++++++++++++++++++++++++++++++++++
  2208.  daemon/util.h         |  10 ++++
  2209.  4 files changed, 174 insertions(+), 44 deletions(-)
  2210.  
  2211. diff --git a/cygwin_idmapper.ksh b/cygwin_idmapper.ksh
  2212. index 4b96ecf..acf6e32 100644
  2213. --- a/cygwin_idmapper.ksh
  2214. +++ b/cygwin_idmapper.ksh
  2215. @@ -79,7 +79,7 @@ compound -A localgroups=(
  2216.  )
  2217.  
  2218.  case "${c.mode}" in
  2219. -       'nfsserveruser2localaccount')
  2220. +       'nfsserver_owner2localaccount')
  2221.                 if [[ "${c.name}" == ~(Elr)[[:digit:]]+ ]] ; then
  2222.                         for s in "${!localusers[@]}" ; do
  2223.                                 if (( localusers[$s].localuid == c.name )) ; then
  2224. @@ -97,7 +97,7 @@ case "${c.mode}" in
  2225.                         exit 1
  2226.                 fi
  2227.                 ;;
  2228. -       'nfsserveruser2localgroup')
  2229. +       'nfsserver_owner_group2localgroup')
  2230.                 if [[ "${c.name}" == ~(Elr)[[:digit:]]+ ]] ; then
  2231.                         for s in "${!localgroups[@]}" ; do
  2232.                                 if (( localgroups[$s].localgid == c.name )) ; then
  2233. diff --git a/daemon/idmap_cygwin.c b/daemon/idmap_cygwin.c
  2234. index 5f82f69..64c1bff 100644
  2235. --- a/daemon/idmap_cygwin.c
  2236. +++ b/daemon/idmap_cygwin.c
  2237. @@ -22,11 +22,11 @@
  2238.  #include <strsafe.h>
  2239.  #include <Winldap.h>
  2240.  #include <stdlib.h> /* for strtoul() */
  2241. -#include <errno.h>
  2242.  #include <time.h>
  2243.  
  2244.  #include "nfs41_build_features.h"
  2245.  #include "idmap.h"
  2246. +#include "util.h"
  2247.  #include "nfs41_const.h"
  2248.  #include "list.h"
  2249.  #include "daemon_debug.h"
  2250. @@ -48,48 +48,46 @@ int cygwin_getent_passwd(const char *name, char *res_loginname, uid_t *res_uid,
  2251.  {
  2252.      char cmdbuff[1024];
  2253.      char buff[2048];
  2254. -    size_t num_buff_read;
  2255. -    FILE* script_pipe = NULL;
  2256. +    DWORD num_buff_read;
  2257. +    subcmd_popen_context *script_pipe = NULL;
  2258.      int res = 1;
  2259.      unsigned long uid = -1;
  2260.      unsigned long gid = -1;
  2261.      void *cpvp = NULL;
  2262.      int numcnv = 0;
  2263.      int i = 0;
  2264. -    cpv_name_val cnv[256] = { 0 };
  2265. +    cpv_name_val cnv[64] = { 0 };
  2266.      cpv_name_val *cnv_cur = NULL;
  2267.      const char *localaccoutname = NULL;
  2268. -    int retries = 3;
  2269.  
  2270.      dprintf(CYGWINIDLVL, "--> cygwin_getent_passwd('%s')\n", name);
  2271.  
  2272.      /* fixme: better quoting for |name| needed */
  2273.      (void)snprintf(cmdbuff, sizeof(cmdbuff),
  2274. -        "%s nfsserveruser2localaccount \"%s\"",
  2275. +        "%s nfsserver_owner2localaccount \"%s\"",
  2276.          CYGWIN_IDMAPPER_SCRIPT,
  2277.          name);
  2278. -retry:
  2279. -    if ((script_pipe = _popen(cmdbuff, "rt")) == NULL) {
  2280. -        int saved_errno = errno;
  2281. -        dprintf(0, "cygwin_getent_passwd: '%s' failed, errno='%s', retries=%d\n",
  2282. +    if ((script_pipe = subcmd_popen(cmdbuff)) == NULL) {
  2283. +        int last_error = GetLastError();
  2284. +        dprintf(0, "cygwin_getent_passwd: '%s' failed, GetLastError()='%d'\n",
  2285.              cmdbuff,
  2286. -            strerror(saved_errno),
  2287. -            retries);
  2288. -        if ((saved_errno == EINVAL) && (retries-- > 0)) {
  2289. -            (void)SwitchToThread();
  2290. -            goto retry;
  2291. -        }
  2292. +            last_error);
  2293.          goto fail;
  2294.      }
  2295.  
  2296. -    num_buff_read = fread(buff, 1, sizeof(buff), script_pipe);
  2297. -    if (num_buff_read < 10) {
  2298. -        dprintf(0, "cygwin_getent_passwd: Could not read enough data, returned %d\n", (int)num_buff_read);
  2299. +    if (!subcmd_readcmdoutput(script_pipe,
  2300. +        buff, sizeof(buff), &num_buff_read)) {
  2301. +        dprintf(0, "cygwin_getent_passwd: subcmd_readcmdoutput() failed\n");
  2302.          goto fail;
  2303.      }
  2304.  
  2305.      buff[num_buff_read] = '\0';
  2306.  
  2307. +    if (num_buff_read < 10) {
  2308. +        dprintf(0, "cygwin_getent_passwd: Could not read enough data, returned %d\n", (int)num_buff_read);
  2309. +        goto fail;
  2310. +    }
  2311. +
  2312.      cpvp = cpv_create_parser(buff, 0/*CPVFLAG_DEBUG_OUTPUT*/);
  2313.      if (!cpvp) {
  2314.          dprintf(0, "cygwin_getent_passwd: Could not create parser\n");
  2315. @@ -101,7 +99,10 @@ retry:
  2316.          goto fail;
  2317.      }
  2318.  
  2319. -    for (numcnv=0 ; cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0 ; numcnv++) {
  2320. +    /* Loop parsing compound variable elements */
  2321. +    for (numcnv=0 ;
  2322. +        (cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0) && (numcnv < 64) ;
  2323. +        numcnv++) {
  2324.      }
  2325.  
  2326.      for (i=0 ; i < numcnv ; i++) {
  2327. @@ -131,7 +132,7 @@ retry:
  2328.  
  2329.  fail:
  2330.      if (script_pipe)
  2331. -        (void)_pclose(script_pipe);
  2332. +        (void)subcmd_pclose(script_pipe);
  2333.  
  2334.      for (i=0 ; i < numcnv ; i++) {
  2335.          cpv_free_name_val_data(&cnv[i]);
  2336. @@ -159,16 +160,15 @@ int cygwin_getent_group(const char* name, char* res_group_name, gid_t* res_gid)
  2337.  {
  2338.      char cmdbuff[1024];
  2339.      char buff[2048];
  2340. -    size_t num_buff_read;
  2341. -    FILE* script_pipe = NULL;
  2342. +    DWORD num_buff_read;
  2343. +    subcmd_popen_context *script_pipe = NULL;
  2344.      int res = 1;
  2345.      unsigned long gid = -1;
  2346.      void *cpvp = NULL;
  2347.      int numcnv = 0;
  2348.      int i = 0;
  2349. -    cpv_name_val cnv[256] = { 0 };
  2350. +    cpv_name_val cnv[64] = { 0 };
  2351.      cpv_name_val *cnv_cur = NULL;
  2352. -    int retries = 3;
  2353.  
  2354.      const char *localgroupname = NULL;
  2355.  
  2356. @@ -176,32 +176,30 @@ int cygwin_getent_group(const char* name, char* res_group_name, gid_t* res_gid)
  2357.  
  2358.      /* fixme: better quoting for |name| needed */
  2359.      (void)snprintf(cmdbuff, sizeof(cmdbuff),
  2360. -        "%s nfsserveruser2localgroup \"%s\"",
  2361. +        "%s nfsserver_owner_group2localgroup \"%s\"",
  2362.          CYGWIN_IDMAPPER_SCRIPT,
  2363.          name);
  2364. -retry:
  2365. -    if ((script_pipe = _popen(cmdbuff, "rt")) == NULL) {
  2366. -        int saved_errno = errno;
  2367. -        dprintf(0,
  2368. -            "cygwin_getent_group: '%s' failed, errno='%s', retries=%d\n",
  2369. +    if ((script_pipe = subcmd_popen(cmdbuff)) == NULL) {
  2370. +        int last_error = GetLastError();
  2371. +        dprintf(0, "cygwin_getent_group: '%s' failed, GetLastError()='%d'\n",
  2372.              cmdbuff,
  2373. -            strerror(saved_errno),
  2374. -            retries);
  2375. -        if ((saved_errno == EINVAL) && (retries-- > 0)) {
  2376. -            (void)SwitchToThread();
  2377. -            goto retry;
  2378. -        }
  2379. +            last_error);
  2380.          goto fail;
  2381.      }
  2382.  
  2383. -    num_buff_read = fread(buff, 1, sizeof(buff), script_pipe);
  2384. -    if (num_buff_read < 10) {
  2385. -        dprintf(0, "cygwin_getent_group: Could not read enough data, returned %d\n", (int)num_buff_read);
  2386. +    if (!subcmd_readcmdoutput(script_pipe,
  2387. +        buff, sizeof(buff), &num_buff_read)) {
  2388. +        dprintf(0, "cygwin_getent_group: subcmd_readcmdoutput() failed\n");
  2389.          goto fail;
  2390.      }
  2391.  
  2392.      buff[num_buff_read] = '\0';
  2393.  
  2394. +    if (num_buff_read < 10) {
  2395. +        dprintf(0, "cygwin_getent_group: Could not read enough data, returned %d\n", (int)num_buff_read);
  2396. +        goto fail;
  2397. +    }
  2398. +
  2399.      cpvp = cpv_create_parser(buff, 0/*CPVFLAG_DEBUG_OUTPUT*/);
  2400.      if (!cpvp) {
  2401.          dprintf(0, "cygwin_getent_group: Could not create parser\n");
  2402. @@ -213,7 +211,10 @@ retry:
  2403.          goto fail;
  2404.      }
  2405.  
  2406. -    for (numcnv=0 ; cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0 ; numcnv++) {
  2407. +    /* Loop parsing compound variable elements */
  2408. +    for (numcnv=0 ;
  2409. +        (cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0) && (numcnv < 64) ;
  2410. +        numcnv++) {
  2411.      }
  2412.  
  2413.      for (i=0 ; i < numcnv ; i++) {
  2414. @@ -236,7 +237,7 @@ retry:
  2415.  
  2416.  fail:
  2417.      if (script_pipe)
  2418. -        (void)_pclose(script_pipe);
  2419. +        (void)subcmd_pclose(script_pipe);
  2420.  
  2421.      for (i=0 ; i < numcnv ; i++) {
  2422.          cpv_free_name_val_data(&cnv[i]);
  2423. diff --git a/daemon/util.c b/daemon/util.c
  2424. index 3680d27..3051f4b 100644
  2425. --- a/daemon/util.c
  2426. +++ b/daemon/util.c
  2427. @@ -3,6 +3,7 @@
  2428.   *
  2429.   * Olga Kornievskaia <aglo@umich.edu>
  2430.   * Casey Bodley <cbodley@umich.edu>
  2431. + * Roland Mainz <roland.mainz@nrubsig.org>
  2432.   *
  2433.   * This library is free software; you can redistribute it and/or modify it
  2434.   * under the terms of the GNU Lesser General Public License as published by
  2435. @@ -458,3 +459,121 @@ out_context:
  2436.  out:
  2437.      return status;
  2438.  }
  2439. +
  2440. +
  2441. +/*
  2442. + * Like Win32 |popen()| but doesn't randomly fail or genrates EINVAL
  2443. + * for unknown reasons
  2444. + */
  2445. +subcmd_popen_context *subcmd_popen(const char *command)
  2446. +{
  2447. +    subcmd_popen_context *pinfo;
  2448. +    STARTUPINFOA si;
  2449. +    SECURITY_ATTRIBUTES sa = { 0 };
  2450. +
  2451. +    if (!command) {
  2452. +        return NULL;
  2453. +    }
  2454. +
  2455. +    pinfo = malloc(sizeof(subcmd_popen_context));
  2456. +    if (!pinfo)
  2457. +        return NULL;
  2458. +
  2459. +    pinfo->hReadPipe = pinfo->hWritePipe = NULL;
  2460. +
  2461. +#ifdef NOT_WORKING_YET
  2462. +    /*
  2463. +     * gisburn: fixme: Currently |CreatePipe()| can fail with
  2464. +     * |ERROR_BAD_IMPERSONATION_LEVEL|/|1346| for user
  2465. +     * "SYSTEM" if nfsd(|debug).exe tries to impersonate
  2466. +     * user "SYSTEM" while running as normal user.
  2467. +     */
  2468. +    SECURITY_DESCRIPTOR sd;
  2469. +    (void)memset(&sd, 0, sizeof(SECURITY_DESCRIPTOR));
  2470. +    (void)InitializeSecurityDescriptor(&sd, 1);
  2471. +    sd.Revision = 1;
  2472. +    sd.Control |= SE_DACL_PRESENT;
  2473. +    sd.Dacl = NULL;
  2474. +#endif /* NOT_WORKING_YET */
  2475. +
  2476. +    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  2477. +    sa.bInheritHandle = TRUE;
  2478. +#ifdef NOT_WORKING_YET
  2479. +    sa.lpSecurityDescriptor = &sd;
  2480. +#else
  2481. +    sa.lpSecurityDescriptor = NULL;
  2482. +#endif /* NOT_WORKING_YET */
  2483. +
  2484. +    /*
  2485. +     * Create a pipe for communication between the parent and child
  2486. +     * processes
  2487. +     */
  2488. +    if (!CreatePipe(&pinfo->hReadPipe, &pinfo->hWritePipe, &sa, 0)) {
  2489. +        dprintf(0, "subcmd_popen: CreatePipe error, status=%d\n",
  2490. +            (int)GetLastError());
  2491. +        goto fail;
  2492. +    }
  2493. +
  2494. +    /* Set the pipe handles to non-inheritable */
  2495. +    if (!SetHandleInformation(pinfo->hReadPipe, HANDLE_FLAG_INHERIT, FALSE)) {
  2496. +        dprintf(0, "subcmd_popen: SetHandleInformation error\n");
  2497. +        goto fail;
  2498. +    }
  2499. +
  2500. +    (void)memset(&si, 0, sizeof(si));
  2501. +    si.cb = sizeof(si);
  2502. +    si.hStdInput = NULL;
  2503. +    si.hStdOutput = pinfo->hWritePipe;
  2504. +    si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
  2505. +    si.dwFlags |= STARTF_USESTDHANDLES;
  2506. +
  2507. +    if (!CreateProcessA(NULL,
  2508. +        (LPSTR)command, NULL, NULL, TRUE, 0, NULL, NULL, &si,
  2509. +        &pinfo->pi)) {
  2510. +        dprintf(0, "subcmd_popen: cannot create process\n");
  2511. +        goto fail;
  2512. +    }
  2513. +
  2514. +    CloseHandle(pinfo->hWritePipe);
  2515. +
  2516. +    return pinfo;
  2517. +fail:
  2518. +    if (pinfo) {
  2519. +        if (pinfo->hReadPipe)
  2520. +            CloseHandle(pinfo->hReadPipe);
  2521. +        if (pinfo->hWritePipe)
  2522. +            CloseHandle(pinfo->hWritePipe);
  2523. +
  2524. +        free(pinfo);
  2525. +    }
  2526. +    return NULL;
  2527. +}
  2528. +
  2529. +int subcmd_pclose(subcmd_popen_context *pinfo)
  2530. +{
  2531. +    DWORD status;
  2532. +
  2533. +    /* Close the read handle to the pipe from the child process */
  2534. +    CloseHandle(pinfo->hReadPipe);
  2535. +
  2536. +    WaitForSingleObject(pinfo->pi.hProcess, INFINITE);
  2537. +
  2538. +    if (!GetExitCodeProcess(pinfo->pi.hProcess, &status)) {
  2539. +        status = -1;
  2540. +    }
  2541. +
  2542. +    CloseHandle(pinfo->pi.hProcess);
  2543. +    CloseHandle(pinfo->pi.hThread);
  2544. +
  2545. +    if (status != 0) {
  2546. +        (void)dprintf(0, "subcmd_pclose(): exit code=%d\n", (int)status);
  2547. +    }
  2548. +    free(pinfo);
  2549. +
  2550. +    return status;
  2551. +}
  2552. +
  2553. +BOOL subcmd_readcmdoutput(subcmd_popen_context *pinfo, char *buff, size_t buff_size, DWORD *num_buff_read_ptr)
  2554. +{
  2555. +    return ReadFile(pinfo->hReadPipe, buff, (DWORD)buff_size, num_buff_read_ptr, NULL);
  2556. +}
  2557. diff --git a/daemon/util.h b/daemon/util.h
  2558. index 573e0fe..3d6395a 100644
  2559. --- a/daemon/util.h
  2560. +++ b/daemon/util.h
  2561. @@ -256,4 +256,14 @@ __inline int valid_handle(HANDLE handle) {
  2562.      return handle != INVALID_HANDLE_VALUE && handle != 0;
  2563.  }
  2564.  
  2565. +typedef struct _subcmd_popen_context {
  2566. +    HANDLE hReadPipe;
  2567. +    HANDLE hWritePipe;
  2568. +    PROCESS_INFORMATION pi;
  2569. +} subcmd_popen_context;
  2570. +
  2571. +subcmd_popen_context *subcmd_popen(const char *command);
  2572. +int subcmd_pclose(subcmd_popen_context *pinfo);
  2573. +BOOL subcmd_readcmdoutput(subcmd_popen_context *pinfo, char *buff, size_t buff_size, DWORD *num_buff_read_ptr);
  2574. +
  2575.  #endif /* !__NFS41_DAEMON_UTIL_H__ */
  2576. --
  2577. 2.42.1

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