1 /*-------------------------------------------------------------------------
2  * Copyright (C) 2000 Caldera Systems, Inc
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *    Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  *    Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  *    Neither the name of Caldera Systems nor the names of its
17  *    contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA
24  * SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *-------------------------------------------------------------------------*/
32 
33 /** Database abstraction.
34  *
35  * Implements database abstraction. Currently a simple double linked list
36  * (common/slp_database.c) is used for the underlying storage, and indexes on
37  * service type and attributes are optionally maintained as balanced binary trees.
38  *
39  * @file       slpd_database.c
40  * @author     Matthew Peterson, John Calcote (jcalcote@novell.com), Richard Morrell
41  * @attention  Please submit patches to http://www.openslp.org
42  * @ingroup    SlpdCode
43  *
44  * @bug Attribute request for a service type rather than a URL should return a
45  *      set of attributes formed from merging the value lists of all the entries
46  *      conforming to that service type.  It currently returns the attributes from
47  *      a single instance of that service type.
48  */
49 
50 #define _GNU_SOURCE
51 #include <string.h>
52 
53 #include "../libslpattr/libslpattr.h"
54 #include "slpd_database.h"
55 #include "slpd_regfile.h"
56 #include "slpd_property.h"
57 #include "slpd_log.h"
58 #include "slpd_knownda.h"
59 
60 #ifdef ENABLE_PREDICATES
61 # include "slpd_predicate.h"
62 #endif
63 
64 #include "slp_compare.h"
65 #include "slp_xmalloc.h"
66 #include "slp_pid.h"
67 #include "slp_net.h"
68 #include "slpd_incoming.h"
69 #include "slpd_index.h"
70 #include "slp_debug.h"
71 
72 /* Entries used in the "handles" array in the database entry */
73 #define HANDLE_ATTRS            0
74 #define HANDLE_SRVTYPE          1
75 
76 static IndexTreeNode *srvtype_index_tree = (IndexTreeNode *)0;
77 
78 #ifdef ENABLE_PREDICATES
79 /** A structure to hold a tag and its index tree
80  */
81 typedef struct _SLPTagIndex
82 {
83    struct _SLPTagIndex *next;
84    IndexTreeNode *root_node;
85    size_t tag_len;
86    char tag[1];
87 } SLPTagIndex;
88 
89 static SLPTagIndex *tag_index_head = (SLPTagIndex *)0;
90 
91 /** Create a tag index structure for the given tag, and add it to the tag index list
92  *
93  * @param[in] tag - Pointer to a buffer containing the tag string
94  * @param[in] tag_len - Length of the tag string
95  *
96  * @return SLP_ERROR_OK if the allocation succeeds, or SLP_ERROR_INTERNAL_ERROR
97  *         if the allocation fails
98  */
addTagIndex(size_t tag_len,const char * tag)99 int addTagIndex(size_t tag_len, const char *tag)
100 {
101    SLPTagIndex *entry = xmalloc(sizeof (SLPTagIndex) + tag_len);
102 
103    if (entry)
104    {
105       entry->root_node = (IndexTreeNode *)0;
106       entry->tag_len = tag_len;
107       strncpy(entry->tag, tag, tag_len);
108       entry->next = tag_index_head;
109       tag_index_head = entry;
110       return SLP_ERROR_OK;
111    }
112    return SLP_ERROR_INTERNAL_ERROR;
113 }
114 
115 /** Search the tag index list for the given tag.
116  *
117  * @param[in] tag - Pointer to a buffer containing the tag string
118  * @param[in] tag_len - Length of the tag string
119  *
120  * @return Pointer to the tag index entry, or NULL if not found
121  */
findTagIndex(size_t tag_len,const char * tag)122 SLPTagIndex *findTagIndex(size_t tag_len, const char *tag)
123 {
124    SLPTagIndex *entry = tag_index_head;
125 
126    while (entry)
127    {
128       if (entry->tag_len == tag_len)
129       {
130          /* Compare the requested tag and the entry's tag.
131           * Case-insensitive comparison to match the code in
132           * attr_val_find_str
133           */
134          if (strncasecmp(entry->tag, tag, tag_len) == 0)
135             break;
136       }
137       entry = entry->next;
138    }
139    return entry;
140 }
141 #endif /* ENABLE_PREDICATES */
142 
143 /** A structure to hold an allocated service type and its length.
144  */
145 typedef struct
146 {
147    char *srvtype;
148    size_t srvtypelen;
149 } SLPNormalisedSrvtype;
150 
151 /** Takes a service type, and creates a normalised version of it.
152  *
153  * @param[in] srvtypelen - Length of the service type
154  * @param[in] srvtype - Pointer to a buffer containing the service type
155  * @param[out] normalisedSrvtypelen - Length of the normalised service type
156  * @param[out] normalisedSrvtype - Buffer pointer to return the normalised service type
157  *
158  * @return SLP_ERROR_OK if the conversion can succeed, or SLP_ERROR_INTERNAL_ERROR
159  *         if the buffer for the normalised service type cannot be allocated
160  *
161  * @remarks The "service:" prefix is ignored, if present
162  */
getNormalisedSrvtype(size_t srvtypelen,const char * srvtype,size_t * normalisedSrvtypeLen,char ** normalisedSrvtype)163 static int getNormalisedSrvtype(size_t srvtypelen, const char* srvtype, size_t *normalisedSrvtypeLen, char * *normalisedSrvtype)
164 {
165     /* Normalisation may involve collapsing escaped character sequences,
166      * and should never be longer than the service type itself, but allow
167      * for the addition of a trailing NUL
168      */
169    *normalisedSrvtype = (char *)xmalloc(srvtypelen+1);
170    if (!*normalisedSrvtype)
171       return SLP_ERROR_INTERNAL_ERROR;
172 
173    /* The "service:" prefix is optional, so we strip it before the character normalisation */
174    if (srvtypelen >= 8 && strncmp(srvtype, "service:", 8) == 0)
175    {
176       srvtype += 8;
177       srvtypelen -= 8;
178    }
179    *normalisedSrvtypeLen = SLPNormalizeString(srvtypelen, srvtype, *normalisedSrvtype, 1);
180    return SLP_ERROR_OK;
181 }
182 
183 /** Takes a service type, and outputs a structure holding the normalised service type and its length
184  *
185  * @param[in] srvtypelen - Length of the service type
186  * @param[in] srvtype - Pointer to a buffer containing the service type
187  * @param[out] ppNormalisedSrvtype - Buffer pointer to return the allocated structure
188  *
189  * @return SLP_ERROR_INTERNAL_ERROR if the structure cannot be allocated, SLP_ERROR_OK otherwise
190  */
createNormalisedSrvtype(size_t srvtypelen,const char * srvtype,SLPNormalisedSrvtype ** ppNormalisedSrvtype)191 static int createNormalisedSrvtype(size_t srvtypelen, const char* srvtype, SLPNormalisedSrvtype **ppNormalisedSrvtype)
192 {
193    int result;
194 
195    *ppNormalisedSrvtype = (SLPNormalisedSrvtype *)xmalloc(sizeof (SLPNormalisedSrvtype));
196    if (!*ppNormalisedSrvtype)
197       return SLP_ERROR_INTERNAL_ERROR;
198 
199    result = getNormalisedSrvtype(srvtypelen, srvtype, &(*ppNormalisedSrvtype)->srvtypelen, &(*ppNormalisedSrvtype)->srvtype);
200    if (result != SLP_ERROR_OK)
201    {
202       xfree(*ppNormalisedSrvtype);
203       *ppNormalisedSrvtype = (SLPNormalisedSrvtype *)0;
204    }
205 
206    return result;
207 }
208 
209 /** Takes a normalised service type structure, and frees the allocated buffer, and the structure itself
210  *
211  * @param[in] pNormalisedSrvtype - Pointer to the allocated structure
212  */
freeNormalisedSrvtype(SLPNormalisedSrvtype * pNormalisedSrvtype)213 static void freeNormalisedSrvtype(SLPNormalisedSrvtype *pNormalisedSrvtype)
214 {
215    if (pNormalisedSrvtype)
216    {
217       xfree(pNormalisedSrvtype->srvtype);
218       xfree(pNormalisedSrvtype);
219    }
220 }
221 
222 /** Remove an entry from the database.
223  *
224  * @param[in] dh - database handle
225  * @param[in] entry - to be removed
226  *
227  * Frees up the normalised service type, and the parsed attributes, and deals with
228  * cleaning up the service type and attribute indexes, as well as freeing the entry itself.
229  */
SLPDDatabaseRemove(SLPDatabaseHandle dh,SLPDatabaseEntry * entry)230 void SLPDDatabaseRemove(SLPDatabaseHandle dh, SLPDatabaseEntry * entry)
231 {
232    SLPNormalisedSrvtype *pNormalisedSrvtype = (SLPNormalisedSrvtype *)entry->handles[HANDLE_SRVTYPE];
233    SLPAttributes slp_attr = (SLPAttributes)entry->handles[HANDLE_ATTRS];
234 
235    if (G_SlpdProperty.srvtypeIsIndexed)
236    {
237       /* Remove the index entries for this entry */
238       srvtype_index_tree = index_tree_delete(srvtype_index_tree, pNormalisedSrvtype->srvtypelen, pNormalisedSrvtype->srvtype, (void *)entry);
239    }
240 
241    if (pNormalisedSrvtype)
242       freeNormalisedSrvtype(pNormalisedSrvtype);
243 
244    if (slp_attr)
245    {
246 #ifdef ENABLE_PREDICATES
247       /* Parsed attributes - remove them from the attribute indexes, if necessary */
248       if (G_SlpdProperty.indexedAttributes)
249       {
250          const char * tag;
251          SLPType type;
252          SLPAttrIterator iter_h;
253          SLPError err = SLPAttrIteratorAlloc(slp_attr, &iter_h);
254 
255          if (err == SLP_OK)
256          {
257             /* For each attribute name */
258             while (SLPAttrIterNext(iter_h, (char const * *) &tag, &type) == SLP_TRUE)
259             {
260                /* Ensure it is a string value */
261                if (type == SLP_STRING)
262                {
263                   /* Check to see if it is indexed */
264                   SLPTagIndex *tag_index = findTagIndex(strlen(tag), tag);
265                   if (tag_index)
266                   {
267                      SLPValue value;
268                      /* For each value in the attribute's list */
269                      while (SLPAttrIterValueNext(iter_h, &value) == SLP_TRUE)
270                      {
271                         /* Remove the value from the index */
272                         tag_index->root_node = index_tree_delete(tag_index->root_node, value.len, value.data.va_str, (void *)entry);
273                      }
274                   }
275                }
276             }
277             SLPAttrIteratorFree(iter_h);
278          }
279       }
280 #endif
281 
282       /* De-allocate the attribute structures */
283       SLPAttrFree(slp_attr);
284    }
285 
286    /* Now remove the entry itself */
287    SLPDatabaseRemove(dh, entry);
288 }
289 
290 
291 /** The slpd static global database object.
292  */
293 static SLPDDatabase G_SlpdDatabase;
294 
295 /** Ages the database entries and clears new and deleted entry lists
296  *
297  * @param[in] seconds - The number of seconds to age each entry by.
298  * @param[in] ageall - Age even entries with SLP_LIFETIME_MAXIMUM.
299  */
SLPDDatabaseAge(int seconds,int ageall)300 void SLPDDatabaseAge(int seconds, int ageall)
301 {
302    SLPDatabaseHandle dh;
303 
304    if ((dh = SLPDatabaseOpen(&G_SlpdDatabase.database)) != 0)
305    {
306       SLPDatabaseEntry * entry;
307 
308       while ((entry = SLPDatabaseEnum(dh)) != 0)
309       {
310          /* srvreg is the SrvReg message from the database */
311          SLPSrvReg * srvreg = &entry->msg->body.srvreg;
312 
313          /* If the entry is local and it's configured for pid watching and
314           * its pid is invalid, then notify DA's and remove it.
315           */
316          if (srvreg->source == SLP_REG_SOURCE_LOCAL
317                && srvreg->pid != 0 && !SLPPidExists(srvreg->pid))
318          {
319             if (G_SlpdProperty.traceReg)
320             {
321                char buffer[50];
322                sprintf(buffer, "PID Watcher Deregistration (pid=%d)", (int)srvreg->pid);
323                SLPDLogRegistration(buffer, entry);
324             }
325             SLPDKnownDADeRegisterWithAllDas(entry->msg, entry->buf);
326             SLPDIncomingRemoveService(srvreg->srvtype, srvreg->srvtypelen);
327             SLPDDatabaseRemove(dh, entry);
328             continue;
329          }
330 
331          /* Don't age entries whose lifetime is set to SLP_LIFETIME_MAXIMUM
332           * if we've been told not to age all entries, or if the entry came
333           * from the local static registration file.
334           */
335          if (srvreg->urlentry.lifetime == SLP_LIFETIME_MAXIMUM
336                && (!ageall || srvreg->source == SLP_REG_SOURCE_STATIC || srvreg->source == SLP_REG_SOURCE_LOCAL))
337             continue;
338 
339          /* Age entry and remove those that have timed out */
340          srvreg->urlentry.lifetime -= seconds;
341          if (srvreg->urlentry.lifetime <= 0)
342          {
343             SLPDLogRegistration("Timeout", entry);
344             SLPDIncomingRemoveService(srvreg->srvtype, srvreg->srvtypelen);
345             SLPDDatabaseRemove(dh, entry);
346          }
347       }
348       SLPDatabaseClose(dh);
349    }
350 }
351 
352 /** Checks if a srvtype is already in the database
353  *
354  * @param [in] srvtype
355  * @param [in] srvtypelen
356  *
357  * @return 1 if the srvtype is already in the database
358  */
SLPDDatabaseSrvtypeUsed(const char * srvtype,size_t srvtypelen)359 int SLPDDatabaseSrvtypeUsed(const char* srvtype, size_t srvtypelen)
360 {
361    SLPDatabaseHandle dh;
362    SLPDatabaseEntry * entry;
363    SLPSrvReg * entryreg;
364    int result = 0;
365 
366    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
367    if (dh)
368    {
369       while (1)
370       {
371          entry = SLPDatabaseEnum(dh);
372          if (entry == 0)
373             break;
374 
375          /* entry reg is the SrvReg message from the database */
376          entryreg = &entry->msg->body.srvreg;
377          if(SLPCompareString(entryreg->srvtypelen, entryreg->srvtype, srvtypelen, srvtype) == 0)
378          {
379             result = 1;
380             break;
381          }
382       }
383       SLPDatabaseClose(dh);
384    }
385 
386    return result;
387 }
388 
389 /** Add a service registration to the database.
390  *
391  * @param[in] msg - SLPMessage of a SrvReg message as returned by
392  *    SLPMessageParse.
393  *
394  * @param[in] buf - Otherwise unreferenced buffer interpreted by the
395  *    msg structure.
396  *
397  * @return Zero on success, or a non-zero value on error.
398  *
399  * @remarks All registrations are treated as fresh.
400  */
SLPDDatabaseReg(SLPMessage * msg,SLPBuffer buf)401 int SLPDDatabaseReg(SLPMessage * msg, SLPBuffer buf)
402 {
403    SLPDatabaseHandle dh;
404    SLPDatabaseEntry * entry;
405    SLPSrvReg * entryreg;
406    SLPSrvReg * reg;
407    int result;
408    int i;
409 
410    /* reg is the SrvReg message being registered */
411    reg = &msg->body.srvreg;
412 
413    /* check service-url syntax */
414    if (SLPCheckServiceUrlSyntax(reg->urlentry.url, reg->urlentry.urllen))
415       return SLP_ERROR_INVALID_REGISTRATION;
416 
417    /* check attr-list syntax */
418    if (reg->attrlistlen
419          && SLPCheckAttributeListSyntax(reg->attrlist,reg->attrlistlen))
420       return SLP_ERROR_INVALID_REGISTRATION;
421 
422    /* add a socket to listen for IPv6 requests if we haven't already (includes if this one was already registered) */
423    if (SLPNetIsIPV6() &&
424        !SLPDDatabaseSrvtypeUsed(msg->body.srvreg.srvtype, msg->body.srvreg.srvtypelen))
425    {
426       SLPIfaceInfo ifaces;
427 
428       ifaces.iface_addr = malloc(slp_max_ifaces *
429             sizeof(struct sockaddr_storage));
430       if (ifaces.iface_addr == NULL)
431       {
432          fprintf(stderr, "iface_addr malloc(%lu) failed\n",
433             slp_max_ifaces * sizeof(struct sockaddr_storage));
434          exit(1);
435       }
436       ifaces.bcast_addr = malloc(slp_max_ifaces *
437             sizeof(struct sockaddr_storage));
438       if (ifaces.bcast_addr == NULL)
439       {
440          fprintf(stderr, "bcast_addr malloc(%lu) failed\n",
441             slp_max_ifaces * sizeof(struct sockaddr_storage));
442          exit(1);
443       }
444 
445       SLPIfaceGetInfo(G_SlpdProperty.interfaces, &ifaces, AF_INET6);
446       for (i = 0; i < ifaces.iface_count; i++)
447          if(ifaces.iface_addr[i].ss_family == AF_INET6)
448             SLPDIncomingAddService(msg->body.srvreg.srvtype,
449                   msg->body.srvreg.srvtypelen, &ifaces.iface_addr[i]);
450       xfree(ifaces.iface_addr);
451       xfree(ifaces.bcast_addr);
452    }
453 
454    /* fixup the lifetime a bit */
455    if (reg->urlentry.lifetime > 0 && reg->urlentry.lifetime < SLP_LIFETIME_MAXIMUM)
456    {
457       if (reg->urlentry.lifetime >= SLP_LIFETIME_MAXIMUM - SLPD_AGE_INTERVAL)
458          reg->urlentry.lifetime = SLP_LIFETIME_MAXIMUM - 1;
459       else
460          reg->urlentry.lifetime += SLPD_AGE_INTERVAL;
461    }
462 
463    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
464    if (dh)
465    {
466       SLPNormalisedSrvtype *pNormalisedSrvtype = (SLPNormalisedSrvtype *)0;
467       SLPAttributes attr = (SLPAttributes)0;
468 #ifdef ENABLE_PREDICATES
469       char attrnull;
470 #endif
471 
472       /* Get the normalised service type */
473       result = createNormalisedSrvtype(reg->srvtypelen, reg->srvtype, &pNormalisedSrvtype);
474       if (result != SLP_ERROR_OK)
475       {
476          SLPDatabaseClose(dh);
477          return SLP_ERROR_INTERNAL_ERROR;
478       }
479 
480 #ifdef ENABLE_PREDICATES
481       /* Get the parsed attributes */
482 
483       /* TRICKY: Temporarily NULL terminate the attribute list. We can do this
484        * because there is room in the corresponding SLPv2 SRVREG SRVRQST
485        * messages. Basically we are squashing the authcount and
486        * the spi string length. Don't worry, we fix things up later and it is
487        * MUCH faster than a malloc for a new buffer 1 byte longer!
488        */
489       attrnull = reg->attrlist[reg->attrlistlen];
490       ((char *) reg->attrlist)[reg->attrlistlen] = 0;
491 
492       /* Generate an SLPAttr from the comma delimited list */
493       if (SLPAttrAlloc("en", NULL, SLP_FALSE, &attr) == 0)
494       {
495          if (SLPAttrFreshen(attr, reg->attrlist) != 0)
496          {
497             /* Invalid attributes */
498             SLPAttrFree(attr);
499             attr = (SLPAttributes)0;
500          }
501       }
502 
503       /* Restore the overwritten byte */
504       ((char *) reg->attrlist)[reg->attrlistlen] = attrnull;
505 #endif
506 
507       /* check to see if there is already an identical entry */
508       while (1)
509       {
510          entry = SLPDatabaseEnum(dh);
511          if (entry == 0)
512             break;
513 
514          /* entry reg is the SrvReg message from the database */
515          entryreg = &entry->msg->body.srvreg;
516 
517          if (SLPCompareString(entryreg->urlentry.urllen,
518                entryreg->urlentry.url, reg->urlentry.urllen,
519                reg->urlentry.url) == 0)
520          {
521             if (SLPIntersectStringList(entryreg->scopelistlen,
522                   entryreg->scopelist, reg->scopelistlen,reg->scopelist) > 0)
523             {
524                /* check to ensure the source addr is the same
525                   as the original */
526                if (G_SlpdProperty.checkSourceAddr)
527                {
528                   if ((entry->msg->peer.ss_family == AF_INET
529                         && msg->peer.ss_family == AF_INET
530                         && memcmp(&(((struct sockaddr_in *)
531                               &(entry->msg->peer))->sin_addr),
532                               &(((struct sockaddr_in *)
533                                     &(msg->peer))->sin_addr),
534                               sizeof(struct in_addr)))
535                         || (entry->msg->peer.ss_family == AF_INET6
536                               && msg->peer.ss_family == AF_INET6
537                               && memcmp(&(((struct sockaddr_in6 *)
538                                     &(entry->msg->peer))->sin6_addr),
539                                     &(((struct sockaddr_in6 *)
540                                           &(msg->peer))->sin6_addr),
541                                     sizeof(struct in6_addr))))
542                   {
543                      SLPDatabaseClose(dh);
544                      freeNormalisedSrvtype(pNormalisedSrvtype);
545                      if (attr)
546                         SLPAttrFree(attr);
547                      return SLP_ERROR_AUTHENTICATION_FAILED;
548                   }
549                }
550 
551 #ifdef ENABLE_SLPv2_SECURITY
552                if (entryreg->urlentry.authcount
553                      && entryreg->urlentry.authcount != reg->urlentry.authcount)
554                {
555                   SLPDatabaseClose(dh);
556                   freeNormalisedSrvtype(pNormalisedSrvtype);
557                   if (attr)
558                      SLPAttrFree(attr);
559                   return SLP_ERROR_AUTHENTICATION_FAILED;
560                }
561 #endif
562                /* Remove the identical entry */
563                SLPDDatabaseRemove(dh, entry);
564                break;
565             }
566          }
567       }
568 
569       /* add the new srvreg to the database */
570       entry = SLPDatabaseEntryCreate(msg, buf);
571       if (entry)
572       {
573          /* set the source (allows for quicker aging ) */
574          if (msg->body.srvreg.source == SLP_REG_SOURCE_UNKNOWN)
575          {
576             if (SLPNetIsLoopback(&(msg->peer)))
577                msg->body.srvreg.source = SLP_REG_SOURCE_LOCAL;
578             else
579                msg->body.srvreg.source = SLP_REG_SOURCE_REMOTE;
580          }
581 
582          /* add to database */
583          SLPDatabaseAdd(dh, entry);
584 
585          /* Update the service type index with the new entry */
586          entry->handles[HANDLE_SRVTYPE] = (void *)pNormalisedSrvtype;
587          if (G_SlpdProperty.srvtypeIsIndexed)
588          {
589             srvtype_index_tree = add_to_index(srvtype_index_tree, pNormalisedSrvtype->srvtypelen, pNormalisedSrvtype->srvtype, (void *)entry);
590          }
591 
592          /* Update the attribute indexes */
593          entry->handles[HANDLE_ATTRS] = (void *)attr;
594 #ifdef ENABLE_PREDICATES
595          if (attr && G_SlpdProperty.indexedAttributes)
596          {
597             const char * tag;
598             SLPType type;
599             SLPAttrIterator iter_h;
600             SLPError err = SLPAttrIteratorAlloc(attr, &iter_h);
601 
602             if (err == SLP_OK)
603             {
604                /* For each attribute name */
605                while (SLPAttrIterNext(iter_h, (char const * *) &tag, &type) == SLP_TRUE)
606                {
607                   /* Ensure it is a string value */
608                   if (type == SLP_STRING)
609                   {
610                      /* Check to see if it is indexed */
611                      SLPTagIndex *tag_index = findTagIndex(strlen(tag), tag);
612                      if (tag_index)
613                      {
614                         SLPValue value;
615                         /* For each value in the attribute's list */
616                         while (SLPAttrIterValueNext(iter_h, &value) == SLP_TRUE)
617                         {
618                            /* Add the value to the index */
619                            tag_index->root_node = add_to_index(tag_index->root_node, value.len, value.data.va_str, (void *)entry);
620                         }
621                      }
622                   }
623                }
624                SLPAttrIteratorFree(iter_h);
625             }
626          }
627 #endif
628 
629          if (G_SlpdProperty.traceReg)
630          {
631             char buffer[40];
632             sprintf(buffer, "Registration (pid=%d)", (int)reg->pid);
633             SLPDLogRegistration(buffer, entry);
634          }
635 
636          result = SLP_ERROR_OK; /* SUCCESS! */
637       }
638       else
639       {
640          result = SLP_ERROR_INTERNAL_ERROR;
641          freeNormalisedSrvtype(pNormalisedSrvtype);
642       }
643       SLPDatabaseClose(dh);
644    }
645    else
646       result = SLP_ERROR_OK; /* SUCCESS! */
647 
648    return result;
649 }
650 
651 /** Remove a service registration from the database.
652  *
653  * @param[in] msg - Message interpreting an SrvDereg message.
654  *
655  * @return Zero on success, or a non-zero value on failure.
656  */
SLPDDatabaseDeReg(SLPMessage * msg)657 int SLPDDatabaseDeReg(SLPMessage * msg)
658 {
659    SLPDatabaseHandle dh;
660    SLPDatabaseEntry * entry = 0;
661    SLPSrvReg * entryreg;
662    SLPSrvDeReg * dereg;
663    char srvtype[MAX_HOST_NAME];
664    size_t srvtypelen = 0;
665 
666    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
667    if (dh)
668    {
669       /* dereg is the SrvDereg being deregistered */
670       dereg = &msg->body.srvdereg;
671 
672       /* check to see if there is an identical entry */
673       while (1)
674       {
675          entry = SLPDatabaseEnum(dh);
676          if (entry == 0)
677             break;
678 
679          /* entry reg is the SrvReg message from the database */
680          entryreg = &entry->msg->body.srvreg;
681 
682          if (SLPCompareString(entryreg->urlentry.urllen,
683                entryreg->urlentry.url, dereg->urlentry.urllen,
684                dereg->urlentry.url) == 0)
685          {
686             if (SLPIntersectStringList(entryreg->scopelistlen,
687                   entryreg->scopelist, dereg->scopelistlen,
688                   dereg->scopelist) > 0)
689             {
690                /* Check to ensure the source addr is the same as */
691                /* the original */
692                if (G_SlpdProperty.checkSourceAddr)
693                {
694                   if ((entry->msg->peer.ss_family == AF_INET
695                         && msg->peer.ss_family == AF_INET
696                         && memcmp(&(((struct sockaddr_in *)
697                               &(entry->msg->peer))->sin_addr),
698                               &(((struct sockaddr_in *)&(msg->peer))->sin_addr),
699                               sizeof(struct in_addr)))
700                         || (entry->msg->peer.ss_family == AF_INET6
701                               && msg->peer.ss_family == AF_INET6
702                               && memcmp(&(((struct sockaddr_in6 *)
703                                     &(entry->msg->peer))->sin6_addr),
704                                     &(((struct sockaddr_in6 *)
705                                           &(msg->peer))->sin6_addr),
706                                     sizeof(struct in6_addr))))
707                   {
708                      SLPDatabaseClose(dh);
709                      return SLP_ERROR_AUTHENTICATION_FAILED;
710                   }
711                }
712 
713 #ifdef ENABLE_SLPv2_SECURITY
714                if (entryreg->urlentry.authcount
715                      && entryreg->urlentry.authcount
716                            != dereg->urlentry.authcount)
717                {
718                   SLPDatabaseClose(dh);
719                   return SLP_ERROR_AUTHENTICATION_FAILED;
720                }
721 #endif
722 
723                /* save the srvtype for later */
724                strncpy(srvtype, entryreg->srvtype, entryreg->srvtypelen);
725                srvtypelen = entryreg->srvtypelen;
726 
727                /* remove the registration from the database */
728                SLPDLogRegistration("Deregistration",entry);
729                SLPDDatabaseRemove(dh,entry);
730 
731                break;
732             }
733          }
734       }
735       SLPDatabaseClose(dh);
736 
737       if (entry != 0)
738       {
739          /* check to see if we can stop listening for service requests for this service */
740          dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
741          if (dh)
742          {
743             while (1)
744             {
745                entry = SLPDatabaseEnum(dh);
746                if (entry == 0)
747                   break;
748 
749                entryreg = &entry->msg->body.srvreg;
750                if (SLPCompareString(entryreg->srvtypelen, entryreg->srvtype,
751                      srvtypelen, srvtype) == 0)
752                   break;
753             }
754          }
755 
756          SLPDatabaseClose(dh);
757 
758          /* okay, remove the listening sockets */
759          if (entry == 0)
760             SLPDIncomingRemoveService(srvtype, srvtypelen);
761       }
762       else
763          return SLP_ERROR_INVALID_REGISTRATION;
764    }
765    return 0;
766 }
767 
768 /** Test an entry for whether it should be returned.
769  *
770  * @param[in] msg - request message.
771  * @param[in] entry - database entry to be tested.
772  *
773  * @return Non-zero if the entry matches the request, and should be returned,
774  *         zero otherwise
775  */
SLPDDatabaseSrvRqstTestEntry(SLPMessage * msg,SLPDPredicateTreeNode * predicate_parse_tree,SLPDatabaseEntry * entry)776 static int SLPDDatabaseSrvRqstTestEntry(
777    SLPMessage * msg,
778 #ifdef ENABLE_PREDICATES
779    SLPDPredicateTreeNode * predicate_parse_tree,
780 #endif
781    SLPDatabaseEntry * entry)
782 {
783    SLPSrvReg * entryreg;
784    SLPSrvRqst * srvrqst;
785 
786 #ifdef ENABLE_SLPv2_SECURITY
787    int i;
788 #endif
789 
790    /* srvrqst is the SrvRqst being made */
791    srvrqst = &(msg->body.srvrqst);
792 
793    /* entry reg is the SrvReg message from the database */
794    entryreg = &entry->msg->body.srvreg;
795 
796    /* check the service type */
797    if (SLPCompareSrvType(srvrqst->srvtypelen, srvrqst->srvtype,
798          entryreg->srvtypelen, entryreg->srvtype) == 0
799          && SLPIntersectStringList(entryreg->scopelistlen,
800                entryreg->scopelist, srvrqst->scopelistlen,
801                srvrqst->scopelist) > 0)
802    {
803 
804 #ifdef ENABLE_PREDICATES
805       if (SLPDPredicateTestTree(predicate_parse_tree, (SLPAttributes)entry->handles[HANDLE_ATTRS]))
806 #endif
807       {
808 
809 #ifdef ENABLE_SLPv2_SECURITY
810          if (srvrqst->spistrlen)
811          {
812             for (i = 0; i < entryreg->urlentry.authcount; i++)
813                if (SLPCompareString(srvrqst->spistrlen,
814                      srvrqst->spistr, entryreg->urlentry.autharray
815                            [i].spistrlen, entryreg->urlentry.autharray
816                            [i].spistr) == 0)
817                   break;
818 
819             if (i == entryreg->urlentry.authcount)
820                return 0;
821          }
822 #endif
823          return 1;
824       }
825    }
826    return 0;
827 }
828 
829 typedef struct
830 {
831    SLPMessage *                  msg;
832    SLPDDatabaseSrvRqstResult **  result;
833 #ifdef ENABLE_PREDICATES
834    SLPDPredicateTreeNode *       predicate_parse_tree;
835 #endif
836    int                           error_code;
837 } SLPDDatabaseSrvRqstStartIndexCallbackParams;
838 
839 /** Filter services in the database via an index.
840  *
841  * @param[in] cookie - context data.
842  * @param[in] p - database entry.
843  *
844  * @remarks @p p represents an entry with a matching srvtype
845  */
SLPDDatabaseSrvRqstStartIndexCallback(void * cookie,void * p)846 static void SLPDDatabaseSrvRqstStartIndexCallback(void * cookie, void *p)
847 {
848    SLPDDatabaseSrvRqstStartIndexCallbackParams *params;
849    SLPMessage * msg;
850    SLPDDatabaseSrvRqstResult ** result;
851    SLPDatabaseEntry * entry;
852 #ifdef ENABLE_PREDICATES
853    SLPDPredicateTreeNode * predicate_parse_tree;
854 #endif
855    SLPSrvReg * entryreg;
856 
857    params = (SLPDDatabaseSrvRqstStartIndexCallbackParams *)cookie;
858    if (params->error_code)
859    {
860       return;
861    }
862 
863    msg = params->msg;
864    result = params->result;
865 #ifdef ENABLE_PREDICATES
866    predicate_parse_tree = params->predicate_parse_tree;
867 #endif
868    entry = (SLPDatabaseEntry *)p;
869 
870    if (SLPDDatabaseSrvRqstTestEntry(msg,
871 #ifdef ENABLE_PREDICATES
872                                     predicate_parse_tree,
873 #endif
874                                     entry))
875    {
876       if ((*result)->urlcount + 1 > G_SlpdDatabase.urlcount)
877       {
878          /* Oops we did not allocate a big enough result */
879          params->error_code = 1;
880          return;
881       }
882       /* entry reg is the SrvReg message from the database */
883       entryreg = &entry->msg->body.srvreg;
884 
885       (*result)->urlarray[(*result)->urlcount]
886             = &entryreg->urlentry;
887       (*result)->urlcount ++;
888    }
889 }
890 
891 /** Find services in the database via the srvtype index.
892  *
893  * @param[in] msg - The SrvRqst to find.
894  *
895  * @param[out] result - The address of storage for the returned
896  *    result structure
897  *
898  * @return Zero on success, or a non-zero value on failure.
899  *
900  * @remarks Caller must pass @p result (dereferenced) to
901  *    SLPDDatabaseSrvRqstEnd to free.
902  */
SLPDDatabaseSrvRqstStartIndexType(SLPMessage * msg,SLPDPredicateTreeNode * parse_tree,SLPDDatabaseSrvRqstResult ** result)903 static int SLPDDatabaseSrvRqstStartIndexType(SLPMessage * msg,
904 #ifdef ENABLE_PREDICATES
905       SLPDPredicateTreeNode *parse_tree,
906 #endif
907       SLPDDatabaseSrvRqstResult ** result)
908 {
909    SLPSrvRqst * srvrqst;
910    size_t srvtypelen;
911    const char *srvtype;
912    size_t normalized_srvtypelen;
913    char *normalized_srvtype;
914    SLPDDatabaseSrvRqstStartIndexCallbackParams params;
915 
916    /* srvrqst is the SrvRqst being made */
917    srvrqst = &(msg->body.srvrqst);
918 
919    srvtypelen = srvrqst->srvtypelen;
920    srvtype = srvrqst->srvtype;
921 
922    if (srvtypelen >= 8)
923    {
924       if (strncasecmp(srvtype, "service:", 8) == 0)
925       {
926          /* Skip "service:" */
927          srvtypelen -= 8;
928          srvtype += 8;
929       }
930    }
931    /* the index contains normalized service type strings, so normalize the
932     * string we want to search for
933     */
934    if ((normalized_srvtype = (char *)xmalloc(srvtypelen + 1)) == 0)
935       return SLP_MEMORY_ALLOC_FAILED;
936    normalized_srvtypelen = SLPNormalizeString(srvtypelen, srvtype, normalized_srvtype, 1);
937    normalized_srvtype[normalized_srvtypelen] = '\0';
938 
939    /* Search the srvtype index */
940    params.msg = msg;
941    params.result = result;
942 #ifdef ENABLE_PREDICATES
943    params.predicate_parse_tree = parse_tree;
944 #endif
945    params.error_code = 0;
946    find_and_call(srvtype_index_tree,
947       normalized_srvtypelen,
948       normalized_srvtype,
949       SLPDDatabaseSrvRqstStartIndexCallback,
950       (void *)&params);
951 
952    xfree(normalized_srvtype);
953    return params.error_code;
954 }
955 
956 #ifdef ENABLE_PREDICATES
957 /** Find services in the database via an attribute index.
958  *
959  * @param[in] msg - The SrvRqst to find.
960  *
961  * @param[out] result - The address of storage for the returned
962  *    result structure
963  *
964  * @return Zero on success, or a non-zero value on failure.
965  *
966  * @remarks Caller must pass @p result (dereferenced) to
967  *    SLPDDatabaseSrvRqstEnd to free.
968  */
SLPDDatabaseSrvRqstStartIndexAttribute(size_t search_str_len,const char * search_str,IndexTreeNode * attribute_index,SLPMessage * msg,SLPDPredicateTreeNode * parse_tree,SLPDDatabaseSrvRqstResult ** result)969 static int SLPDDatabaseSrvRqstStartIndexAttribute(
970       size_t search_str_len,
971       const char *search_str,
972       IndexTreeNode * attribute_index,
973       SLPMessage * msg,
974       SLPDPredicateTreeNode *parse_tree,
975       SLPDDatabaseSrvRqstResult ** result)
976 {
977    size_t processed_searchstr_len;
978    char *processed_searchstr;
979    SLPDDatabaseSrvRqstStartIndexCallbackParams params;
980    char * wildcard;
981    SLPError err;
982 
983    /* We can use the index in two ways
984     * If the string we are searching for is not wildcarded, then we
985     * can simply use the index to filter all entries which match the
986     * full string.
987     * If the string we are searching for is wildcarded, then we can
988     * use the index to filter all entries which start with the part of
989     * the string preceding the first wildcard character.
990     */
991    wildcard = memchr(search_str, '*', search_str_len);
992    if (wildcard)
993    {
994       /** found wildcard character - this can't be the first character
995        *  as we check for that before calling this function
996        */
997       SLP_ASSERT(wildcard != search_str);
998       search_str_len = wildcard - search_str;
999    }
1000 
1001    /* the index contains processed attribute strings, so process the
1002     * string we're searching for in the same way
1003     */
1004    if ((err = SLPAttributeSearchString(search_str_len, search_str, &processed_searchstr_len, &processed_searchstr)) != SLP_OK)
1005       return (int)err;
1006 
1007    /* Search the index */
1008    params.msg = msg;
1009    params.result = result;
1010    params.predicate_parse_tree = parse_tree;
1011    params.error_code = 0;
1012    if (wildcard)
1013       find_leading_and_call(attribute_index,
1014          processed_searchstr_len,
1015          processed_searchstr,
1016          SLPDDatabaseSrvRqstStartIndexCallback,
1017          (void *)&params);
1018    else
1019       find_and_call(attribute_index,
1020          processed_searchstr_len,
1021          processed_searchstr,
1022          SLPDDatabaseSrvRqstStartIndexCallback,
1023          (void *)&params);
1024 
1025    xfree(processed_searchstr);
1026    return params.error_code;
1027 }
1028 #endif /* ENABLE_PREDICATES */
1029 
1030 /** Find services in the database via linear scan.
1031  *
1032  * @param[in] msg - The SrvRqst to find.
1033  *
1034  * @param[out] result - The address of storage for the returned
1035  *    result structure
1036  *
1037  * @return Zero on success, or a non-zero value on failure (not enough result entries).
1038  *
1039  * @remarks Caller must pass @p result (dereferenced) to
1040  *    SLPDDatabaseSrvRqstEnd to free.
1041  */
SLPDDatabaseSrvRqstStartScan(SLPMessage * msg,SLPDPredicateTreeNode * parse_tree,SLPDDatabaseSrvRqstResult ** result)1042 static int SLPDDatabaseSrvRqstStartScan(SLPMessage * msg,
1043 #ifdef ENABLE_PREDICATES
1044       SLPDPredicateTreeNode *parse_tree,
1045 #endif
1046       SLPDDatabaseSrvRqstResult ** result)
1047 {
1048    SLPDatabaseHandle dh;
1049    SLPDatabaseEntry * entry;
1050    SLPSrvReg * entryreg;
1051    /* SLPSrvRqst * srvrqst; */
1052 
1053    dh = (*result)->reserved;
1054    if (dh)
1055    {
1056       /* srvrqst is the SrvRqst being made */
1057       /* srvrqst = &(msg->body.srvrqst); */
1058 
1059       /* Check to see if there is matching entry */
1060       while (1)
1061       {
1062          entry = SLPDatabaseEnum(dh);
1063          if (entry == 0)
1064             return 0; /* This is the only successful way out */
1065 
1066          if (SLPDDatabaseSrvRqstTestEntry(msg,
1067 #ifdef ENABLE_PREDICATES
1068                                           parse_tree,
1069 #endif
1070                                           entry))
1071          {
1072             if ((*result)->urlcount + 1 > G_SlpdDatabase.urlcount)
1073             {
1074                /* Oops we did not allocate a big enough result */
1075                return 1;
1076             }
1077             /* entry reg is the SrvReg message from the database */
1078             entryreg = &entry->msg->body.srvreg;
1079 
1080             (*result)->urlarray[(*result)->urlcount]
1081                   = &entryreg->urlentry;
1082             (*result)->urlcount ++;
1083          }
1084       }
1085    }
1086    return 0;
1087 }
1088 
1089 /** Find services in the database.
1090  *
1091  * @param[in] msg - The SrvRqst to find.
1092  *
1093  * @param[out] result - The address of storage for the returned
1094  *    result structure
1095  *
1096  * @return Zero on success, or a non-zero value on failure.
1097  *
1098  * @remarks Caller must pass @p result (dereferenced) to
1099  *    SLPDDatabaseSrvRqstEnd to free.
1100  */
SLPDDatabaseSrvRqstStart(SLPMessage * msg,SLPDDatabaseSrvRqstResult ** result)1101 int SLPDDatabaseSrvRqstStart(SLPMessage * msg,
1102       SLPDDatabaseSrvRqstResult ** result)
1103 {
1104    SLPDatabaseHandle dh;
1105    SLPSrvRqst * srvrqst;
1106 
1107    int start_result;
1108    int use_index = 0;
1109 
1110 #ifdef ENABLE_PREDICATES
1111    SLPDPredicateTreeNode * predicate_parse_tree = (SLPDPredicateTreeNode *)0;
1112 #endif
1113 
1114    /* start with the result set to NULL just to be safe */
1115    *result = 0;
1116 
1117    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
1118    if (dh)
1119    {
1120       /* srvrqst is the SrvRqst being made */
1121       srvrqst = &(msg->body.srvrqst);
1122 
1123       while (1)
1124       {
1125          /* allocate result with generous array of url entry pointers */
1126          *result = (SLPDDatabaseSrvRqstResult *)xrealloc(*result,
1127                sizeof(SLPDDatabaseSrvRqstResult) + (sizeof(SLPUrlEntry*)
1128                      * G_SlpdDatabase.urlcount));
1129          if (*result == 0)
1130          {
1131             /* out of memory */
1132             SLPDatabaseClose(dh);
1133             return SLP_ERROR_INTERNAL_ERROR;
1134          }
1135          (*result)->urlarray = (SLPUrlEntry **)((*result) + 1);
1136          (*result)->urlcount = 0;
1137          (*result)->reserved = dh;
1138 
1139          /* rewind enumeration in case we had to reallocate */
1140          SLPDatabaseRewind(dh);
1141 
1142          /* Check if we can use the srvtype index */
1143          if (G_SlpdProperty.srvtypeIsIndexed)
1144          {
1145             size_t srvtypelen = srvrqst->srvtypelen;
1146             const char *srvtype = srvrqst->srvtype;
1147             if (srvtypelen >= 8)
1148             {
1149                if (strncasecmp(srvtype, "service:", 8) == 0)
1150                {
1151                   /* Skip "service:" */
1152                   srvtypelen -= 8;
1153                   srvtype += 8;
1154                }
1155             }
1156             if (memchr(srvtype, ':', srvtypelen))
1157             {
1158                /* Searching for a concrete type - can use the index */
1159                use_index = 1;
1160             }
1161          }
1162 
1163 #ifdef ENABLE_PREDICATES
1164          /* Generate the predicate parse tree */
1165          if (srvrqst->predicatelen > 0)
1166          {
1167             /* TRICKY: Temporarily NULL-terminate the predicate string.  We can do
1168              * this because there is room in the corresponding SLPv2 SRVREG message.
1169              * Don't worry, we fix things up later and it is MUCH faster than a
1170              * malloc for a new buffer 1 byte longer!
1171              */
1172             SLPDPredicateParseResult err;
1173             const char *end;
1174             char *prednullptr = (char *)&srvrqst->predicate[srvrqst->predicatelen];
1175             char prednull;
1176 
1177             prednull = *prednullptr;
1178             *prednullptr = '\0';
1179 
1180 #if defined(ENABLE_SLPv1)
1181             if (msg->header.version == 1)
1182                err = createPredicateParseTreev1(srvrqst->predicate, &end, &predicate_parse_tree, SLPD_PREDICATE_RECURSION_DEPTH);
1183             else
1184 #endif
1185                err = createPredicateParseTree(srvrqst->predicate, &end, &predicate_parse_tree, SLPD_PREDICATE_RECURSION_DEPTH);
1186 
1187             /* Restore the squashed byte */
1188             *prednullptr = prednull;
1189 
1190             if (err == PREDICATE_PARSE_OK && end != prednullptr)
1191             {
1192                /* Found trash characters after the predicate - discard the parse tree before aborting */
1193                SLPDLog("Trash after predicate\n");
1194                freePredicateParseTree(predicate_parse_tree);
1195                return 0;
1196             }
1197             else if (err != PREDICATE_PARSE_OK)
1198             {
1199                SLPDLog("Invalid predicate\n");
1200                /* Nothing matches an invalid predicate */
1201                return 0;
1202             }
1203          }
1204 #endif /* ENABLE_PREDICATES */
1205 
1206          if (use_index)
1207             start_result = SLPDDatabaseSrvRqstStartIndexType(msg,
1208 #ifdef ENABLE_PREDICATES
1209                                                              predicate_parse_tree,
1210 #endif
1211                                                              result);
1212          else
1213          {
1214 #ifdef ENABLE_PREDICATES
1215             /* Analyse the parse tree to see if we can use the attribute indexes.
1216              * If the top node is a leaf node whose attribute name is indexed, or
1217              * if the top node is an AND node and one of its sub-nodes is a leaf
1218              * node whose attribute name is indexed, and the leaf node's type is
1219              * EQUALS, then we can use the index for that attribute name, unless
1220              * the search value starts with a wildcard character.
1221              */
1222             SLPTagIndex * tag_index = (SLPTagIndex *)0;
1223             SLPDPredicateTreeNode * tag_node = (SLPDPredicateTreeNode *)0;
1224 
1225             if (predicate_parse_tree)
1226             {
1227                if (predicate_parse_tree->nodeType == EQUAL && predicate_parse_tree->nodeBody.comparison.value_str[0] != WILDCARD)
1228                {
1229                   tag_index = findTagIndex(predicate_parse_tree->nodeBody.comparison.tag_len, predicate_parse_tree->nodeBody.comparison.tag_str);
1230                   if (tag_index)
1231                      tag_node = predicate_parse_tree;
1232                }
1233                else if (predicate_parse_tree->nodeType == NODE_AND)
1234                {
1235                   SLPDPredicateTreeNode * sub_node = predicate_parse_tree->nodeBody.logical.first;
1236                   while (sub_node)
1237                   {
1238                      if (sub_node->nodeType == EQUAL && sub_node->nodeBody.comparison.value_str[0] != WILDCARD)
1239                      {
1240                         tag_index = findTagIndex(sub_node->nodeBody.comparison.tag_len, sub_node->nodeBody.comparison.tag_str);
1241                         if (tag_index)
1242                         {
1243                            tag_node = sub_node;
1244                            break;
1245                         }
1246                      }
1247                      sub_node = sub_node->next;
1248                   }
1249                }
1250             }
1251             if (tag_index)
1252             {
1253                start_result = SLPDDatabaseSrvRqstStartIndexAttribute(
1254                   tag_node->nodeBody.comparison.value_len,
1255                   tag_node->nodeBody.comparison.value_str,
1256                   tag_index->root_node,
1257                   msg,
1258                   predicate_parse_tree,
1259                   result);
1260             }
1261             else
1262 
1263 #endif /* ENABLE_PREDICATES */
1264 
1265                start_result = SLPDDatabaseSrvRqstStartScan(msg,
1266 #ifdef ENABLE_PREDICATES
1267                                                            predicate_parse_tree,
1268 #endif
1269                                                            result);
1270          }
1271 #ifdef ENABLE_PREDICATES
1272          if (predicate_parse_tree)
1273             freePredicateParseTree(predicate_parse_tree);
1274 #endif
1275          if (start_result == 0)
1276             return 0;
1277 
1278          /* We didn't allocate enough URL entries - loop round after updating the number to allocate */
1279          G_SlpdDatabase.urlcount *= 2;
1280       }
1281    }
1282    return 0;
1283 }
1284 
1285 /** Clean up at the end of a search.
1286  *
1287  * @param[in] result - The result structure previously passed to
1288  *    SLPDDatabaseSrvRqstStart.
1289  */
SLPDDatabaseSrvRqstEnd(SLPDDatabaseSrvRqstResult * result)1290 void SLPDDatabaseSrvRqstEnd(SLPDDatabaseSrvRqstResult * result)
1291 {
1292    if (result)
1293    {
1294       SLPDatabaseClose((SLPDatabaseHandle)result->reserved);
1295       xfree(result);
1296    }
1297 }
1298 
1299 /** Find service types in the database.
1300  *
1301  * @param[in] msg - The SrvTypRqst to find.
1302  * @param[out] result - The address of storage for the result structure.
1303  *
1304  * @return Zero on success, or a non-zero value on failure.
1305  *
1306  * @remarks Caller must pass @p result (dereferenced) to
1307  *    SLPDDatabaseSrvtypeRqstEnd to free it.
1308  */
SLPDDatabaseSrvTypeRqstStart(SLPMessage * msg,SLPDDatabaseSrvTypeRqstResult ** result)1309 int SLPDDatabaseSrvTypeRqstStart(SLPMessage * msg,
1310       SLPDDatabaseSrvTypeRqstResult ** result)
1311 {
1312    SLPDatabaseHandle dh;
1313    SLPDatabaseEntry * entry;
1314    SLPSrvReg * entryreg;
1315    SLPSrvTypeRqst * srvtyperqst;
1316 
1317    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
1318    if (dh)
1319    {
1320       /* srvtyperqst is the SrvTypeRqst being made */
1321       srvtyperqst = &(msg->body.srvtyperqst);
1322 
1323       while (1)
1324       {
1325          /* allocate result with generous srvtypelist of url entry pointers */
1326          *result = (SLPDDatabaseSrvTypeRqstResult *)xrealloc(*result,
1327                sizeof(SLPDDatabaseSrvTypeRqstResult)
1328                      + G_SlpdDatabase.srvtypelistlen);
1329          if (*result == 0)
1330          {
1331             /* out of memory */
1332             SLPDatabaseClose(dh);
1333             return SLP_ERROR_INTERNAL_ERROR;
1334          }
1335          (*result)->srvtypelist = (char*)((*result) + 1);
1336          (*result)->srvtypelistlen = 0;
1337          (*result)->reserved = dh;
1338 
1339          /* rewind enumeration in case we had to reallocate */
1340          SLPDatabaseRewind(dh);
1341 
1342          while (1)
1343          {
1344             entry = SLPDatabaseEnum(dh);
1345             if (entry == 0)
1346                return 0; /* This is the only successful way out */
1347 
1348             /* entry reg is the SrvReg message from the database */
1349             entryreg = &entry->msg->body.srvreg;
1350 
1351             if (SLPCompareNamingAuth(entryreg->srvtypelen, entryreg->srvtype,
1352                      srvtyperqst->namingauthlen, srvtyperqst->namingauth) == 0
1353                   && SLPIntersectStringList(srvtyperqst->scopelistlen,
1354                         srvtyperqst->scopelist, entryreg->scopelistlen,
1355                         entryreg->scopelist)
1356                   && SLPContainsStringList((*result)->srvtypelistlen,
1357                         (*result)->srvtypelist, entryreg->srvtypelen,
1358                         entryreg->srvtype) == 0)
1359             {
1360                /* Check to see if we allocated a big enough srvtypelist, not forgetting to allow for a comma separator */
1361                if ((*result)->srvtypelistlen + entryreg->srvtypelen + 1
1362                      > G_SlpdDatabase.srvtypelistlen)
1363                {
1364                   /* Oops we did not allocate a big enough result */
1365                   G_SlpdDatabase.srvtypelistlen *= 2;
1366                   break;
1367                }
1368 
1369                /* Append a comma if needed */
1370                if ((*result)->srvtypelistlen)
1371                {
1372                   (*result)->srvtypelist[(*result)->srvtypelistlen] = ',';
1373                   (*result)->srvtypelistlen += 1;
1374                }
1375 
1376                /* Append the service type */
1377                memcpy(((*result)->srvtypelist) + (*result)->srvtypelistlen,
1378                      entryreg->srvtype, entryreg->srvtypelen);
1379                (*result)->srvtypelistlen += entryreg->srvtypelen;
1380             }
1381          }
1382       }
1383       SLPDatabaseClose(dh);
1384    }
1385    return 0;
1386 }
1387 
1388 /** Release resources used to find service types in the database.
1389  *
1390  * @param[in] result - A pointer to the result structure previously
1391  *    passed to SLPDDatabaseSrvTypeRqstStart.
1392  */
SLPDDatabaseSrvTypeRqstEnd(SLPDDatabaseSrvTypeRqstResult * result)1393 void SLPDDatabaseSrvTypeRqstEnd(SLPDDatabaseSrvTypeRqstResult * result)
1394 {
1395    if (result)
1396    {
1397       SLPDatabaseClose((SLPDatabaseHandle)result->reserved);
1398       xfree(result);
1399    }
1400 }
1401 
1402 /** Process an entry and incorporate its attributes into the result.
1403  *
1404  * @param[in] msg - request message.
1405  * @param[in] entry - database entry to be tested.
1406  *
1407  * @return Non-zero if the entry matches the request, and should be returned,
1408  *         zero otherwise
1409  */
SLPDDatabaseAttrRqstProcessEntry(SLPAttrRqst * attrrqst,SLPSrvReg * entryreg,SLPDDatabaseAttrRqstResult ** result)1410 static int SLPDDatabaseAttrRqstProcessEntry(
1411    SLPAttrRqst * attrrqst,
1412    SLPSrvReg * entryreg,
1413    SLPDDatabaseAttrRqstResult ** result)
1414 {
1415 #ifdef ENABLE_SLPv2_SECURITY
1416    int i;
1417 #endif
1418 
1419    if (SLPCompareString(attrrqst->urllen, attrrqst->url,
1420             entryreg->urlentry.urllen, entryreg->urlentry.url) == 0
1421          || SLPCompareSrvType(attrrqst->urllen, attrrqst->url,
1422                entryreg->srvtypelen, entryreg->srvtype) == 0)
1423    {
1424       if (SLPIntersectStringList(attrrqst->scopelistlen,
1425             attrrqst->scopelist, entryreg->scopelistlen,
1426             entryreg->scopelist))
1427       {
1428          if (attrrqst->taglistlen == 0)
1429          {
1430 #ifdef ENABLE_SLPv2_SECURITY
1431             if (attrrqst->spistrlen)
1432             {
1433                for (i = 0; i < entryreg->authcount; i++)
1434                   if (SLPCompareString(attrrqst->spistrlen,
1435                         attrrqst->spistr,
1436                         entryreg->autharray[i].spistrlen,
1437                         entryreg->autharray[i].spistr) == 0)
1438                      break;
1439 
1440                if (i == entryreg->authcount)
1441                   return 0;
1442             }
1443 #endif
1444             /* Send back what was registered */
1445             (*result)->attrlistlen = entryreg->attrlistlen;
1446             (*result)->attrlist = (char*)entryreg->attrlist;
1447             (*result)->authcount = entryreg->authcount;
1448             (*result)->autharray = entryreg->autharray;
1449             return 1;
1450          }
1451 #ifdef ENABLE_PREDICATES
1452          else
1453          {
1454             /* Send back a partial list as specified by taglist */
1455             if (SLPDFilterAttributes(entryreg->attrlistlen,
1456                   entryreg->attrlist, attrrqst->taglistlen,
1457                   attrrqst->taglist, &(*result)->attrlistlen,
1458                   &(*result)->attrlist) == 0)
1459             {
1460                (*result)->ispartial = 1;
1461                return 1;
1462             }
1463          }
1464 #endif
1465       }
1466    }
1467    return 0;
1468 }
1469 
1470 typedef struct
1471 {
1472    SLPMessage *                   msg;
1473    SLPDDatabaseAttrRqstResult **  result;
1474    int                            error_code;
1475 } SLPDDatabaseAttrRqstStartIndexCallbackParams;
1476 
1477 /** Handle a database entry located in the database via an index.
1478  *
1479  * @param[in] cookie - context data.
1480  * @param[in] p - database entry.
1481  *
1482  * @remarks @p p represents an entry with a matching srvtype
1483  */
SLPDDatabaseAttrRqstStartIndexCallback(void * cookie,void * p)1484 static void SLPDDatabaseAttrRqstStartIndexCallback(void * cookie, void *p)
1485 {
1486    SLPDDatabaseAttrRqstStartIndexCallbackParams * params = (SLPDDatabaseAttrRqstStartIndexCallbackParams *)cookie;
1487    SLPDDatabaseAttrRqstResult ** result = params->result;
1488    SLPMessage * msg;
1489    SLPDatabaseEntry * entry;
1490 
1491    entry = (SLPDatabaseEntry *)p;
1492    msg = params->msg;
1493 
1494    (void)SLPDDatabaseAttrRqstProcessEntry(&msg->body.attrrqst, &entry->msg->body.srvreg, result);
1495 }
1496 
1497 /** Find attributes in the database via srvtype index
1498  *
1499  * @param[in] msg - The AttrRqst to find.
1500  *
1501  * @param[out] result - The address of storage for the returned
1502  *    result structure.
1503  *
1504  * @return Zero on success, or a non-zero value on failure.
1505  *
1506  * @remarks Caller must pass @p result (dereferenced) to
1507  *    SLPDDatabaseAttrRqstEnd to free it.
1508  */
SLPDDatabaseAttrRqstStartIndexType(SLPMessage * msg,SLPDDatabaseAttrRqstResult ** result)1509 int SLPDDatabaseAttrRqstStartIndexType(SLPMessage * msg,
1510       SLPDDatabaseAttrRqstResult ** result)
1511 {
1512    SLPAttrRqst * attrrqst;
1513    size_t srvtypelen;
1514    const char *srvtype;
1515    const char *p;
1516    SLPNormalisedSrvtype * pNormalisedSrvtype;
1517    SLPDDatabaseAttrRqstStartIndexCallbackParams params;
1518    char urlnull;
1519    char *urlnullptr;
1520 
1521    /* attrrqst is the AttrRqst being made */
1522    attrrqst = &msg->body.attrrqst;
1523 
1524    srvtypelen = attrrqst->urllen;
1525    srvtype = attrrqst->url;
1526 
1527    /* Temporarily NUL-terminate the URL to use strstr */
1528    urlnullptr = (char *)&srvtype[srvtypelen];
1529    urlnull = *urlnullptr;
1530 
1531    /* See if we have a full url, or just a srvtype */
1532    p = strstr(srvtype, "://");
1533 
1534    /* Restore the squashed byte */
1535    *urlnullptr = urlnull;
1536 
1537    if (p)
1538    {
1539       /* full URL - srvtype is the first part */
1540       srvtypelen = p - srvtype;
1541    }
1542 
1543    /* index contains normalised service types, so normalise this one before searching for it */
1544    if (createNormalisedSrvtype(srvtypelen, srvtype, &pNormalisedSrvtype) == SLP_ERROR_OK)
1545    {
1546       /* Search the srvtype index */
1547       params.msg = msg;
1548       params.result = result;
1549       params.error_code = 0;
1550       find_and_call(
1551          srvtype_index_tree,
1552          pNormalisedSrvtype->srvtypelen,
1553          pNormalisedSrvtype->srvtype,
1554          SLPDDatabaseAttrRqstStartIndexCallback,
1555          (void *)&params);
1556 
1557       freeNormalisedSrvtype(pNormalisedSrvtype);
1558    }
1559 
1560    return 0;
1561 }
1562 
1563 /** Find attributes in the database via linear scan
1564  *
1565  * @param[in] msg - The AttrRqst to find.
1566  *
1567  * @param[out] result - The address of storage for the returned
1568  *    result structure.
1569  *
1570  * @return Zero on success, or a non-zero value on failure.
1571  *
1572  * @remarks Caller must pass @p result (dereferenced) to
1573  *    SLPDDatabaseAttrRqstEnd to free it.
1574  */
SLPDDatabaseAttrRqstStartScan(SLPMessage * msg,SLPDDatabaseAttrRqstResult ** result)1575 int SLPDDatabaseAttrRqstStartScan(SLPMessage * msg,
1576       SLPDDatabaseAttrRqstResult ** result)
1577 {
1578    SLPDatabaseHandle dh;
1579    SLPDatabaseEntry * entry;
1580    SLPSrvReg * entryreg;
1581    SLPAttrRqst * attrrqst;
1582 
1583    dh = (*result)->reserved;
1584    if (dh)
1585    {
1586       /* attrrqst is the AttrRqst being made */
1587       attrrqst = &msg->body.attrrqst;
1588 
1589       /* Check to see if there is matching entry */
1590       while (1)
1591       {
1592          entry = SLPDatabaseEnum(dh);
1593          if (entry == 0)
1594             return 0;
1595 
1596          /* entry reg is the SrvReg message from the database */
1597          entryreg = &entry->msg->body.srvreg;
1598 
1599          if (SLPDDatabaseAttrRqstProcessEntry(attrrqst, entryreg, result) != 0)
1600             return 0;
1601       }
1602    }
1603    return 0;
1604 }
1605 
1606 /** Find attributes in the database.
1607  *
1608  * @param[in] msg - The AttrRqst to find.
1609  *
1610  * @param[out] result - The address of storage for the returned
1611  *    result structure.
1612  *
1613  * @return Zero on success, or a non-zero value on failure.
1614  *
1615  * @remarks Caller must pass @p result (dereferenced) to
1616  *    SLPDDatabaseAttrRqstEnd to free it.
1617  */
SLPDDatabaseAttrRqstStart(SLPMessage * msg,SLPDDatabaseAttrRqstResult ** result)1618 int SLPDDatabaseAttrRqstStart(SLPMessage * msg,
1619       SLPDDatabaseAttrRqstResult ** result)
1620 {
1621    SLPDatabaseHandle dh;
1622    int start_result = 1;
1623 
1624    *result = xmalloc(sizeof(SLPDDatabaseAttrRqstResult));
1625    if (*result == 0)
1626       return SLP_ERROR_INTERNAL_ERROR;
1627 
1628    memset(*result, 0, sizeof(SLPDDatabaseAttrRqstResult));
1629    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
1630    if (dh)
1631    {
1632       (*result)->reserved = dh;
1633 
1634       /* Check if we can use the srvtype index */
1635       if (G_SlpdProperty.srvtypeIsIndexed)
1636       {
1637          start_result = SLPDDatabaseAttrRqstStartIndexType(msg, result);
1638       }
1639       else
1640       {
1641          start_result = SLPDDatabaseAttrRqstStartScan(msg, result);
1642       }
1643    }
1644 
1645    /** TODO: Figure out what to do with start_result. */
1646    (void)start_result;
1647 
1648    return 0;
1649 }
1650 
1651 /** Release resources used to find attributes in the database.
1652  *
1653  * @param[in] result - A pointer to the result structure previously
1654  *    passed to SLPDDatabaseSrvTypeRqstStart.
1655  */
SLPDDatabaseAttrRqstEnd(SLPDDatabaseAttrRqstResult * result)1656 void SLPDDatabaseAttrRqstEnd(SLPDDatabaseAttrRqstResult * result)
1657 {
1658    if (result)
1659    {
1660       SLPDatabaseClose((SLPDatabaseHandle)result->reserved);
1661       if (result->ispartial && result->attrlist)
1662          xfree(result->attrlist);
1663       xfree(result);
1664    }
1665 }
1666 
1667 /** Start an enumeration of the entire database.
1668  *
1669  * @return An enumeration handle that is passed to subsequent calls to
1670  *    SLPDDatabaseEnum. Returns 0 on failure. Returned enumeration handle
1671  *    (if not 0) must be passed to SLPDDatabaseEnumEnd when you are done
1672  *    with it.
1673  */
SLPDDatabaseEnumStart(void)1674 void * SLPDDatabaseEnumStart(void)
1675 {
1676    return SLPDatabaseOpen(&G_SlpdDatabase.database);
1677 }
1678 
1679 /** Enumerate through all entries of the database.
1680  *
1681  * @param[in] eh - A pointer to opaque data that is used to maintain
1682  *    enumerate entries. Pass in a pointer to NULL to start the process.
1683  *
1684  * @param[out] msg - The address of storage for a SrvReg message object.
1685  * @param[out] buf - The address of storage for a SrvReg buffer object.
1686  *
1687  * @return A pointer to the enumerated entry or 0 if end of enumeration.
1688  */
SLPDDatabaseEnum(void * eh,SLPMessage ** msg,SLPBuffer * buf)1689 SLPMessage * SLPDDatabaseEnum(void * eh, SLPMessage ** msg, SLPBuffer * buf)
1690 {
1691    SLPDatabaseEntry * entry;
1692    entry = SLPDatabaseEnum((SLPDatabaseHandle)eh);
1693    if (entry)
1694    {
1695       *msg = entry->msg;
1696       *buf = entry->buf;
1697    }
1698    else
1699    {
1700       *msg = 0;
1701       *buf = 0;
1702    }
1703    return *msg;
1704 }
1705 
1706 /** End an enumeration started by SLPDDatabaseEnumStart.
1707  *
1708  * @param[in] eh - The enumeration handle returned by SLPDDatabaseEnumStart.
1709  */
SLPDDatabaseEnumEnd(void * eh)1710 void SLPDDatabaseEnumEnd(void * eh)
1711 {
1712    if (eh)
1713       SLPDatabaseClose((SLPDatabaseHandle)eh);
1714 }
1715 
1716 /** Indicates whether or not the database is empty.
1717  *
1718  * Note also that this will return false if the
1719  * database could not be opened as well as if it
1720  * could be opened but is empty.
1721  *
1722  * @return A boolean value; True if the database is empty, False if not.
1723  */
SLPDDatabaseIsEmpty(void)1724 int SLPDDatabaseIsEmpty(void)
1725 {
1726    int result = 1;
1727 
1728    SLPDatabaseHandle dh;
1729    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
1730    if (!dh)
1731       result = 0;
1732    else
1733    {
1734       result = SLPDatabaseCount(dh) == 0;
1735       SLPDatabaseClose(dh);
1736    }
1737    return result;
1738 }
1739 
1740 /** Initialize the database with registrations from a regfile.
1741  *
1742  * @param[in] regfile - The registration file to register.
1743  *    Pass in 0 for no registration file.
1744  *
1745  * @return Zero on success, or a non-zero value on error.
1746  */
SLPDDatabaseInit(const char * regfile)1747 int SLPDDatabaseInit(const char * regfile)
1748 {
1749 #ifdef ENABLE_PREDICATES
1750    char *taglist;
1751 #endif
1752 
1753    /* Set initial values */
1754    memset(&G_SlpdDatabase,0,sizeof(G_SlpdDatabase));
1755    G_SlpdDatabase.urlcount = SLPDDATABASE_INITIAL_URLCOUNT;
1756    G_SlpdDatabase.srvtypelistlen = SLPDDATABASE_INITIAL_SRVTYPELISTLEN;
1757    SLPDatabaseInit(&G_SlpdDatabase.database);
1758 
1759 #ifdef ENABLE_PREDICATES
1760    /* Initialise the tag indexes */
1761    /* Assumption: indexedAttributes cannot change after startup */
1762    taglist = G_SlpdProperty.indexedAttributes;
1763    if (taglist)
1764    {
1765       /* A tag list is like a set of attributes containing only keywords */
1766       int result = SLP_ERROR_OK;
1767       const char * tag;
1768       SLPType type;
1769       SLPAttrIterator iter_h;
1770       SLPAttributes attr;
1771 
1772       if (SLPAttrAlloc("en", NULL, SLP_FALSE, &attr) == 0)
1773       {
1774          if (SLPAttrFreshen(attr, taglist) != 0)
1775          {
1776             SLPDLog("List of indexed attributes is invalid\n");
1777             result = SLP_ERROR_INTERNAL_ERROR;
1778          }
1779          else
1780          {
1781             /* Now process the list, checking all the "attributes" are keywords */
1782             SLPError err = SLPAttrIteratorAlloc(attr, &iter_h);
1783 
1784             if (err == SLP_OK)
1785             {
1786                /* For each attribute name */
1787                while (SLPAttrIterNext(iter_h, (char const * *) &tag, &type) == SLP_TRUE)
1788                {
1789                   /* Ensure it is a keyword value */
1790                   if (type == SLP_KEYWORD)
1791                   {
1792                      /* Set up the index for this tag */
1793                      if ((err = addTagIndex(strlen(tag), tag)) != SLP_ERROR_OK)
1794                      {
1795                         SLPDLog("Error creating index for indexed attributes\n");
1796                         result = SLP_ERROR_INTERNAL_ERROR;
1797                         break;
1798                      }
1799                   }
1800                   else
1801                   {
1802                      /* Non-keyword value */
1803                      SLPDLog("Error processing list of indexed attributes\n");
1804                      result = SLP_ERROR_INTERNAL_ERROR;
1805                      break;
1806                   }
1807                }
1808                SLPAttrIteratorFree(iter_h);
1809             }
1810             else
1811             {
1812                SLPDLog("Memory allocation fail processing list of indexed attributes\n");
1813                result = SLP_ERROR_INTERNAL_ERROR;
1814             }
1815          }
1816       }
1817       else
1818       {
1819          SLPDLog("Memory allocation fail processing list of indexed attributes\n");
1820          result = SLP_ERROR_INTERNAL_ERROR;
1821       }
1822       SLPAttrFree(attr);
1823       if (result != SLP_ERROR_OK)
1824          return result;
1825    }
1826 #endif /* ENABLE_PREDICATES */
1827 
1828    /* Call the reinit function */
1829    return SLPDDatabaseReInit(regfile);
1830 }
1831 
1832 /** Re-initialize the database with changed registrations from a regfile.
1833  *
1834  * @param[in] regfile - The registration file to register.
1835  *
1836  * @return Zzero on success, or a non-zero value on error.
1837  */
SLPDDatabaseReInit(const char * regfile)1838 int SLPDDatabaseReInit(const char * regfile)
1839 {
1840    SLPDatabaseHandle dh;
1841    SLPDatabaseEntry * entry;
1842    SLPMessage * msg;
1843    SLPBuffer buf;
1844    FILE * fd;
1845 
1846    /* open the database handle and remove all the static registrations
1847       (the registrations from the /etc/slp.reg) file. */
1848    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
1849    if (dh)
1850    {
1851       while (1)
1852       {
1853          entry = SLPDatabaseEnum(dh);
1854          if (entry == 0)
1855             break;
1856 
1857          if (entry->msg->body.srvreg.source == SLP_REG_SOURCE_STATIC)
1858             SLPDDatabaseRemove(dh, entry);
1859       }
1860       SLPDatabaseClose(dh);
1861    }
1862 
1863    /* read static registration file if any */
1864    if (regfile)
1865    {
1866       fd = fopen(regfile, "rb");
1867       if (fd)
1868       {
1869          while (SLPDRegFileReadSrvReg(fd, &msg, &buf) == 0)
1870          {
1871             if (SLPDDatabaseReg(msg, buf) != SLP_ERROR_OK)
1872             {
1873                /* Only if the reg *didn't* succeed do we free the memory */
1874                SLPMessageFree(msg);
1875                SLPBufferFree(buf);
1876             }
1877          }
1878          fclose(fd);
1879       }
1880    }
1881    return 0;
1882 }
1883 
1884 #ifdef DEBUG
1885 /** Cleans up all resources used by the database.
1886  */
SLPDDatabaseDeinit(void)1887 void SLPDDatabaseDeinit(void)
1888 {
1889    SLPDatabaseDeinit(&G_SlpdDatabase.database);
1890 }
1891 
1892 /** Dumps currently valid service registrations present with slpd.
1893  */
SLPDDatabaseDump(void)1894 void SLPDDatabaseDump(void)
1895 {
1896    SLPMessage * msg;
1897    SLPBuffer buf;
1898    void * eh;
1899 
1900    eh = SLPDDatabaseEnumStart();
1901    if (eh)
1902    {
1903       SLPDLog("\n========================================================================\n");
1904       SLPDLog("Dumping Registrations\n");
1905       SLPDLog("========================================================================\n");
1906       while (SLPDDatabaseEnum(eh, &msg, &buf))
1907       {
1908          SLPDLogMessageInternals(msg);
1909          SLPDLog("\n");
1910       }
1911       SLPDDatabaseEnumEnd(eh);
1912    }
1913 }
1914 #endif
1915 
1916 #ifdef DEBUG
SLPDDatabaseUsr1(void)1917 void SLPDDatabaseUsr1(void)
1918 {
1919    SLPTagIndex *tag_index;
1920    if (!srvtype_index_tree)
1921       SLPDLog("Service type index is empty\n");
1922    else
1923    {
1924       SLPDLog("Service type index tree:\n");
1925       print_tree(srvtype_index_tree, 1);
1926    }
1927    if (!tag_index_head)
1928       SLPDLog("Tag index list is empty\n");
1929    else
1930    {
1931       for (tag_index = tag_index_head; tag_index; tag_index = tag_index->next)
1932       {
1933          char buffer[100];
1934          strncpy(buffer, tag_index->tag, tag_index->tag_len);
1935          buffer[tag_index->tag_len] = '\0';
1936          SLPDLog("Tag Index Tree for %s\n", buffer);
1937          print_tree(tag_index->root_node, 1);
1938       }
1939    }
1940 }
1941 #endif
1942 /*=========================================================================*/
1943