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