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