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