xref: /openbsd-src/lib/libc/net/ethers.c (revision 42c35b4a87c621cdf23accebeadda321a489e883)
1 /*	$OpenBSD: ethers.c,v 1.17 2004/02/16 19:41:12 otto 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.17 2004/02/16 19:41:12 otto 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 	(void)snprintf(a, sizeof a, "%02x:%02x:%02x:%02x:%02x:%02x",
58 	    e->ether_addr_octet[0], e->ether_addr_octet[1],
59 	    e->ether_addr_octet[2], e->ether_addr_octet[3],
60 	    e->ether_addr_octet[4], e->ether_addr_octet[5]);
61 
62 	return (a);
63 }
64 
65 static char *
66 _ether_aton(s, e)
67 	char *s;
68 	struct ether_addr *e;
69 {
70 	int i;
71 	long l;
72 	char *pp;
73 
74 	while (isspace(*s))
75 		s++;
76 
77 	/* expect 6 hex octets separated by ':' or space/NUL if last octet */
78 	for (i = 0; i < 6; i++) {
79 		l = strtol(s, &pp, 16);
80 		if (pp == s || l > 0xFF || l < 0)
81 			return (NULL);
82 		if (!(*pp == ':' || (i == 5 && (isspace(*pp) || *pp == '\0'))))
83 			return (NULL);
84 		e->ether_addr_octet[i] = (u_char)l;
85 		s = pp + 1;
86 	}
87 
88 	/* return character after the octets ala strtol(3) */
89 	return (pp);
90 }
91 
92 struct ether_addr *
93 ether_aton(s)
94 	char *s;
95 {
96 	static struct ether_addr n;
97 
98 	return (_ether_aton(s, &n) ? &n : NULL);
99 }
100 
101 int
102 ether_ntohost(hostname, e)
103 	char *hostname;
104 	struct ether_addr *e;
105 {
106 	FILE *f;
107 	char buf[BUFSIZ+1], *p;
108 	size_t len;
109 	struct ether_addr try;
110 #ifdef YP
111 	char trybuf[sizeof("xx:xx:xx:xx:xx:xx")];
112 	int trylen;
113 #endif
114 
115 #ifdef YP
116 	snprintf(trybuf, sizeof trybuf, "%x:%x:%x:%x:%x:%x",
117 	    e->ether_addr_octet[0], e->ether_addr_octet[1],
118 	    e->ether_addr_octet[2], e->ether_addr_octet[3],
119 	    e->ether_addr_octet[4], e->ether_addr_octet[5]);
120 	trylen = strlen(trybuf);
121 #endif
122 
123 	f = fopen(_PATH_ETHERS, "r");
124 	if (f == NULL)
125 		return (-1);
126 	while ((p = fgetln(f, &len)) != NULL) {
127 		if (p[len-1] == '\n')
128 			len--;
129 		if (len > sizeof(buf) - 2)
130 			continue;
131 		(void)memcpy(buf, p, len);
132 		buf[len] = '\n';	/* code assumes newlines later on */
133 		buf[len+1] = '\0';
134 #ifdef YP
135 		/* A + in the file means try YP now.  */
136 		if (!strncmp(buf, "+\n", sizeof(buf))) {
137 			char *ypbuf, *ypdom;
138 			int ypbuflen;
139 
140 			if (yp_get_default_domain(&ypdom))
141 				continue;
142 			if (yp_match(ypdom, "ethers.byaddr", trybuf,
143 			    trylen, &ypbuf, &ypbuflen))
144 				continue;
145 			if (ether_line(ypbuf, &try, hostname) == 0) {
146 				free(ypbuf);
147 				(void)fclose(f);
148 				return (0);
149 			}
150 			free(ypbuf);
151 			continue;
152 		}
153 #endif
154 		if (ether_line(buf, &try, hostname) == 0 &&
155 		    memcmp((void *)&try, (void *)e, sizeof(try)) == 0) {
156 			(void)fclose(f);
157 			return (0);
158 		}
159 	}
160 	(void)fclose(f);
161 	errno = ENOENT;
162 	return (-1);
163 }
164 
165 int
166 ether_hostton(hostname, e)
167 	char *hostname;
168 	struct ether_addr *e;
169 {
170 	FILE *f;
171 	char buf[BUFSIZ+1], *p;
172 	char try[MAXHOSTNAMELEN];
173 	size_t len;
174 #ifdef YP
175 	int hostlen = strlen(hostname);
176 #endif
177 
178 	f = fopen(_PATH_ETHERS, "r");
179 	if (f==NULL)
180 		return (-1);
181 
182 	while ((p = fgetln(f, &len)) != NULL) {
183 		if (p[len-1] == '\n')
184 			len--;
185 		if (len > sizeof(buf) - 2)
186 			continue;
187 		memcpy(buf, p, len);
188 		buf[len] = '\n';	/* code assumes newlines later on */
189 		buf[len+1] = '\0';
190 #ifdef YP
191 		/* A + in the file means try YP now.  */
192 		if (!strncmp(buf, "+\n", sizeof(buf))) {
193 			char *ypbuf, *ypdom;
194 			int ypbuflen;
195 
196 			if (yp_get_default_domain(&ypdom))
197 				continue;
198 			if (yp_match(ypdom, "ethers.byname", hostname, hostlen,
199 			    &ypbuf, &ypbuflen))
200 				continue;
201 			if (ether_line(ypbuf, e, try) == 0) {
202 				free(ypbuf);
203 				(void)fclose(f);
204 				return (0);
205 			}
206 			free(ypbuf);
207 			continue;
208 		}
209 #endif
210 		if (ether_line(buf, e, try) == 0 && strcmp(hostname, try) == 0) {
211 			(void)fclose(f);
212 			return (0);
213 		}
214 	}
215 	(void)fclose(f);
216 	errno = ENOENT;
217 	return (-1);
218 }
219 
220 int
221 ether_line(line, e, hostname)
222 	char *line;
223 	struct ether_addr *e;
224 	char *hostname;
225 {
226 	char *p;
227 	size_t n;
228 
229 	/* Parse "xx:xx:xx:xx:xx:xx" */
230 	if ((p = _ether_aton(line, e)) == NULL || (*p != ' ' && *p != '\t'))
231 		goto bad;
232 
233 	/* Now get the hostname */
234 	while (isspace(*p))
235 		p++;
236 	if (*p == '\0')
237 		goto bad;
238 	n = strcspn(p, " \t\n");
239 	if (n >= MAXHOSTNAMELEN)
240 		goto bad;
241 	strlcpy(hostname, p, n + 1);
242 	return (0);
243 
244 bad:
245 	errno = EINVAL;
246 	return (-1);
247 }
248