1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 /*
  27  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  28  * Copyright (c) 2012 by Delphix. All rights reserved.
  29  */
  30 
  31 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  32 /*        All Rights Reserved   */
  33 
  34 /*
  35  * University Copyright- Copyright (c) 1982, 1986, 1988
  36  * The Regents of the University of California
  37  * All Rights Reserved
  38  *
  39  * University Acknowledgment- Portions of this document are derived from
  40  * software developed by the University of California, Berkeley, and its
  41  * contributors.
  42  */
  43 
  44 #include <stdio.h>
  45 #include <sys/types.h>
  46 #include <stdlib.h>
  47 #include <unistd.h>
  48 #include <string.h>
  49 #include <syslog.h>
  50 #include <rpc/rpc.h>
  51 #include <rpcsvc/sm_inter.h>
  52 #include <rpcsvc/nsm_addr.h>
  53 #include <memory.h>
  54 #include <net/if.h>
  55 #include <sys/sockio.h>
  56 #include <sys/socket.h>
  57 #include <netinet/in.h>
  58 #include <arpa/inet.h>
  59 #include <netdb.h>
  60 #include <netdir.h>
  61 #include <synch.h>
  62 #include <thread.h>
  63 #include <ifaddrs.h>
  64 #include <errno.h>
  65 #include <assert.h>
  66 #include "sm_statd.h"
  67 
  68 static int local_state;         /* fake local sm state */
  69                                 /* client name-to-address translation table */
  70 static name_addr_entry_t *name_addr = NULL;
  71 
  72 
  73 #define LOGHOST "loghost"
  74 
  75 static void delete_mon(char *mon_name, my_id *my_idp);
  76 static void insert_mon(mon *monp);
  77 static void pr_mon(char *);
  78 static int statd_call_lockd(mon *monp, int state);
  79 static int hostname_eq(char *host1, char *host2);
  80 static char *get_system_id(char *hostname);
  81 static void add_aliases(struct hostent *phost);
  82 static void *thr_send_notice(void *);
  83 static void delete_onemon(char *mon_name, my_id *my_idp,
  84                                 mon_entry **monitor_q);
  85 static void send_notice(char *mon_name, int state);
  86 static void add_to_host_array(char *host);
  87 static int in_host_array(char *host);
  88 static void pr_name_addr(name_addr_entry_t *name_addr);
  89 
  90 extern int self_check(char *hostname);
  91 extern struct lifconf *getmyaddrs(void);
  92 
  93 /* ARGSUSED */
  94 void
  95 sm_stat_svc(sm_name *namep, sm_stat_res *resp)
  96 {
  97 
  98         if (debug)
  99                 (void) printf("proc sm_stat: mon_name = %s\n",
 100                     namep->mon_name);
 101 
 102         resp->res_stat = stat_succ;
 103         resp->state = LOCAL_STATE;
 104 }
 105 
 106 /* ARGSUSED */
 107 void
 108 sm_mon_svc(mon *monp, sm_stat_res *resp)
 109 {
 110         mon_id *monidp;
 111         monidp = &monp->mon_id;
 112 
 113         rw_rdlock(&thr_rwlock);
 114         if (debug) {
 115                 (void) printf("proc sm_mon: mon_name = %s, id = %d\n",
 116                     monidp->mon_name, * ((int *)monp->priv));
 117                 pr_mon(monp->mon_id.mon_name);
 118         }
 119 
 120         /* only monitor other hosts */
 121         if (self_check(monp->mon_id.mon_name) == 0) {
 122                 /* store monitor request into monitor_q */
 123                 insert_mon(monp);
 124         }
 125 
 126         pr_mon(monp->mon_id.mon_name);
 127         resp->res_stat = stat_succ;
 128         resp->state = local_state;
 129         rw_unlock(&thr_rwlock);
 130 }
 131 
 132 /* ARGSUSED */
 133 void
 134 sm_unmon_svc(mon_id *monidp, sm_stat *resp)
 135 {
 136         rw_rdlock(&thr_rwlock);
 137         if (debug) {
 138                 (void) printf(
 139                     "proc sm_unmon: mon_name = %s, [%s, %d, %d, %d]\n",
 140                     monidp->mon_name, monidp->my_id.my_name,
 141                     monidp->my_id.my_prog, monidp->my_id.my_vers,
 142                     monidp->my_id.my_proc);
 143                 pr_mon(monidp->mon_name);
 144         }
 145 
 146         delete_mon(monidp->mon_name, &monidp->my_id);
 147         pr_mon(monidp->mon_name);
 148         resp->state = local_state;
 149         rw_unlock(&thr_rwlock);
 150 }
 151 
 152 /* ARGSUSED */
 153 void
 154 sm_unmon_all_svc(my_id *myidp, sm_stat *resp)
 155 {
 156         rw_rdlock(&thr_rwlock);
 157         if (debug)
 158                 (void) printf("proc sm_unmon_all: [%s, %d, %d, %d]\n",
 159                     myidp->my_name,
 160                     myidp->my_prog, myidp->my_vers,
 161                     myidp->my_proc);
 162         delete_mon((char *)NULL, myidp);
 163         pr_mon(NULL);
 164         resp->state = local_state;
 165         rw_unlock(&thr_rwlock);
 166 }
 167 
 168 /*
 169  * Notifies lockd specified by name that state has changed for this server.
 170  */
 171 void
 172 sm_notify_svc(stat_chge *ntfp)
 173 {
 174         rw_rdlock(&thr_rwlock);
 175         if (debug)
 176                 (void) printf("sm_notify: %s state =%d\n",
 177                     ntfp->mon_name, ntfp->state);
 178         send_notice(ntfp->mon_name, ntfp->state);
 179         rw_unlock(&thr_rwlock);
 180 }
 181 
 182 /* ARGSUSED */
 183 void
 184 sm_simu_crash_svc(void *myidp)
 185 {
 186         int i;
 187         struct mon_entry *monitor_q;
 188         int found = 0;
 189 
 190         /* Only one crash should be running at a time. */
 191         mutex_lock(&crash_lock);
 192         if (debug)
 193                 (void) printf("proc sm_simu_crash\n");
 194         if (in_crash) {
 195                 cond_wait(&crash_finish, &crash_lock);
 196                 mutex_unlock(&crash_lock);
 197                 return;
 198         } else {
 199                 in_crash = 1;
 200         }
 201         mutex_unlock(&crash_lock);
 202 
 203         for (i = 0; i < MAX_HASHSIZE; i++) {
 204                 mutex_lock(&mon_table[i].lock);
 205                 monitor_q = mon_table[i].sm_monhdp;
 206                 if (monitor_q != (struct mon_entry *)NULL) {
 207                         mutex_unlock(&mon_table[i].lock);
 208                         found = 1;
 209                         break;
 210                 }
 211                 mutex_unlock(&mon_table[i].lock);
 212         }
 213         /*
 214          * If there are entries found in the monitor table,
 215          * initiate a crash, else zero out the in_crash variable.
 216          */
 217         if (found) {
 218                 mutex_lock(&crash_lock);
 219                 die = 1;
 220                 /* Signal sm_retry() thread if sleeping. */
 221                 cond_signal(&retrywait);
 222                 mutex_unlock(&crash_lock);
 223                 rw_wrlock(&thr_rwlock);
 224                 sm_crash();
 225                 rw_unlock(&thr_rwlock);
 226         } else {
 227                 mutex_lock(&crash_lock);
 228                 in_crash = 0;
 229                 mutex_unlock(&crash_lock);
 230         }
 231 }
 232 
 233 /* ARGSUSED */
 234 void
 235 nsmaddrproc1_reg(regargs, regresp)
 236         reg1args *regargs;
 237         reg1res  *regresp;
 238 {
 239         nsm_addr_res status;
 240         name_addr_entry_t *entry;
 241         char *tmp_n_bytes;
 242         addr_entry_t *addr;
 243 
 244         rw_rdlock(&thr_rwlock);
 245         if (debug) {
 246                 int i;
 247 
 248                 (void) printf("nap1_reg: fam= %d, name= %s, len= %d\n",
 249                                 regargs->family,
 250                                 regargs->name,
 251                                 regargs->address.n_len);
 252                 (void) printf("address is: ");
 253                 for (i = 0; i < regargs->address.n_len; i++) {
 254                         (void) printf("%d.",
 255                                 (unsigned char)regargs->address.n_bytes[i]);
 256                 }
 257                 (void) printf("\n");
 258         }
 259 
 260         /*
 261          * Locate the entry with the name in the NSM_ADDR_REG request if
 262          * it exists.  If it doesn't, create a new entry to hold this name.
 263          * The first time through this code, name_addr starts out as NULL.
 264          */
 265         mutex_lock(&name_addrlock);
 266         for (entry = name_addr; entry; entry = entry->next) {
 267                 if (strcmp(regargs->name, entry->name) == 0) {
 268                         if (debug) {
 269                                 (void) printf("nap1_reg: matched name %s\n",
 270                                                 entry->name);
 271                         }
 272                         break;
 273                 }
 274         }
 275 
 276         if (entry == NULL) {
 277                 entry = (name_addr_entry_t *)malloc(sizeof (*entry));
 278                 if (entry == NULL) {
 279                         if (debug) {
 280                                 (void) printf(
 281                                 "nsmaddrproc1_reg: no memory for entry\n");
 282                         }
 283                         status = nsm_addr_fail;
 284                         goto done;
 285                 }
 286 
 287                 entry->name = strdup(regargs->name);
 288                 if (entry->name == NULL) {
 289                         if (debug) {
 290                                 (void) printf(
 291                                 "nsmaddrproc1_reg: no memory for name\n");
 292                         }
 293                         free(entry);
 294                         status = nsm_addr_fail;
 295                         goto done;
 296                 }
 297                 entry->addresses = NULL;
 298 
 299                 /*
 300                  * Link the new entry onto the *head* of the name_addr
 301                  * table.
 302                  *
 303                  * Note: there is code below in the address maintenance
 304                  * section that assumes this behavior.
 305                  */
 306                 entry->next = name_addr;
 307                 name_addr = entry;
 308         }
 309 
 310         /*
 311          * Try to match the address in the request; if it doesn't match,
 312          * add it to the entry's address list.
 313          */
 314         for (addr = entry->addresses; addr; addr = addr->next) {
 315                 if (addr->family == (sa_family_t)regargs->family &&
 316                     addr->ah.n_len == regargs->address.n_len &&
 317                     memcmp(addr->ah.n_bytes, regargs->address.n_bytes,
 318                         addr->ah.n_len) == 0) {
 319                         if (debug) {
 320                                 int i;
 321 
 322                                 (void) printf("nap1_reg: matched addr ");
 323                                 for (i = 0; i < addr->ah.n_len; i++) {
 324                                         (void) printf("%d.",
 325                                         (unsigned char)addr->ah.n_bytes[i]);
 326                                 }
 327                                 (void) printf(" family %d for name %s\n",
 328                                                 addr->family,
 329                                                 entry->name);
 330                         }
 331                         break;
 332                 }
 333         }
 334 
 335         if (addr == NULL) {
 336                 addr = (addr_entry_t *)malloc(sizeof (*addr));
 337                 tmp_n_bytes = (char *)malloc(regargs->address.n_len);
 338                 if (addr == NULL || tmp_n_bytes == NULL) {
 339                         if (debug) {
 340                                 (void) printf(
 341                                         "nap1_reg: no memory for addr\n");
 342                         }
 343 
 344                         /*
 345                          * If this name entry was just newly made in the
 346                          * table, back it out now that we can't register
 347                          * an address with it anyway.
 348                          *
 349                          * Note: we are making an assumption about how
 350                          * names are added to (the head of) name_addr here.
 351                          */
 352                         if (entry == name_addr && entry->addresses == NULL) {
 353                                 name_addr = name_addr->next;
 354                                 free(entry->name);
 355                                 free(entry);
 356                                 if (tmp_n_bytes)
 357                                         free(tmp_n_bytes);
 358                                 if (addr)
 359                                         free(addr);
 360                                 status = nsm_addr_fail;
 361                                 goto done;
 362                         }
 363                 }
 364 
 365                 /*
 366                  * Note:  this check for address family assumes that we
 367                  *        will get something different here someday for
 368                  *        other supported address types, such as IPv6.
 369                  */
 370                 addr->ah.n_len = regargs->address.n_len;
 371                 addr->ah.n_bytes = tmp_n_bytes;
 372                 addr->family = regargs->family;
 373                 if (debug) {
 374                         if ((addr->family != AF_INET) && \
 375                                 (addr->family != AF_INET6)) {
 376                                 (void) printf(
 377                                         "nap1_reg: unknown addr family %d\n",
 378                                         addr->family);
 379                         }
 380                 }
 381                 (void) memcpy(addr->ah.n_bytes, regargs->address.n_bytes,
 382                                 addr->ah.n_len);
 383 
 384                 addr->next = entry->addresses;
 385                 entry->addresses = addr;
 386         }
 387 
 388         status = nsm_addr_succ;
 389 
 390 done:
 391         regresp->status = status;
 392         if (debug) {
 393                 pr_name_addr(name_addr);
 394         }
 395         mutex_unlock(&name_addrlock);
 396         rw_unlock(&thr_rwlock);
 397 }
 398 
 399 /*
 400  * Insert an entry into the monitor_q.  Space for the entry is allocated
 401  * here.  It is then filled in from the information passed in.
 402  */
 403 static void
 404 insert_mon(monp)
 405         mon *monp;
 406 {
 407         mon_entry *new, *found;
 408         my_id *my_idp, *nl_idp;
 409         mon_entry *monitor_q;
 410         unsigned int hash;
 411         name_addr_entry_t *entry;
 412         addr_entry_t *addr;
 413 
 414         /* Allocate entry for new */
 415         if ((new = (mon_entry *) malloc(sizeof (mon_entry))) == 0) {
 416                 syslog(LOG_ERR,
 417                         "statd: insert_mon: malloc error on mon %s (id=%d)\n",
 418                         monp->mon_id.mon_name, * ((int *)monp->priv));
 419                 return;
 420         }
 421 
 422         /* Initialize and copy contents of monp to new */
 423         (void) memset(new, 0, sizeof (mon_entry));
 424         (void) memcpy(&new->id, monp, sizeof (mon));
 425 
 426         /* Allocate entry for new mon_name */
 427         if ((new->id.mon_id.mon_name = strdup(monp->mon_id.mon_name)) == 0) {
 428                 syslog(LOG_ERR,
 429                         "statd: insert_mon: malloc error on mon %s (id=%d)\n",
 430                         monp->mon_id.mon_name, * ((int *)monp->priv));
 431                 free(new);
 432                 return;
 433         }
 434 
 435 
 436         /* Allocate entry for new my_name */
 437         if ((new->id.mon_id.my_id.my_name =
 438                 strdup(monp->mon_id.my_id.my_name)) == 0) {
 439                 syslog(LOG_ERR,
 440                         "statd: insert_mon: malloc error on mon %s (id=%d)\n",
 441                         monp->mon_id.mon_name, * ((int *)monp->priv));
 442                 free(new->id.mon_id.mon_name);
 443                 free(new);
 444                 return;
 445         }
 446 
 447         if (debug)
 448                 (void) printf("add_mon(%x) %s (id=%d)\n",
 449                 (int)new, new->id.mon_id.mon_name, * ((int *)new->id.priv));
 450 
 451         /*
 452          * Record the name, and all addresses which have been registered
 453          * for this name, in the filesystem name space.
 454          */
 455         record_name(new->id.mon_id.mon_name, 1);
 456         if (regfiles_only == 0) {
 457                 mutex_lock(&name_addrlock);
 458                 for (entry = name_addr; entry; entry = entry->next) {
 459                         if (strcmp(new->id.mon_id.mon_name, entry->name) != 0) {
 460                                 continue;
 461                         }
 462 
 463                         for (addr = entry->addresses; addr; addr = addr->next) {
 464                                 record_addr(new->id.mon_id.mon_name,
 465                                                 addr->family, &addr->ah);
 466                         }
 467                         break;
 468                 }
 469                 mutex_unlock(&name_addrlock);
 470         }
 471 
 472         SMHASH(new->id.mon_id.mon_name, hash);
 473         mutex_lock(&mon_table[hash].lock);
 474         monitor_q = mon_table[hash].sm_monhdp;
 475 
 476         /* If mon_table hash list is empty. */
 477         if (monitor_q == (struct mon_entry *)NULL) {
 478                 if (debug)
 479                         (void) printf("\nAdding to monitor_q hash %d\n", hash);
 480                 new->nxt = new->prev = (mon_entry *)NULL;
 481                 mon_table[hash].sm_monhdp = new;
 482                 mutex_unlock(&mon_table[hash].lock);
 483                 return;
 484         } else {
 485                 found = 0;
 486                 my_idp = &new->id.mon_id.my_id;
 487                 while (monitor_q != (mon_entry *)NULL)  {
 488                         /*
 489                          * This list is searched sequentially for the
 490                          * tuple (hostname, prog, vers, proc). The tuples
 491                          * are inserted in the beginning of the monitor_q,
 492                          * if the hostname is not already present in the list.
 493                          * If the hostname is found in the list, the incoming
 494                          * tuple is inserted just after all the tuples with the
 495                          * same hostname. However, if the tuple matches exactly
 496                          * with an entry in the list, space allocated for the
 497                          * new entry is released and nothing is inserted in the
 498                          * list.
 499                          */
 500 
 501                         if (str_cmp_unqual_hostname(
 502                                 monitor_q->id.mon_id.mon_name,
 503                                 new->id.mon_id.mon_name) == 0) {
 504                                 /* found */
 505                                 nl_idp = &monitor_q->id.mon_id.my_id;
 506                                 if ((str_cmp_unqual_hostname(my_idp->my_name,
 507                                         nl_idp->my_name) == 0) &&
 508                                         my_idp->my_prog == nl_idp->my_prog &&
 509                                         my_idp->my_vers == nl_idp->my_vers &&
 510                                         my_idp->my_proc == nl_idp->my_proc) {
 511                                         /*
 512                                          * already exists an identical one,
 513                                          * release the space allocated for the
 514                                          * mon_entry
 515                                          */
 516                                         free(new->id.mon_id.mon_name);
 517                                         free(new->id.mon_id.my_id.my_name);
 518                                         free(new);
 519                                         mutex_unlock(&mon_table[hash].lock);
 520                                         return;
 521                                 } else {
 522                                         /*
 523                                          * mark the last callback that is
 524                                          * not matching; new is inserted
 525                                          * after this
 526                                          */
 527                                         found = monitor_q;
 528                                 }
 529                         } else if (found)
 530                                 break;
 531                         monitor_q = monitor_q->nxt;
 532                 }
 533                 if (found) {
 534                         /*
 535                          * insert just after the entry having matching tuple.
 536                          */
 537                         new->nxt = found->nxt;
 538                         new->prev = found;
 539                         if (found->nxt != (mon_entry *)NULL)
 540                                 found->nxt->prev = new;
 541                         found->nxt = new;
 542                 } else {
 543                         /*
 544                          * not found, insert in front of list.
 545                          */
 546                         new->nxt = mon_table[hash].sm_monhdp;
 547                         new->prev = (mon_entry *) NULL;
 548                         if (new->nxt != (mon_entry *) NULL)
 549                                 new->nxt->prev = new;
 550                         mon_table[hash].sm_monhdp = new;
 551                 }
 552                 mutex_unlock(&mon_table[hash].lock);
 553                 return;
 554         }
 555 }
 556 
 557 /*
 558  * Deletes a specific monitor name or deletes all monitors with same id
 559  * in hash table.
 560  */
 561 static void
 562 delete_mon(mon_name, my_idp)
 563         char *mon_name;
 564         my_id *my_idp;
 565 {
 566         unsigned int hash;
 567 
 568         if (mon_name != (char *)NULL) {
 569                 record_name(mon_name, 0);
 570                 SMHASH(mon_name, hash);
 571                 mutex_lock(&mon_table[hash].lock);
 572                 delete_onemon(mon_name, my_idp, &mon_table[hash].sm_monhdp);
 573                 mutex_unlock(&mon_table[hash].lock);
 574         } else {
 575                 for (hash = 0; hash < MAX_HASHSIZE; hash++) {
 576                         mutex_lock(&mon_table[hash].lock);
 577                         delete_onemon(mon_name, my_idp,
 578                                         &mon_table[hash].sm_monhdp);
 579                         mutex_unlock(&mon_table[hash].lock);
 580                 }
 581         }
 582 }
 583 
 584 /*
 585  * Deletes a monitor in list.
 586  * IF mon_name is NULL, delete all mon_names that have the same id,
 587  * else delete specific monitor.
 588  */
 589 void
 590 delete_onemon(mon_name, my_idp, monitor_q)
 591         char *mon_name;
 592         my_id *my_idp;
 593         mon_entry **monitor_q;
 594 {
 595 
 596         mon_entry *next, *nl;
 597         my_id *nl_idp;
 598 
 599         next = *monitor_q;
 600         while ((nl = next) != (struct mon_entry *)NULL) {
 601                 next = next->nxt;
 602                 if (mon_name == (char *)NULL || (mon_name != (char *)NULL &&
 603                         str_cmp_unqual_hostname(nl->id.mon_id.mon_name,
 604                         mon_name) == 0)) {
 605                         nl_idp = &nl->id.mon_id.my_id;
 606                         if ((str_cmp_unqual_hostname(my_idp->my_name,
 607                                         nl_idp->my_name) == 0) &&
 608                                 my_idp->my_prog == nl_idp->my_prog &&
 609                                 my_idp->my_vers == nl_idp->my_vers &&
 610                                 my_idp->my_proc == nl_idp->my_proc) {
 611                                 /* found */
 612                                 if (debug)
 613                                         (void) printf("delete_mon(%x): %s\n",
 614                                                         (int)nl, mon_name ?
 615                                                         mon_name : "<NULL>");
 616                                 /*
 617                                  * Remove the monitor name from the
 618                                  * record_q, if id matches.
 619                                  */
 620                                 record_name(nl->id.mon_id.mon_name, 0);
 621                                 /* if nl is not the first entry on list */
 622                                 if (nl->prev != (struct mon_entry *)NULL)
 623                                         nl->prev->nxt = nl->nxt;
 624                                 else {
 625                                         *monitor_q = nl->nxt;
 626                                 }
 627                                 if (nl->nxt != (struct mon_entry *)NULL)
 628                                         nl->nxt->prev = nl->prev;
 629                                 free(nl->id.mon_id.mon_name);
 630                                 free(nl_idp->my_name);
 631                                 free(nl);
 632                         }
 633                 } /* end of if mon */
 634         }
 635 
 636 }
 637 /*
 638  * Notify lockd of host specified by mon_name that the specified state
 639  * has changed.
 640  */
 641 static void
 642 send_notice(mon_name, state)
 643         char *mon_name;
 644         int state;
 645 {
 646         struct mon_entry *next;
 647         mon_entry *monitor_q;
 648         unsigned int hash;
 649         moninfo_t *minfop;
 650         mon *monp;
 651 
 652         SMHASH(mon_name, hash);
 653         mutex_lock(&mon_table[hash].lock);
 654         monitor_q = mon_table[hash].sm_monhdp;
 655 
 656         next = monitor_q;
 657         while (next != (struct mon_entry *)NULL) {
 658                 if (hostname_eq(next->id.mon_id.mon_name, mon_name)) {
 659                         monp = &next->id;
 660                         /*
 661                          * Prepare the minfop structure to pass to
 662                          * thr_create(). This structure is a copy of
 663                          * mon info and state.
 664                          */
 665                         if ((minfop =
 666                                 (moninfo_t *)xmalloc(sizeof (moninfo_t))) !=
 667                                 (moninfo_t *)NULL) {
 668                                 (void) memcpy(&minfop->id, monp, sizeof (mon));
 669                                 /* Allocate entry for mon_name */
 670                                 if ((minfop->id.mon_id.mon_name =
 671                                         strdup(monp->mon_id.mon_name)) == 0) {
 672                                         syslog(LOG_ERR,
 673                         "statd: send_notice: malloc error on mon %s (id=%d)\n",
 674                                                 monp->mon_id.mon_name,
 675                                                 * ((int *)monp->priv));
 676                                         free(minfop);
 677                                         continue;
 678                                 }
 679                                 /* Allocate entry for my_name */
 680                                 if ((minfop->id.mon_id.my_id.my_name =
 681                                 strdup(monp->mon_id.my_id.my_name)) == 0) {
 682                                         syslog(LOG_ERR,
 683                         "statd: send_notice: malloc error on mon %s (id=%d)\n",
 684                                                 monp->mon_id.mon_name,
 685                                                 * ((int *)monp->priv));
 686                                         free(minfop->id.mon_id.mon_name);
 687                                         free(minfop);
 688                                         continue;
 689                                 }
 690                                 minfop->state = state;
 691                                 /*
 692                                  * Create detached threads to process each host
 693                                  * to notify.  If error, print out msg, free
 694                                  * resources and continue.
 695                                  */
 696                                 if (thr_create(NULL, NULL, thr_send_notice,
 697                                                 (void *)minfop, THR_DETACHED,
 698                                                 NULL)) {
 699                                     syslog(LOG_ERR,
 700                 "statd: unable to create thread to send_notice to %s.\n",
 701                                         mon_name);
 702                                     free(minfop->id.mon_id.mon_name);
 703                                     free(minfop->id.mon_id.my_id.my_name);
 704                                     free(minfop);
 705                                     continue;
 706                                 }
 707                         }
 708                 }
 709                 next = next->nxt;
 710         }
 711         mutex_unlock(&mon_table[hash].lock);
 712 }
 713 
 714 /*
 715  * Work thread created to do the actual statd_call_lockd
 716  */
 717 static void *
 718 thr_send_notice(void *arg)
 719 {
 720         moninfo_t *minfop;
 721 
 722         minfop = (moninfo_t *)arg;
 723         if (statd_call_lockd(&minfop->id, minfop->state) == -1) {
 724                 if (debug && minfop->id.mon_id.mon_name)
 725                         (void) printf("problem with notifying %s failure, "
 726                             "give up\n", minfop->id.mon_id.mon_name);
 727         } else {
 728                 if (debug)
 729                         (void) printf("send_notice: %s, %d notified.\n",
 730                             minfop->id.mon_id.mon_name, minfop->state);
 731         }
 732 
 733         free(minfop->id.mon_id.mon_name);
 734         free(minfop->id.mon_id.my_id.my_name);
 735         free(minfop);
 736 
 737         thr_exit((void *) 0);
 738 #ifdef lint
 739         /*NOTREACHED*/
 740         return ((void *)0);
 741 #endif
 742 }
 743 
 744 /*
 745  * Contact lockd specified by monp.
 746  */
 747 static int
 748 statd_call_lockd(monp, state)
 749         mon *monp;
 750         int state;
 751 {
 752         enum clnt_stat clnt_stat;
 753         struct timeval tottimeout;
 754         struct sm_status stat;
 755         my_id *my_idp;
 756         char *mon_name;
 757         int i;
 758         int rc = 0;
 759         CLIENT *clnt;
 760 
 761         mon_name = monp->mon_id.mon_name;
 762         my_idp = &monp->mon_id.my_id;
 763         (void) memset(&stat, 0, sizeof (stat));
 764         stat.mon_name = mon_name;
 765         stat.state = state;
 766         for (i = 0; i < 16; i++) {
 767                 stat.priv[i] = monp->priv[i];
 768         }
 769         if (debug)
 770                 (void) printf("statd_call_lockd: %s state = %d\n",
 771                         stat.mon_name, stat.state);
 772 
 773         tottimeout.tv_sec = SM_RPC_TIMEOUT;
 774         tottimeout.tv_usec = 0;
 775 
 776         clnt = create_client(my_idp->my_name, my_idp->my_prog, my_idp->my_vers,
 777             "ticotsord", &tottimeout);
 778         if (clnt == NULL) {
 779                 return (-1);
 780         }
 781 
 782         clnt_stat = clnt_call(clnt, my_idp->my_proc,
 783                                 xdr_sm_status, (char *)&stat,
 784                                 xdr_void, NULL, tottimeout);
 785         if (debug) {
 786                 (void) printf("clnt_stat=%s(%d)\n",
 787                         clnt_sperrno(clnt_stat), clnt_stat);
 788         }
 789         if (clnt_stat != (int)RPC_SUCCESS) {
 790                 syslog(LOG_WARNING,
 791                         "statd: cannot talk to lockd at %s, %s(%d)\n",
 792                         my_idp->my_name, clnt_sperrno(clnt_stat), clnt_stat);
 793                 rc = -1;
 794         }
 795 
 796         clnt_destroy(clnt);
 797         return (rc);
 798 
 799 }
 800 
 801 /*
 802  * Client handle created.
 803  */
 804 CLIENT *
 805 create_client(char *host, int prognum, int versnum, char *netid,
 806     struct timeval *utimeout)
 807 {
 808         int             fd;
 809         struct timeval  timeout;
 810         CLIENT          *client;
 811         struct t_info   tinfo;
 812 
 813         if (netid == NULL) {
 814                 client = clnt_create_timed(host, prognum, versnum,
 815                     "netpath", utimeout);
 816         } else {
 817                 struct netconfig *nconf;
 818 
 819                 nconf = getnetconfigent(netid);
 820                 if (nconf == NULL) {
 821                         return (NULL);
 822                 }
 823 
 824                 client = clnt_tp_create_timed(host, prognum, versnum, nconf,
 825                     utimeout);
 826 
 827                 freenetconfigent(nconf);
 828         }
 829 
 830         if (client == NULL) {
 831                 return (NULL);
 832         }
 833 
 834         (void) CLNT_CONTROL(client, CLGET_FD, (caddr_t)&fd);
 835         if (t_getinfo(fd, &tinfo) != -1) {
 836                 if (tinfo.servtype == T_CLTS) {
 837                         /*
 838                          * Set time outs for connectionless case
 839                          */
 840                         timeout.tv_usec = 0;
 841                         timeout.tv_sec = SM_CLTS_TIMEOUT;
 842                         (void) CLNT_CONTROL(client,
 843                             CLSET_RETRY_TIMEOUT, (caddr_t)&timeout);
 844                 }
 845         } else
 846                 return (NULL);
 847 
 848         return (client);
 849 }
 850 
 851 /*
 852  * ONLY for debugging.
 853  * Debug messages which prints out the monitor table information.
 854  * If name is specified, just print out the hash list corresponding
 855  * to name, otherwise print out the entire monitor table.
 856  */
 857 static void
 858 pr_mon(name)
 859         char *name;
 860 {
 861         mon_entry *nl;
 862         int hash;
 863 
 864         if (!debug)
 865                 return;
 866 
 867         /* print all */
 868         if (name == NULL) {
 869                 for (hash = 0; hash < MAX_HASHSIZE; hash++) {
 870                         mutex_lock(&mon_table[hash].lock);
 871                         nl = mon_table[hash].sm_monhdp;
 872                         if (nl == (struct mon_entry *)NULL) {
 873                                 (void) printf(
 874                                         "*****monitor_q = NULL hash %d\n",
 875                                         hash);
 876                                 mutex_unlock(&mon_table[hash].lock);
 877                                 continue;
 878                         }
 879                         (void) printf("*****monitor_q:\n ");
 880                         while (nl != (mon_entry *)NULL) {
 881                                 (void) printf("%s:(%x), ",
 882                                         nl->id.mon_id.mon_name, (int)nl);
 883                                 nl = nl->nxt;
 884                         }
 885                         mutex_unlock(&mon_table[hash].lock);
 886                         (void) printf("\n");
 887                 }
 888         } else { /* print one hash list */
 889                 SMHASH(name, hash);
 890                 mutex_lock(&mon_table[hash].lock);
 891                 nl = mon_table[hash].sm_monhdp;
 892                 if (nl == (struct mon_entry *)NULL) {
 893                         (void) printf("*****monitor_q = NULL hash %d\n", hash);
 894                 } else {
 895                         (void) printf("*****monitor_q:\n ");
 896                         while (nl != (mon_entry *)NULL) {
 897                                 (void) printf("%s:(%x), ",
 898                                         nl->id.mon_id.mon_name, (int)nl);
 899                                 nl = nl->nxt;
 900                         }
 901                         (void) printf("\n");
 902                 }
 903                 mutex_unlock(&mon_table[hash].lock);
 904         }
 905 }
 906 
 907 /*
 908  * Only for debugging.
 909  * Dump the host name-to-address translation table passed in `name_addr'.
 910  */
 911 static void
 912 pr_name_addr(name_addr_entry_t *name_addr)
 913 {
 914         name_addr_entry_t *entry;
 915         addr_entry_t *addr;
 916         struct in_addr ipv4_addr;
 917         char *ipv6_addr;
 918         char abuf[INET6_ADDRSTRLEN];
 919 
 920         assert(MUTEX_HELD(&name_addrlock));
 921         (void) printf("name-to-address translation table:\n");
 922         for (entry = name_addr; entry != NULL; entry = entry->next) {
 923                 (void) printf("\t%s: ",
 924                     (entry->name ? entry->name : "(null)"));
 925                 for (addr = entry->addresses; addr; addr = addr->next) {
 926                         switch (addr->family) {
 927                         case AF_INET:
 928                                 ipv4_addr = *(struct in_addr *)addr->ah.n_bytes;
 929                                 (void) printf(" %s (fam %d)",
 930                                     inet_ntoa(ipv4_addr), addr->family);
 931                                 break;
 932                         case AF_INET6:
 933                                 ipv6_addr = (char *)addr->ah.n_bytes;
 934                                 (void) printf(" %s (fam %d)",
 935                                     inet_ntop(addr->family, ipv6_addr, abuf,
 936                                     sizeof (abuf)), addr->family);
 937                                 break;
 938                         default:
 939                                 return;
 940                         }
 941                 }
 942                 printf("\n");
 943         }
 944 }
 945 
 946 /*
 947  * First, try to compare the hostnames as strings.  If the hostnames does not
 948  * match we might deal with the hostname aliases.  In this case two different
 949  * aliases for the same machine don't match each other when using strcmp.  To
 950  * deal with this, the hostnames must be translated into some sort of universal
 951  * identifier.  These identifiers can be compared.  Universal network addresses
 952  * are currently used for this identifier because it is general and easy to do.
 953  * Other schemes are possible and this routine could be converted if required.
 954  *
 955  * If it can't find an address for some reason, 0 is returned.
 956  */
 957 static int
 958 hostname_eq(char *host1, char *host2)
 959 {
 960         char *sysid1;
 961         char *sysid2;
 962         int rv;
 963 
 964         /* Compare hostnames as strings */
 965         if (host1 != NULL && host2 != NULL && strcmp(host1, host2) == 0)
 966                 return (1);
 967 
 968         /* Try harder if hostnames do not match */
 969         sysid1 = get_system_id(host1);
 970         sysid2 = get_system_id(host2);
 971         if ((sysid1 == NULL) || (sysid2 == NULL))
 972                 rv = 0;
 973         else
 974                 rv = (strcmp(sysid1, sysid2) == 0);
 975         free(sysid1);
 976         free(sysid2);
 977         return (rv);
 978 }
 979 
 980 /*
 981  * Convert a hostname character string into its network address.
 982  * A network address is found by searching through all the entries
 983  * in /etc/netconfig and doing a netdir_getbyname() for each inet
 984  * entry found.  The netbuf structure returned is converted into
 985  * a universal address format.
 986  *
 987  * If a NULL hostname is given, then the name of the current host
 988  * is used.  If the hostname doesn't map to an address, a NULL
 989  * pointer is returned.
 990  *
 991  * N.B. the character string returned is allocated in taddr2uaddr()
 992  * and should be freed by the caller using free().
 993  */
 994 static char *
 995 get_system_id(char *hostname)
 996 {
 997         void *hp;
 998         struct netconfig *ncp;
 999         struct nd_hostserv service;
1000         struct nd_addrlist *addrs;
1001         char *uaddr;
1002         int rv;
1003 
1004         if (hostname == NULL)
1005                 service.h_host = HOST_SELF;
1006         else
1007                 service.h_host = hostname;
1008         service.h_serv = NULL;
1009         hp = setnetconfig();
1010         if (hp == (void *) NULL) {
1011                 return (NULL);
1012         }
1013         while ((ncp = getnetconfig(hp)) != (struct netconfig *)NULL) {
1014                 if ((strcmp(ncp->nc_protofmly, NC_INET) == 0) ||
1015                     (strcmp(ncp->nc_protofmly, NC_INET6) == 0)) {
1016                         addrs = NULL;
1017                         rv = netdir_getbyname(ncp, &service, &addrs);
1018                         if (rv != 0) {
1019                                 continue;
1020                         }
1021                         if (addrs) {
1022                                 uaddr = taddr2uaddr(ncp, addrs->n_addrs);
1023                                 netdir_free(addrs, ND_ADDRLIST);
1024                                 endnetconfig(hp);
1025                                 return (uaddr);
1026                         }
1027                 }
1028                 else
1029                         continue;
1030         }
1031         endnetconfig(hp);
1032         return (NULL);
1033 }
1034 
1035 void
1036 merge_hosts(void)
1037 {
1038         struct lifconf *lifc = NULL;
1039         int sock = -1;
1040         struct lifreq *lifrp;
1041         struct lifreq lifr;
1042         int n;
1043         struct sockaddr_in *sin;
1044         struct sockaddr_in6 *sin6;
1045         struct sockaddr_storage *sa;
1046         int af;
1047         struct hostent *phost;
1048         char *addr;
1049         size_t alen;
1050         int errnum;
1051 
1052         /*
1053          * This function will enumerate all the interfaces for
1054          * this platform, then get the hostent for each i/f.
1055          * With the hostent structure, we can get all of the
1056          * aliases for the i/f. Then we'll merge all the aliases
1057          * with the existing host_name[] list to come up with
1058          * all of the known names for each interface. This solves
1059          * the problem of a multi-homed host not knowing which
1060          * name to publish when statd is started. All the aliases
1061          * will be stored in the array, host_name.
1062          *
1063          * NOTE: Even though we will use all of the aliases we
1064          * can get from the i/f hostent, the receiving statd
1065          * will still need to handle aliases with hostname_eq.
1066          * This is because the sender's aliases may not match
1067          * those of the receiver.
1068          */
1069         lifc = getmyaddrs();
1070         if (lifc == (struct lifconf *)NULL) {
1071                 goto finish;
1072         }
1073         lifrp = lifc->lifc_req;
1074         for (n = lifc->lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
1075 
1076                 (void) strncpy(lifr.lifr_name, lifrp->lifr_name,
1077                     sizeof (lifr.lifr_name));
1078 
1079                 af = lifrp->lifr_addr.ss_family;
1080                 sock = socket(af, SOCK_DGRAM, 0);
1081                 if (sock == -1) {
1082                         syslog(LOG_ERR, "statd: socket failed\n");
1083                         goto finish;
1084                 }
1085 
1086                 /* If it's the loopback interface, ignore */
1087                 if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
1088                         syslog(LOG_ERR,
1089                             "statd: SIOCGLIFFLAGS failed, error: %m\n");
1090                         goto finish;
1091                 }
1092                 if (lifr.lifr_flags & IFF_LOOPBACK)
1093                         continue;
1094 
1095                 if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
1096                         syslog(LOG_ERR,
1097                             "statd: SIOCGLIFADDR failed, error: %m\n");
1098                         goto finish;
1099                 }
1100                 sa = (struct sockaddr_storage *)&(lifr.lifr_addr);
1101 
1102                 if (sa->ss_family == AF_INET) {
1103                         sin = (struct sockaddr_in *)&lifr.lifr_addr;
1104                         addr = (char *)(&sin->sin_addr);
1105                         alen = sizeof (struct in_addr);
1106                 } else if (sa->ss_family == AF_INET6) {
1107                         sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1108                         addr = (char *)(&sin6->sin6_addr);
1109                         alen = sizeof (struct in6_addr);
1110                 } else {
1111                         syslog(LOG_WARNING,
1112                             "unexpected address family (%d)",
1113                             sa->ss_family);
1114                         continue;
1115                 }
1116 
1117                 phost = getipnodebyaddr(addr, alen, sa->ss_family, &errnum);
1118 
1119                 if (phost)
1120                         add_aliases(phost);
1121         }
1122         /*
1123          * Now, just in case we didn't get them all byaddr,
1124          * let's look by name.
1125          */
1126         phost = getipnodebyname(hostname, AF_INET6, AI_ALL, &errnum);
1127 
1128         if (phost)
1129                 add_aliases(phost);
1130 
1131 finish:
1132         if (sock != -1)
1133                 (void) close(sock);
1134         if (lifc) {
1135                 free(lifc->lifc_buf);
1136                 free(lifc);
1137         }
1138 }
1139 
1140 /*
1141  * add_aliases traverses a hostent alias list, compares
1142  * the aliases to the contents of host_name, and if an
1143  * alias is not already present, adds it to host_name[].
1144  */
1145 
1146 static void
1147 add_aliases(struct hostent *phost)
1148 {
1149         char **aliases;
1150 
1151         if (!in_host_array(phost->h_name)) {
1152                 add_to_host_array(phost->h_name);
1153         }
1154 
1155         if (phost->h_aliases == NULL)
1156                 return;                 /* no aliases to register */
1157 
1158         for (aliases = phost->h_aliases; *aliases != NULL; aliases++) {
1159                 if (!in_host_array(*aliases)) {
1160                         add_to_host_array(*aliases);
1161                 }
1162         }
1163 }
1164 
1165 /*
1166  * in_host_array checks if the given hostname exists in the host_name
1167  * array. Returns 0 if the host doesn't exist, and 1 if it does exist
1168  */
1169 static int
1170 in_host_array(char *host)
1171 {
1172         int i;
1173 
1174         if (debug)
1175                 (void) printf("%s ", host);
1176 
1177         if ((strcmp(hostname, host) == 0) || (strcmp(LOGHOST, host) == 0))
1178                 return (1);
1179 
1180         for (i = 0; i < addrix; i++) {
1181                 if (strcmp(host_name[i], host) == 0)
1182                         return (1);
1183         }
1184 
1185         return (0);
1186 }
1187 
1188 /*
1189  * add_to_host_array adds a hostname to the host_name array. But if
1190  * the array is already full, then it first reallocates the array with
1191  * HOST_NAME_INCR extra elements. If the realloc fails, then it does
1192  * nothing and leaves host_name the way it was previous to the call.
1193  */
1194 static void
1195 add_to_host_array(char *host) {
1196 
1197         void *new_block = NULL;
1198 
1199         /* Make sure we don't overrun host_name. */
1200         if (addrix >= host_name_count) {
1201                 host_name_count += HOST_NAME_INCR;
1202                 new_block = realloc((void *)host_name,
1203                                     host_name_count*sizeof (char *));
1204                 if (new_block != NULL)
1205                         host_name = new_block;
1206                 else {
1207                         host_name_count -= HOST_NAME_INCR;
1208                         return;
1209                 }
1210         }
1211 
1212         if ((host_name[addrix] = strdup(host)) != NULL)
1213                 addrix++;
1214 }
1215 
1216 /*
1217  * Compares the unqualified hostnames for hosts. Returns 0 if the
1218  * names match, and 1 if the names fail to match.
1219  */
1220 int
1221 str_cmp_unqual_hostname(char *rawname1, char *rawname2)
1222 {
1223         size_t unq_len1, unq_len2;
1224         char *domain;
1225 
1226         if (debug) {
1227                 (void) printf("str_cmp_unqual: rawname1= %s, rawname2= %s\n",
1228                     rawname1, rawname2);
1229         }
1230 
1231         unq_len1 = strcspn(rawname1, ".");
1232         unq_len2 = strcspn(rawname2, ".");
1233         domain = strchr(rawname1, '.');
1234         if (domain != NULL) {
1235                 if ((strncmp(rawname1, SM_ADDR_IPV4, unq_len1) == 0) ||
1236                     (strncmp(rawname1, SM_ADDR_IPV6, unq_len1) == 0))
1237                 return (1);
1238         }
1239 
1240         if ((unq_len1 == unq_len2) &&
1241             (strncmp(rawname1, rawname2, unq_len1) == 0)) {
1242                 return (0);
1243         }
1244 
1245         return (1);
1246 }
1247 
1248 /*
1249  * Compares <family>.<address-specifier> ASCII names for hosts.  Returns
1250  * 0 if the addresses match, and 1 if the addresses fail to match.
1251  * If the args are indeed specifiers, they should look like this:
1252  *
1253  *      ipv4.192.9.200.1 or ipv6.::C009:C801
1254  */
1255 int
1256 str_cmp_address_specifier(char *specifier1, char *specifier2)
1257 {
1258         size_t unq_len1, unq_len2;
1259         char *rawaddr1, *rawaddr2;
1260         int af1, af2, len;
1261 
1262         if (debug) {
1263                 (void) printf("str_cmp_addr: specifier1= %s, specifier2= %s\n",
1264                     specifier1, specifier2);
1265         }
1266 
1267         /*
1268          * Verify that:
1269          *      1. The family tokens match;
1270          *      2. The IP addresses following the `.' are legal; and
1271          *      3. These addresses match.
1272          */
1273         unq_len1 = strcspn(specifier1, ".");
1274         unq_len2 = strcspn(specifier2, ".");
1275         rawaddr1 = strchr(specifier1, '.');
1276         rawaddr2 = strchr(specifier2, '.');
1277 
1278         if (strncmp(specifier1, SM_ADDR_IPV4, unq_len1) == 0) {
1279                 af1 = AF_INET;
1280                 len = 4;
1281         } else if (strncmp(specifier1, SM_ADDR_IPV6, unq_len1) == 0) {
1282                 af1 = AF_INET6;
1283                 len = 16;
1284         }
1285         else
1286                 return (1);
1287 
1288         if (strncmp(specifier2, SM_ADDR_IPV4, unq_len2) == 0)
1289                 af2 = AF_INET;
1290         else if (strncmp(specifier2, SM_ADDR_IPV6, unq_len2) == 0)
1291                 af2 = AF_INET6;
1292         else
1293                 return (1);
1294 
1295         if (af1 != af2)
1296                 return (1);
1297 
1298         if (rawaddr1 != NULL && rawaddr2 != NULL) {
1299                 char dst1[16];
1300                 char dst2[16];
1301                 ++rawaddr1;
1302                 ++rawaddr2;
1303 
1304                 if (inet_pton(af1, rawaddr1, dst1) == 1 &&
1305                     inet_pton(af2, rawaddr1, dst2) == 1 &&
1306                     memcmp(dst1, dst2, len) == 0) {
1307                         return (0);
1308                 }
1309         }
1310         return (1);
1311 }
1312 
1313 /*
1314  * Add IP address strings to the host_name list.
1315  */
1316 void
1317 merge_ips(void)
1318 {
1319         struct ifaddrs *ifap, *cifap;
1320         int error;
1321 
1322         error = getifaddrs(&ifap);
1323         if (error) {
1324                 syslog(LOG_WARNING, "getifaddrs error: '%s'",
1325                     strerror(errno));
1326                 return;
1327         }
1328 
1329         for (cifap = ifap; cifap != NULL; cifap = cifap->ifa_next) {
1330                 struct sockaddr *sa = cifap->ifa_addr;
1331                 char addr_str[INET6_ADDRSTRLEN];
1332                 void *addr = NULL;
1333 
1334                 switch (sa->sa_family) {
1335                 case AF_INET: {
1336                         struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1337 
1338                         /* Skip loopback addresses. */
1339                         if (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
1340                                 continue;
1341                         }
1342 
1343                         addr = &sin->sin_addr;
1344                         break;
1345                 }
1346 
1347                 case AF_INET6: {
1348                         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
1349 
1350                         /* Skip loopback addresses. */
1351                         if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) {
1352                                 continue;
1353                         }
1354 
1355                         addr = &sin6->sin6_addr;
1356                         break;
1357                 }
1358 
1359                 default:
1360                         syslog(LOG_WARNING, "Unknown address family %d for "
1361                             "interface %s", sa->sa_family, cifap->ifa_name);
1362                         continue;
1363                 }
1364 
1365                 if (inet_ntop(sa->sa_family, addr, addr_str, sizeof (addr_str))
1366                     == NULL) {
1367                         syslog(LOG_WARNING, "Failed to convert address into "
1368                             "string representation for interface '%s' "
1369                             "address family %d", cifap->ifa_name,
1370                             sa->sa_family);
1371                         continue;
1372                 }
1373 
1374                 if (!in_host_array(addr_str)) {
1375                         add_to_host_array(addr_str);
1376                 }
1377         }
1378 
1379         freeifaddrs(ifap);
1380 }