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