nwbind: implement NCP 17/4c list object relations
All checks were successful
Source release / source-package (push) Successful in 44s

Implement the Bindery "List Relations of an Object" endpoint.

Parse the NCP 17 subfunction 0x4c request, look up the requested bindery
object and set property, and return up to 32 related object IDs from the set
property value segments. Support the Novell last-seen cursor convention where
0xffffffff starts a new scan and subsequent calls continue after the last
returned object ID.

Add a small nwdbm helper for listing set-property members while preserving the
existing bindery property read-right checks. Reject wildcard object names with
the documented illegal-wildcard completion code.
This commit is contained in:
Mario Fetka
2026-05-29 15:49:54 +02:00
parent 98630eede8
commit 9f4f8fcbfe
3 changed files with 135 additions and 2 deletions

View File

@@ -206,6 +206,11 @@ extern int nw_delete_obj_from_set(int object_type,
int member_type,
uint8 *member_name, int member_namlen);
extern int nw_list_obj_relations(int object_type,
uint8 *object_name, int object_namlen,
uint8 *prop_name, int prop_namlen,
uint32 last_seen,
uint32 *relations, int max_relations);
extern int nw_write_prop_value(int object_type,

View File

@@ -1466,8 +1466,33 @@ static void handle_fxx(int gelen, int func)
break;
case 0x4c : { /* List Relations of an Object */
XDPRINTF((1, 0, "TODO:List Relations of an Object"));
completition=0xfb;
struct XDATA {
uint8 count[2];
uint8 relations[32*4];
} *xdata = (struct XDATA*) responsedata;
uint8 *p = rdata;
uint32 last_seen = GET_BE32(p);
int object_type = GET_BE16(p+4);
int object_namlen = (int)*(p+6);
uint8 *object_name = p+7;
int prop_namlen = (int)*(p+7+object_namlen);
uint8 *prop_name = p+8+object_namlen;
uint32 relations[32];
int result = nw_list_obj_relations(object_type,
object_name, object_namlen,
prop_name, prop_namlen,
last_seen, relations, 32);
if (result > -1) {
int k;
uint8 *rp = xdata->relations;
U16_TO_BE16((uint16)result, xdata->count);
for (k=0; k < result; k++) {
U32_TO_BE32(relations[k], rp);
rp += 4;
}
data_len = 2 + (result * 4);
XDPRINTF((2, 0, "List Relations of an Object count=%d", result));
} else completition = (uint8)-result;
} break;
case 0x64 : { /* Create Queue, prehandled by nwconn */

View File

@@ -999,6 +999,109 @@ int nw_delete_obj_from_set(int object_type,
}
static void copy_bindery_packet_name(uint8 *dst, int dst_size,
uint8 *src, int src_len)
{
int len = min(src_len, dst_size - 1);
if (len > 0) memcpy(dst, src, len);
dst[len] = '\0';
}
static int bindery_packet_name_has_wildcards(uint8 *name, int namlen)
{
while (namlen-- > 0) {
if (*name == '*' || *name == '?') return(1);
++name;
}
return(0);
}
static int prop_list_members(uint32 obj_id, int prop_id, int prop_security,
uint32 last_seen,
uint32 *relations, int max_relations)
{
NETVAL val;
int result;
int count = 0;
int collect = (last_seen == (uint32)0xffffffff);
if (0 != (result=b_acc(obj_id, prop_security, 0x10))) return(result);
if (!dbminit(FNVAL)){
key.dsize = NETVAL_KEY_SIZE;
key.dptr = (char*)&val;
val.obj_id = obj_id;
val.prop_id = (uint8)prop_id;
val.segment = (uint8)0;
while (val.segment++ < (uint8)255 && count < max_relations) {
data = fetch(key);
if (data.dptr != NULL){
NETVAL *v = (NETVAL*)data.dptr;
uint8 *p = v->value;
int k = 0;
while (k++ < 32 && count < max_relations) {
uint32 id = GET_BE32(p);
if (id != 0) {
if (collect) {
relations[count++] = id;
} else if (id == last_seen) {
collect = 1;
}
}
p += 4;
}
}
}
result = count;
} else result = -0xff;
dbmclose();
return(result);
}
int nw_list_obj_relations(int object_type,
uint8 *object_name, int object_namlen,
uint8 *prop_name, int prop_namlen,
uint32 last_seen,
uint32 *relations, int max_relations)
{
NETOBJ obj;
NETPROP prop;
int result=-0xff;
memset(&obj, 0, sizeof(obj));
memset(&prop, 0, sizeof(prop));
if (bindery_packet_name_has_wildcards(object_name, object_namlen))
return(-0xf0);
copy_bindery_packet_name(obj.name, sizeof(obj.name),
object_name, object_namlen);
copy_bindery_packet_name(prop.name, sizeof(prop.name),
prop_name, prop_namlen);
obj.type = (uint16)object_type;
XDPRINTF((2,0, "nw_list_obj_relations obj=%s,0x%x, prop=%s, last=0x%x",
obj.name, object_type, prop.name, last_seen));
if ((result = find_obj_id(&obj)) == 0) {
result = find_first_prop_id(&prop, obj.id);
if (!result) {
if (!(prop.flags & P_FL_SET))
result = -0xfb;
else
result = prop_list_members(obj.id, (int)prop.id, prop.security,
last_seen, relations, max_relations);
}
}
return(result);
}
int nw_write_prop_value(int object_type,
uint8 *object_name, int object_namlen,
int segment_nr, int erase_segments,