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