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