You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1504 lines
54 KiB

/**************************************************************************/
/* */
/* Project: OpenSLP - OpenSource implementation of Service Location */
/* Protocol Version 2 */
/* */
/* File: slpd_process.c */
/* */
/* Abstract: Processes incoming SLP messages */
/* */
/*-------------------------------------------------------------------------*/
/* */
/* Please submit patches to http://www.openslp.org */
/* */
/*-------------------------------------------------------------------------*/
/* */
/* Copyright (C) 2000 Caldera Systems, Inc */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are */
/* met: */
/* */
/* Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* */
/* Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in */
/* the documentation and/or other materials provided with the */
/* distribution. */
/* */
/* Neither the name of Caldera Systems nor the names of its */
/* contributors may be used to endorse or promote products derived */
/* from this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA */
/* SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/***************************************************************************/
/*=========================================================================*/
/* slpd includes */
/*=========================================================================*/
#include "slpd_process.h"
#include "slpd_property.h"
#include "slpd_database.h"
#include "slpd_knownda.h"
#include "slpd_log.h"
#ifdef ENABLE_SLPv2_SECURITY
#include "slpd_spi.h"
#endif
/*=========================================================================*/
/* common code includes */
/*=========================================================================*/
#include "slp_xmalloc.h"
#include "slp_message.h"
#include "slp_compare.h"
#ifdef ENABLE_SLPv2_SECURITY
#include "slp_auth.h"
#endif
/*-------------------------------------------------------------------------*/
int ProcessSASrvRqst(SLPMessage message,
SLPBuffer* sendbuf,
int errorcode)
/*-------------------------------------------------------------------------*/
{
int size = 0;
SLPBuffer result = *sendbuf;
if (message->body.srvrqst.scopelistlen == 0 ||
SLPIntersectStringList(message->body.srvrqst.scopelistlen,
message->body.srvrqst.scopelist,
G_SlpdProperty.useScopesLen,
G_SlpdProperty.useScopes) != 0)
{
/*----------------------*/
/* Send back a SAAdvert */
/*----------------------*/
/*--------------------------------------------------------------*/
/* ensure the buffer is big enough to handle the whole SAAdvert */
/*--------------------------------------------------------------*/
size = message->header.langtaglen + 21; /* 14 bytes for header */
/* 2 bytes for url count */
/* 2 bytes for scope list len */
/* 2 bytes for attr list len */
/* 1 byte for authblock count */
size += G_SlpdProperty.myUrlLen;
size += G_SlpdProperty.useScopesLen;
/* TODO: size += G_SlpdProperty.SAAttributes */
result = SLPBufferRealloc(result,size);
if (result == 0)
{
/* TODO: out of memory, what should we do here! */
errorcode = SLP_ERROR_INTERNAL_ERROR;
goto FINISHED;
}
/*----------------*/
/* Add the header */
/*----------------*/
/*version*/
*(result->start) = 2;
/*function id*/
*(result->start + 1) = SLP_FUNCT_SAADVERT;
/*length*/
ToUINT24(result->start + 2, size);
/*flags*/
ToUINT16(result->start + 5,
(size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0));
/*ext offset*/
ToUINT24(result->start + 7,0);
/*xid*/
ToUINT16(result->start + 10,message->header.xid);
/*lang tag len*/
ToUINT16(result->start + 12,message->header.langtaglen);
/*lang tag*/
memcpy(result->start + 14,
message->header.langtag,
message->header.langtaglen);
/*--------------------------*/
/* Add rest of the SAAdvert */
/*--------------------------*/
result->curpos = result->start + 14 + message->header.langtaglen;
/* url len */
ToUINT16(result->curpos, G_SlpdProperty.myUrlLen);
result->curpos = result->curpos + 2;
/* url */
memcpy(result->curpos,G_SlpdProperty.myUrl,G_SlpdProperty.myUrlLen);
result->curpos = result->curpos + G_SlpdProperty.myUrlLen;
/* scope list len */
ToUINT16(result->curpos, G_SlpdProperty.useScopesLen);
result->curpos = result->curpos + 2;
/* scope list */
memcpy(result->curpos,G_SlpdProperty.useScopes,G_SlpdProperty.useScopesLen);
result->curpos = result->curpos + G_SlpdProperty.useScopesLen;
/* attr list len */
/* ToUINT16(result->curpos,G_SlpdProperty.SAAttributesLen) */
ToUINT16(result->curpos, 0);
result->curpos = result->curpos + 2;
/* attr list */
/* memcpy(result->start,G_SlpdProperty.SAAttributes,G_SlpdProperty.SAAttributesLen) */
/* authblock count */
*(result->curpos) = 0;
}
else
{
errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED;
}
FINISHED:
*sendbuf = result;
return errorcode;
}
/*-------------------------------------------------------------------------*/
int ProcessDASrvRqst(SLPMessage message,
SLPBuffer* sendbuf,
int errorcode)
/*-------------------------------------------------------------------------*/
{
SLPBuffer tmp = 0;
SLPMessage msg = 0;
void* eh = 0;
/*---------------------------------------------------------------------*/
/* Special case for when libslp asks slpd (through the loopback) about */
/* a known DAs. Fill sendbuf with DAAdverts from all known DAs. */
/*---------------------------------------------------------------------*/
if (ISLOCAL(message->peer.sin_addr))
{
/* TODO: be smarter about how much memory is allocated here! */
/* 4096 may not be big enough to handle all DAAdverts */
*sendbuf = SLPBufferRealloc(*sendbuf, 4096);
if (*sendbuf == 0)
{
return SLP_ERROR_INTERNAL_ERROR;
}
if (errorcode == 0)
{
/* Note: The weird *sendbuf code is making a single SLPBuffer */
/* that contains multiple DAAdverts. This is a special */
/* process that only happens for the DA SrvRqst through */
/* loopback to the SLPAPI */
eh = SLPDKnownDAEnumStart();
if (eh)
{
while (1)
{
if (SLPDKnownDAEnum(eh, &msg, &tmp) == 0)
{
break;
}
if (((*sendbuf)->curpos) + (tmp->end - tmp->start) > (*sendbuf)->end)
{
break;
}
/* TRICKY: fix up the xid */
tmp->curpos = tmp->start + 10;
ToUINT16(tmp->curpos, message->header.xid);
memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start);
(*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start);
}
SLPDKnownDAEnumEnd(eh);
}
/* Tack on a "terminator" DAAdvert */
SLPDKnownDAGenerateMyDAAdvert(SLP_ERROR_INTERNAL_ERROR,
0,
message->header.xid,
&tmp);
if (((*sendbuf)->curpos) + (tmp->end - tmp->start) <= (*sendbuf)->end)
{
memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start);
(*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start);
}
/* mark the end of the sendbuf */
(*sendbuf)->end = (*sendbuf)->curpos;
if (tmp)
{
SLPBufferFree(tmp);
}
}
return errorcode;
}
/*---------------------------------------------------------------------*/
/* Normal case where a remote Agent asks for a DA */
/*---------------------------------------------------------------------*/
*sendbuf = SLPBufferRealloc(*sendbuf, SLP_MAX_DATAGRAM_SIZE);
if (*sendbuf == 0)
{
return SLP_ERROR_INTERNAL_ERROR;
}
if (G_SlpdProperty.isDA)
{
if (message->body.srvrqst.scopelistlen == 0 ||
SLPIntersectStringList(message->body.srvrqst.scopelistlen,
message->body.srvrqst.scopelist,
G_SlpdProperty.useScopesLen,
G_SlpdProperty.useScopes))
{
errorcode = SLPDKnownDAGenerateMyDAAdvert(errorcode,
0,
message->header.xid,
sendbuf);
}
else
{
errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED;
}
}
else
{
errorcode = SLP_ERROR_MESSAGE_NOT_SUPPORTED;
}
/*-----------------------------------------------*/
/* don't return errorcodes to multicast messages */
/*-----------------------------------------------*/
if (errorcode != 0)
{
if (message->header.flags & SLP_FLAG_MCAST ||
ISMCAST(message->peer.sin_addr))
{
(*sendbuf)->end = (*sendbuf)->start;
}
}
return errorcode;
}
/*-------------------------------------------------------------------------*/
int ProcessSrvRqst(SLPMessage message,
SLPBuffer* sendbuf,
int errorcode)
/*-------------------------------------------------------------------------*/
{
int i;
SLPUrlEntry* urlentry;
SLPDDatabaseSrvRqstResult* db = 0;
int size = 0;
SLPBuffer result = *sendbuf;
#ifdef ENABLE_SLPv2_SECURITY
SLPAuthBlock* authblock = 0;
int j;
#endif
/*--------------------------------------------------------------*/
/* If errorcode is set, we can not be sure that message is good */
/* Go directly to send response code */
/*--------------------------------------------------------------*/
if (errorcode)
{
goto RESPOND;
}
/*-------------------------------------------------*/
/* Check for one of our IP addresses in the prlist */
/*-------------------------------------------------*/
if (SLPIntersectStringList(message->body.srvrqst.prlistlen,
message->body.srvrqst.prlist,
G_SlpdProperty.interfacesLen,
G_SlpdProperty.interfaces) )
{
/* silently ignore */
result->end = result->start;
goto FINISHED;
}
/*------------------------------------------------------------------*/
/* Make sure that we handle at least verify registrations made with */
/* the requested SPI. If we can't then have to return an error */
/* because there is no way we can return URL entries that ares */
/* signed in a way the requester can understand */
/*------------------------------------------------------------------*/
#ifdef ENABLE_SLPv2_SECURITY
if (G_SlpdProperty.securityEnabled)
{
if (SLPSpiCanVerify(G_SlpdSpiHandle,
message->body.srvrqst.spistrlen,
message->body.srvrqst.spistr) == 0)
{
errorcode = SLP_ERROR_AUTHENTICATION_UNKNOWN;
goto RESPOND;
}
}
else if (message->body.srvrqst.spistrlen)
{
errorcode = SLP_ERROR_AUTHENTICATION_UNKNOWN;
goto RESPOND;
}
#else
if (message->body.srvrqst.spistrlen)
{
errorcode = SLP_ERROR_AUTHENTICATION_UNKNOWN;
goto RESPOND;
}
#endif
/*------------------------------------------------*/
/* Check to to see if a this is a special SrvRqst */
/*------------------------------------------------*/
if (SLPCompareString(message->body.srvrqst.srvtypelen,
message->body.srvrqst.srvtype,
23,
SLP_DA_SERVICE_TYPE) == 0)
{
errorcode = ProcessDASrvRqst(message, sendbuf, errorcode);
if (errorcode == 0)
{
// Since we have an errorcode of 0, we were successful,
// and have already formed a response packet; return now.
return errorcode;
}
goto RESPOND;
}
if (SLPCompareString(message->body.srvrqst.srvtypelen,
message->body.srvrqst.srvtype,
21,
SLP_SA_SERVICE_TYPE) == 0)
{
errorcode = ProcessSASrvRqst(message, sendbuf, errorcode);
if (errorcode == 0)
{
// Since we have an errorcode of 0, we were successful,
// and have already formed a response packet; return now.
return errorcode;
}
goto RESPOND;
}
/*------------------------------------*/
/* Make sure that we handle the scope */
/*------ -----------------------------*/
if (SLPIntersectStringList(message->body.srvrqst.scopelistlen,
message->body.srvrqst.scopelist,
G_SlpdProperty.useScopesLen,
G_SlpdProperty.useScopes) != 0)
{
/*-------------------------------*/
/* Find services in the database */
/*-------------------------------*/
errorcode = SLPDDatabaseSrvRqstStart(message, &db);
}
else
{
errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED;
}
RESPOND:
/*----------------------------------------------------------------*/
/* Do not send error codes or empty replies to multicast requests */
/*----------------------------------------------------------------*/
if (errorcode != 0 || db->urlcount == 0)
{
if (message->header.flags & SLP_FLAG_MCAST ||
ISMCAST(message->peer.sin_addr))
{
result->end = result->start;
goto FINISHED;
}
}
/*-------------------------------------------------------------*/
/* ensure the buffer is big enough to handle the whole srvrply */
/*-------------------------------------------------------------*/
size = message->header.langtaglen + 18; /* 14 bytes for header */
/* 2 bytes for error code */
/* 2 bytes for url count */
if (errorcode == 0)
{
for (i=0;i<db->urlcount;i++)
{
/* urlentry is the url from the db result */
urlentry = db->urlarray[i];
size += urlentry->urllen + 6; /* 1 byte for reserved */
/* 2 bytes for lifetime */
/* 2 bytes for urllen */
/* 1 byte for authcount */
#ifdef ENABLE_SLPv2_SECURITY
/* make room to include the authblock that was asked for */
if (G_SlpdProperty.securityEnabled &&
message->body.srvrqst.spistrlen )
{
for (j=0; j<urlentry->authcount;j++)
{
if (SLPCompareString(urlentry->autharray[j].spistrlen,
urlentry->autharray[j].spistr,
message->body.srvrqst.spistrlen,
message->body.srvrqst.spistr) == 0)
{
authblock = &(urlentry->autharray[j]);
size += authblock->length;
break;
}
}
}
#endif
}
}
/*------------------------------*/
/* Reallocate the result buffer */
/*------------------------------*/
result = SLPBufferRealloc(result,size);
if (result == 0)
{
errorcode = SLP_ERROR_INTERNAL_ERROR;
goto FINISHED;
}
/*----------------*/
/* Add the header */
/*----------------*/
/*version*/
*(result->start) = 2;
/*function id*/
*(result->start + 1) = SLP_FUNCT_SRVRPLY;
/*length*/
ToUINT24(result->start + 2, size);
/*flags*/
ToUINT16(result->start + 5,
(size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0));
/*ext offset*/
ToUINT24(result->start + 7,0);
/*xid*/
ToUINT16(result->start + 10,message->header.xid);
/*lang tag len*/
ToUINT16(result->start + 12,message->header.langtaglen);
/*lang tag*/
memcpy(result->start + 14,
message->header.langtag,
message->header.langtaglen);
/*-------------------------*/
/* Add rest of the SrvRply */
/*-------------------------*/
result->curpos = result->start + 14 + message->header.langtaglen;
/* error code*/
ToUINT16(result->curpos, errorcode);
result->curpos = result->curpos + 2;
if (errorcode == 0)
{
/* urlentry count */
ToUINT16(result->curpos, db->urlcount);
result->curpos = result->curpos + 2;
for (i=0;i<db->urlcount;i++)
{
/* urlentry is the url from the db result */
urlentry = db->urlarray[i];
#ifdef ENABLE_SLPv1
if (urlentry->opaque == 0)
{
/* url-entry reserved */
*result->curpos = 0;
result->curpos = result->curpos + 1;
/* url-entry lifetime */
ToUINT16(result->curpos,urlentry->lifetime);
result->curpos = result->curpos + 2;
/* url-entry urllen */
ToUINT16(result->curpos,urlentry->urllen);
result->curpos = result->curpos + 2;
/* url-entry url */
memcpy(result->curpos,urlentry->url,urlentry->urllen);
result->curpos = result->curpos + urlentry->urllen;
/* url-entry auths */
*result->curpos = 0;
result->curpos = result->curpos + 1;
}
else
#endif
{
/* Use an opaque copy if available (and authentication is not being used)*/
/* TRICKY: fix up the lifetime */
ToUINT16(urlentry->opaque + 1,urlentry->lifetime);
memcpy(result->curpos,urlentry->opaque,urlentry->opaquelen);
result->curpos = result->curpos + urlentry->opaquelen;
}
}
}
else
{
/* set urlentry count to 0*/
ToUINT16(result->curpos, 0);
result->curpos = result->curpos + 2;
}
FINISHED:
if (db) SLPDDatabaseSrvRqstEnd(db);
*sendbuf = result;
return errorcode;
}
/*-------------------------------------------------------------------------*/
int ProcessSrvReg(SLPMessage message,
SLPBuffer recvbuf,
SLPBuffer* sendbuf,
int errorcode)
/* */
/* Returns: non-zero if message should be silently dropped */
/*-------------------------------------------------------------------------*/
{
SLPBuffer result = *sendbuf;
/*--------------------------------------------------------------*/
/* If errorcode is set, we can not be sure that message is good */
/* Go directly to send response code also do not process mcast */
/* srvreg or srvdereg messages */
/*--------------------------------------------------------------*/
if (errorcode ||
message->header.flags & SLP_FLAG_MCAST ||
ISMCAST(message->peer.sin_addr))
{
goto RESPOND;
}
/*------------------------------------*/
/* Make sure that we handle the scope */
/*------ -----------------------------*/
if (SLPIntersectStringList(message->body.srvreg.scopelistlen,
message->body.srvreg.scopelist,
G_SlpdProperty.useScopesLen,
G_SlpdProperty.useScopes))
{
#ifdef ENABLE_SLPv2_SECURITY
/*-------------------------------*/
/* Validate the authblocks */
/*-------------------------------*/
errorcode = SLPAuthVerifyUrl(G_SlpdSpiHandle,
0,
&(message->body.srvreg.urlentry));
if (errorcode == 0)
{
errorcode = SLPAuthVerifyString(G_SlpdSpiHandle,
0,
message->body.srvreg.attrlistlen,
message->body.srvreg.attrlist,
message->body.srvreg.authcount,
message->body.srvreg.autharray);
}
if (errorcode == 0)
#endif
{
/*--------------------------------------------------------------*/
/* Put the registration in the */
/*--------------------------------------------------------------*/
/* TRICKY: Remember the recvbuf was duplicated back in */
/* SLPDProcessMessage() */
if (ISLOCAL(message->peer.sin_addr))
{
message->body.srvreg.source= SLP_REG_SOURCE_LOCAL;
}
else
{
message->body.srvreg.source = SLP_REG_SOURCE_REMOTE;
}
errorcode = SLPDDatabaseReg(message, recvbuf);
}
}
else
{
errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED;
}
RESPOND:
/*--------------------------------------------------------------------*/
/* don't send back reply anything multicast SrvReg (set result empty) */
/*--------------------------------------------------------------------*/
if (message->header.flags & SLP_FLAG_MCAST ||
ISMCAST(message->peer.sin_addr))
{
result->end = result->start;
goto FINISHED;
}
/*------------------------------------------------------------*/
/* ensure the buffer is big enough to handle the whole srvack */
/*------------------------------------------------------------*/
result = SLPBufferRealloc(result,message->header.langtaglen + 16);
if (result == 0)
{
errorcode = SLP_ERROR_INTERNAL_ERROR;
goto FINISHED;
}
/*----------------*/
/* Add the header */
/*----------------*/
/*version*/
*(result->start) = 2;
/*function id*/
*(result->start + 1) = SLP_FUNCT_SRVACK;
/*length*/
ToUINT24(result->start + 2,message->header.langtaglen + 16);
/*flags*/
ToUINT16(result->start + 5,0);
/*ext offset*/
ToUINT24(result->start + 7,0);
/*xid*/
ToUINT16(result->start + 10,message->header.xid);
/*lang tag len*/
ToUINT16(result->start + 12,message->header.langtaglen);
/*lang tag*/
memcpy(result->start + 14,
message->header.langtag,
message->header.langtaglen);
/*-------------------*/
/* Add the errorcode */
/*-------------------*/
ToUINT16(result->start + 14 + message->header.langtaglen, errorcode);
FINISHED:
*sendbuf = result;
return errorcode;
}
/*-------------------------------------------------------------------------*/
int ProcessSrvDeReg(SLPMessage message,
SLPBuffer* sendbuf,
int errorcode)
/* */
/* Returns: non-zero if message should be silently dropped */
/*-------------------------------------------------------------------------*/
{
SLPBuffer result = *sendbuf;
/*--------------------------------------------------------------*/
/* If errorcode is set, we can not be sure that message is good */
/* Go directly to send response code also do not process mcast */
/* srvreg or srvdereg messages */
/*--------------------------------------------------------------*/
if (errorcode || message->header.flags & SLP_FLAG_MCAST)
{
goto RESPOND;
}
/*------------------------------------*/
/* Make sure that we handle the scope */
/*------------------------------------*/
if (SLPIntersectStringList(message->body.srvdereg.scopelistlen,
message->body.srvdereg.scopelist,
G_SlpdProperty.useScopesLen,
G_SlpdProperty.useScopes))
{
#ifdef ENABLE_SLPv2_SECURITY
/*-------------------------------*/
/* Validate the authblocks */
/*-------------------------------*/
errorcode = SLPAuthVerifyUrl(G_SlpdSpiHandle,
0,
&(message->body.srvdereg.urlentry));
if (errorcode == 0)
#endif
{
/*--------------------------------------*/
/* remove the service from the database */
/*--------------------------------------*/
errorcode = SLPDDatabaseDeReg(message);
}
}
else
{
errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED;
}
RESPOND:
/*---------------------------------------------------------*/
/* don't do anything multicast SrvDeReg (set result empty) */
/*---------------------------------------------------------*/
if (message->header.flags & SLP_FLAG_MCAST ||
ISMCAST(message->peer.sin_addr))
{
result->end = result->start;
goto FINISHED;
}
/*------------------------------------------------------------*/
/* ensure the buffer is big enough to handle the whole srvack */
/*------------------------------------------------------------*/
result = SLPBufferRealloc(result,message->header.langtaglen + 16);
if (result == 0)
{
errorcode = SLP_ERROR_INTERNAL_ERROR;
goto FINISHED;
}
/*----------------*/
/* Add the header */
/*----------------*/
/*version*/
*(result->start) = 2;
/*function id*/
*(result->start + 1) = SLP_FUNCT_SRVACK;
/*length*/
ToUINT24(result->start + 2,message->header.langtaglen + 16);
/*flags*/
ToUINT16(result->start + 5,0);
/*ext offset*/
ToUINT24(result->start + 7,0);
/*xid*/
ToUINT16(result->start + 10,message->header.xid);
/*lang tag len*/
ToUINT16(result->start + 12,message->header.langtaglen);
/*lang tag*/
memcpy(result->start + 14,
message->header.langtag,
message->header.langtaglen);
/*-------------------*/
/* Add the errorcode */
/*-------------------*/
ToUINT16(result->start + 14 + message->header.langtaglen, errorcode);
FINISHED:
*sendbuf = result;
return errorcode;
}
/*-------------------------------------------------------------------------*/
int ProcessSrvAck(SLPMessage message,
SLPBuffer* sendbuf,
int errorcode)
/*-------------------------------------------------------------------------*/
{
/* Ignore SrvAck. Just return errorcode to caller */
SLPBuffer result = *sendbuf;
result->end = result->start;
return 0;
}
/*-------------------------------------------------------------------------*/
int ProcessAttrRqst(SLPMessage message,
SLPBuffer* sendbuf,
int errorcode)
/*-------------------------------------------------------------------------*/
{
SLPDDatabaseAttrRqstResult* db = 0;
int size = 0;
SLPBuffer result = *sendbuf;
#ifdef ENABLE_SLPv2_SECURITY
int i;
unsigned char* generatedauth = 0;
int generatedauthlen = 0;
unsigned char* opaqueauth = 0;
int opaqueauthlen = 0;
#endif
/*--------------------------------------------------------------*/
/* If errorcode is set, we can not be sure that message is good */
/* Go directly to send response code */
/*--------------------------------------------------------------*/
if (errorcode)
{
goto RESPOND;
}
/*-------------------------------------------------*/
/* Check for one of our IP addresses in the prlist */
/*-------------------------------------------------*/
if (SLPIntersectStringList(message->body.attrrqst.prlistlen,
message->body.attrrqst.prlist,
G_SlpdProperty.interfacesLen,
G_SlpdProperty.interfaces))
{
/* Silently ignore */
result->end = result->start;
goto FINISHED;
}
/*------------------------------------*/
/* Make sure that we handle the scope */
/*------ -----------------------------*/
if (SLPIntersectStringList(message->body.attrrqst.scopelistlen,
message->body.attrrqst.scopelist,
G_SlpdProperty.useScopesLen,
G_SlpdProperty.useScopes))
{
/*------------------------------------------------------------------*/
/* Make sure that we handle at least verify registrations made with */
/* the requested SPI. If we can't then have to return an error */
/* because there is no way we can return URL entries that ares */
/* signed in a way the requester can understand */
/*------------------------------------------------------------------*/
#ifdef ENABLE_SLPv2_SECURITY
if (G_SlpdProperty.securityEnabled)
{
if (message->body.attrrqst.taglistlen == 0)
{
/* We can send back entire attribute strings without */
/* generating a new attribute authentication block */
/* we just use the one sent by the registering agent */
/* which we have to have been able to verify */
if (SLPSpiCanVerify(G_SlpdSpiHandle,
message->body.attrrqst.spistrlen,
message->body.attrrqst.spistr) == 0)
{
errorcode = SLP_ERROR_AUTHENTICATION_UNKNOWN;
goto RESPOND;
}
}
else
{
/* We have to be able to *generate* (sign) authentication */
/* blocks for attrrqst with taglists since it is possible */
/* that the returned attributes are a subset of what the */
/* original registering agent sent */
if (SLPSpiCanSign(G_SlpdSpiHandle,
message->body.attrrqst.spistrlen,
message->body.attrrqst.spistr) == 0)
{
errorcode = SLP_ERROR_AUTHENTICATION_UNKNOWN;
goto RESPOND;
}
}
}
else
{
if (message->body.attrrqst.spistrlen)
{
errorcode = SLP_ERROR_AUTHENTICATION_UNKNOWN;
goto RESPOND;
}
}
#else
if (message->body.attrrqst.spistrlen)
{
errorcode = SLP_ERROR_AUTHENTICATION_UNKNOWN;
goto RESPOND;
}
#endif
/*---------------------------------*/
/* Find attributes in the database */
/*---------------------------------*/
errorcode = SLPDDatabaseAttrRqstStart(message,&db);
}
else
{
errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED;
}
RESPOND:
/*----------------------------------------------------------------*/
/* Do not send error codes or empty replies to multicast requests */
/*----------------------------------------------------------------*/
if (errorcode != 0 || db->attrlistlen == 0)
{
if (message->header.flags & SLP_FLAG_MCAST ||
ISMCAST(message->peer.sin_addr))
{
result->end = result->start;
goto FINISHED;
}
}
/*--------------------------------------------------------------*/
/* ensure the buffer is big enough to handle the whole attrrply */
/*--------------------------------------------------------------*/
size = message->header.langtaglen + 19; /* 14 bytes for header */
/* 2 bytes for error code */
/* 2 bytes for attr-list len */
/* 1 byte for the authcount */
if(errorcode == 0)
{
size += db->attrlistlen;
#ifdef ENABLE_SLPv2_SECURITY
/*------------------------------------------------------------------*/
/* Generate authblock if necessary or just use the one was included */
/* by registering agent. Reserve sufficent space for either case. */
/*------------------------------------------------------------------*/
if (G_SlpdProperty.securityEnabled &&
message->body.attrrqst.spistrlen )
{
if (message->body.attrrqst.taglistlen == 0)
{
for (i=0; i<db->authcount;i++)
{
if (SLPCompareString(db->autharray[i].spistrlen,
db->autharray[i].spistr,
message->body.attrrqst.spistrlen,
message->body.attrrqst.spistr) == 0)
{
opaqueauth = db->autharray[i].opaque;
opaqueauthlen = db->autharray[i].opaquelen;
break;
}
}
}
else
{
errorcode = SLPAuthSignString(G_SlpdSpiHandle,
message->body.attrrqst.spistrlen,
message->body.attrrqst.spistr,
db->attrlistlen,
db->attrlist,
&generatedauthlen,
&generatedauth);
opaqueauthlen = generatedauthlen;
opaqueauth = generatedauth;
}
size += opaqueauthlen;
}
#endif
}
/*-------------------*/
/* Alloc the buffer */
/*-------------------*/
result = SLPBufferRealloc(result,size);
if (result == 0)
{
errorcode = SLP_ERROR_INTERNAL_ERROR;
goto FINISHED;
}
/*----------------*/
/* Add the header */
/*----------------*/
/*version*/
*(result->start) = 2;
/*function id*/
*(result->start + 1) = SLP_FUNCT_ATTRRPLY;
/*length*/
ToUINT24(result->start + 2,size);
/*flags*/
ToUINT16(result->start + 5,
(size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0));
/*ext offset*/
ToUINT24(result->start + 7,0);
/*xid*/
ToUINT16(result->start + 10,message->header.xid);
/*lang tag len*/
ToUINT16(result->start + 12,message->header.langtaglen);
/*lang tag*/
memcpy(result->start + 14,
message->header.langtag,
message->header.langtaglen);
/*--------------------------*/
/* Add rest of the AttrRqst */
/*--------------------------*/
result->curpos = result->start + 14 + message->header.langtaglen;
/* error code*/
ToUINT16(result->curpos, errorcode);
result->curpos = result->curpos + 2;
if (errorcode == 0)
{
/* attr-list len */
ToUINT16(result->curpos, db->attrlistlen);
result->curpos = result->curpos + 2;
if (db->attrlistlen)
{
memcpy(result->curpos, db->attrlist, db->attrlistlen);
}
result->curpos = result->curpos + db->attrlistlen;
/* authentication block */
#ifdef ENABLE_SLPv2_SECURITY
if (opaqueauth)
{
/* authcount */
*(result->curpos) = 1;
result->curpos = result->curpos + 1;
memcpy(result->curpos,
opaqueauth,
opaqueauthlen);
result->curpos = result->curpos + opaqueauthlen;
}
else
#endif
{
/* authcount */
*(result->curpos) = 0;
result->curpos = result->curpos + 1;
}
}
FINISHED:
#ifdef ENABLE_SLPv2_SECURITY
/* free the generated authblock if any */
if (generatedauth) xfree(generatedauth);
#endif
if (db) SLPDDatabaseAttrRqstEnd(db);
*sendbuf = result;
return errorcode;
}
/*-------------------------------------------------------------------------*/
int ProcessDAAdvert(SLPMessage message,
SLPBuffer recvbuf,
SLPBuffer* sendbuf,
int errorcode)
/*-------------------------------------------------------------------------*/
{
SLPBuffer result = *sendbuf;
/*--------------------------------------------------------------*/
/* If errorcode is set, we can not be sure that message is good */
/* Go directly to send response code */
/*--------------------------------------------------------------*/
if (errorcode)
{
goto RESPOND;
}
/*--------------------------------------------------------------*/
/* If net.slp.passiveDADetection is turned off then we ignore */
/* DAAdverts with xid == 0 */
/*--------------------------------------------------------------*/
if(G_SlpdProperty.passiveDADetection == 0 &&
message->header.xid == 0)
{
goto RESPOND;
}
/*--------------------------------------------------------------*/
/* If net.slp.DAActiveDiscoveryInterval == 0 then we ignore */
/* DAAdverts with xid != 0 */
/*--------------------------------------------------------------*/
if(G_SlpdProperty.DAActiveDiscoveryInterval == 0 &&
message->header.xid != 0)
{
goto RESPOND;
}
/*-------------------------------*/
/* Validate the authblocks */
/*-------------------------------*/
#ifdef ENABLE_SLPv2_SECURITY
errorcode = SLPAuthVerifyDAAdvert(G_SlpdSpiHandle,
0,
&(message->body.daadvert));
if (errorcode == 0);
#endif
{
/* Only process if errorcode is not set */
if (message->body.daadvert.errorcode == SLP_ERROR_OK)
{
errorcode = SLPDKnownDAAdd(message,recvbuf);
}
}
RESPOND:
/* DAAdverts should never be replied to. Set result buffer to empty*/
result->end = result->start;
*sendbuf = result;
return errorcode;
}
/*-------------------------------------------------------------------------*/
int ProcessSrvTypeRqst(SLPMessage message,
SLPBuffer* sendbuf,
int errorcode)
/*-------------------------------------------------------------------------*/
{
int size = 0;
SLPDDatabaseSrvTypeRqstResult* db = 0;
SLPBuffer result = *sendbuf;
/*--------------------------------------------------------------*/
/* If errorcode is set, we can not be sure that message is good */
/* Go directly to send response code */
/*--------------------------------------------------------------*/
if (errorcode)
{
goto RESPOND;
}
/*-------------------------------------------------*/
/* Check for one of our IP addresses in the prlist */
/*-------------------------------------------------*/
if (SLPIntersectStringList(message->body.srvtyperqst.prlistlen,
message->body.srvtyperqst.prlist,
G_SlpdProperty.interfacesLen,
G_SlpdProperty.interfaces))
{
/* Silently ignore */
result->end = result->start;
goto FINISHED;
}
/*------------------------------------*/
/* Make sure that we handle the scope */
/*------ -----------------------------*/
if (SLPIntersectStringList(message->body.srvtyperqst.scopelistlen,
message->body.srvtyperqst.scopelist,
G_SlpdProperty.useScopesLen,
G_SlpdProperty.useScopes) != 0)
{
/*------------------------------------*/
/* Find service types in the database */
/*------------------------------------*/
errorcode = SLPDDatabaseSrvTypeRqstStart(message, &db);
}
else
{
errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED;
}
RESPOND:
/*----------------------------------------------------------------*/
/* Do not send error codes or empty replies to multicast requests */
/*----------------------------------------------------------------*/
if (errorcode != 0 || db->srvtypelistlen == 0)
{
if (message->header.flags & SLP_FLAG_MCAST ||
ISMCAST(message->peer.sin_addr))
{
result->end = result->start;
goto FINISHED;
}
}
/*-----------------------------------------------------------------*/
/* ensure the buffer is big enough to handle the whole srvtyperply */
/*-----------------------------------------------------------------*/
size = message->header.langtaglen + 18; /* 14 bytes for header */
/* 2 bytes for error code */
/* 2 bytes for srvtype
list length */
if(errorcode == 0)
{
size += db->srvtypelistlen;
}
/*------------------------------*/
/* Reallocate the result buffer */
/*------------------------------*/
result = SLPBufferRealloc(result,size);
if (result == 0)
{
errorcode = SLP_ERROR_INTERNAL_ERROR;
goto FINISHED;
}
/*----------------*/
/* Add the header */
/*----------------*/
/*version*/
*(result->start) = 2;
/*function id*/
*(result->start + 1) = SLP_FUNCT_SRVTYPERPLY;
/*length*/
ToUINT24(result->start + 2,size);
/*flags*/
ToUINT16(result->start + 5,
(size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0));
/*ext offset*/
ToUINT24(result->start + 7,0);
/*xid*/
ToUINT16(result->start + 10,message->header.xid);
/*lang tag len*/
ToUINT16(result->start + 12,message->header.langtaglen);
/*lang tag*/
memcpy(result->start + 14,
message->header.langtag,
message->header.langtaglen);
/*-----------------------------*/
/* Add rest of the SrvTypeRply */
/*-----------------------------*/
result->curpos = result->start + 14 + message->header.langtaglen;
/* error code*/
ToUINT16(result->curpos, errorcode);
result->curpos += 2;
if (errorcode == 0)
{
/* length of srvtype-list */
ToUINT16(result->curpos, db->srvtypelistlen);
result->curpos += 2;
memcpy(result->curpos,
db->srvtypelist,
db->srvtypelistlen);
result->curpos += db->srvtypelistlen;
}
FINISHED:
if (db) SLPDDatabaseSrvTypeRqstEnd(db);
*sendbuf = result;
return errorcode;
}
/*-------------------------------------------------------------------------*/
int ProcessSAAdvert(SLPMessage message,
SLPBuffer* sendbuf,
int errorcode)
/*-------------------------------------------------------------------------*/
{
/* Ignore all SAADVERTS */
(*sendbuf)->end = (*sendbuf)->start;
return errorcode;
}
/*=========================================================================*/
int SLPDProcessMessage(struct sockaddr_in* peerinfo,
SLPBuffer recvbuf,
SLPBuffer* sendbuf)
/* Processes the recvbuf and places the results in sendbuf */
/* */
/* peerinfo - the socket the message was received on */
/* */
/* recvbuf - message to process */
/* */
/* sendbuf - results of the processed message */
/* */
/* Returns - zero on success if sendbuf contains a response to send. */
/* non-zero if sendbuf does not contain a response to send */
/*=========================================================================*/
{
SLPHeader header;
SLPMessage message = 0;
int errorcode = 0;
SLPDLogMessage(SLPDLOG_TRACEMSG_IN,peerinfo,recvbuf);
if(!*sendbuf)
{
*sendbuf = SLPBufferAlloc(SLP_MAX_DATAGRAM_SIZE);
if (!*sendbuf)
return SLP_ERROR_PARSE_ERROR;
}
/* set the sendbuf empty */
(*sendbuf)->end = (*sendbuf)->start;
/* zero out the header before parsing it */
memset(&header,0,sizeof(header));
/* Parse just the message header */
recvbuf->curpos = recvbuf->start;
errorcode = SLPMessageParseHeader(recvbuf,&header);
/* Reset the buffer "curpos" pointer so that full message can be
* parsed later
*/
recvbuf->curpos = recvbuf->start;
#if defined(ENABLE_SLPv1)
/* if version == 1 then parse message as a version 1 message */
if (errorcode == SLP_ERROR_VER_NOT_SUPPORTED &&
header.version == 1)
{
errorcode = SLPDv1ProcessMessage(peerinfo,
recvbuf,
sendbuf);
}
else
#endif
if (errorcode == 0)
{
/* TRICKY: Duplicate SRVREG recvbufs *before* parsing them */
/* we do this because we are going to keep track of */
/* in the registration database */
if (header.functionid == SLP_FUNCT_SRVREG ||
header.functionid == SLP_FUNCT_DAADVERT )
{
recvbuf = SLPBufferDup(recvbuf);
if (recvbuf == NULL)
{
return SLP_ERROR_INTERNAL_ERROR;
}
}
/* Allocate the message descriptor */
message = SLPMessageAlloc();
if (message)
{
/* Parse the message and fill out the message descriptor */
errorcode = SLPMessageParseBuffer(peerinfo,recvbuf, message);
if (errorcode == 0)
{
/* Process messages based on type */
switch (message->header.functionid)
{
case SLP_FUNCT_SRVRQST:
errorcode = ProcessSrvRqst(message,sendbuf,errorcode);
break;
case SLP_FUNCT_SRVREG:
errorcode = ProcessSrvReg(message,recvbuf,sendbuf,errorcode);
if (errorcode == 0)
{
SLPDKnownDAEcho(message, recvbuf);
}
break;
case SLP_FUNCT_SRVDEREG:
errorcode = ProcessSrvDeReg(message,sendbuf,errorcode);
if (errorcode == 0)
{
SLPDKnownDAEcho(message, recvbuf);
}
break;
case SLP_FUNCT_SRVACK:
errorcode = ProcessSrvAck(message,sendbuf, errorcode);
break;
case SLP_FUNCT_ATTRRQST:
errorcode = ProcessAttrRqst(message,sendbuf, errorcode);
break;
case SLP_FUNCT_DAADVERT:
errorcode = ProcessDAAdvert(message,
recvbuf,
sendbuf,
errorcode);
break;
case SLP_FUNCT_SRVTYPERQST:
errorcode = ProcessSrvTypeRqst(message, sendbuf, errorcode);
break;
case SLP_FUNCT_SAADVERT:
errorcode = ProcessSAAdvert(message, sendbuf, errorcode);
break;
default:
/* Should never happen... but we're paranoid */
errorcode = SLP_ERROR_PARSE_ERROR;
break;
}
}
else
{
SLPDLogParseWarning(peerinfo, recvbuf);
}
if (header.functionid == SLP_FUNCT_SRVREG ||
header.functionid == SLP_FUNCT_DAADVERT )
{
/* TRICKY: If this is a reg or daadvert message we do not
* free the message descriptor or duplicated recvbuf
* because they are being kept in the database!
*
*/
if (errorcode == 0)
{
goto FINISHED;
}
/* TRICKY: If there is an error we need to free the
* duplicated recvbuf,
*/
SLPBufferFree(recvbuf);
}
SLPMessageFree(message);
}
else
{
/* out of memory */
errorcode = SLP_ERROR_INTERNAL_ERROR;
}
}
else
{
SLPDLogParseWarning(peerinfo,recvbuf);
}
FINISHED:
#ifdef DEBUG
if (errorcode)
{
SLPDLog("\n*** DEBUG *** errorcode %i during processing of message from %s\n",
errorcode,
inet_ntoa(peerinfo->sin_addr));
}
#endif
/* Log message silently ignored because of an error */
if(errorcode)
{
if (*sendbuf == 0 ||
(*sendbuf)->end == (*sendbuf)->start )
{
SLPDLogMessage(SLPDLOG_TRACEDROP,peerinfo,recvbuf);
}
}
/* Log trace message */
SLPDLogMessage(SLPDLOG_TRACEMSG_OUT, peerinfo, *sendbuf);
return errorcode;
}