xref: /illumos-gate/usr/src/cmd/sendmail/cf/sh/check-hostname.sh (revision 89b2a9fbeabf42fa54594df0e5927bcc50a07cc9)
1#!/bin/sh --
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License, Version 1.0 only
7# (the "License").  You may not use this file except in compliance
8# with the License.
9#
10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11# or http://www.opensolaris.org/os/licensing.
12# See the License for the specific language governing permissions
13# and limitations under the License.
14#
15# When distributing Covered Code, include this CDDL HEADER in each
16# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17# If applicable, add the following below this CDDL HEADER, with the
18# fields enclosed by brackets "[]" replaced with your own identifying
19# information: Portions Copyright [yyyy] [name of copyright owner]
20#
21# CDDL HEADER END
22#
23
24# Check hostname configuration as per the sendmail code.
25#
26# See http://www.sendmail.org/sun-specific/migration.html#FQHN for details.
27#
28# Copyright (c) 1997-2000 by Sun Microsystems, Inc.
29# All Rights Reserved.
30#
31# %W% (Sun) %G%
32# ident	"%Z%%M%	%I%	%E% SMI"
33
34PATH=/bin:/usr/sbin
35
36# If $1 has a ".", accept it and exit.
37
38accept_if_fully_qualified() {
39	case $1 in
40	*.*)
41		echo "Hostname $myhostname OK: fully qualified as $1"
42		exit 0
43		;;
44	esac
45}
46
47# Check the `getent hosts $1` output, skipping the 1st entry (IP address).
48
49check_gethostbyname() {
50	for host in `getent hosts $1 | awk '{for (f=2; f <= NF; f++) print $f}'`
51	do
52		accept_if_fully_qualified $host
53	done
54}
55
56# Parse /etc/hosts, looking for $1 as an entry by itself, and try to find
57# a long name on the same line.  First kill all comments, then check for
58# $1 as a word by itself, then take just the first such line, then skip
59# its first entry (IP address).
60
61check_hosts_file() {
62	for entry in `sed -e 's/#.*$//' /etc/hosts | \
63		awk '/[ 	]'$1'([ 	]|$)/ \
64			{for (f=2; f <= NF; f++) print $f; exit}'`
65	do
66		accept_if_fully_qualified $entry
67	done
68}
69
70# Parse the output of `nslookup $1`, checking the Name and Aliases.
71
72check_dns() {
73	for host in `nslookup $1 2>/dev/null | \
74		awk '$1 == "Name:" || $1 == "Aliases:"{print $2}'`
75	do
76		accept_if_fully_qualified $host
77	done
78}
79
80# Check the `ypmatch $1 hosts` output, skipping the 1st entry (IP address).
81
82check_nis() {
83	for hst in `ypmatch $1 hosts | awk '{for (f=2; f <= NF; f++) print $f}'`
84	do
85		accept_if_fully_qualified $hst
86	done
87}
88
89# Check the `nismatch $1 hosts` output.  Its output is different from ypmatch
90# and the hosts file.  Field 1 is a cname (i.e., alias), field 2 is the
91# proper name, field 3 is the IP address and field 4 is comment.
92
93check_nisplus() {
94	for hst in `nismatch $1 hosts.org_dir | \
95		awk '{for (f=1; f <= 2; f++) print $f}'`
96	do
97		accept_if_fully_qualified $hst
98	done
99}
100
101# Recommend how to reconfigure to get $1.$2 as the FQHN.
102# $3 is the first entry for hosts in /etc/nsswitch.conf .
103
104suggest_fix_and_exit() {
105	myhost=$1
106	suggested_domain=$2
107	fhe=$3
108	myipaddr=`getent hosts $myhost | head -1 | awk '{print $1}'`
109
110	# aliases: skip the 1st & 2nd entries: IP address & canonical name
111
112	set -- '' '' '[ aliases ... ]'
113	set -- `grep "^$myipaddr[	 ]" /etc/hosts 2>/dev/null`
114	result=$?
115	shift 2
116	echo "We recommend \c"
117	if [ "x$fhe" != "xfiles" ] ; then
118		echo "listing files first for hosts in /etc/nsswitch.conf"
119		echo "and then \c"
120	fi
121	if [ $result = 0 ] ; then
122		echo "changing the /etc/hosts entry:\n"
123		echo "$myipaddr $myhost $*\n"
124		echo "to:\n"
125	else
126		echo "adding the /etc/hosts entry:\n"
127	fi
128	echo "$myipaddr $myhost $myhost.$suggested_domain $*"
129	exit 0
130}
131
132# Fall back to the NIS[+] domain, minus the first label.  If it is non-null,
133# use it but recommend against it.  $2 is just informative, indicating whether
134# we're checking the NIS or NIS+ domain.  $3 is to pass on.
135
136check_nis_domain() {
137	nisdomain=`domainname`
138	realdomain=`echo $nisdomain | sed 's/[^.]*\.//'`
139	if [ "x$realdomain" != "x" ] ; then
140		echo "Hostname $1 can be fully qualified using NIS$2 domain"
141		echo "	$nisdomain"
142		echo "resulting in the name"
143		echo "	$1.$realdomain"
144		echo "but this is bad practice.\n"
145		suggest_fix_and_exit $1 $realdomain $3
146	fi
147}
148
149# Goal: try to fully qualify `hostname` as sendmail would.
150# Algorithm (stop as soon as a name with a dot is found):
151#    1. gethostbyname (simulate with getent hosts)
152#    2. fall back to individual hosts: methods in nsswitch.conf, using
153#       only those that are configured, in their configured order
154#       * files (parse /etc/hosts directly)
155#       * dns (parse nslookup output)
156#       * nis (parse ypmatch output)
157#       * nisplus (parse nismatch output)
158#    3. fall back to the NIS[+] domain name.
159# If none of the above succeed, give up.  Recommend:
160#    a. the domain entry in /etc/resolv.conf, if one exists
161#    b. "pick.some.domain"
162
163myhostname=`hostname`
164
165check_gethostbyname $myhostname
166
167hosts_line=`sed -n -e 's/^hosts:\([^#]*\).*/\1/p' /etc/nsswitch.conf`
168first_hosts_entry=`echo $hosts_line | awk '{print $1}'`
169nis_domains=""
170
171for entry in $hosts_line
172do
173	case $entry in
174	files)
175		check_hosts_file $myhostname
176		;;
177	dns)
178		check_dns $myhostname
179		;;
180	nis)
181		check_nis $myhostname
182		nis_domains="$nis_domains nis"
183		;;
184	nisplus)
185		check_nisplus $myhostname
186		nis_domains="$nis_domains nisplus"
187		;;
188	esac
189done
190
191for entry in $nis_domains
192do
193	case $entry in
194	nis)
195		check_nis_domain $myhostname "" $first_hosts_entry
196		;;
197	nisplus)
198		check_nis_domain $myhostname "+" $first_hosts_entry
199		;;
200	esac
201done
202
203realdomain=`awk '$1 ~ /^domain/ {print $2}' 2>/dev/null < /etc/resolv.conf`
204case $realdomain in
205*.*)
206	# OK
207	;;
208*)
209	realdomain="pick.some.domain"
210	;;
211esac
212
213echo "Hostname $myhostname could not be fully qualified."
214suggest_fix_and_exit $myhostname $realdomain $first_hosts_entry
215