/**************************************************************************/ /* */ /* 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;iurlcount;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; jauthcount;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;iurlcount;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; iauthcount;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; }