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