/***************************************************************************/ /* */ /* Project: OpenSLP - OpenSource implementation of Service Location */ /* Protocol Version 2 */ /* */ /* File: slpd_regfile.c */ /* */ /* Abstract: Reads service registrations from a file */ /* */ /* WARNING: NOT thread safe! */ /* */ /*-------------------------------------------------------------------------*/ /* */ /* 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_regfile.h" #include "slpd_property.h" #include "slpd_log.h" #ifdef ENABLE_SLPv2_SECURITY #include "slpd_spi.h" #endif /*=========================================================================*/ /* common code includes */ /*=========================================================================*/ #include "slp_xmalloc.h" #include "slp_compare.h" #ifdef ENABLE_SLPv2_SECURITY #include "slp_auth.h" #endif /*-------------------------------------------------------------------------*/ char* TrimWhitespace(char* str) /*-------------------------------------------------------------------------*/ { char* end; end=str+strlen(str)-1; while(*str && *str <= 0x20) { str++; } while(end >= str) { if(*end > 0x20) { break; } *end = 0; end--; } return str; } /*-------------------------------------------------------------------------*/ char* RegFileReadLine(FILE* fd, char* line, int linesize) /*-------------------------------------------------------------------------*/ { while(1) { if(fgets(line,linesize,fd) == 0) { return 0; } while(*line && *line <= 0x20 && *line != 0x0d && *line != 0x0a) line++; if(*line == 0x0d || *line == 0x0a) { break; } if(*line != 0 && *line != '#' && *line != ';') { break; } } return line; } /*=========================================================================*/ int SLPDRegFileReadSrvReg(FILE* fd, SLPMessage* msg, SLPBuffer* buf) /* A really big and nasty function that reads an service registration from */ /* from a file. Don't look at this too hard or you'll be sick. This is by */ /* the most horrible code in OpenSLP. Please volunteer to rewrite it! */ /* */ /* "THANK GOODNESS this function is only called at startup" -- Matt */ /* */ /* */ /* fd (IN) file to read from */ /* */ /* msg (OUT) message describing the SrvReg in buf */ /* */ /* buf (OUT) buffer containing the SrvReg */ /* */ /* Returns: zero on success. > 0 on error. < 0 if EOF */ /* */ /* Note: Eventually the caller needs to call SLPBufferFree() and */ /* SLPMessageFree() to free memory */ /*=========================================================================*/ { char* slider1; char* slider2; char* p; char line[4096]; struct sockaddr_in peer; int result = 0; int bufsize = 0; int langtaglen = 0; char* langtag = 0; int scopelistlen = 0; char* scopelist = 0; int urllen = 0; char* url = 0; int lifetime = 0; int srvtypelen = 0; char* srvtype = 0; int attrlistlen = 0; char* attrlist = 0; #ifdef ENABLE_SLPv2_SECURITY unsigned char* urlauth = 0; int urlauthlen = 0; unsigned char* attrauth = 0; int attrauthlen = 0; #endif /*-------------------------------------------*/ /* give the out params an initial NULL value */ /*-------------------------------------------*/ *buf = 0; *msg = 0; /*----------------------------------------------------------*/ /* read the next non-white non-comment line from the stream */ /*----------------------------------------------------------*/ do { slider1 = RegFileReadLine(fd,line,4096); if(slider1 == 0) { /* Breath a sigh of relief. We get out before really */ /* horrid code */ return -1; } }while(*slider1 == 0x0d || *slider1 == 0x0a); /*---------------------*/ /* Parse the url-props */ /*---------------------*/ slider2 = strchr(slider1,','); if(slider2) { /* srvurl */ *slider2 = 0; /* squash comma to null terminate srvurl */ url = xstrdup(TrimWhitespace(slider1)); if(url == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } /* replace "$HOSTNAME" string in url */ while ((p = strchr(url, '$')) && !strncmp(p, "$HOSTNAME", 9)) { char *_url = (char*)malloc(strlen(url) - 9 + G_SlpdProperty.myHostnameLen + 1); strncpy(_url, url, p - url); strncpy(_url + (p - url), G_SlpdProperty.myHostname, G_SlpdProperty.myHostnameLen); strcpy(_url + (p - url) + G_SlpdProperty.myHostnameLen, url + (p - url) + 9); free(url); url = _url; } urllen = strlen(url); /* derive srvtype from srvurl */ srvtype = strstr(slider1,"://"); if(srvtype == 0) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } *srvtype = 0; srvtype=xstrdup(TrimWhitespace(slider1)); if(srvtype == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } srvtypelen = strlen(srvtype); slider1 = slider2 + 1; /*lang*/ slider2 = strchr(slider1,','); if(slider2) { *slider2 = 0; /* squash comma to null terminate lang */ langtag = xstrdup(TrimWhitespace(slider1)); if(langtag == 0) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } langtaglen = strlen(langtag); slider1 = slider2 + 1; } else { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } /* ltime */ slider2 = strchr(slider1,','); if(slider2) { *slider2 = 0; /* squash comma to null terminate ltime */ lifetime = atoi(slider1); slider1 = slider2 + 1; } else { lifetime = atoi(slider1); slider1 = slider2; } if(lifetime < 1 || lifetime > SLP_LIFETIME_MAXIMUM) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } /* get the srvtype if one was not derived by the srvurl*/ if(srvtype == 0) { srvtype = xstrdup(TrimWhitespace(slider1)); if(srvtype == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } srvtypelen = strlen(srvtype); if(srvtypelen == 0) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } } } else { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } /*-------------------------------------------------*/ /* Read all the attributes including the scopelist */ /*-------------------------------------------------*/ *line=0; while(1) { slider1 = RegFileReadLine(fd,line,4096); if(slider1 == 0) { /* Breathe a sigh of relief. We're done */ result = -1; break; } if(*slider1 == 0x0d || *slider1 == 0x0a) { break; } /* Check to see if it is the scopes line */ /* FIXME We can collapse the scope stuff into the value getting and * just make it a special case (do strcmp on the tag as opposed to the * line) of attribute getting. */ if(strncasecmp(slider1,"scopes",6) == 0) { /* found scopes line */ slider2 = strchr(slider1,'='); if(slider2) { slider2++; if(*slider2) { /* just in case some idiot puts multiple scopes lines */ if(scopelist) { result = SLP_ERROR_SCOPE_NOT_SUPPORTED; goto CLEANUP; } /* make sure there are no spaces in the scope list */ if(strchr(slider2,' ')) { result = SLP_ERROR_SCOPE_NOT_SUPPORTED; goto CLEANUP; } scopelist=xstrdup(TrimWhitespace(slider2)); if(scopelist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } scopelistlen = strlen(scopelist); } } } else { /* line contains an attribute (slow but it works)*/ /* TODO Fix this so we do not have to realloc memory each time! */ TrimWhitespace(slider1); if(attrlist == 0) { attrlistlen += strlen(slider1) + 2; attrlist = xmalloc(attrlistlen + 1); *attrlist = 0; } else { attrlistlen += strlen(slider1) + 3; attrlist = xrealloc(attrlist, attrlistlen + 1); strcat(attrlist,","); } if(attrlist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } /* we need special case for keywords (why do we need these) */ /* they seem like a waste of code. Why not just use booleans */ if(strchr(slider1,'=')) { /* normal attribute (with '=') */ strcat(attrlist,"("); strcat(attrlist,slider1); strcat(attrlist,")"); } else { /* keyword (no '=') */ attrlistlen -= 2; /* subtract 2 bytes for no '(' or ')' */ strcat(attrlist,slider1); } } } /* Set the scope set in properties if not is set */ if(scopelist == 0) { scopelist=xstrdup(G_SlpdProperty.useScopes); if(scopelist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } scopelistlen = G_SlpdProperty.useScopesLen; } #ifdef ENABLE_SLPv2_SECURITY /*--------------------------------*/ /* Generate authentication blocks */ /*--------------------------------*/ if(G_SlpdProperty.securityEnabled) { SLPAuthSignUrl(G_SlpdSpiHandle, 0, 0, urllen, url, &urlauthlen, &urlauth); SLPAuthSignString(G_SlpdSpiHandle, 0, 0, attrlistlen, attrlist, &attrauthlen, &attrauth); } #endif /*----------------------------------------*/ /* Allocate buffer for the SrvReg Message */ /*----------------------------------------*/ bufsize = 14 + langtaglen; /* 14 bytes for header */ bufsize += urllen + 6; /* 1 byte for reserved */ /* 2 bytes for lifetime */ /* 2 bytes for urllen */ /* 1 byte for authcount */ bufsize += srvtypelen + 2; /* 2 bytes for len field */ bufsize += scopelistlen + 2;/* 2 bytes for len field */ bufsize += attrlistlen + 2; /* 2 bytes for len field */ bufsize += 1; /* 1 byte for authcount */ #ifdef ENABLE_SLPv2_SECURITY bufsize += urlauthlen; bufsize += attrauthlen; #endif *buf = SLPBufferAlloc(bufsize); if(*buf == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } /*------------------------------*/ /* Now build the SrvReg Message */ /*------------------------------*/ /*version*/ *((*buf)->start) = 2; /*function id*/ *((*buf)->start + 1) = SLP_FUNCT_SRVREG; /*length*/ ToUINT24((*buf)->start + 2, bufsize); /*flags*/ ToUINT16((*buf)->start + 5, 0); /*ext offset*/ ToUINT24((*buf)->start + 7,0); /*xid*/ ToUINT16((*buf)->start + 10, 0); /*lang tag len*/ ToUINT16((*buf)->start + 12,langtaglen); /*lang tag*/ memcpy((*buf)->start + 14, langtag, langtaglen); (*buf)->curpos = (*buf)->start + langtaglen + 14 ; /* url-entry reserved */ *(*buf)->curpos= 0; (*buf)->curpos = (*buf)->curpos + 1; /* url-entry lifetime */ ToUINT16((*buf)->curpos,lifetime); (*buf)->curpos = (*buf)->curpos + 2; /* url-entry urllen */ ToUINT16((*buf)->curpos,urllen); (*buf)->curpos = (*buf)->curpos + 2; /* url-entry url */ memcpy((*buf)->curpos,url,urllen); (*buf)->curpos = (*buf)->curpos + urllen; /* url-entry authblock */ #ifdef ENABLE_SLPv2_SECURITY if(urlauth) { /* authcount */ *(*buf)->curpos = 1; (*buf)->curpos = (*buf)->curpos + 1; /* authblock */ memcpy((*buf)->curpos,urlauth,urlauthlen); (*buf)->curpos = (*buf)->curpos + urlauthlen; } else #endif { /* authcount */ *(*buf)->curpos = 0; (*buf)->curpos += 1; } /* service type */ ToUINT16((*buf)->curpos,srvtypelen); (*buf)->curpos = (*buf)->curpos + 2; memcpy((*buf)->curpos,srvtype,srvtypelen); (*buf)->curpos = (*buf)->curpos + srvtypelen; /* scope list */ ToUINT16((*buf)->curpos,scopelistlen); (*buf)->curpos = (*buf)->curpos + 2; memcpy((*buf)->curpos,scopelist,scopelistlen); (*buf)->curpos = (*buf)->curpos + scopelistlen; /* attr list */ ToUINT16((*buf)->curpos,attrlistlen); (*buf)->curpos = (*buf)->curpos + 2; memcpy((*buf)->curpos,attrlist,attrlistlen); (*buf)->curpos = (*buf)->curpos + attrlistlen; /* attribute auth block */ #ifdef ENABLE_SLPv2_SECURITY if(attrauth) { /* authcount */ *(*buf)->curpos = 1; (*buf)->curpos = (*buf)->curpos + 1; /* authblock */ memcpy((*buf)->curpos,attrauth,attrauthlen); (*buf)->curpos = (*buf)->curpos + attrauthlen; } else #endif { /* authcount */ *(*buf)->curpos = 0; (*buf)->curpos = (*buf)->curpos + 1; } /*------------------------------------------------*/ /* Ok Now comes the really stupid (and lazy part) */ /*------------------------------------------------*/ *msg = SLPMessageAlloc(); if(*msg == 0) { SLPBufferFree(*buf); *buf=0; result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } peer.sin_addr.s_addr = htonl(LOOPBACK_ADDRESS); result = SLPMessageParseBuffer(&peer,*buf,*msg); (*msg)->body.srvreg.source = SLP_REG_SOURCE_STATIC; CLEANUP: /*----------------------------------*/ /* Check for errors and free memory */ /*----------------------------------*/ switch(result) { case SLP_ERROR_INTERNAL_ERROR: SLPDLog("\nERROR: Out of memory one reg file line:\n %s\n",line); break; case SLP_ERROR_INVALID_REGISTRATION: SLPDLog("\nERROR: Invalid reg file format near:\n %s\n",line); break; case SLP_ERROR_SCOPE_NOT_SUPPORTED: SLPDLog("\nERROR: Duplicate scopes or scope list with imbedded spaces near:\n %s\n",line); break; default: break; } if(langtag) xfree(langtag); if(scopelist) xfree(scopelist); if(url) xfree(url); if(srvtype) xfree(srvtype); if(attrlist)xfree(attrlist); #ifdef ENABLE_SLPv2_SECURITY if(urlauth) xfree(urlauth); if(attrauth) xfree(attrauth); #endif return result; }