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 }