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