Files
ncpfs/lib/ds/search.c
2026-04-28 20:56:03 +02:00

539 lines
14 KiB
C

/*
search.c - NWDSSearch implementation
Copyright (C) 1999, 2000 Petr Vandrovec
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Revision history:
1.00 2000, February 6 Petr Vandrovec <vandrove@vc.cvut.cz>
Initial release.
1.01 2000, February 7 Petr Vandrovec <vandrove@vc.cvut.cz>
NWDSExtSyncSearch added.
1.02 2000, August 25 Petr Vandrovec <vandrove@vc.cvut.cz>
Removed DS_RESOLVE_WALK_TREE from resolve calls.
1.03 2001, June 13 Petr Vandrovec <vandrove@vc.cvut.cz>
Fixed internal bug assertion when invalid DN passed
to NWDSSearch.
*/
#include "config.h"
#include <stddef.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "ncplib_i.h"
#include "nwnet_i.h"
static NWDSCCODE __NWDSSearchV3(
NWCONN_HANDLE conn,
nuint32 nameFormat,
nuint32* lowlevelIH,
NWObjectID objectID,
nuint32 scope,
nuint32 unk1,
nuint32 infoType,
nuint32 dsiFlags,
nuint32 allAttrs,
Buf_T* attr,
Buf_T* filter,
NWObjectCount* countObjectsSearched,
Buf_T* objectInfo) {
NWDSCCODE err;
NW_FRAGMENT rq_frag[3];
nuint8 rq_b[36];
static const nuint8 zero4[4] = { 0, 0, 0, 0};
NW_FRAGMENT rp_frag[2];
nuint8 rp_b[8];
DSET_LH(rq_b, 0, 3);
DSET_LH(rq_b, 4, nameFormat);
DSET_LH(rq_b, 8, *lowlevelIH);
DSET_HL(rq_b, 12, objectID);
DSET_LH(rq_b, 16, scope);
DSET_LH(rq_b, 20, unk1);
DSET_LH(rq_b, 24, infoType);
DSET_LH(rq_b, 28, dsiFlags);
DSET_LH(rq_b, 32, allAttrs);
rq_frag[0].fragAddr.ro = rq_b;
rq_frag[0].fragSize = 36;
if (!allAttrs && attr) {
size_t len;
rq_frag[1].fragAddr.ro = NWDSBufRetrieve(attr, &len);
rq_frag[1].fragSize = ROUNDPKT(len);
} else {
rq_frag[1].fragAddr.ro = zero4;
rq_frag[1].fragSize = 4;
}
rq_frag[2].fragAddr.ro = NWDSBufRetrieve(filter, &rq_frag[2].fragSize);
rp_frag[0].fragAddr.rw = rp_b;
rp_frag[0].fragSize = 8;
rp_frag[1].fragAddr.rw = NWDSBufPutPtrLen(objectInfo, &rp_frag[1].fragSize);
err = NWCFragmentRequest(conn, DSV_SEARCH, 3, rq_frag, 2, rp_frag, NULL);
if (!err) {
*lowlevelIH = DVAL_LH(rp_b, 0);
if (countObjectsSearched) {
*countObjectsSearched = DVAL_LH(rp_b, 4);
}
NWDSBufPutSkip(objectInfo, rp_frag[1].fragSize);
}
return err;
}
static NWDSCCODE __NWDSSearchV4(
NWCONN_HANDLE conn,
nuint32 nameFormat,
nuint32* lowlevelIH,
NWObjectID objectID,
nuint32 scope,
nuint32 unk1,
nuint32 infoType,
nuint32 dsiFlags,
const TimeStamp_T* timeStamp,
nuint32 allAttrs,
Buf_T* attr,
Buf_T* filter,
NWObjectCount* countObjectsSearched,
Buf_T* objectInfo) {
NWDSCCODE err;
nuint8 rq_b[44];
NW_FRAGMENT rq_frag[3];
static const nuint8 zero4[4] = {0, 0, 0, 0};
nuint8 rp_b[8];
NW_FRAGMENT rp_frag[2];
DSET_LH(rq_b, 0, 4);
DSET_LH(rq_b, 4, nameFormat);
DSET_LH(rq_b, 8, *lowlevelIH);
DSET_HL(rq_b, 12, objectID);
DSET_LH(rq_b, 16, scope);
DSET_LH(rq_b, 20, unk1);
DSET_LH(rq_b, 24, infoType);
DSET_LH(rq_b, 28, dsiFlags);
DSET_LH(rq_b, 32, timeStamp->wholeSeconds);
WSET_LH(rq_b, 36, timeStamp->replicaNum);
WSET_LH(rq_b, 38, timeStamp->eventID);
DSET_LH(rq_b, 40, allAttrs);
rq_frag[0].fragAddr.ro = rq_b;
rq_frag[0].fragSize = 44;
if (!allAttrs && attr) {
size_t len;
rq_frag[1].fragAddr.ro = NWDSBufRetrieve(attr, &len);
rq_frag[1].fragSize = ROUNDPKT(len);
} else {
rq_frag[1].fragAddr.ro = zero4;
rq_frag[1].fragSize = 4;
}
rq_frag[2].fragAddr.ro = NWDSBufRetrieve(filter, &rq_frag[2].fragSize);
rp_frag[0].fragAddr.rw = rp_b;
rp_frag[0].fragSize = 8;
rp_frag[1].fragAddr.rw = NWDSBufPutPtrLen(objectInfo, &rp_frag[1].fragSize);
err = NWCFragmentRequest(conn, DSV_SEARCH, 3, rq_frag, 2, rp_frag, NULL);
if (!err) {
*lowlevelIH = DVAL_LH(rp_b, 0);
if (countObjectsSearched) {
*countObjectsSearched = DVAL_LH(rp_b, 4);
}
NWDSBufPutSkip(objectInfo, rp_frag[1].fragSize);
}
return err;
}
struct search_referrals {
struct search_referrals* next;
nuint32 referrals;
unsigned char data[0];
};
struct SearchIH {
u_int16_t iteration;
nuint8* entrystart;
struct search_referrals* namePtr;
};
static void __NWDSAbortSearchHandle(struct wrappedIterationHandle* ih) {
struct SearchIH* searchIH;
searchIH = (struct SearchIH*)ih->data;
if (searchIH) {
struct search_referrals* ptr;
ptr = searchIH->namePtr;
while (ptr) {
struct search_referrals* tmp;
tmp = ptr;
ptr = ptr->next;
free(tmp);
}
free(searchIH);
ih->data = NULL;
}
}
static NWDSCCODE UpdateSearchHandle(struct wrappedIterationHandle** pSearchIH, Buf_T* buffer, NWCONN_HANDLE conn, NWObjectID objectID, nuint32 lowlevelIH) {
struct wrappedIterationHandle* searchIH;
nuint32 len;
nuint32 referrals;
void* data;
struct search_referrals** end;
struct search_referrals* namePtr;
NWDSCCODE err;
/* length */
err = NWDSBufGetLE32(buffer, &len);
if (err)
return err;
if (len < 4)
return ERR_INVALID_SERVER_RESPONSE;
err = NWDSBufGetLE32(buffer, &referrals);
if (err)
return err;
data = NWDSBufGetPtr(buffer, len - 4);
if (!data)
return ERR_BUFFER_EMPTY;
searchIH = *pSearchIH;
if (!searchIH) {
struct SearchIH* sih;
sih = malloc(sizeof(*sih));
if (!sih)
return ERR_NOT_ENOUGH_MEMORY;
searchIH = __NWDSIHInit(conn, lowlevelIH, DSV_SEARCH);
if (!searchIH) {
free(sih);
return ERR_NOT_ENOUGH_MEMORY;
}
searchIH->abort = __NWDSAbortSearchHandle;
searchIH->objectID = objectID;
sih->namePtr = NULL;
sih->entrystart = NULL;
sih->iteration = 0;
searchIH->data = sih;
}
if (referrals) {
struct SearchIH* sih;
sih = searchIH->data;
end = &sih->namePtr;
while ((namePtr = *end) != NULL)
end = &namePtr->next;
namePtr = malloc(sizeof(*namePtr) + len);
if (!namePtr) {
__NWDSIHAbort(searchIH);
return ERR_NOT_ENOUGH_MEMORY;
}
*end = namePtr;
namePtr->next = NULL;
namePtr->referrals = referrals;
memcpy(namePtr->data, data, len - 4);
}
*pSearchIH = searchIH;
return 0;
}
static inline void NextNamePtr(struct SearchIH* searchIH) {
struct search_referrals* currName;
currName = searchIH->namePtr;
if (--currName->referrals) {
/* skip entry: 32bit info + name */
searchIH->entrystart += 4;
searchIH->entrystart += ROUNDPKT(4 + DVAL_LH(searchIH->entrystart, 0));
} else {
struct search_referrals* nextName;
nextName = currName->next;
searchIH->namePtr = nextName;
searchIH->entrystart = NULL;
free(currName);
}
}
static NWDSCCODE GetCurrentName(struct SearchIH* searchIH, u_int32_t* objInfo, unicode** objName, size_t* objNameLen) {
nuint8* curPos;
curPos = searchIH->entrystart;
if (!curPos) {
struct search_referrals* namePtr;
namePtr = searchIH->namePtr;
if (!namePtr)
return ERR_BUFFER_EMPTY;
curPos = namePtr->data;
searchIH->entrystart = curPos;
}
*objInfo = DVAL_LH(curPos, 0);
/* FIXME: Check buffer overflow */
*objNameLen = DVAL_LH(curPos, 4);
*objName = (unicode*)(curPos + 8);
NextNamePtr(searchIH);
return 0;
}
static NWDSCCODE __SearchProtocol(
NWDSContextHandle ctx,
NWCONN_HANDLE conn,
NWObjectID objectID,
nint scope,
Buf_T* filter,
const TimeStamp_T* timeStamp,
nuint infoType,
nuint allAttrs,
Buf_T* attrNames,
nuint32* lowlevelIH,
UNUSED( NWObjectCount countObjectsToSearch),
NWObjectCount* countObjectsSearched,
Buf_T* objectInfo,
nuint32 nameFormat) {
nuint32 dsiFlags;
nuint32 dckFlags;
NWDSCCODE err;
if (!filter)
return ERR_NULL_POINTER;
err = NWDSGetContext(ctx, DCK_FLAGS, &dckFlags);
if (err)
return err;
dsiFlags = ctx->dck.dsi_flags;
if (dckFlags & DCV_DEREF_BASE_CLASS)
dsiFlags |= DSI_DEREFERENCE_BASE_CLASS;
NWDSBufStartPut(objectInfo, DSV_SEARCH);
NWDSBufSetDSIFlags(objectInfo, dsiFlags);
if (allAttrs)
attrNames = NULL;
if (timeStamp) {
err = __NWDSSearchV4(conn, nameFormat, lowlevelIH, objectID, scope, 0, infoType,
dsiFlags, timeStamp, allAttrs, attrNames, filter,
countObjectsSearched, objectInfo);
} else {
err = __NWDSSearchV3(conn, nameFormat, lowlevelIH, objectID, scope, 0, infoType,
dsiFlags, allAttrs, attrNames, filter,
countObjectsSearched, objectInfo);
}
NWDSBufFinishPut(objectInfo);
/* Now we skip infoType value returned by server. Maybe we should check it for being
equal with passed infoType? */
NWDSBufGetSkip(objectInfo, 4);
return err;
}
static NWDSCCODE UpdateServerInSearchHandle(struct wrappedIterationHandle* searchIH, NWCONN_HANDLE conn, NWObjectID objectID) {
searchIH->objectID = objectID;
__NWDSIHSetConn(searchIH, conn);
return 0;
}
NWDSCCODE NWDSExtSyncSearch(
NWDSContextHandle ctx,
const NWDSChar* baseObjectName,
nint scope,
nuint searchAliases,
Buf_T* filter,
const TimeStamp_T* timeStamp,
nuint infoType,
nuint allAttrs,
Buf_T* attrNames,
nuint32* iterHandle,
NWObjectCount countObjectsToSearch,
NWObjectCount* countObjectsSearched,
Buf_T* objectInfo) {
NWCONN_HANDLE conn;
NWObjectID objectID;
nuint32 dckFlags;
nuint32 nameForm;
struct wrappedIterationHandle* currIH;
NWDSCCODE err;
wchar_t* revobjname = NULL;
size_t revobjnamelen = 0;
nuint32 lowlevelIH;
nuint32 le32;
void* bufptr;
err = NWDSGetContext(ctx, DCK_FLAGS, &dckFlags);
if (err)
return err;
nameForm = ctx->dck.name_form;
if (dckFlags & DCV_TYPELESS_NAMES)
nameForm |= 0x00000001;
if (searchAliases)
nameForm |= 0x00010000;
if (*iterHandle == NO_MORE_ITERATIONS) {
currIH = NULL;
err = NWDSResolveName2(ctx, baseObjectName, DS_RESOLVE_READABLE,
&conn, &objectID);
if (err)
goto abandon_nc;
lowlevelIH = NO_MORE_ITERATIONS;
} else {
struct SearchIH* sih;
currIH = __NWDSIHLookup(*iterHandle, DSV_SEARCH);
if (!currIH)
return ERR_INVALID_HANDLE;
sih = currIH->data;
if (currIH->conn) {
conn = currIH->conn;
ncp_conn_use(conn);
objectID = currIH->objectID;
lowlevelIH = currIH->iterHandle;
} else {
sih->iteration++;
while (1) {
unicode* objName;
size_t objNameLen;
nuint32 isReal;
err = GetCurrentName(sih, &isReal, &objName, &objNameLen);
if (err) {
err = 0;
goto abandon_nc;
}
if (searchAliases && !isReal) {
wchar_t wname[MAX_DN_CHARS+1];
err = NWDSPtrDN(objName, objNameLen, wname, sizeof(wname));
if (err)
goto abandon_nc;
wcsrev(wname);
if (!revobjname) {
revobjname = malloc(MAX_DN_BYTES);
if (!revobjname) {
err = ERR_NOT_ENOUGH_MEMORY;
goto abandon_nc;
}
/* we should return empty string for [root] */
err = NWDSGetCanonicalizedName(ctx, baseObjectName, revobjname);
if (err) {
goto abandon_nc;
}
wcsrev(revobjname);
revobjnamelen = wcslen(revobjname);
/* append dot at the end... */
revobjname[revobjnamelen++] = '.';
}
if (!wcsncasecmp(revobjname, wname, revobjnamelen))
continue;
}
err = __NWDSResolveName2u(ctx, objName, DS_RESOLVE_READABLE,
&conn, &objectID);
if (err)
continue;
lowlevelIH = NO_MORE_ITERATIONS;
err = UpdateServerInSearchHandle(currIH, conn, objectID);
if (err)
goto abandon;
break;
}
}
/* check for DS_SEARCH_PARTITION? */
if ((scope == DS_SEARCH_SUBORDINATES) && (sih->iteration))
scope = DS_SEARCH_ENTRY;
}
err = __SearchProtocol(ctx, conn, objectID, scope, filter, timeStamp, infoType, allAttrs, attrNames, &lowlevelIH,
countObjectsToSearch, countObjectsSearched, objectInfo, nameForm);
if (err)
goto abandon;
bufptr = NWDSBufTell(objectInfo);
err = NWDSBufSkipBuffer(objectInfo);
if (err)
goto abandon;
/* retrieve external references count */
err = NWDSBufPeekLE32(objectInfo, 4, &le32);
if (err)
goto abandon;
if (le32 || (lowlevelIH != NO_MORE_ITERATIONS)) {
err = UpdateSearchHandle(&currIH, objectInfo, conn, objectID, lowlevelIH);
if (err)
goto abandon;
}
/* Return back to objects buffer */
NWDSBufSeek(objectInfo, bufptr);
/* Retrieve objects buffer length */
err = NWDSBufGetLE32(objectInfo, &le32);
if (err)
goto abandon;
/* And modify object end so that we cannot overrun */
objectInfo->dataend = objectInfo->curPos + le32;
if (!currIH) {
*iterHandle = NO_MORE_ITERATIONS;
} else if (lowlevelIH == NO_MORE_ITERATIONS) {
struct SearchIH* sih = currIH->data;
if (!sih->namePtr) {
*iterHandle = NO_MORE_ITERATIONS;
__NWDSIHAbort(currIH);
} else {
__NWDSIHSetConn(currIH, NULL);
__NWDSIHPut(currIH, iterHandle);
}
} else {
currIH->iterHandle = lowlevelIH;
__NWDSIHPut(currIH, iterHandle);
}
NWCCCloseConn(conn);
goto quit;
abandon:;
NWCCCloseConn(conn);
abandon_nc:;
if (currIH) {
__NWDSIHUpdate(currIH, err, lowlevelIH, iterHandle);
} else {
*iterHandle = NO_MORE_ITERATIONS;
}
/* Rewind buffer */
NWDSBufSeek(objectInfo, objectInfo->data);
/* and put zero objects in */
NWDSBufPutLE32(objectInfo, 0);
NWDSBufFinishPut(objectInfo);
quit:;
if (revobjname)
free(revobjname);
return err;
}
NWDSCCODE NWDSSearch(
NWDSContextHandle ctx,
const NWDSChar* baseObjectName,
nint scope,
nuint searchAliases,
Buf_T* filter,
nuint infoType,
nuint allAttrs,
Buf_T* attrNames,
nuint32* iterHandle,
NWObjectCount countObjectsToSearch,
NWObjectCount* countObjectsSearched,
Buf_T* objectInfo) {
return NWDSExtSyncSearch(ctx, baseObjectName, scope, searchAliases,
filter, NULL, infoType, allAttrs, attrNames,
iterHandle, countObjectsToSearch,
countObjectsSearched, objectInfo);
}