1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <stdio.h> 30*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 31*7c478bd9Sstevel@tonic-gate #include <unistd.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 33*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 34*7c478bd9Sstevel@tonic-gate #include <net/if.h> 35*7c478bd9Sstevel@tonic-gate #include <netinet/dhcp.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 38*7c478bd9Sstevel@tonic-gate #include <time.h> 39*7c478bd9Sstevel@tonic-gate #include <string.h> /* memcpy */ 40*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 41*7c478bd9Sstevel@tonic-gate #include <limits.h> 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate #include "dhcp_hostconf.h" 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate static void relativize_time(DHCP_OPT *, time_t, time_t); 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* 48*7c478bd9Sstevel@tonic-gate * ifname_to_hostconf(): converts an interface name into a hostconf file for 49*7c478bd9Sstevel@tonic-gate * that interface 50*7c478bd9Sstevel@tonic-gate * 51*7c478bd9Sstevel@tonic-gate * input: const char *: the interface name 52*7c478bd9Sstevel@tonic-gate * output: char *: the hostconf filename 53*7c478bd9Sstevel@tonic-gate * note: uses an internal static buffer (not threadsafe) 54*7c478bd9Sstevel@tonic-gate */ 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate char * 57*7c478bd9Sstevel@tonic-gate ifname_to_hostconf(const char *ifname) 58*7c478bd9Sstevel@tonic-gate { 59*7c478bd9Sstevel@tonic-gate static char filename[sizeof (DHCP_HOSTCONF_TMPL) + IFNAMSIZ]; 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate (void) snprintf(filename, sizeof (filename), "%s%s%s", 62*7c478bd9Sstevel@tonic-gate DHCP_HOSTCONF_PREFIX, ifname, DHCP_HOSTCONF_SUFFIX); 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate return (filename); 65*7c478bd9Sstevel@tonic-gate } 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* 68*7c478bd9Sstevel@tonic-gate * remove_hostconf(): removes an interface.dhc file 69*7c478bd9Sstevel@tonic-gate * 70*7c478bd9Sstevel@tonic-gate * input: const char *: the interface name 71*7c478bd9Sstevel@tonic-gate * output: int: 0 if the file is removed, -1 if it can't be removed 72*7c478bd9Sstevel@tonic-gate * (errno is set) 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate int 76*7c478bd9Sstevel@tonic-gate remove_hostconf(const char *ifname) 77*7c478bd9Sstevel@tonic-gate { 78*7c478bd9Sstevel@tonic-gate return (unlink(ifname_to_hostconf(ifname))); 79*7c478bd9Sstevel@tonic-gate } 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* 82*7c478bd9Sstevel@tonic-gate * read_hostconf(): reads the contents of an <if>.dhc file into a PKT_LIST 83*7c478bd9Sstevel@tonic-gate * 84*7c478bd9Sstevel@tonic-gate * input: const char *: the interface name 85*7c478bd9Sstevel@tonic-gate * PKT_LIST **: a pointer to a PKT_LIST * to store the info in 86*7c478bd9Sstevel@tonic-gate * uint_t: the length of the list of PKT_LISTs 87*7c478bd9Sstevel@tonic-gate * output: int: 0 if the file is read and loaded into the PKT_LIST * 88*7c478bd9Sstevel@tonic-gate * successfully, -1 otherwise (errno is set) 89*7c478bd9Sstevel@tonic-gate * note: the PKT and PKT_LISTs are dynamically allocated here 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate int 93*7c478bd9Sstevel@tonic-gate read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen) 94*7c478bd9Sstevel@tonic-gate { 95*7c478bd9Sstevel@tonic-gate PKT_LIST *plp = NULL; 96*7c478bd9Sstevel@tonic-gate PKT *pkt = NULL; 97*7c478bd9Sstevel@tonic-gate int fd; 98*7c478bd9Sstevel@tonic-gate time_t orig_time, current_time = time(NULL); 99*7c478bd9Sstevel@tonic-gate uint32_t lease; 100*7c478bd9Sstevel@tonic-gate uint32_t magic; 101*7c478bd9Sstevel@tonic-gate int pcnt = 0; 102*7c478bd9Sstevel@tonic-gate int retval; 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate fd = open(ifname_to_hostconf(ifname), O_RDONLY); 105*7c478bd9Sstevel@tonic-gate if (fd == -1) 106*7c478bd9Sstevel@tonic-gate return (-1); 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate if (read(fd, &magic, sizeof (magic)) != sizeof (magic)) 109*7c478bd9Sstevel@tonic-gate goto failure; 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate if (magic != DHCP_HOSTCONF_MAGIC) 112*7c478bd9Sstevel@tonic-gate goto failure; 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate if (read(fd, &orig_time, sizeof (orig_time)) != sizeof (orig_time)) 115*7c478bd9Sstevel@tonic-gate goto failure; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* 118*7c478bd9Sstevel@tonic-gate * read the packet back in from disk, and run it through 119*7c478bd9Sstevel@tonic-gate * dhcp_options_scan(). note that we use calloc() since 120*7c478bd9Sstevel@tonic-gate * dhcp_options_scan() relies on the packet being zeroed. 121*7c478bd9Sstevel@tonic-gate */ 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate for (pcnt = 0; pcnt < plplen; pcnt++) { 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate plp = NULL; 126*7c478bd9Sstevel@tonic-gate pkt = NULL; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate if ((plp = calloc(1, sizeof (PKT_LIST))) == NULL) 129*7c478bd9Sstevel@tonic-gate goto failure; 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate retval = read(fd, &plp->len, sizeof (plp->len)); 132*7c478bd9Sstevel@tonic-gate if (retval == 0 && pcnt != 0) { 133*7c478bd9Sstevel@tonic-gate /* 134*7c478bd9Sstevel@tonic-gate * Reached end of file on a boundary, but after 135*7c478bd9Sstevel@tonic-gate * we've read at least one packet, so we consider 136*7c478bd9Sstevel@tonic-gate * this successful, allowing us to use files from 137*7c478bd9Sstevel@tonic-gate * older versions of the agent happily. 138*7c478bd9Sstevel@tonic-gate */ 139*7c478bd9Sstevel@tonic-gate free(plp); 140*7c478bd9Sstevel@tonic-gate break; 141*7c478bd9Sstevel@tonic-gate } else if (retval != sizeof (plp->len)) 142*7c478bd9Sstevel@tonic-gate goto failure; 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate if ((pkt = malloc(plp->len)) == NULL) 145*7c478bd9Sstevel@tonic-gate goto failure; 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate if (read(fd, pkt, plp->len) != plp->len) 148*7c478bd9Sstevel@tonic-gate goto failure; 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate plp->pkt = pkt; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate plpp[pcnt] = plp; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate if (dhcp_options_scan(plp, B_TRUE) != 0) 155*7c478bd9Sstevel@tonic-gate goto failure; 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate /* 158*7c478bd9Sstevel@tonic-gate * First packet used to validate that we're interested, 159*7c478bd9Sstevel@tonic-gate * the rest are presumed to be historical reference and 160*7c478bd9Sstevel@tonic-gate * are not relativized 161*7c478bd9Sstevel@tonic-gate */ 162*7c478bd9Sstevel@tonic-gate if (pcnt == 0) 163*7c478bd9Sstevel@tonic-gate continue; 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* 166*7c478bd9Sstevel@tonic-gate * make sure the lease is still valid. 167*7c478bd9Sstevel@tonic-gate */ 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate if (plp->opts[CD_LEASE_TIME] != NULL && 170*7c478bd9Sstevel@tonic-gate plp->opts[CD_LEASE_TIME]->len == sizeof (lease_t)) { 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate (void) memcpy(&lease, plp->opts[CD_LEASE_TIME]->value, 173*7c478bd9Sstevel@tonic-gate sizeof (lease_t)); 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate lease = ntohl(lease); 176*7c478bd9Sstevel@tonic-gate if ((lease != DHCP_PERM) && 177*7c478bd9Sstevel@tonic-gate (orig_time + lease) <= current_time) 178*7c478bd9Sstevel@tonic-gate goto failure; 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate relativize_time(plp->opts[CD_T1_TIME], orig_time, current_time); 182*7c478bd9Sstevel@tonic-gate relativize_time(plp->opts[CD_T2_TIME], orig_time, current_time); 183*7c478bd9Sstevel@tonic-gate relativize_time(plp->opts[CD_LEASE_TIME], orig_time, 184*7c478bd9Sstevel@tonic-gate current_time); 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate (void) close(fd); 188*7c478bd9Sstevel@tonic-gate return (pcnt); 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate failure: 191*7c478bd9Sstevel@tonic-gate free(pkt); 192*7c478bd9Sstevel@tonic-gate free(plp); 193*7c478bd9Sstevel@tonic-gate while (pcnt-- > 0) { 194*7c478bd9Sstevel@tonic-gate free(plpp[pcnt]->pkt); 195*7c478bd9Sstevel@tonic-gate free(plpp[pcnt]); 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate (void) close(fd); 198*7c478bd9Sstevel@tonic-gate return (-1); 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* 202*7c478bd9Sstevel@tonic-gate * write_hostconf(): writes the contents of a PKT_LIST into an <if>.dhc file 203*7c478bd9Sstevel@tonic-gate * 204*7c478bd9Sstevel@tonic-gate * input: const char *: the interface name 205*7c478bd9Sstevel@tonic-gate * PKT_LIST **: a list of pointers to PKT_LIST to write 206*7c478bd9Sstevel@tonic-gate * int: length of the list of PKT_LIST pointers 207*7c478bd9Sstevel@tonic-gate * time_t: a starting time to treat the relative lease times 208*7c478bd9Sstevel@tonic-gate * in the first packet as relative to 209*7c478bd9Sstevel@tonic-gate * output: int: 0 if the file is written successfully, -1 otherwise 210*7c478bd9Sstevel@tonic-gate * (errno is set) 211*7c478bd9Sstevel@tonic-gate */ 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate int 214*7c478bd9Sstevel@tonic-gate write_hostconf( 215*7c478bd9Sstevel@tonic-gate const char *ifname, 216*7c478bd9Sstevel@tonic-gate PKT_LIST *pl[], 217*7c478bd9Sstevel@tonic-gate uint_t pllen, 218*7c478bd9Sstevel@tonic-gate time_t relative_to) 219*7c478bd9Sstevel@tonic-gate { 220*7c478bd9Sstevel@tonic-gate int fd; 221*7c478bd9Sstevel@tonic-gate struct iovec iov[IOV_MAX]; 222*7c478bd9Sstevel@tonic-gate int retval; 223*7c478bd9Sstevel@tonic-gate uint32_t magic = DHCP_HOSTCONF_MAGIC; 224*7c478bd9Sstevel@tonic-gate ssize_t explen = 0; /* Expected length of write */ 225*7c478bd9Sstevel@tonic-gate int i, iovlen = 0; 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate fd = open(ifname_to_hostconf(ifname), O_WRONLY|O_CREAT|O_TRUNC, 0600); 228*7c478bd9Sstevel@tonic-gate if (fd == -1) 229*7c478bd9Sstevel@tonic-gate return (-1); 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate /* 232*7c478bd9Sstevel@tonic-gate * first write our magic number, then the relative time of the 233*7c478bd9Sstevel@tonic-gate * leases, then for each packet we write the length of the packet 234*7c478bd9Sstevel@tonic-gate * followed by the packet. we will then use the relative time in 235*7c478bd9Sstevel@tonic-gate * read_hostconf() to recalculate the lease times for the first packet. 236*7c478bd9Sstevel@tonic-gate */ 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate iov[iovlen].iov_base = (caddr_t)&magic; 239*7c478bd9Sstevel@tonic-gate explen += iov[iovlen++].iov_len = sizeof (magic); 240*7c478bd9Sstevel@tonic-gate iov[iovlen].iov_base = (caddr_t)&relative_to; 241*7c478bd9Sstevel@tonic-gate explen += iov[iovlen++].iov_len = sizeof (relative_to); 242*7c478bd9Sstevel@tonic-gate for (i = 0; i < pllen && iovlen < (IOV_MAX - 1); i++) { 243*7c478bd9Sstevel@tonic-gate iov[iovlen].iov_base = (caddr_t)&pl[i]->len; 244*7c478bd9Sstevel@tonic-gate explen += iov[iovlen++].iov_len = sizeof (pl[i]->len); 245*7c478bd9Sstevel@tonic-gate iov[iovlen].iov_base = (caddr_t)pl[i]->pkt; 246*7c478bd9Sstevel@tonic-gate explen += iov[iovlen++].iov_len = pl[i]->len; 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate retval = writev(fd, iov, iovlen); 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate (void) close(fd); 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate if (retval != explen) 254*7c478bd9Sstevel@tonic-gate return (-1); 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate return (0); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate /* 260*7c478bd9Sstevel@tonic-gate * relativize_time(): re-relativizes a time in a DHCP option 261*7c478bd9Sstevel@tonic-gate * 262*7c478bd9Sstevel@tonic-gate * input: DHCP_OPT *: the DHCP option parameter to convert 263*7c478bd9Sstevel@tonic-gate * time_t: the time the leases in the packet are currently relative to 264*7c478bd9Sstevel@tonic-gate * time_t: the current time which leases will become relative to 265*7c478bd9Sstevel@tonic-gate * output: void 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate static void 269*7c478bd9Sstevel@tonic-gate relativize_time(DHCP_OPT *option, time_t orig_time, time_t current_time) 270*7c478bd9Sstevel@tonic-gate { 271*7c478bd9Sstevel@tonic-gate uint32_t pkt_time; 272*7c478bd9Sstevel@tonic-gate time_t time_diff = current_time - orig_time; 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate if (option == NULL || option->len != sizeof (lease_t)) 275*7c478bd9Sstevel@tonic-gate return; 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate (void) memcpy(&pkt_time, option->value, option->len); 278*7c478bd9Sstevel@tonic-gate if (ntohl(pkt_time) != DHCP_PERM) 279*7c478bd9Sstevel@tonic-gate pkt_time = htonl(ntohl(pkt_time) - time_diff); 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate (void) memcpy(option->value, &pkt_time, option->len); 282*7c478bd9Sstevel@tonic-gate } 283