📄 dbfunct.c
字号:
*/
BOOL getNextExpired(UINT8* channelId)
{
if (nextExpChNbrListInd >= expChNbrListSize)
return FALSE;
*channelId = expChNbrList[nextExpChNbrListInd];
nextExpChNbrListInd++;
return TRUE;
}
/*
* Add a host to the specified channel. The string pointed out
* by 'host' is copied and not taken over by the database.
*
* The string pointed out by 'host' must include a host name which
* may be followed by a path name. The first '/' delimits the host from
* the path. The host name may be the empty string.
*
* An object or a data channel is created if either is missing.
*
* 'length' is the length of host including any path but excluding an
* optional terminating EOL.
*/
void addHost(UINT8 object, UINT8 channel, const BYTE* host, UINT16 length)
{
ChannelListPtr channelStruct;
DataUnion newHost;
UINT8 error;
if (host == NULL)
return;
if (length && (host[length-1] == '\0')) /* Null terminated, even */
if (--length == 0) /* though it shouldn't be */
return;
channelStruct = getObjectOrChannel_add(object, channel, TRUE).channelStruct;
if (channelStruct == NULL)
return;
newHost.s = dupSubStr(host, host + length);
#ifndef HAS_SETJMP
if (newHost.s == NULL)
return;
#endif
/* Create new element */
db_createNewElement(channelStruct->hostPtr, NULL, DB_flag_str | DB_flag_dataExternal,
newHost, NULL, NULL, &error);
/* Insert new flags, when introduced in wipdb.c */
/* BOOKMARK:FLAGS */
}
/*
* Remove a host, if found, from the named channel.
*
* The string pointed out by 'host' must include a host name which
* may be followed by a path name. The first '/' delimits the host from
* the path. The host name may be the empty string.
*
* 'length' is the length of host including any path but excluding an
* optional terminating EOL.
*
* Calling deleteHost, the 'host'
* string must match the host and any path to be deleted.
* When matching, the host part is compared case insensitively while any path
* part is compared case sensitively.
*/
void deleteHost(UINT8 object, UINT8 channel, const BYTE* host, UINT16 length)
{
ChannelListPtr channelStruct;
ElementPtr element;
ElementPtr prev;
ElementPtr hostPtr;
BYTE* s;
const BYTE* t;
UINT16 i;
BOOL caseSens;
if (host == NULL || length == 0)
return;
if (host[length-1] == '\0')
if (--length == 0)
return;
channelStruct = getChannel(object, channel);
if (channelStruct == NULL)
return;
hostPtr = (ElementPtr) channelStruct->hostPtr;
/* Search through all channels, until a match is found */
for (element = hostPtr->data.e, prev = NULL;
element != (ElementPtr) hostPtr;
prev = element, element = element->next) {
caseSens = FALSE;
s = element->data.s;
for (t=host, i=length; ; s++, t++) {
if (!caseSens && (*s == '/'))
caseSens = TRUE;
if (caseSens && (*s != *t))
goto Next_loop;
if (!caseSens && (latin1_lc[*s] != latin1_lc[*t]))
goto Next_loop;
if (--i == 0)
if (!*(s+1))
break;
else
goto Next_loop;
}
/* Delete element */
if (prev == NULL)
hostPtr->data.p = element->next;
else {
prev->next = element->next;
if (prev->next == hostPtr)
prev->flags |= DB_flag_lastElement;
}
OSConnectorFree(element->data.s);
OSConnectorFree(element);
return;
Next_loop:;
}
}
/* ======== admin ======== */
/*
* Initiate structures connected to data channel handling.
*/
void dataChannelInit(void)
{
ChannelListPtr channelList;
ObjectListPtr objectRecord;
BYTE* temp;
UINT8 error;
objectList = (ObjectListPtr) OSConnectorAlloc(sizeof(ObjectList));
#ifndef HAS_SETJMP
if (objectList == NULL)
return;
#endif
objectListSize = 1;
globalRef = db_createRecord(DB_root, (BYTE*) "globl", DB_rec, &error);
obj00Ref = db_createRecord(globalRef, (BYTE*) "obj00", DB_rec, &error);
channelList = (ChannelListPtr) OSConnectorAlloc(sizeof(ChannelList));
objectRecord = &objectList[0];
objectRecord->objectRef = obj00Ref;
objectRecord->channelListSize = 0;
objectRecord->objectNbr = 0;
objectRecord->defaultChannel = -1;
objectRecord->channelList = channelList;
/* Fields added to the global object */
db_setInt(globalRef, (BYTE*) CACHE_AGE, 86400); /* Cache age */
db_setInt(globalRef, (BYTE*) CACHE_MODE, 1); /* Cache mode */
db_setInt(globalRef, (BYTE*) COOKIES_ENABLED, 1);/* Using cookies */
if (db_setStr(globalRef, (BYTE*) USER_AGENT, temp = B_STRDUP((BYTE*) "WAPPER")))
OSConnectorFree(temp); /* User agent */
/* Fields added to the object template */
db_setInt(obj00Ref, (BYTE*) HISTORY_SIZE, 10); /* History size */
db_setInt(obj00Ref, (BYTE*) DISPLAY_IMAGES, 1); /* Display images */
db_setInt(obj00Ref, (BYTE*) UPDATE_IMAGES, 0); /* Update images */
}
/*
* Remove all structures associated with objects and data
* channels. To be called when closing down the database.
*/
void dataChannelTerminate(void) {
int i;
for (i=0; i < objectListSize; i++)
OSConnectorFree(objectList[i].channelList);
OSConnectorFree(objectList);
}
/*************************************************************/
/********************** authenticate ***********************/
/*************************************************************/
/*
STRUCTURE
The database structure used to save authentication information
is arranged like this:
root
|
authP ---- authH
| |
proxy host
| |
| <> ------------------------------ <> ---------------------------- <> ---
| | |
| host --- realm --- cred host --- realm --- cred
| | | | | | |
| string string mem string string mem
|
|
<> ---------------------------- <> --------------------------- <> ---
| |
addr --- port --- cred addr --- port --- cred
| | | |
string mem string mem
Name type comment
---------------------
authP - rec write-through
authH - rec write-through
proxy - set proxy authentication list
host - set host authentication list
<> - rec nameless record
host - str host taken from URL
realm - str realm
cred - mem credentials
addr - str address of proxy
port - int port number
The order of elements within a list is significant for the
addr-port-cred and host-realm-cred lists.
The 'authH' record is write through and thus the entire structure.
The 'authP' record is not saved persistently.
Two counters (hostAuthSize and proxyAuthSize) are used for saving
the list lengths. They can be at most maxHostListSize resp.
maxProxyAuthSize elements long.
SEARCHING
Searching for a matching host is not done in the same way as is
done for proxies. The host find function (checkHostAuth) is
called in two cases: before a http request and when a request
results in a challange for authenification. In the first case,
checkHostAuth is called with no realm and the matching is done
based on only the host. Even if the item exists in the database,
a mismatch may occur. This can happen if several items with
identical host are in the database. A mismatch will result in a
challenge for the server, containing the correct realm and the
correct credentials can be found.
When found an match, this item is moved first in list for three
reasons.
1. When the list is full the least reasently used item
(i.e. last element in the list) is deleted.
2. When searching, it is likely that the item searched for is
the same as last time, especially for proxies.
3. If searching for a host without a realm, the first matching
item is used. If this is not the correct on, a realm is
returned and the correct one is placed ahead of the wrong one.
The next lookup for the same host will probably be for the
same realm.
The third case can be solved a little more elegant by saving the
path along with the host. Out of the paths, a more inteligen
guess can be made. Still, it is not foolproof and demands
more code, a larger amount of RAM and more persistent memory
will be locked up. Add to this, it will be slower. If sending
alternating requests to the same host, but using different
realms is a frequent operation, then it will probably worthwhile
to implement such a solution.
The host and realm are both text strings and are matched agaist
the database case insensitivily.
The address can contain any data not only character data and is
only an exact match counts when comparing addresses.
*/
/*************
* Constants *
*************/
enum {
/* Must be at least 2 */
maxHostListSize = cfg_wae_wspif_AuthenticationItems,
maxProxyListSize = cfg_wae_wspif_AuthenticationItems
};
/*********
* Types *
*********/
/*************
* Variables *
*************/
static RecordPtr hostListRec; /* Pointer to host list record */
static RecordPtr proxyListRec; /* Pointer to proxy list record */
static UINT8 hostAuthSize; /* Number of site authentification records in database. */
static UINT8 proxyAuthSize; /* Number of proxy authentification records in database. */
/*************
* Functions *
*************/
/* ======== host ======== */
/*
* Find host in database. Functionality common to storeHostAuth
* and checkHostAuth is located in this function.
*
* Matches the host of 'url' and 'realm', if not NULL.
*
* Return TRUE if match found.
*/
BOOL findHost(BYTE* *url, BYTE* realm, BYTE* *endPointer, RecordPtr *currentRec)
{
RecordPtr rec;
RecordPtr tempRec;
BYTE* endPtr;
BYTE* s;
BYTE* t;
/* The url is known to be a well formatted http/https URL */
s = *url;
while (*s++ != ':')
;
*url = s + 2;
for (endPtr=*url; *endPtr!='\0' && *endPtr!='/' && *endPtr!=':' &&
*endPtr!='?' && *endPtr!='#'; endPtr++)
;
/* Search for matching host and realm */
rec = NULL;
for (tempRec = hostListRec->data.r; tempRec != hostListRec;
tempRec = (RecordPtr) rec->next) {
rec = tempRec;
for (s = rec->data.f->data.s, t = *url; ; s++, t++) {
if (latin1_lc[*s] != latin1_lc[*t])
if (!*s && t == endPtr)
break;
else
goto Next_loop;
if (!*s)
break;
}
/* Host found, check realm */
if (realm != NULL) {
for (s=rec->data.f->next->data.s, t=realm; ;s++, t++)
if (latin1_lc[*s] == latin1_lc[*t] && !*s)
goto Match_found;
} else
goto Match_found;
Next_loop:;
}
/* --- No match found ---*/
*endPointer = endPtr;
*currentRec = rec;
return FALSE;
/* --- Matching host and realm (if present) found --- */
Match_found:
/* Move current record first in queue. Nessesary if several
* realms are connected to a single host.*/
if (hostListRec->data.r != rec)
db_moveToFront(hostListRec, (ElementPtr) rec);
*currentRec = rec;
return TRUE;
}
/*
* Store the host of 'url' together with 'realm' and 'credientials'.
* If already cfg_wae_wspif_AuthenticationItems are present, the
* least reasently used element is replaced by the new one.
*
* If host and 'realm' matches an item, then the credentials are
* uppdated to 'credentials'. The host and 'realm' are text
* strings and are matched agaist the database case insensitivily.
*
* Return TRUE if successfull.
*/
BOOL storeHostAuth(BYTE* url, BYTE* realm, BYTE* credentials, UINT8 credLength)
{
DB_ref ref;
RecordPtr rec;
BYTE* endPtr;
BYTE* host;
BYTE* cred;
BYTE* s;
BYTE* t;
UINT8 error;
if (!url || !realm || !credentials)
return FALSE;
cred = (BYTE*) OSConnectorAlloc(credLength+2);
#ifndef HAS_SETJMP
if (cred == NULL)
return FALSE;
#endif
*(UINT16*) cred = credLength + 2;
memcpy(cred+2, credentials, credLength);
/* Update or create host information */
if (findHost(&url, realm, &endPtr, &rec))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -