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