#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#include <syslog.h>
#include <sys/un.h>
#include <pthread.h> // for pthread_*_t
#include <unistd.h> // for _POSIX_THREADS
#include "mslp_sd.h"
#include "slp.h"
#include "mslp.h"
static int issep(char c, const char *pcSeps);
int sysLogInitialized = 0;
int gethostbynameLockInitialized = 0;
pthread_mutex_t sysLogLock;
pthread_mutex_t gethostbynameLock;
pthread_mutex_t gMallocLock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t gStrCatLock = PTHREAD_MUTEX_INITIALIZER;
EXPORT void slp_strcat( char* targetStr, const char* strToAppend )
{
pthread_mutex_lock(&gStrCatLock);
strcat( targetStr, strToAppend );
pthread_mutex_unlock(&gStrCatLock);
}
EXPORT SLPReturnError InternalToReturnError( SLPInternalError iErr )
{
SLPReturnError returnErr;
switch (iErr)
{
case SLP_OK:
returnErr = NO_ERROR;
break;
case SLP_LANGUAGE_NOT_SUPPORTED:
returnErr = LANGUAGE_NOT_SUPPORTED;
break;
case SLP_PARSE_ERROR:
returnErr = PARSE_ERROR;
break;
case SLP_INVALID_REGISTRATION:
returnErr = INVALID_REGISTRATION;
break;
case SLP_SCOPE_NOT_SUPPORTED:
returnErr = SCOPE_NOT_SUPPORTED;
break;
case SLP_AUTHENTICATION_ABSENT:
returnErr = AUTHENTICATION_ABSENT;
break;
case SLP_AUTHENTICATION_FAILED:
returnErr = AUTHENTICATION_FAILED;
break;
default:
returnErr = INTERNAL_ERROR;
break;
}
return returnErr;
}
EXPORT char * safe_malloc(int size, const char *pcCpyInto, int iCpyLen)
{
char *pcNewBuf;
if (size <= 0)
{
SLP_LOG( SLP_LOG_ERR,"SAFE_MALLOC got size <= 0, return NULL");
return NULL;
}
if ((unsigned int)size > MAX_REPLY_LENGTH)
{
SLP_LOG( SLP_LOG_ERR,"SAFE_MALLOC got size too large (%ld), return NULL", size );
return NULL;
}
if (size < iCpyLen)
{
SLP_LOG( SLP_LOG_ERR, "Could not copy into smaller buffer" );
return NULL;
}
pthread_mutex_lock(&gMallocLock);
pcNewBuf = (char*) calloc(1,size);
if (!pcNewBuf)
{
SLP_LOG( SLP_LOG_ERR, "Could not allocate memory" );
pthread_mutex_unlock(&gMallocLock);
return NULL;
}
if (pcCpyInto && iCpyLen > 0)
memcpy(pcNewBuf, pcCpyInto, iCpyLen);
if (!pcCpyInto && iCpyLen > 0)
{
SLP_LOG( SLP_LOG_ERR,"safe_malloc: could not copy from NULL buffer");
}
pthread_mutex_unlock(&gMallocLock);
return pcNewBuf;
}
int IsIPAddress(const char* adrsStr, long *ipAdrs)
{
short i,accum,numOctets,lastDotPos;
long tempAdrs;
register char c;
char localCopy[20];
strncpy(localCopy, adrsStr,sizeof(localCopy)-1);
*ipAdrs = tempAdrs = 0;
numOctets = 1;
accum = 0;
lastDotPos = -1;
for (i = 0; localCopy[i] != 0; i++) { c = localCopy[i]; if (c == '.') {
if (i - lastDotPos <= 1) return 0; if (accum > 255) return 0; *ipAdrs = tempAdrs = (tempAdrs<<8) + accum; accum = 0;
lastDotPos = i;
numOctets++; }
else if ((c >= '0') && (c <= '9')) {
accum = accum * 10 + (c - '0'); }
else return 0; }
if (accum > 255) return 0; tempAdrs = (tempAdrs<<8) + accum; *ipAdrs = tempAdrs;
if (numOctets != 4) return 0; else if (i-lastDotPos <= 1) return 0; else { return 1; }
}
struct in_addr get_in_addr_by_name(const char* pcAddr)
{
struct hostent *phe;
struct in_addr ina;
long addr;
memset(&ina, 0, sizeof ina);
if ( !IsIPAddress( pcAddr, &addr ) ) {
if ( !gethostbynameLockInitialized )
{
pthread_mutex_init( &gethostbynameLock, NULL );
gethostbynameLockInitialized = 1;
}
pthread_mutex_lock( &gethostbynameLock );
phe = gethostbyname(pcAddr);
pthread_mutex_unlock( &gethostbynameLock );
if (phe == NULL)
{
mslplog(SLP_LOG_DEBUG,"get_in_addr_by_name: could not get host by name",pcAddr);
return ina;
}
ina = * (struct in_addr *) phe->h_addr_list[0];
}
else
ina.s_addr = htonl( addr );
return ina;
}
EXPORT SLPInternalError get_sin_from_url(const char *pcURL, int iLen,
struct sockaddr_in *psin) {
char *pcBase, *pc;
const char *pcAddr = NULL;
char *pcPort = NULL;
if (!pcURL || !psin || iLen <= 0) return SLP_PARAMETER_BAD;
memset(psin, 0, sizeof(struct sockaddr_in));
if ( SDstrncasecmp(pcURL,"service:directory-agent:",
strlen("service:directory-agent:"))==0
|| SDstrncasecmp(pcURL,"service:service-agent:",
strlen("service:directory-agent:"))==0) {
psin->sin_port = htons(SLP_PORT);
}
pcBase = safe_malloc(strlen(pcURL)+1,pcURL,strlen(pcURL));
pc = pcBase;
while(--iLen> 0 && *pc && *pc != '/') pc++;
if (pc == NULL || --iLen < 0) {
free(pcBase);
return SLP_PARSE_ERROR;
}
pc++;
if (*pc != '/' || --iLen < 0) {
free(pcBase);
return SLP_PARSE_ERROR;
}
pc++;
pcAddr = pc;
while( --iLen >= 0 && *pc && (*pc != '/') && (*pc != ';') && (*pc != ':')) pc++;
psin->sin_family = AF_INET;
if (*pc == '/' || *pc == ';') {
psin->sin_addr = get_in_addr_by_name(pcAddr);
} else if (*pc == '\0' || iLen < 0) {
psin->sin_addr = get_in_addr_by_name(pcAddr);
} else if (*pc == ':') {
*pc = '\0';
psin->sin_addr = get_in_addr_by_name(pcAddr);
if (pc == NULL || --iLen < 0) {
free(pcBase);
return SLP_PARSE_ERROR;
}
pc++;
pcPort = pc;
while( --iLen >= 0 && *pc && *pc != '/' && *pc != ';') pc++;
if (pc != pcPort)
{
char* endPtr = NULL;
psin->sin_port = (unsigned short)(0xFFFF & strtol(pcPort,&endPtr,10));
}
} else {
free(pcBase);
LOG_SLP_ERROR_AND_RETURN(SLP_LOG_DROP,"could not parse URL", SLP_PARSE_ERROR);
}
free(pcBase);
return SLP_OK;
}
SLPInternalError add_header(const char *pcLangTag, char *pcSendBuf, int iSendBufSz,
int iFun, int iLen, int *piLen)
{
int iLangLen;
static unsigned short xid = 0;
if (!pcLangTag || strlen(pcLangTag) < 2 || !pcSendBuf || !piLen) {
return SLP_PARAMETER_BAD;
}
if (xid == 0) {
srand( (unsigned) time(NULL) );
xid = (unsigned short) (0xFFFF & rand());
}
iLangLen = strlen(pcLangTag);
if ((HDRLEN + *piLen + iLangLen) > iSendBufSz)
return SLP_BUFFER_OVERFLOW;
memset(pcSendBuf, 0, HDRLEN+iLangLen);
SETVER(pcSendBuf,SLP_VER);
SETFUN(pcSendBuf,iFun);
SETLEN(pcSendBuf,iLen);
SETXID(pcSendBuf,xid);
SETLANG(pcSendBuf,pcLangTag);
xid++;
*piLen = HDRLEN + iLangLen;
return SLP_OK;
}
SLPInternalError get_header(const char *pcSendBuf, const char *pcRecvBuf, int len, Slphdr *pslphdr, int *piLen)
{
int iLangLen=0;
memset(pslphdr,0,sizeof(Slphdr));
if (!pcRecvBuf || !pslphdr || !piLen)
return SLP_PARAMETER_BAD;
if (len < HDRLEN)
return SLP_PARSE_ERROR;
if ( GETVER(pcRecvBuf) != SLP_VER )
{
LOG_SLP_ERROR_AND_RETURN(SLP_LOG_DROP,"get_header: bad version",SLP_PARSE_ERROR);
return SLP_PARSE_ERROR;
}
iLangLen = GETLANGLEN(pcRecvBuf);
if ((iLangLen+ *piLen + HDRLEN) > len)
return SLP_PARSE_ERROR;
else if ( iLangLen < 2 )
return SLP_PARSE_ERROR;
#ifndef IGNORE_XID_FROM_REPLY
if (pcSendBuf != NULL && (GETXID(pcRecvBuf) != GETXID(pcSendBuf)))
{
LOG_SLP_ERROR_AND_RETURN(SLP_LOG_DROP,"get_header: bad reply xid",SLP_PARSE_ERROR);
}
#endif
if (pcSendBuf != NULL
&& ( (GETLANGLEN(pcSendBuf) != GETLANGLEN(pcRecvBuf))
|| (SDstrncasecmp(&(pcSendBuf[HDRLEN]),&(pcRecvBuf[HDRLEN]),
GETLANGLEN(pcSendBuf)) != 0)))
{
LOG_SLP_ERROR_AND_RETURN(SLP_LOG_DROP, "get_header: lang tag of reply does not match that of request", SLP_PARSE_ERROR);
}
if ((pslphdr->h_ucVer = GETVER(pcRecvBuf)) != SLP_VER)
{
LOG_SLP_ERROR_AND_RETURN(SLP_LOG_DROP,"get_header: version not supported",SLP_PARSE_ERROR);
}
pslphdr->h_ucFun = GETFUN(pcRecvBuf);
pslphdr->h_ulLen = (0xff0000 & GETBYTE(pcRecvBuf,LEN)<<16) +
(0x00ff00 & GETBYTE(pcRecvBuf,LEN+1)<<8) +
(0x0000ff & GETBYTE(pcRecvBuf,LEN+2));
pslphdr->h_usXID = GETXID(pcRecvBuf);
if (((pslphdr->h_usFlags = GETFLAGS(pcRecvBuf)) & 0x07) != 0)
{
LOG(SLP_LOG_ERR,"get_header: illegal flags set, process anyway");
}
pslphdr->h_iOffset = GETNEXTOP(pcRecvBuf);
pslphdr->h_pcLangTag = safe_malloc(iLangLen+1,&pcRecvBuf[HDRLEN],iLangLen);
pslphdr->h_usErrCode = GETSHT(pcRecvBuf,HDRLEN+iLangLen);
*piLen += HDRLEN + iLangLen;
return SLP_OK;
}
EXPORT SLPInternalError add_sht(char *pcBuf, int iBufSz, int iVal, int *piLen)
{
if (!pcBuf || !piLen)
return SLP_PARAMETER_BAD;
if ((*piLen + 2) > iBufSz)
return SLP_BUFFER_OVERFLOW;
pcBuf[(*piLen)++] = (unsigned char) ((iVal & 0xFF00) >> 8);
pcBuf[(*piLen)++] = (unsigned char) (iVal & 0xFF);
return SLP_OK;
}
EXPORT SLPInternalError get_sht(const char *pcBuf, int maxlen, int *piOffset, int *piSht) {
int offset = 0;
if (!pcBuf || !piOffset || !piSht) return SLP_PARAMETER_BAD;
if (piOffset != NULL) {
if ((*piOffset+2) > maxlen) return SLP_PARSE_ERROR;
offset = *piOffset;
*piOffset += 2;
}
*piSht = (int) ((unsigned char)pcBuf[offset] & (unsigned char)0xFF);
*piSht = *piSht<< 8;
*piSht += (int) ((unsigned char)pcBuf[offset+1] & (unsigned char)0xFF);
return SLP_OK;
}
SLPInternalError add_string(char *pcBuf, int iBufSz, const char *pcStr, int *piLen) {
int iStrLen ;
SLPInternalError err = SLP_OK;
if (!pcBuf || !pcStr || !piLen) return SLP_PARAMETER_BAD;
iStrLen = strlen(pcStr);
if (iStrLen > 0xFFFF) return SLP_PARSE_ERROR;
if ((iStrLen + *piLen + 2) >= iBufSz) return SLP_BUFFER_OVERFLOW;
if ((err = add_sht(pcBuf, iBufSz, iStrLen, piLen)) != SLP_OK) return err;
memcpy(&(pcBuf[*piLen]), pcStr, strlen(pcStr));
*piLen += strlen(pcStr);
return SLP_OK;
}
EXPORT SLPInternalError get_string(const char *pcBuf, int iMaxLen, int *piOffset, char **ppcString) {
int iLen;
SLPInternalError err;
if (ppcString)
*ppcString = NULL;
if (!ppcString || !pcBuf || !piOffset)
return SLP_PARAMETER_BAD;
*ppcString = NULL;
err = get_sht(pcBuf, iMaxLen, piOffset, &iLen);
if (err)
return err;
if ((iLen+*piOffset) > iMaxLen)
{
SLP_LOG( SLP_LOG_ERR, "get_string: tried to parse but got iLen(%d)+*piOffset(%d) > iMaxLen (%d)", iLen, *piOffset, iMaxLen );
return SLP_PARSE_ERROR;
}
*ppcString = safe_malloc(iLen+1, &(pcBuf[*piOffset]), iLen);
*piOffset += iLen;
return SLP_OK;
}
EXPORT char * get_next_string(const char *pcSeps, const char *pcStringList,
int *piIndex, char *pcDelim) {
int iLen = 0;
int iNext = 0;
int iEndsSep = 0;
char *pcStr = NULL;
*pcDelim = '\0';
if (pcStringList == NULL || pcStringList[*piIndex] == '\0') return NULL;
while(pcStringList[*piIndex] && isspace(pcStringList[*piIndex]))
*piIndex += 1;
if (issep(pcStringList[*piIndex],pcSeps)) {
*pcDelim = pcStringList[*piIndex];
*piIndex += 1;
return NULL;
}
if (pcStringList[*piIndex] == '\0') return NULL;
while(pcStringList[*piIndex+iLen]) {
if (issep(pcStringList[*piIndex+iLen],pcSeps)) {
iEndsSep = 1;
*pcDelim = pcStringList[*piIndex+iLen];
break;
}
iLen++;
}
iNext = iLen + iEndsSep;
while(iLen > 0
&& ( isspace(pcStringList[*piIndex+iLen-1])
|| pcStringList[*piIndex+iLen-1] == '\0'
|| issep(pcStringList[*piIndex+iLen-1],pcSeps)))
iLen--;
if (iLen < 1) return NULL;
pcStr = safe_malloc(iLen+1,&pcStringList[*piIndex],iLen);
*piIndex += iNext;
return pcStr;
}
static int issep(char c, const char *pcSeps) {
while (*pcSeps) {
if (c == *pcSeps) return 1;
else pcSeps++;
}
return 0;
}
EXPORT const char * slp_strerror(SLPInternalError slpe) {
switch (slpe) {
case SLP_OK: return "SLP_OK";
case SLP_LANGUAGE_NOT_SUPPORTED: return "SLP_LANGUAGE_NOT_SUPPORTED";
case SLP_PARSE_ERROR: return "SLP_PARSE_ERROR";
case SLP_INVALID_REGISTRATION: return "SLP_INVALID_REGISTRATION";
case SLP_SCOPE_NOT_SUPPORTED: return "SLP_SCOPE_NOT_SUPPORTED";
case SLP_AUTHENTICATION_ABSENT: return "SLP_AUTHENTICATION_ABSENT";
case SLP_AUTHENTICATION_FAILED: return "SLP_AUTHENTICATION_FAILED";
case SLP_INVALID_UPDATE: return "SLP_INVALID_UPDATE";
case SLP_NOT_IMPLEMENTED: return "SLP_NOT_IMPLEMENTED";
case SLP_BUFFER_OVERFLOW: return "SLP_BUFFER_OVERFLOW";
case SLP_NETWORK_TIMED_OUT: return "SLP_NETWORK_TIMED_OUT";
case SLP_NETWORK_INIT_FAILED: return "SLP_NETWORK_INIT_FAILED";
case SLP_MEMORY_ALLOC_FAILED: return "SLP_MEMORY_ALLOC_FAILED";
case SLP_PARAMETER_BAD: return "SLP_PARAMETER_BAD";
case SLP_NETWORK_ERROR: return "SLP_NETWORK_ERROR";
case SLP_INTERNAL_SYSTEM_ERROR: return "SLP_INTERNAL_SYSTEM_ERROR";
case SLP_RECURSIVE_CALLBACK_ERROR: return "SLP_RECURSIVE_CALLBACK_ERROR";
case SLP_TYPE_ERROR: return "SLP_TYPE_ERROR";
case SLP_REPLY_TOO_BIG_FOR_PROTOCOL: return "SLP_REPLY_TOO_BIG_FOR_PROTOCOL";
case SERVICE_NOT_REGISTERED: return "SERVICE_NOT_REGISTERED";
case SERVICE_ALREADY_REGISTERED: return "SERVICE_ALREADY_REGISTERED";
case SERVICE_TYPE_NOT_SUPPORTED: return "SERVICE_TYPE_NOT_SUPPORTED";
default: return "unknown error";
}
}
int gLastLogOption = 0;
EXPORT void SLP_LOG(LogLevel lev, const char* format, ...)
{
va_list ap;
va_start( ap, format );
newlog( lev, format, ap );
va_end( ap );
}
EXPORT void newlog(LogLevel lev, const char* format, va_list ap )
{
char pcMsg[MAXLINE +1];
vsnprintf( pcMsg, MAXLINE, format, ap );
mslplog( lev, pcMsg, NULL );
}
EXPORT void mslplog(LogLevel lev, const char *pcMsg, const char *pcSysMsg)
{
char * pcLogName;
if ( !pcMsg )
return;
if (
(SLPGetProperty("com.sun.slp.traceAll") &&
!SDstrcasecmp(SLPGetProperty("com.sun.slp.traceAll"),"true")) ||
(SLPGetProperty("com.apple.slp.logAll") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.logAll"),"true")) ||
((lev & SLP_LOG_STATE) &&
(SLPGetProperty("net.slp.traceState") &&
!SDstrcasecmp(SLPGetProperty("net.slp.traceDrop"),"true"))) ||
((lev & SLP_LOG_RADMIN) &&
(SLPGetProperty("net.slp.traceRAdmin") &&
!SDstrcasecmp(SLPGetProperty("net.slp.traceRAdmin"),"true"))) ||
((lev & SLP_LOG_DROP) &&
(SLPGetProperty("net.slp.traceDrop") &&
!SDstrcasecmp(SLPGetProperty("net.slp.traceDrop"),"true"))) ||
((lev & SLP_LOG_DA) &&
(SLPGetProperty("net.slp.traceDATraffic") &&
!SDstrcasecmp(SLPGetProperty("net.slp.traceDATraffic"),"true"))) ||
((lev & SLP_LOG_SA) &&
(SLPGetProperty("com.apple.slp.traceSATraffic") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.traceSATraffic"),"true"))) ||
((lev & SLP_LOG_REG) &&
(SLPGetProperty("net.slp.traceReg") &&
!SDstrcasecmp(SLPGetProperty("net.slp.traceReg"),"true"))) ||
((lev & SLP_LOG_MSG) &&
(SLPGetProperty("net.slp.traceMsg") &&
!SDstrcasecmp(SLPGetProperty("net.slp.traceMsg"),"true"))) ||
((lev & SLP_LOG_DEBUG) &&
(SLPGetProperty("com.sun.slp.traceDebug") &&
!SDstrcasecmp(SLPGetProperty("com.sun.slp.traceDebug"),"true"))) ||
((lev & SLP_LOG_REG) &&
(SLPGetProperty("com.apple.slp.traceRegistrations") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.traceRegistrations"),"true"))) ||
((lev & SLP_LOG_EXP) &&
(SLPGetProperty("com.apple.slp.traceExpirations") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.traceExpirations"),"true"))) ||
((lev & SLP_LOG_SR) &&
(SLPGetProperty("com.apple.slp.traceServiceRequests") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.traceServiceRequests"),"true"))) ||
((lev & SLP_LOG_DA) &&
(SLPGetProperty("com.apple.slp.traceDAInfoRequests") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.traceDAInfoRequests"),"true"))) ||
((lev & SLP_LOG_ERR) &&
(SLPGetProperty("com.apple.slp.traceErrors") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.traceErrors"),"true"))) ||
((lev & SLP_LOG_NOTIFICATIONS) &&
(SLPGetProperty("com.apple.slp.traceNotifications") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.traceNotifications"),"true"))) ||
((lev & SLP_LOG_CONFIG) &&
(SLPGetProperty("com.apple.slp.traceConfig") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.traceConfig"),"true"))) ||
((lev & SLP_LOG_SIGNAL) &&
(SLPGetProperty("com.apple.slp.traceSignals") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.traceSignals"),"true"))) ||
((lev & SLP_LOG_DEBUG) &&
(SLPGetProperty("com.apple.slp.traceDebug") &&
!SDstrcasecmp(SLPGetProperty("com.apple.slp.traceDebug"),"true"))))
{
int priority;
int logOption = LOG_CONS | LOG_NDELAY;
switch (lev)
{
case SLP_LOG_FAIL:
pcLogName = "FAIL";
priority = LOG_CRIT;
logOption |= LOG_PERROR; break;
case SLP_LOG_ERR:
pcLogName = "ERR";
priority = LOG_ERR;
logOption |= LOG_PERROR; break;
case SLP_LOG_DA:
pcLogName = "DA";
priority = LOG_ERR;
break;
case SLP_LOG_SA:
pcLogName = "SA";
priority = LOG_INFO;
break;
case SLP_LOG_REG:
pcLogName = "REG";
priority = LOG_ERR;
break;
case SLP_LOG_MSG:
pcLogName = "MSG";
priority = LOG_INFO;
break;
case SLP_LOG_NOTIFICATIONS:
pcLogName = "NOTIFY";
priority = LOG_INFO;
break;
case SLP_LOG_DROP:
pcLogName = "DROP";
priority = LOG_INFO;
break;
case SLP_LOG_DEBUG:
pcLogName = "DEBUG";
priority = LOG_INFO;
break;
case SLP_LOG_RADMIN:
pcLogName = "ServerAdmin";
priority = LOG_ERR;
break;
case SLP_LOG_EXP:
pcLogName = "EXP";
priority = LOG_ERR;
break;
case SLP_LOG_SR:
pcLogName = "SR";
priority = LOG_INFO;
break;
case SLP_LOG_STATE:
pcLogName = "STATE";
priority = LOG_ERR;
break;
case SLP_LOG_CONFIG:
pcLogName = "CONFIG";
priority = LOG_INFO;
break;
default:
pcLogName = "UNKNOWN";
priority = LOG_INFO;
}
if ( !sysLogInitialized )
{
pthread_mutex_init( &sysLogLock, NULL );
sysLogInitialized = 1;
}
pthread_mutex_lock( &sysLogLock );
if ( SLPGetProperty("com.apple.slp.identity") && gLastLogOption != logOption )
{
if ( gLastLogOption )
closelog();
openlog( SLPGetProperty("com.apple.slp.identity"), logOption, LOG_DAEMON );
gLastLogOption = logOption;
}
syslog( priority, "%s: %s\n", pcLogName, pcMsg );
pthread_mutex_unlock( &sysLogLock );
}
}
EXPORT SLPInternalError isAttrvalEscapedOK(const char *pcVal)
{
const char *pc = pcVal;
int count = 0;
if (pcVal == NULL)
return SLP_PARAMETER_BAD;
if (pcVal[0] == '\0')
return SLP_OK;
for ( ; *pc; pc++)
{
count++;
if (*pc == '\\')
{
char c1,c2;
pc++;
if (strlen(pc) < 2)
{
#ifndef READER_TEST
mslplog(SLP_LOG_DEBUG, "isAttrvalEscapedOK: token too large (>2 char)",(pc)?(pc):"");
#endif
return SLP_PARSE_ERROR;
}
c1 = *pc++;
c2 = *pc;
if (count == 1 && (c1=='F' || c1=='f') && (c2=='F' || c2=='f'))
return SLP_OK;
if ( (c1=='2' && (c2 == '1' ||
c2=='8' ||
c2=='9' ||
c2=='A' || c2=='a' ||
c2=='C' || c2=='c'))
|| ( (c1=='0' || c1 == '1') &&
((c2>='0' && c2<='9') ||
(c2>='a' && c2<='f') ||
(c2>='A' && c2<='F')))
|| (c1=='3' &&
(c2=='c' || c2=='C' ||
c2=='d' || c2=='D' ||
c2=='e' || c2=='E'))
|| (c1=='5' && (c2=='c' || c2=='C' ||
c2=='f' || c2=='F'))
|| (c1=='7' && (c2=='e' || c2=='E')))
{
continue;
}
#ifndef READER_TEST
SLP_LOG(SLP_LOG_DEBUG,"isAttrvalEscapedOK: illegal escape value: %s from %s", pc, pcVal);
#endif
return SLP_PARSE_ERROR;
}
if (*pc == '(' || *pc == ')' || *pc == ',' || *pc == '\\' ||
*pc == '!' || *pc == '<' || *pc == '=' || *pc == '>' ||
*pc == '~' || (*pc>= 0x00 && *pc<= 0x1F))
{
#ifndef READER_TEST
SLP_LOG(SLP_LOG_DEBUG, "isAttrvalEscapedOK: illegal value, needs to be escaped: %s",pc);
#endif
return SLP_PARSE_ERROR;
}
}
return SLP_OK;
}
EXPORT SLPInternalError isURLEscapedOK(const char *pcVal) {
const char *pc = pcVal;
if (pcVal == NULL) return SLP_PARAMETER_BAD;
if (pcVal[0] == '\0') return SLP_OK;
for ( ; *pc && *pc != '/' ; pc++) {
if (*pc != '%') {
if ((*pc >= '0' && *pc <= '9') ||
(*pc >= 'a' && *pc <= 'z') ||
(*pc >= 'A' && *pc <= 'Z') ||
*pc == '.' || *pc == '+' || *pc == '-' || *pc == ':') {
continue;
} else {
LOG(SLP_LOG_ERR,
"isURLEscapedOK: malformed service type or naming authority");
return SLP_PARSE_ERROR;
}
} else {
char c1,c2;
pc++;
if (strlen(pc) < 2) {
#ifndef READER_TEST
mslplog(SLP_LOG_DEBUG,
"isURLEscapedOK: token too large (>2 char)",(pc)?(pc):"");
#endif
return SLP_PARSE_ERROR;
}
c1 = *pc++;
c2 = *pc++;
if (((c1 >= '0' && c1 <= '9') ||
(c1 >= 'A' && c1 <= 'F') ||
(c1 >= 'a' && c1 <= 'f')) &&
((c2 >= '0' && c2 <= '9') ||
(c2 >= 'A' && c2 <= 'F') ||
(c2 >= 'a' && c2 <= 'f'))) {
continue;
} else {
SLP_LOG( SLP_LOG_DEBUG, "isURLEscapedOK: bad hex escape value");
return SLP_PARSE_ERROR;
}
}
}
return SLP_OK;
}