- From bc771d7a6dbc05549488846ad81d4185b56201f9 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Tue, 28 Nov 2023 12:35:10 +0100
- Subject: [PATCH 1/2] daemon: Rework Cygwin idmapper code to use a script
- instead of getent
- Rework the Cygwin idmapper code to use a script instead of
- /usr/bin/getent, as this is much more flexible.
- The feature is still work-in-progress, and requires that
- NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN is set in
- sys/nfs41_build_features.h
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- build.vc19/nfsd/nfsd.vcxproj | 5 +
- build.vc19/nfsd/nfsd.vcxproj.filters | 15 +
- cygwin_idmapper.ksh | 124 +++++++
- daemon/acl.c | 305 +---------------
- daemon/cpvparser1.c | 361 +++++++++++++++++++
- daemon/cpvparser1.h | 64 ++++
- daemon/idmap.c | 247 +------------
- daemon/idmap.h | 6 +
- daemon/idmap_cygwin.c | 261 ++++++++++++++
- daemon/nfs41_daemon.c | 2 +
- daemon/sid.c | 500 +++++++++++++++++++++++++++
- daemon/sid.h | 35 ++
- 12 files changed, 1382 insertions(+), 543 deletions(-)
- create mode 100644 cygwin_idmapper.ksh
- create mode 100644 daemon/cpvparser1.c
- create mode 100644 daemon/cpvparser1.h
- create mode 100644 daemon/idmap_cygwin.c
- create mode 100644 daemon/sid.c
- create mode 100644 daemon/sid.h
- diff --git a/build.vc19/nfsd/nfsd.vcxproj b/build.vc19/nfsd/nfsd.vcxproj
- index 047f02d..e374d66 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" />
- @@ -182,12 +184,14 @@
- <ClCompile Include="..\..\daemon\recovery.c" />
- <ClCompile Include="..\..\daemon\service.c" />
- <ClCompile Include="..\..\daemon\setattr.c" />
- + <ClCompile Include="..\..\daemon\sid.c" />
- <ClCompile Include="..\..\daemon\symlink.c" />
- <ClCompile Include="..\..\daemon\upcall.c" />
- <ClCompile Include="..\..\daemon\util.c" />
- <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" />
- @@ -204,6 +208,7 @@
- <ClInclude Include="..\..\daemon\pnfs.h" />
- <ClInclude Include="..\..\daemon\recovery.h" />
- <ClInclude Include="..\..\daemon\service.h" />
- + <ClInclude Include="..\..\daemon\sid.h" />
- <ClInclude Include="..\..\daemon\tree.h" />
- <ClInclude Include="..\..\daemon\upcall.h" />
- <ClInclude Include="..\..\daemon\util.h" />
- diff --git a/build.vc19/nfsd/nfsd.vcxproj.filters b/build.vc19/nfsd/nfsd.vcxproj.filters
- index d0ebad9..995410e 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>
- @@ -111,6 +117,9 @@
- <ClCompile Include="..\..\daemon\setattr.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- + <ClCompile Include="..\..\daemon\sid.c">
- + <Filter>Source Files</Filter>
- + </ClCompile>
- <ClCompile Include="..\..\daemon\symlink.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- @@ -125,6 +134,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>
- @@ -173,6 +185,9 @@
- <ClInclude Include="..\..\daemon\service.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- + <ClInclude Include="..\..\daemon\sid.h">
- + <Filter>Header Files</Filter>
- + </ClInclude>
- <ClInclude Include="..\..\daemon\tree.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..6c87f30 100644
- --- a/daemon/acl.c
- +++ b/daemon/acl.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
- @@ -32,7 +33,7 @@
- #include "util.h"
- #include "upcall.h"
- #include "nfs41_xdr.h"
- -#include "idmap.h"
- +#include "sid.h"
- //#define DEBUG_ACLS
- #define ACLLVL 2 /* dprintf level for acl logging */
- @@ -51,41 +52,6 @@ out:
- return status;
- }
- -static int create_unknownsid(WELL_KNOWN_SID_TYPE type, PSID *sid,
- - DWORD *sid_len)
- -{
- - int status;
- - *sid_len = 0;
- - *sid = NULL;
- -
- - status = CreateWellKnownSid(type, NULL, *sid, sid_len);
- - dprintf(ACLLVL, "create_unknownsid: CreateWellKnownSid type %d returned %d "
- - "GetLastError %d sid len %d needed\n", type, status,
- - GetLastError(), *sid_len);
- - if (status) {
- - status = ERROR_INTERNAL_ERROR;
- - goto err;
- - }
- - status = GetLastError();
- - if (status != ERROR_INSUFFICIENT_BUFFER)
- - goto err;
- -
- - *sid = malloc(*sid_len);
- - if (*sid == NULL) {
- - status = ERROR_INSUFFICIENT_BUFFER;
- - goto err;
- - }
- - status = CreateWellKnownSid(type, NULL, *sid, sid_len);
- - if (status)
- - return ERROR_SUCCESS;
- - free(*sid);
- - *sid = NULL;
- - status = GetLastError();
- -err:
- - eprintf("create_unknownsid: CreateWellKnownSid failed with %d\n", status);
- - return status;
- -}
- -
- static void convert_nfs4name_2_user_domain(LPSTR nfs4name,
- LPSTR *domain)
- {
- @@ -100,267 +66,6 @@ static void convert_nfs4name_2_user_domain(LPSTR nfs4name,
- }
- }
- -#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
- -/*
- - * Allocate a SID from SECURITY_SAMBA_UNIX_AUTHORITY, which encodes an
- - * UNIX/POSIX uid directly into a SID.
- - *
- - * Examples:
- - * UID 1616 gets mapped to "Unix_User+1616", encoding the UID into the
- - * SID as "S-1-22-1-1616":
- - * $ getent passwd Unix_User+1616
- - * Unix_User+1616:*:4278191696:4278191696:U-Unix_User616,S-1-22-1-1616:/:/sbin/nologin
- - *
- - * GID 1984 gets mapped to "Unix_Group+1984", encoding the GID into the
- - * SID as "S-1-22-2-1984":
- - * $ getent group Unix_Group+1984
- - * Unix_Group+1984:S-1-22-2-1984:4278192064:
- - *
- - */
- -
- -#define SECURITY_SAMBA_UNIX_AUTHORITY { { 0,0,0,0,0,22 } }
- -SID_IDENTIFIER_AUTHORITY sid_id_auth = SECURITY_SAMBA_UNIX_AUTHORITY;
- -
- -static
- -BOOL allocate_unixuser_sid(unsigned long uid, PSID *pSid)
- -{
- - PSID sid = NULL;
- - PSID malloced_sid = NULL;
- - DWORD sid_len;
- -
- - if (AllocateAndInitializeSid(&sid_id_auth, 2, 1, (DWORD)uid,
- - 0, 0, 0, 0, 0, 0, &sid)) {
- - sid_len = GetLengthSid(sid);
- -
- - malloced_sid = malloc(sid_len);
- -
- - if (malloced_sid) {
- - /*
- - * |AllocateAndInitializeSid()| has an own memory
- - * allocator, but we need the sid in memory from
- - * |malloc()|
- - */
- - if (CopySid(sid_len, malloced_sid, sid)) {
- - FreeSid(sid);
- - *pSid = malloced_sid;
- - dprintf(ACLLVL, "allocate_unixuser_sid(): Allocated "
- - "Unix_User+%lu: success, len=%ld\n",
- - uid, (long)sid_len);
- - return TRUE;
- - }
- - }
- - }
- -
- - FreeSid(sid);
- - free(malloced_sid);
- - dprintf(ACLLVL, "allocate_unixuser_sid(): Failed to allocate "
- - "SID for Unix_User+%lu: error code %d\n",
- - uid, GetLastError());
- - return FALSE;
- -}
- -
- -static
- -BOOL allocate_unixgroup_sid(unsigned long gid, PSID *pSid)
- -{
- - PSID sid = NULL;
- - PSID malloced_sid = NULL;
- - DWORD sid_len;
- -
- - if (AllocateAndInitializeSid(&sid_id_auth, 2, 2, (DWORD)gid,
- - 0, 0, 0, 0, 0, 0, &sid)) {
- - sid_len = GetLengthSid(sid);
- -
- - malloced_sid = malloc(sid_len);
- -
- - if (malloced_sid) {
- - /*
- - * |AllocateAndInitializeSid()| has an own memory
- - * allocator, but we need the sid in memory from
- - * |malloc()|
- - */
- - if (CopySid(sid_len, malloced_sid, sid)) {
- - FreeSid(sid);
- - *pSid = malloced_sid;
- - dprintf(ACLLVL, "allocate_unixgroup_sid(): Allocated "
- - "Unix_Group+%lu: success, len=%ld\n",
- - gid, (long)sid_len);
- - return TRUE;
- - }
- - }
- - }
- -
- - FreeSid(sid);
- - free(malloced_sid);
- - dprintf(ACLLVL, "allocate_unixgroup_sid(): Failed to allocate "
- - "SID for Unix_Group+%lu: error code %d\n",
- - gid, GetLastError());
- - return FALSE;
- -}
- -#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)
- -{
- - int status = ERROR_INTERNAL_ERROR;
- - SID_NAME_USE sid_type;
- - LPSTR tmp_buf = NULL;
- - DWORD tmp = 0;
- -#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
- - signed long user_uid = -1;
- - signed long group_gid = -1;
- -#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
- -
- -#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
- - 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");
- - }
- - 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 "
- - "GetLastError %d name len %d domain len %d\n",
- - query, name, status, GetLastError(), *sid_len, tmp);
- - if (status)
- - return ERROR_INTERNAL_ERROR;
- -
- - status = GetLastError();
- - switch(status) {
- - case ERROR_INSUFFICIENT_BUFFER:
- - *sid = malloc(*sid_len);
- - if (*sid == NULL) {
- - status = GetLastError();
- - goto out;
- - }
- - tmp_buf = (LPSTR) malloc(tmp);
- - if (tmp_buf == NULL)
- - goto out_free_sid;
- - status = LookupAccountName(NULL, name, *sid, sid_len, tmp_buf,
- - &tmp, &sid_type);
- - free(tmp_buf);
- - if (!status) {
- - eprintf("map_name_2_sid(query=%x,name='%s'): LookupAccountName failed "
- - "with %d\n", query, name, GetLastError());
- - goto out_free_sid;
- - } else {
- -#ifdef DEBUG_ACLS
- - LPSTR ssid = NULL;
- - if (IsValidSid(*sid))
- - if (ConvertSidToStringSidA(*sid, &ssid))
- - dprintf(1, "map_name_2_sid: sid_type = %d SID %s\n",
- - sid_type, ssid);
- - else
- - dprintf(1, "map_name_2_sid: ConvertSidToStringSidA failed "
- - "with %d\n", GetLastError());
- - else
- - dprintf(1, "map_name_2_sid: Invalid Sid ?\n");
- - if (ssid) LocalFree(ssid);
- -#endif
- - }
- - status = ERROR_SUCCESS;
- - 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, "
- - "trying Unix_User+/Unix_Group+ mapping\n",
- - query, name);
- -
- - if ((user_uid == -1) && (query & OWNER_SECURITY_INFORMATION)) {
- - uid_t map_uid = -1;
- - gid_t gid_dummy = -1;
- -
- - if (nfs41_idmap_name_to_ids(
- - nfs41dg->idmapper,
- - name,
- - &map_uid,
- - &gid_dummy) == 0) {
- - user_uid = map_uid;
- - }
- - else {
- - dprintf(1, "map_name_2_sid(query=%x,name='%s'): nfs41_idmap_name_to_ids() failed\n",
- - query, name);
- - /* fixme: try harder here, "1234" should to to |atol()| */
- - }
- - }
- -
- - if ((group_gid == -1) && (query & GROUP_SECURITY_INFORMATION)) {
- - gid_t map_gid = -1;
- -
- - if (nfs41_idmap_group_to_gid(
- - nfs41dg->idmapper,
- - name,
- - &map_gid) == 0) {
- - group_gid = map_gid;
- - }
- - else {
- - dprintf(1, "map_name_2_sid(query=%x,name='%s'): nfs41_idmap_group_to_gid() failed\n",
- - query, name);
- - /* fixme: try harder here, "1234" should to to |atol()| */
- - }
- - }
- -
- - if (user_uid != -1) {
- - if (allocate_unixuser_sid(user_uid, sid)) {
- - dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
- - "allocate_unixuser_sid(uid=%ld) success\n",
- - query, name, user_uid);
- - return ERROR_SUCCESS;
- - }
- -
- - status = GetLastError();
- - dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
- - "allocate_unixuser_sid(uid=%ld) failed, error=%d\n",
- - query, name, user_uid, status);
- - return status;
- - }
- -
- - if (group_gid != -1) {
- - if (allocate_unixgroup_sid(group_gid, sid)) {
- - dprintf(ACLLVL, "map_name_2_sid(query=%x,name='%s'): "
- - "allocate_unixgroup_sid(gid=%ld) success\n",
- - query, name, group_gid);
- - return ERROR_SUCCESS;
- - }
- -
- - status = GetLastError();
- - dprintf(ACLLVL, "map_name_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, "
- - "using WinNullSid mapping\n",
- - query, name);
- -
- - status = create_unknownsid(WinNullSid, sid, sid_len);
- - if (status)
- - goto out_free_sid;
- - break;
- - default:
- - dprintf(1, "map_name_2_sid(query=%x,name='%s'): error %d not handled\n",
- - query, name, GetLastError());
- - break;
- - }
- -out:
- - return status;
- -out_free_sid:
- - status = GetLastError();
- - free(*sid);
- - *sid = NULL;
- - goto out;
- -}
- -
- static void free_sids(PSID *sids, int count)
- {
- int i;
- @@ -417,7 +122,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 +239,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 +257,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..46a234d 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
- @@ -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.h b/daemon/idmap.h
- index 6a78476..d729575 100644
- --- a/daemon/idmap.h
- +++ b/daemon/idmap.h
- @@ -64,4 +64,10 @@ int nfs41_idmap_gid_to_group(
- char *name_out,
- size_t len);
- +/* idmap_cygwin.c */
- +#ifdef NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN
- +int cygwin_getent_passwd(const char *name, char *res_loginname, uid_t *res_uid, gid_t *res_gid);
- +int cygwin_getent_group(const char* name, char* res_group_name, gid_t* res_gid);
- +#endif /* NFS41_DRIVER_FEATURE_NAMESERVICE_CYGWIN */
- +
- #endif /* !IDMAP_H */
- diff --git a/daemon/idmap_cygwin.c b/daemon/idmap_cygwin.c
- new file mode 100644
- index 0000000..5f82f69
- --- /dev/null
- +++ b/daemon/idmap_cygwin.c
- @@ -0,0 +1,261 @@
- +/* NFSv4.1 client for Windows
- + * Copyright x 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 2 /* 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;
- + int retries = 3;
- +
- + 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);
- +retry:
- + if ((script_pipe = _popen(cmdbuff, "rt")) == NULL) {
- + int saved_errno = errno;
- + dprintf(0, "cygwin_getent_passwd: '%s' failed, errno='%s', retries=%d\n",
- + cmdbuff,
- + strerror(saved_errno),
- + retries);
- + if ((saved_errno == EINVAL) && (retries-- > 0)) {
- + (void)SwitchToThread();
- + goto retry;
- + }
- + 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;
- + int retries = 3;
- +
- + 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);
- +retry:
- + if ((script_pipe = _popen(cmdbuff, "rt")) == NULL) {
- + int saved_errno = errno;
- + dprintf(0,
- + "cygwin_getent_group: '%s' failed, errno='%s', retries=%d\n",
- + cmdbuff,
- + strerror(saved_errno),
- + retries);
- + if ((saved_errno == EINVAL) && (retries-- > 0)) {
- + (void)SwitchToThread();
- + goto retry;
- + }
- + 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 */
- diff --git a/daemon/nfs41_daemon.c b/daemon/nfs41_daemon.c
- index 12b7c55..047e468 100644
- --- a/daemon/nfs41_daemon.c
- +++ b/daemon/nfs41_daemon.c
- @@ -33,6 +33,7 @@
- #include "nfs41_daemon.h"
- #include "daemon_debug.h"
- #include "upcall.h"
- +#include "sid.h"
- #include "util.h"
- /* nfs41_dg.num_worker_threads sets the actual number of worker threads */
- @@ -409,6 +410,7 @@ VOID ServiceStart(DWORD argc, LPTSTR *argv)
- exit(1);
- set_debug_level(cmd_args.debug_level);
- open_log_files();
- + sidcache_init();
- #ifdef _DEBUG
- /* dump memory leaks to stderr on exit; this requires the debug heap,
- diff --git a/daemon/sid.c b/daemon/sid.c
- new file mode 100644
- index 0000000..21d9732
- --- /dev/null
- +++ b/daemon/sid.c
- @@ -0,0 +1,500 @@
- +/* NFSv4.1 client for Windows
- + * Copyright x 2012 The Regents of the University of Michigan
- + *
- + * 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
- + * 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 <stdio.h>
- +#include <time.h>
- +#include <strsafe.h>
- +#include <sddl.h>
- +
- +#include "nfs41_ops.h"
- +#include "nfs41_build_features.h"
- +#include "nfs41_daemon.h"
- +#include "delegation.h"
- +#include "daemon_debug.h"
- +#include "util.h"
- +#include "upcall.h"
- +#include "nfs41_xdr.h"
- +#include "idmap.h"
- +#include "sid.h"
- +
- +//#define DEBUG_ACLS
- +#define ACLLVL 2 /* dprintf level for acl logging */
- +
- +
- +int create_unknownsid(WELL_KNOWN_SID_TYPE type, PSID *sid, DWORD *sid_len)
- +{
- + int status;
- + *sid_len = 0;
- + *sid = NULL;
- +
- + status = CreateWellKnownSid(type, NULL, *sid, sid_len);
- + dprintf(ACLLVL,
- + "create_unknownsid: CreateWellKnownSid(type=%d) returned %d "
- + "GetLastError %d sid len %d needed\n", (int)type, status,
- + GetLastError(), *sid_len);
- + if (status) {
- + status = ERROR_INTERNAL_ERROR;
- + goto err;
- + }
- + status = GetLastError();
- + if (status != ERROR_INSUFFICIENT_BUFFER)
- + goto err;
- +
- + *sid = malloc(*sid_len);
- + if (*sid == NULL) {
- + status = ERROR_INSUFFICIENT_BUFFER;
- + goto err;
- + }
- + status = CreateWellKnownSid(type, NULL, *sid, sid_len);
- + if (status)
- + return ERROR_SUCCESS;
- + free(*sid);
- + *sid = NULL;
- + status = GetLastError();
- +err:
- + eprintf("create_unknownsid: CreateWellKnownSid(type=%d) failed with %d\n",
- + (int)type, status);
- + return status;
- +}
- +
- +#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
- +/*
- + * Allocate a SID from SECURITY_SAMBA_UNIX_AUTHORITY, which encodes an
- + * UNIX/POSIX uid directly into a SID.
- + *
- + * Examples:
- + * UID 1616 gets mapped to "Unix_User+1616", encoding the UID into the
- + * SID as "S-1-22-1-1616":
- + * $ getent passwd Unix_User+1616
- + * Unix_User+1616:*:4278191696:4278191696:U-Unix_User616,S-1-22-1-1616:/:/sbin/nologin
- + *
- + * GID 1984 gets mapped to "Unix_Group+1984", encoding the GID into the
- + * SID as "S-1-22-2-1984":
- + * $ getent group Unix_Group+1984
- + * Unix_Group+1984:S-1-22-2-1984:4278192064:
- + *
- + */
- +
- +#define SECURITY_SAMBA_UNIX_AUTHORITY { { 0,0,0,0,0,22 } }
- +SID_IDENTIFIER_AUTHORITY sid_id_auth = SECURITY_SAMBA_UNIX_AUTHORITY;
- +
- +static
- +BOOL allocate_unixuser_sid(unsigned long uid, PSID *pSid)
- +{
- + PSID sid = NULL;
- + PSID malloced_sid = NULL;
- + DWORD sid_len;
- +
- + if (AllocateAndInitializeSid(&sid_id_auth, 2, 1, (DWORD)uid,
- + 0, 0, 0, 0, 0, 0, &sid)) {
- + sid_len = GetLengthSid(sid);
- +
- + malloced_sid = malloc(sid_len);
- +
- + if (malloced_sid) {
- + /*
- + * |AllocateAndInitializeSid()| has an own memory
- + * allocator, but we need the sid in memory from
- + * |malloc()|
- + */
- + if (CopySid(sid_len, malloced_sid, sid)) {
- + FreeSid(sid);
- + *pSid = malloced_sid;
- + dprintf(ACLLVL, "allocate_unixuser_sid(): Allocated "
- + "Unix_User+%lu: success, len=%ld\n",
- + uid, (long)sid_len);
- + return TRUE;
- + }
- + }
- + }
- +
- + FreeSid(sid);
- + free(malloced_sid);
- + dprintf(ACLLVL, "allocate_unixuser_sid(): Failed to allocate "
- + "SID for Unix_User+%lu: error code %d\n",
- + uid, GetLastError());
- + return FALSE;
- +}
- +
- +static
- +BOOL allocate_unixgroup_sid(unsigned long gid, PSID *pSid)
- +{
- + PSID sid = NULL;
- + PSID malloced_sid = NULL;
- + DWORD sid_len;
- +
- + if (AllocateAndInitializeSid(&sid_id_auth, 2, 2, (DWORD)gid,
- + 0, 0, 0, 0, 0, 0, &sid)) {
- + sid_len = GetLengthSid(sid);
- +
- + malloced_sid = malloc(sid_len);
- +
- + if (malloced_sid) {
- + /*
- + * |AllocateAndInitializeSid()| has an own memory
- + * allocator, but we need the sid in memory from
- + * |malloc()|
- + */
- + if (CopySid(sid_len, malloced_sid, sid)) {
- + FreeSid(sid);
- + *pSid = malloced_sid;
- + dprintf(ACLLVL, "allocate_unixgroup_sid(): Allocated "
- + "Unix_Group+%lu: success, len=%ld\n",
- + gid, (long)sid_len);
- + return TRUE;
- + }
- + }
- + }
- +
- + FreeSid(sid);
- + free(malloced_sid);
- + dprintf(ACLLVL, "allocate_unixgroup_sid(): Failed to allocate "
- + "SID for Unix_Group+%lu: error code %d\n",
- + gid, GetLastError());
- + return FALSE;
- +}
- +#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
- +
- +
- +/* fixme: should be in sys/nfs41_build_features.h */
- +#define USE_SID_CACHE 1
- +
- +
- +#ifdef USE_SID_CACHE
- +#define SIDCACHE_SIZE 20
- +#define SIDCACHE_TTL 600
- +
- +typedef struct _sidcache_entry
- +{
- + char name[128]; /* must fit something like "user@domain" */
- + PSID sid;
- + DWORD sid_len;
- + time_t timestamp;
- +} sidcache_entry;
- +
- +typedef struct _sidcache
- +{
- + CRITICAL_SECTION lock;
- + sidcache_entry entries[SIDCACHE_SIZE];
- + ssize_t cacheIndex;
- +} sidcache;
- +
- +/* fixme: need function to deallocate this */
- +sidcache user_sidcache = { 0 };
- +
- +
- +void sidcache_init(void)
- +{
- + dprintf(0, "SID cache init\n");
- + InitializeCriticalSection(&user_sidcache.lock);
- +}
- +
- +/* copy SID |value| into cache */
- +void sidcache_add(sidcache *cache, const char* name, PSID value)
- +{
- + int i;
- + ssize_t freeEntryIndex;
- + time_t currentTimestamp;
- +
- + EnterCriticalSection(&cache->lock);
- + currentTimestamp = time(NULL);
- +
- + /* purge obsolete entries */
- + for (i = 0; i < SIDCACHE_SIZE; i++) {
- + sidcache_entry *e = &cache->entries[i];
- +
- + if ((e->sid != NULL) &&
- + (e->timestamp < (currentTimestamp - SIDCACHE_TTL))) {
- + free(e->sid);
- + e->sid = NULL;
- + e->name[0] = '\0';
- + }
- + }
- +
- + /* Find the oldest valid cache entry */
- + freeEntryIndex = -1;
- + for (i = 0; i < SIDCACHE_SIZE; i++) {
- + if (cache->entries[i].sid == NULL) {
- + freeEntryIndex = i;
- + break;
- + }
- + }
- +
- + /* If no valid entry was found, overwrite the oldest entry */
- + if (freeEntryIndex == -1) {
- + freeEntryIndex = 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;
- + }
- +
- + sidcache_entry *e = &cache->entries[freeEntryIndex];
- +
- + e->sid_len = sid_len;
- + if (e->sid)
- + free(e->sid);
- + e->sid = malloced_sid;
- + (void)strcpy_s(e->name, sizeof(e->name), name);
- + e->timestamp = currentTimestamp;
- +
- + cache->cacheIndex = (cache->cacheIndex + 1) % SIDCACHE_SIZE;
- +
- +done:
- + LeaveCriticalSection(&cache->lock);
- +}
- +
- +/* return |malloc()|'ed copy of SID from cache entry */
- +PSID *sidcache_getcached(sidcache *cache, const char *name)
- +{
- + int i;
- + time_t currentTimestamp;
- + sidcache_entry *e;
- + PSID *ret_sid = NULL;
- +
- + EnterCriticalSection(&cache->lock);
- + currentTimestamp = time(NULL);
- +
- + for (i = 0; i < SIDCACHE_SIZE; i++) {
- + e = &cache->entries[i];
- +
- + if ((e->sid != NULL) &&
- + (!strcmp(e->name, name)) &&
- + ((currentTimestamp - e->timestamp) < SIDCACHE_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 /* USE_SID_CACHE */
- +
- +
- +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
- + signed long user_uid = -1;
- + signed long group_gid = -1;
- +#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) {
- + uid_t udummy = -1;
- + gid_t gdummy = -1;
- +
- +#ifdef USE_SID_CACHE
- + if (*sid = sidcache_getcached(&user_sidcache, name)) {
- + *sid_len = GetLengthSid(*sid);
- + dprintf(1, "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(1,
- + "map_nfs4servername_2_sid: remap '%s' --> '%s'\n",
- + name,
- + name_buff);
- + name = name_buff;
- + }
- + }
- + }
- +#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
- +
- + status = LookupAccountName(NULL, name, NULL, sid_len, NULL, &tmp, &sid_type);
- + 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)
- + return ERROR_INTERNAL_ERROR;
- +
- + status = GetLastError();
- + switch(status) {
- + case ERROR_INSUFFICIENT_BUFFER:
- + *sid = malloc(*sid_len);
- + if (*sid == NULL) {
- + status = GetLastError();
- + goto out;
- + }
- + tmp_buf = (LPSTR) malloc(tmp);
- + if (tmp_buf == NULL)
- + goto out_free_sid;
- + status = LookupAccountName(NULL, name, *sid, sid_len, tmp_buf,
- + &tmp, &sid_type);
- + free(tmp_buf);
- + if (!status) {
- + eprintf("map_nfs4servername_2_sid(query=%x,name='%s'): LookupAccountName failed "
- + "with %d\n", query, name, GetLastError());
- + goto out_free_sid;
- + } else {
- +#ifdef DEBUG_ACLS
- + LPSTR ssid = NULL;
- + if (IsValidSid(*sid))
- + if (ConvertSidToStringSidA(*sid, &ssid))
- + dprintf(1, "map_nfs4servername_2_sid: sid_type = %d SID '%s'\n",
- + sid_type, ssid);
- + else
- + dprintf(1, "map_nfs4servername_2_sid: ConvertSidToStringSidA failed "
- + "with %d\n", GetLastError());
- + else
- + dprintf(1, "map_nfs4servername_2_sid: Invalid Sid ?\n");
- + if (ssid)
- + LocalFree(ssid);
- +#endif
- + }
- + status = ERROR_SUCCESS;
- + break;
- + case ERROR_NONE_MAPPED:
- +#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
- + dprintf(1, "map_nfs4servername_2_sid(query=%x,name='%s'): "
- + "none mapped, "
- + "trying Unix_User+/Unix_Group+ mapping\n",
- + query, name);
- +
- + if ((user_uid == -1) && (query & OWNER_SECURITY_INFORMATION)) {
- + uid_t map_uid = -1;
- + gid_t gid_dummy = -1;
- +
- + if (nfs41_idmap_name_to_ids(
- + nfs41dg->idmapper,
- + name,
- + &map_uid,
- + &gid_dummy) == 0) {
- + user_uid = map_uid;
- + }
- + else {
- + 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()| */
- + }
- + }
- +
- + if ((group_gid == -1) && (query & GROUP_SECURITY_INFORMATION)) {
- + gid_t map_gid = -1;
- +
- + if (nfs41_idmap_group_to_gid(
- + nfs41dg->idmapper,
- + name,
- + &map_gid) == 0) {
- + group_gid = map_gid;
- + }
- + else {
- + 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()| */
- + }
- + }
- +
- + if (user_uid != -1) {
- + if (allocate_unixuser_sid(user_uid, sid)) {
- + dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): "
- + "allocate_unixuser_sid(uid=%ld) success\n",
- + query, name, user_uid);
- + status = ERROR_SUCCESS;
- + goto out;
- + }
- +
- + status = GetLastError();
- + 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;
- + }
- +
- + if (group_gid != -1) {
- + if (allocate_unixgroup_sid(group_gid, sid)) {
- + dprintf(ACLLVL, "map_nfs4servername_2_sid(query=%x,name='%s'): "
- + "allocate_unixgroup_sid(gid=%ld) success\n",
- + query, name, group_gid);
- + status = ERROR_SUCCESS;
- + goto out;
- + }
- +
- + status = GetLastError();
- + 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_nfs4servername_2_sid(query=%x,name='%s'): none mapped, "
- + "using WinNullSid mapping\n",
- + query, name);
- +
- + status = create_unknownsid(WinNullSid, sid, sid_len);
- + if (status)
- + goto out_free_sid;
- + break;
- + default:
- + 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) {
- + sidcache_add(&user_sidcache, orig_name, *sid);
- + }
- + }
- +#endif /* USE_SID_CACHE */
- +
- + return status;
- +out_free_sid:
- + status = GetLastError();
- + free(*sid);
- + *sid = NULL;
- + goto out;
- +}
- diff --git a/daemon/sid.h b/daemon/sid.h
- new file mode 100644
- index 0000000..e6d87c5
- --- /dev/null
- +++ b/daemon/sid.h
- @@ -0,0 +1,35 @@
- +
- +/* NFSv4.1 client for Windows
- + * Copyright x 2012 The Regents of the University of Michigan
- + *
- + * 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
- + * 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
- + */
- +
- +#ifndef __NFS41_DAEMON_SID_H
- +#define __NFS41_DAEMON_SID_H 1
- +
- +#include "nfs41_build_features.h"
- +#include "nfs41_daemon.h"
- +
- +/* prototypes */
- +int create_unknownsid(WELL_KNOWN_SID_TYPE type, PSID *sid, DWORD *sid_len);
- +void sidcache_init(void);
- +int map_nfs4servername_2_sid(nfs41_daemon_globals *nfs41dg, int query, DWORD *sid_len, PSID *sid, LPCSTR name);
- +
- +#endif /* !__NFS41_DAEMON_SID_H */
- --
- 2.42.1
- From 00ec1812f6e7ff3c918844f9e7f935978456cf11 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Tue, 28 Nov 2023 16:33:23 +0100
- Subject: [PATCH 2/2] daemon: Fix Cygwin idmapper random |popen()| failure
- Fix Cygwin idmapper random |popen()| failure by replacing Win32
- |popen()| with our own code to read output from the idmapper
- script.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- cygwin_idmapper.ksh | 4 +-
- daemon/idmap_cygwin.c | 85 +++++++++++++++---------------
- daemon/util.c | 119 ++++++++++++++++++++++++++++++++++++++++++
- daemon/util.h | 10 ++++
- 4 files changed, 174 insertions(+), 44 deletions(-)
- diff --git a/cygwin_idmapper.ksh b/cygwin_idmapper.ksh
- index 4b96ecf..acf6e32 100644
- --- a/cygwin_idmapper.ksh
- +++ b/cygwin_idmapper.ksh
- @@ -79,7 +79,7 @@ compound -A localgroups=(
- )
- case "${c.mode}" in
- - 'nfsserveruser2localaccount')
- + 'nfsserver_owner2localaccount')
- if [[ "${c.name}" == ~(Elr)[[:digit:]]+ ]] ; then
- for s in "${!localusers[@]}" ; do
- if (( localusers[$s].localuid == c.name )) ; then
- @@ -97,7 +97,7 @@ case "${c.mode}" in
- exit 1
- fi
- ;;
- - 'nfsserveruser2localgroup')
- + 'nfsserver_owner_group2localgroup')
- if [[ "${c.name}" == ~(Elr)[[:digit:]]+ ]] ; then
- for s in "${!localgroups[@]}" ; do
- if (( localgroups[$s].localgid == c.name )) ; then
- diff --git a/daemon/idmap_cygwin.c b/daemon/idmap_cygwin.c
- index 5f82f69..64c1bff 100644
- --- a/daemon/idmap_cygwin.c
- +++ b/daemon/idmap_cygwin.c
- @@ -22,11 +22,11 @@
- #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 "util.h"
- #include "nfs41_const.h"
- #include "list.h"
- #include "daemon_debug.h"
- @@ -48,48 +48,46 @@ int cygwin_getent_passwd(const char *name, char *res_loginname, uid_t *res_uid,
- {
- char cmdbuff[1024];
- char buff[2048];
- - size_t num_buff_read;
- - FILE* script_pipe = NULL;
- + DWORD num_buff_read;
- + subcmd_popen_context *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[64] = { 0 };
- cpv_name_val *cnv_cur = NULL;
- const char *localaccoutname = NULL;
- - int retries = 3;
- dprintf(CYGWINIDLVL, "--> cygwin_getent_passwd('%s')\n", name);
- /* fixme: better quoting for |name| needed */
- (void)snprintf(cmdbuff, sizeof(cmdbuff),
- - "%s nfsserveruser2localaccount \"%s\"",
- + "%s nfsserver_owner2localaccount \"%s\"",
- CYGWIN_IDMAPPER_SCRIPT,
- name);
- -retry:
- - if ((script_pipe = _popen(cmdbuff, "rt")) == NULL) {
- - int saved_errno = errno;
- - dprintf(0, "cygwin_getent_passwd: '%s' failed, errno='%s', retries=%d\n",
- + if ((script_pipe = subcmd_popen(cmdbuff)) == NULL) {
- + int last_error = GetLastError();
- + dprintf(0, "cygwin_getent_passwd: '%s' failed, GetLastError()='%d'\n",
- cmdbuff,
- - strerror(saved_errno),
- - retries);
- - if ((saved_errno == EINVAL) && (retries-- > 0)) {
- - (void)SwitchToThread();
- - goto retry;
- - }
- + last_error);
- 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);
- + if (!subcmd_readcmdoutput(script_pipe,
- + buff, sizeof(buff), &num_buff_read)) {
- + dprintf(0, "cygwin_getent_passwd: subcmd_readcmdoutput() failed\n");
- goto fail;
- }
- buff[num_buff_read] = '\0';
- + if (num_buff_read < 10) {
- + dprintf(0, "cygwin_getent_passwd: Could not read enough data, returned %d\n", (int)num_buff_read);
- + goto fail;
- + }
- +
- cpvp = cpv_create_parser(buff, 0/*CPVFLAG_DEBUG_OUTPUT*/);
- if (!cpvp) {
- dprintf(0, "cygwin_getent_passwd: Could not create parser\n");
- @@ -101,7 +99,10 @@ retry:
- goto fail;
- }
- - for (numcnv=0 ; cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0 ; numcnv++) {
- + /* Loop parsing compound variable elements */
- + for (numcnv=0 ;
- + (cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0) && (numcnv < 64) ;
- + numcnv++) {
- }
- for (i=0 ; i < numcnv ; i++) {
- @@ -131,7 +132,7 @@ retry:
- fail:
- if (script_pipe)
- - (void)_pclose(script_pipe);
- + (void)subcmd_pclose(script_pipe);
- for (i=0 ; i < numcnv ; i++) {
- cpv_free_name_val_data(&cnv[i]);
- @@ -159,16 +160,15 @@ 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;
- + DWORD num_buff_read;
- + subcmd_popen_context *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[64] = { 0 };
- cpv_name_val *cnv_cur = NULL;
- - int retries = 3;
- const char *localgroupname = NULL;
- @@ -176,32 +176,30 @@ int cygwin_getent_group(const char* name, char* res_group_name, gid_t* res_gid)
- /* fixme: better quoting for |name| needed */
- (void)snprintf(cmdbuff, sizeof(cmdbuff),
- - "%s nfsserveruser2localgroup \"%s\"",
- + "%s nfsserver_owner_group2localgroup \"%s\"",
- CYGWIN_IDMAPPER_SCRIPT,
- name);
- -retry:
- - if ((script_pipe = _popen(cmdbuff, "rt")) == NULL) {
- - int saved_errno = errno;
- - dprintf(0,
- - "cygwin_getent_group: '%s' failed, errno='%s', retries=%d\n",
- + if ((script_pipe = subcmd_popen(cmdbuff)) == NULL) {
- + int last_error = GetLastError();
- + dprintf(0, "cygwin_getent_group: '%s' failed, GetLastError()='%d'\n",
- cmdbuff,
- - strerror(saved_errno),
- - retries);
- - if ((saved_errno == EINVAL) && (retries-- > 0)) {
- - (void)SwitchToThread();
- - goto retry;
- - }
- + last_error);
- 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);
- + if (!subcmd_readcmdoutput(script_pipe,
- + buff, sizeof(buff), &num_buff_read)) {
- + dprintf(0, "cygwin_getent_group: subcmd_readcmdoutput() failed\n");
- goto fail;
- }
- buff[num_buff_read] = '\0';
- + if (num_buff_read < 10) {
- + dprintf(0, "cygwin_getent_group: Could not read enough data, returned %d\n", (int)num_buff_read);
- + goto fail;
- + }
- +
- cpvp = cpv_create_parser(buff, 0/*CPVFLAG_DEBUG_OUTPUT*/);
- if (!cpvp) {
- dprintf(0, "cygwin_getent_group: Could not create parser\n");
- @@ -213,7 +211,10 @@ retry:
- goto fail;
- }
- - for (numcnv=0 ; cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0 ; numcnv++) {
- + /* Loop parsing compound variable elements */
- + for (numcnv=0 ;
- + (cpv_parse_name_val(cpvp, &cnv[numcnv]) == 0) && (numcnv < 64) ;
- + numcnv++) {
- }
- for (i=0 ; i < numcnv ; i++) {
- @@ -236,7 +237,7 @@ retry:
- fail:
- if (script_pipe)
- - (void)_pclose(script_pipe);
- + (void)subcmd_pclose(script_pipe);
- for (i=0 ; i < numcnv ; i++) {
- cpv_free_name_val_data(&cnv[i]);
- diff --git a/daemon/util.c b/daemon/util.c
- index 3680d27..3051f4b 100644
- --- a/daemon/util.c
- +++ b/daemon/util.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
- @@ -458,3 +459,121 @@ out_context:
- out:
- return status;
- }
- +
- +
- +/*
- + * Like Win32 |popen()| but doesn't randomly fail or genrates EINVAL
- + * for unknown reasons
- + */
- +subcmd_popen_context *subcmd_popen(const char *command)
- +{
- + subcmd_popen_context *pinfo;
- + STARTUPINFOA si;
- + SECURITY_ATTRIBUTES sa = { 0 };
- +
- + if (!command) {
- + return NULL;
- + }
- +
- + pinfo = malloc(sizeof(subcmd_popen_context));
- + if (!pinfo)
- + return NULL;
- +
- + pinfo->hReadPipe = pinfo->hWritePipe = NULL;
- +
- +#ifdef NOT_WORKING_YET
- + /*
- + * gisburn: fixme: Currently |CreatePipe()| can fail with
- + * |ERROR_BAD_IMPERSONATION_LEVEL|/|1346| for user
- + * "SYSTEM" if nfsd(|debug).exe tries to impersonate
- + * user "SYSTEM" while running as normal user.
- + */
- + SECURITY_DESCRIPTOR sd;
- + (void)memset(&sd, 0, sizeof(SECURITY_DESCRIPTOR));
- + (void)InitializeSecurityDescriptor(&sd, 1);
- + sd.Revision = 1;
- + sd.Control |= SE_DACL_PRESENT;
- + sd.Dacl = NULL;
- +#endif /* NOT_WORKING_YET */
- +
- + sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- + sa.bInheritHandle = TRUE;
- +#ifdef NOT_WORKING_YET
- + sa.lpSecurityDescriptor = &sd;
- +#else
- + sa.lpSecurityDescriptor = NULL;
- +#endif /* NOT_WORKING_YET */
- +
- + /*
- + * Create a pipe for communication between the parent and child
- + * processes
- + */
- + if (!CreatePipe(&pinfo->hReadPipe, &pinfo->hWritePipe, &sa, 0)) {
- + dprintf(0, "subcmd_popen: CreatePipe error, status=%d\n",
- + (int)GetLastError());
- + goto fail;
- + }
- +
- + /* Set the pipe handles to non-inheritable */
- + if (!SetHandleInformation(pinfo->hReadPipe, HANDLE_FLAG_INHERIT, FALSE)) {
- + dprintf(0, "subcmd_popen: SetHandleInformation error\n");
- + goto fail;
- + }
- +
- + (void)memset(&si, 0, sizeof(si));
- + si.cb = sizeof(si);
- + si.hStdInput = NULL;
- + si.hStdOutput = pinfo->hWritePipe;
- + si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
- + si.dwFlags |= STARTF_USESTDHANDLES;
- +
- + if (!CreateProcessA(NULL,
- + (LPSTR)command, NULL, NULL, TRUE, 0, NULL, NULL, &si,
- + &pinfo->pi)) {
- + dprintf(0, "subcmd_popen: cannot create process\n");
- + goto fail;
- + }
- +
- + CloseHandle(pinfo->hWritePipe);
- +
- + return pinfo;
- +fail:
- + if (pinfo) {
- + if (pinfo->hReadPipe)
- + CloseHandle(pinfo->hReadPipe);
- + if (pinfo->hWritePipe)
- + CloseHandle(pinfo->hWritePipe);
- +
- + free(pinfo);
- + }
- + return NULL;
- +}
- +
- +int subcmd_pclose(subcmd_popen_context *pinfo)
- +{
- + DWORD status;
- +
- + /* Close the read handle to the pipe from the child process */
- + CloseHandle(pinfo->hReadPipe);
- +
- + WaitForSingleObject(pinfo->pi.hProcess, INFINITE);
- +
- + if (!GetExitCodeProcess(pinfo->pi.hProcess, &status)) {
- + status = -1;
- + }
- +
- + CloseHandle(pinfo->pi.hProcess);
- + CloseHandle(pinfo->pi.hThread);
- +
- + if (status != 0) {
- + (void)dprintf(0, "subcmd_pclose(): exit code=%d\n", (int)status);
- + }
- + free(pinfo);
- +
- + return status;
- +}
- +
- +BOOL subcmd_readcmdoutput(subcmd_popen_context *pinfo, char *buff, size_t buff_size, DWORD *num_buff_read_ptr)
- +{
- + return ReadFile(pinfo->hReadPipe, buff, (DWORD)buff_size, num_buff_read_ptr, NULL);
- +}
- diff --git a/daemon/util.h b/daemon/util.h
- index 573e0fe..3d6395a 100644
- --- a/daemon/util.h
- +++ b/daemon/util.h
- @@ -256,4 +256,14 @@ __inline int valid_handle(HANDLE handle) {
- return handle != INVALID_HANDLE_VALUE && handle != 0;
- }
- +typedef struct _subcmd_popen_context {
- + HANDLE hReadPipe;
- + HANDLE hWritePipe;
- + PROCESS_INFORMATION pi;
- +} subcmd_popen_context;
- +
- +subcmd_popen_context *subcmd_popen(const char *command);
- +int subcmd_pclose(subcmd_popen_context *pinfo);
- +BOOL subcmd_readcmdoutput(subcmd_popen_context *pinfo, char *buff, size_t buff_size, DWORD *num_buff_read_ptr);
- +
- #endif /* !__NFS41_DAEMON_UTIL_H__ */
- --
- 2.42.1
msnfs41client: Patches for Cygwin idmapper rework, 2023-11-28
Posted by Anonymous on Tue 28th Nov 2023 18:02
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.