tests: resolve AFP smoke volume paths
All checks were successful
Source release / source-package (push) Successful in 47s
All checks were successful
Source release / source-package (push) Successful in 47s
Teach the Linux AFP Entry ID smoke test to treat VOL:PATH arguments like normal NetWare paths instead of sending the full string as the AFP path component. The WebSDK documents AFP Get Entry ID From Path Name as taking a NetWare directory handle plus a path string. A user-supplied path such as SYS:PUBLIC therefore needs a directory handle for the SYS volume root and a relative AFP path of PUBLIC; sending SYS:PUBLIC as the AFP path with directory handle zero makes the server reject the request with Invalid Path before the actual AFP lookup is useful. Use the existing ncpfs/libncp request path to allocate a temporary directory handle for the volume root when the test receives a VOL:PATH argument and no explicit --dir-handle was supplied. Keep --raw-path for callers that want to send the path exactly as typed, and add --allow-invalid-path so negative path-resolution tests can distinguish Invalid Path from Invalid Namespace. Also add failure diagnostics to the server-side AFP path lookup so unsupported-backend, boundary-check, path-resolution, and stat failures are visible in the mars_nwe log. This changes only the Linux smoke test and debug logging; it does not change successful AFP protocol semantics.
This commit is contained in:
31
src/nwconn.c
31
src/nwconn.c
@@ -32,6 +32,7 @@
|
||||
# define LOC_RW_BUFFERSIZE 512
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
#if !CALL_NWCONN_OVER_SOCKET
|
||||
@@ -486,19 +487,39 @@ static int afp_get_entry_id_from_path_name(uint8 *afp_req, int afp_len,
|
||||
uint32 entry_id = 0;
|
||||
int result;
|
||||
|
||||
if (afp_len < 3) return(-0x7e); /* NCP Boundary Check Failed */
|
||||
if (afp_len < 3) {
|
||||
XDPRINTF((2,0, "AFP Get Entry ID From Path Name rejected: short request len=%d",
|
||||
afp_len));
|
||||
return(-0x7e); /* NCP Boundary Check Failed */
|
||||
}
|
||||
|
||||
dir_handle = afp_req[1];
|
||||
path_len = (int)afp_req[2];
|
||||
if (path_len < 0 || afp_len < 3 + path_len) return(-0x7e);
|
||||
if (path_len < 0 || afp_len < 3 + path_len) {
|
||||
XDPRINTF((2,0, "AFP Get Entry ID From Path Name rejected: boundary check len=%d path_len=%d",
|
||||
afp_len, path_len));
|
||||
return(-0x7e);
|
||||
}
|
||||
|
||||
if (!nwatalk_backend_available()) return(-0xbf); /* invalid namespace */
|
||||
if (!nwatalk_backend_available()) {
|
||||
XDPRINTF((3,0, "AFP Get Entry ID From Path Name rejected: libatalk backend unavailable"));
|
||||
return(-0xbf); /* invalid namespace */
|
||||
}
|
||||
|
||||
volume = conn_get_kpl_unxname(unixname, sizeof(unixname),
|
||||
(int)dir_handle, afp_req + 3, path_len);
|
||||
if (volume < 0) return(volume);
|
||||
if (volume < 0) {
|
||||
XDPRINTF((2,0, "AFP Get Entry ID From Path Name path resolve failed: dh=%d path='%s' result=-0x%x",
|
||||
(int)dir_handle, visable_data(afp_req + 3, path_len), -volume));
|
||||
return(volume);
|
||||
}
|
||||
|
||||
if (stat(unixname, &stbuff)) return(-0x9c); /* Invalid Path */
|
||||
if (stat(unixname, &stbuff)) {
|
||||
XDPRINTF((2,0, "AFP Get Entry ID From Path Name stat failed: dh=%d path='%s' unix='%s' errno=%d",
|
||||
(int)dir_handle, visable_data(afp_req + 3, path_len),
|
||||
unixname, errno));
|
||||
return(-0x9c); /* Invalid Path */
|
||||
}
|
||||
|
||||
result = nwatalk_get_entry_id(unixname, &entry_id);
|
||||
if (result < 0 || !entry_id)
|
||||
|
||||
@@ -24,20 +24,23 @@
|
||||
|
||||
#define AFP_GET_ENTRY_ID_FROM_PATH_NAME 0x0c
|
||||
#define NWE_INVALID_NAMESPACE 0xbf
|
||||
#define NWE_INVALID_PATH 0x9c
|
||||
#define AFP_TEMP_DH_NONE 0xff
|
||||
|
||||
static void usage(const char *prog)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [--allow-invalid-namespace] [--dir-handle N] "
|
||||
"[ncpfs options] PATH\n"
|
||||
"Usage: %s [--allow-invalid-namespace] [--allow-invalid-path] "
|
||||
"[--dir-handle N] [--raw-path] [ncpfs options] PATH\n"
|
||||
"\n"
|
||||
"ncpfs options are parsed by ncp_initialize(), for example:\n"
|
||||
" -S SERVER -U USER -P PASSWORD -n\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
" %s -S MARS -U SUPERVISOR -P secret SYS:LOGIN\n"
|
||||
" %s --allow-invalid-namespace -S MARS SYS:LOGIN\n",
|
||||
prog, prog, prog);
|
||||
" %s --allow-invalid-namespace -S MARS SYS:LOGIN\n"
|
||||
" %s --allow-invalid-path -S MARS SYS:NO_SUCH_PATH\n",
|
||||
prog, prog, prog, prog);
|
||||
}
|
||||
|
||||
static int parse_u8(const char *text, unsigned int *value)
|
||||
@@ -58,7 +61,75 @@ static uint32_t be32_to_cpu(const uint8_t p[4])
|
||||
return ((uint32_t)p[0] << 24) |
|
||||
((uint32_t)p[1] << 16) |
|
||||
((uint32_t)p[2] << 8) |
|
||||
((uint32_t)p[3]);
|
||||
p[3];
|
||||
}
|
||||
|
||||
static int split_volume_path(const char *path, char *volume, size_t volume_size,
|
||||
const char **relpath)
|
||||
{
|
||||
const char *colon = strchr(path, ':');
|
||||
size_t len;
|
||||
|
||||
if (!colon)
|
||||
return -1;
|
||||
|
||||
len = (size_t)(colon - path);
|
||||
if (!len || len >= volume_size)
|
||||
return -1;
|
||||
|
||||
memcpy(volume, path, len);
|
||||
volume[len] = '\0';
|
||||
|
||||
*relpath = colon + 1;
|
||||
while (**relpath == '/' || **relpath == '\\')
|
||||
(*relpath)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static NWCCODE allocate_temp_dir_handle(NWCONN_HANDLE conn, const char *volume,
|
||||
unsigned int *dir_handle)
|
||||
{
|
||||
uint8_t rq[1 + 1 + 1 + 32];
|
||||
uint8_t rpbuf[2];
|
||||
NW_FRAGMENT rp;
|
||||
size_t volume_len = strlen(volume);
|
||||
NWCCODE err;
|
||||
|
||||
if (volume_len + 1 > 32)
|
||||
return NWE_INVALID_PATH;
|
||||
|
||||
rq[0] = 0; /* source directory handle */
|
||||
rq[1] = 0; /* drive letter, unused by the test */
|
||||
rq[2] = (uint8_t)(volume_len + 1);
|
||||
memcpy(rq + 3, volume, volume_len);
|
||||
rq[3 + volume_len] = ':';
|
||||
|
||||
memset(rpbuf, 0, sizeof(rpbuf));
|
||||
rp.fragAddr.rw = rpbuf;
|
||||
rp.fragSize = sizeof(rpbuf);
|
||||
|
||||
err = NWRequestSimple(conn, NCPC_SFN(0x16, 0x13), rq,
|
||||
3 + volume_len + 1, &rp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (rp.fragSize < 1)
|
||||
return NWE_INVALID_NCP_PACKET_LENGTH;
|
||||
|
||||
*dir_handle = rpbuf[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void deallocate_dir_handle(NWCONN_HANDLE conn, unsigned int dir_handle)
|
||||
{
|
||||
uint8_t rq[1];
|
||||
|
||||
if (dir_handle == AFP_TEMP_DH_NONE)
|
||||
return;
|
||||
|
||||
rq[0] = (uint8_t)dir_handle;
|
||||
(void)NWRequestSimple(conn, NCPC_SFN(0x16, 0x14), rq, sizeof(rq), NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -67,10 +138,15 @@ int main(int argc, char **argv)
|
||||
NW_FRAGMENT reply;
|
||||
long init_err = 0;
|
||||
const char *path = NULL;
|
||||
const char *request_path = NULL;
|
||||
unsigned int dir_handle = 0;
|
||||
unsigned int allocated_dir_handle = AFP_TEMP_DH_NONE;
|
||||
int allow_invalid_namespace = 0;
|
||||
int allow_invalid_path = 0;
|
||||
int raw_path = 0;
|
||||
int i;
|
||||
size_t path_len;
|
||||
char volume[32];
|
||||
uint8_t request[1 + 1 + 255];
|
||||
uint8_t reply_buf[4];
|
||||
NWCCODE err;
|
||||
@@ -90,6 +166,10 @@ int main(int argc, char **argv)
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--allow-invalid-namespace")) {
|
||||
allow_invalid_namespace = 1;
|
||||
} else if (!strcmp(argv[i], "--allow-invalid-path")) {
|
||||
allow_invalid_path = 1;
|
||||
} else if (!strcmp(argv[i], "--raw-path")) {
|
||||
raw_path = 1;
|
||||
} else if (!strcmp(argv[i], "--dir-handle")) {
|
||||
if (++i >= argc || parse_u8(argv[i], &dir_handle)) {
|
||||
fprintf(stderr, "invalid --dir-handle value\n");
|
||||
@@ -117,17 +197,32 @@ int main(int argc, char **argv)
|
||||
return 2;
|
||||
}
|
||||
|
||||
path_len = strlen(path);
|
||||
request_path = path;
|
||||
if (!raw_path && dir_handle == 0 &&
|
||||
split_volume_path(path, volume, sizeof(volume), &request_path) == 0) {
|
||||
err = allocate_temp_dir_handle(conn, volume, &dir_handle);
|
||||
if (err) {
|
||||
fprintf(stderr,
|
||||
"Allocate Temp Dir Handle failed: completion=0x%02x (%u) volume=%s path=%s\n",
|
||||
(unsigned int)err & 0xff, (unsigned int)err, volume, path);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
allocated_dir_handle = dir_handle;
|
||||
}
|
||||
|
||||
path_len = strlen(request_path);
|
||||
if (path_len > 255) {
|
||||
fprintf(stderr, "PATH is too long for AFP Get Entry ID From Path Name: %zu\n",
|
||||
path_len);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 2;
|
||||
}
|
||||
|
||||
request[0] = (uint8_t)dir_handle;
|
||||
request[1] = (uint8_t)path_len;
|
||||
memcpy(request + 2, path, path_len);
|
||||
memcpy(request + 2, request_path, path_len);
|
||||
|
||||
memset(reply_buf, 0, sizeof(reply_buf));
|
||||
reply.fragAddr.rw = reply_buf;
|
||||
@@ -139,32 +234,47 @@ int main(int argc, char **argv)
|
||||
2 + path_len,
|
||||
&reply);
|
||||
|
||||
if (err == NWE_INVALID_NAMESPACE && allow_invalid_namespace) {
|
||||
if (((unsigned int)err & 0xff) == NWE_INVALID_NAMESPACE && allow_invalid_namespace) {
|
||||
printf("AFP Get Entry ID From Path Name returned invalid namespace "
|
||||
"as expected: path=%s\n", path);
|
||||
"as expected: path=%s request_path=%s dir_handle=%u\n",
|
||||
path, request_path, dir_handle);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (((unsigned int)err & 0xff) == NWE_INVALID_PATH && allow_invalid_path) {
|
||||
printf("AFP Get Entry ID From Path Name returned invalid path "
|
||||
"as expected: path=%s request_path=%s dir_handle=%u\n",
|
||||
path, request_path, dir_handle);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
fprintf(stderr,
|
||||
"AFP Get Entry ID From Path Name failed: completion=0x%02x (%u) path=%s\n",
|
||||
(unsigned int)err & 0xff, (unsigned int)err, path);
|
||||
"AFP Get Entry ID From Path Name failed: completion=0x%02x (%u) path=%s request_path=%s dir_handle=%u\n",
|
||||
(unsigned int)err & 0xff, (unsigned int)err, path,
|
||||
request_path, dir_handle);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (reply.fragSize < 4) {
|
||||
fprintf(stderr, "short AFP reply: %zu bytes\n", reply.fragSize);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("AFP Entry ID path=%s dir_handle=%u entry_id=0x%08x (%u)\n",
|
||||
path, dir_handle,
|
||||
printf("AFP Entry ID path=%s request_path=%s dir_handle=%u entry_id=0x%08x (%u)\n",
|
||||
path, request_path, dir_handle,
|
||||
(unsigned int)be32_to_cpu(reply_buf),
|
||||
(unsigned int)be32_to_cpu(reply_buf));
|
||||
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user