17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22*98573c19SMarcel Telka 23*98573c19SMarcel Telka /* 24*98573c19SMarcel Telka * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 25*98573c19SMarcel Telka */ 26*98573c19SMarcel Telka 277c478bd9Sstevel@tonic-gate /* 28a6f0fae9Sgt29601 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 297c478bd9Sstevel@tonic-gate * Use is subject to license terms. 307c478bd9Sstevel@tonic-gate */ 31b17f03d7SMarcel Telka /* 32bbaa8b60SDan Kruchinin * Copyright (c) 2012 by Delphix. All rights reserved. 33b17f03d7SMarcel Telka */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 367c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate /* 397c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 407c478bd9Sstevel@tonic-gate * The Regents of the University of California 417c478bd9Sstevel@tonic-gate * All Rights Reserved 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 447c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 457c478bd9Sstevel@tonic-gate * contributors. 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #include <stdio.h> 497c478bd9Sstevel@tonic-gate #include <sys/types.h> 507c478bd9Sstevel@tonic-gate #include <stdlib.h> 517c478bd9Sstevel@tonic-gate #include <unistd.h> 527c478bd9Sstevel@tonic-gate #include <string.h> 537c478bd9Sstevel@tonic-gate #include <syslog.h> 547c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 557c478bd9Sstevel@tonic-gate #include <rpcsvc/sm_inter.h> 567c478bd9Sstevel@tonic-gate #include <rpcsvc/nsm_addr.h> 577c478bd9Sstevel@tonic-gate #include <memory.h> 587c478bd9Sstevel@tonic-gate #include <net/if.h> 597c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 607c478bd9Sstevel@tonic-gate #include <sys/socket.h> 617c478bd9Sstevel@tonic-gate #include <netinet/in.h> 627c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 637c478bd9Sstevel@tonic-gate #include <netdb.h> 647c478bd9Sstevel@tonic-gate #include <netdir.h> 657c478bd9Sstevel@tonic-gate #include <synch.h> 667c478bd9Sstevel@tonic-gate #include <thread.h> 67bbaa8b60SDan Kruchinin #include <ifaddrs.h> 68bbaa8b60SDan Kruchinin #include <errno.h> 697c478bd9Sstevel@tonic-gate #include <assert.h> 707c478bd9Sstevel@tonic-gate #include "sm_statd.h" 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate static int local_state; /* fake local sm state */ 737c478bd9Sstevel@tonic-gate /* client name-to-address translation table */ 747c478bd9Sstevel@tonic-gate static name_addr_entry_t *name_addr = NULL; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate #define LOGHOST "loghost" 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate static void delete_mon(char *mon_name, my_id *my_idp); 807c478bd9Sstevel@tonic-gate static void insert_mon(mon *monp); 817c478bd9Sstevel@tonic-gate static void pr_mon(char *); 827c478bd9Sstevel@tonic-gate static int statd_call_lockd(mon *monp, int state); 837c478bd9Sstevel@tonic-gate static int hostname_eq(char *host1, char *host2); 847c478bd9Sstevel@tonic-gate static char *get_system_id(char *hostname); 857c478bd9Sstevel@tonic-gate static void add_aliases(struct hostent *phost); 867c478bd9Sstevel@tonic-gate static void *thr_send_notice(void *); 877c478bd9Sstevel@tonic-gate static void delete_onemon(char *mon_name, my_id *my_idp, 887c478bd9Sstevel@tonic-gate mon_entry **monitor_q); 897c478bd9Sstevel@tonic-gate static void send_notice(char *mon_name, int state); 907c478bd9Sstevel@tonic-gate static void add_to_host_array(char *host); 917c478bd9Sstevel@tonic-gate static int in_host_array(char *host); 927c478bd9Sstevel@tonic-gate static void pr_name_addr(name_addr_entry_t *name_addr); 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate extern int self_check(char *hostname); 957c478bd9Sstevel@tonic-gate extern struct lifconf *getmyaddrs(void); 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* ARGSUSED */ 987c478bd9Sstevel@tonic-gate void 99bbaa8b60SDan Kruchinin sm_stat_svc(sm_name *namep, sm_stat_res *resp) 1007c478bd9Sstevel@tonic-gate { 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate if (debug) 1037c478bd9Sstevel@tonic-gate (void) printf("proc sm_stat: mon_name = %s\n", 1047c478bd9Sstevel@tonic-gate namep->mon_name); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate resp->res_stat = stat_succ; 1077c478bd9Sstevel@tonic-gate resp->state = LOCAL_STATE; 1087c478bd9Sstevel@tonic-gate } 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1117c478bd9Sstevel@tonic-gate void 112bbaa8b60SDan Kruchinin sm_mon_svc(mon *monp, sm_stat_res *resp) 1137c478bd9Sstevel@tonic-gate { 1147c478bd9Sstevel@tonic-gate mon_id *monidp; 1157c478bd9Sstevel@tonic-gate monidp = &monp->mon_id; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate rw_rdlock(&thr_rwlock); 1187c478bd9Sstevel@tonic-gate if (debug) { 1197c478bd9Sstevel@tonic-gate (void) printf("proc sm_mon: mon_name = %s, id = %d\n", 1207c478bd9Sstevel@tonic-gate monidp->mon_name, *((int *)monp->priv)); 1217c478bd9Sstevel@tonic-gate pr_mon(monp->mon_id.mon_name); 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* only monitor other hosts */ 1257c478bd9Sstevel@tonic-gate if (self_check(monp->mon_id.mon_name) == 0) { 1267c478bd9Sstevel@tonic-gate /* store monitor request into monitor_q */ 1277c478bd9Sstevel@tonic-gate insert_mon(monp); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate pr_mon(monp->mon_id.mon_name); 1317c478bd9Sstevel@tonic-gate resp->res_stat = stat_succ; 1327c478bd9Sstevel@tonic-gate resp->state = local_state; 1337c478bd9Sstevel@tonic-gate rw_unlock(&thr_rwlock); 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1377c478bd9Sstevel@tonic-gate void 138bbaa8b60SDan Kruchinin sm_unmon_svc(mon_id *monidp, sm_stat *resp) 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate rw_rdlock(&thr_rwlock); 1417c478bd9Sstevel@tonic-gate if (debug) { 1427c478bd9Sstevel@tonic-gate (void) printf( 1437c478bd9Sstevel@tonic-gate "proc sm_unmon: mon_name = %s, [%s, %d, %d, %d]\n", 1447c478bd9Sstevel@tonic-gate monidp->mon_name, monidp->my_id.my_name, 1457c478bd9Sstevel@tonic-gate monidp->my_id.my_prog, monidp->my_id.my_vers, 1467c478bd9Sstevel@tonic-gate monidp->my_id.my_proc); 1477c478bd9Sstevel@tonic-gate pr_mon(monidp->mon_name); 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate delete_mon(monidp->mon_name, &monidp->my_id); 1517c478bd9Sstevel@tonic-gate pr_mon(monidp->mon_name); 1527c478bd9Sstevel@tonic-gate resp->state = local_state; 1537c478bd9Sstevel@tonic-gate rw_unlock(&thr_rwlock); 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1577c478bd9Sstevel@tonic-gate void 158bbaa8b60SDan Kruchinin sm_unmon_all_svc(my_id *myidp, sm_stat *resp) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate rw_rdlock(&thr_rwlock); 1617c478bd9Sstevel@tonic-gate if (debug) 1627c478bd9Sstevel@tonic-gate (void) printf("proc sm_unmon_all: [%s, %d, %d, %d]\n", 1637c478bd9Sstevel@tonic-gate myidp->my_name, 1647c478bd9Sstevel@tonic-gate myidp->my_prog, myidp->my_vers, 1657c478bd9Sstevel@tonic-gate myidp->my_proc); 166*98573c19SMarcel Telka delete_mon(NULL, myidp); 1677c478bd9Sstevel@tonic-gate pr_mon(NULL); 1687c478bd9Sstevel@tonic-gate resp->state = local_state; 1697c478bd9Sstevel@tonic-gate rw_unlock(&thr_rwlock); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate /* 1737c478bd9Sstevel@tonic-gate * Notifies lockd specified by name that state has changed for this server. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate void 176bbaa8b60SDan Kruchinin sm_notify_svc(stat_chge *ntfp) 1777c478bd9Sstevel@tonic-gate { 1787c478bd9Sstevel@tonic-gate rw_rdlock(&thr_rwlock); 1797c478bd9Sstevel@tonic-gate if (debug) 1807c478bd9Sstevel@tonic-gate (void) printf("sm_notify: %s state =%d\n", 1817c478bd9Sstevel@tonic-gate ntfp->mon_name, ntfp->state); 1827c478bd9Sstevel@tonic-gate send_notice(ntfp->mon_name, ntfp->state); 1837c478bd9Sstevel@tonic-gate rw_unlock(&thr_rwlock); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1877c478bd9Sstevel@tonic-gate void 188bbaa8b60SDan Kruchinin sm_simu_crash_svc(void *myidp) 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate int i; 1917c478bd9Sstevel@tonic-gate struct mon_entry *monitor_q; 1927c478bd9Sstevel@tonic-gate int found = 0; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (debug) 1957c478bd9Sstevel@tonic-gate (void) printf("proc sm_simu_crash\n"); 196*98573c19SMarcel Telka 197*98573c19SMarcel Telka /* Only one crash should be running at a time. */ 198*98573c19SMarcel Telka mutex_lock(&crash_lock); 199*98573c19SMarcel Telka if (in_crash != 0) { 2007c478bd9Sstevel@tonic-gate mutex_unlock(&crash_lock); 2017c478bd9Sstevel@tonic-gate return; 2027c478bd9Sstevel@tonic-gate } 203*98573c19SMarcel Telka in_crash = 1; 2047c478bd9Sstevel@tonic-gate mutex_unlock(&crash_lock); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_HASHSIZE; i++) { 2077c478bd9Sstevel@tonic-gate mutex_lock(&mon_table[i].lock); 2087c478bd9Sstevel@tonic-gate monitor_q = mon_table[i].sm_monhdp; 209*98573c19SMarcel Telka if (monitor_q != NULL) { 2107c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[i].lock); 2117c478bd9Sstevel@tonic-gate found = 1; 2127c478bd9Sstevel@tonic-gate break; 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[i].lock); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * If there are entries found in the monitor table, 2187c478bd9Sstevel@tonic-gate * initiate a crash, else zero out the in_crash variable. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate if (found) { 2217c478bd9Sstevel@tonic-gate mutex_lock(&crash_lock); 2227c478bd9Sstevel@tonic-gate die = 1; 223*98573c19SMarcel Telka /* Signal sm_try() thread if sleeping. */ 2247c478bd9Sstevel@tonic-gate cond_signal(&retrywait); 2257c478bd9Sstevel@tonic-gate mutex_unlock(&crash_lock); 2267c478bd9Sstevel@tonic-gate rw_wrlock(&thr_rwlock); 2277c478bd9Sstevel@tonic-gate sm_crash(); 2287c478bd9Sstevel@tonic-gate rw_unlock(&thr_rwlock); 2297c478bd9Sstevel@tonic-gate } else { 2307c478bd9Sstevel@tonic-gate mutex_lock(&crash_lock); 2317c478bd9Sstevel@tonic-gate in_crash = 0; 2327c478bd9Sstevel@tonic-gate mutex_unlock(&crash_lock); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2377c478bd9Sstevel@tonic-gate void 238*98573c19SMarcel Telka nsmaddrproc1_reg(reg1args *regargs, reg1res *regresp) 2397c478bd9Sstevel@tonic-gate { 2407c478bd9Sstevel@tonic-gate nsm_addr_res status; 2417c478bd9Sstevel@tonic-gate name_addr_entry_t *entry; 2427c478bd9Sstevel@tonic-gate char *tmp_n_bytes; 2437c478bd9Sstevel@tonic-gate addr_entry_t *addr; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate rw_rdlock(&thr_rwlock); 2467c478bd9Sstevel@tonic-gate if (debug) { 2477c478bd9Sstevel@tonic-gate int i; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate (void) printf("nap1_reg: fam= %d, name= %s, len= %d\n", 250*98573c19SMarcel Telka regargs->family, regargs->name, regargs->address.n_len); 2517c478bd9Sstevel@tonic-gate (void) printf("address is: "); 2527c478bd9Sstevel@tonic-gate for (i = 0; i < regargs->address.n_len; i++) { 2537c478bd9Sstevel@tonic-gate (void) printf("%d.", 2547c478bd9Sstevel@tonic-gate (unsigned char)regargs->address.n_bytes[i]); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate (void) printf("\n"); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate /* 2607c478bd9Sstevel@tonic-gate * Locate the entry with the name in the NSM_ADDR_REG request if 2617c478bd9Sstevel@tonic-gate * it exists. If it doesn't, create a new entry to hold this name. 2627c478bd9Sstevel@tonic-gate * The first time through this code, name_addr starts out as NULL. 2637c478bd9Sstevel@tonic-gate */ 2647c478bd9Sstevel@tonic-gate mutex_lock(&name_addrlock); 2657c478bd9Sstevel@tonic-gate for (entry = name_addr; entry; entry = entry->next) { 2667c478bd9Sstevel@tonic-gate if (strcmp(regargs->name, entry->name) == 0) { 2677c478bd9Sstevel@tonic-gate if (debug) { 2687c478bd9Sstevel@tonic-gate (void) printf("nap1_reg: matched name %s\n", 2697c478bd9Sstevel@tonic-gate entry->name); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate break; 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate if (entry == NULL) { 2767c478bd9Sstevel@tonic-gate entry = (name_addr_entry_t *)malloc(sizeof (*entry)); 2777c478bd9Sstevel@tonic-gate if (entry == NULL) { 2787c478bd9Sstevel@tonic-gate if (debug) { 2797c478bd9Sstevel@tonic-gate (void) printf( 2807c478bd9Sstevel@tonic-gate "nsmaddrproc1_reg: no memory for entry\n"); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate status = nsm_addr_fail; 2837c478bd9Sstevel@tonic-gate goto done; 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate entry->name = strdup(regargs->name); 2877c478bd9Sstevel@tonic-gate if (entry->name == NULL) { 2887c478bd9Sstevel@tonic-gate if (debug) { 2897c478bd9Sstevel@tonic-gate (void) printf( 2907c478bd9Sstevel@tonic-gate "nsmaddrproc1_reg: no memory for name\n"); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate free(entry); 2937c478bd9Sstevel@tonic-gate status = nsm_addr_fail; 2947c478bd9Sstevel@tonic-gate goto done; 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate entry->addresses = NULL; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * Link the new entry onto the *head* of the name_addr 3007c478bd9Sstevel@tonic-gate * table. 3017c478bd9Sstevel@tonic-gate * 3027c478bd9Sstevel@tonic-gate * Note: there is code below in the address maintenance 3037c478bd9Sstevel@tonic-gate * section that assumes this behavior. 3047c478bd9Sstevel@tonic-gate */ 3057c478bd9Sstevel@tonic-gate entry->next = name_addr; 3067c478bd9Sstevel@tonic-gate name_addr = entry; 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * Try to match the address in the request; if it doesn't match, 3117c478bd9Sstevel@tonic-gate * add it to the entry's address list. 3127c478bd9Sstevel@tonic-gate */ 3137c478bd9Sstevel@tonic-gate for (addr = entry->addresses; addr; addr = addr->next) { 3147c478bd9Sstevel@tonic-gate if (addr->family == (sa_family_t)regargs->family && 3157c478bd9Sstevel@tonic-gate addr->ah.n_len == regargs->address.n_len && 3167c478bd9Sstevel@tonic-gate memcmp(addr->ah.n_bytes, regargs->address.n_bytes, 3177c478bd9Sstevel@tonic-gate addr->ah.n_len) == 0) { 3187c478bd9Sstevel@tonic-gate if (debug) { 3197c478bd9Sstevel@tonic-gate int i; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate (void) printf("nap1_reg: matched addr "); 3227c478bd9Sstevel@tonic-gate for (i = 0; i < addr->ah.n_len; i++) { 3237c478bd9Sstevel@tonic-gate (void) printf("%d.", 3247c478bd9Sstevel@tonic-gate (unsigned char)addr->ah.n_bytes[i]); 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate (void) printf(" family %d for name %s\n", 327*98573c19SMarcel Telka addr->family, entry->name); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate break; 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate if (addr == NULL) { 3347c478bd9Sstevel@tonic-gate addr = (addr_entry_t *)malloc(sizeof (*addr)); 3357c478bd9Sstevel@tonic-gate tmp_n_bytes = (char *)malloc(regargs->address.n_len); 3367c478bd9Sstevel@tonic-gate if (addr == NULL || tmp_n_bytes == NULL) { 3377c478bd9Sstevel@tonic-gate if (debug) { 338*98573c19SMarcel Telka (void) printf("nap1_reg: no memory for addr\n"); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * If this name entry was just newly made in the 3437c478bd9Sstevel@tonic-gate * table, back it out now that we can't register 3447c478bd9Sstevel@tonic-gate * an address with it anyway. 3457c478bd9Sstevel@tonic-gate * 3467c478bd9Sstevel@tonic-gate * Note: we are making an assumption about how 3477c478bd9Sstevel@tonic-gate * names are added to (the head of) name_addr here. 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate if (entry == name_addr && entry->addresses == NULL) { 3507c478bd9Sstevel@tonic-gate name_addr = name_addr->next; 3517c478bd9Sstevel@tonic-gate free(entry->name); 3527c478bd9Sstevel@tonic-gate free(entry); 3537c478bd9Sstevel@tonic-gate if (tmp_n_bytes) 3547c478bd9Sstevel@tonic-gate free(tmp_n_bytes); 3557c478bd9Sstevel@tonic-gate if (addr) 3567c478bd9Sstevel@tonic-gate free(addr); 3577c478bd9Sstevel@tonic-gate status = nsm_addr_fail; 3587c478bd9Sstevel@tonic-gate goto done; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * Note: this check for address family assumes that we 3647c478bd9Sstevel@tonic-gate * will get something different here someday for 3657c478bd9Sstevel@tonic-gate * other supported address types, such as IPv6. 3667c478bd9Sstevel@tonic-gate */ 3677c478bd9Sstevel@tonic-gate addr->ah.n_len = regargs->address.n_len; 3687c478bd9Sstevel@tonic-gate addr->ah.n_bytes = tmp_n_bytes; 3697c478bd9Sstevel@tonic-gate addr->family = regargs->family; 3707c478bd9Sstevel@tonic-gate if (debug) { 371*98573c19SMarcel Telka if ((addr->family != AF_INET) && 3727c478bd9Sstevel@tonic-gate (addr->family != AF_INET6)) { 3737c478bd9Sstevel@tonic-gate (void) printf( 3747c478bd9Sstevel@tonic-gate "nap1_reg: unknown addr family %d\n", 3757c478bd9Sstevel@tonic-gate addr->family); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate (void) memcpy(addr->ah.n_bytes, regargs->address.n_bytes, 3797c478bd9Sstevel@tonic-gate addr->ah.n_len); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate addr->next = entry->addresses; 3827c478bd9Sstevel@tonic-gate entry->addresses = addr; 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate status = nsm_addr_succ; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate done: 3887c478bd9Sstevel@tonic-gate regresp->status = status; 3897c478bd9Sstevel@tonic-gate if (debug) { 3907c478bd9Sstevel@tonic-gate pr_name_addr(name_addr); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate mutex_unlock(&name_addrlock); 3937c478bd9Sstevel@tonic-gate rw_unlock(&thr_rwlock); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * Insert an entry into the monitor_q. Space for the entry is allocated 3987c478bd9Sstevel@tonic-gate * here. It is then filled in from the information passed in. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate static void 401*98573c19SMarcel Telka insert_mon(mon *monp) 4027c478bd9Sstevel@tonic-gate { 4037c478bd9Sstevel@tonic-gate mon_entry *new, *found; 4047c478bd9Sstevel@tonic-gate my_id *my_idp, *nl_idp; 4057c478bd9Sstevel@tonic-gate mon_entry *monitor_q; 4067c478bd9Sstevel@tonic-gate unsigned int hash; 4077c478bd9Sstevel@tonic-gate name_addr_entry_t *entry; 4087c478bd9Sstevel@tonic-gate addr_entry_t *addr; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* Allocate entry for new */ 4117c478bd9Sstevel@tonic-gate if ((new = (mon_entry *) malloc(sizeof (mon_entry))) == 0) { 4127c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 4137c478bd9Sstevel@tonic-gate "statd: insert_mon: malloc error on mon %s (id=%d)\n", 4147c478bd9Sstevel@tonic-gate monp->mon_id.mon_name, *((int *)monp->priv)); 4157c478bd9Sstevel@tonic-gate return; 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* Initialize and copy contents of monp to new */ 4197c478bd9Sstevel@tonic-gate (void) memset(new, 0, sizeof (mon_entry)); 4207c478bd9Sstevel@tonic-gate (void) memcpy(&new->id, monp, sizeof (mon)); 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* Allocate entry for new mon_name */ 4237c478bd9Sstevel@tonic-gate if ((new->id.mon_id.mon_name = strdup(monp->mon_id.mon_name)) == 0) { 4247c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 4257c478bd9Sstevel@tonic-gate "statd: insert_mon: malloc error on mon %s (id=%d)\n", 4267c478bd9Sstevel@tonic-gate monp->mon_id.mon_name, *((int *)monp->priv)); 4277c478bd9Sstevel@tonic-gate free(new); 4287c478bd9Sstevel@tonic-gate return; 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* Allocate entry for new my_name */ 4337c478bd9Sstevel@tonic-gate if ((new->id.mon_id.my_id.my_name = 4347c478bd9Sstevel@tonic-gate strdup(monp->mon_id.my_id.my_name)) == 0) { 4357c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 4367c478bd9Sstevel@tonic-gate "statd: insert_mon: malloc error on mon %s (id=%d)\n", 4377c478bd9Sstevel@tonic-gate monp->mon_id.mon_name, *((int *)monp->priv)); 4387c478bd9Sstevel@tonic-gate free(new->id.mon_id.mon_name); 4397c478bd9Sstevel@tonic-gate free(new); 4407c478bd9Sstevel@tonic-gate return; 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate if (debug) 4447c478bd9Sstevel@tonic-gate (void) printf("add_mon(%x) %s (id=%d)\n", 4457c478bd9Sstevel@tonic-gate (int)new, new->id.mon_id.mon_name, *((int *)new->id.priv)); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate /* 4487c478bd9Sstevel@tonic-gate * Record the name, and all addresses which have been registered 4497c478bd9Sstevel@tonic-gate * for this name, in the filesystem name space. 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate record_name(new->id.mon_id.mon_name, 1); 4527c478bd9Sstevel@tonic-gate if (regfiles_only == 0) { 4537c478bd9Sstevel@tonic-gate mutex_lock(&name_addrlock); 4547c478bd9Sstevel@tonic-gate for (entry = name_addr; entry; entry = entry->next) { 4557c478bd9Sstevel@tonic-gate if (strcmp(new->id.mon_id.mon_name, entry->name) != 0) { 4567c478bd9Sstevel@tonic-gate continue; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate for (addr = entry->addresses; addr; addr = addr->next) { 4607c478bd9Sstevel@tonic-gate record_addr(new->id.mon_id.mon_name, 4617c478bd9Sstevel@tonic-gate addr->family, &addr->ah); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate break; 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate mutex_unlock(&name_addrlock); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate SMHASH(new->id.mon_id.mon_name, hash); 4697c478bd9Sstevel@tonic-gate mutex_lock(&mon_table[hash].lock); 4707c478bd9Sstevel@tonic-gate monitor_q = mon_table[hash].sm_monhdp; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* If mon_table hash list is empty. */ 473*98573c19SMarcel Telka if (monitor_q == NULL) { 4747c478bd9Sstevel@tonic-gate if (debug) 4757c478bd9Sstevel@tonic-gate (void) printf("\nAdding to monitor_q hash %d\n", hash); 476*98573c19SMarcel Telka new->nxt = new->prev = NULL; 4777c478bd9Sstevel@tonic-gate mon_table[hash].sm_monhdp = new; 4787c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[hash].lock); 4797c478bd9Sstevel@tonic-gate return; 4807c478bd9Sstevel@tonic-gate } else { 4817c478bd9Sstevel@tonic-gate found = 0; 4827c478bd9Sstevel@tonic-gate my_idp = &new->id.mon_id.my_id; 483*98573c19SMarcel Telka while (monitor_q != NULL) { 4847c478bd9Sstevel@tonic-gate /* 4857c478bd9Sstevel@tonic-gate * This list is searched sequentially for the 4867c478bd9Sstevel@tonic-gate * tuple (hostname, prog, vers, proc). The tuples 4877c478bd9Sstevel@tonic-gate * are inserted in the beginning of the monitor_q, 4887c478bd9Sstevel@tonic-gate * if the hostname is not already present in the list. 4897c478bd9Sstevel@tonic-gate * If the hostname is found in the list, the incoming 4907c478bd9Sstevel@tonic-gate * tuple is inserted just after all the tuples with the 4917c478bd9Sstevel@tonic-gate * same hostname. However, if the tuple matches exactly 4927c478bd9Sstevel@tonic-gate * with an entry in the list, space allocated for the 4937c478bd9Sstevel@tonic-gate * new entry is released and nothing is inserted in the 4947c478bd9Sstevel@tonic-gate * list. 4957c478bd9Sstevel@tonic-gate */ 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate if (str_cmp_unqual_hostname( 4987c478bd9Sstevel@tonic-gate monitor_q->id.mon_id.mon_name, 4997c478bd9Sstevel@tonic-gate new->id.mon_id.mon_name) == 0) { 5007c478bd9Sstevel@tonic-gate /* found */ 5017c478bd9Sstevel@tonic-gate nl_idp = &monitor_q->id.mon_id.my_id; 5027c478bd9Sstevel@tonic-gate if ((str_cmp_unqual_hostname(my_idp->my_name, 5037c478bd9Sstevel@tonic-gate nl_idp->my_name) == 0) && 5047c478bd9Sstevel@tonic-gate my_idp->my_prog == nl_idp->my_prog && 5057c478bd9Sstevel@tonic-gate my_idp->my_vers == nl_idp->my_vers && 5067c478bd9Sstevel@tonic-gate my_idp->my_proc == nl_idp->my_proc) { 5077c478bd9Sstevel@tonic-gate /* 5087c478bd9Sstevel@tonic-gate * already exists an identical one, 5097c478bd9Sstevel@tonic-gate * release the space allocated for the 5107c478bd9Sstevel@tonic-gate * mon_entry 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate free(new->id.mon_id.mon_name); 5137c478bd9Sstevel@tonic-gate free(new->id.mon_id.my_id.my_name); 5147c478bd9Sstevel@tonic-gate free(new); 5157c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[hash].lock); 5167c478bd9Sstevel@tonic-gate return; 5177c478bd9Sstevel@tonic-gate } else { 5187c478bd9Sstevel@tonic-gate /* 5197c478bd9Sstevel@tonic-gate * mark the last callback that is 5207c478bd9Sstevel@tonic-gate * not matching; new is inserted 5217c478bd9Sstevel@tonic-gate * after this 5227c478bd9Sstevel@tonic-gate */ 5237c478bd9Sstevel@tonic-gate found = monitor_q; 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate } else if (found) 5267c478bd9Sstevel@tonic-gate break; 5277c478bd9Sstevel@tonic-gate monitor_q = monitor_q->nxt; 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate if (found) { 5307c478bd9Sstevel@tonic-gate /* 5317c478bd9Sstevel@tonic-gate * insert just after the entry having matching tuple. 5327c478bd9Sstevel@tonic-gate */ 5337c478bd9Sstevel@tonic-gate new->nxt = found->nxt; 5347c478bd9Sstevel@tonic-gate new->prev = found; 535*98573c19SMarcel Telka if (found->nxt != NULL) 5367c478bd9Sstevel@tonic-gate found->nxt->prev = new; 5377c478bd9Sstevel@tonic-gate found->nxt = new; 5387c478bd9Sstevel@tonic-gate } else { 5397c478bd9Sstevel@tonic-gate /* 5407c478bd9Sstevel@tonic-gate * not found, insert in front of list. 5417c478bd9Sstevel@tonic-gate */ 5427c478bd9Sstevel@tonic-gate new->nxt = mon_table[hash].sm_monhdp; 5437c478bd9Sstevel@tonic-gate new->prev = (mon_entry *) NULL; 5447c478bd9Sstevel@tonic-gate if (new->nxt != (mon_entry *) NULL) 5457c478bd9Sstevel@tonic-gate new->nxt->prev = new; 5467c478bd9Sstevel@tonic-gate mon_table[hash].sm_monhdp = new; 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[hash].lock); 5497c478bd9Sstevel@tonic-gate return; 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate /* 5547c478bd9Sstevel@tonic-gate * Deletes a specific monitor name or deletes all monitors with same id 5557c478bd9Sstevel@tonic-gate * in hash table. 5567c478bd9Sstevel@tonic-gate */ 5577c478bd9Sstevel@tonic-gate static void 558*98573c19SMarcel Telka delete_mon(char *mon_name, my_id *my_idp) 5597c478bd9Sstevel@tonic-gate { 5607c478bd9Sstevel@tonic-gate unsigned int hash; 5617c478bd9Sstevel@tonic-gate 562*98573c19SMarcel Telka if (mon_name != NULL) { 5637c478bd9Sstevel@tonic-gate record_name(mon_name, 0); 5647c478bd9Sstevel@tonic-gate SMHASH(mon_name, hash); 5657c478bd9Sstevel@tonic-gate mutex_lock(&mon_table[hash].lock); 5667c478bd9Sstevel@tonic-gate delete_onemon(mon_name, my_idp, &mon_table[hash].sm_monhdp); 5677c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[hash].lock); 5687c478bd9Sstevel@tonic-gate } else { 5697c478bd9Sstevel@tonic-gate for (hash = 0; hash < MAX_HASHSIZE; hash++) { 5707c478bd9Sstevel@tonic-gate mutex_lock(&mon_table[hash].lock); 5717c478bd9Sstevel@tonic-gate delete_onemon(mon_name, my_idp, 5727c478bd9Sstevel@tonic-gate &mon_table[hash].sm_monhdp); 5737c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[hash].lock); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* 5797c478bd9Sstevel@tonic-gate * Deletes a monitor in list. 5807c478bd9Sstevel@tonic-gate * IF mon_name is NULL, delete all mon_names that have the same id, 5817c478bd9Sstevel@tonic-gate * else delete specific monitor. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate void 584*98573c19SMarcel Telka delete_onemon(char *mon_name, my_id *my_idp, mon_entry **monitor_q) 5857c478bd9Sstevel@tonic-gate { 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate mon_entry *next, *nl; 5887c478bd9Sstevel@tonic-gate my_id *nl_idp; 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate next = *monitor_q; 591*98573c19SMarcel Telka while ((nl = next) != NULL) { 5927c478bd9Sstevel@tonic-gate next = next->nxt; 593*98573c19SMarcel Telka if (mon_name == NULL || (mon_name != NULL && 5947c478bd9Sstevel@tonic-gate str_cmp_unqual_hostname(nl->id.mon_id.mon_name, 5957c478bd9Sstevel@tonic-gate mon_name) == 0)) { 5967c478bd9Sstevel@tonic-gate nl_idp = &nl->id.mon_id.my_id; 5977c478bd9Sstevel@tonic-gate if ((str_cmp_unqual_hostname(my_idp->my_name, 5987c478bd9Sstevel@tonic-gate nl_idp->my_name) == 0) && 5997c478bd9Sstevel@tonic-gate my_idp->my_prog == nl_idp->my_prog && 6007c478bd9Sstevel@tonic-gate my_idp->my_vers == nl_idp->my_vers && 6017c478bd9Sstevel@tonic-gate my_idp->my_proc == nl_idp->my_proc) { 6027c478bd9Sstevel@tonic-gate /* found */ 6037c478bd9Sstevel@tonic-gate if (debug) 6047c478bd9Sstevel@tonic-gate (void) printf("delete_mon(%x): %s\n", 6057c478bd9Sstevel@tonic-gate (int)nl, mon_name ? 6067c478bd9Sstevel@tonic-gate mon_name : "<NULL>"); 6077c478bd9Sstevel@tonic-gate /* 6087c478bd9Sstevel@tonic-gate * Remove the monitor name from the 6097c478bd9Sstevel@tonic-gate * record_q, if id matches. 6107c478bd9Sstevel@tonic-gate */ 6117c478bd9Sstevel@tonic-gate record_name(nl->id.mon_id.mon_name, 0); 6127c478bd9Sstevel@tonic-gate /* if nl is not the first entry on list */ 613*98573c19SMarcel Telka if (nl->prev != NULL) 6147c478bd9Sstevel@tonic-gate nl->prev->nxt = nl->nxt; 6157c478bd9Sstevel@tonic-gate else { 6167c478bd9Sstevel@tonic-gate *monitor_q = nl->nxt; 6177c478bd9Sstevel@tonic-gate } 618*98573c19SMarcel Telka if (nl->nxt != NULL) 6197c478bd9Sstevel@tonic-gate nl->nxt->prev = nl->prev; 6207c478bd9Sstevel@tonic-gate free(nl->id.mon_id.mon_name); 6217c478bd9Sstevel@tonic-gate free(nl_idp->my_name); 6227c478bd9Sstevel@tonic-gate free(nl); 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate } /* end of if mon */ 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate /* 6297c478bd9Sstevel@tonic-gate * Notify lockd of host specified by mon_name that the specified state 6307c478bd9Sstevel@tonic-gate * has changed. 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate static void 633*98573c19SMarcel Telka send_notice(char *mon_name, int state) 6347c478bd9Sstevel@tonic-gate { 6357c478bd9Sstevel@tonic-gate struct mon_entry *next; 6367c478bd9Sstevel@tonic-gate mon_entry *monitor_q; 6377c478bd9Sstevel@tonic-gate unsigned int hash; 6387c478bd9Sstevel@tonic-gate moninfo_t *minfop; 6397c478bd9Sstevel@tonic-gate mon *monp; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate SMHASH(mon_name, hash); 6427c478bd9Sstevel@tonic-gate mutex_lock(&mon_table[hash].lock); 6437c478bd9Sstevel@tonic-gate monitor_q = mon_table[hash].sm_monhdp; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate next = monitor_q; 646*98573c19SMarcel Telka while (next != NULL) { 6477c478bd9Sstevel@tonic-gate if (hostname_eq(next->id.mon_id.mon_name, mon_name)) { 6487c478bd9Sstevel@tonic-gate monp = &next->id; 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * Prepare the minfop structure to pass to 6517c478bd9Sstevel@tonic-gate * thr_create(). This structure is a copy of 6527c478bd9Sstevel@tonic-gate * mon info and state. 6537c478bd9Sstevel@tonic-gate */ 6547c478bd9Sstevel@tonic-gate if ((minfop = 655*98573c19SMarcel Telka (moninfo_t *)xmalloc(sizeof (moninfo_t))) != NULL) { 6567c478bd9Sstevel@tonic-gate (void) memcpy(&minfop->id, monp, sizeof (mon)); 6577c478bd9Sstevel@tonic-gate /* Allocate entry for mon_name */ 6587c478bd9Sstevel@tonic-gate if ((minfop->id.mon_id.mon_name = 6597c478bd9Sstevel@tonic-gate strdup(monp->mon_id.mon_name)) == 0) { 660*98573c19SMarcel Telka syslog(LOG_ERR, "statd: send_notice: " 661*98573c19SMarcel Telka "malloc error on mon %s (id=%d)\n", 6627c478bd9Sstevel@tonic-gate monp->mon_id.mon_name, 6637c478bd9Sstevel@tonic-gate *((int *)monp->priv)); 6647c478bd9Sstevel@tonic-gate free(minfop); 6657c478bd9Sstevel@tonic-gate continue; 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate /* Allocate entry for my_name */ 6687c478bd9Sstevel@tonic-gate if ((minfop->id.mon_id.my_id.my_name = 6697c478bd9Sstevel@tonic-gate strdup(monp->mon_id.my_id.my_name)) == 0) { 670*98573c19SMarcel Telka syslog(LOG_ERR, "statd: send_notice: " 671*98573c19SMarcel Telka "malloc error on mon %s (id=%d)\n", 6727c478bd9Sstevel@tonic-gate monp->mon_id.mon_name, 6737c478bd9Sstevel@tonic-gate *((int *)monp->priv)); 6747c478bd9Sstevel@tonic-gate free(minfop->id.mon_id.mon_name); 6757c478bd9Sstevel@tonic-gate free(minfop); 6767c478bd9Sstevel@tonic-gate continue; 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate minfop->state = state; 6797c478bd9Sstevel@tonic-gate /* 6807c478bd9Sstevel@tonic-gate * Create detached threads to process each host 6817c478bd9Sstevel@tonic-gate * to notify. If error, print out msg, free 6827c478bd9Sstevel@tonic-gate * resources and continue. 6837c478bd9Sstevel@tonic-gate */ 6847c478bd9Sstevel@tonic-gate if (thr_create(NULL, NULL, thr_send_notice, 685*98573c19SMarcel Telka minfop, THR_DETACHED, NULL)) { 686*98573c19SMarcel Telka syslog(LOG_ERR, "statd: unable to " 687*98573c19SMarcel Telka "create thread to send_notice to " 688*98573c19SMarcel Telka "%s.\n", mon_name); 6897c478bd9Sstevel@tonic-gate free(minfop->id.mon_id.mon_name); 6907c478bd9Sstevel@tonic-gate free(minfop->id.mon_id.my_id.my_name); 6917c478bd9Sstevel@tonic-gate free(minfop); 6927c478bd9Sstevel@tonic-gate continue; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate next = next->nxt; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[hash].lock); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * Work thread created to do the actual statd_call_lockd 7037c478bd9Sstevel@tonic-gate */ 7047c478bd9Sstevel@tonic-gate static void * 7057c478bd9Sstevel@tonic-gate thr_send_notice(void *arg) 7067c478bd9Sstevel@tonic-gate { 7077c478bd9Sstevel@tonic-gate moninfo_t *minfop; 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate minfop = (moninfo_t *)arg; 7107c478bd9Sstevel@tonic-gate if (statd_call_lockd(&minfop->id, minfop->state) == -1) { 7117c478bd9Sstevel@tonic-gate if (debug && minfop->id.mon_id.mon_name) 712b17f03d7SMarcel Telka (void) printf("problem with notifying %s failure, " 713b17f03d7SMarcel Telka "give up\n", minfop->id.mon_id.mon_name); 7147c478bd9Sstevel@tonic-gate } else { 7157c478bd9Sstevel@tonic-gate if (debug) 716b17f03d7SMarcel Telka (void) printf("send_notice: %s, %d notified.\n", 7177c478bd9Sstevel@tonic-gate minfop->id.mon_id.mon_name, minfop->state); 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate free(minfop->id.mon_id.mon_name); 7217c478bd9Sstevel@tonic-gate free(minfop->id.mon_id.my_id.my_name); 7227c478bd9Sstevel@tonic-gate free(minfop); 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate thr_exit((void *) 0); 7257c478bd9Sstevel@tonic-gate #ifdef lint 7267c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 7277c478bd9Sstevel@tonic-gate return ((void *)0); 7287c478bd9Sstevel@tonic-gate #endif 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate /* 7327c478bd9Sstevel@tonic-gate * Contact lockd specified by monp. 7337c478bd9Sstevel@tonic-gate */ 7347c478bd9Sstevel@tonic-gate static int 735*98573c19SMarcel Telka statd_call_lockd(mon *monp, int state) 7367c478bd9Sstevel@tonic-gate { 7377c478bd9Sstevel@tonic-gate enum clnt_stat clnt_stat; 7387c478bd9Sstevel@tonic-gate struct timeval tottimeout; 739bbaa8b60SDan Kruchinin struct sm_status stat; 7407c478bd9Sstevel@tonic-gate my_id *my_idp; 7417c478bd9Sstevel@tonic-gate char *mon_name; 7427c478bd9Sstevel@tonic-gate int i; 7437c478bd9Sstevel@tonic-gate int rc = 0; 7447c478bd9Sstevel@tonic-gate CLIENT *clnt; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate mon_name = monp->mon_id.mon_name; 7477c478bd9Sstevel@tonic-gate my_idp = &monp->mon_id.my_id; 748bbaa8b60SDan Kruchinin (void) memset(&stat, 0, sizeof (stat)); 7497c478bd9Sstevel@tonic-gate stat.mon_name = mon_name; 7507c478bd9Sstevel@tonic-gate stat.state = state; 7517c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) { 7527c478bd9Sstevel@tonic-gate stat.priv[i] = monp->priv[i]; 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate if (debug) 7557c478bd9Sstevel@tonic-gate (void) printf("statd_call_lockd: %s state = %d\n", 7567c478bd9Sstevel@tonic-gate stat.mon_name, stat.state); 7577c478bd9Sstevel@tonic-gate 758a6f0fae9Sgt29601 tottimeout.tv_sec = SM_RPC_TIMEOUT; 759a6f0fae9Sgt29601 tottimeout.tv_usec = 0; 760a6f0fae9Sgt29601 761bbaa8b60SDan Kruchinin clnt = create_client(my_idp->my_name, my_idp->my_prog, my_idp->my_vers, 762bbaa8b60SDan Kruchinin "ticotsord", &tottimeout); 763bbaa8b60SDan Kruchinin if (clnt == NULL) { 7647c478bd9Sstevel@tonic-gate return (-1); 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 767*98573c19SMarcel Telka clnt_stat = clnt_call(clnt, my_idp->my_proc, xdr_sm_status, 768*98573c19SMarcel Telka (char *)&stat, xdr_void, NULL, tottimeout); 7697c478bd9Sstevel@tonic-gate if (debug) { 7707c478bd9Sstevel@tonic-gate (void) printf("clnt_stat=%s(%d)\n", 7717c478bd9Sstevel@tonic-gate clnt_sperrno(clnt_stat), clnt_stat); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate if (clnt_stat != (int)RPC_SUCCESS) { 7747c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, 7757c478bd9Sstevel@tonic-gate "statd: cannot talk to lockd at %s, %s(%d)\n", 7767c478bd9Sstevel@tonic-gate my_idp->my_name, clnt_sperrno(clnt_stat), clnt_stat); 7777c478bd9Sstevel@tonic-gate rc = -1; 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate clnt_destroy(clnt); 7817c478bd9Sstevel@tonic-gate return (rc); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* 7867c478bd9Sstevel@tonic-gate * Client handle created. 7877c478bd9Sstevel@tonic-gate */ 7887c478bd9Sstevel@tonic-gate CLIENT * 789bbaa8b60SDan Kruchinin create_client(char *host, int prognum, int versnum, char *netid, 790bbaa8b60SDan Kruchinin struct timeval *utimeout) 7917c478bd9Sstevel@tonic-gate { 7927c478bd9Sstevel@tonic-gate int fd; 7937c478bd9Sstevel@tonic-gate struct timeval timeout; 7947c478bd9Sstevel@tonic-gate CLIENT *client; 7957c478bd9Sstevel@tonic-gate struct t_info tinfo; 7967c478bd9Sstevel@tonic-gate 797bbaa8b60SDan Kruchinin if (netid == NULL) { 798bbaa8b60SDan Kruchinin client = clnt_create_timed(host, prognum, versnum, 799bbaa8b60SDan Kruchinin "netpath", utimeout); 800bbaa8b60SDan Kruchinin } else { 801bbaa8b60SDan Kruchinin struct netconfig *nconf; 802bbaa8b60SDan Kruchinin 803bbaa8b60SDan Kruchinin nconf = getnetconfigent(netid); 804bbaa8b60SDan Kruchinin if (nconf == NULL) { 8057c478bd9Sstevel@tonic-gate return (NULL); 8067c478bd9Sstevel@tonic-gate } 807bbaa8b60SDan Kruchinin 808bbaa8b60SDan Kruchinin client = clnt_tp_create_timed(host, prognum, versnum, nconf, 809bbaa8b60SDan Kruchinin utimeout); 810bbaa8b60SDan Kruchinin 811bbaa8b60SDan Kruchinin freenetconfigent(nconf); 812bbaa8b60SDan Kruchinin } 813bbaa8b60SDan Kruchinin 814bbaa8b60SDan Kruchinin if (client == NULL) { 815bbaa8b60SDan Kruchinin return (NULL); 816bbaa8b60SDan Kruchinin } 817bbaa8b60SDan Kruchinin 8187c478bd9Sstevel@tonic-gate (void) CLNT_CONTROL(client, CLGET_FD, (caddr_t)&fd); 8197c478bd9Sstevel@tonic-gate if (t_getinfo(fd, &tinfo) != -1) { 8207c478bd9Sstevel@tonic-gate if (tinfo.servtype == T_CLTS) { 8217c478bd9Sstevel@tonic-gate /* 8227c478bd9Sstevel@tonic-gate * Set time outs for connectionless case 8237c478bd9Sstevel@tonic-gate */ 8247c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 8257c478bd9Sstevel@tonic-gate timeout.tv_sec = SM_CLTS_TIMEOUT; 8267c478bd9Sstevel@tonic-gate (void) CLNT_CONTROL(client, 8277c478bd9Sstevel@tonic-gate CLSET_RETRY_TIMEOUT, (caddr_t)&timeout); 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate } else 8307c478bd9Sstevel@tonic-gate return (NULL); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate return (client); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate /* 8367c478bd9Sstevel@tonic-gate * ONLY for debugging. 8377c478bd9Sstevel@tonic-gate * Debug messages which prints out the monitor table information. 8387c478bd9Sstevel@tonic-gate * If name is specified, just print out the hash list corresponding 8397c478bd9Sstevel@tonic-gate * to name, otherwise print out the entire monitor table. 8407c478bd9Sstevel@tonic-gate */ 8417c478bd9Sstevel@tonic-gate static void 842*98573c19SMarcel Telka pr_mon(char *name) 8437c478bd9Sstevel@tonic-gate { 8447c478bd9Sstevel@tonic-gate mon_entry *nl; 8457c478bd9Sstevel@tonic-gate int hash; 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate if (!debug) 8487c478bd9Sstevel@tonic-gate return; 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate /* print all */ 8517c478bd9Sstevel@tonic-gate if (name == NULL) { 8527c478bd9Sstevel@tonic-gate for (hash = 0; hash < MAX_HASHSIZE; hash++) { 8537c478bd9Sstevel@tonic-gate mutex_lock(&mon_table[hash].lock); 8547c478bd9Sstevel@tonic-gate nl = mon_table[hash].sm_monhdp; 855*98573c19SMarcel Telka if (nl == NULL) { 8567c478bd9Sstevel@tonic-gate (void) printf( 857*98573c19SMarcel Telka "*****monitor_q = NULL hash %d\n", hash); 8587c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[hash].lock); 8597c478bd9Sstevel@tonic-gate continue; 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate (void) printf("*****monitor_q:\n "); 862*98573c19SMarcel Telka while (nl != NULL) { 8637c478bd9Sstevel@tonic-gate (void) printf("%s:(%x), ", 8647c478bd9Sstevel@tonic-gate nl->id.mon_id.mon_name, (int)nl); 8657c478bd9Sstevel@tonic-gate nl = nl->nxt; 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[hash].lock); 8687c478bd9Sstevel@tonic-gate (void) printf("\n"); 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate } else { /* print one hash list */ 8717c478bd9Sstevel@tonic-gate SMHASH(name, hash); 8727c478bd9Sstevel@tonic-gate mutex_lock(&mon_table[hash].lock); 8737c478bd9Sstevel@tonic-gate nl = mon_table[hash].sm_monhdp; 874*98573c19SMarcel Telka if (nl == NULL) { 8757c478bd9Sstevel@tonic-gate (void) printf("*****monitor_q = NULL hash %d\n", hash); 8767c478bd9Sstevel@tonic-gate } else { 8777c478bd9Sstevel@tonic-gate (void) printf("*****monitor_q:\n "); 878*98573c19SMarcel Telka while (nl != NULL) { 8797c478bd9Sstevel@tonic-gate (void) printf("%s:(%x), ", 8807c478bd9Sstevel@tonic-gate nl->id.mon_id.mon_name, (int)nl); 8817c478bd9Sstevel@tonic-gate nl = nl->nxt; 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate (void) printf("\n"); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate mutex_unlock(&mon_table[hash].lock); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate /* 8907c478bd9Sstevel@tonic-gate * Only for debugging. 8917c478bd9Sstevel@tonic-gate * Dump the host name-to-address translation table passed in `name_addr'. 8927c478bd9Sstevel@tonic-gate */ 8937c478bd9Sstevel@tonic-gate static void 8947c478bd9Sstevel@tonic-gate pr_name_addr(name_addr_entry_t *name_addr) 8957c478bd9Sstevel@tonic-gate { 8967c478bd9Sstevel@tonic-gate name_addr_entry_t *entry; 8977c478bd9Sstevel@tonic-gate addr_entry_t *addr; 8987c478bd9Sstevel@tonic-gate struct in_addr ipv4_addr; 8997c478bd9Sstevel@tonic-gate char *ipv6_addr; 9007c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&name_addrlock)); 9037c478bd9Sstevel@tonic-gate (void) printf("name-to-address translation table:\n"); 9047c478bd9Sstevel@tonic-gate for (entry = name_addr; entry != NULL; entry = entry->next) { 9057c478bd9Sstevel@tonic-gate (void) printf("\t%s: ", 9067c478bd9Sstevel@tonic-gate (entry->name ? entry->name : "(null)")); 9077c478bd9Sstevel@tonic-gate for (addr = entry->addresses; addr; addr = addr->next) { 9087c478bd9Sstevel@tonic-gate switch (addr->family) { 9097c478bd9Sstevel@tonic-gate case AF_INET: 910b17f03d7SMarcel Telka ipv4_addr = *(struct in_addr *)addr->ah.n_bytes; 9117c478bd9Sstevel@tonic-gate (void) printf(" %s (fam %d)", 912b17f03d7SMarcel Telka inet_ntoa(ipv4_addr), addr->family); 9137c478bd9Sstevel@tonic-gate break; 9147c478bd9Sstevel@tonic-gate case AF_INET6: 9157c478bd9Sstevel@tonic-gate ipv6_addr = (char *)addr->ah.n_bytes; 9167c478bd9Sstevel@tonic-gate (void) printf(" %s (fam %d)", 917b17f03d7SMarcel Telka inet_ntop(addr->family, ipv6_addr, abuf, 918b17f03d7SMarcel Telka sizeof (abuf)), addr->family); 9197c478bd9Sstevel@tonic-gate break; 9207c478bd9Sstevel@tonic-gate default: 9217c478bd9Sstevel@tonic-gate return; 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate printf("\n"); 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate /* 929b17f03d7SMarcel Telka * First, try to compare the hostnames as strings. If the hostnames does not 930b17f03d7SMarcel Telka * match we might deal with the hostname aliases. In this case two different 931b17f03d7SMarcel Telka * aliases for the same machine don't match each other when using strcmp. To 932b17f03d7SMarcel Telka * deal with this, the hostnames must be translated into some sort of universal 933b17f03d7SMarcel Telka * identifier. These identifiers can be compared. Universal network addresses 934b17f03d7SMarcel Telka * are currently used for this identifier because it is general and easy to do. 935b17f03d7SMarcel Telka * Other schemes are possible and this routine could be converted if required. 9367c478bd9Sstevel@tonic-gate * 9377c478bd9Sstevel@tonic-gate * If it can't find an address for some reason, 0 is returned. 9387c478bd9Sstevel@tonic-gate */ 9397c478bd9Sstevel@tonic-gate static int 9407c478bd9Sstevel@tonic-gate hostname_eq(char *host1, char *host2) 9417c478bd9Sstevel@tonic-gate { 9427c478bd9Sstevel@tonic-gate char *sysid1; 9437c478bd9Sstevel@tonic-gate char *sysid2; 9447c478bd9Sstevel@tonic-gate int rv; 9457c478bd9Sstevel@tonic-gate 946b17f03d7SMarcel Telka /* Compare hostnames as strings */ 947b17f03d7SMarcel Telka if (host1 != NULL && host2 != NULL && strcmp(host1, host2) == 0) 948b17f03d7SMarcel Telka return (1); 949b17f03d7SMarcel Telka 950b17f03d7SMarcel Telka /* Try harder if hostnames do not match */ 9517c478bd9Sstevel@tonic-gate sysid1 = get_system_id(host1); 9527c478bd9Sstevel@tonic-gate sysid2 = get_system_id(host2); 9537c478bd9Sstevel@tonic-gate if ((sysid1 == NULL) || (sysid2 == NULL)) 9547c478bd9Sstevel@tonic-gate rv = 0; 9557c478bd9Sstevel@tonic-gate else 9567c478bd9Sstevel@tonic-gate rv = (strcmp(sysid1, sysid2) == 0); 9577c478bd9Sstevel@tonic-gate free(sysid1); 9587c478bd9Sstevel@tonic-gate free(sysid2); 9597c478bd9Sstevel@tonic-gate return (rv); 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate /* 9637c478bd9Sstevel@tonic-gate * Convert a hostname character string into its network address. 9647c478bd9Sstevel@tonic-gate * A network address is found by searching through all the entries 9657c478bd9Sstevel@tonic-gate * in /etc/netconfig and doing a netdir_getbyname() for each inet 9667c478bd9Sstevel@tonic-gate * entry found. The netbuf structure returned is converted into 9677c478bd9Sstevel@tonic-gate * a universal address format. 9687c478bd9Sstevel@tonic-gate * 9697c478bd9Sstevel@tonic-gate * If a NULL hostname is given, then the name of the current host 9707c478bd9Sstevel@tonic-gate * is used. If the hostname doesn't map to an address, a NULL 9717c478bd9Sstevel@tonic-gate * pointer is returned. 9727c478bd9Sstevel@tonic-gate * 9737c478bd9Sstevel@tonic-gate * N.B. the character string returned is allocated in taddr2uaddr() 9747c478bd9Sstevel@tonic-gate * and should be freed by the caller using free(). 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate static char * 9777c478bd9Sstevel@tonic-gate get_system_id(char *hostname) 9787c478bd9Sstevel@tonic-gate { 9797c478bd9Sstevel@tonic-gate void *hp; 9807c478bd9Sstevel@tonic-gate struct netconfig *ncp; 9817c478bd9Sstevel@tonic-gate struct nd_hostserv service; 9827c478bd9Sstevel@tonic-gate struct nd_addrlist *addrs; 9837c478bd9Sstevel@tonic-gate char *uaddr; 9847c478bd9Sstevel@tonic-gate int rv; 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate if (hostname == NULL) 9877c478bd9Sstevel@tonic-gate service.h_host = HOST_SELF; 9887c478bd9Sstevel@tonic-gate else 9897c478bd9Sstevel@tonic-gate service.h_host = hostname; 9907c478bd9Sstevel@tonic-gate service.h_serv = NULL; 9917c478bd9Sstevel@tonic-gate hp = setnetconfig(); 9927c478bd9Sstevel@tonic-gate if (hp == (void *) NULL) { 9937c478bd9Sstevel@tonic-gate return (NULL); 9947c478bd9Sstevel@tonic-gate } 995*98573c19SMarcel Telka while ((ncp = getnetconfig(hp)) != NULL) { 9967c478bd9Sstevel@tonic-gate if ((strcmp(ncp->nc_protofmly, NC_INET) == 0) || 9977c478bd9Sstevel@tonic-gate (strcmp(ncp->nc_protofmly, NC_INET6) == 0)) { 9987c478bd9Sstevel@tonic-gate addrs = NULL; 9997c478bd9Sstevel@tonic-gate rv = netdir_getbyname(ncp, &service, &addrs); 10007c478bd9Sstevel@tonic-gate if (rv != 0) { 10017c478bd9Sstevel@tonic-gate continue; 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate if (addrs) { 10047c478bd9Sstevel@tonic-gate uaddr = taddr2uaddr(ncp, addrs->n_addrs); 10057c478bd9Sstevel@tonic-gate netdir_free(addrs, ND_ADDRLIST); 10067c478bd9Sstevel@tonic-gate endnetconfig(hp); 10077c478bd9Sstevel@tonic-gate return (uaddr); 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate else 10117c478bd9Sstevel@tonic-gate continue; 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate endnetconfig(hp); 10147c478bd9Sstevel@tonic-gate return (NULL); 10157c478bd9Sstevel@tonic-gate } 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate void 10187c478bd9Sstevel@tonic-gate merge_hosts(void) 10197c478bd9Sstevel@tonic-gate { 10207c478bd9Sstevel@tonic-gate struct lifconf *lifc = NULL; 10217c478bd9Sstevel@tonic-gate int sock = -1; 10227c478bd9Sstevel@tonic-gate struct lifreq *lifrp; 10237c478bd9Sstevel@tonic-gate struct lifreq lifr; 10247c478bd9Sstevel@tonic-gate int n; 10257c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 10267c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 10277c478bd9Sstevel@tonic-gate struct sockaddr_storage *sa; 10287c478bd9Sstevel@tonic-gate int af; 10297c478bd9Sstevel@tonic-gate struct hostent *phost; 10307c478bd9Sstevel@tonic-gate char *addr; 10317c478bd9Sstevel@tonic-gate size_t alen; 10327c478bd9Sstevel@tonic-gate int errnum; 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate /* 10357c478bd9Sstevel@tonic-gate * This function will enumerate all the interfaces for 10367c478bd9Sstevel@tonic-gate * this platform, then get the hostent for each i/f. 10377c478bd9Sstevel@tonic-gate * With the hostent structure, we can get all of the 10387c478bd9Sstevel@tonic-gate * aliases for the i/f. Then we'll merge all the aliases 10397c478bd9Sstevel@tonic-gate * with the existing host_name[] list to come up with 10407c478bd9Sstevel@tonic-gate * all of the known names for each interface. This solves 10417c478bd9Sstevel@tonic-gate * the problem of a multi-homed host not knowing which 10427c478bd9Sstevel@tonic-gate * name to publish when statd is started. All the aliases 10437c478bd9Sstevel@tonic-gate * will be stored in the array, host_name. 10447c478bd9Sstevel@tonic-gate * 10457c478bd9Sstevel@tonic-gate * NOTE: Even though we will use all of the aliases we 10467c478bd9Sstevel@tonic-gate * can get from the i/f hostent, the receiving statd 10477c478bd9Sstevel@tonic-gate * will still need to handle aliases with hostname_eq. 10487c478bd9Sstevel@tonic-gate * This is because the sender's aliases may not match 10497c478bd9Sstevel@tonic-gate * those of the receiver. 10507c478bd9Sstevel@tonic-gate */ 10517c478bd9Sstevel@tonic-gate lifc = getmyaddrs(); 1052*98573c19SMarcel Telka if (lifc == NULL) { 10537c478bd9Sstevel@tonic-gate goto finish; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate lifrp = lifc->lifc_req; 10567c478bd9Sstevel@tonic-gate for (n = lifc->lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) { 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, lifrp->lifr_name, 10597c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate af = lifrp->lifr_addr.ss_family; 10627c478bd9Sstevel@tonic-gate sock = socket(af, SOCK_DGRAM, 0); 10637c478bd9Sstevel@tonic-gate if (sock == -1) { 10647c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "statd: socket failed\n"); 10657c478bd9Sstevel@tonic-gate goto finish; 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate /* If it's the loopback interface, ignore */ 10697c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 10707c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 10717c478bd9Sstevel@tonic-gate "statd: SIOCGLIFFLAGS failed, error: %m\n"); 10727c478bd9Sstevel@tonic-gate goto finish; 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate if (lifr.lifr_flags & IFF_LOOPBACK) 10757c478bd9Sstevel@tonic-gate continue; 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 10787c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 10797c478bd9Sstevel@tonic-gate "statd: SIOCGLIFADDR failed, error: %m\n"); 10807c478bd9Sstevel@tonic-gate goto finish; 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate sa = (struct sockaddr_storage *)&(lifr.lifr_addr); 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate if (sa->ss_family == AF_INET) { 10857c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&lifr.lifr_addr; 10867c478bd9Sstevel@tonic-gate addr = (char *)(&sin->sin_addr); 10877c478bd9Sstevel@tonic-gate alen = sizeof (struct in_addr); 10887c478bd9Sstevel@tonic-gate } else if (sa->ss_family == AF_INET6) { 10897c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 10907c478bd9Sstevel@tonic-gate addr = (char *)(&sin6->sin6_addr); 10917c478bd9Sstevel@tonic-gate alen = sizeof (struct in6_addr); 10927c478bd9Sstevel@tonic-gate } else { 10937c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, 10947c478bd9Sstevel@tonic-gate "unexpected address family (%d)", 10957c478bd9Sstevel@tonic-gate sa->ss_family); 10967c478bd9Sstevel@tonic-gate continue; 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate phost = getipnodebyaddr(addr, alen, sa->ss_family, &errnum); 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate if (phost) 11027c478bd9Sstevel@tonic-gate add_aliases(phost); 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate /* 11057c478bd9Sstevel@tonic-gate * Now, just in case we didn't get them all byaddr, 11067c478bd9Sstevel@tonic-gate * let's look by name. 11077c478bd9Sstevel@tonic-gate */ 11087c478bd9Sstevel@tonic-gate phost = getipnodebyname(hostname, AF_INET6, AI_ALL, &errnum); 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate if (phost) 11117c478bd9Sstevel@tonic-gate add_aliases(phost); 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate finish: 11147c478bd9Sstevel@tonic-gate if (sock != -1) 11157c478bd9Sstevel@tonic-gate (void) close(sock); 11167c478bd9Sstevel@tonic-gate if (lifc) { 11177c478bd9Sstevel@tonic-gate free(lifc->lifc_buf); 11187c478bd9Sstevel@tonic-gate free(lifc); 11197c478bd9Sstevel@tonic-gate } 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate /* 11237c478bd9Sstevel@tonic-gate * add_aliases traverses a hostent alias list, compares 11247c478bd9Sstevel@tonic-gate * the aliases to the contents of host_name, and if an 11257c478bd9Sstevel@tonic-gate * alias is not already present, adds it to host_name[]. 11267c478bd9Sstevel@tonic-gate */ 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate static void 11297c478bd9Sstevel@tonic-gate add_aliases(struct hostent *phost) 11307c478bd9Sstevel@tonic-gate { 11317c478bd9Sstevel@tonic-gate char **aliases; 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate if (!in_host_array(phost->h_name)) { 11347c478bd9Sstevel@tonic-gate add_to_host_array(phost->h_name); 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate if (phost->h_aliases == NULL) 11387c478bd9Sstevel@tonic-gate return; /* no aliases to register */ 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate for (aliases = phost->h_aliases; *aliases != NULL; aliases++) { 11417c478bd9Sstevel@tonic-gate if (!in_host_array(*aliases)) { 11427c478bd9Sstevel@tonic-gate add_to_host_array(*aliases); 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate /* 11487c478bd9Sstevel@tonic-gate * in_host_array checks if the given hostname exists in the host_name 11497c478bd9Sstevel@tonic-gate * array. Returns 0 if the host doesn't exist, and 1 if it does exist 11507c478bd9Sstevel@tonic-gate */ 11517c478bd9Sstevel@tonic-gate static int 11527c478bd9Sstevel@tonic-gate in_host_array(char *host) 11537c478bd9Sstevel@tonic-gate { 11547c478bd9Sstevel@tonic-gate int i; 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate if (debug) 11577c478bd9Sstevel@tonic-gate (void) printf("%s ", host); 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate if ((strcmp(hostname, host) == 0) || (strcmp(LOGHOST, host) == 0)) 11607c478bd9Sstevel@tonic-gate return (1); 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate for (i = 0; i < addrix; i++) { 11637c478bd9Sstevel@tonic-gate if (strcmp(host_name[i], host) == 0) 11647c478bd9Sstevel@tonic-gate return (1); 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate return (0); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate /* 11717c478bd9Sstevel@tonic-gate * add_to_host_array adds a hostname to the host_name array. But if 11727c478bd9Sstevel@tonic-gate * the array is already full, then it first reallocates the array with 11737c478bd9Sstevel@tonic-gate * HOST_NAME_INCR extra elements. If the realloc fails, then it does 11747c478bd9Sstevel@tonic-gate * nothing and leaves host_name the way it was previous to the call. 11757c478bd9Sstevel@tonic-gate */ 11767c478bd9Sstevel@tonic-gate static void 11777c478bd9Sstevel@tonic-gate add_to_host_array(char *host) { 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate void *new_block = NULL; 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate /* Make sure we don't overrun host_name. */ 11827c478bd9Sstevel@tonic-gate if (addrix >= host_name_count) { 11837c478bd9Sstevel@tonic-gate host_name_count += HOST_NAME_INCR; 11847c478bd9Sstevel@tonic-gate new_block = realloc((void *)host_name, 11857c478bd9Sstevel@tonic-gate host_name_count*sizeof (char *)); 11867c478bd9Sstevel@tonic-gate if (new_block != NULL) 11877c478bd9Sstevel@tonic-gate host_name = new_block; 11887c478bd9Sstevel@tonic-gate else { 11897c478bd9Sstevel@tonic-gate host_name_count -= HOST_NAME_INCR; 11907c478bd9Sstevel@tonic-gate return; 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate if ((host_name[addrix] = strdup(host)) != NULL) 11957c478bd9Sstevel@tonic-gate addrix++; 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate /* 11997c478bd9Sstevel@tonic-gate * Compares the unqualified hostnames for hosts. Returns 0 if the 12007c478bd9Sstevel@tonic-gate * names match, and 1 if the names fail to match. 12017c478bd9Sstevel@tonic-gate */ 12027c478bd9Sstevel@tonic-gate int 12037c478bd9Sstevel@tonic-gate str_cmp_unqual_hostname(char *rawname1, char *rawname2) 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate size_t unq_len1, unq_len2; 12067c478bd9Sstevel@tonic-gate char *domain; 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate if (debug) { 12097c478bd9Sstevel@tonic-gate (void) printf("str_cmp_unqual: rawname1= %s, rawname2= %s\n", 12107c478bd9Sstevel@tonic-gate rawname1, rawname2); 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate unq_len1 = strcspn(rawname1, "."); 12147c478bd9Sstevel@tonic-gate unq_len2 = strcspn(rawname2, "."); 12157c478bd9Sstevel@tonic-gate domain = strchr(rawname1, '.'); 12167c478bd9Sstevel@tonic-gate if (domain != NULL) { 12177c478bd9Sstevel@tonic-gate if ((strncmp(rawname1, SM_ADDR_IPV4, unq_len1) == 0) || 12187c478bd9Sstevel@tonic-gate (strncmp(rawname1, SM_ADDR_IPV6, unq_len1) == 0)) 12197c478bd9Sstevel@tonic-gate return (1); 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate if ((unq_len1 == unq_len2) && 12237c478bd9Sstevel@tonic-gate (strncmp(rawname1, rawname2, unq_len1) == 0)) { 12247c478bd9Sstevel@tonic-gate return (0); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate return (1); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate /* 12317c478bd9Sstevel@tonic-gate * Compares <family>.<address-specifier> ASCII names for hosts. Returns 12327c478bd9Sstevel@tonic-gate * 0 if the addresses match, and 1 if the addresses fail to match. 12337c478bd9Sstevel@tonic-gate * If the args are indeed specifiers, they should look like this: 12347c478bd9Sstevel@tonic-gate * 12357c478bd9Sstevel@tonic-gate * ipv4.192.9.200.1 or ipv6.::C009:C801 12367c478bd9Sstevel@tonic-gate */ 12377c478bd9Sstevel@tonic-gate int 12387c478bd9Sstevel@tonic-gate str_cmp_address_specifier(char *specifier1, char *specifier2) 12397c478bd9Sstevel@tonic-gate { 12407c478bd9Sstevel@tonic-gate size_t unq_len1, unq_len2; 12417c478bd9Sstevel@tonic-gate char *rawaddr1, *rawaddr2; 12427c478bd9Sstevel@tonic-gate int af1, af2, len; 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate if (debug) { 12457c478bd9Sstevel@tonic-gate (void) printf("str_cmp_addr: specifier1= %s, specifier2= %s\n", 12467c478bd9Sstevel@tonic-gate specifier1, specifier2); 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate /* 12507c478bd9Sstevel@tonic-gate * Verify that: 12517c478bd9Sstevel@tonic-gate * 1. The family tokens match; 12527c478bd9Sstevel@tonic-gate * 2. The IP addresses following the `.' are legal; and 12537c478bd9Sstevel@tonic-gate * 3. These addresses match. 12547c478bd9Sstevel@tonic-gate */ 12557c478bd9Sstevel@tonic-gate unq_len1 = strcspn(specifier1, "."); 12567c478bd9Sstevel@tonic-gate unq_len2 = strcspn(specifier2, "."); 12577c478bd9Sstevel@tonic-gate rawaddr1 = strchr(specifier1, '.'); 12587c478bd9Sstevel@tonic-gate rawaddr2 = strchr(specifier2, '.'); 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate if (strncmp(specifier1, SM_ADDR_IPV4, unq_len1) == 0) { 12617c478bd9Sstevel@tonic-gate af1 = AF_INET; 12627c478bd9Sstevel@tonic-gate len = 4; 12637c478bd9Sstevel@tonic-gate } else if (strncmp(specifier1, SM_ADDR_IPV6, unq_len1) == 0) { 12647c478bd9Sstevel@tonic-gate af1 = AF_INET6; 12657c478bd9Sstevel@tonic-gate len = 16; 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate else 12687c478bd9Sstevel@tonic-gate return (1); 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate if (strncmp(specifier2, SM_ADDR_IPV4, unq_len2) == 0) 12717c478bd9Sstevel@tonic-gate af2 = AF_INET; 12727c478bd9Sstevel@tonic-gate else if (strncmp(specifier2, SM_ADDR_IPV6, unq_len2) == 0) 12737c478bd9Sstevel@tonic-gate af2 = AF_INET6; 12747c478bd9Sstevel@tonic-gate else 12757c478bd9Sstevel@tonic-gate return (1); 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate if (af1 != af2) 12787c478bd9Sstevel@tonic-gate return (1); 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate if (rawaddr1 != NULL && rawaddr2 != NULL) { 12817c478bd9Sstevel@tonic-gate char dst1[16]; 12827c478bd9Sstevel@tonic-gate char dst2[16]; 12837c478bd9Sstevel@tonic-gate ++rawaddr1; 12847c478bd9Sstevel@tonic-gate ++rawaddr2; 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate if (inet_pton(af1, rawaddr1, dst1) == 1 && 12877c478bd9Sstevel@tonic-gate inet_pton(af2, rawaddr1, dst2) == 1 && 12887c478bd9Sstevel@tonic-gate memcmp(dst1, dst2, len) == 0) { 12897c478bd9Sstevel@tonic-gate return (0); 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate return (1); 12937c478bd9Sstevel@tonic-gate } 1294bbaa8b60SDan Kruchinin 1295bbaa8b60SDan Kruchinin /* 1296bbaa8b60SDan Kruchinin * Add IP address strings to the host_name list. 1297bbaa8b60SDan Kruchinin */ 1298bbaa8b60SDan Kruchinin void 1299bbaa8b60SDan Kruchinin merge_ips(void) 1300bbaa8b60SDan Kruchinin { 1301bbaa8b60SDan Kruchinin struct ifaddrs *ifap, *cifap; 1302bbaa8b60SDan Kruchinin int error; 1303bbaa8b60SDan Kruchinin 1304bbaa8b60SDan Kruchinin error = getifaddrs(&ifap); 1305bbaa8b60SDan Kruchinin if (error) { 1306bbaa8b60SDan Kruchinin syslog(LOG_WARNING, "getifaddrs error: '%s'", 1307bbaa8b60SDan Kruchinin strerror(errno)); 1308bbaa8b60SDan Kruchinin return; 1309bbaa8b60SDan Kruchinin } 1310bbaa8b60SDan Kruchinin 1311bbaa8b60SDan Kruchinin for (cifap = ifap; cifap != NULL; cifap = cifap->ifa_next) { 1312bbaa8b60SDan Kruchinin struct sockaddr *sa = cifap->ifa_addr; 1313bbaa8b60SDan Kruchinin char addr_str[INET6_ADDRSTRLEN]; 1314bbaa8b60SDan Kruchinin void *addr = NULL; 1315bbaa8b60SDan Kruchinin 1316bbaa8b60SDan Kruchinin switch (sa->sa_family) { 1317bbaa8b60SDan Kruchinin case AF_INET: { 1318bbaa8b60SDan Kruchinin struct sockaddr_in *sin = (struct sockaddr_in *)sa; 1319bbaa8b60SDan Kruchinin 1320bbaa8b60SDan Kruchinin /* Skip loopback addresses. */ 1321bbaa8b60SDan Kruchinin if (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { 1322bbaa8b60SDan Kruchinin continue; 1323bbaa8b60SDan Kruchinin } 1324bbaa8b60SDan Kruchinin 1325bbaa8b60SDan Kruchinin addr = &sin->sin_addr; 1326bbaa8b60SDan Kruchinin break; 1327bbaa8b60SDan Kruchinin } 1328bbaa8b60SDan Kruchinin 1329bbaa8b60SDan Kruchinin case AF_INET6: { 1330bbaa8b60SDan Kruchinin struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 1331bbaa8b60SDan Kruchinin 1332bbaa8b60SDan Kruchinin /* Skip loopback addresses. */ 1333bbaa8b60SDan Kruchinin if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) { 1334bbaa8b60SDan Kruchinin continue; 1335bbaa8b60SDan Kruchinin } 1336bbaa8b60SDan Kruchinin 1337bbaa8b60SDan Kruchinin addr = &sin6->sin6_addr; 1338bbaa8b60SDan Kruchinin break; 1339bbaa8b60SDan Kruchinin } 1340bbaa8b60SDan Kruchinin 1341bbaa8b60SDan Kruchinin default: 1342bbaa8b60SDan Kruchinin syslog(LOG_WARNING, "Unknown address family %d for " 1343bbaa8b60SDan Kruchinin "interface %s", sa->sa_family, cifap->ifa_name); 1344bbaa8b60SDan Kruchinin continue; 1345bbaa8b60SDan Kruchinin } 1346bbaa8b60SDan Kruchinin 1347bbaa8b60SDan Kruchinin if (inet_ntop(sa->sa_family, addr, addr_str, sizeof (addr_str)) 1348bbaa8b60SDan Kruchinin == NULL) { 1349bbaa8b60SDan Kruchinin syslog(LOG_WARNING, "Failed to convert address into " 1350bbaa8b60SDan Kruchinin "string representation for interface '%s' " 1351bbaa8b60SDan Kruchinin "address family %d", cifap->ifa_name, 1352bbaa8b60SDan Kruchinin sa->sa_family); 1353bbaa8b60SDan Kruchinin continue; 1354bbaa8b60SDan Kruchinin } 1355bbaa8b60SDan Kruchinin 1356bbaa8b60SDan Kruchinin if (!in_host_array(addr_str)) { 1357bbaa8b60SDan Kruchinin add_to_host_array(addr_str); 1358bbaa8b60SDan Kruchinin } 1359bbaa8b60SDan Kruchinin } 1360bbaa8b60SDan Kruchinin 1361bbaa8b60SDan Kruchinin freeifaddrs(ifap); 1362bbaa8b60SDan Kruchinin } 1363