/*-------------------------------------------------------------------------*/ int KnownDAListAdd(SLPList* dalist, SLPDAEntry* addition) /* Add an entry to the KnownDA cache */ /* */ /* Returns: zero if DA was already in the list. >0 if DA was new */ /*-------------------------------------------------------------------------*/ { SLPDAEntry* entry; entry = (SLPDAEntry*)dalist->head; while(entry) { if(SLPCompareString(addition->urllen, addition->url, entry->urllen, entry->url) == 0) { /* entry already in the list */ break; } entry = (SLPDAEntry*) entry->listitem.next; } if(entry == 0) { /* Add the entry if it does not exist */ SLPListLinkHead(dalist,(SLPListItem*)addition); return 1; } /* entry already in the list */ return 0; }
/*-------------------------------------------------------------------------*/ int KnownDAAdd(SLPMessage msg, SLPBuffer buf) /* Add an entry to the KnownDA cache */ /* */ /* Returns: zero on success, non-zero on error */ /*-------------------------------------------------------------------------*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; SLPDAAdvert* entrydaadvert; SLPDAAdvert* daadvert; int result; result = 0; dh = SLPDatabaseOpen(&G_KnownDACache); if(dh) { /* daadvert is the DAAdvert message being added */ daadvert = &(msg->body.daadvert); /*-----------------------------------------------------*/ /* Check to see if there is already an identical entry */ /*-----------------------------------------------------*/ while(1) { entry = SLPDatabaseEnum(dh); if(entry == NULL) break; /* entrydaadvert is the DAAdvert message from the database */ entrydaadvert = &(entry->msg->body.daadvert); /* Assume DAs are identical if their URLs match */ if(SLPCompareString(entrydaadvert->urllen, entrydaadvert->url, daadvert->urllen, daadvert->url) == 0) { SLPDatabaseRemove(dh,entry); break; } } /* Create and link in a new entry */ entry = SLPDatabaseEntryCreate(msg,buf); if(entry) { SLPDatabaseAdd(dh, entry); } else { result = SLP_MEMORY_ALLOC_FAILED; } SLPDatabaseClose(dh); } return result; }
/** Checks a string-list for the occurence of a string * * @param[in] list - A pointer to the string-list to be checked. * @param[in] listlen - The length in bytes of @p list. * @param[in] string - A pointer to a string to find in @p list. * @param[in] stringlen - The length in bytes of @p string. * * @return Zero if @p string is NOT contained in @p list; * A non-zero value if it is. * * @internal */ static int SLPIfaceContainsAddr(size_t listlen, const char * list, size_t stringlen, const char * string) { char * listend = (char *) list + listlen; char * itembegin = (char *) list; char * itemend = itembegin; struct sockaddr_storage addr; char buffer[INET6_ADDRSTRLEN]; /* must be at least 40 characters */ int buffer_len; while (itemend < listend) { itembegin = itemend; /* seek to the end of the next list item */ while (1) { if (itemend == listend || *itemend == ',') if (*(itemend - 1) != '\\') break; itemend ++; } if (itemend - itembegin < sizeof(buffer)) buffer_len = (int)(itemend - itembegin); else buffer_len = sizeof(buffer); strncpy(buffer, itembegin, buffer_len); buffer[itemend - itembegin] = '\0'; if (SLPNetIsIPV6() && inet_pton(AF_INET6, buffer, &addr) == 1) { inet_ntop(AF_INET6, &addr, buffer, sizeof(buffer)); if (SLPCompareString(strlen(buffer), buffer, stringlen, string) == 0) return 1; } else if (SLPNetIsIPV4() && inet_pton(AF_INET, buffer, &addr) == 1) { inet_ntop(AF_INET, &addr, buffer, sizeof(buffer)); if (SLPCompareString(strlen(buffer), buffer, stringlen, string) == 0) return 1; } itemend ++; } return 0; }
/*=========================================================================*/ int SLPContainsStringList(int listlen, const char* list, int stringlen, const char* string) /* Checks a string-list for the occurence of a string */ /* */ /* list - pointer to the string-list to be checked */ /* */ /* listlen - length in bytes of the list to be checked */ /* */ /* string - pointer to a string to find in the string-list */ /* */ /* stringlen - the length of the string in bytes */ /* */ /* Returns - zero if string is NOT contained in the list. non-zero if it*/ /* is. */ /*=========================================================================*/ { char* listend = (char*)list + listlen; char* itembegin = (char*)list; char* itemend = itembegin; while(itemend < listend) { itembegin = itemend; /* seek to the end of the next list item */ while(1) { if(itemend == listend || *itemend == ',') { if (*(itemend - 1) != '\\') { break; } } itemend ++; } if(SLPCompareString(itemend - itembegin, itembegin, stringlen, string) == 0) { return 1; } itemend ++; } return 0; }
/*=========================================================================*/ int SLPDDatabaseFindAttr(SLPAttrRqst* attrrqst, SLPDDatabaseAttr* result, int count) /* Find attributes */ /* */ /* srvtyperqst (IN) the request to find. */ /* */ /* result (OUT) pointer to a result structure that receives */ /* results */ /* */ /* count (IN) number of elements in the result array */ /* */ /* Returns - >0 on success. 0 if the url of the attrrqst could not be */ /* cound and <0 on error. */ /*=========================================================================*/ { SLPDDatabaseEntry* entry = 0; int found = 0; /* TODO: Do we ever want to handle passing back all of the attributes */ /* for service types? */ found = 0; entry = (SLPDDatabaseEntry*)G_DatabaseList.head; while(entry) { if(SLPCompareString(attrrqst->urllen, attrrqst->url, entry->urllen, entry->url) == 0 || SLPCompareSrvType(attrrqst->urllen, attrrqst->url, entry->srvtypelen, entry->srvtype) == 0 ) { if(SLPIntersectStringList(attrrqst->scopelistlen, attrrqst->scopelist, entry->scopelistlen, entry->scopelist)) { result[found].attrlen = entry->attrlistlen; result[found].attr = entry->attrlist; found++; break; } } entry = (SLPDDatabaseEntry*)entry->listitem.next; } return found; }
/*-------------------------------------------------------------------------*/ SLPBoolean KnownDAListFind(int scopelistlen, const char* scopelist, int spistrlen, const char* spistr, struct in_addr* daaddr) /* Returns: non-zero on success, zero if DA can not be found */ /*-------------------------------------------------------------------------*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; int result = SLP_FALSE; dh = SLPDatabaseOpen(&G_KnownDACache); if(dh) { /*----------------------------------------*/ /* Check to see if there a matching entry */ /*----------------------------------------*/ while(1) { entry = SLPDatabaseEnum(dh); if(entry == NULL) break; /* Check scopes */ if(SLPSubsetStringList(entry->msg->body.daadvert.scopelistlen, entry->msg->body.daadvert.scopelist, scopelistlen, scopelist)) { #ifdef ENABLE_SLPv2_SECURITY if(SLPCompareString(entry->msg->body.daadvert.spilistlen, entry->msg->body.daadvert.spilist, spistrlen, spistr) == 0) #endif { memcpy(daaddr, &(entry->msg->peer.sin_addr), sizeof(struct in_addr)); result = SLP_TRUE; } } } SLPDatabaseClose(dh); } return result; }
/*=========================================================================*/ int SLPDDatabaseDeReg(SLPSrvDeReg* srvdereg) /* Remove a service registration from the database */ /* */ /* regfile - (IN) filename of the registration file to read into the */ /* database. Pass in NULL for no file. */ /* */ /* Returns - Zero on success. Non-zero if syntax error in registration */ /* file. */ /*=========================================================================*/ { SLPDDatabaseEntry* del = 0; SLPDDatabaseEntry* entry = (SLPDDatabaseEntry*)G_DatabaseList.head; while(entry) { if(SLPCompareString(entry->urllen, entry->url, srvdereg->urlentry.urllen, srvdereg->urlentry.url) == 0) { if(SLPIntersectStringList(entry->scopelistlen, entry->scopelist, srvdereg->scopelistlen, srvdereg->scopelist) > 0) { if(G_SlpdProperty.traceReg) { SLPDLogTraceReg("SrvDeReg",entry); } del = entry; break; } } entry = (SLPDDatabaseEntry*) entry->listitem.next; if(del) { FreeEntry((SLPDDatabaseEntry*)SLPListUnlink(&G_DatabaseList,(SLPListItem*)del)); del = 0; } } return 0; }
/** Scan a string list for a string. * * Determine if a specified string list contains a specified string. * * @param[in] list - A list of strings to search for @p string. * @param[in] listlen - The length of @p list in bytes. * @param[in] string - A string to locate in @p list. * @param[in] stringlen - The length of @p string in bytes. * * @return 1-based index of position of @p string in @p list; zero if not in list. * * @remarks The @p list parameter is a zero-terminated string consisting * of a comma-separated list of sub-strings. This routine actually * determines if a specified sub-string (@p string) matches one of * the sub-strings in this list. */ int SLPContainsStringList(size_t listlen, const char * list, size_t stringlen, const char * string) { const char * listend = list + listlen; const char * itembegin = list; const char * itemend = itembegin; while (itemend < listend) { itembegin = itemend; /* Seek to the end of the next list item, break on commas. */ while (itemend != listend && itemend[0] != ',') itemend++; if (SLPCompareString(itemend - itembegin, itembegin, stringlen, string) == 0) return (int)(1 + (itembegin - list)); /* 1-based index of the position of the string in the list */ itemend++; } return 0; }
/*-------------------------------------------------------------------------*/ int KnownDAListRemove(SLPList* dalist, SLPDAEntry* remove) /* Remove an entry to the KnownDA cach */ /*-------------------------------------------------------------------------*/ { SLPDAEntry* entry; entry = (SLPDAEntry*)dalist->head; while(entry) { if(SLPCompareString(remove->urllen, remove->url, entry->urllen, entry->url) == 0) { /* Remove entry from list and free it */ SLPDAEntryFree( (SLPDAEntry*)SLPListUnlink(dalist, (SLPListItem*)entry) ); break; } entry = (SLPDAEntry*) entry->listitem.next; } return 0; }
/** Process a general attribute request message. * * @param[in] message - The message to process. * @param[out] sendbuf - The response buffer to fill. * @param[in] errorcode - The error code from the client request. * * @return Zero on success, or a non-zero SLP error on failure. * * @internal */ static int ProcessAttrRqst(SLPMessage * message, SLPBuffer * sendbuf, int errorcode) { SLPDDatabaseAttrRqstResult * db = 0; size_t size = 0; SLPBuffer result = *sendbuf; #ifdef ENABLE_SLPv2_SECURITY int i; uint8_t * generatedauth = 0; int generatedauthlen = 0; uint8_t * 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 || SLPNetIsMCast(&(message->peer))) { 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->curpos++ = 2; /* function id */ *result->curpos++ = SLP_FUNCT_ATTRRPLY; /* length */ PutUINT24(&result->curpos, size); /* flags */ PutUINT16(&result->curpos, (size > (size_t)G_SlpdProperty.MTU? SLP_FLAG_OVERFLOW: 0)); /* ext offset */ PutUINT24(&result->curpos, 0); /* xid */ PutUINT16(&result->curpos, message->header.xid); /* lang tag len */ PutUINT16(&result->curpos, message->header.langtaglen); /* lang tag */ memcpy(result->curpos, message->header.langtag, message->header.langtaglen); result->curpos += message->header.langtaglen; /* Add rest of the AttrRqst */ /* error code*/ PutUINT16(&result->curpos, errorcode); if (errorcode == 0) { /* attr-list len */ PutUINT16(&result->curpos, db->attrlistlen); if (db->attrlistlen) memcpy(result->curpos, db->attrlist, db->attrlistlen); result->curpos += db->attrlistlen; /* authentication block */ #ifdef ENABLE_SLPv2_SECURITY if (opaqueauth) { /* authcount */ *result->curpos++ = 1; memcpy(result->curpos, opaqueauth, opaqueauthlen); result->curpos += opaqueauthlen; } else #endif *result->curpos++ = 0; /* authcount */ } FINISHED: #ifdef ENABLE_SLPv2_SECURITY /* free the generated authblock if any */ xfree(generatedauth); #endif if (db) SLPDDatabaseAttrRqstEnd(db); *sendbuf = result; return errorcode; }
/*=========================================================================*/ int SLPDDatabaseSrvRqstStart(SLPMessage msg, SLPDDatabaseSrvRqstResult** result) /* Find services in the database */ /* */ /* msg (IN) the SrvRqst to find. */ /* */ /* result (OUT) pointer result structure */ /* */ /* Returns - Zero on success. Non-zero on failure */ /* */ /* Note: Caller must pass *result to SLPDDatabaseSrvRqstEnd() to free */ /*=========================================================================*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; SLPSrvReg* entryreg; SLPSrvRqst* srvrqst; #ifdef ENABLE_SLPv2_SECURITY int i; #endif /* start with the result set to NULL just to be safe */ *result = NULL; dh = SLPDatabaseOpen(&G_SlpdDatabase.database); if ( dh ) { /* srvrqst is the SrvRqst being made */ srvrqst = &(msg->body.srvrqst); while ( 1 ) { /*-----------------------------------------------------------*/ /* Allocate result with generous array of url entry pointers */ /*-----------------------------------------------------------*/ *result = (SLPDDatabaseSrvRqstResult*) xrealloc(*result, sizeof(SLPDDatabaseSrvRqstResult) + (sizeof(SLPUrlEntry*) * G_SlpdDatabase.urlcount)); if ( *result == NULL ) { /* out of memory */ SLPDatabaseClose(dh); return SLP_ERROR_INTERNAL_ERROR; } (*result)->urlarray = (SLPUrlEntry**)((*result) + 1); (*result)->urlcount = 0; (*result)->reserved = dh; /*-------------------------------------------------*/ /* Rewind enumeration in case we had to reallocate */ /*-------------------------------------------------*/ SLPDatabaseRewind(dh); /*-----------------------------------------*/ /* Check to see if there is matching entry */ /*-----------------------------------------*/ while ( 1 ) { entry = SLPDatabaseEnum(dh); if ( entry == NULL ) { /* This is the only successful way out */ return 0; } /* entry reg is the SrvReg message from the database */ entryreg = &(entry->msg->body.srvreg); /* check the service type */ if ( SLPCompareSrvType(srvrqst->srvtypelen, srvrqst->srvtype, entryreg->srvtypelen, entryreg->srvtype) == 0 && SLPIntersectStringList(entryreg->scopelistlen, entryreg->scopelist, srvrqst->scopelistlen, srvrqst->scopelist) > 0 ) { #ifdef ENABLE_PREDICATES if ( SLPDPredicateTest(msg->header.version, entryreg->attrlistlen, entryreg->attrlist, srvrqst->predicatelen, srvrqst->predicate) ) #endif { #ifdef ENABLE_SLPv2_SECURITY if ( srvrqst->spistrlen ) { for ( i=0; i< entryreg->urlentry.authcount;i++ ) { if ( SLPCompareString(srvrqst->spistrlen, srvrqst->spistr, entryreg->urlentry.autharray[i].spistrlen, entryreg->urlentry.autharray[i].spistr) == 0 ) { break; } } if ( i == entryreg->urlentry.authcount ) { continue; } } #endif if ( (*result)->urlcount + 1 > G_SlpdDatabase.urlcount ) { /* Oops we did not allocate a big enough result */ G_SlpdDatabase.urlcount *= 2; break; } (*result)->urlarray[(*result)->urlcount] = &(entryreg->urlentry); (*result)->urlcount ++; } } } } } return 0; }
/** Process a general service request message. * * @param[in] message - The message to process. * @param[out] sendbuf - The response buffer to fill. * @param[in] errorcode - The error code from the client request. * * @return Zero on success, or a non-zero SLP error on failure. * * @internal */ static int ProcessSrvRqst(SLPMessage * message, SLPBuffer * sendbuf, int errorcode) { int i; SLPUrlEntry * urlentry; SLPDDatabaseSrvRqstResult * db = 0; size_t 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 are 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) 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 || SLPNetIsMCast(&(message->peer))) { 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->curpos++ = 2; /* function id */ *result->curpos++ = SLP_FUNCT_SRVRPLY; /* length */ PutUINT24(&result->curpos, size); /* flags */ PutUINT16(&result->curpos, (size > (size_t)G_SlpdProperty.MTU? SLP_FLAG_OVERFLOW: 0)); /* ext offset */ PutUINT24(&result->curpos, 0); /* xid */ PutUINT16(&result->curpos, message->header.xid); /* lang tag len */ PutUINT16(&result->curpos, message->header.langtaglen); /* lang tag */ memcpy(result->curpos, message->header.langtag, message->header.langtaglen); result->curpos += message->header.langtaglen; /* add rest of the SrvRply */ /* error code*/ PutUINT16(&result->curpos, errorcode); if (errorcode == 0) { /* urlentry count */ PutUINT16(&result->curpos, db->urlcount); 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; /* url-entry lifetime */ PutUINT16(&result->curpos, urlentry->lifetime); /* url-entry urllen */ PutUINT16(&result->curpos, urlentry->urllen); /* url-entry url */ memcpy(result->curpos, urlentry->url, urlentry->urllen); result->curpos += urlentry->urllen; /* url-entry auths */ *result->curpos++ = 0; } else #endif { /* Use an opaque copy if available (and authentication is * not being used). */ /* TRICKY: Fix up the lifetime. */ TO_UINT16(urlentry->opaque + 1, urlentry->lifetime); memcpy(result->curpos, urlentry->opaque, urlentry->opaquelen); result->curpos += urlentry->opaquelen; } } } else PutUINT16(&result->curpos, 0); /* set urlentry count to 0*/ FINISHED: if (db) SLPDDatabaseSrvRqstEnd(db); *sendbuf = result; return errorcode; }
/*-------------------------------------------------------------------------*/ int ProcessSrvRqst(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /*-------------------------------------------------------------------------*/ { int i; int size = 0; int count = 0; int found = 0; SLPDDatabaseSrvUrl* srvarray = 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.srvrqst.prlistlen, message->body.srvrqst.prlist, G_SlpdProperty.interfacesLen, G_SlpdProperty.interfaces)) { result->end = result->start; goto FINISHED; } /*------------------------------------------------*/ /* Check to to see if a this is a special SrvRqst */ /*------------------------------------------------*/ if(SLPCompareString(message->body.srvrqst.srvtypelen, message->body.srvrqst.srvtype, 23, "service:directory-agent") == 0) { errorcode = ProcessDASrvRqst(peeraddr, message, sendbuf, errorcode); return errorcode; } if(SLPCompareString(message->body.srvrqst.srvtypelen, message->body.srvrqst.srvtype, 21, "service:service-agent") == 0) { errorcode = ProcessSASrvRqst(peeraddr, message, sendbuf, errorcode); return errorcode; } /* TODO: check the spi list of the message and return */ /* AUTHENTICATION_UNKNOWN since we do not do authentication yet */ /*------------------------------------*/ /* 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 */ /*-------------------------------*/ while(found == count) { count += G_SlpdProperty.maxResults; if(srvarray) free(srvarray); srvarray = (SLPDDatabaseSrvUrl*)malloc(sizeof(SLPDDatabaseSrvUrl) * count); if(srvarray == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } found = SLPDDatabaseFindSrv(&(message->body.srvrqst), srvarray, count); if(found < 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } } /* remember the amount found if is really big for next time */ if(found > G_SlpdProperty.maxResults) { G_SlpdProperty.maxResults = found; } } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } RESPOND: /*----------------------------------------------------------------*/ /* Do not send error codes or empty replies to multicast requests */ /*----------------------------------------------------------------*/ if(found == 0 || errorcode != 0) { if(message->header.flags & SLP_FLAG_MCAST || ISMCAST(peeraddr->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<found;i++) { size += srvarray[i].urllen + 6; /* 1 byte for reserved */ /* 2 bytes for lifetime */ /* 2 bytes for urllen */ /* 1 byte for authcount */ /* TODO: Fix this for authentication */ } result = SLPBufferRealloc(result,size); if(result == 0) { found = 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; /* urlentry count */ ToUINT16(result->curpos, found); result->curpos = result->curpos + 2; for(i=0;i<found;i++) { /* url-entry reserved */ *result->curpos = 0; result->curpos = result->curpos + 1; /* url-entry lifetime */ ToUINT16(result->curpos,srvarray[i].lifetime); result->curpos = result->curpos + 2; /* url-entry urllen */ ToUINT16(result->curpos,srvarray[i].urllen); result->curpos = result->curpos + 2; /* url-entry url */ memcpy(result->curpos,srvarray[i].url,srvarray[i].urllen); result->curpos = result->curpos + srvarray[i].urllen; /* url-entry authcount */ *result->curpos = 0; result->curpos = result->curpos + 1; /* TODO: put in authentication stuff too */ } FINISHED: if(srvarray) free(srvarray); *sendbuf = result; return errorcode; }
/*=========================================================================*/ int SLPDDatabaseAttrRqstStart(SLPMessage msg, SLPDDatabaseAttrRqstResult** result) /* Find attributes in the database */ /* */ /* msg (IN) the AttrRqst to find. */ /* */ /* result (OUT) pointer result structure */ /* */ /* Returns - Zero on success. Non-zero on failure */ /* */ /* Note: Caller must pass *result to SLPDDatabaseAttrRqstEnd() to */ /* free */ /*=========================================================================*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; SLPSrvReg* entryreg; SLPAttrRqst* attrrqst; #ifdef ENABLE_SLPv2_SECURITY int i; #endif *result = xmalloc(sizeof(SLPDDatabaseAttrRqstResult)); if ( *result == NULL ) { return SLP_ERROR_INTERNAL_ERROR; } memset(*result,0,sizeof(SLPDDatabaseAttrRqstResult)); dh = SLPDatabaseOpen(&G_SlpdDatabase.database); if ( dh ) { (*result)->reserved = dh; /* attrrqst is the AttrRqst being made */ attrrqst = &(msg->body.attrrqst); while ( 1 ) { entry = SLPDatabaseEnum(dh); if ( entry == NULL ) { return 0; } /* entry reg is the SrvReg message from the database */ entryreg = &(entry->msg->body.srvreg); if ( SLPCompareString(attrrqst->urllen, attrrqst->url, entryreg->urlentry.urllen, entryreg->urlentry.url) == 0 || SLPCompareSrvType(attrrqst->urllen, attrrqst->url, entryreg->srvtypelen, entryreg->srvtype) == 0 ) { if ( SLPIntersectStringList(attrrqst->scopelistlen, attrrqst->scopelist, entryreg->scopelistlen, entryreg->scopelist) ) { if ( attrrqst->taglistlen == 0 ) { #ifdef ENABLE_SLPv2_SECURITY if ( attrrqst->spistrlen ) { for ( i=0; i< entryreg->authcount;i++ ) { if ( SLPCompareString(attrrqst->spistrlen, attrrqst->spistr, entryreg->autharray[i].spistrlen, entryreg->autharray[i].spistr) == 0 ) { break; } } if ( i == entryreg->authcount ) { continue; } } #endif /* Send back what was registered */ (*result)->attrlistlen = entryreg->attrlistlen; (*result)->attrlist = (char*)entryreg->attrlist; (*result)->authcount = entryreg->authcount; (*result)->autharray = entryreg->autharray; } #ifdef ENABLE_PREDICATES else { /* Send back a partial list as specified by taglist */ if ( SLPDFilterAttributes(entryreg->attrlistlen, entryreg->attrlist, attrrqst->taglistlen, attrrqst->taglist, &(*result)->attrlistlen, &(*result)->attrlist) == 0 ) { (*result)->ispartial = 1; break; } } #endif } } } } return 0; }
/*-------------------------------------------------------------------------*/ void ProcessSrvRqst(SLPDPeerInfo* peerinfo, SLPMessage message, SLPBuffer result) /*-------------------------------------------------------------------------*/ { int i; int size = 0; int count = 0; int found = 0; SLPDDatabaseSrvUrl* srvarray = 0; int errorcode = 0; /*-------------------------------------------------*/ /* 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)) { result->end = result->start; goto FINISHED; } /*------------------------------------------------*/ /* Check to to see if a this is a special SrvRqst */ /*------------------------------------------------*/ if(SLPCompareString(message->body.srvrqst.srvtypelen, message->body.srvrqst.srvtype, 23, "service:directory-agent") == 0) { ProcessDASrvRqst(peerinfo, message, result); goto FINISHED; } if(SLPCompareString(message->body.srvrqst.srvtypelen, message->body.srvrqst.srvtype, 21, "service:service-agent") == 0) { ProcessSASrvRqst(peerinfo, message, result); goto FINISHED; } /*------------------------------------*/ /* 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 */ /*-------------------------------*/ while(found == count) { count += SLPDPROCESS_RESULT_COUNT; if(srvarray) free(srvarray); srvarray = (SLPDDatabaseSrvUrl*)malloc(sizeof(SLPDDatabaseSrvUrl) * count); if(srvarray == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } found = SLPDDatabaseFindSrv(&(message->body.srvrqst), srvarray, count); if(found < 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } } } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } /*----------------------------------------------------------------*/ /* Do not send error codes or empty replies to multicast requests */ /*----------------------------------------------------------------*/ if(found <= 0 && (message->header.flags & SLP_FLAG_MCAST)) { 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 */ for(i=0;i<found;i++) { size += srvarray[i].urllen + 6; /* 1 byte for reserved */ /* 2 bytes for lifetime */ /* 2 bytes for urllen */ /* 1 byte for authcount */ /* TODO: Fix this for authentication */ } result = SLPBufferRealloc(result,size); if(result == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; } /*----------------*/ /* 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; /* urlentry count */ ToUINT16(result->curpos, found); result->curpos = result->curpos + 2; for(i=0;i<found;i++) { /* url-entry reserved */ *result->curpos = 0; result->curpos = result->curpos + 1; /* url-entry lifetime */ ToUINT16(result->curpos,srvarray[i].lifetime); result->curpos = result->curpos + 2; /* url-entry urllen */ ToUINT16(result->curpos,srvarray[i].urllen); result->curpos = result->curpos + 2; /* url-entry url */ memcpy(result->curpos,srvarray[i].url,srvarray[i].urllen); result->curpos = result->curpos + srvarray[i].urllen; /* url-entry authcount */ *result->curpos = 0; result->curpos = result->curpos + 1; /* TODO: put in authentication stuff too */ } FINISHED: if(srvarray) free(srvarray); }
/*=========================================================================*/ int SLPDDatabaseReg(SLPSrvReg* srvreg, unsigned int regtype) /* Add a service registration to the database */ /* */ /* srvreg - (IN) pointer to the SLPSrvReg to be added to the database */ /* */ /* regtype - (IN) registration types or'ed together: */ /* SLPDDATABASE_REG_FRESH */ /* SLPDDATABASE_REG_LOCAL */ /* SLPDDATABASE_REG_STATIC */ /* */ /* Returns - Zero on success. > 0 if something is wrong with srvreg */ /* < 0 if out of memory */ /* */ /* NOTE: All registrations are treated as fresh regardless of the */ /* setting of the fresh parameter */ /*=========================================================================*/ { int result = -1; SLPDDatabaseEntry* entry = (SLPDDatabaseEntry*)G_DatabaseList.head; /* Check to see if there is already an identical entry */ while(entry) { if(SLPCompareString(entry->urllen, entry->url, srvreg->urlentry.urllen, srvreg->urlentry.url) == 0) { if(SLPIntersectStringList(entry->scopelistlen, entry->scopelist, srvreg->scopelistlen, srvreg->scopelist) > 0) { SLPListUnlink(&G_DatabaseList,(SLPListItem*)entry); break; } } entry = (SLPDDatabaseEntry*) entry->listitem.next; } /* if no identical entry are found, create a new one */ if(entry == 0) { entry = SLPDDatabaseEntryAlloc(); if(entry == 0) { /* Out of memory */ goto FAILURE; } } /*----------------------------------------------------------------*/ /* copy info from the message from the wire to the database entry */ /*----------------------------------------------------------------*/ /* scope */ if(entry->scopelistlen >= srvreg->scopelistlen) { memcpy(entry->scopelist,srvreg->scopelist,srvreg->scopelistlen); } else { if(entry->scopelist) free(entry->scopelist); entry->scopelist = (char*)memdup(srvreg->scopelist,srvreg->scopelistlen); if(entry->scopelist == 0) goto FAILURE; } entry->scopelistlen = srvreg->scopelistlen; /* URL */ if(entry->urllen >= srvreg->urlentry.urllen) { memcpy(entry->url,srvreg->urlentry.url,srvreg->urlentry.urllen); } else { if(entry->url) free(entry->url); entry->url = (char*)memdup(srvreg->urlentry.url,srvreg->urlentry.urllen); if(entry->url == 0) goto FAILURE; } entry->urllen = srvreg->urlentry.urllen; /* lifetime */ entry->lifetime = srvreg->urlentry.lifetime; /* is local */ entry->regtype = regtype; /* SrvType */ if(entry->srvtypelen >= srvreg->srvtypelen) { memcpy(entry->srvtype,srvreg->srvtype,srvreg->srvtypelen); } else { if(entry->srvtype) free(entry->srvtype); entry->srvtype = (char*)memdup(srvreg->srvtype,srvreg->srvtypelen); if(entry->srvtype == 0) goto FAILURE; } entry->srvtypelen = srvreg->srvtypelen; /* Attributes */ if(srvreg->attrlistlen) { #ifdef USE_PREDICATES /* Tricky: perform an in place null termination of the attrlist */ /* Remember this squishes the authblock count */ ((char*)srvreg->attrlist)[srvreg->attrlistlen] = 0; if(SLPAttrFreshen(entry->attr, srvreg->attrlist) != SLP_OK) { result = 1; goto FAILURE; } /* Serialize all attributes into entry->attrlist */ if(entry->attrlist) { free(entry->attrlist); entry->attrlist = 0; entry->attrlistlen = 0; } if(SLPAttrSerialize(entry->attr, "", &entry->attrlist, entry->attrlistlen, &entry->attrlistlen, SLP_FALSE)) { goto FAILURE; } #else if(entry->attrlistlen >= srvreg->attrlistlen) { memcpy(entry->attrlist,srvreg->attrlist,srvreg->attrlistlen); } else { if(entry->attrlist) free(entry->attrlist); entry->attrlist = memdup(srvreg->attrlist,srvreg->attrlistlen); if(entry->attrlist == 0) goto FAILURE; } entry->attrlistlen = srvreg->attrlistlen; #endif } /* link the new (or modified) entry into the list */ SLPListLinkHead(&G_DatabaseList,(SLPListItem*)entry); /* traceReg if necessary */ SLPDLogTraceReg("Registered", entry); return 0; FAILURE: if(entry) { SLPDDatabaseEntryFree(entry); } return result; }
/*=========================================================================*/ int SLPDDatabaseDeReg(SLPMessage msg) /* Remove a service registration from the database */ /* */ /* msg - (IN) message interpreting an SrvDereg message */ /* */ /* Returns - Zero on success. Non-zero on failure */ /*=========================================================================*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; SLPSrvReg* entryreg; SLPSrvDeReg* dereg; dh = SLPDatabaseOpen(&G_SlpdDatabase.database); if ( dh ) { /* dereg is the SrvDereg being deregistered */ dereg = &(msg->body.srvdereg); /*---------------------------------------------*/ /* Check to see if there is an identical entry */ /*---------------------------------------------*/ while ( 1 ) { entry = SLPDatabaseEnum(dh); if ( entry == NULL ) break; /* entry reg is the SrvReg message from the database */ entryreg = &(entry->msg->body.srvreg); if ( SLPCompareString(entryreg->urlentry.urllen, entryreg->urlentry.url, dereg->urlentry.urllen, dereg->urlentry.url) == 0 ) { if ( SLPIntersectStringList(entryreg->scopelistlen, entryreg->scopelist, dereg->scopelistlen, dereg->scopelist) > 0 ) { /* Check to ensure the source addr is the same as */ /* the original */ if ( G_SlpdProperty.checkSourceAddr && memcmp(&(entry->msg->peer.sin_addr), &(msg->peer.sin_addr), sizeof(struct in_addr)) ) { SLPDatabaseClose(dh); return SLP_ERROR_AUTHENTICATION_FAILED; } #ifdef ENABLE_SLPv2_SECURITY if ( entryreg->urlentry.authcount && entryreg->urlentry.authcount != dereg->urlentry.authcount ) { SLPDatabaseClose(dh); return SLP_ERROR_AUTHENTICATION_FAILED; } #endif /* remove the registration from the database */ SLPDatabaseRemove(dh,entry); SLPDLogRegistration("Deregistration",entry); break; } } } SLPDatabaseClose(dh); if ( entry==NULL ) { return SLP_ERROR_INVALID_REGISTRATION; } } return 0; }
/*=========================================================================*/ int SLPDDatabaseFindType(SLPSrvTypeRqst* srvtyperqst, SLPDDatabaseSrvType* result, int count) /* Find service types */ /* */ /* srvtyperqst (IN) the request to find. */ /* */ /* result (OUT) pointer to an array of result structures that receives */ /* results */ /* */ /* count (IN) number of elements in the result array */ /* */ /* Returns - The number of srvtypes found or <0 on error. If the number */ /* of srvtypes found is exactly equal to the number of elements */ /* in the array, the call may be repeated with a larger array. */ /*=========================================================================*/ { SLPDDatabaseEntry* entry; int found; int i; found = 0; entry = (SLPDDatabaseEntry*)G_DatabaseList.head; while(entry) { if(SLPCompareNamingAuth(entry->srvtypelen, entry->srvtype, srvtyperqst->namingauthlen, srvtyperqst->namingauth) == 0) { if(SLPIntersectStringList(srvtyperqst->scopelistlen, srvtyperqst->scopelist, entry->scopelistlen, entry->scopelist)) { for(i = 0; i < found; i++) { if(SLPCompareString(result[i].typelen, result[i].type, entry->srvtypelen, entry->srvtype) == 0) { break; } } if(i == found) { result[found].type = entry->srvtype; result[found].typelen = entry->srvtypelen; found++; if(found >= count) { break; } } } } entry = (SLPDDatabaseEntry*)entry->listitem.next; } return found; }
/*=========================================================================*/ int SLPDDatabaseFindAttr(SLPAttrRqst* attrrqst, SLPDDatabaseAttr* result) /* Find attributes */ /* */ /* srvtyperqst (IN) the request to find. */ /* */ /* result (OUT) pointer to a result structure that receives */ /* results */ /* */ /* Returns - 1 on success, zero if not found, negative on error */ /*=========================================================================*/ { SLPDDatabaseEntry* entry = 0; int found = 0; found = 0; entry = (SLPDDatabaseEntry*)G_DatabaseList.head; while(entry) { if(SLPCompareString(attrrqst->urllen, attrrqst->url, entry->urllen, entry->url) == 0 || SLPCompareSrvType(attrrqst->urllen, attrrqst->url, entry->srvtypelen, entry->srvtype) == 0) { if(SLPIntersectStringList(attrrqst->scopelistlen, attrrqst->scopelist, entry->scopelistlen, entry->scopelist)) { #ifdef USE_PREDICATES if(attrrqst->taglistlen && entry->attr) { /* serialize into entry->partiallist and return partiallist */ int count; SLPError err; /* TRICKY: null terminate the taglist. This is squishes the spistrlen */ /* which is not a problem because it was already copied */ ((char*)attrrqst->taglist)[attrrqst->taglistlen] = 0; err = SLPAttrSerialize(entry->attr, attrrqst->taglist, &entry->partiallist, entry->partiallistlen, &count, SLP_FALSE); if(err == SLP_BUFFER_OVERFLOW) { /* free previously allocated memory */ free(entry->partiallist); entry->partiallist = 0; entry->partiallistlen = 0; /* SLPAttrSerialize will allocate memory for us */ err = SLPAttrSerialize(entry->attr, attrrqst->taglist, &entry->partiallist, entry->partiallistlen, &entry->partiallistlen, SLP_FALSE); entry->partiallistlen = count; } if(err == SLP_OK) { result->attrlistlen = entry->partiallistlen; result->attrlist = entry->partiallist; found = 1; break; } } else #endif { result->attrlistlen = entry->attrlistlen; result->attrlist = entry->attrlist; found = 1; break; } } } entry = (SLPDDatabaseEntry*)entry->listitem.next; } return found; }
/*-------------------------------------------------------------------------*/ int v1ProcessSrvRqst(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /*-------------------------------------------------------------------------*/ { int i; int urllen; int size = 0; SLPDDatabaseSrvRqstResult* 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.srvrqst.prlistlen, message->body.srvrqst.prlist, G_SlpdProperty.interfacesLen, G_SlpdProperty.interfaces)) { result->end = result->start; goto FINISHED; } /*------------------------------------------------*/ /* Check to to see if a this is a special SrvRqst */ /*------------------------------------------------*/ if (SLPCompareString(message->body.srvrqst.srvtypelen, message->body.srvrqst.srvtype, 15, "directory-agent") == 0) { errorcode = v1ProcessDASrvRqst(peeraddr, message, sendbuf, errorcode); return errorcode; } /*------------------------------------*/ /* 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 (message->header.flags & SLP_FLAG_MCAST) { if (errorcode != 0 || db->urlcount == 0) { result->end = result->start; goto FINISHED; } } /*-------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvrply */ /*-------------------------------------------------------------*/ size = 16; /* 12 bytes for header, 2 bytes for error code, 2 bytes for url count */ if (errorcode == 0) { for (i = 0; i < db->urlcount; i++) { urllen = INT_MAX; errorcode = SLPv1ToEncoding(0, &urllen, message->header.encoding, db->urlarray[i]->url, db->urlarray[i]->urllen); if (errorcode) break; size += urllen + 4; /* 2 bytes for lifetime, 2 bytes for urllen */ } result = SLPBufferRealloc(result,size); if (result == 0) { errorcode = SLP_ERROR_INTERNAL_ERROR; } } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 1; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVRPLY; /*length*/ ToUINT16(result->start + 2, size); /*flags - TODO set the flags correctly */ *(result->start + 4) = message->header.flags | (size > SLP_MAX_DATAGRAM_SIZE ? SLPv1_FLAG_OVERFLOW : 0); /*dialect*/ *(result->start + 5) = 0; /*language code*/ memcpy(result->start + 6, message->header.langtag, 2); ToUINT16(result->start + 8, message->header.encoding); /*xid*/ ToUINT16(result->start + 10, message->header.xid); /*-------------------------*/ /* Add rest of the SrvRply */ /*-------------------------*/ result->curpos = result->start + 12; /* 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++) { /* url-entry lifetime */ ToUINT16(result->curpos, db->urlarray[i]->lifetime); result->curpos = result->curpos + 2; /* url-entry url and urllen */ urllen = size; errorcode = SLPv1ToEncoding(result->curpos + 2, &urllen, message->header.encoding, db->urlarray[i]->url, db->urlarray[i]->urllen); ToUINT16(result->curpos, urllen); result->curpos = result->curpos + 2 + urllen; } } else { /* urlentry count */ ToUINT16(result->curpos, 0); result->curpos = result->curpos + 2; } FINISHED: SLPDDatabaseSrvRqstEnd(db); *sendbuf = result; return errorcode; }
/*=========================================================================*/ int SLPDDatabaseReg(SLPSrvReg* srvreg, int fresh, pid_t pid, uid_t uid) /* Add a service registration to the database */ /* */ /* srvreg - (IN) pointer to the SLPSrvReg to be added to the database */ /* */ /* fresh - (IN) pass in nonzero if the registration is fresh. */ /* */ /* pid - (IN) process id of the process that registered the service */ /* */ /* uid - (IN) user id of the user that registered the service */ /* */ /* Returns - Zero on success. non-zero on error */ /* */ /* NOTE: All registrations are treated as fresh regardless of the */ /* setting of the fresh parameter */ /*=========================================================================*/ { int result = 0; SLPDDatabaseEntry* entry = (SLPDDatabaseEntry*)G_DatabaseList.head; /* Check to see if there is already an identical entry */ while(entry) { if(SLPCompareString(entry->urllen, entry->url, srvreg->urlentry.urllen, srvreg->urlentry.url) == 0) { if(SLPIntersectStringList(entry->scopelistlen, entry->scopelist, srvreg->scopelistlen, srvreg->scopelist) > 0) { SLPListUnlink(&G_DatabaseList,(SLPListItem*)entry); break; } } entry = (SLPDDatabaseEntry*) entry->listitem.next; } /* if no identical entry are found, create a new one */ if(entry == 0) { entry = (SLPDDatabaseEntry*)malloc(sizeof(SLPDDatabaseEntry)); if(entry == 0) { return -1; } memset(entry,0,sizeof(SLPDDatabaseEntry)); } /* copy info from the message from the wire to the database entry */ entry->pid = pid; entry->uid = uid; entry->scopelistlen = srvreg->scopelistlen; entry->scopelist = (char*)memdup(srvreg->scopelist,srvreg->scopelistlen); entry->lifetime = srvreg->urlentry.lifetime; entry->urllen = srvreg->urlentry.urllen; entry->url = (char*)memdup(srvreg->urlentry.url, srvreg->urlentry.urllen); entry->srvtypelen = srvreg->srvtypelen; entry->srvtype = (char*)memdup(srvreg->srvtype,srvreg->srvtypelen); entry->attrlistlen = srvreg->attrlistlen; if (entry->attrlistlen) entry->attrlist = (char*)memdup(srvreg->attrlist,srvreg->attrlistlen); /* check for malloc() failures */ if(entry->scopelist == 0 || entry->url == 0 || entry->srvtype == 0 || (entry->attrlistlen && entry->attrlist == 0)) { FreeEntry(entry); return -1; } /* link the new (or modified) entry into the list */ SLPListLinkHead(&G_DatabaseList,(SLPListItem*)entry); /* traceReg if necessary */ if(G_SlpdProperty.traceReg) { SLPDLogTraceReg("SrvReg", entry); } return result; }
/*=========================================================================*/ int SLPContainsStringList(int listlen, const char* list, int stringlen, const char* string) /* Checks a string-list for the occurence of a string */ /* */ /* list - pointer to the string-list to be checked */ /* */ /* listlen - length in bytes of the list to be checked */ /* */ /* string - pointer to a string to find in the string-list */ /* */ /* stringlen - the length of the string in bytes */ /* */ /* Returns - zero if string is NOT contained in the list. non-zero if it*/ /* is. */ /*=========================================================================*/ { char* listend = (char*)list + listlen; char* itembegin = (char*)list; char* itemend = itembegin; char ipv6Buffer[41]; /* must be at least 40 characters */ while(itemend < listend) { itembegin = itemend; /* seek to the end of the next list item */ while(1) { if(itemend == listend || *itemend == ',') { if(*(itemend - 1) != '\\') { break; } } itemend ++; } if (strchr(itembegin, ':')) { SLPFormatAddress(itembegin, ipv6Buffer, sizeof(ipv6Buffer)); if(SLPCompareString(strlen(ipv6Buffer), ipv6Buffer, stringlen, string) == 0) { return 1; } } else { if(SLPCompareString(itemend - itembegin, itembegin, stringlen, string) == 0) { return 1; } } itemend ++; } return 0; }
/*=========================================================================*/ int SLPDDatabaseReg(SLPMessage msg, SLPBuffer buf) /* Add a service registration to the database */ /* */ /* msg (IN) SLPMessage of a SrvReg message as returned by */ /* SLPMessageParse() */ /* */ /* buf (IN) Otherwise unreferenced buffer interpreted by the msg */ /* structure */ /* */ /* Returns - Zero on success. Nonzero on error */ /* */ /* NOTE: All registrations are treated as fresh */ /*=========================================================================*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; SLPSrvReg* entryreg; SLPSrvReg* reg; int result; /* reg is the SrvReg message being registered */ reg = &(msg->body.srvreg); /* check service-url syntax */ if ( SLPCheckServiceUrlSyntax(reg->urlentry.url, reg->urlentry.urllen) ) { return SLP_ERROR_INVALID_REGISTRATION; } /* check attr-list syntax */ if ( reg->attrlistlen && SLPCheckAttributeListSyntax(reg->attrlist,reg->attrlistlen) ) { return SLP_ERROR_INVALID_REGISTRATION; } dh = SLPDatabaseOpen(&G_SlpdDatabase.database); if ( dh ) { /*-----------------------------------------------------*/ /* Check to see if there is already an identical entry */ /*-----------------------------------------------------*/ while ( 1 ) { entry = SLPDatabaseEnum(dh); if ( entry == NULL ) break; /* entry reg is the SrvReg message from the database */ entryreg = &(entry->msg->body.srvreg); if ( SLPCompareString(entryreg->urlentry.urllen, entryreg->urlentry.url, reg->urlentry.urllen, reg->urlentry.url) == 0 ) { if ( SLPIntersectStringList(entryreg->scopelistlen, entryreg->scopelist, reg->scopelistlen, reg->scopelist) > 0 ) { /* Check to ensure the source addr is the same */ /* as the original */ if ( G_SlpdProperty.checkSourceAddr && memcmp(&(entry->msg->peer.sin_addr), &(msg->peer.sin_addr), sizeof(struct in_addr)) ) { SLPDatabaseClose(dh); return SLP_ERROR_AUTHENTICATION_FAILED; } #ifdef ENABLE_SLPv2_SECURITY if ( entryreg->urlentry.authcount && entryreg->urlentry.authcount != reg->urlentry.authcount ) { SLPDatabaseClose(dh); return SLP_ERROR_AUTHENTICATION_FAILED; } #endif /* Remove the identical entry */ SLPDatabaseRemove(dh,entry); break; } } } /*------------------------------------*/ /* Add the new srvreg to the database */ /*------------------------------------*/ entry = SLPDatabaseEntryCreate(msg,buf); if ( entry ) { /* set the source (allows for quicker aging ) */ if ( msg->body.srvreg.source == SLP_REG_SOURCE_UNKNOWN ) { if ( ISLOCAL(msg->peer.sin_addr) ) { msg->body.srvreg.source = SLP_REG_SOURCE_LOCAL; } else { msg->body.srvreg.source = SLP_REG_SOURCE_REMOTE; } } /* add to database */ SLPDatabaseAdd(dh, entry); SLPDLogRegistration("Registration",entry); /* SUCCESS! */ result = 0; } else { result = SLP_ERROR_INTERNAL_ERROR; } SLPDatabaseClose(dh); } else { result = SLP_ERROR_INTERNAL_ERROR; } return result; }