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