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 (the "License").
7# You may not use this file except in compliance 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# Check hostname configuration as per the sendmail code.
24#
25# See http://www.sendmail.org/sun-specific/migration.html#FQHN for details.
26#
27# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
28# Use is subject to license terms.
29#
30
31PATH=/bin:/usr/sbin
32
33# If $1 has a ".", accept it and exit.
34
35accept_if_fully_qualified() {
36	case $1 in
37	*.*)
38		echo "Hostname $myhostname OK: fully qualified as $1"
39		exit 0
40		;;
41	esac
42}
43
44# Check the `getent hosts $1` output, skipping the 1st entry (IP address).
45
46check_gethostbyname() {
47	for host in `getent hosts $1 | awk '{for (f=2; f <= NF; f++) print $f}'`
48	do
49		accept_if_fully_qualified $host
50	done
51}
52
53# Parse /etc/hosts, looking for $1 as an entry by itself, and try to find
54# a long name on the same line.  First kill all comments, then check for
55# $1 as a word by itself, then take just the first such line, then skip
56# its first entry (IP address).
57
58check_hosts_file() {
59	for entry in `sed -e 's/#.*$//' /etc/hosts | \
60		awk '/[ 	]'$1'([ 	]|$)/ \
61			{for (f=2; f <= NF; f++) print $f; exit}'`
62	do
63		accept_if_fully_qualified $entry
64	done
65}
66
67# Parse the output of `nslookup $1`, checking the Name and Aliases.
68
69check_dns() {
70	for host in `nslookup $1 2>/dev/null | \
71		awk '$1 == "Name:" || $1 == "Aliases:"{print $2}'`
72	do
73		accept_if_fully_qualified $host
74	done
75}
76
77# Check the `ypmatch $1 hosts` output, skipping the 1st entry (IP address).
78
79check_nis() {
80	for hst in `ypmatch $1 hosts | awk '{for (f=2; f <= NF; f++) print $f}'`
81	do
82		accept_if_fully_qualified $hst
83	done
84}
85
86# Recommend how to reconfigure to get $1.$2 as the FQHN.
87# $3 is the first entry for hosts in /etc/nsswitch.conf .
88
89suggest_fix_and_exit() {
90	myhost=$1
91	suggested_domain=$2
92	fhe=$3
93	myipaddr=`getent hosts $myhost | head -1 | awk '{print $1}'`
94
95	# aliases: skip the 1st & 2nd entries: IP address & canonical name
96
97	set -- '' '' '[ aliases ... ]'
98	set -- `grep "^$myipaddr[	 ]" /etc/hosts 2>/dev/null`
99	result=$?
100	shift 2
101	echo "We recommend \c"
102	if [ "x$fhe" != "xfiles" ] ; then
103		echo "listing files first for hosts in /etc/nsswitch.conf"
104		echo "and then \c"
105	fi
106	if [ $result = 0 ] ; then
107		echo "changing the /etc/hosts entry:\n"
108		echo "$myipaddr $myhost $*\n"
109		echo "to:\n"
110	else
111		echo "adding the /etc/hosts entry:\n"
112	fi
113	echo "$myipaddr $myhost $myhost.$suggested_domain $*"
114	exit 0
115}
116
117# Fall back to the NIS domain, minus the first label.  If it is non-null,
118# use it but recommend against it.  $2 is just informative, indicating whether
119# we're checking the NIS domain.  $3 is to pass on.
120
121check_nis_domain() {
122	nisdomain=`domainname`
123	realdomain=`echo $nisdomain | sed 's/[^.]*\.//'`
124	if [ "x$realdomain" != "x" ] ; then
125		echo "Hostname $1 can be fully qualified using NIS$2 domain"
126		echo "	$nisdomain"
127		echo "resulting in the name"
128		echo "	$1.$realdomain"
129		echo "but this is bad practice.\n"
130		suggest_fix_and_exit $1 $realdomain $3
131	fi
132}
133
134# Goal: try to fully qualify `hostname` as sendmail would.
135# Algorithm (stop as soon as a name with a dot is found):
136#    1. gethostbyname (simulate with getent hosts)
137#    2. fall back to individual hosts: methods in nsswitch.conf, using
138#       only those that are configured, in their configured order
139#       * files (parse /etc/hosts directly)
140#       * dns (parse nslookup output)
141#       * nis (parse ypmatch output)
142#    3. fall back to the NIS domain name.
143# If none of the above succeed, give up.  Recommend:
144#    a. the domain entry in /etc/resolv.conf, if one exists
145#    b. "pick.some.domain"
146
147myhostname=`hostname`
148
149check_gethostbyname $myhostname
150
151hosts_line=`sed -n -e 's/^hosts:\([^#]*\).*/\1/p' /etc/nsswitch.conf`
152first_hosts_entry=`echo $hosts_line | awk '{print $1}'`
153nis_domains=""
154
155for entry in $hosts_line
156do
157	case $entry in
158	files)
159		check_hosts_file $myhostname
160		;;
161	dns)
162		check_dns $myhostname
163		;;
164	nis)
165		check_nis $myhostname
166		nis_domains="$nis_domains nis"
167		;;
168	esac
169done
170
171for entry in $nis_domains
172do
173	case $entry in
174	nis)
175		check_nis_domain $myhostname "" $first_hosts_entry
176		;;
177	esac
178done
179
180realdomain=`awk '$1 ~ /^domain/ {print $2}' 2>/dev/null < /etc/resolv.conf`
181case $realdomain in
182*.*)
183	# OK
184	;;
185*)
186	realdomain="pick.some.domain"
187	;;
188esac
189
190echo "Hostname $myhostname could not be fully qualified."
191suggest_fix_and_exit $myhostname $realdomain $first_hosts_entry
192