xref: /openbsd/lib/libc/net/ethers.c (revision bf198cc6)
1 /*	$OpenBSD: ethers.c,v 1.27 2019/01/25 00:19:25 millert Exp $	*/
2 
3 /*
4  * Copyright (c) 1998 Todd C. Miller <millert@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * ethers(3) a la Sun.
21  * Originally Written by Roland McGrath <roland@frob.com> 10/14/93.
22  * Substantially modified by Todd C. Miller <millert@openbsd.org>
23  */
24 
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <net/if.h>
28 #include <netinet/in.h>
29 #include <netinet/if_ether.h>
30 #include <paths.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <limits.h>
37 
38 #ifndef _PATH_ETHERS
39 #define _PATH_ETHERS	"/etc/ethers"
40 #endif
41 
42 static char * _ether_aton(const char *, struct ether_addr *);
43 
44 char *
ether_ntoa(struct ether_addr * e)45 ether_ntoa(struct ether_addr *e)
46 {
47 	static char a[] = "xx:xx:xx:xx:xx:xx";
48 
49 	(void)snprintf(a, sizeof a, "%02x:%02x:%02x:%02x:%02x:%02x",
50 	    e->ether_addr_octet[0], e->ether_addr_octet[1],
51 	    e->ether_addr_octet[2], e->ether_addr_octet[3],
52 	    e->ether_addr_octet[4], e->ether_addr_octet[5]);
53 
54 	return (a);
55 }
56 
57 static char *
_ether_aton(const char * s,struct ether_addr * e)58 _ether_aton(const char *s, struct ether_addr *e)
59 {
60 	int i;
61 	long l;
62 	char *pp;
63 
64 	while (isspace((unsigned char)*s))
65 		s++;
66 
67 	/* expect 6 hex octets separated by ':' or space/NUL if last octet */
68 	for (i = 0; i < 6; i++) {
69 		l = strtol(s, &pp, 16);
70 		if (pp == s || l > 0xFF || l < 0)
71 			return (NULL);
72 		if (!(*pp == ':' ||
73 		    (i == 5 && (isspace((unsigned char)*pp) ||
74 		    *pp == '\0'))))
75 			return (NULL);
76 		e->ether_addr_octet[i] = (u_char)l;
77 		s = pp + 1;
78 	}
79 
80 	/* return character after the octets ala strtol(3) */
81 	return (pp);
82 }
83 
84 struct ether_addr *
ether_aton(const char * s)85 ether_aton(const char *s)
86 {
87 	static struct ether_addr n;
88 
89 	return (_ether_aton(s, &n) ? &n : NULL);
90 }
91 
92 int
ether_ntohost(char * hostname,struct ether_addr * e)93 ether_ntohost(char *hostname, struct ether_addr *e)
94 {
95 	FILE *f;
96 	char buf[BUFSIZ+1], *p;
97 	size_t len;
98 	struct ether_addr try;
99 
100 	f = fopen(_PATH_ETHERS, "re");
101 	if (f == NULL)
102 		return (-1);
103 	while ((p = fgetln(f, &len)) != NULL) {
104 		if (p[len-1] == '\n')
105 			len--;
106 		if (len > sizeof(buf) - 2)
107 			continue;
108 		(void)memcpy(buf, p, len);
109 		buf[len] = '\n';	/* code assumes newlines later on */
110 		buf[len+1] = '\0';
111 		/* A + in the file meant try YP, ignore it. */
112 		if (!strncmp(buf, "+\n", sizeof(buf)))
113 			continue;
114 		if (ether_line(buf, &try, hostname) == 0 &&
115 		    memcmp(&try, e, sizeof(try)) == 0) {
116 			(void)fclose(f);
117 			return (0);
118 		}
119 	}
120 	(void)fclose(f);
121 	errno = ENOENT;
122 	return (-1);
123 }
124 
125 int
ether_hostton(const char * hostname,struct ether_addr * e)126 ether_hostton(const char *hostname, struct ether_addr *e)
127 {
128 	FILE *f;
129 	char buf[BUFSIZ+1], *p;
130 	char try[HOST_NAME_MAX+1];
131 	size_t len;
132 
133 	f = fopen(_PATH_ETHERS, "re");
134 	if (f==NULL)
135 		return (-1);
136 
137 	while ((p = fgetln(f, &len)) != NULL) {
138 		if (p[len-1] == '\n')
139 			len--;
140 		if (len > sizeof(buf) - 2)
141 			continue;
142 		memcpy(buf, p, len);
143 		buf[len] = '\n';	/* code assumes newlines later on */
144 		buf[len+1] = '\0';
145 		/* A + in the file meant try YP, ignore it. */
146 		if (!strncmp(buf, "+\n", sizeof(buf)))
147 			continue;
148 		if (ether_line(buf, e, try) == 0 && strcmp(hostname, try) == 0) {
149 			(void)fclose(f);
150 			return (0);
151 		}
152 	}
153 	(void)fclose(f);
154 	errno = ENOENT;
155 	return (-1);
156 }
157 
158 int
ether_line(const char * line,struct ether_addr * e,char * hostname)159 ether_line(const char *line, struct ether_addr *e, char *hostname)
160 {
161 	char *p;
162 	size_t n;
163 
164 	/* Parse "xx:xx:xx:xx:xx:xx" */
165 	if ((p = _ether_aton(line, e)) == NULL || (*p != ' ' && *p != '\t'))
166 		goto bad;
167 
168 	/* Now get the hostname */
169 	while (isspace((unsigned char)*p))
170 		p++;
171 	if (*p == '\0')
172 		goto bad;
173 	n = strcspn(p, " \t\n");
174 	if (n >= HOST_NAME_MAX+1)
175 		goto bad;
176 	strlcpy(hostname, p, n + 1);
177 	return (0);
178 
179 bad:
180 	errno = EINVAL;
181 	return (-1);
182 }
183 DEF_WEAK(ether_line);
184