1/*	$NetBSD: ethers.c,v 1.24 2014/06/19 15:09:07 christos Exp $	*/
2
3/*
4 * ethers(3N) a la Sun.
5 *
6 * Written by Roland McGrath <roland@frob.com> 10/14/93.
7 * Public domain.
8 */
9
10#include <sys/cdefs.h>
11#if defined(LIBC_SCCS) && !defined(lint)
12__RCSID("$NetBSD: ethers.c,v 1.24 2014/06/19 15:09:07 christos Exp $");
13#endif /* LIBC_SCCS and not lint */
14
15#include "namespace.h"
16#include <sys/param.h>
17#include <sys/socket.h>
18
19#include <net/if.h>
20#include <net/if_ether.h>
21#include <netinet/in.h>
22
23#include <assert.h>
24#include <errno.h>
25#include <paths.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#ifdef YP
31#include <rpcsvc/ypclnt.h>
32#endif
33
34#ifdef __weak_alias
35__weak_alias(ether_aton,_ether_aton)
36__weak_alias(ether_hostton,_ether_hostton)
37__weak_alias(ether_line,_ether_line)
38__weak_alias(ether_ntoa,_ether_ntoa)
39__weak_alias(ether_ntohost,_ether_ntohost)
40#endif
41
42#ifndef _PATH_ETHERS
43#define _PATH_ETHERS "/etc/ethers"
44#endif
45
46char *
47ether_ntoa(const struct ether_addr *e)
48{
49	static char a[18];
50
51	_DIAGASSERT(e != NULL);
52
53	(void) snprintf(a, sizeof a, "%02x:%02x:%02x:%02x:%02x:%02x",
54	    e->ether_addr_octet[0], e->ether_addr_octet[1],
55	    e->ether_addr_octet[2], e->ether_addr_octet[3],
56	    e->ether_addr_octet[4], e->ether_addr_octet[5]);
57	return a;
58}
59
60struct ether_addr *
61ether_aton(const char *s)
62{
63	static struct ether_addr n;
64	u_int i[6];
65
66	_DIAGASSERT(s != NULL);
67
68	if (sscanf(s, " %x:%x:%x:%x:%x:%x ", &i[0], &i[1],
69	    &i[2], &i[3], &i[4], &i[5]) == 6) {
70		n.ether_addr_octet[0] = (u_char)i[0];
71		n.ether_addr_octet[1] = (u_char)i[1];
72		n.ether_addr_octet[2] = (u_char)i[2];
73		n.ether_addr_octet[3] = (u_char)i[3];
74		n.ether_addr_octet[4] = (u_char)i[4];
75		n.ether_addr_octet[5] = (u_char)i[5];
76		return &n;
77	}
78	return NULL;
79}
80
81int
82ether_ntohost(char *hostname, const struct ether_addr *e)
83{
84	FILE *f;
85	char *p;
86	struct ether_addr try;
87
88	_DIAGASSERT(hostname != NULL);
89	_DIAGASSERT(e != NULL);
90
91#ifdef YP
92	char trybuf[sizeof "xx:xx:xx:xx:xx:xx"];
93	int trylen;
94	trylen = snprintf(trybuf, sizeof trybuf, "%x:%x:%x:%x:%x:%x",
95	    e->ether_addr_octet[0], e->ether_addr_octet[1],
96	    e->ether_addr_octet[2], e->ether_addr_octet[3],
97	    e->ether_addr_octet[4], e->ether_addr_octet[5]);
98#endif
99
100	f = fopen(_PATH_ETHERS, "re");
101	if (f == NULL)
102		return -1;
103	for (p = NULL;;) {
104		free(p);
105		p = fparseln(f, NULL, NULL, NULL, FPARSELN_UNESCALL);
106		if (p == NULL)
107			break;
108#ifdef YP
109		/* A + in the file means try YP now.  */
110		if (strcmp(p, "+") == 0) {
111			char *ypbuf, *ypdom;
112			int ypbuflen;
113
114			if (yp_get_default_domain(&ypdom))
115				continue;
116			if (yp_match(ypdom, "ethers.byaddr", trybuf,
117			    trylen, &ypbuf, &ypbuflen))
118				continue;
119			ypbuflen = ether_line(ypbuf, &try, hostname);
120			free(ypbuf);
121			if (ypbuflen == 0)
122				goto done;
123			continue;
124		}
125#endif
126		if (ether_line(p, &try, hostname) == 0 &&
127		    memcmp(&try, e, sizeof try) == 0)
128			goto done;
129	}
130	free(p);
131	(void)fclose(f);
132	errno = ENOENT;
133	return -1;
134done:
135	free(p);
136	(void)fclose(f);
137	return 0;
138}
139
140int
141ether_hostton(const char *hostname, struct ether_addr *e)
142{
143	FILE *f;
144	char *p;
145	char try[MAXHOSTNAMELEN + 1];
146#ifdef YP
147	int hostlen = (int)strlen(hostname);
148#endif
149
150	_DIAGASSERT(hostname != NULL);
151	_DIAGASSERT(e != NULL);
152
153	f = fopen(_PATH_ETHERS, "re");
154	if (f == NULL)
155		return -1;
156
157	for (p = NULL;;) {
158		free(p);
159		p = fparseln(f, NULL, NULL, NULL, FPARSELN_UNESCALL);
160		if (p == NULL)
161			break;
162#ifdef YP
163		/* A + in the file means try YP now.  */
164		if (strcmp(p, "+") == 0) {
165			char *ypbuf, *ypdom;
166			int ypbuflen;
167
168			if (yp_get_default_domain(&ypdom))
169				continue;
170			if (yp_match(ypdom, "ethers.byname", hostname, hostlen,
171			    &ypbuf, &ypbuflen))
172				continue;
173			ypbuflen = ether_line(ypbuf, e, try);
174			free(ypbuf);
175			if (ypbuflen == 0)
176				goto done;
177			continue;
178		}
179#endif
180		if (ether_line(p, e, try) == 0 && strcmp(hostname, try) == 0)
181			goto done;
182	}
183	free(p);
184	(void)fclose(f);
185	errno = ENOENT;
186	return -1;
187done:
188	free(p);
189	(void)fclose(f);
190	return 0;
191}
192
193int
194ether_line(const char *l, struct ether_addr *e, char *hostname)
195{
196	u_int i[6];
197
198#define S2(arg) #arg
199#define S1(arg) S2(arg)
200	static const char fmt[] = " %x:%x:%x:%x:%x:%x"
201	    " %" S1(MAXHOSTNAMELEN) "s\n";
202#undef S2
203#undef S1
204
205	_DIAGASSERT(l != NULL);
206	_DIAGASSERT(e != NULL);
207	_DIAGASSERT(hostname != NULL);
208
209	if (sscanf(l, fmt,
210	    &i[0], &i[1], &i[2], &i[3], &i[4], &i[5], hostname) == 7) {
211		e->ether_addr_octet[0] = (u_char)i[0];
212		e->ether_addr_octet[1] = (u_char)i[1];
213		e->ether_addr_octet[2] = (u_char)i[2];
214		e->ether_addr_octet[3] = (u_char)i[3];
215		e->ether_addr_octet[4] = (u_char)i[4];
216		e->ether_addr_octet[5] = (u_char)i[5];
217		return 0;
218	}
219	errno = EINVAL;
220	return -1;
221}
222