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