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