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 *)¶ms);
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 *)¶ms);
1018 else
1019 find_and_call(attribute_index,
1020 processed_searchstr_len,
1021 processed_searchstr,
1022 SLPDDatabaseSrvRqstStartIndexCallback,
1023 (void *)¶ms);
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 *)¶ms);
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