diff --git a/TODO.md b/TODO.md index 880a72a..2cdbac7 100644 --- a/TODO.md +++ b/TODO.md @@ -406,9 +406,9 @@ Refactor/wrapper follow-up: reusing existing mars_nwe volume, namespace, and directory-handle helpers. - Route all AFP writes through existing mars_nwe policy checks before changing metadata. Archive and Modify timestamp already do this through NetWare - helpers; FinderInfo and AFP-only Invisible/System xattr writes still need an - explicit Modify-rights gate using the same trustee/effective-rights policy as - normal NetWare metadata writes. + helpers. FinderInfo and AFP-only Invisible/System xattr writes are now gated + by the same trustee/effective-rights Modify policy before the AFP metadata + xattrs are updated. - Continue moving AFP-visible NetWare attributes onto the existing NetWare attribute store. Archive is already mapped to `FILE_ATTR_A`; ReadOnly, Hidden, System, ExecuteOnly, and Shareable still need either a real mapping @@ -428,6 +428,19 @@ Refactor/wrapper follow-up: Entry ID/CNID index or an existing canonical path lookup once the entry-id backend grows beyond xattr/stat-derived compatibility IDs. + +AFP Set File Information metadata-rights convergence: + +- AFP FinderInfo writes and AFP-only Invisible/System attribute xattr writes no + longer bypass NetWare policy just because their storage is AFP-specific. + `afp_set_file_information()` now checks the resolved file through the existing + trustee/effective-rights Modify policy before writing `org.mars-nwe.afp.*` + metadata. +- Archive continues to route through the NetWare attribute helper (`FILE_ATTR_A`), + and Modify timestamp continues to route through `nw_utime_node()`. The new + check only covers metadata that has to remain AFP-specific, keeping AFP as an + Apple-facing adapter over mars_nwe policy rather than a parallel file server. + Endpoint order: - First finish the non-destructive convergence work above. diff --git a/src/nwconn.c b/src/nwconn.c index c05be94..4f390b2 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -1305,6 +1305,20 @@ static int afp_set_netware_archive_attribute(int volume, char *unixname, return(set_nw_attrib_word(volume, unixname, stb, (int)(nw_attrs & 0xffff))); } +static int afp_check_metadata_modify_rights(int volume, char *unixname, + struct stat *stb, + const char *call_name, + uint8 *path, int path_len) +{ + if (!unixname || !stb) return(-0x9c); + if (tru_eff_rights_exists(volume, (uint8 *)unixname, stb, TRUSTEE_M)) { + XDPRINTF((2,0, "%s rejected: no Modify rights for AFP metadata path='%s'", + call_name, visable_data(path, path_len))); + return(-0x8c); /* no modify rights */ + } + return(0); +} + static int afp_set_file_information(uint8 *afp_req, int afp_len, const char *call_name) /* @@ -1333,6 +1347,7 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len, int result; uint16 log_attrs = 0; time_t log_mtime = (time_t)-1; + int needs_afp_metadata_modify = 0; if (afp_len < 9) { XDPRINTF((2,0, "%s rejected: short request len=%d", @@ -1390,6 +1405,8 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len, call_name, requested_attrs, visable_data(afp_req + 9, path_len))); return(-0x9c); } + if (requested_bits & AFP_ATTR_XATTR_MASK) + needs_afp_metadata_modify = 1; data_off += 2; } if ((request_mask & AFP_FILE_BITMAP_MODIFY_DATE) && afp_len < data_off + 4) { @@ -1400,6 +1417,8 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len, if (request_mask & AFP_FILE_BITMAP_MODIFY_DATE) data_off += 4; if ((request_mask & AFP_FILE_BITMAP_FINDER_INFO) && data_off & 1) data_off++; + if (request_mask & AFP_FILE_BITMAP_FINDER_INFO) + needs_afp_metadata_modify = 1; if ((request_mask & AFP_FILE_BITMAP_FINDER_INFO) && afp_len < data_off + NWATALK_FINDER_INFO_LEN) { XDPRINTF((2,0, "%s rejected: short FinderInfo data len=%d data_off=%d", @@ -1429,6 +1448,13 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len, return(-0x9c); } + if (needs_afp_metadata_modify) { + result = afp_check_metadata_modify_rights(path_volume, unixname, &stbuff, + call_name, afp_req + 9, path_len); + if (result < 0) + return(result); + } + data_off = 9 + path_len; if (data_off & 1) data_off++; if (request_mask & AFP_FILE_BITMAP_ATTRIBUTES) { diff --git a/tests/linux/README.md b/tests/linux/README.md index f377879..bca2975 100644 --- a/tests/linux/README.md +++ b/tests/linux/README.md @@ -87,6 +87,17 @@ collected separately. Use `--stop-on-failure` for strict bisect-style runs; by default the script keeps going so one failing endpoint does not hide later AFP output from the report. +AFP metadata writes and NetWare Modify rights: + +FinderInfo and AFP-only attribute metadata are stored in `org.mars-nwe.afp.*` +xattrs, but those writes are still file metadata changes. The Set File +Information handler now resolves the target through the normal mars_nwe path and +checks the existing NetWare Modify trustee policy before updating FinderInfo or +AFP-only Invisible/System metadata. Archive uses the existing NetWare attribute +path, and Modify timestamp uses `nw_utime_node()`, so the smoke suite should +continue to pass for SUPERVISOR while non-supervisor negative coverage can later +exercise the same policy gate. + A verified suite run after the FinderInfo payload-alignment fix completed with `failures=0` for `SYS:PUBLIC/pmdflts.ini`. The report covered Entry ID by path, Entry ID from NetWare handle, Get File Information, Scan File Information,