nwconn: require WebSDK AFP set file information layout
All checks were successful
Source release / source-package (push) Successful in 48s

This commit is contained in:
a
2026-05-30 20:39:57 +00:00
committed by Mario Fetka
parent dce62be6d5
commit e08ce594b5
3 changed files with 27 additions and 166 deletions

View File

@@ -1992,20 +1992,17 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len,
/*
* Conservative AFP Set File Information subset.
*
* Keep accepting the older mars_nwe smoke payload where the path immediately
* follows the request bitmap and only the selected data fields are appended
* after the path. In addition, accept the Novell/WebSDK fixed record layout
* used by real AFP clients: Attributes/Date/FinderInfo fields live at fixed
* offsets and the path is at offset 55 for 0x09 or 61 for 0x10 (including the
* AFP subfunction byte). All NetWare semantics still route through existing
* mars_nwe helpers; only genuine AFP metadata stays in nwatalk xattrs.
* Accept only the Novell/WebSDK fixed record layout used by real AFP clients:
* Attributes/Date/FinderInfo fields live at fixed offsets and the path is at
* offset 55 for 0x09 or 61 for 0x10 (including the AFP subfunction byte). All
* NetWare semantics still route through existing mars_nwe helpers; only genuine
* AFP metadata stays in nwatalk xattrs.
*/
{
uint8 volume_number;
uint32 request_entry_id;
uint16 request_mask;
int is_afp20;
int use_websdk_layout = 0;
int path_len;
int path_off;
int path_volume;
@@ -2023,7 +2020,6 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len,
uint8 *modify_data = NULL;
uint8 *backup_data = NULL;
uint8 *finder_data = NULL;
int data_off;
if (afp_len < 9) {
XDPRINTF((2,0, "%s rejected: short request len=%d",
@@ -2040,94 +2036,31 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len,
* WebSDK fixed layout, including afp_req[0] subfunction byte:
* 0x09: path_len @ 54, path @ 55
* 0x10: path_len @ 60, path @ 61, ProDOSInfo @ 54..59
* Prefer it only when the documented path-length slot is plausible; older
* mars_nwe tests keep using the compact path-at-8 form below.
*/
{
int websdk_path_len_off = is_afp20 ? 60 : 54;
int websdk_path_off = websdk_path_len_off + 1;
if (afp_len > websdk_path_len_off) {
int candidate_len = (int)afp_req[websdk_path_len_off];
if (candidate_len > 0 && afp_len >= websdk_path_off + candidate_len) {
use_websdk_layout = 1;
path_len = candidate_len;
path_off = websdk_path_off;
attribute_data = afp_req + 8;
create_data = afp_req + 10;
access_data = afp_req + 12;
modify_data = afp_req + 14;
backup_data = afp_req + 18;
finder_data = afp_req + 22;
}
}
}
if (!use_websdk_layout) {
path_len = (int)afp_req[8];
path_off = 9;
if (path_len < 0 || afp_len < path_off + path_len) {
XDPRINTF((2,0, "%s rejected: boundary check len=%d path_len=%d",
call_name, afp_len, path_len));
if (afp_len <= websdk_path_len_off) {
XDPRINTF((2,0, "%s rejected: short WebSDK request len=%d path_len_off=%d",
call_name, afp_len, websdk_path_len_off));
return(-0x7e);
}
data_off = path_off + path_len;
if (data_off & 1) data_off++;
if (request_mask & AFP_FILE_BITMAP_ATTRIBUTES) {
if (afp_len < data_off + 2) {
XDPRINTF((2,0, "%s rejected: short attribute data len=%d data_off=%d",
call_name, afp_len, data_off));
return(-0x7e);
}
attribute_data = afp_req + data_off;
data_off += 2;
}
if (request_mask & AFP_FILE_BITMAP_ACCESS_DATE) {
if (afp_len < data_off + 4) {
XDPRINTF((2,0, "%s rejected: short access timestamp data len=%d data_off=%d",
call_name, afp_len, data_off));
return(-0x7e);
}
access_data = afp_req + data_off;
data_off += 4;
}
if (request_mask & AFP_FILE_BITMAP_CREATE_DATE) {
if (afp_len < data_off + 4) {
XDPRINTF((2,0, "%s rejected: short create timestamp data len=%d data_off=%d",
call_name, afp_len, data_off));
return(-0x7e);
}
create_data = afp_req + data_off;
data_off += 4;
}
if (request_mask & AFP_FILE_BITMAP_MODIFY_DATE) {
if (afp_len < data_off + 4) {
XDPRINTF((2,0, "%s rejected: short modify timestamp data len=%d data_off=%d",
call_name, afp_len, data_off));
return(-0x7e);
}
modify_data = afp_req + data_off;
data_off += 4;
}
if (request_mask & AFP_FILE_BITMAP_BACKUP_DATE) {
if (afp_len < data_off + 4) {
XDPRINTF((2,0, "%s rejected: short backup timestamp data len=%d data_off=%d",
call_name, afp_len, data_off));
return(-0x7e);
}
backup_data = afp_req + data_off;
data_off += 4;
}
if ((request_mask & AFP_FILE_BITMAP_FINDER_INFO) && data_off & 1) data_off++;
if (request_mask & AFP_FILE_BITMAP_FINDER_INFO) {
if (afp_len < data_off + NWATALK_FINDER_INFO_LEN) {
XDPRINTF((2,0, "%s rejected: short FinderInfo data len=%d data_off=%d",
call_name, afp_len, data_off));
return(-0x7e);
}
finder_data = afp_req + data_off;
path_len = (int)afp_req[websdk_path_len_off];
path_off = websdk_path_off;
if (path_len < 0 || afp_len < path_off + path_len) {
XDPRINTF((2,0, "%s rejected: WebSDK boundary check len=%d path_len=%d path_off=%d",
call_name, afp_len, path_len, path_off));
return(-0x7e);
}
attribute_data = afp_req + 8;
create_data = afp_req + 10;
access_data = afp_req + 12;
modify_data = afp_req + 14;
backup_data = afp_req + 18;
finder_data = afp_req + 22;
}
path_data = afp_req + path_off;
@@ -2271,10 +2204,9 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len,
return(result);
}
XDPRINTF((3,0, "%s: vol=%d request_vol=%d entry=0x%08x mask=0x%04x path='%s' layout=%s%s%s%s%s%s attrs=0x%04x atime=%ld mtime=%ld",
XDPRINTF((3,0, "%s: vol=%d request_vol=%d entry=0x%08x mask=0x%04x path='%s' layout=websdk%s%s%s%s%s%s attrs=0x%04x atime=%ld mtime=%ld",
call_name, path_volume, (int)volume_number, request_entry_id,
request_mask, visable_data(path_data, path_len),
use_websdk_layout ? "websdk" : "compact",
(request_mask & AFP_FILE_BITMAP_ATTRIBUTES) ? " attributes" : "",
(request_mask & AFP_FILE_BITMAP_ACCESS_DATE) ? " access_time" : "",
(request_mask & AFP_FILE_BITMAP_CREATE_DATE) ? " create_time" : "",

View File

@@ -41,7 +41,7 @@
static void usage(const char *prog)
{
fprintf(stderr,
"Usage: %s [--afp09|--afp20] [--websdk-layout] [--expect-completion CODE] [--allow-invalid-namespace] [--allow-invalid-path] "
"Usage: %s [--afp09|--afp20] [--expect-completion CODE] [--allow-invalid-namespace] [--allow-invalid-path] "
"[--volume N] [--entry-id ID] [--type FOUR] [--creator FOUR] "
"[--hidden|--clear-hidden|--invisible|--clear-invisible|--system|--clear-system|--archive|--clear-archive] "
"[--access-time-epoch SECONDS] [--create-time-epoch SECONDS] [--mtime-epoch SECONDS] [--backup-time-epoch SECONDS] [--finder-info-only|--attributes-only|--access-time-only|--create-time-only|--timestamp-only|--backup-time-only] "
@@ -168,7 +168,6 @@ int main(int argc, char **argv)
int allow_invalid_namespace = 0;
int allow_invalid_path = 0;
int expect_completion = -1;
int websdk_layout = 0;
uint32_t volume_number = 0;
uint32_t entry_id = 0;
uint8_t finder_info[32];
@@ -188,7 +187,6 @@ int main(int argc, char **argv)
uint8_t verify_buf[AFP_REPLY_LEN];
uint8_t request[1 + 4 + 2 + 1 + 255 + 1 + 2 + 4 + 4 + 4 + 4 + 1 + 32];
size_t path_len;
size_t afp_data_off;
size_t data_off;
int i;
NWCCODE err;
@@ -218,8 +216,6 @@ int main(int argc, char **argv)
set_subfunction = AFP_SET_FILE_INFORMATION;
} else if (!strcmp(argv[i], "--afp20")) {
set_subfunction = AFP20_SET_FILE_INFORMATION;
} else if (!strcmp(argv[i], "--websdk-layout")) {
websdk_layout = 1;
} else if (!strcmp(argv[i], "--expect-completion")) {
uint32_t completion;
if (++i >= argc || parse_u32(argv[i], &completion) || completion > 255) {
@@ -392,12 +388,12 @@ int main(int argc, char **argv)
return 2;
}
if (websdk_layout) {
{
size_t path_len_off;
size_t path_off;
/*
* WebSDK/nwafp.h fixed SetInfo layout, in the payload passed to
* Novell/WebSDK nwafp.h fixed SetInfo layout, in the payload passed to
* NWRequestSimple() without the leading AFP subfunction byte:
* 0x09: path_len @ 53, path @ 54
* 0x10: ProDOSInfo @ 53..58, path_len @ 59, path @ 60
@@ -423,49 +419,6 @@ int main(int argc, char **argv)
request[path_len_off] = (uint8_t)path_len;
memcpy(request + path_off, path, path_len);
data_off = path_off + path_len;
} else {
request[7] = (uint8_t)path_len;
memcpy(request + 8, path, path_len);
/*
* The server-side AFP request buffer includes the NCP AFP subfunction byte
* at offset 0. This smoke helper passes only the subfunction payload to
* NWRequestSimple(), so every server offset after the leading function byte
* maps to request_offset - 1 here. Align once in AFP/server coordinates,
* then subtract one; do not align the payload offset again or FinderInfo-only
* requests with an even path length get a leading zero byte persisted.
*/
afp_data_off = 1 + 8 + path_len;
if (afp_data_off & 1)
afp_data_off++;
data_off = afp_data_off - 1;
if (request_mask & AFP_ATTRIBUTES_MASK) {
cpu_to_be16(attr_request, request + data_off);
data_off += 2;
}
if (request_mask & AFP_ACCESS_DATE_MASK) {
memcpy(request + data_off, access_time, sizeof(access_time));
data_off += sizeof(access_time);
}
if (request_mask & AFP_CREATE_DATE_MASK) {
memcpy(request + data_off, create_time, sizeof(create_time));
data_off += sizeof(create_time);
}
if (request_mask & AFP_MODIFY_DATE_MASK) {
memcpy(request + data_off, modify_time, sizeof(modify_time));
data_off += sizeof(modify_time);
}
if (request_mask & AFP_BACKUP_DATE_MASK) {
memcpy(request + data_off, backup_time, sizeof(backup_time));
data_off += sizeof(backup_time);
}
if ((request_mask & AFP_FINDER_INFO_MASK) &&
(request_mask & (AFP_ATTRIBUTES_MASK | AFP_ACCESS_DATE_MASK | AFP_CREATE_DATE_MASK | AFP_MODIFY_DATE_MASK | AFP_BACKUP_DATE_MASK)) &&
((data_off + 1) & 1))
data_off++;
if (request_mask & AFP_FINDER_INFO_MASK) {
memcpy(request + data_off, finder_info, sizeof(finder_info));
data_off += sizeof(finder_info);
}
}
err = NWRequestSimple(conn,
@@ -572,8 +525,8 @@ int main(int argc, char **argv)
return 1;
}
printf("AFP Set File Info subfunction=0x%02x layout=%s path=%s bitmap=0x%04x attrs=0x%04x create=0x%04x access=0x%04x modify=0x%04x%04x backup=0x%04x%04x finder_type=%.4s finder_creator=%.4s entry_id=0x%08x verified\n",
set_subfunction, websdk_layout ? "websdk" : "compact", path, request_mask, be16_to_cpu(verify_buf + 8),
printf("AFP Set File Info subfunction=0x%02x layout=websdk path=%s bitmap=0x%04x attrs=0x%04x create=0x%04x access=0x%04x modify=0x%04x%04x backup=0x%04x%04x finder_type=%.4s finder_creator=%.4s entry_id=0x%08x verified\n",
set_subfunction, path, request_mask, be16_to_cpu(verify_buf + 8),
be16_to_cpu(verify_buf + 20), be16_to_cpu(verify_buf + 22),
be16_to_cpu(verify_buf + 24), be16_to_cpu(verify_buf + 26),
be16_to_cpu(verify_buf + 28), be16_to_cpu(verify_buf + 30),

View File

@@ -601,30 +601,6 @@ run_cmd \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--afp09 --finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information FinderInfo WebSDK layout" \
"./afp_set_file_info_smoke $COMMON_PRINT --websdk-layout --finder-info-only --type '$FINDER_TYPE' --creator '$FINDER_CREATOR' '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--websdk-layout --finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information FinderInfo WebSDK legacy" \
"./afp_set_file_info_smoke $COMMON_PRINT --afp09 --websdk-layout --finder-info-only --type '$FINDER_TYPE' --creator '$FINDER_CREATOR' '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--afp09 --websdk-layout --finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Hidden WebSDK layout" \
"./afp_set_file_info_smoke $COMMON_PRINT --websdk-layout --attributes-only --hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--websdk-layout --attributes-only --hidden "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Clear Hidden WebSDK layout" \
"./afp_set_file_info_smoke $COMMON_PRINT --websdk-layout --attributes-only --clear-hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--websdk-layout --attributes-only --clear-hidden "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Hidden" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --hidden '$NETWARE_PATH'" \