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 /** Keeps track of known DA's.
34 *
35 * @file slpd_knownda.c
36 * @author Matthew Peterson, John Calcote (jcalcote@novell.com)
37 * @attention Please submit patches to http://www.openslp.org
38 * @ingroup SlpdCode
39 */
40
41 #include "slpd_knownda.h"
42 #include "slpd_property.h"
43 #include "slpd_database.h"
44 #include "slpd_socket.h"
45 #include "slpd_outgoing.h"
46 #include "slpd_log.h"
47 #include "slpd.h"
48 #include "slpd_incoming.h" /*For the global incoming socket map. Instead of creating a new
49 socket for every multicast and broadcast, we'll simply send
50 on the existing sockets, using their network interfaces*/
51
52 #ifdef ENABLE_SLPv2_SECURITY
53 # include "slpd_spi.h"
54 #endif
55
56 #include "slp_xmalloc.h"
57 #include "slp_v1message.h"
58 #include "slp_utf8.h"
59 #include "slp_compare.h"
60 #include "slp_xid.h"
61 #include "slp_dhcp.h"
62 #include "slp_parse.h"
63 #include "slp_net.h"
64
65 #ifdef ENABLE_SLPv2_SECURITY
66 # include "slp_auth.h"
67 # include "slp_spi.h"
68 #endif
69
70 /*=========================================================================*/
71 SLPDatabase G_SlpdKnownDAs;
72 /* The database of DAAdverts from DAs known to slpd. */
73 /*=========================================================================*/
74
75 /*=========================================================================*/
76 int G_KnownDATimeSinceLastRefresh = 0;
77 /*=========================================================================*/
78
79 /*=========================================================================*/
80 char* G_ifaceurls = 0;
81 size_t G_ifaceurlsLen = 0;
82 /* Used to filter out our own DA urls */
83 /*=========================================================================*/
84
85 /*-------------------------------------------------------------------------*/
MakeActiveDiscoveryRqst(int ismcast,SLPBuffer * buffer)86 int MakeActiveDiscoveryRqst(int ismcast, SLPBuffer * buffer)
87 /* Pack a buffer with service:directory-agent SrvRqst *
88 * *
89 * Caller must free buffer *
90 *-------------------------------------------------------------------------*/
91 {
92 size_t size;
93 void * eh;
94 SLPMessage * msg;
95 char * prlist = 0;
96 size_t prlistlen = 0;
97 int errorcode = 0;
98 SLPBuffer tmp = 0;
99 SLPBuffer result = *buffer;
100 char addr_str[INET6_ADDRSTRLEN];
101
102 /*-------------------------------------------------*/
103 /* Generate a DA service request buffer to be sent */
104 /*-------------------------------------------------*/
105 /* determine the size of the fixed portion of the SRVRQST */
106 size = 47; /* 14 bytes for the header */
107 /* 2 bytes for the prlistlen */
108 /* 2 bytes for the srvtype length */
109 /* 23 bytes for "service:directory-agent" srvtype */
110 /* 2 bytes for scopelistlen */
111 /* 2 bytes for predicatelen */
112 /* 2 bytes for sprstrlen */
113
114 /* figure out what our Prlist will be by going through our list of */
115 /* known DAs */
116 prlistlen = 0;
117 prlist = xmalloc(G_SlpdProperty.MTU - size);
118 if (prlist == 0)
119 {
120 /* out of memory */
121 errorcode = SLP_ERROR_INTERNAL_ERROR;
122 goto FINISHED;
123 }
124
125 *prlist = 0;
126 /* Don't send active discoveries to DAs we already know about */
127 eh = SLPDKnownDAEnumStart();
128 if (eh)
129 {
130 while (1)
131 {
132 size_t addrstrlen;
133
134 if (SLPDKnownDAEnum(eh, &msg, &tmp) == 0)
135 break;
136 /*Make sure we have room for the potential pr addr*/
137 if(G_SlpdProperty.MTU - size < prlistlen + sizeof(addr_str) + 1) /*1 for the comma*/
138 break;
139
140 *addr_str = 0;
141 SLPNetSockAddrStorageToString(&(msg->peer), addr_str,
142 sizeof(addr_str));
143 addrstrlen = strlen(addr_str);
144 if (addrstrlen > 0 && SLPContainsStringList(prlistlen,
145 prlist, addrstrlen, addr_str) == 0)
146 {
147 if (prlistlen != 0)
148 strcat(prlist, ",");
149 strcat(prlist, addr_str);
150 prlistlen = strlen(prlist);
151 }
152 }
153
154 SLPDKnownDAEnumEnd(eh);
155 }
156
157 /* Allocate the send buffer */
158 size += G_SlpdProperty.localeLen + prlistlen;
159 result = SLPBufferRealloc(result, size);
160 if (result == 0)
161 {
162 /* out of memory */
163 errorcode = SLP_ERROR_INTERNAL_ERROR;
164 goto FINISHED;
165 }
166
167 /*------------------------------------------------------------*/
168 /* Build a buffer containing the fixed portion of the SRVRQST */
169 /*------------------------------------------------------------*/
170
171 /* version */
172 *result->curpos++ = 2;
173
174 /* function id */
175 *result->curpos++ = SLP_FUNCT_SRVRQST;
176
177 /* length */
178 PutUINT24(&result->curpos, size);
179
180 /* flags */
181 PutUINT16(&result->curpos, (ismcast ? SLP_FLAG_MCAST : 0));
182
183 /* ext offset */
184 PutUINT24(&result->curpos, 0);
185
186 /* xid */
187 PutUINT16(&result->curpos, SLPXidGenerate());
188
189 /* lang tag len */
190 PutUINT16(&result->curpos, G_SlpdProperty.localeLen);
191
192 /* lang tag */
193 memcpy(result->curpos, G_SlpdProperty.locale, G_SlpdProperty.localeLen);
194 result->curpos += G_SlpdProperty.localeLen;
195
196 /* Prlist */
197 PutUINT16(&result->curpos, prlistlen);
198 memcpy(result->curpos, prlist, prlistlen);
199 result->curpos += prlistlen;
200
201 /* service type */
202 PutUINT16(&result->curpos, 23);
203
204 /* 23 is the length of SLP_DA_SERVICE_TYPE */
205 memcpy(result->curpos, SLP_DA_SERVICE_TYPE, 23);
206 result->curpos += 23;
207
208 /* scope list zero length */
209 PutUINT16(&result->curpos, 0);
210
211 /* predicate zero length */
212 PutUINT16(&result->curpos, 0);
213
214 /* spi list zero length */
215 PutUINT16(&result->curpos, 0);
216
217 *buffer = result;
218
219 FINISHED:
220
221 if (prlist)
222 xfree(prlist);
223
224 /** TODO: incorporate errorcode into return value. */
225 (void)errorcode;
226
227 return 0;
228 }
229
230
231 /*-------------------------------------------------------------------------*/
SLPDKnownDARegisterAll(SLPMessage * daadvert,int immortalonly)232 void SLPDKnownDARegisterAll(SLPMessage * daadvert, int immortalonly)
233 /* registers all services with specified DA */
234 /*-------------------------------------------------------------------------*/
235 {
236 SLPBuffer buf;
237 SLPMessage * msg;
238 SLPSrvReg * srvreg;
239 SLPDSocket * sock;
240 SLPBuffer sendbuf = 0;
241 void * handle = 0;
242
243 /*---------------------------------------------------------------*/
244 /* Check to see if the database is empty and open an enumeration */
245 /* handle if it is not empty */
246 /*---------------------------------------------------------------*/
247 if (SLPDDatabaseIsEmpty())
248 return;
249
250 /*--------------------------------------*/
251 /* Never do a Register All to ourselves */
252 /*--------------------------------------*/
253 if(SLPIntersectStringList(G_ifaceurlsLen, G_ifaceurls, daadvert->body.daadvert.urllen,
254 daadvert->body.daadvert.url) > 0)
255 return;
256
257 handle = SLPDDatabaseEnumStart();
258 if (handle == 0)
259 return;
260
261 /*----------------------------------------------*/
262 /* Establish a new connection with the known DA */
263 /*----------------------------------------------*/
264 sock = SLPDOutgoingConnect(0, &(daadvert->peer));
265 if (sock)
266 while (1)
267 {
268 msg = SLPDDatabaseEnum(handle, &msg, &buf);
269 if (msg == NULL)
270 break;
271 srvreg = &(msg->body.srvreg);
272
273 /*-----------------------------------------------*/
274 /* If so instructed, skip mortal registrations */
275 /*-----------------------------------------------*/
276 if (immortalonly && srvreg->urlentry.lifetime < SLP_LIFETIME_MAXIMUM)
277 continue;
278
279 /*---------------------------------------------------------*/
280 /* Only register local (or static) registrations of scopes */
281 /* supported by peer DA */
282 /*---------------------------------------------------------*/
283 if ((srvreg->source == SLP_REG_SOURCE_LOCAL
284 || srvreg->source == SLP_REG_SOURCE_STATIC)
285 && SLPIntersectStringList(srvreg->scopelistlen,
286 srvreg->scopelist,
287 daadvert->body.daadvert.scopelistlen,
288 daadvert->body.daadvert.scopelist))
289 {
290 sendbuf = SLPBufferDup(buf);
291 if (sendbuf)
292 {
293 /*--------------------------------------------------------------*/
294 /* link newly constructed buffer to socket resendlist, and send */
295 /*--------------------------------------------------------------*/
296 SLPListLinkTail(&(sock->sendlist), (SLPListItem *) sendbuf);
297 SLPDOutgoingDatagramWrite(sock, sendbuf);
298 }
299 }
300 }
301
302 SLPDDatabaseEnumEnd(handle);
303 }
304
305
306 /*-------------------------------------------------------------------------*/
307 /* Pack a buffer with a SrvDereg message using information from an existing
308 * SrvReg message
309 *
310 * Caller must free outbuf
311 *-------------------------------------------------------------------------*/
MakeSrvderegFromSrvReg(SLPMessage * msg,SLPBuffer inbuf,SLPBuffer * outbuf)312 int MakeSrvderegFromSrvReg(SLPMessage * msg, SLPBuffer inbuf, SLPBuffer * outbuf)
313 {
314 size_t size;
315 SLPBuffer sendbuf;
316 SLPSrvReg * srvreg;
317
318 (void)inbuf;
319
320 srvreg = &(msg->body.srvreg);
321
322 /*-------------------------------------------------------------*/
323 /* ensure the buffer is big enough to handle the whole srvdereg*/
324 /*-------------------------------------------------------------*/
325 size = msg->header.langtaglen + 18; /* 14 bytes for header */
326 /* 2 bytes for scopelen */
327 /* see below for URLEntry */
328 /* 2 bytes for taglist len */
329 if (srvreg->urlentry.opaque)
330 size += srvreg->urlentry.opaquelen;
331 else
332 {
333 size += 6; /* +6 for the static portion of the url-entry */
334 size += srvreg->urlentry.urllen;
335 }
336 size += srvreg->scopelistlen;
337 /* taglistlen is always 0 */
338
339 *outbuf = sendbuf = SLPBufferAlloc(size);
340 if (*outbuf == NULL)
341 return SLP_ERROR_INTERNAL_ERROR;
342
343 /*----------------------*/
344 /* Construct a SrvDereg */
345 /*----------------------*/
346
347 /* version */
348 *sendbuf->curpos++ = 2;
349
350 /* function id */
351 *sendbuf->curpos++ = SLP_FUNCT_SRVDEREG;
352
353 /* length */
354 PutUINT24(&sendbuf->curpos, size);
355
356 /* flags */
357 PutUINT16(&sendbuf->curpos, (size > (size_t)G_SlpdProperty.MTU?
358 SLP_FLAG_OVERFLOW: 0));
359
360 /* ext offset */
361 PutUINT24(&sendbuf->curpos, 0);
362
363 /* xid */
364 PutUINT16(&sendbuf->curpos, SLPXidGenerate());
365
366 /* lang tag len */
367 PutUINT16(&sendbuf->curpos, msg->header.langtaglen);
368
369 /* lang tag */
370 memcpy(sendbuf->curpos, msg->header.langtag, msg->header.langtaglen);
371 sendbuf->curpos += msg->header.langtaglen;
372
373 /* scope list */
374 PutUINT16(&sendbuf->curpos, srvreg->scopelistlen);
375 memcpy(sendbuf->curpos, srvreg->scopelist, srvreg->scopelistlen);
376 sendbuf->curpos += srvreg->scopelistlen;
377
378 /* the URL entry */
379 #ifdef ENABLE_SLPv1
380 if (srvreg->urlentry.opaque == 0)
381 {
382 /* url-entry reserved */
383 *sendbuf->curpos++ = 0;
384
385 /* url-entry lifetime */
386 PutUINT16(&sendbuf->curpos, srvreg->urlentry.lifetime);
387
388 /* url-entry urllen */
389 PutUINT16(&sendbuf->curpos, srvreg->urlentry.urllen);
390
391 /* url-entry url */
392 memcpy(sendbuf->curpos, srvreg->urlentry.url, srvreg->urlentry.urllen);
393 sendbuf->curpos += srvreg->urlentry.urllen;
394
395 /* url-entry authcount */
396 *sendbuf->curpos++ = 0;
397 }
398 else
399 #endif /* ENABLE_SLPv1 */
400 {
401 memcpy(sendbuf->curpos, srvreg->urlentry.opaque,
402 srvreg->urlentry.opaquelen);
403 sendbuf->curpos += srvreg->urlentry.opaquelen;
404 }
405
406 /* taglist (always 0) */
407 PutUINT16(&sendbuf->curpos, 0);
408
409 return 0;
410 }
411
412
413 /*-------------------------------------------------------------------------*/
SLPDKnownDADeregisterAll(SLPMessage * daadvert)414 void SLPDKnownDADeregisterAll(SLPMessage * daadvert)
415 /* de-registers all services with specified DA */
416 /*-------------------------------------------------------------------------*/
417 {
418 SLPBuffer buf;
419 SLPMessage * msg;
420 SLPSrvReg * srvreg;
421 SLPDSocket * sock;
422 SLPBuffer sendbuf = 0;
423 void * handle = 0;
424
425 /*---------------------------------------------------------------*/
426 /* Check to see if the database is empty and open an enumeration */
427 /* handle if it is not empty */
428 /*---------------------------------------------------------------*/
429 if (SLPDDatabaseIsEmpty())
430 return;
431 handle = SLPDDatabaseEnumStart();
432 if (handle == 0)
433 return;
434
435 /* Establish a new connection with the known DA */
436 sock = SLPDOutgoingConnect(0, &(daadvert->peer));
437 if (sock)
438 while (1)
439 {
440 msg = SLPDDatabaseEnum(handle, &msg, &buf);
441 if (msg == NULL)
442 break;
443 srvreg = &(msg->body.srvreg);
444
445 /*-----------------------------------------------------------*/
446 /* Only Deregister local (or static) registrations of scopes */
447 /* supported by peer DA */
448 /*-----------------------------------------------------------*/
449 if ( ( srvreg->source == SLP_REG_SOURCE_LOCAL ||
450 srvreg->source == SLP_REG_SOURCE_STATIC ) &&
451 SLPIntersectStringList(srvreg->scopelistlen,
452 srvreg->scopelist,
453 daadvert->body.daadvert.scopelistlen,
454 daadvert->body.daadvert.scopelist) )
455 {
456 if (MakeSrvderegFromSrvReg(msg, buf, &sendbuf) == 0)
457 {
458 /*--------------------------------------------------------------*/
459 /* link newly constructed buffer to socket resendlist, and send */
460 /*--------------------------------------------------------------*/
461 SLPListLinkTail(&(sock->sendlist), (SLPListItem *) sendbuf);
462 SLPDOutgoingDatagramWrite(sock, sendbuf);
463 }
464 }
465 }
466
467 SLPDDatabaseEnumEnd(handle);
468 }
469
470
471 /*=========================================================================*/
SLPDKnownDAFromDHCP()472 int SLPDKnownDAFromDHCP()
473 /* Queries DHCP for configured DA's. IPv4 is the only supported address */
474 /* family presently. */
475 /* returns zero on success, Non-zero on failure */
476 /*=========================================================================*/
477 {
478 SLPBuffer buf;
479 DHCPContext ctx;
480 SLPDSocket * sock;
481 struct sockaddr_storage daaddr;
482 unsigned char * alp;
483 unsigned char dhcpOpts[] =
484 {
485 TAG_SLP_SCOPE, TAG_SLP_DA
486 };
487
488 *ctx.scopelist = 0;
489 ctx.addrlistlen = 0;
490
491 DHCPGetOptionInfo(dhcpOpts, sizeof(dhcpOpts), DHCPParseSLPTags, &ctx);
492
493 alp = ctx.addrlist;
494 while (ctx.addrlistlen >= 4)
495 {
496 memset(&daaddr, 0, sizeof(struct sockaddr_in)); /*Some platforms require sin_zero be 0*/
497 daaddr.ss_family = AF_INET;
498 memcpy(&(((struct sockaddr_in *) &daaddr)->sin_addr.s_addr), alp, 4);
499 if (&(((struct sockaddr_in *) &daaddr)->sin_addr.s_addr))
500 {
501 /*--------------------------------------------------------
502 Get an outgoing socket to the DA and set it up to make
503 the service:directoryagent request
504 --------------------------------------------------------*/
505 sock = SLPDOutgoingConnect(0, &daaddr);
506 if (sock)
507 {
508 buf = 0;
509 if (MakeActiveDiscoveryRqst(0, &buf) == 0)
510 {
511 SLPListLinkTail(&(sock->sendlist), (SLPListItem *) buf);
512 SLPDOutgoingDatagramWrite(sock, buf);
513 }
514 }
515 }
516 ctx.addrlistlen -= 4;
517 alp += 4;
518 }
519 return 0;
520 }
521
522 /*=========================================================================*/
SLPKnownDAFromProperties()523 int SLPKnownDAFromProperties()
524 /* Queries static configuration for DA's. */
525 /* */
526 /* returns zero on success, Non-zero on failure */
527 /*=========================================================================*/
528 {
529 char * temp;
530 char * tempend;
531 char * slider1;
532 char * slider2;
533 struct addrinfo * ai;
534 struct addrinfo * ai_ref;
535 struct sockaddr_storage daaddr;
536 int daaddr_isset;
537 SLPDSocket * sock;
538 SLPBuffer buf;
539
540 if (G_SlpdProperty.DAAddresses && *G_SlpdProperty.DAAddresses)
541 {
542 temp = slider1 = xstrdup(G_SlpdProperty.DAAddresses);
543 if (temp)
544 {
545 tempend = temp + strlen(temp);
546 while (slider1 < tempend)
547 {
548 while (*slider1 && *slider1 == ' ')
549 slider1++;
550 slider2 = slider1;
551 while (*slider2 && *slider2 != ',')
552 slider2++;
553 *slider2++ = 0;
554
555 daaddr_isset = 0;
556 if (inet_pton(AF_INET6, slider1,
557 &((struct sockaddr_in6 *) &daaddr)->sin6_addr) > 0)
558 {
559 daaddr.ss_family = AF_INET6;
560 ((struct sockaddr_in6 *) &daaddr)->sin6_family = AF_INET6;
561 daaddr_isset = 1;
562 }
563 else if (inet_pton(AF_INET, slider1,
564 &((struct sockaddr_in *) &daaddr)->sin_addr) > 0)
565 {
566 daaddr.ss_family = AF_INET;
567 ((struct sockaddr_in *) &daaddr)->sin_family = AF_INET;
568 daaddr_isset = 1;
569 }
570 else if (getaddrinfo(slider1, NULL, NULL, &ai) == 0)
571 {
572 ai_ref = ai;
573 while (ai_ref != NULL)
574 {
575 if (SLPNetIsIPV6() && ai_ref->ai_addr->sa_family == AF_INET6)
576 {
577 memcpy(&daaddr, &ai_ref->ai_addr,
578 sizeof(struct sockaddr_in6));
579 daaddr_isset = 1;
580 break;
581 /* we prefer IPv6 when configured, so we'll take the first IPv6 address and break */
582 }
583 else if (SLPNetIsIPV4()
584 && !daaddr_isset
585 && ai_ref->ai_addr->sa_family == AF_INET)
586 {
587 memcpy(&daaddr, &ai_ref->ai_addr,
588 sizeof(struct sockaddr_in));
589 daaddr_isset = 1;
590 /* we'll continue searching for an IPv6 address, but we'll use the first IPv4 address if none are found */
591 }
592 ai_ref = ai_ref->ai_next;
593 }
594
595 freeaddrinfo(ai);
596 }
597
598 if (daaddr_isset)
599 {
600 /*--------------------------------------------------------*/
601 /* Get an outgoing socket to the DA and set it up to make */
602 /* the service:directoryagent request */
603 /*--------------------------------------------------------*/
604 sock = SLPDOutgoingConnect(0, &daaddr);
605 if (sock)
606 {
607 buf = 0;
608 if (MakeActiveDiscoveryRqst(0, &buf) == 0)
609 {
610 SLPListLinkTail(&(sock->sendlist), (SLPListItem *) buf);
611 SLPDOutgoingDatagramWrite(sock, buf);
612 }
613 }
614 }
615 slider1 = slider2;
616 }
617 xfree(temp);
618 }
619 }
620 return 0;
621 }
622
623 /*=========================================================================*/
SLPDKnownDAGenerateIfaceURLs()624 void SLPDKnownDAGenerateIfaceURLs()
625 /* Initializes G_ifaceurls and G_ifaceurlsLen from GSlpdProperties.ifaceInfo */
626 /* Much of this is pulled from SLPDKnownDAGenerateMyDAAdvert */
627 /*=========================================================================*/
628 {
629 int i;
630 char localaddr_str[INET6_ADDRSTRLEN + 2];
631 struct sockaddr_storage* localaddr;
632 size_t strmax = G_SlpdProperty.ifaceInfo.iface_count * (G_SlpdProperty.urlPrefixLen + INET6_ADDRSTRLEN + 2 + 1); /*The +1 is for the ','*/
633
634 if(strmax)
635 {
636 ++strmax; /*For the terminating NULL*/
637 G_ifaceurls = xmalloc(strmax);
638 if(G_ifaceurls)
639 {
640 G_ifaceurls[0] = '\0';
641 for(i = 0; i < G_SlpdProperty.ifaceInfo.iface_count; ++i)
642 {
643 /*build the ipaddr string*/
644 localaddr_str[0] = '\0';
645 localaddr = G_SlpdProperty.ifaceInfo.iface_addr + i;
646 if (localaddr->ss_family == AF_INET)
647 inet_ntop(localaddr->ss_family,
648 &((struct sockaddr_in *) localaddr)->sin_addr, localaddr_str,
649 sizeof(localaddr_str));
650 else if (localaddr->ss_family == AF_INET6)
651 {
652 strcpy(localaddr_str, "[");
653 inet_ntop(localaddr->ss_family,
654 &((struct sockaddr_in6 *) localaddr)->sin6_addr,
655 &localaddr_str[1], sizeof(localaddr_str) - 1);
656 strcat(localaddr_str, "]");
657 }
658
659 /*Add the url to G_ifaceurls*/
660 strncat(G_ifaceurls, G_SlpdProperty.urlPrefix, G_SlpdProperty.urlPrefixLen);
661 strcat(G_ifaceurls, localaddr_str);
662 strcat(G_ifaceurls, ",");
663 }
664 G_ifaceurlsLen = strlen(G_ifaceurls);
665 }
666 }
667 }
668
669 /*=========================================================================*/
SLPDKnownDAInit()670 int SLPDKnownDAInit()
671 /* Initializes the KnownDA list. Removes all entries and adds entries */
672 /* that are statically configured. Adds entries configured through DHCP. */
673 /* */
674 /* returns zero on success, Non-zero on failure */
675 /*=========================================================================*/
676 {
677 /*--------------------------------------*/
678 /* Set initialize the DAAdvert database */
679 /*--------------------------------------*/
680 SLPDatabaseInit(&G_SlpdKnownDAs);
681
682 /*-----------------------------------------------------------------*/
683 /* Added statically configured DAs to the Known DA List by sending */
684 /* active DA discovery requests directly to them */
685 /*-----------------------------------------------------------------*/
686 SLPKnownDAFromProperties();
687
688 /*-----------------------------------------------------------------*/
689 /* Discover DHCP DA's and add them to the active discovery list. */
690 /*-----------------------------------------------------------------*/
691 if (G_SlpdProperty.useDHCP)
692 SLPDKnownDAFromDHCP();
693
694 /*------------------------------------------------------------------*/
695 /* Generate the list of our URLs */
696 /*------------------------------------------------------------------*/
697 SLPDKnownDAGenerateIfaceURLs();
698
699 /*----------------------------------------*/
700 /* Lastly, Perform first active discovery */
701 /*----------------------------------------*/
702 SLPDKnownDAActiveDiscovery(0);
703
704 return 0;
705 }
706
707
708 /*=========================================================================*/
SLPDKnownDADeinit()709 int SLPDKnownDADeinit()
710 /* Deinitializes the KnownDA list. Removes all entries and deregisters */
711 /* all services. */
712 /* */
713 /* returns zero on success, Non-zero on failure */
714 /*=========================================================================*/
715 {
716 SLPDatabaseHandle dh;
717 SLPDatabaseEntry * entry;
718 dh = SLPDatabaseOpen(&G_SlpdKnownDAs);
719 if (dh)
720 {
721 /*------------------------------------*/
722 /* Unregister all local registrations */
723 /*------------------------------------*/
724 while (1)
725 {
726 entry = SLPDatabaseEnum(dh);
727 if (entry == NULL)
728 break;
729
730 SLPDKnownDADeregisterAll(entry->msg);
731 }
732 SLPDatabaseClose(dh);
733 }
734
735 SLPDatabaseDeinit(&G_SlpdKnownDAs);
736
737 if(G_ifaceurls)
738 xfree(G_ifaceurls);
739
740 return 0;
741 }
742
743
744 /*=========================================================================*/
SLPDKnownDAAdd(SLPMessage * msg,SLPBuffer buf)745 int SLPDKnownDAAdd(SLPMessage * msg, SLPBuffer buf)
746 /* Adds a DA to the known DA list if it is new, removes it if DA is going */
747 /* down or adjusts entry if DA changed. */
748 /* */
749 /* msg (IN) DAAdvert Message descriptor */
750 /* */
751 /* buf (IN) The DAAdvert message buffer */
752 /* */
753 /* returns Zero on success, Non-zero on error */
754 /*=========================================================================*/
755 {
756 SLPDatabaseEntry * entry;
757 SLPDAAdvert * entrydaadvert;
758 SLPDAAdvert * daadvert;
759 struct sockaddr_storage daaddr;
760 SLPParsedSrvUrl * parsedurl = NULL;
761 int result = 0;
762 SLPDatabaseHandle dh = NULL;
763 uint32_t saved_scope = 0;
764
765 dh = SLPDatabaseOpen(&G_SlpdKnownDAs);
766 if (dh == NULL)
767 {
768 result = SLP_ERROR_INTERNAL_ERROR;
769 goto CLEANUP;
770 }
771
772 /* daadvert is the DAAdvert message being added */
773 daadvert = &(msg->body.daadvert);
774
775
776 /* --------------------------------------------------------
777 * Make sure that the peer address in the DAAdvert matches
778 * the host in the DA service URL.
779 *---------------------------------------------------------
780 */
781
782 if(SLPNetIsIPV6())
783 {
784 /*We need to save the scope of the address, since a multi-nic machine
785 with multiple link-local addresses has no other way of differentiating route*/
786 saved_scope = ((struct sockaddr_in6*)&msg->peer)->sin6_scope_id;
787 }
788
789 if (SLPParseSrvUrl(daadvert->urllen, daadvert->url, &parsedurl))
790 {
791 /* could not parse the DA service url */
792 result = SLP_ERROR_PARSE_ERROR;
793 goto CLEANUP;
794 }
795 if (SLPNetResolveHostToAddr(parsedurl->host, &daaddr))
796 {
797 /* Unable to resolve the host in the DA advert to an address */
798 xfree(parsedurl);
799 result = SLP_ERROR_PARSE_ERROR;
800 goto CLEANUP;
801 }
802 /* free the parsed url created in call to SLPParseSrvUrl() */
803 xfree(parsedurl);
804 /* set the peer address in the DAAdvert message so that it matches
805 * the address the DA service URL resolves to
806 */
807 msg->peer = daaddr;
808
809 if(SLPNetIsIPV6())
810 {
811 /*reset the scope*/
812 ((struct sockaddr_in6*)&msg->peer)->sin6_scope_id = saved_scope;
813 }
814
815
816
817 /*-----------------------------------------------------*/
818 /* Check to see if there is already an identical entry */
819 /*-----------------------------------------------------*/
820 while (1)
821 {
822 entry = SLPDatabaseEnum(dh);
823 if (entry == NULL)
824 break;
825
826 /* entrydaadvert is the DAAdvert message from the database */
827 entrydaadvert = &(entry->msg->body.daadvert);
828
829 /* Assume DAs are identical if their URLs match */
830 if (SLPCompareString(entrydaadvert->urllen, entrydaadvert->url,
831 daadvert->urllen, daadvert->url) == 0)
832 {
833 #ifdef ENABLE_SLPv2_SECURITY
834 if (G_SlpdProperty.checkSourceAddr)
835 {
836 if ((entry->msg->peer.ss_family == AF_INET
837 && msg->peer.ss_family == AF_INET
838 && memcmp(&(((struct sockaddr_in *)&entry->msg->peer)->sin_addr),
839 &(((struct sockaddr_in *)&msg->peer)->sin_addr),
840 sizeof(struct in_addr)))
841 || (entry->msg->peer.ss_family == AF_INET6
842 && msg->peer.ss_family == AF_INET6
843 && memcmp(&(((struct sockaddr_in6 *)&entry->msg->peer)->sin6_addr),
844 &(((struct sockaddr_in6 *)&msg->peer)->sin6_addr),
845 sizeof(struct in6_addr))))
846 {
847 SLPDatabaseClose(dh);
848 result = SLP_ERROR_AUTHENTICATION_FAILED;
849 goto CLEANUP;
850 }
851 }
852
853 /* make sure an unauthenticated DAAdvert can't replace */
854 /* an authenticated one */
855 if (entrydaadvert->authcount
856 && entrydaadvert->authcount != daadvert->authcount)
857 {
858 SLPDatabaseClose(dh);
859 result = SLP_ERROR_AUTHENTICATION_FAILED;
860 goto CLEANUP;
861 }
862 #endif
863 if (daadvert->bootstamp != 0
864 && daadvert->bootstamp != entrydaadvert->bootstamp)
865 {
866 /* Advertising DA must have went down then came back up */
867 SLPDLogDAAdvertisement("Replacement", entry);
868 SLPDKnownDARegisterAll(msg, 0);
869 }
870
871 if ( daadvert->bootstamp == 0 )
872 {
873 /* Dying DA was found in our KnownDA database. Log that it
874 * was removed.
875 */
876 SLPDLogDAAdvertisement("Removal", entry);
877 }
878
879 /* Remove the entry that is the same as the advertised entry */
880 /* so that we can put the new advertised entry back in */
881 SLPDatabaseRemove(dh, entry);
882 break;
883 }
884 }
885
886 /* Make sure the DA is not dying */
887 if (daadvert->bootstamp != 0)
888 {
889 if (entry == 0)
890 {
891 /* create a new database entry using the DAAdvert message */
892 entry = SLPDatabaseEntryCreate(msg, buf);
893 if (entry)
894 {
895 /* reset the "time to stale" count to indicate the DA is active (not stale) */
896 entry->entryvalue = G_SlpdProperty.staleDACheckPeriod / SLPD_AGE_INTERVAL;
897
898 SLPDatabaseAdd(dh, entry);
899
900 /* register all the services we know about with this new DA */
901 SLPDKnownDARegisterAll(msg, 0);
902
903 /* log the addition of a new DA */
904 SLPDLogDAAdvertisement("Addition", entry);
905 }
906 else
907 {
908 /* Could not create a new entry */
909 result = SLP_ERROR_INTERNAL_ERROR;
910 goto CLEANUP;
911 }
912 }
913 else
914 {
915 /* The advertising DA is not new to us, but the old entry */
916 /* has been deleted from our database so that the new entry */
917 /* with its up to date time stamp can be put back in. */
918 /* create a new database entry using the DAAdvert message */
919 entry = SLPDatabaseEntryCreate(msg, buf);
920 if (entry)
921 {
922 /* reset the "time to stale" count to indicate the DA is active (not stale) */
923 entry->entryvalue = G_SlpdProperty.staleDACheckPeriod / SLPD_AGE_INTERVAL;
924
925 SLPDatabaseAdd(dh, entry);
926 }
927 else
928 {
929 /* Could not create a new entry */
930 result = SLP_ERROR_INTERNAL_ERROR;
931 goto CLEANUP;
932 }
933 }
934 } else {
935 /* If we are here, we need to cleanup the message descriptor and the */
936 /* message buffer because they were not added to the database and not */
937 /* cleaning them up would result in a memory leak. This is because we */
938 /* return zero, so the caller thinks it must not do the cleanup. */
939 SLPMessageFree(msg);
940 SLPBufferFree(buf);
941 }
942
943 CLEANUP:
944 if (dh)
945 SLPDatabaseClose(dh);
946
947 return result;
948 }
949
950 /*=========================================================================*/
SLPDKnownDARemove(struct sockaddr_storage * addr)951 void SLPDKnownDARemove(struct sockaddr_storage * addr)
952 /* Removes known DAs that sent DAAdverts from the specified in_addr */
953 /*=========================================================================*/
954 {
955 SLPDatabaseHandle dh;
956 SLPDatabaseEntry * entry;
957
958 dh = SLPDatabaseOpen(&G_SlpdKnownDAs);
959 if (dh)
960 {
961 /*-----------------------------------------------------*/
962 /* Check to see if there is already an identical entry */
963 /*-----------------------------------------------------*/
964 while (1)
965 {
966 entry = SLPDatabaseEnum(dh);
967 if (entry == NULL)
968 break;
969
970 /* Assume DAs are identical if their peer match */
971 if ((entry->msg->peer.ss_family == AF_INET
972 && addr->ss_family == AF_INET
973 && (0 == memcmp(&(((struct sockaddr_in *) &(entry->msg->peer))->sin_addr),
974 &(((struct sockaddr_in *) addr)->sin_addr),
975 sizeof(struct in_addr))))
976 || (entry->msg->peer.ss_family == AF_INET6
977 && addr->ss_family == AF_INET6
978 && (0 == memcmp(&(((struct sockaddr_in6 *) &(entry->msg->peer))->sin6_addr),
979 &(((struct sockaddr_in6 *) addr)->sin6_addr),
980 sizeof(struct in6_addr)))))
981 {
982 SLPDLogDAAdvertisement("Removal", entry);
983 SLPDatabaseRemove(dh, entry);
984 break;
985 }
986 }
987
988 SLPDatabaseClose(dh);
989 }
990 }
991
992
993 /*=========================================================================*/
SLPDKnownDAEnumStart()994 void * SLPDKnownDAEnumStart()
995 /* Start an enumeration of all Known DAs */
996 /* */
997 /* Returns: An enumeration handle that is passed to subsequent calls to */
998 /* SLPDKnownDAEnum(). Returns NULL on failure. Returned */
999 /* enumeration handle (if not NULL) must be passed to */
1000 /* SLPDKnownDAEnumEnd() when you are done with it. */
1001 /*=========================================================================*/
1002 {
1003 return SLPDatabaseOpen(&G_SlpdKnownDAs);
1004 }
1005
1006
1007 /*=========================================================================*/
SLPDKnownDAEnum(void * eh,SLPMessage ** msg,SLPBuffer * buf)1008 SLPMessage * SLPDKnownDAEnum(void * eh, SLPMessage ** msg, SLPBuffer * buf)
1009 /* Enumerate through all Known DAs */
1010 /* */
1011 /* eh (IN) pointer to opaque data that is used to maintain */
1012 /* enumerate entries. Pass in a pointer to NULL to start */
1013 /* enumeration. */
1014 /* */
1015 /* msg (OUT) pointer to the DAAdvert message descriptor */
1016 /* */
1017 /* buf (OUT) pointer to the DAAdvert message buffer */
1018 /* */
1019 /* returns: Pointer to enumerated entry or NULL if end of enumeration */
1020 /*=========================================================================*/
1021 {
1022 SLPDatabaseEntry * entry;
1023 entry = SLPDatabaseEnum((SLPDatabaseHandle) eh);
1024 if (entry)
1025 {
1026 *msg = entry->msg;
1027 *buf = entry->buf;
1028 }
1029 else
1030 {
1031 *msg = 0;
1032 *buf = 0;
1033 }
1034
1035 return *msg;
1036 }
1037
1038 /*=========================================================================*/
SLPDKnownDAEnumEnd(void * eh)1039 void SLPDKnownDAEnumEnd(void * eh)
1040 /* End an enumeration started by SLPDKnownDAEnumStart() */
1041 /* */
1042 /* Parameters: eh (IN) The enumeration handle returned by */
1043 /* SLPDKnownDAEnumStart() */
1044 /*=========================================================================*/
1045 {
1046 if (eh)
1047 SLPDatabaseClose((SLPDatabaseHandle) eh);
1048 }
1049
1050 /*=========================================================================*/
SLPDKnownDAGenerateMyDAAdvert(struct sockaddr_storage * localaddr,int errorcode,int deadda,int ismcast,int xid,SLPBuffer * sendbuf)1051 int SLPDKnownDAGenerateMyDAAdvert(struct sockaddr_storage * localaddr,
1052 int errorcode, int deadda, int ismcast, int xid, SLPBuffer * sendbuf)
1053 /* Pack a buffer with a DAAdvert using information from a SLPDAentry */
1054 /* */
1055 /* localaddr (IN) the address of the DA to advertise */
1056 /* */
1057 /* errorcode (IN) the errorcode for the DAAdvert */
1058 /* */
1059 /* deadda (IN) whether the DAAdvert should indicate the DA is shut down */
1060 /* */
1061 /* ismcast (IN) whether the mcast flag should be set for the DAAdvert */
1062 /* */
1063 /* xid (IN) the xid to for the DAAdvert */
1064 /* */
1065 /* daentry (IN) pointer to the daentry that contains the rest of the info */
1066 /* to make the DAAdvert */
1067 /* */
1068 /* sendbuf (OUT) pointer to the SLPBuffer that will be packed with a */
1069 /* DAAdvert */
1070 /* */
1071 /* returns: zero on success, non-zero on error */
1072 /*=========================================================================*/
1073 {
1074 char localaddr_str[INET6_ADDRSTRLEN + 2];
1075 size_t size;
1076 SLPBuffer result = *sendbuf;
1077
1078 #ifdef ENABLE_SLPv2_SECURITY
1079 int daadvertauthlen = 0;
1080 unsigned char * daadvertauth = 0;
1081 size_t spistrlen = 0;
1082 char * spistr = 0;
1083
1084 /** @todo Use correct delay value - 1000 is just an arbitrary choice. */
1085 uint32_t expires = (uint32_t)time(0) + 1000;
1086
1087 if (G_SlpdProperty.securityEnabled)
1088 {
1089 SLPSpiGetDefaultSPI(G_SlpdSpiHandle, SLPSPI_KEY_TYPE_PRIVATE,
1090 &spistrlen, &spistr);
1091
1092 SLPAuthSignDAAdvert(G_SlpdSpiHandle, spistrlen, spistr,
1093 expires, G_SlpdProperty.urlPrefixLen,
1094 G_SlpdProperty.urlPrefix, 0, 0, G_SlpdProperty.useScopesLen,
1095 G_SlpdProperty.useScopes, spistrlen, spistr, &daadvertauthlen,
1096 &daadvertauth);
1097 }
1098 #endif
1099
1100 /*-------------------------------------------------------------*/
1101 /* ensure the buffer is big enough to handle the whole srvrply */
1102 /*-------------------------------------------------------------*/
1103 size = G_SlpdProperty.localeLen + 29; /* 14 bytes for header */
1104 /* 2 errorcode */
1105 /* 4 bytes for timestamp */
1106 /* 2 bytes for url len */
1107 /* 2 bytes for scope list len */
1108 /* 2 bytes for attr list len */
1109 /* 2 bytes for spi str len */
1110 /* 1 byte for authblock count */
1111 size += G_SlpdProperty.urlPrefixLen;
1112 localaddr_str[0] = '\0';
1113 if (localaddr->ss_family == AF_INET)
1114 inet_ntop(localaddr->ss_family,
1115 &((struct sockaddr_in *) localaddr)->sin_addr, localaddr_str,
1116 sizeof(localaddr_str));
1117 else if (localaddr->ss_family == AF_INET6)
1118 {
1119 strcpy(localaddr_str, "[");
1120 inet_ntop(localaddr->ss_family,
1121 &((struct sockaddr_in6 *) localaddr)->sin6_addr,
1122 &localaddr_str[1], sizeof(localaddr_str) - 1);
1123 strcat(localaddr_str, "]");
1124 }
1125 size += strlen(localaddr_str);
1126 size += G_SlpdProperty.useScopesLen;
1127 #ifdef ENABLE_SLPv2_SECURITY
1128 size += spistrlen;
1129 size += daadvertauthlen;
1130 #endif
1131
1132 result = SLPBufferRealloc(result, size);
1133 if (result == 0)
1134 {
1135 /* Out of memory, what should we do here! */
1136 errorcode = SLP_ERROR_INTERNAL_ERROR;
1137 goto FINISHED;
1138 }
1139
1140 /*----------------*/
1141 /* Add the header */
1142 /*----------------*/
1143
1144 /* version */
1145 *result->curpos++ = 2;
1146
1147 /* function id */
1148 *result->curpos++ = SLP_FUNCT_DAADVERT;
1149
1150 /* length */
1151 PutUINT24(&result->curpos, size);
1152
1153 /* flags */
1154 PutUINT16(&result->curpos,
1155 (size > (size_t)G_SlpdProperty.MTU ? SLP_FLAG_OVERFLOW : 0) |
1156 (ismcast ? SLP_FLAG_MCAST : 0));
1157
1158 /* ext offset */
1159 PutUINT24(&result->curpos, 0);
1160
1161 /* xid */
1162 PutUINT16(&result->curpos, xid);
1163
1164 /* lang tag len */
1165 PutUINT16(&result->curpos, G_SlpdProperty.localeLen);
1166
1167 /* lang tag */
1168 memcpy(result->curpos, G_SlpdProperty.locale, G_SlpdProperty.localeLen);
1169 result->curpos += G_SlpdProperty.localeLen;
1170
1171 /*--------------------------*/
1172 /* Add rest of the DAAdvert */
1173 /*--------------------------*/
1174
1175 /* error code */
1176 PutUINT16(&result->curpos, errorcode);
1177 if (errorcode == 0)
1178 {
1179 /* timestamp */
1180 if (deadda)
1181 PutUINT32(&result->curpos, 0);
1182 else
1183 PutUINT32(&result->curpos, G_SlpdProperty.DATimestamp);
1184
1185 /* url len */
1186 PutUINT16(&result->curpos, G_SlpdProperty.urlPrefixLen
1187 + strlen(localaddr_str));
1188
1189 /* url */
1190 memcpy(result->curpos, G_SlpdProperty.urlPrefix,
1191 G_SlpdProperty.urlPrefixLen);
1192 result->curpos += G_SlpdProperty.urlPrefixLen;
1193 memcpy(result->curpos, localaddr_str, strlen(localaddr_str));
1194 result->curpos += strlen(localaddr_str);
1195
1196 /* scope list len */
1197 PutUINT16(&result->curpos, G_SlpdProperty.useScopesLen);
1198
1199 /* scope list */
1200 memcpy(result->curpos, G_SlpdProperty.useScopes,
1201 G_SlpdProperty.useScopesLen);
1202 result->curpos += G_SlpdProperty.useScopesLen;
1203
1204 /* attr list len */
1205 PutUINT16(&result->curpos, 0);
1206
1207 /* attr list */
1208 /* memcpy(result->start, ???, 0); */
1209 /* result->curpos = result->curpos + daentry->attrlistlen; */
1210 /* SPI List */
1211 #ifdef ENABLE_SLPv2_SECURITY
1212 PutUINT16(&result->curpos, spistrlen);
1213 memcpy(result->curpos, spistr, spistrlen);
1214 result->curpos += spistrlen;
1215 #else
1216 PutUINT16(&result->curpos, 0);
1217 #endif
1218
1219 /* authblock count */
1220 #ifdef ENABLE_SLPv2_SECURITY
1221 if (daadvertauth)
1222 {
1223 /* authcount */
1224 *result->curpos++ = 1;
1225
1226 /* authblock */
1227 memcpy(result->curpos, daadvertauth, daadvertauthlen);
1228 result->curpos += daadvertauthlen;
1229 }
1230 else
1231 #endif
1232 *result->curpos++ = 0;
1233 }
1234
1235 FINISHED:
1236
1237 #ifdef ENABLE_SLPv2_SECURITY
1238 if (daadvertauth)
1239 xfree(daadvertauth);
1240 if (spistr)
1241 xfree(spistr);
1242 #endif
1243 *sendbuf = result;
1244
1245 return errorcode;
1246 }
1247
1248 #if defined(ENABLE_SLPv1)
1249 /*=========================================================================*/
SLPDKnownDAGenerateMyV1DAAdvert(struct sockaddr_storage * localaddr,int errorcode,int encoding,unsigned int xid,SLPBuffer * sendbuf)1250 int SLPDKnownDAGenerateMyV1DAAdvert(struct sockaddr_storage * localaddr,
1251 int errorcode, int encoding, unsigned int xid, SLPBuffer * sendbuf)
1252 /* Pack a buffer with a v1 DAAdvert using information from a SLPDAentry */
1253 /* */
1254 /* localaddr (IN) the address of the DA to advertise */
1255 /* */
1256 /* errorcode (IN) the errorcode for the DAAdvert */
1257 /* */
1258 /* encoding (IN) the SLPv1 language encoding for the DAAdvert */
1259 /* */
1260 /* xid (IN) the xid to for the DAAdvert */
1261 /* */
1262 /* sendbuf (OUT) pointer to the SLPBuffer that will be packed with a */
1263 /* DAAdvert */
1264 /* */
1265 /* returns: zero on success, non-zero on error */
1266 /*=========================================================================*/
1267 {
1268 size_t size = 0;
1269 size_t urllen = INT_MAX;
1270 size_t scopelistlen = INT_MAX;
1271 SLPBuffer result = *sendbuf;
1272 char localaddr_str[INET6_ADDRSTRLEN + 2];
1273 char da_url[INET6_ADDRSTRLEN + 29];
1274
1275 /*-------------------------------------------------------------*/
1276 /* ensure the buffer is big enough to handle the whole srvrply */
1277 /*-------------------------------------------------------------*/
1278 size = 18; /* 12 bytes for header */
1279 /* 2 errorcode */
1280 /* 2 bytes for url len */
1281 /* 2 bytes for scope list len */
1282
1283 /* Create the local address in string form */
1284 localaddr_str[0] = '\0';
1285 if (localaddr->ss_family == AF_INET)
1286 inet_ntop(localaddr->ss_family,
1287 &((struct sockaddr_in *) localaddr)->sin_addr, localaddr_str,
1288 sizeof(localaddr_str));
1289 else if (localaddr->ss_family == AF_INET6)
1290 {
1291 strcpy(localaddr_str, "[");
1292 inet_ntop(localaddr->ss_family,
1293 &((struct sockaddr_in6 *) localaddr)->sin6_addr,
1294 &localaddr_str[1], sizeof(localaddr_str) - 1);
1295 strcat(localaddr_str, "]");
1296 }
1297
1298 /* Create the DA URL */
1299 da_url[0] = '\0';
1300 strcpy(da_url, G_SlpdProperty.urlPrefix);
1301 strcat(da_url, localaddr_str);
1302
1303 if (!errorcode)
1304 {
1305 errorcode = SLPv1ToEncoding(0, &urllen, encoding, da_url, strlen(da_url));
1306 if (!errorcode)
1307 {
1308 size += urllen;
1309 #ifndef FAKE_UNSCOPED_DA
1310 errorcode = SLPv1ToEncoding(0, &scopelistlen, encoding,
1311 G_SlpdProperty.useScopes,
1312 G_SlpdProperty.useScopesLen);
1313 #else
1314 scopelistlen = 0; /* pretend that we're unscoped */
1315 #endif
1316 if (!errorcode)
1317 size += scopelistlen;
1318 }
1319 }
1320 else
1321 {
1322 /* don't add these */
1323 urllen = scopelistlen = 0;
1324 }
1325
1326 result = SLPBufferRealloc(result, size);
1327 if (result == 0)
1328 {
1329 /* TODO: out of memory, what should we do here! */
1330 errorcode = SLP_ERROR_INTERNAL_ERROR;
1331 goto FINISHED;
1332 }
1333
1334 /*----------------*/
1335 /* Add the header */
1336 /*----------------*/
1337
1338 /* version */
1339 *result->curpos++ = 1;
1340
1341 /* function id */
1342 *result->curpos++ = SLP_FUNCT_DAADVERT;
1343
1344 /* length */
1345 PutUINT16(&result->curpos, size);
1346
1347 /* flags */
1348 /** @todo We have to handle monoling and all that stuff. */
1349 *result->curpos++ = (size > (size_t)G_SlpdProperty.MTU?
1350 SLPv1_FLAG_OVERFLOW: 0);
1351
1352 /* dialect */
1353 *result->curpos++ = 0;
1354
1355 /* language code */
1356 if (G_SlpdProperty.locale)
1357 {
1358 memcpy(result->curpos, G_SlpdProperty.locale, 2);
1359 result->curpos += 2;
1360 }
1361 PutUINT16(&result->curpos, encoding);
1362
1363 /* xid */
1364 PutUINT16(&result->curpos, xid);
1365
1366 /*--------------------------*/
1367 /* Add rest of the DAAdvert */
1368 /*--------------------------*/
1369
1370 /* error code */
1371 PutUINT16(&result->curpos, errorcode);
1372
1373 /* url len */
1374 PutUINT16(&result->curpos, urllen);
1375
1376 /* url */
1377 SLPv1ToEncoding((char *)result->curpos, &urllen, encoding, da_url, strlen(da_url));
1378 result->curpos += urllen;
1379
1380 /* scope list len */
1381 PutUINT16(&result->curpos, scopelistlen);
1382
1383 /* scope list */
1384 #ifndef FAKE_UNSCOPED_DA
1385 SLPv1ToEncoding((char *)result->curpos, &scopelistlen, encoding,
1386 G_SlpdProperty.useScopes, G_SlpdProperty.useScopesLen);
1387 #endif
1388
1389 result->curpos += scopelistlen;
1390
1391 FINISHED:
1392
1393 *sendbuf = result;
1394
1395 return errorcode;
1396 }
1397 #endif
1398
1399 /*=========================================================================*/
SLPDKnownDAEcho(SLPMessage * msg,SLPBuffer buf)1400 void SLPDKnownDAEcho(SLPMessage * msg, SLPBuffer buf)
1401 /* Echo a srvreg message to a known DA */
1402 /* */
1403 /* msg (IN) the SrvReg message descriptor */
1404 /* */
1405 /* buf (IN) the SrvReg message buffer to echo */
1406 /* */
1407 /* Returns: none */
1408 /*=========================================================================*/
1409 {
1410 SLPBuffer dup;
1411 SLPDatabaseHandle dh;
1412 SLPDatabaseEntry * entry;
1413 SLPDAAdvert * entrydaadvert;
1414 SLPDSocket * sock;
1415 const char * msgscope;
1416 size_t msgscopelen;
1417
1418 /* Do not echo registrations if we are a DA unless they were made */
1419 /* local through the API! */
1420 if (G_SlpdProperty.isDA && !SLPNetIsLocal(&(msg->peer)))
1421 return;
1422
1423 if (msg->header.functionid == SLP_FUNCT_SRVREG)
1424 {
1425 msgscope = msg->body.srvreg.scopelist;
1426 msgscopelen = msg->body.srvreg.scopelistlen;
1427 }
1428 else if (msg->header.functionid == SLP_FUNCT_SRVDEREG)
1429 {
1430 msgscope = msg->body.srvdereg.scopelist;
1431 msgscopelen = msg->body.srvdereg.scopelistlen;
1432 }
1433 else
1434 {
1435 /* We only echo SRVREG and SRVDEREG */
1436 return;
1437 }
1438
1439 dh = SLPDatabaseOpen(&G_SlpdKnownDAs);
1440 if (dh)
1441 {
1442 /*-----------------------------------------------------*/
1443 /* Check to see if there is already an identical entry */
1444 /*-----------------------------------------------------*/
1445 while (1)
1446 {
1447 entry = SLPDatabaseEnum(dh);
1448 if (entry == NULL)
1449 break;
1450
1451 /* entrydaadvert is the DAAdvert message from the database */
1452 entrydaadvert = &(entry->msg->body.daadvert);
1453
1454 /* Send to all DAs that have matching scope */
1455 if (SLPIntersectStringList(msgscopelen, msgscope,
1456 entrydaadvert->scopelistlen, entrydaadvert->scopelist))
1457 {
1458 /* Do not echo to ourselves if we are a DA*/
1459 if (G_SlpdProperty.isDA
1460 && (SLPIntersectStringList(G_ifaceurlsLen,
1461 G_ifaceurls,
1462 entrydaadvert->urllen,
1463 entrydaadvert->url) > 0))
1464 {
1465 /* don't do anything because it makes no sense to echo */
1466 /* to myself */
1467 }
1468 else
1469 {
1470 /*------------------------------------------*/
1471 /* Load the socket with the message to send */
1472 /*------------------------------------------*/
1473 sock = SLPDOutgoingConnect(0, &(entry->msg->peer));
1474 if (sock)
1475 {
1476 dup = SLPBufferDup(buf);
1477 if (dup)
1478 {
1479 SLPListLinkTail(&(sock->sendlist), (SLPListItem *) dup);
1480 SLPDOutgoingDatagramWrite(sock, buf);
1481 }
1482 else
1483 sock->state = SOCKET_CLOSE;
1484 }
1485 }
1486 }
1487 }
1488 SLPDatabaseClose(dh);
1489 }
1490 }
1491
1492 /*=========================================================================*/
SLPDKnownDAActiveDiscovery(int seconds)1493 void SLPDKnownDAActiveDiscovery(int seconds)
1494 /* Add a socket to the outgoing list to do active DA discovery SrvRqst */
1495 /* */
1496 /* seconds (IN) number of seconds that expired since last call */
1497 /* */
1498 /* Returns: none */
1499 /*=========================================================================*/
1500 {
1501 SLPDSocket * sock;
1502
1503 /* Check to see if we should perform active DA detection */
1504 if (G_SlpdProperty.DAActiveDiscoveryInterval == 0)
1505 return;
1506 /* When activeDiscoveryXmits is < 0 then we should not xmit any more */
1507 if (G_SlpdProperty.activeDiscoveryXmits < 0)
1508 return ;
1509
1510 if (G_SlpdProperty.nextActiveDiscovery <= 0)
1511 {
1512 if (G_SlpdProperty.activeDiscoveryXmits == 0)
1513 {
1514 if (G_SlpdProperty.DAActiveDiscoveryInterval == 1)
1515 {
1516 /* ensures xmit on first call */
1517 /* don't xmit any more */
1518 G_SlpdProperty.activeDiscoveryXmits = -1;
1519 }
1520 else
1521 {
1522 G_SlpdProperty.nextActiveDiscovery = G_SlpdProperty.DAActiveDiscoveryInterval;
1523 G_SlpdProperty.activeDiscoveryXmits = 3;
1524 }
1525 }
1526
1527 G_SlpdProperty.activeDiscoveryXmits --;
1528
1529 /*Send the datagram, either broadcast or multicast*/
1530 if((G_SlpdProperty.isBroadcastOnly == 1) && SLPNetIsIPV4())
1531 {
1532 /* Use sockaddr_storage consistently for SLPDSocketCreateDatagram */
1533 struct sockaddr_storage peeraddr;
1534 struct sockaddr_in * p_peeraddr = (struct sockaddr_in *)&peeraddr;
1535 /* Use sockaddr_in cast for ipv4 only */
1536 memset(&peeraddr, 0, sizeof(struct sockaddr_storage)); /*Some platforms require sin_zero be 0*/
1537 p_peeraddr->sin_family = AF_INET;
1538 p_peeraddr->sin_addr.s_addr = htonl(SLP_BCAST_ADDRESS);
1539 sock = SLPDSocketCreateDatagram(&peeraddr, DATAGRAM_BROADCAST);
1540 if (sock)
1541 {
1542 MakeActiveDiscoveryRqst(1, &(sock->sendbuf));
1543 SLPDOutgoingDatagramWrite(sock, sock->sendbuf);
1544 SLPDSocketFree(sock);
1545 }
1546 }
1547 else
1548 {
1549 /* For each incoming socket, find the sockets that can send multicast
1550 and send the appropriate datagram. The incoming list is used because
1551 it already has ready-to-use multicast sending sockets allocated for every interface.*/
1552 sock = (SLPDSocket *)G_IncomingSocketList.head;
1553 while (sock)
1554 {
1555 if(sock->can_send_mcast)
1556 {
1557 struct sockaddr_storage mcastaddr;
1558
1559 if(SLPNetIsIPV6() && (sock->localaddr.ss_family == AF_INET6))
1560 {
1561 MakeActiveDiscoveryRqst(1, &(sock->sendbuf));
1562
1563 SLPNetSetAddr(&mcastaddr, AF_INET6, G_SlpdProperty.port, &in6addr_srvlocda_node);
1564 SLPDOutgoingDatagramMcastWrite(sock, &mcastaddr, sock->sendbuf);
1565 SLPNetSetAddr(&mcastaddr, AF_INET6, G_SlpdProperty.port, &in6addr_srvlocda_link);
1566 SLPDOutgoingDatagramMcastWrite(sock, &mcastaddr, sock->sendbuf);
1567 if (!IN6_IS_ADDR_LINKLOCAL(&(((struct sockaddr_in6 *) &sock->localaddr)->sin6_addr)))
1568 {
1569 SLPNetSetAddr(&mcastaddr, AF_INET6, G_SlpdProperty.port, &in6addr_srvlocda_site);
1570 SLPDOutgoingDatagramMcastWrite(sock, &mcastaddr, sock->sendbuf);
1571 }
1572 }
1573 else if((sock->localaddr.ss_family == AF_INET) && SLPNetIsIPV4())
1574 {
1575 int tmpaddr = SLP_MCAST_ADDRESS;
1576 MakeActiveDiscoveryRqst(1, &(sock->sendbuf));
1577
1578 SLPNetSetAddr(&mcastaddr, AF_INET, G_SlpdProperty.port, &tmpaddr);
1579 SLPDOutgoingDatagramMcastWrite(sock, &mcastaddr, sock->sendbuf);
1580 }
1581 }
1582
1583 sock = (SLPDSocket *) sock->listitem.next;
1584 }
1585 }
1586 }
1587 else
1588 G_SlpdProperty.nextActiveDiscovery =
1589 G_SlpdProperty.nextActiveDiscovery - seconds;
1590 }
1591
1592 /*=========================================================================*/
SLPDKnownDAStaleDACheck(int seconds)1593 void SLPDKnownDAStaleDACheck(int seconds)
1594 /* Check for stale DAs if properly configured */
1595 /* */
1596 /* seconds (IN) number seconds that elapsed since the last call to this */
1597 /* function */
1598 /* */
1599 /* Returns: none */
1600 /*=========================================================================*/
1601 {
1602 /* Check to see if we should perform stale DA detection */
1603 if (G_SlpdProperty.staleDACheckPeriod == 0)
1604 return;
1605
1606 {
1607 SLPDatabaseHandle dh;
1608 SLPDatabaseEntry * entry;
1609 SLPDatabaseEntry * nextEntry;
1610
1611 (void) seconds; /*unused parameter warning*/
1612
1613 dh = SLPDatabaseOpen(&G_SlpdKnownDAs);
1614 if (dh)
1615 {
1616 nextEntry = SLPDatabaseEnum(dh);
1617 while (1)
1618 {
1619 entry = nextEntry;
1620 if (entry == NULL)
1621 break;
1622 nextEntry = SLPDatabaseEnum(dh);
1623 if (!entry->entryvalue)
1624 {
1625 /* No DAAdvert received for this DA within the check period */
1626 SLPDLogDAAdvertisement("Removed - stale", entry);
1627 SLPDatabaseRemove(dh, entry);
1628 }
1629 else
1630 entry->entryvalue--; /* Decrement the "time to stale" count */
1631 }
1632 }
1633 SLPDatabaseClose(dh);
1634 }
1635 }
1636
1637 /*=========================================================================*/
SLPDKnownDAPassiveDAAdvert(int seconds,int dadead)1638 void SLPDKnownDAPassiveDAAdvert(int seconds, int dadead)
1639 /* Send passive daadvert messages if properly configured and running as */
1640 /* a DA */
1641 /* */
1642 /* seconds (IN) number seconds that elapsed since the last call to this */
1643 /* function */
1644 /* */
1645 /* dadead (IN) nonzero if the DA is dead and a bootstamp of 0 should be */
1646 /* sent */
1647 /* */
1648 /* Returns: none */
1649 /*=========================================================================*/
1650 {
1651 SLPDSocket * sock;
1652
1653 /* SAs don't send passive DAAdverts */
1654 if (G_SlpdProperty.isDA == 0)
1655 return;
1656
1657 /* Check to see if we should perform passive DA detection */
1658 if ((G_SlpdProperty.passiveDADetection == 0) &&
1659 (G_SlpdProperty.staleDACheckPeriod == 0))
1660 return;
1661
1662 G_SlpdProperty.nextPassiveDAAdvert = G_SlpdProperty.nextPassiveDAAdvert - seconds;
1663 if (G_SlpdProperty.nextPassiveDAAdvert <= 0 || dadead)
1664 {
1665 G_SlpdProperty.nextPassiveDAAdvert += G_SlpdProperty.DAHeartBeat;
1666
1667 /*Send the datagram, either broadcast or multicast*/
1668 if ((G_SlpdProperty.isBroadcastOnly == 1) && SLPNetIsIPV4())
1669 {
1670 /* Use sockaddr_storage consistently for SLPDSocketCreateDatagram */
1671 struct sockaddr_storage peeraddr;
1672 struct sockaddr_in *p_peeraddr = (struct sockaddr_in *)&peeraddr;
1673 /* Use sockaddr_in cast for ipv4 only */
1674 memset(&peeraddr, 0, sizeof(struct sockaddr_storage)); /*Some platforms require sin_zero be 0*/
1675 p_peeraddr->sin_family = AF_INET;
1676 p_peeraddr->sin_addr.s_addr = htonl(SLP_BCAST_ADDRESS);
1677 sock = SLPDSocketCreateDatagram(&peeraddr, DATAGRAM_BROADCAST);
1678 if(sock)
1679 {
1680 /* @todo sock doesn't have a localaddr, and some platforms send broadcasts on all
1681 network interfaces, so I'm not sure what to send -- I'll just pick a non-loopback
1682 interface for now, and perhaps later cycle through the list and send as all local
1683 addrs. Note that the original broadcasting code had the same problem, so this
1684 probably wasn't used much.*/
1685 if(G_IncomingSocketList.tail)
1686 {
1687 struct sockaddr_storage* myaddr = &((SLPDSocket *)G_IncomingSocketList.tail)->localaddr;
1688 if (SLPDKnownDAGenerateMyDAAdvert(myaddr, 0, dadead, 1, 0, &(sock->sendbuf)) == 0)
1689 SLPDOutgoingDatagramWrite(sock, sock->sendbuf);
1690 #ifdef ENABLE_SLPv1
1691 if (SLPDKnownDAGenerateMyV1DAAdvert(myaddr, 0, SLP_CHAR_UTF8, 0, &(sock->sendbuf)) == 0)
1692 SLPDOutgoingDatagramWrite(sock, sock->sendbuf);
1693 #endif
1694 }
1695 SLPDSocketFree(sock);
1696 }
1697 }
1698 else
1699 {
1700 /* For each incoming socket, find the sockets that can send multicast
1701 and send the appropriate datagram. */
1702 sock = (SLPDSocket *)G_IncomingSocketList.head;
1703 while (sock)
1704 {
1705 if(sock->can_send_mcast)
1706 {
1707 struct sockaddr_storage mcastaddr;
1708
1709 if(SLPNetIsIPV6() && (sock->localaddr.ss_family == AF_INET6))
1710 {
1711 if (SLPDKnownDAGenerateMyDAAdvert(&sock->localaddr, 0, dadead, 1, 0, &(sock->sendbuf)) == 0)
1712 {
1713 SLPNetSetAddr(&mcastaddr, AF_INET6, G_SlpdProperty.port, &in6addr_srvlocda_node);
1714 SLPDOutgoingDatagramMcastWrite(sock, &mcastaddr, sock->sendbuf);
1715 SLPNetSetAddr(&mcastaddr, AF_INET6, G_SlpdProperty.port, &in6addr_srvlocda_link);
1716 SLPDOutgoingDatagramMcastWrite(sock, &mcastaddr, sock->sendbuf);
1717 if (!IN6_IS_ADDR_LINKLOCAL(&(((struct sockaddr_in6 *) &sock->localaddr)->sin6_addr)))
1718 {
1719 SLPNetSetAddr(&mcastaddr, AF_INET6, G_SlpdProperty.port, &in6addr_srvlocda_site);
1720 SLPDOutgoingDatagramMcastWrite(sock, &mcastaddr, sock->sendbuf);
1721 }
1722 }
1723 }
1724 else if((sock->localaddr.ss_family == AF_INET) && SLPNetIsIPV4())
1725 {
1726 int tmpaddr = SLP_MCAST_ADDRESS;
1727
1728 if (SLPDKnownDAGenerateMyDAAdvert(&sock->localaddr, 0, dadead, 1, 0, &(sock->sendbuf)) == 0)
1729 {
1730 SLPNetSetAddr(&mcastaddr, AF_INET, G_SlpdProperty.port, &tmpaddr);
1731 SLPDOutgoingDatagramMcastWrite(sock, &mcastaddr, sock->sendbuf);
1732 }
1733 #ifdef ENABLE_SLPv1
1734 if (SLPDKnownDAGenerateMyV1DAAdvert(&sock->localaddr, 0,
1735 SLP_CHAR_UTF8, 0, &(sock->sendbuf)) == 0)
1736 {
1737 tmpaddr = SLPv1_DA_MCAST_ADDRESS;
1738 SLPNetSetAddr(&mcastaddr, AF_INET, G_SlpdProperty.port, &tmpaddr);
1739 SLPDOutgoingDatagramMcastWrite(sock, &mcastaddr, sock->sendbuf);
1740 }
1741 #endif
1742 }
1743 }
1744
1745 sock = (SLPDSocket *) sock->listitem.next;
1746 }
1747 }
1748 }
1749 }
1750
1751
1752 /*=========================================================================*/
SLPDKnownDAImmortalRefresh(int seconds)1753 void SLPDKnownDAImmortalRefresh(int seconds)
1754 /* Refresh all SLP_LIFETIME_MAXIMUM services */
1755 /* */
1756 /* seconds (IN) time in seconds since last call */
1757 /*=========================================================================*/
1758 {
1759 SLPDatabaseHandle dh;
1760 SLPDatabaseEntry * entry;
1761 SLPDAAdvert * entrydaadvert;
1762
1763 G_KnownDATimeSinceLastRefresh += seconds;
1764
1765 if (G_KnownDATimeSinceLastRefresh >= SLP_LIFETIME_MAXIMUM - seconds)
1766 {
1767 /* Refresh all SLP_LIFETIME_MAXIMUM registrations */
1768 dh = SLPDatabaseOpen(&G_SlpdKnownDAs);
1769 if (dh)
1770 {
1771 /*-----------------------------------------------------*/
1772 /* Check to see if there is already an identical entry */
1773 /*-----------------------------------------------------*/
1774 while (1)
1775 {
1776 entry = SLPDatabaseEnum(dh);
1777 if (entry == NULL)
1778 break;
1779
1780 /* entrydaadvert is the DAAdvert message from the database */
1781 entrydaadvert = &(entry->msg->body.daadvert);
1782
1783 /* Skip ourself, which we detect by matching the entry's url */
1784 /* (ip address) against the list of our own interface addresses. */
1785 /* If there's no match, then we can go ahead */
1786 if(SLPIntersectStringList(G_ifaceurlsLen, G_ifaceurls, entrydaadvert->urllen, entrydaadvert->url) == 0)
1787 SLPDKnownDARegisterAll(entry->msg, 1);
1788 }
1789
1790 SLPDatabaseClose(dh);
1791 }
1792
1793 G_KnownDATimeSinceLastRefresh = 0;
1794 }
1795 }
1796
1797 /*=========================================================================*/
SLPDKnownDADeRegisterWithAllDas(SLPMessage * msg,SLPBuffer buf)1798 void SLPDKnownDADeRegisterWithAllDas(SLPMessage * msg, SLPBuffer buf)
1799 /* Deregister the registration described by the specified message */
1800 /* */
1801 /* msg (IN) A message descriptor for a SrvReg or SrvDereg message to */
1802 /* deregister */
1803 /* */
1804 /* buf (IN) Message buffer associated with msg */
1805 /* */
1806 /* Returns: None */
1807 /*=========================================================================*/
1808 {
1809 SLPBuffer sendbuf;
1810
1811 if (msg->header.functionid == SLP_FUNCT_SRVREG)
1812 {
1813 if (MakeSrvderegFromSrvReg(msg, buf, &sendbuf) == 0)
1814 {
1815 SLPDKnownDAEcho(msg, sendbuf);
1816 SLPBufferFree(sendbuf);
1817 }
1818 }
1819 else if (msg->header.functionid == SLP_FUNCT_SRVDEREG)
1820 {
1821 /* Simply echo the message through as is */
1822 SLPDKnownDAEcho(msg, buf);
1823 }
1824 }
1825
1826 /*=========================================================================*/
SLPDKnownDARegisterWithAllDas(SLPMessage * msg,SLPBuffer buf)1827 void SLPDKnownDARegisterWithAllDas(SLPMessage * msg, SLPBuffer buf)
1828 /* Register the registration described by the specified message with all */
1829 /* known DAs */
1830 /* */
1831 /* msg (IN) A message descriptor for a SrvReg or SrvDereg message to */
1832 /* deregister */
1833 /* */
1834 /* buf (IN) Message buffer associated with msg */
1835 /* */
1836 /* Returns: None */
1837 /*=========================================================================*/
1838 {
1839 if (msg->header.functionid == SLP_FUNCT_SRVDEREG)
1840 {
1841 /* Simply echo the message through as is */
1842 SLPDKnownDAEcho(msg, buf);
1843 }
1844 }
1845
1846 #ifdef DEBUG
1847 /*=========================================================================*/
SLPDKnownDADump(void)1848 void SLPDKnownDADump(void)
1849 /*=========================================================================*/
1850 {
1851 SLPMessage * msg;
1852 SLPBuffer buf;
1853 void * eh;
1854
1855 eh = SLPDKnownDAEnumStart();
1856 if (eh)
1857 {
1858 SLPDLog("========================================================================\n");
1859 SLPDLog("Dumping KnownDAs \n");
1860 SLPDLog("========================================================================\n");
1861 while (SLPDKnownDAEnum(eh, &msg, &buf))
1862 {
1863 SLPDLogMessageInternals(msg);
1864 SLPDLog("\n");
1865 }
1866
1867 SLPDKnownDAEnumEnd(eh);
1868 }
1869 }
1870 #endif
1871
1872 /*=========================================================================*/
1873