xref: /openbsd-src/lib/libc/net/ethers.c (revision 328f1f07242028b5b73191fde3c55ec0652eb60e)
1 /*	$OpenBSD: ethers.c,v 1.16 2003/06/17 21:56:24 millert Exp $	*/
2 
3 /*
4  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
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 <Todd.Miller@courtesan.com>
23  */
24 
25 #if defined(LIBC_SCCS) && !defined(lint)
26 static char rcsid[] = "$OpenBSD: ethers.c,v 1.16 2003/06/17 21:56:24 millert Exp $";
27 #endif /* LIBC_SCCS and not lint */
28 
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <net/if.h>
32 #include <netinet/in.h>
33 #include <netinet/if_ether.h>
34 #include <sys/param.h>
35 #include <paths.h>
36 #include <errno.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41 #ifdef YP
42 #include <rpcsvc/ypclnt.h>
43 #endif
44 
45 #ifndef _PATH_ETHERS
46 #define _PATH_ETHERS	"/etc/ethers"
47 #endif
48 
49 static char * _ether_aton(char *, struct ether_addr *);
50 
51 char *
52 ether_ntoa(e)
53 	struct ether_addr *e;
54 {
55 	static char a[] = "xx:xx:xx:xx:xx:xx";
56 
57 	if (e->ether_addr_octet[0] > 0xFF || e->ether_addr_octet[1] > 0xFF ||
58 	    e->ether_addr_octet[2] > 0xFF || e->ether_addr_octet[3] > 0xFF ||
59 	    e->ether_addr_octet[4] > 0xFF || e->ether_addr_octet[5] > 0xFF) {
60 		errno = EINVAL;
61 		return (NULL);
62 	}
63 
64 	(void)snprintf(a, sizeof a, "%02x:%02x:%02x:%02x:%02x:%02x",
65 	    e->ether_addr_octet[0], e->ether_addr_octet[1],
66 	    e->ether_addr_octet[2], e->ether_addr_octet[3],
67 	    e->ether_addr_octet[4], e->ether_addr_octet[5]);
68 
69 	return (a);
70 }
71 
72 static char *
73 _ether_aton(s, e)
74 	char *s;
75 	struct ether_addr *e;
76 {
77 	int i;
78 	long l;
79 	char *pp;
80 
81 	while (isspace(*s))
82 		s++;
83 
84 	/* expect 6 hex octets separated by ':' or space/NUL if last octet */
85 	for (i = 0; i < 6; i++) {
86 		l = strtol(s, &pp, 16);
87 		if (pp == s || l > 0xFF || l < 0)
88 			return (NULL);
89 		if (!(*pp == ':' || (i == 5 && (isspace(*pp) || *pp == '\0'))))
90 			return (NULL);
91 		e->ether_addr_octet[i] = (u_char)l;
92 		s = pp + 1;
93 	}
94 
95 	/* return character after the octets ala strtol(3) */
96 	return (pp);
97 }
98 
99 struct ether_addr *
100 ether_aton(s)
101 	char *s;
102 {
103 	static struct ether_addr n;
104 
105 	return (_ether_aton(s, &n) ? &n : NULL);
106 }
107 
108 int
109 ether_ntohost(hostname, e)
110 	char *hostname;
111 	struct ether_addr *e;
112 {
113 	FILE *f;
114 	char buf[BUFSIZ+1], *p;
115 	size_t len;
116 	struct ether_addr try;
117 #ifdef YP
118 	char trybuf[sizeof("xx:xx:xx:xx:xx:xx")];
119 	int trylen;
120 #endif
121 
122 	if (e->ether_addr_octet[0] > 0xFF || e->ether_addr_octet[1] > 0xFF ||
123 	    e->ether_addr_octet[2] > 0xFF || e->ether_addr_octet[3] > 0xFF ||
124 	    e->ether_addr_octet[4] > 0xFF || e->ether_addr_octet[5] > 0xFF) {
125 		errno = EINVAL;
126 		return (-1);
127 	}
128 
129 #ifdef YP
130 	snprintf(trybuf, sizeof trybuf, "%x:%x:%x:%x:%x:%x",
131 	    e->ether_addr_octet[0], e->ether_addr_octet[1],
132 	    e->ether_addr_octet[2], e->ether_addr_octet[3],
133 	    e->ether_addr_octet[4], e->ether_addr_octet[5]);
134 	trylen = strlen(trybuf);
135 #endif
136 
137 	f = fopen(_PATH_ETHERS, "r");
138 	if (f == NULL)
139 		return (-1);
140 	while ((p = fgetln(f, &len)) != NULL) {
141 		if (p[len-1] == '\n')
142 			len--;
143 		if (len > sizeof(buf) - 2)
144 			continue;
145 		(void)memcpy(buf, p, len);
146 		buf[len] = '\n';	/* code assumes newlines later on */
147 		buf[len+1] = '\0';
148 #ifdef YP
149 		/* A + in the file means try YP now.  */
150 		if (!strncmp(buf, "+\n", sizeof(buf))) {
151 			char *ypbuf, *ypdom;
152 			int ypbuflen;
153 
154 			if (yp_get_default_domain(&ypdom))
155 				continue;
156 			if (yp_match(ypdom, "ethers.byaddr", trybuf,
157 			    trylen, &ypbuf, &ypbuflen))
158 				continue;
159 			if (ether_line(ypbuf, &try, hostname) == 0) {
160 				free(ypbuf);
161 				(void)fclose(f);
162 				return (0);
163 			}
164 			free(ypbuf);
165 			continue;
166 		}
167 #endif
168 		if (ether_line(buf, &try, hostname) == 0 &&
169 		    memcmp((void *)&try, (void *)e, sizeof(try)) == 0) {
170 			(void)fclose(f);
171 			return (0);
172 		}
173 	}
174 	(void)fclose(f);
175 	errno = ENOENT;
176 	return (-1);
177 }
178 
179 int
180 ether_hostton(hostname, e)
181 	char *hostname;
182 	struct ether_addr *e;
183 {
184 	FILE *f;
185 	char buf[BUFSIZ+1], *p;
186 	char try[MAXHOSTNAMELEN];
187 	size_t len;
188 #ifdef YP
189 	int hostlen = strlen(hostname);
190 #endif
191 
192 	f = fopen(_PATH_ETHERS, "r");
193 	if (f==NULL)
194 		return (-1);
195 
196 	while ((p = fgetln(f, &len)) != NULL) {
197 		if (p[len-1] == '\n')
198 			len--;
199 		if (len > sizeof(buf) - 2)
200 			continue;
201 		memcpy(buf, p, len);
202 		buf[len] = '\n';	/* code assumes newlines later on */
203 		buf[len+1] = '\0';
204 #ifdef YP
205 		/* A + in the file means try YP now.  */
206 		if (!strncmp(buf, "+\n", sizeof(buf))) {
207 			char *ypbuf, *ypdom;
208 			int ypbuflen;
209 
210 			if (yp_get_default_domain(&ypdom))
211 				continue;
212 			if (yp_match(ypdom, "ethers.byname", hostname, hostlen,
213 			    &ypbuf, &ypbuflen))
214 				continue;
215 			if (ether_line(ypbuf, e, try) == 0) {
216 				free(ypbuf);
217 				(void)fclose(f);
218 				return (0);
219 			}
220 			free(ypbuf);
221 			continue;
222 		}
223 #endif
224 		if (ether_line(buf, e, try) == 0 && strcmp(hostname, try) == 0) {
225 			(void)fclose(f);
226 			return (0);
227 		}
228 	}
229 	(void)fclose(f);
230 	errno = ENOENT;
231 	return (-1);
232 }
233 
234 int
235 ether_line(line, e, hostname)
236 	char *line;
237 	struct ether_addr *e;
238 	char *hostname;
239 {
240 	char *p;
241 	size_t n;
242 
243 	/* Parse "xx:xx:xx:xx:xx:xx" */
244 	if ((p = _ether_aton(line, e)) == NULL || (*p != ' ' && *p != '\t'))
245 		goto bad;
246 
247 	/* Now get the hostname */
248 	while (isspace(*p))
249 		p++;
250 	if (*p == '\0')
251 		goto bad;
252 	n = strcspn(p, " \t\n");
253 	if (n >= MAXHOSTNAMELEN)
254 		goto bad;
255 	strlcpy(hostname, p, n + 1);
256 	return (0);
257 
258 bad:
259 	errno = EINVAL;
260 	return (-1);
261 }
262