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