xref: /titanic_44/usr/src/cmd/cmd-inet/sbin/dhcpagent/util.c (revision ea8dc4b6d2251b437950c0056bc626b311c73c27)
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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <stdlib.h>
33 #include <netinet/in.h>		/* struct in_addr */
34 #include <netinet/dhcp.h>
35 #include <signal.h>
36 #include <sys/dlpi.h>
37 #include <sys/sockio.h>
38 #include <sys/socket.h>
39 #include <errno.h>
40 #include <net/route.h>
41 #include <net/if_arp.h>
42 #include <string.h>
43 #include <dhcpmsg.h>
44 #include <ctype.h>
45 #include <netdb.h>
46 #include <fcntl.h>
47 #include <stdio.h>
48 
49 #include "states.h"
50 #include "agent.h"
51 #include "interface.h"
52 #include "util.h"
53 #include "packet.h"
54 #include "defaults.h"
55 
56 /*
57  * this file contains utility functions that have no real better home
58  * of their own.  they can largely be broken into six categories:
59  *
60  *  o  conversion functions -- functions to turn integers into strings,
61  *     or to convert between units of a similar measure.
62  *
63  *  o  ipc-related functions -- functions to simplify the generation of
64  *     ipc messages to the agent's clients.
65  *
66  *  o  signal-related functions -- functions to clean up the agent when
67  *     it receives a signal.
68  *
69  *  o  routing table manipulation functions
70  *
71  *  o  acknak handler functions
72  *
73  *  o  true miscellany -- anything else
74  */
75 
76 /*
77  * pkt_type_to_string(): stringifies a packet type
78  *
79  *   input: uchar_t: a DHCP packet type value, as defined in RFC2131
80  *  output: const char *: the stringified packet type
81  */
82 
83 const char *
84 pkt_type_to_string(uchar_t type)
85 {
86 	/*
87 	 * note: the ordering here allows direct indexing of the table
88 	 *	 based on the RFC2131 packet type value passed in.
89 	 */
90 
91 	static const char *types[] = {
92 		"BOOTP",  "DISCOVER", "OFFER",   "REQUEST", "DECLINE",
93 		"ACK",    "NAK",      "RELEASE", "INFORM"
94 	};
95 
96 	if (type >= (sizeof (types) / sizeof (*types)) || types[type] == NULL)
97 		return ("<unknown>");
98 
99 	return (types[type]);
100 }
101 
102 /*
103  * dlpi_to_arp(): converts DLPI datalink types into ARP datalink types
104  *
105  *   input: uchar_t: the DLPI datalink type
106  *  output: uchar_t: the ARP datalink type (0 if no corresponding code)
107  */
108 
109 uchar_t
110 dlpi_to_arp(uchar_t dlpi_type)
111 {
112 	switch (dlpi_type) {
113 
114 	case DL_ETHER:
115 		return (1);
116 
117 	case DL_FRAME:
118 		return (15);
119 
120 	case DL_ATM:
121 		return (16);
122 
123 	case DL_HDLC:
124 		return (17);
125 
126 	case DL_FC:
127 		return (18);
128 
129 	case DL_CSMACD:				/* ieee 802 networks */
130 	case DL_TPB:
131 	case DL_TPR:
132 	case DL_METRO:
133 	case DL_FDDI:
134 		return (6);
135 	case DL_IB:
136 		return (ARPHRD_IB);
137 	}
138 
139 	return (0);
140 }
141 
142 /*
143  * monosec_to_string(): converts a monosec_t into a date string
144  *
145  *   input: monosec_t: the monosec_t to convert
146  *  output: const char *: the corresponding date string
147  */
148 
149 const char *
150 monosec_to_string(monosec_t monosec)
151 {
152 	time_t	time = monosec_to_time(monosec);
153 	char	*time_string = ctime(&time);
154 
155 	/* strip off the newline -- ugh, why, why, why.. */
156 	time_string[strlen(time_string) - 1] = '\0';
157 	return (time_string);
158 }
159 
160 /*
161  * monosec(): returns a monotonically increasing time in seconds that
162  *            is not affected by stime(2) or adjtime(2).
163  *
164  *   input: void
165  *  output: monosec_t: the number of seconds since some time in the past
166  */
167 
168 monosec_t
169 monosec(void)
170 {
171 	return (gethrtime() / NANOSEC);
172 }
173 
174 /*
175  * monosec_to_time(): converts a monosec_t into real wall time
176  *
177  *    input: monosec_t: the absolute monosec_t to convert
178  *   output: time_t: the absolute time that monosec_t represents in wall time
179  */
180 
181 time_t
182 monosec_to_time(monosec_t abs_monosec)
183 {
184 	return (abs_monosec - monosec()) + time(NULL);
185 }
186 
187 /*
188  * send_ok_reply(): sends an "ok" reply to a request and closes the ipc
189  *		    connection
190  *
191  *   input: dhcp_ipc_request_t *: the request to reply to
192  *	    int *: the ipc connection file descriptor (set to -1 on return)
193  *  output: void
194  *    note: the request is freed (thus the request must be on the heap).
195  */
196 
197 void
198 send_ok_reply(dhcp_ipc_request_t *request, int *control_fd)
199 {
200 	send_error_reply(request, 0, control_fd);
201 }
202 
203 /*
204  * send_error_reply(): sends an "error" reply to a request and closes the ipc
205  *		       connection
206  *
207  *   input: dhcp_ipc_request_t *: the request to reply to
208  *	    int: the error to send back on the ipc connection
209  *	    int *: the ipc connection file descriptor (set to -1 on return)
210  *  output: void
211  *    note: the request is freed (thus the request must be on the heap).
212  */
213 
214 void
215 send_error_reply(dhcp_ipc_request_t *request, int error, int *control_fd)
216 {
217 	send_data_reply(request, control_fd, error, DHCP_TYPE_NONE, NULL, NULL);
218 }
219 
220 /*
221  * send_data_reply(): sends a reply to a request and closes the ipc connection
222  *
223  *   input: dhcp_ipc_request_t *: the request to reply to
224  *	    int *: the ipc connection file descriptor (set to -1 on return)
225  *	    int: the status to send back on the ipc connection (zero for
226  *		 success, DHCP_IPC_E_* otherwise).
227  *	    dhcp_data_type_t: the type of the payload in the reply
228  *	    void *: the payload for the reply, or NULL if there is no payload
229  *	    size_t: the size of the payload
230  *  output: void
231  *    note: the request is freed (thus the request must be on the heap).
232  */
233 
234 void
235 send_data_reply(dhcp_ipc_request_t *request, int *control_fd,
236     int error, dhcp_data_type_t type, void *buffer, size_t size)
237 {
238 	dhcp_ipc_reply_t	*reply;
239 
240 	if (*control_fd == -1)
241 		return;
242 
243 	reply = dhcp_ipc_alloc_reply(request, error, buffer, size, type);
244 	if (reply == NULL)
245 		dhcpmsg(MSG_ERR, "send_data_reply: cannot allocate reply");
246 
247 	else if (dhcp_ipc_send_reply(*control_fd, reply) != 0)
248 		dhcpmsg(MSG_ERR, "send_data_reply: dhcp_ipc_send_reply");
249 
250 	/*
251 	 * free the request since we've now used it to send our reply.
252 	 * we can also close the socket since the reply has been sent.
253 	 */
254 
255 	free(reply);
256 	free(request);
257 	(void) dhcp_ipc_close(*control_fd);
258 	*control_fd = -1;
259 }
260 
261 /*
262  * print_server_msg(): prints a message from a DHCP server
263  *
264  *   input: struct ifslist *: the interface the message came in on
265  *	    DHCP_OPT *: the option containing the string to display
266  *  output: void
267  */
268 
269 void
270 print_server_msg(struct ifslist *ifsp, DHCP_OPT *p)
271 {
272 	dhcpmsg(MSG_INFO, "%s: message from server: %.*s", ifsp->if_name,
273 	    p->len, p->value);
274 }
275 
276 /*
277  * alrm_exit(): Signal handler for SIGARLM. terminates grandparent.
278  *
279  *    input: int: signal the handler was called with.
280  *
281  *   output: void
282  */
283 
284 static void
285 alrm_exit(int sig)
286 {
287 	int exitval;
288 
289 	if (sig == SIGALRM && grandparent != 0)
290 		exitval = EXIT_SUCCESS;
291 	else
292 		exitval = EXIT_FAILURE;
293 
294 	_exit(exitval);
295 }
296 
297 /*
298  * daemonize(): daemonizes the process
299  *
300  *   input: void
301  *  output: int: 1 on success, 0 on failure
302  */
303 
304 int
305 daemonize(void)
306 {
307 	/*
308 	 * We've found that adoption takes sufficiently long that
309 	 * a dhcpinfo run after dhcpagent -a is started may occur
310 	 * before the agent is ready to process the request.
311 	 * The result is an error message and an unhappy user.
312 	 *
313 	 * The initial process now sleeps for DHCP_ADOPT_SLEEP,
314 	 * unless interrupted by a SIGALRM, in which case it
315 	 * exits immediately. This has the effect that the
316 	 * grandparent doesn't exit until the dhcpagent is ready
317 	 * to process requests. This defers the the balance of
318 	 * the system start-up script processing until the
319 	 * dhcpagent is ready to field requests.
320 	 *
321 	 * grandparent is only set for the adopt case; other
322 	 * cases do not require the wait.
323 	 */
324 
325 	if (grandparent != 0)
326 		(void) signal(SIGALRM, alrm_exit);
327 
328 	switch (fork()) {
329 
330 	case -1:
331 		return (0);
332 
333 	case  0:
334 		if (grandparent != 0)
335 			(void) signal(SIGALRM, SIG_DFL);
336 
337 		/*
338 		 * setsid() makes us lose our controlling terminal,
339 		 * and become both a session leader and a process
340 		 * group leader.
341 		 */
342 
343 		(void) setsid();
344 
345 		/*
346 		 * under POSIX, a session leader can accidentally
347 		 * (through open(2)) acquire a controlling terminal if
348 		 * it does not have one.  just to be safe, fork again
349 		 * so we are not a session leader.
350 		 */
351 
352 		switch (fork()) {
353 
354 		case -1:
355 			return (0);
356 
357 		case 0:
358 			(void) signal(SIGHUP, SIG_IGN);
359 			(void) chdir("/");
360 			(void) umask(022);
361 			closefrom(0);
362 			break;
363 
364 		default:
365 			_exit(EXIT_SUCCESS);
366 		}
367 		break;
368 
369 	default:
370 		if (grandparent != 0) {
371 			(void) signal(SIGCHLD, SIG_IGN);
372 			dhcpmsg(MSG_DEBUG, "dhcpagent: daemonize: "
373 			    "waiting for adoption to complete.");
374 			if (sleep(DHCP_ADOPT_SLEEP) == 0) {
375 				dhcpmsg(MSG_WARNING, "dhcpagent: daemonize: "
376 				    "timed out awaiting adoption.");
377 			}
378 		}
379 		_exit(EXIT_SUCCESS);
380 	}
381 
382 	return (1);
383 }
384 
385 /*
386  * update_default_route(): update the interface's default route
387  *
388  *   input: int: the type of message; either RTM_ADD or RTM_DELETE
389  *	    struct in_addr: the default gateway to use
390  *	    const char *: the interface associated with the route
391  *	    int: any additional flags (besides RTF_STATIC and RTF_GATEWAY)
392  *  output: int: 1 on success, 0 on failure
393  */
394 
395 static int
396 update_default_route(const char *ifname, int type, struct in_addr *gateway_nbo,
397     int flags)
398 {
399 	static int rtsock_fd = -1;
400 	struct {
401 		struct rt_msghdr	rm_mh;
402 		struct sockaddr_in	rm_dst;
403 		struct sockaddr_in	rm_gw;
404 		struct sockaddr_in	rm_mask;
405 		struct sockaddr_dl	rm_ifp;
406 	} rtmsg;
407 
408 	if (rtsock_fd == -1) {
409 		rtsock_fd = socket(PF_ROUTE, SOCK_RAW, 0);
410 		if (rtsock_fd == -1) {
411 			dhcpmsg(MSG_ERR, "update_default_route: "
412 			    "cannot create routing socket");
413 			return (0);
414 		}
415 	}
416 
417 	(void) memset(&rtmsg, 0, sizeof (rtmsg));
418 	rtmsg.rm_mh.rtm_version = RTM_VERSION;
419 	rtmsg.rm_mh.rtm_msglen	= sizeof (rtmsg);
420 	rtmsg.rm_mh.rtm_type	= type;
421 	rtmsg.rm_mh.rtm_pid	= getpid();
422 	rtmsg.rm_mh.rtm_flags	= RTF_GATEWAY | RTF_STATIC | flags;
423 	rtmsg.rm_mh.rtm_addrs	= RTA_GATEWAY | RTA_DST | RTA_NETMASK | RTA_IFP;
424 
425 	rtmsg.rm_gw.sin_family	= AF_INET;
426 	rtmsg.rm_gw.sin_addr	= *gateway_nbo;
427 
428 	rtmsg.rm_dst.sin_family = AF_INET;
429 	rtmsg.rm_dst.sin_addr.s_addr = htonl(INADDR_ANY);
430 
431 	rtmsg.rm_mask.sin_family = AF_INET;
432 	rtmsg.rm_mask.sin_addr.s_addr = htonl(0);
433 
434 	rtmsg.rm_ifp.sdl_family	= AF_LINK;
435 	rtmsg.rm_ifp.sdl_index	= if_nametoindex(ifname);
436 
437 	return (write(rtsock_fd, &rtmsg, sizeof (rtmsg)) == sizeof (rtmsg));
438 }
439 
440 /*
441  * add_default_route(): add the default route to the given gateway
442  *
443  *   input: const char *: the name of the interface associated with the route
444  *	    struct in_addr: the default gateway to add
445  *  output: int: 1 on success, 0 on failure
446  */
447 
448 int
449 add_default_route(const char *ifname, struct in_addr *gateway_nbo)
450 {
451 	if (strchr(ifname, ':') != NULL)	/* see README */
452 		return (1);
453 
454 	return (update_default_route(ifname, RTM_ADD, gateway_nbo, RTF_UP));
455 }
456 
457 /*
458  * del_default_route(): deletes the default route to the given gateway
459  *
460  *   input: const char *: the name of the interface associated with the route
461  *	    struct in_addr: if not INADDR_ANY, the default gateway to remove
462  *  output: int: 1 on success, 0 on failure
463  */
464 
465 int
466 del_default_route(const char *ifname, struct in_addr *gateway_nbo)
467 {
468 	if (strchr(ifname, ':') != NULL)
469 		return (1);
470 
471 	if (gateway_nbo->s_addr == htonl(INADDR_ANY)) /* no router */
472 		return (1);
473 
474 	return (update_default_route(ifname, RTM_DELETE, gateway_nbo, 0));
475 }
476 
477 /*
478  * inactivity_shutdown(): shuts down agent if there are no interfaces to manage
479  *
480  *   input: iu_tq_t *: unused
481  *	    void *: unused
482  *  output: void
483  */
484 
485 /* ARGSUSED */
486 void
487 inactivity_shutdown(iu_tq_t *tqp, void *arg)
488 {
489 	if (ifs_count() > 0)	/* shouldn't happen, but... */
490 		return;
491 
492 	iu_stop_handling_events(eh, DHCP_REASON_INACTIVITY, NULL, NULL);
493 }
494 
495 /*
496  * graceful_shutdown(): shuts down the agent gracefully
497  *
498  *   input: int: the signal that caused graceful_shutdown to be called
499  *  output: void
500  */
501 
502 void
503 graceful_shutdown(int sig)
504 {
505 	iu_stop_handling_events(eh, sig, drain_script, NULL);
506 }
507 
508 /*
509  * register_acknak(): registers dhcp_acknak() to be called back when ACK or
510  *		      NAK packets are received on a given interface
511  *
512  *   input: struct ifslist *: the interface to register for
513  *  output: int: 1 on success, 0 on failure
514  */
515 
516 int
517 register_acknak(struct ifslist *ifsp)
518 {
519 	iu_event_id_t	ack_id, ack_bcast_id = -1;
520 
521 	/*
522 	 * having an acknak id already registered isn't impossible;
523 	 * handle the situation as gracefully as possible.
524 	 */
525 
526 	if (ifsp->if_acknak_id != -1) {
527 		dhcpmsg(MSG_DEBUG, "register_acknak: acknak id pending, "
528 		    "attempting to cancel");
529 		if (unregister_acknak(ifsp) == 0)
530 			return (0);
531 	}
532 
533 	switch (ifsp->if_state) {
534 
535 	case BOUND:
536 	case REBINDING:
537 	case RENEWING:
538 
539 		ack_bcast_id = iu_register_event(eh, ifsp->if_sock_fd, POLLIN,
540 		    dhcp_acknak, ifsp);
541 
542 		if (ack_bcast_id == -1) {
543 			dhcpmsg(MSG_WARNING, "register_acknak: cannot "
544 			    "register to receive socket broadcasts");
545 			return (0);
546 		}
547 
548 		ack_id = iu_register_event(eh, ifsp->if_sock_ip_fd, POLLIN,
549 		    dhcp_acknak, ifsp);
550 		break;
551 
552 	default:
553 		ack_id = iu_register_event(eh, ifsp->if_dlpi_fd, POLLIN,
554 		    dhcp_acknak, ifsp);
555 		break;
556 	}
557 
558 	if (ack_id == -1) {
559 		dhcpmsg(MSG_WARNING, "register_acknak: cannot register event");
560 		(void) iu_unregister_event(eh, ack_bcast_id, NULL);
561 		return (0);
562 	}
563 
564 	ifsp->if_acknak_id = ack_id;
565 	hold_ifs(ifsp);
566 
567 	ifsp->if_acknak_bcast_id = ack_bcast_id;
568 	if (ifsp->if_acknak_bcast_id != -1) {
569 		hold_ifs(ifsp);
570 		dhcpmsg(MSG_DEBUG, "register_acknak: registered broadcast id "
571 		    "%d", ack_bcast_id);
572 	}
573 
574 	dhcpmsg(MSG_DEBUG, "register_acknak: registered acknak id %d", ack_id);
575 	return (1);
576 }
577 
578 /*
579  * unregister_acknak(): unregisters dhcp_acknak() to be called back
580  *
581  *   input: struct ifslist *: the interface to unregister for
582  *  output: int: 1 on success, 0 on failure
583  */
584 
585 int
586 unregister_acknak(struct ifslist *ifsp)
587 {
588 	if (ifsp->if_acknak_id != -1) {
589 
590 		if (iu_unregister_event(eh, ifsp->if_acknak_id, NULL) == 0) {
591 			dhcpmsg(MSG_DEBUG, "unregister_acknak: cannot "
592 			    "unregister acknak id %d on %s",
593 			    ifsp->if_acknak_id, ifsp->if_name);
594 			return (0);
595 		}
596 
597 		dhcpmsg(MSG_DEBUG, "unregister_acknak: unregistered acknak id "
598 		    "%d", ifsp->if_acknak_id);
599 
600 		ifsp->if_acknak_id = -1;
601 		(void) release_ifs(ifsp);
602 	}
603 
604 	if (ifsp->if_acknak_bcast_id != -1) {
605 
606 		if (iu_unregister_event(eh, ifsp->if_acknak_bcast_id, NULL)
607 		    == 0) {
608 			dhcpmsg(MSG_DEBUG, "unregister_acknak: cannot "
609 			    "unregister broadcast id %d on %s",
610 			    ifsp->if_acknak_id, ifsp->if_name);
611 			return (0);
612 		}
613 
614 		dhcpmsg(MSG_DEBUG, "unregister_acknak: unregistered "
615 		    "broadcast id %d", ifsp->if_acknak_bcast_id);
616 
617 		ifsp->if_acknak_bcast_id = -1;
618 		(void) release_ifs(ifsp);
619 	}
620 
621 	return (1);
622 }
623 
624 /*
625  * bind_sock(): binds a socket to a given IP address and port number
626  *
627  *   input: int: the socket to bind
628  *	    in_port_t: the port number to bind to, host byte order
629  *	    in_addr_t: the address to bind to, host byte order
630  *  output: int: 1 on success, 0 on failure
631  */
632 
633 int
634 bind_sock(int fd, in_port_t port_hbo, in_addr_t addr_hbo)
635 {
636 	struct sockaddr_in	sin;
637 	int			on = 1;
638 
639 	(void) memset(&sin, 0, sizeof (struct sockaddr_in));
640 	sin.sin_family = AF_INET;
641 	sin.sin_port   = htons(port_hbo);
642 	sin.sin_addr.s_addr = htonl(addr_hbo);
643 
644 	(void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (int));
645 
646 	return (bind(fd, (struct sockaddr *)&sin, sizeof (sin)) == 0);
647 }
648 
649 /*
650  * valid_hostname(): check whether a string is a valid hostname
651  *
652  *   input: const char *: the string to verify as a hostname
653  *  output: boolean_t: B_TRUE if the string is a valid hostname
654  *
655  * Note that we accept both host names beginning with a digit and
656  * those containing hyphens.  Neither is strictly legal according
657  * to the RFCs, but both are in common practice, so we endeavour
658  * to not break what customers are using.
659  */
660 
661 static boolean_t
662 valid_hostname(const char *hostname)
663 {
664 	unsigned int i;
665 
666 	for (i = 0; hostname[i] != '\0'; i++) {
667 
668 		if (isalpha(hostname[i]) || isdigit(hostname[i]) ||
669 		    (((hostname[i] == '-') || (hostname[i] == '.')) && (i > 0)))
670 			continue;
671 
672 		return (B_FALSE);
673 	}
674 
675 	return (i > 0);
676 }
677 
678 /*
679  * iffile_to_hostname(): return the hostname contained on a line of the form
680  *
681  * [ ^I]*inet[ ^I]+hostname[\n]*\0
682  *
683  * in the file located at the specified path
684  *
685  *   input: const char *: the path of the file to look in for the hostname
686  *  output: const char *: the hostname at that path, or NULL on failure
687  */
688 
689 #define	IFLINE_MAX	1024	/* maximum length of a hostname.<if> line */
690 
691 const char *
692 iffile_to_hostname(const char *path)
693 {
694 	FILE		*fp;
695 	static char	ifline[IFLINE_MAX];
696 
697 	fp = fopen(path, "r");
698 	if (fp == NULL)
699 		return (NULL);
700 
701 	/*
702 	 * /etc/hostname.<if> may contain multiple ifconfig commands, but each
703 	 * such command is on a separate line (see the "while read ifcmds" code
704 	 * in /etc/init.d/inetinit).  Thus we will read the file a line at a
705 	 * time, searching for a line of the form
706 	 *
707 	 * [ ^I]*inet[ ^I]+hostname[\n]*\0
708 	 *
709 	 * extract the host name from it, and check it for validity.
710 	 */
711 	while (fgets(ifline, sizeof (ifline), fp) != NULL) {
712 		char *p;
713 
714 		if ((p = strstr(ifline, "inet")) != NULL) {
715 			if ((p != ifline) && !isspace(p[-1])) {
716 				(void) fclose(fp);
717 				return (NULL);
718 			}
719 			p += 4;	/* skip over "inet" and expect spaces or tabs */
720 			if ((*p == '\n') || (*p == '\0')) {
721 				(void) fclose(fp);
722 				return (NULL);
723 			}
724 			if (isspace(*p)) {
725 				char *nlptr;
726 
727 				/* no need to read more of the file */
728 				(void) fclose(fp);
729 
730 				while (isspace(*p))
731 					p++;
732 				if ((nlptr = strrchr(p, '\n')) != NULL)
733 					*nlptr = '\0';
734 				if (strlen(p) > MAXHOSTNAMELEN) {
735 					dhcpmsg(MSG_WARNING,
736 					    "iffile_to_hostname:"
737 					    " host name too long");
738 					return (NULL);
739 				}
740 				if (valid_hostname(p)) {
741 					return (p);
742 				} else {
743 					dhcpmsg(MSG_WARNING,
744 					    "iffile_to_hostname:"
745 					    " host name not valid");
746 					return (NULL);
747 				}
748 			} else {
749 				(void) fclose(fp);
750 				return (NULL);
751 			}
752 		}
753 	}
754 
755 	(void) fclose(fp);
756 	return (NULL);
757 }
758