1 /* $OpenBSD: ethers.c,v 1.27 2019/01/25 00:19:25 millert Exp $ */ 2 3 /* 4 * Copyright (c) 1998 Todd C. Miller <millert@openbsd.org> 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 <millert@openbsd.org> 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 38 #ifndef _PATH_ETHERS 39 #define _PATH_ETHERS "/etc/ethers" 40 #endif 41 42 static char * _ether_aton(const char *, struct ether_addr *); 43 44 char * 45 ether_ntoa(struct ether_addr *e) 46 { 47 static char a[] = "xx:xx:xx:xx:xx:xx"; 48 49 (void)snprintf(a, sizeof a, "%02x:%02x:%02x:%02x:%02x:%02x", 50 e->ether_addr_octet[0], e->ether_addr_octet[1], 51 e->ether_addr_octet[2], e->ether_addr_octet[3], 52 e->ether_addr_octet[4], e->ether_addr_octet[5]); 53 54 return (a); 55 } 56 57 static char * 58 _ether_aton(const char *s, struct ether_addr *e) 59 { 60 int i; 61 long l; 62 char *pp; 63 64 while (isspace((unsigned char)*s)) 65 s++; 66 67 /* expect 6 hex octets separated by ':' or space/NUL if last octet */ 68 for (i = 0; i < 6; i++) { 69 l = strtol(s, &pp, 16); 70 if (pp == s || l > 0xFF || l < 0) 71 return (NULL); 72 if (!(*pp == ':' || 73 (i == 5 && (isspace((unsigned char)*pp) || 74 *pp == '\0')))) 75 return (NULL); 76 e->ether_addr_octet[i] = (u_char)l; 77 s = pp + 1; 78 } 79 80 /* return character after the octets ala strtol(3) */ 81 return (pp); 82 } 83 84 struct ether_addr * 85 ether_aton(const char *s) 86 { 87 static struct ether_addr n; 88 89 return (_ether_aton(s, &n) ? &n : NULL); 90 } 91 92 int 93 ether_ntohost(char *hostname, struct ether_addr *e) 94 { 95 FILE *f; 96 char buf[BUFSIZ+1], *p; 97 size_t len; 98 struct ether_addr try; 99 100 f = fopen(_PATH_ETHERS, "re"); 101 if (f == NULL) 102 return (-1); 103 while ((p = fgetln(f, &len)) != NULL) { 104 if (p[len-1] == '\n') 105 len--; 106 if (len > sizeof(buf) - 2) 107 continue; 108 (void)memcpy(buf, p, len); 109 buf[len] = '\n'; /* code assumes newlines later on */ 110 buf[len+1] = '\0'; 111 /* A + in the file meant try YP, ignore it. */ 112 if (!strncmp(buf, "+\n", sizeof(buf))) 113 continue; 114 if (ether_line(buf, &try, hostname) == 0 && 115 memcmp(&try, e, sizeof(try)) == 0) { 116 (void)fclose(f); 117 return (0); 118 } 119 } 120 (void)fclose(f); 121 errno = ENOENT; 122 return (-1); 123 } 124 125 int 126 ether_hostton(const char *hostname, struct ether_addr *e) 127 { 128 FILE *f; 129 char buf[BUFSIZ+1], *p; 130 char try[HOST_NAME_MAX+1]; 131 size_t len; 132 133 f = fopen(_PATH_ETHERS, "re"); 134 if (f==NULL) 135 return (-1); 136 137 while ((p = fgetln(f, &len)) != NULL) { 138 if (p[len-1] == '\n') 139 len--; 140 if (len > sizeof(buf) - 2) 141 continue; 142 memcpy(buf, p, len); 143 buf[len] = '\n'; /* code assumes newlines later on */ 144 buf[len+1] = '\0'; 145 /* A + in the file meant try YP, ignore it. */ 146 if (!strncmp(buf, "+\n", sizeof(buf))) 147 continue; 148 if (ether_line(buf, e, try) == 0 && strcmp(hostname, try) == 0) { 149 (void)fclose(f); 150 return (0); 151 } 152 } 153 (void)fclose(f); 154 errno = ENOENT; 155 return (-1); 156 } 157 158 int 159 ether_line(const char *line, struct ether_addr *e, char *hostname) 160 { 161 char *p; 162 size_t n; 163 164 /* Parse "xx:xx:xx:xx:xx:xx" */ 165 if ((p = _ether_aton(line, e)) == NULL || (*p != ' ' && *p != '\t')) 166 goto bad; 167 168 /* Now get the hostname */ 169 while (isspace((unsigned char)*p)) 170 p++; 171 if (*p == '\0') 172 goto bad; 173 n = strcspn(p, " \t\n"); 174 if (n >= HOST_NAME_MAX+1) 175 goto bad; 176 strlcpy(hostname, p, n + 1); 177 return (0); 178 179 bad: 180 errno = EINVAL; 181 return (-1); 182 } 183 DEF_WEAK(ether_line); 184