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