- diff --git a/build.vc19/nfsd/nfsd.vcxproj b/build.vc19/nfsd/nfsd.vcxproj
 - index 047f02d..77df470 100644
 - --- a/build.vc19/nfsd/nfsd.vcxproj
 - +++ b/build.vc19/nfsd/nfsd.vcxproj
 - @@ -153,11 +153,13 @@
 - <ClCompile Include="..\..\daemon\acl.c" />
 - <ClCompile Include="..\..\daemon\callback_server.c" />
 - <ClCompile Include="..\..\daemon\callback_xdr.c" />
 - + <ClCompile Include="..\..\daemon\cpvparser1.c" />
 - <ClCompile Include="..\..\daemon\daemon_debug.c" />
 - <ClCompile Include="..\..\daemon\delegation.c" />
 - <ClCompile Include="..\..\daemon\ea.c" />
 - <ClCompile Include="..\..\daemon\getattr.c" />
 - <ClCompile Include="..\..\daemon\idmap.c" />
 - + <ClCompile Include="..\..\daemon\idmap_cygwin.c" />
 - <ClCompile Include="..\..\daemon\lock.c" />
 - <ClCompile Include="..\..\daemon\lookup.c" />
 - <ClCompile Include="..\..\daemon\mount.c" />
 - @@ -188,6 +190,7 @@
 - <ClCompile Include="..\..\daemon\volume.c" />
 - </ItemGroup>
 - <ItemGroup>
 - + <ClInclude Include="..\..\daemon\cpvparser1.h" />
 - <ClInclude Include="..\..\daemon\daemon_debug.h" />
 - <ClInclude Include="..\..\daemon\delegation.h" />
 - <ClInclude Include="..\..\daemon\from_kernel.h" />
 - diff --git a/build.vc19/nfsd/nfsd.vcxproj.filters b/build.vc19/nfsd/nfsd.vcxproj.filters
 - index d0ebad9..cc1ee27 100644
 - --- a/build.vc19/nfsd/nfsd.vcxproj.filters
 - +++ b/build.vc19/nfsd/nfsd.vcxproj.filters
 - @@ -24,6 +24,9 @@
 - <ClCompile Include="..\..\daemon\callback_xdr.c">
 - <Filter>Source Files</Filter>
 - </ClCompile>
 - + <ClCompile Include="..\..\daemon\cpvparser1.c">
 - + <Filter>Source Files</Filter>
 - + </ClCompile>
 - <ClCompile Include="..\..\daemon\daemon_debug.c">
 - <Filter>Source Files</Filter>
 - </ClCompile>
 - @@ -39,6 +42,9 @@
 - <ClCompile Include="..\..\daemon\idmap.c">
 - <Filter>Source Files</Filter>
 - </ClCompile>
 - + <ClCompile Include="..\..\daemon\idmap_cygwin.c">
 - + <Filter>Source Files</Filter>
 - + </ClCompile>
 - <ClCompile Include="..\..\daemon\lock.c">
 - <Filter>Source Files</Filter>
 - </ClCompile>
 - @@ -125,6 +131,9 @@
 - </ClCompile>
 - </ItemGroup>
 - <ItemGroup>
 - + <ClInclude Include="..\..\daemon\cpvparser1.h">
 - + <Filter>Header Files</Filter>
 - + </ClInclude>
 - <ClInclude Include="..\..\daemon\daemon_debug.h">
 - <Filter>Header Files</Filter>
 - </ClInclude>
 - diff --git a/cygwin_idmapper.ksh b/cygwin_idmapper.ksh
 - new file mode 100644
 - index 0000000..4b96ecf
 - --- /dev/null
 - +++ b/cygwin_idmapper.ksh
 - @@ -0,0 +1,124 @@
 - +#!/bin/ksh93
 - +
 - +set -o nounset
 - +typeset IFS=''
 - +
 - +#
 - +# global variables
 - +# (stored in compound variable so we
 - +# can do a $ print -u2 -v c # for debugging)
 - +#
 - +compound c=(
 - + mode="$1"
 - + name="$2"
 - +)
 - +
 - +compound -A localusers=(
 - + ["roland_mainz"]=(
 - + localaccoutname='roland_mainz'
 - + localuid=197608
 - + localgid=197121
 - + )
 - + ["siegfried_wulsch"]=(
 - + localaccoutname='siegfried_wulsch'
 - + localuid=197609
 - + localgid=197121
 - + )
 - + ["SYSTEM"]=(
 - + localaccoutname='SYSTEM'
 - + localuid=18
 - + localgid=18
 - + )
 - + ["rmainz"]=(
 - + localaccoutname='rmainz'
 - + localuid=1616
 - + localgid=1616
 - + )
 - + ["swulsch"]=(
 - + localaccoutname='swulsch'
 - + localuid=1818
 - + localgid=1818
 - + )
 - + ["root"]=(
 - + localaccoutname='root'
 - + localuid=0
 - + localgid=0
 - + )
 - + ["nobody"]=(
 - + localaccoutname='nobody'
 - + localuid=65534
 - + localgid=65534
 - + )
 - +)
 - +
 - +compound -A localgroups=(
 - + ["Kein"]=(
 - + localaccoutname='Kein'
 - + localgid=197121
 - + )
 - + ["rmainz"]=(
 - + localaccoutname='rmainz'
 - + localuid=1616
 - + localgid=1616
 - + )
 - + ["swulsch"]=(
 - + localaccoutname='swulsch'
 - + localuid=1818
 - + localgid=1818
 - + )
 - + ["root"]=(
 - + localaccoutname='root'
 - + localuid=0
 - + localgid=0
 - + )
 - + ["nogroup"]=(
 - + localaccoutname='nogroup'
 - + localuid=65534
 - + localgid=65534
 - + )
 - +)
 - +
 - +case "${c.mode}" in
 - + 'nfsserveruser2localaccount')
 - + if [[ "${c.name}" == ~(Elr)[[:digit:]]+ ]] ; then
 - + for s in "${!localusers[@]}" ; do
 - + if (( localusers[$s].localuid == c.name )) ; then
 - + print -v localusers[$s]
 - + exit 0
 - + fi
 - + done
 - + fi
 - +
 - + if [[ -v localusers["${c.name}"] ]] ; then
 - + print -v localusers["${c.name}"]
 - + exit 0
 - + else
 - + print -u2 -f "cygwin_idmapper.ksh: Account '%s' not found.\n" "${c.name}"
 - + exit 1
 - + fi
 - + ;;
 - + 'nfsserveruser2localgroup')
 - + if [[ "${c.name}" == ~(Elr)[[:digit:]]+ ]] ; then
 - + for s in "${!localgroups[@]}" ; do
 - + if (( localgroups[$s].localgid == c.name )) ; then
 - + print -v localgroups[$s]
 - + exit 0
 - + fi
 - + done
 - + fi
 - +
 - + if [[ -v localgroups["${c.name}"] ]] ; then
 - + print -v localgroups["${c.name}"]
 - + exit 0
 - + else
 - + print -u2 -f "cygwin_idmapper.ksh: Account '%s' not found.\n" "${c.name}"
 - + exit 1
 - + fi
 - + ;;
 - + *)
 - + print -u2 "cygwin_idmapper.ksh: Unknown mode"
 - + exit 1
 - + ;;
 - +esac
 - +
 - +# EOF.
 - diff --git a/daemon/acl.c b/daemon/acl.c
 - index 1d1eac4..86e0d5a 100644
 - --- a/daemon/acl.c
 - +++ b/daemon/acl.c
 - @@ -21,6 +21,7 @@
 - #include <Windows.h>
 - #include <stdio.h>
 - +#include <time.h>
 - #include <strsafe.h>
 - #include <sddl.h>
 - @@ -198,10 +199,138 @@ BOOL allocate_unixgroup_sid(unsigned long gid, PSID *pSid)
 - }
 - #endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
 - -static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_len, PSID *sid, LPCSTR name)
 - +
 - +/* fixme: should be in sys/nfs41_build_features.h */
 - +#define USE_SID_CACHE 1
 - +
 - +
 - +#ifdef USE_SID_CACHE
 - +#define SID_CACHE_SIZE 20
 - +#define SID_CACHE_TTL 600
 - +
 - +typedef struct _sid_cache_entry
 - +{
 - + char name[256]; /* fixme: size correct ? */
 - + PSID sid;
 - + DWORD sid_len;
 - + time_t timestamp;
 - +} sid_cache_entry;
 - +
 - +typedef struct _sid_cache
 - +{
 - + CRITICAL_SECTION lock;
 - + sid_cache_entry entries[SID_CACHE_SIZE];
 - + ssize_t cacheIndex;
 - +} sid_cache;
 - +
 - +/* fixme: need function to deallocate this */
 - +sid_cache user_sid_cache = { 0 };
 - +
 - +static volatile int cache_once = 0;
 - +
 - +/* copy SID |value| into cache */
 - +void sid_addcache(sid_cache *cache, const char* name, PSID *value)
 - +{
 - + int i;
 - + int oldestEntryIndex;
 - + time_t currentTimestamp;
 - +
 - + /* fixme: this is not really threadsafe!! */
 - + if (cache_once++ == 0) {
 - + InitializeCriticalSection(&cache->lock);
 - + dprintf(0, "SID cache init\n");
 - + }
 - +
 - + EnterCriticalSection(&cache->lock);
 - + currentTimestamp = time(NULL);
 - +
 - + /* Find the oldest valid cache entry */
 - + oldestEntryIndex = -1;
 - + for (i = 0; i < SID_CACHE_SIZE; i++) {
 - + if ((cache->entries[i].sid == NULL) || (cache->entries[i].timestamp < (currentTimestamp - SID_CACHE_TTL))) {
 - + oldestEntryIndex = i;
 - + break;
 - + }
 - + }
 - +
 - + /* If no valid entry was found, overwrite the oldest entry */
 - + if (oldestEntryIndex == -1) {
 - + oldestEntryIndex = cache->cacheIndex;
 - + }
 - +
 - + /* Replace the cache entry */
 - + DWORD sid_len = GetLengthSid(value);
 - + PSID malloced_sid = malloc(sid_len);
 - + if (!malloced_sid)
 - + goto done;
 - + if (!CopySid(sid_len, malloced_sid, value)) {
 - + free(malloced_sid);
 - + goto done;
 - + }
 - +
 - + sid_cache_entry *e = &cache->entries[oldestEntryIndex];
 - +
 - + e->sid_len = sid_len;
 - + if (e->sid)
 - + free(e->sid);
 - + e->sid = malloced_sid;
 - + (void)strcpy(e->name, name);
 - + e->timestamp = currentTimestamp;
 - +
 - + cache->cacheIndex = (cache->cacheIndex + 1) % SID_CACHE_SIZE;
 - +
 - +done:
 - + LeaveCriticalSection(&cache->lock);
 - +}
 - +
 - +/* return |malloc()|'ed copy of SID from cache entry */
 - +PSID *sid_getfromcache(sid_cache *cache, const char *name)
 - {
 - + int i;
 - + time_t currentTimestamp;
 - + PSID *ret_sid = NULL;
 - +
 - + /* fixme: this is not really threadsafe!! */
 - + if (cache_once++ == 0) {
 - + InitializeCriticalSection(&cache->lock);
 - + dprintf(0, "SID cache init\n");
 - + }
 - +
 - + EnterCriticalSection(&cache->lock);
 - + currentTimestamp = time(NULL);
 - +
 - + for (i = 0; i < SID_CACHE_SIZE; i++) {
 - + sid_cache_entry *e = &cache->entries[i];
 - +
 - + if ((!strcmp(e->name, name)) && (e->timestamp >= (currentTimestamp - SID_CACHE_TTL))) {
 - + PSID malloced_sid = malloc(e->sid_len);
 - +
 - + if (!malloced_sid)
 - + goto done;
 - +
 - + if (!CopySid(e->sid_len, malloced_sid, e->sid)) {
 - + free(malloced_sid);
 - + goto done;
 - + }
 - +
 - + ret_sid = malloced_sid;
 - + goto done;
 - + }
 - + }
 - +
 - +done:
 - + LeaveCriticalSection(&cache->lock);
 - + return ret_sid;
 - +}
 - +#endif
 - +
 - +static int map_nfs4servername_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_len, PSID *sid, LPCSTR name)
 - +{
 - + const char *orig_name = name;
 - +
 - int status = ERROR_INTERNAL_ERROR;
 - SID_NAME_USE sid_type;
 - + char name_buff[256+2];
 - LPSTR tmp_buf = NULL;
 - DWORD tmp = 0;
 - #ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
 - @@ -210,24 +339,38 @@ static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_l
 - #endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
 - #ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
 - + /* use our own idmapper script to map nfsv4 owner string to local Windows account */
 - if (query & OWNER_SECURITY_INFORMATION) {
 - - if (!strcmp(name, "rmainz")) {
 - - name = "roland_mainz";
 - - dprintf(ACLLVL, "map_name_2_sid: remap rmainz --> roland_mainz\n");
 - - }
 - - else if (!strcmp(name, "197608")) {
 - - name = "roland_mainz";
 - - dprintf(ACLLVL, "map_name_2_sid: remap 197608 --> roland_mainz\n");
 - + uid_t udummy = -1;
 - + gid_t gdummy = -1;
 - +
 - +int cygwin_getent_passwd(const char *name, char *res_loginname, uid_t *res_uid, gid_t *res_gid);
 - +
 - +#ifdef USE_SID_CACHE
 - + if (*sid = sid_getfromcache(&user_sid_cache, name)) {
 - + *sid_len = GetLengthSid(*sid);
 - +// dprintf(0, "map_nfs4servername_2_sid: returning cached sid for '%s'\n", name);
 - + return 0;
 - + }
 - +#endif /* USE_SID_CACHE */
 - +
 - +#ifndef USE_SID_CACHE
 - + /* gisburn: fixme: We must cache this, or the performance impact will be devastating!! */
 - +#endif /* !USE_SID_CACHE */
 - + if (!cygwin_getent_passwd(name, name_buff, &udummy, &gdummy)) {
 - + if (strcmp(name, name_buff)) {
 - + dprintf(0,
 - + "map_nfs4servername_2_sid: remap '%s' --> '%s'\n",
 - + name,
 - + name_buff);
 - + name = name_buff;
 - }
 - - else if (!strcmp(name, "1616")) {
 - - name = "roland_mainz";
 - - dprintf(ACLLVL, "map_name_2_sid: remap 1616 --> roland_mainz\n");
 - }
 - }
 - #endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
 - status = LookupAccountName(NULL, name, NULL, sid_len, NULL, &tmp, &sid_type);
 - - dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): LookupAccountName returned %d "
 - + dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): LookupAccountName returned %d "
 - "GetLastError %d name len %d domain len %d\n",
 - query, name, status, GetLastError(), *sid_len, tmp);
 - if (status)
 - @@ -248,7 +391,7 @@ static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_l
 - &tmp, &sid_type);
 - free(tmp_buf);
 - if (!status) {
 - - eprintf("map_name_2_sid(query=%x,name='%s'): LookupAccountName failed "
 - + eprintf("map_nfs4servername_2_sid(query=%x,name='%s'): LookupAccountName failed "
 - "with %d\n", query, name, GetLastError());
 - goto out_free_sid;
 - } else {
 - @@ -256,13 +399,13 @@ static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_l
 - LPSTR ssid = NULL;
 - if (IsValidSid(*sid))
 - if (ConvertSidToStringSidA(*sid, &ssid))
 - - dprintf(1, "map_name_2_sid: sid_type = %d SID %s\n",
 - + dprintf(1, "map_nfs4servername_2_sid: sid_type = %d SID %s\n",
 - sid_type, ssid);
 - else
 - - dprintf(1, "map_name_2_sid: ConvertSidToStringSidA failed "
 - + dprintf(1, "map_nfs4servername_2_sid: ConvertSidToStringSidA failed "
 - "with %d\n", GetLastError());
 - else
 - - dprintf(1, "map_name_2_sid: Invalid Sid ?\n");
 - + dprintf(1, "map_nfs4servername_2_sid: Invalid Sid ?\n");
 - if (ssid) LocalFree(ssid);
 - #endif
 - }
 - @@ -270,7 +413,7 @@ static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_l
 - break;
 - case ERROR_NONE_MAPPED:
 - #ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
 - - dprintf(1, "map_name_2_sid(query=%x,name='%s'): none mapped, "
 - + dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): none mapped, "
 - "trying Unix_User+/Unix_Group+ mapping\n",
 - query, name);
 - @@ -286,7 +429,7 @@ static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_l
 - user_uid = map_uid;
 - }
 - else {
 - - dprintf(1, "map_name_2_sid(query=%x,name='%s'): nfs41_idmap_name_to_ids() failed\n",
 - + dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): nfs41_idmap_name_to_ids() failed\n",
 - query, name);
 - /* fixme: try harder here, "1234" should to to |atol()| */
 - }
 - @@ -302,7 +445,7 @@ static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_l
 - group_gid = map_gid;
 - }
 - else {
 - - dprintf(1, "map_name_2_sid(query=%x,name='%s'): nfs41_idmap_group_to_gid() failed\n",
 - + dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): nfs41_idmap_group_to_gid() failed\n",
 - query, name);
 - /* fixme: try harder here, "1234" should to to |atol()| */
 - }
 - @@ -310,14 +453,15 @@ static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_l
 - if (user_uid != -1) {
 - if (allocate_unixuser_sid(user_uid, sid)) {
 - - dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
 - + dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): "
 - "allocate_unixuser_sid(uid=%ld) success\n",
 - query, name, user_uid);
 - - return ERROR_SUCCESS;
 - + status = ERROR_SUCCESS;
 - + goto out;
 - }
 - status = GetLastError();
 - - dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
 - + dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): "
 - "allocate_unixuser_sid(uid=%ld) failed, error=%d\n",
 - query, name, user_uid, status);
 - return status;
 - @@ -325,21 +469,22 @@ static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_l
 - if (group_gid != -1) {
 - if (allocate_unixgroup_sid(group_gid, sid)) {
 - - dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
 - + dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): "
 - "allocate_unixgroup_sid(gid=%ld) success\n",
 - query, name, group_gid);
 - - return ERROR_SUCCESS;
 - + status = ERROR_SUCCESS;
 - + goto out;
 - }
 - status = GetLastError();
 - - dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
 - + dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): "
 - "allocate_unixgroup_sid(gid=%ld) failed, error=%d\n",
 - query, name, group_gid, status);
 - return status;
 - }
 - #endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
 - - dprintf(1, "map_name_2_sid(query=%x,name='%s'): none mapped, "
 - + dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): none mapped, "
 - "using WinNullSid mapping\n",
 - query, name);
 - @@ -348,11 +493,20 @@ static int map_name_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_l
 - goto out_free_sid;
 - break;
 - default:
 - - dprintf(1, "map_name_2_sid(query=%x,name='%s'): error %d not handled\n",
 - + dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): error %d not handled\n",
 - query, name, GetLastError());
 - break;
 - }
 - out:
 - +#ifdef USE_SID_CACHE
 - + if (*sid) {
 - + /* fixme: No other flags in |query| must be set!! */
 - + if (query & OWNER_SECURITY_INFORMATION) {
 - + sid_addcache(&user_sid_cache, orig_name, *sid);
 - + }
 - + }
 - +#endif /* USE_SID_CACHE */
 - +
 - return status;
 - out_free_sid:
 - status = GetLastError();
 - @@ -417,7 +571,7 @@ static int convert_nfs4acl_2_dacl(nfs41_daemon_globals *nfs41dg,
 - goto out;
 - }
 - if (!flag) {
 - - status = map_name_2_sid(nfs41dg,
 - + status = map_nfs4servername_2_sid(nfs41dg,
 - 0xFFFF /* fixme: Unknown whether user or group */,
 - &sid_len, &sids[i], acl->aces[i].who);
 - if (status) {
 - @@ -534,7 +688,7 @@ static int handle_getacl(void *daemon_context, nfs41_upcall *upcall)
 - dprintf(ACLLVL, "handle_getacl: OWNER_SECURITY_INFORMATION: for user=%s "
 - "domain=%s\n", info.owner, domain?domain:"<null>");
 - sid_len = 0;
 - - status = map_name_2_sid(nfs41dg,
 - + status = map_nfs4servername_2_sid(nfs41dg,
 - OWNER_SECURITY_INFORMATION, &sid_len, &osid, info.owner);
 - if (status)
 - goto out;
 - @@ -552,7 +706,7 @@ static int handle_getacl(void *daemon_context, nfs41_upcall *upcall)
 - dprintf(ACLLVL, "handle_getacl: GROUP_SECURITY_INFORMATION: for %s "
 - "domain=%s\n", info.owner_group, domain?domain:"<null>");
 - sid_len = 0;
 - - status = map_name_2_sid(nfs41dg,
 - + status = map_nfs4servername_2_sid(nfs41dg,
 - GROUP_SECURITY_INFORMATION, &sid_len, &gsid, info.owner_group);
 - if (status)
 - goto out;
 - diff --git a/daemon/cpvparser1.c b/daemon/cpvparser1.c
 - new file mode 100644
 - index 0000000..285fc76
 - --- /dev/null
 - +++ b/daemon/cpvparser1.c
 - @@ -0,0 +1,361 @@
 - +
 - +/*
 - + * MIT License
 - + *
 - + * Copyright (c) 2023 Roland Mainz <roland.mainz@nrubsig.org>
 - + *
 - + * Permission is hereby granted, free of charge, to any person obtaining a copy
 - + * of this software and associated documentation files (the "Software"), to deal
 - + * in the Software without restriction, including without limitation the rights
 - + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 - + * copies of the Software, and to permit persons to whom the Software is
 - + * furnished to do so, subject to the following conditions:
 - + *
 - + * The above copyright notice and this permission notice shall be included in all
 - + * copies or substantial portions of the Software.
 - + *
 - + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 - + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 - + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 - + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FORalloca ANY CLAIM, DAMAGES OR OTHER
 - + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 - + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 - + * SOFTWARE.
 - + */
 - +
 - +/*
 - + * cpvparser1.c - simple ksh93 compound variable parsing
 - + *
 - + * It basically reads the output of $ print -v ... # like this:
 - + * ---- snip ----
 - + * $ ksh93 -c 'compound c=( va=1 vb=hello ) ; print -v c'
 - + * (
 - + * va=1
 - + * vb=hello
 - + * )
 - + * ---- snip ----
 - + *
 - + * ToDo:
 - + * - arrays (indexed, sparse indexed and associative)
 - + * - multibyte characters
 - + *
 - + * Written by Roland Mainz <roland.mainz@nrubsig.org>
 - + */
 - +
 - +#include <stdlib.h>
 - +#include <stdbool.h>
 - +#include <string.h>
 - +#include <stdio.h>
 - +#include <ctype.h>
 - +
 - +#include "cpvparser1.h"
 - +
 - +#ifdef _WIN32
 - +#define strdup(s) _strdup(s)
 - +#endif
 - +
 - +/* private data! */
 - +typedef struct cpv_parse_context {
 - + const char *start_string;
 - + const char *curr_string;
 - + size_t max_name_val_size;
 - + unsigned long flags;
 - +} cpv_parse_context;
 - +
 - +
 - +void *cpv_create_parser(const char *s, unsigned long flags, ...)
 - +{
 - + cpv_parse_context *cpc;
 - +
 - + cpc = calloc(1, sizeof(cpv_parse_context));
 - + if (!cpc)
 - + goto fail;
 - +
 - + cpc->start_string = strdup(s);
 - + if (!cpc->start_string)
 - + goto fail;
 - +
 - + cpc->curr_string = cpc->start_string;
 - + cpc->max_name_val_size = strlen(cpc->start_string);
 - + cpc->flags = flags;
 - +
 - + return (cpc);
 - +
 - +fail:
 - + if (cpc) {
 - + free((void *)cpc->start_string);
 - + free(cpc);
 - + }
 - +
 - + return NULL;
 - +}
 - +
 - +void cpv_free_parser(void *v_cpc)
 - +{
 - + cpv_parse_context *cpc = (cpv_parse_context *)v_cpc;
 - + if (cpc) {
 - + free((void *)cpc->start_string);
 - + free(cpc);
 - + }
 - +}
 - +
 - +int cpv_read_cpv_header(void *v_cpc)
 - +{
 - + cpv_parse_context *cpc = (cpv_parse_context *)v_cpc;
 - + const char *s = cpc->curr_string;
 - +
 - +skipspaces:
 - + while((*s != '\0') && isspace(*s))
 - + s++;
 - +
 - + /*
 - + * skip POSIX-style '#' comments
 - + * (allowed since this is based on POSIX sh(1) syntax)
 - + */
 - + if (*s == '#') {
 - + s++;
 - + /* ignore everything until the end-of-line */
 - + while((*s != '\0') && (*s != '\n'))
 - + s++;
 - + goto skipspaces;
 - + }
 - +
 - + if (*s == '(') {
 - + cpc->curr_string=++s;
 - + if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
 - + (void)fprintf(stderr, "cpv_read_cpv_header: begin-of-cpv\n");
 - + }
 - + return 0;
 - + }
 - +
 - + if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
 - + (void)fprintf(stderr, "cpv_read_cpv_header: end-of-string, should not happen\n");
 - + }
 - + return 1;
 - +}
 - +
 - +int cpv_parse_name_val(void *v_cpc, cpv_name_val *cpv_nv)
 - +{
 - + cpv_parse_context *cpc = (cpv_parse_context *)v_cpc;
 - +#ifdef _WIN32
 - + char *namebuff = _alloca(cpc->max_name_val_size+1);
 - + char *valbuff = _alloca(cpc->max_name_val_size+1);
 - +#else
 - + char namebuff[cpc->max_name_val_size+1];
 - + char valbuff[cpc->max_name_val_size+1];
 - +#endif
 - +
 - + const char *s = cpc->curr_string;
 - +
 - + char *n; /* pointer in |namebuff| */
 - + char *v; /* pointer in |valbuff| */
 - +
 - +skipspaces:
 - + while((*s != '\0') && isspace(*s))
 - + s++;
 - +
 - + /*
 - + * skip POSIX-style '#' comments
 - + * (allowed since this is based on POSIX sh(1) syntax)
 - + */
 - + if (*s == '#') {
 - + s++;
 - + /* ignore everything until the end-of-line */
 - + while((*s != '\0') && (*s != '\n'))
 - + s++;
 - + goto skipspaces;
 - + }
 - +
 - + if (*s == '\0') {
 - + if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
 - + (void)fprintf(stderr, "cpv_parse_name_val: "
 - + "error: end-of-string, should not happen\n");
 - + }
 - + return 1;
 - + }
 - +
 - + /* cpv == "( foo=bar blabla=text )"*/
 - + if (*s == ')') {
 - + if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
 - + (void)fprintf(stderr, "cpv_parse_name_val: end-of-cpv (OK)\n");
 - + }
 - + return 1;
 - + }
 - +
 - +parse_varname:
 - + /*
 - + * start parsing variable name
 - + */
 - +
 - + /* variable names MUST start with a letter! */
 - + if (!isalpha(*s)) {
 - + if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
 - + (void)fprintf(stderr,
 - + "cpv_parse_name_val: parser error, first char "
 - + "in variable name not isalpha(c=%c)\n",
 - + *s);
 - + }
 - + return 1;
 - + }
 - +
 - + n = namebuff;
 - + while((*s != '\0') && isalnum(*s))
 - + *n++ = *s++;
 - + *n = '\0';
 - +
 - + /*
 - + * skip typed member varables
 - + * (e.g. "typeset ", "typeset -i ", "typeset -l -i2" etc.)
 - + */
 - + if (isspace(*s)) {
 - + if ((!strcmp(namebuff, "typeset")) ||
 - + (!strcmp(namebuff, "integer")) ||
 - + (!strcmp(namebuff, "float")) ||
 - + (!strcmp(namebuff, "compound"))) {
 - +skip_typeset_options:
 - + while(isspace(*s))
 - + s++;
 - + if (*s == '-') {
 - + s++;
 - + while(isalnum(*s))
 - + s++;
 - + goto skip_typeset_options;
 - + }
 - +
 - + goto parse_varname;
 - + }
 - + }
 - +
 - + /* handle '=' */
 - + if (*s != '=') {
 - + if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
 - + (void)fprintf(stderr, "cpv_parse_name_val: "
 - + "parser error, expected '=', got '%c'.\n",
 - + *s);
 - + }
 - + return 1;
 - + }
 - +
 - + s++; /* skip '=' */
 - +
 - + /*
 - + * start parsing variable value
 - + */
 - + bool in_doublequotes=false;
 - + bool in_singlequotes=false;
 - + v = valbuff;
 - +val_quotes:
 - + if (in_singlequotes) {
 - + while(*s != '\0') {
 - + if (*s == '\'') {
 - + in_singlequotes = false;
 - + s++;
 - + goto val_quotes;
 - + }
 - +
 - + if ((*s == '\\') && (*(s+1) != '\0')) {
 - + /*
 - + * fixme: should support \ooo octals,
 - + * \u[hex] unicode and \w[hex] wchar
 - + */
 - + s++;
 - + }
 - + *v++ = *s++;
 - + }
 - + }
 - + else if (in_doublequotes) {
 - + while(*s != '\0') {
 - + if (*s == '"') {
 - + in_doublequotes = false;
 - + s++;
 - + goto val_quotes;
 - + }
 - +
 - + if ((*s == '\\') && (*(s+1) != '\0')) {
 - + /*
 - + * fixme: should support \ooo octals,
 - + * \u[hex] unicode and \w[hex] wchar
 - + */
 - + s++;
 - + }
 - +
 - + *v++ = *s++;
 - + }
 - + }
 - + else
 - + {
 - + while((*s != '\0') && (!isspace(*s))) {
 - + if (*s == '"') {
 - + in_doublequotes = true;
 - + s++;
 - + goto val_quotes;
 - + }
 - +
 - + if (*s == '\'') {
 - + in_singlequotes = true;
 - + s++;
 - + goto val_quotes;
 - + }
 - +
 - + if ((*s == '\\') && (*(s+1) != '\0')) {
 - + /*
 - + * fixme: should support \ooo octals,
 - + * \u[hex] unicode and \w[hex] wchar
 - + */
 - + s++;
 - + }
 - + *v++ = *s++;
 - + }
 - + }
 - +
 - + if (in_singlequotes) {
 - + if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
 - + (void)fprintf(stderr, "cpv_parse_name_val: "
 - + "parsererror, still in single quotes "
 - + "at the end\n");
 - + }
 - + return 1;
 - + }
 - + if (in_doublequotes) {
 - + if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
 - + (void)fprintf(stderr, "cpv_parse_name_val: "
 - + "parser error, still in double quotes "
 - + "at the end\n");
 - + }
 - + return 1;
 - + }
 - +
 - + *v = '\0';
 - +
 - +#if 0
 - + (void)printf("cpv_parse_name_val: name='%s', value='%s'\n",
 - + namebuff, valbuff);
 - +#endif
 - +
 - + cpv_nv->cpv_name = strdup(namebuff);
 - + cpv_nv->cpv_value = strdup(valbuff);
 - +
 - + if ((cpv_nv->cpv_name == NULL) || (cpv_nv->cpv_value == NULL)) {
 - + cpv_free_name_val_data(cpv_nv);
 - + if (cpc->flags & CPVFLAG_DEBUG_OUTPUT) {
 - + (void)fprintf(stderr, "cpv_parse_name_val: "
 - + "parser error, out of memory\n");
 - + }
 - + return 2;
 - + }
 - +
 - + cpc->curr_string = s;
 - +
 - + return 0;
 - +}
 - +
 - +void cpv_free_name_val_data(cpv_name_val *cnv)
 - +{
 - + if (!cnv)
 - + return;
 - +
 - + free((void *)cnv->cpv_name);
 - + free((void *)cnv->cpv_value);
 - + cnv->cpv_name = NULL;
 - + cnv->cpv_value = NULL;
 - +}
 - diff --git a/daemon/cpvparser1.h b/daemon/cpvparser1.h
 - new file mode 100644
 - index 0000000..a6ed609
 - --- /dev/null
 - +++ b/daemon/cpvparser1.h
 - @@ -0,0 +1,64 @@
 - +
 - +/*
 - + * MIT License
 - + *
 - + * Copyright (c) 2023 Roland Mainz <roland.mainz@nrubsig.org>
 - + *
 - + * Permission is hereby granted, free of charge, to any person obtaining a copy
 - + * of this software and associated documentation files (the "Software"), to deal
 - + * in the Software without restriction, including without limitation the rights
 - + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 - + * copies of the Software, and to permit persons to whom the Software is
 - + * furnished to do so, subject to the following conditions:
 - + *
 - + * The above copyright notice and this permission notice shall be included in all
 - + * copies or substantial portions of the Software.
 - + *
 - + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 - + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 - + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 - + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 - + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 - + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 - + * SOFTWARE.
 - + */
 - +
 - +/*
 - + * cpvparser1.h - simple ksh93 compound variable parsing
 - + *
 - + * It basically reads the output of $ print -v ... # like this:
 - + * ---- snip ----
 - + * $ ksh93 -c 'compound c=( va=1 vb=hello ) ; print -v c'
 - + * (
 - + * va=1
 - + * vb=hello
 - + * )
 - + * ---- snip ----
 - + *
 - + * ToDo:
 - + * - arrays (indexed, sparse indexed and associative)
 - + * - multibyte characters
 - + *
 - + * Written by Roland Mainz <roland.mainz@nrubsig.org>
 - + */
 - +
 - +#ifndef CPV_PARSER_H
 - +#define CPV_PARSER_H 1
 - +
 - +typedef struct cpv_name_val
 - +{
 - + const char *cpv_name;
 - + const char *cpv_value;
 - +} cpv_name_val;
 - +
 - +/* Flags for |cpv_create_parser()| */
 - +#define CPVFLAG_DEBUG_OUTPUT (0x00000008L)
 - +
 - +/* prototypes */
 - +void *cpv_create_parser(const char *s, unsigned long flags, ...);
 - +void cpv_free_parser(void *);
 - +int cpv_read_cpv_header(void *);
 - +void cpv_free_name_val_data(cpv_name_val *);
 - +int cpv_parse_name_val(void *, cpv_name_val *);
 - +
 - +#endif /* !CPV_PARSER_H */
 - diff --git a/daemon/idmap.c b/daemon/idmap.c
 - index 00af1fe..0672a85 100644
 - --- a/daemon/idmap.c
 - +++ b/daemon/idmap.c
 - @@ -3,6 +3,7 @@
 - *
 - * Olga Kornievskaia <aglo@umich.edu>
 - * Casey Bodley <cbodley@umich.edu>
 - + * Roland Mainz <roland.mainz@nrubsig.org>
 - *
 - * This library is free software; you can redistribute it and/or modify it
 - * under the terms of the GNU Lesser General Public License as published by
 - @@ -33,7 +34,7 @@
 - #include "daemon_debug.h"
 - #define IDLVL 2 /* dprintf level for idmap logging */
 - -#define CYGWINIDLVL 2 /* dprintf level for idmap logging */
 - +#define CYGWINIDLVL 0 /* dprintf level for idmap logging */
 - #define FILTER_LEN 1024
 - #define NAME_LEN 32
 - @@ -133,7 +134,7 @@ static const struct config_option g_options[] = {
 - OPT_ATTR("ldap_attr_gidNumber", "gidNumber", ATTR_GID),
 - /* caching configuration */
 - - OPT_INT("cache_ttl", "60", cache_ttl),
 - + OPT_INT("cache_ttl", "6000", cache_ttl),
 - };
 - @@ -376,246 +377,6 @@ out:
 - return status;
 - }
 - -#ifdef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
 - -int cygwin_getent_passwd(const char *name, char *res_loginname, uid_t *res_uid, gid_t *res_gid)
 - -{
 - - char cmdbuff[1024];
 - - char passwd_line[1024];
 - - FILE* getent_pipe = NULL;
 - - int res = 1;
 - - unsigned long uid = -1;
 - - unsigned long gid = -1;
 - - struct _cypwent {
 - - char* loginname;
 - - char* passwd;
 - - char* uidstr;
 - - char* gidstr;
 - - char* comment;
 - - char* homedir;
 - - char* shell;
 - - } pwent = { 0 };
 - -#define PWENT_ENTRY(var, prevvar) \
 - - (((var) = strchr((prevvar), ':'))?(*(var)++ = '\0',(var)):(NULL))
 - -
 - - dprintf(CYGWINIDLVL, "--> cygwin_getent_passwd('%s')\n", name);
 - -
 - -#if 1
 - - /* hack for testing, map "roland_mainz" to rmainz account */
 - - if ((!strcmp(name, "rmainz")) || (!strcmp(name, "1616"))) {
 - - uid = 1616;
 - - gid = 1616;
 - - pwent.loginname = "rmainz";
 - - goto found;
 - - }
 - - if ((!strcmp(name, "nobody")) || (!strcmp(name, "no+body")) ||
 - - (!strcmp(name, "65534"))) {
 - - uid = 65534;
 - - gid = 65534;
 - - pwent.loginname = "no+body"; /* Cygwin-specific */
 - - goto found;
 - - }
 - - if ((!strcmp(name, "root")) || (!strcmp(name, "0"))) {
 - - uid = 0;
 - - gid = 0;
 - - pwent.loginname = "root";
 - - goto found;
 - - }
 - - if ((!strcmp(name, "iam")) || (!strcmp(name, "2010"))) {
 - - uid = 2010;
 - - gid = 2010;
 - - pwent.loginname = "iam";
 - - goto found;
 - - }
 - - if ((!strcmp(name, "swulsch")) || (!strcmp(name, "1818"))) {
 - - uid = 1818;
 - - gid = 1818;
 - - pwent.loginname = "swulsch";
 - - goto found;
 - - }
 - - if ((!strcmp(name, "mwenzel")) || (!strcmp(name, "8239"))) {
 - - uid = 8239;
 - - gid = 8239;
 - - pwent.loginname = "mwenzel";
 - - goto found;
 - - }
 - -#endif
 - -
 - - /* fixme: better quoting for |name| needed */
 - - (void)snprintf(cmdbuff, sizeof(cmdbuff), "%s passwd \"%s\"",
 - - "C:\\cygwin64\\bin\\getent.exe",
 - - name);
 - - if ((getent_pipe = _popen(cmdbuff, "rt")) == NULL) {
 - - dprintf(CYGWINIDLVL, "cygwin_getent_passwd: /usr/bin/getent failed, errno='%s'\n",
 - - strerror(errno));
 - - goto fail;
 - - }
 - -
 - - if (fgets(passwd_line, sizeof(passwd_line), getent_pipe)) {
 - - pwent.loginname = passwd_line;
 - - if (!PWENT_ENTRY(pwent.passwd, pwent.loginname)) goto fail;
 - - if (!PWENT_ENTRY(pwent.uidstr, pwent.passwd)) goto fail;
 - - if (!PWENT_ENTRY(pwent.gidstr, pwent.uidstr)) goto fail;
 - - if (!PWENT_ENTRY(pwent.comment, pwent.gidstr)) goto fail;
 - - if (!PWENT_ENTRY(pwent.homedir, pwent.comment)) goto fail;
 - - PWENT_ENTRY(pwent.shell, pwent.homedir);
 - -
 - - errno = 0;
 - - uid = strtol(pwent.uidstr, NULL, 10);
 - - if (errno != 0)
 - - goto fail;
 - -
 - - errno = 0;
 - - gid = strtol(pwent.gidstr, NULL, 10);
 - - if (errno != 0)
 - - goto fail;
 - -
 - -#if 0
 - - dprintf(CYGWINIDLVL, "cygwin_getent_passwd(): name='%s'\n", name);
 - - dprintf(CYGWINIDLVL, "loginname\t='%s'\n", pwent.loginname);
 - - dprintf(CYGWINIDLVL, "passwd\t='%s'\n", pwent.passwd);
 - - dprintf(CYGWINIDLVL, "uidstr\t='%s' (%lu)\n", pwent.uidstr, (unsigned long)uid);
 - - dprintf(CYGWINIDLVL, "gidstr\t='%s' (%lu)\n", pwent.gidstr, (unsigned long)gid);
 - - dprintf(CYGWINIDLVL, "comment\t='%s'\n", pwent.comment);
 - - dprintf(CYGWINIDLVL, "homedir\t='%s'\n", pwent.homedir);
 - - dprintf(CYGWINIDLVL, "shell\t='%s'\n", pwent.shell);
 - -#endif
 - -
 - -found:
 - - if (res_loginname)
 - - (void)strcpy_s(res_loginname, VAL_LEN, pwent.loginname);
 - - *res_uid = uid;
 - - *res_gid = gid;
 - - res = 0;
 - - }
 - -
 - -fail:
 - - if (getent_pipe)
 - - (void)_pclose(getent_pipe);
 - -
 - - if (res == 0) {
 - - dprintf(CYGWINIDLVL, "<-- cygwin_getent_passwd('%s'): "
 - - "returning res_uid=%lu, res_gid=%lu, res_loginname='%s'\n",
 - - name,
 - - (unsigned long)(*res_uid),
 - - (unsigned long)(*res_gid),
 - - res_loginname?res_loginname:"<NULL>");
 - - }
 - - else {
 - - dprintf(CYGWINIDLVL, "<-- cygwin_getent_passwd('%s'): no match found\n",
 - - name);
 - - }
 - -
 - - return res;
 - -}
 - -
 - -int cygwin_getent_group(const char* name, char* res_group_name, gid_t* res_gid)
 - -{
 - - char cmdbuff[1024];
 - - char group_line[1024];
 - - FILE* getent_pipe = NULL;
 - - int res = 1;
 - - unsigned long gid = -1;
 - - struct _cygrent
 - - {
 - - char* group_name;
 - - char* passwd;
 - - char* gidstr;
 - - char* userlist;
 - - } grent = { 0 };
 - -
 - - dprintf(CYGWINIDLVL, "--> cygwin_getent_group('%s')\n", name);
 - -
 - -#if 1
 - - if ((!strcmp(name, "rmainz")) || (!strcmp(name, "1616"))) {
 - - gid = 1616;
 - - grent.group_name = "rmainz";
 - - goto found;
 - - }
 - - if ((!strcmp(name, "nogroup")) || (!strcmp(name, "no+body")) ||
 - - (!strcmp(name, "65534"))) {
 - - gid = 65534;
 - - grent.group_name = "no+body"; /* Cygwin-specific */
 - - goto found;
 - - }
 - - if ((!strcmp(name, "root")) || (!strcmp(name, "0"))) {
 - - gid = 0;
 - - grent.group_name = "root";
 - - goto found;
 - - }
 - - if ((!strcmp(name, "iam")) || (!strcmp(name, "2010"))) {
 - - gid = 2010;
 - - grent.group_name = "iam";
 - - goto found;
 - - }
 - - if ((!strcmp(name, "swulsch")) || (!strcmp(name, "1818"))) {
 - - gid = 1818;
 - - grent.group_name = "swulsch";
 - - goto found;
 - - }
 - - if ((!strcmp(name, "mwenzel")) || (!strcmp(name, "8239"))) {
 - - gid = 8239;
 - - grent.group_name = "mwenzel";
 - - goto found;
 - - }
 - -#endif
 - -
 - - /* fixme: better quoting for |name| needed */
 - - (void)snprintf(cmdbuff, sizeof(cmdbuff), "%s group \"%s\"",
 - - "C:\\cygwin64\\bin\\getent.exe",
 - - name);
 - - if ((getent_pipe = _popen(cmdbuff, "rt")) == NULL) {
 - - dprintf(CYGWINIDLVL,
 - - "cygwin_getent_group: /usr/bin/getent failed, errno='%s'\n",
 - - strerror(errno));
 - - goto fail;
 - - }
 - -
 - - if (fgets(group_line, sizeof(group_line), getent_pipe))
 - - {
 - - grent.group_name = group_line;
 - - if (!PWENT_ENTRY(grent.passwd, grent.group_name)) goto fail;
 - - if (!PWENT_ENTRY(grent.gidstr, grent.passwd)) goto fail;
 - - PWENT_ENTRY(grent.userlist, grent.gidstr);
 - -
 - - errno = 0;
 - - gid = strtol(grent.gidstr, NULL, 10);
 - - if (errno != 0)
 - - goto fail;
 - -
 - -#if 0
 - - dprintf(CYGWINIDLVL, "cygwin_getent_group(): name='%s'\n", name);
 - - dprintf(CYGWINIDLVL, "group_name\t='%s'\n", grent.group_name);
 - - dprintf(CYGWINIDLVL, "passwd\t='%s'\n", grent.passwd);
 - - dprintf(CYGWINIDLVL, "gidstr\t='%s' (%lu)\n", grent.gidstr, (unsigned long)gid);
 - - dprintf(CYGWINIDLVL, "userlist\t='%s'\n", grent.userlist);
 - -#endif
 - -
 - -found:
 - - if (res_group_name)
 - - (void)strcpy_s(res_group_name, VAL_LEN, grent.group_name);
 - - *res_gid = gid;
 - - res = 0;
 - - }
 - -
 - -fail:
 - - if (getent_pipe)
 - - (void)_pclose(getent_pipe);
 - -
 - - if (res == 0) {
 - - dprintf(CYGWINIDLVL, "<-- cygwin_getent_group('%s'): "
 - - "returning res_gid=%lu, res_group_name='%s'\n",
 - - name, (unsigned long)(*res_gid),
 - - res_group_name?res_group_name:"<NULL>");
 - - }
 - - else {
 - - dprintf(CYGWINIDLVL,
 - - "<-- cygwin_getent_group('%s'): no match found\n",
 - - name);
 - - }
 - -
 - - return res;
 - -}
 - -#endif /* NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN */
 - /* generic cache */
 - typedef struct list_entry* (*entry_alloc_fn)();
 - @@ -906,7 +667,7 @@ static int idmap_lookup_user(
 - if (status == NO_ERROR) {
 - /* don't return expired entries; query new attributes
 - * and overwrite the entry with cache_insert() */
 - - if ((time(NULL) - user->last_updated) < context->config.cache_ttl)
 - + if (difftime(time(NULL), user->last_updated) < (double)context->config.cache_ttl)
 - goto out;
 - }
 - #ifndef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
 - @@ -1060,7 +821,7 @@ static int idmap_lookup_group(
 - if (status == NO_ERROR) {
 - /* don't return expired entries; query new attributes
 - * and overwrite the entry with cache_insert() */
 - - if ((time(NULL) - group->last_updated) < context->config.cache_ttl)
 - + if (difftime(time(NULL), group->last_updated) < (double)context->config.cache_ttl)
 - goto out;
 - }
 - #ifndef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
 - diff --git a/daemon/idmap_cygwin.c b/daemon/idmap_cygwin.c
 - new file mode 100644
 - index 0000000..8d62f2f
 - --- /dev/null
 - +++ b/daemon/idmap_cygwin.c
 - @@ -0,0 +1,243 @@
 - +/* NFSv4.1 client for Windows
 - + * Copyright 2023 Roland Mainz <roland.mainz@nrubsig.org>
 - + *
 - + * Roland Mainz <roland.mainz@nrubsig.org>
 - + *
 - + * This library is free software; you can redistribute it and/or modify it
 - + * under the terms of the GNU Lesser General Public License as published by
 - + * the Free Software Foundation; either version 2.1 of the License, or (at
 - + * your option) any later version.
 - + *
 - + * This library is distributed in the hope that it will be useful, but
 - + * without any warranty; without even the implied warranty of merchantability
 - + * or fitness for a particular purpose. See the GNU Lesser General Public
 - + * License for more details.
 - + *
 - + * You should have received a copy of the GNU Lesser General Public License
 - + * along with this library; if not, write to the Free Software Foundation,
 - + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 - + */
 - +
 - +#include <Windows.h>
 - +#include <strsafe.h>
 - +#include <Winldap.h>
 - +#include <stdlib.h> /* for strtoul() */
 - +#include <errno.h>
 - +#include <time.h>
 - +
 - +#include "nfs41_build_features.h"
 - +#include "idmap.h"
 - +#include "nfs41_const.h"
 - +#include "list.h"
 - +#include "daemon_debug.h"
 - +#ifdef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
 - +#include "cpvparser1.h"
 - +#endif /* NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN */
 - +
 - +#define CYGWINIDLVL 0 /* dprintf level for idmap logging */
 - +
 - +#define VAL_LEN 257
 - +
 - +#define CYGWIN_IDMAPPER_SCRIPT \
 - + ("C:\\cygwin64\\bin\\ksh93.exe " \
 - + "/home/roland_mainz/work/msnfs41_uidmapping/ms-nfs41-client/cygwin_idmapper.ksh")
 - +
 - +
 - +#ifdef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
 - +int cygwin_getent_passwd(const char *name, char *res_loginname, uid_t *res_uid, gid_t *res_gid)
 - +{
 - + char cmdbuff[1024];
 - + char buff[2048];
 - + size_t num_buff_read;
 - + FILE* script_pipe = NULL;
 - + int res = 1;
 - + unsigned long uid = -1;
 - + unsigned long gid = -1;
 - + void *cpvp = NULL;
 - + int numcnv = 0;
 - + int i = 0;
 - + cpv_name_val cnv[256] = { 0 };
 - + cpv_name_val *cnv_cur = NULL;
 - + const char *localaccoutname = NULL;
 - +
 - + dprintf(CYGWINIDLVL, "--> cygwin_getent_passwd('%s')\n", name);
 - +
 - + /* fixme: better quoting for |name| needed */
 - + (void)snprintf(cmdbuff, sizeof(cmdbuff), "%s nfsserveruser2localaccount \"%s\"",
 - + CYGWIN_IDMAPPER_SCRIPT,
 - + name);
 - + if ((script_pipe = _popen(cmdbuff, "rt")) == NULL) {
 - + dprintf(0, "cygwin_getent_passwd: '%s' failed, errno='%s'\n",
 - + cmdbuff,
 - + strerror(errno));
 - + goto fail;
 - + }
 - +
 - + num_buff_read = fread(buff, 1, sizeof(buff), script_pipe);
 - + if (num_buff_read < 10) {
 - + dprintf(0, "cygwin_getent_passwd: Could not read enough data, returned %d\n", (int)num_buff_read);
 - + goto fail;
 - + }
 - +
 - + buff[num_buff_read] = '\0';
 - +
 - + cpvp = cpv_create_parser(buff, 0/*CPVFLAG_DEBUG_OUTPUT*/);
 - + if (!cpvp) {
 - + dprintf(0, "cygwin_getent_passwd: Could not create parser\n");
 - + goto fail;
 - + }
 - +
 - + if (cpv_read_cpv_header(cpvp)) {
 - + dprintf(0, "cygwin_getent_passwd: cpv_read_cpv_header failed\n");
 - + goto fail;
 - + }
 - +
 - + for (numcnv=0 ; cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0 ; numcnv++) {
 - + }
 - +
 - + for (i=0 ; i < numcnv ; i++) {
 - + cnv_cur = &cnv[i];
 - + if (!strcmp("localaccoutname", cnv_cur->cpv_name)) {
 - + localaccoutname = cnv_cur->cpv_value;
 - + }
 - + else if (!strcmp("localuid", cnv_cur->cpv_name)) {
 - + errno = 0;
 - + uid = strtol(cnv_cur->cpv_value, NULL, 10);
 - + if (errno != 0)
 - + goto fail;
 - + }
 - + else if (!strcmp("localgid", cnv_cur->cpv_name)) {
 - + errno = 0;
 - + gid = strtol(cnv_cur->cpv_value, NULL, 10);
 - + if (errno != 0)
 - + goto fail;
 - + }
 - + }
 - +
 - + if (res_loginname)
 - + (void)strcpy_s(res_loginname, VAL_LEN, localaccoutname);
 - + *res_uid = uid;
 - + *res_gid = gid;
 - + res = 0;
 - +
 - +fail:
 - + if (script_pipe)
 - + (void)_pclose(script_pipe);
 - +
 - + for (i=0 ; i < numcnv ; i++) {
 - + cpv_free_name_val_data(&cnv[i]);
 - + }
 - +
 - + cpv_free_parser(cpvp);
 - +
 - + if (res == 0) {
 - + dprintf(CYGWINIDLVL, "<-- cygwin_getent_passwd('%s'): "
 - + "returning res_uid=%lu, res_gid=%lu, res_loginname='%s'\n",
 - + name,
 - + (unsigned long)(*res_uid),
 - + (unsigned long)(*res_gid),
 - + res_loginname?res_loginname:"<NULL>");
 - + }
 - + else {
 - + dprintf(CYGWINIDLVL, "<-- cygwin_getent_passwd('%s'): no match found\n",
 - + name);
 - + }
 - +
 - + return res;
 - +}
 - +
 - +int cygwin_getent_group(const char* name, char* res_group_name, gid_t* res_gid)
 - +{
 - + char cmdbuff[1024];
 - + char buff[2048];
 - + size_t num_buff_read;
 - + FILE* script_pipe = NULL;
 - + int res = 1;
 - + unsigned long gid = -1;
 - + void *cpvp = NULL;
 - + int numcnv = 0;
 - + int i = 0;
 - + cpv_name_val cnv[256] = { 0 };
 - + cpv_name_val *cnv_cur = NULL;
 - +
 - + const char *localgroupname = NULL;
 - +
 - + dprintf(CYGWINIDLVL, "--> cygwin_getent_group('%s')\n", name);
 - +
 - + /* fixme: better quoting for |name| needed */
 - + (void)snprintf(cmdbuff, sizeof(cmdbuff), "%s nfsserveruser2localgroup \"%s\"",
 - + CYGWIN_IDMAPPER_SCRIPT,
 - + name);
 - + if ((script_pipe = _popen(cmdbuff, "rt")) == NULL) {
 - + dprintf(0, "cygwin_getent_group: '%s' failed, errno='%s'\n",
 - + cmdbuff,
 - + strerror(errno));
 - + goto fail;
 - + }
 - +
 - + num_buff_read = fread(buff, 1, sizeof(buff), script_pipe);
 - + if (num_buff_read < 10) {
 - + dprintf(0, "cygwin_getent_group: Could not read enough data, returned %d\n", (int)num_buff_read);
 - + goto fail;
 - + }
 - +
 - + buff[num_buff_read] = '\0';
 - +
 - + cpvp = cpv_create_parser(buff, 0/*CPVFLAG_DEBUG_OUTPUT*/);
 - + if (!cpvp) {
 - + dprintf(0, "cygwin_getent_group: Could not create parser\n");
 - + goto fail;
 - + }
 - +
 - + if (cpv_read_cpv_header(cpvp)) {
 - + dprintf(0, "cygwin_getent_group: cpv_read_cpv_header failed\n");
 - + goto fail;
 - + }
 - +
 - + for (numcnv=0 ; cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0 ; numcnv++) {
 - + }
 - +
 - + for (i=0 ; i < numcnv ; i++) {
 - + cnv_cur = &cnv[i];
 - + if (!strcmp("localgroupname", cnv_cur->cpv_name)) {
 - + localgroupname = cnv_cur->cpv_value;
 - + }
 - + else if (!strcmp("localgid", cnv_cur->cpv_name)) {
 - + errno = 0;
 - + gid = strtol(cnv_cur->cpv_value, NULL, 10);
 - + if (errno != 0)
 - + goto fail;
 - + }
 - + }
 - +
 - + if (res_group_name)
 - + (void)strcpy_s(res_group_name, VAL_LEN, localgroupname);
 - + *res_gid = gid;
 - + res = 0;
 - +
 - +fail:
 - + if (script_pipe)
 - + (void)_pclose(script_pipe);
 - +
 - + for (i=0 ; i < numcnv ; i++) {
 - + cpv_free_name_val_data(&cnv[i]);
 - + }
 - +
 - + cpv_free_parser(cpvp);
 - +
 - + if (res == 0) {
 - + dprintf(CYGWINIDLVL, "<-- cygwin_getent_group('%s'): "
 - + "returning res_gid=%lu, res_group_name='%s'\n",
 - + name,
 - + (unsigned long)(*res_gid),
 - + res_group_name?res_group_name:"<NULL>");
 - + }
 - + else {
 - + dprintf(CYGWINIDLVL, "<-- cygwin_getent_group('%s'): no match found\n",
 - + name);
 - + }
 - +
 - + return res;
 - +}
 - +#endif /* NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN */
 - +
 
idmapper prototype rework 2023-11-27
Posted by Anonymous on Mon 27th Nov 2023 19:07
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.
 nrubsig.kpaste.net RSS