1 /* $OpenBSD: ethers.c,v 1.20 2005/08/06 20:30:03 espie 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 <sys/param.h> 31 #include <paths.h> 32 #include <errno.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <ctype.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(*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 == ':' || (i == 5 && (isspace(*pp) || *pp == '\0')))) 76 return (NULL); 77 e->ether_addr_octet[i] = (u_char)l; 78 s = pp + 1; 79 } 80 81 /* return character after the octets ala strtol(3) */ 82 return (pp); 83 } 84 85 struct ether_addr * 86 ether_aton(const char *s) 87 { 88 static struct ether_addr n; 89 90 return (_ether_aton(s, &n) ? &n : NULL); 91 } 92 93 int 94 ether_ntohost(char *hostname, struct ether_addr *e) 95 { 96 FILE *f; 97 char buf[BUFSIZ+1], *p; 98 size_t len; 99 struct ether_addr try; 100 #ifdef YP 101 char trybuf[sizeof("xx:xx:xx:xx:xx:xx")]; 102 int trylen; 103 #endif 104 105 #ifdef YP 106 snprintf(trybuf, sizeof trybuf, "%x:%x:%x:%x:%x:%x", 107 e->ether_addr_octet[0], e->ether_addr_octet[1], 108 e->ether_addr_octet[2], e->ether_addr_octet[3], 109 e->ether_addr_octet[4], e->ether_addr_octet[5]); 110 trylen = strlen(trybuf); 111 #endif 112 113 f = fopen(_PATH_ETHERS, "r"); 114 if (f == NULL) 115 return (-1); 116 while ((p = fgetln(f, &len)) != NULL) { 117 if (p[len-1] == '\n') 118 len--; 119 if (len > sizeof(buf) - 2) 120 continue; 121 (void)memcpy(buf, p, len); 122 buf[len] = '\n'; /* code assumes newlines later on */ 123 buf[len+1] = '\0'; 124 #ifdef YP 125 /* A + in the file means try YP now. */ 126 if (!strncmp(buf, "+\n", sizeof(buf))) { 127 char *ypbuf, *ypdom; 128 int ypbuflen; 129 130 if (yp_get_default_domain(&ypdom)) 131 continue; 132 if (yp_match(ypdom, "ethers.byaddr", trybuf, 133 trylen, &ypbuf, &ypbuflen)) 134 continue; 135 if (ether_line(ypbuf, &try, hostname) == 0) { 136 free(ypbuf); 137 (void)fclose(f); 138 return (0); 139 } 140 free(ypbuf); 141 continue; 142 } 143 #endif 144 if (ether_line(buf, &try, hostname) == 0 && 145 memcmp((void *)&try, (void *)e, sizeof(try)) == 0) { 146 (void)fclose(f); 147 return (0); 148 } 149 } 150 (void)fclose(f); 151 errno = ENOENT; 152 return (-1); 153 } 154 155 int 156 ether_hostton(const char *hostname, struct ether_addr *e) 157 { 158 FILE *f; 159 char buf[BUFSIZ+1], *p; 160 char try[MAXHOSTNAMELEN]; 161 size_t len; 162 #ifdef YP 163 int hostlen = strlen(hostname); 164 #endif 165 166 f = fopen(_PATH_ETHERS, "r"); 167 if (f==NULL) 168 return (-1); 169 170 while ((p = fgetln(f, &len)) != NULL) { 171 if (p[len-1] == '\n') 172 len--; 173 if (len > sizeof(buf) - 2) 174 continue; 175 memcpy(buf, p, len); 176 buf[len] = '\n'; /* code assumes newlines later on */ 177 buf[len+1] = '\0'; 178 #ifdef YP 179 /* A + in the file means try YP now. */ 180 if (!strncmp(buf, "+\n", sizeof(buf))) { 181 char *ypbuf, *ypdom; 182 int ypbuflen; 183 184 if (yp_get_default_domain(&ypdom)) 185 continue; 186 if (yp_match(ypdom, "ethers.byname", hostname, hostlen, 187 &ypbuf, &ypbuflen)) 188 continue; 189 if (ether_line(ypbuf, e, try) == 0) { 190 free(ypbuf); 191 (void)fclose(f); 192 return (0); 193 } 194 free(ypbuf); 195 continue; 196 } 197 #endif 198 if (ether_line(buf, e, try) == 0 && strcmp(hostname, try) == 0) { 199 (void)fclose(f); 200 return (0); 201 } 202 } 203 (void)fclose(f); 204 errno = ENOENT; 205 return (-1); 206 } 207 208 int 209 ether_line(const char *line, struct ether_addr *e, char *hostname) 210 { 211 char *p; 212 size_t n; 213 214 /* Parse "xx:xx:xx:xx:xx:xx" */ 215 if ((p = _ether_aton(line, e)) == NULL || (*p != ' ' && *p != '\t')) 216 goto bad; 217 218 /* Now get the hostname */ 219 while (isspace(*p)) 220 p++; 221 if (*p == '\0') 222 goto bad; 223 n = strcspn(p, " \t\n"); 224 if (n >= MAXHOSTNAMELEN) 225 goto bad; 226 strlcpy(hostname, p, n + 1); 227 return (0); 228 229 bad: 230 errno = EINVAL; 231 return (-1); 232 } 233