1/* 2 * Copyright (c) 2000-2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * DHCPServer.c 26 */ 27/* 28 * Modification History 29 * 30 * November 10, 2000 Dieter Siegmund (dieter@apple.com) 31 * - initial revision 32 */ 33 34#include <unistd.h> 35#include <stdlib.h> 36#include <stdio.h> 37#include <sys/types.h> 38#include <sys/time.h> 39#include <CoreFoundation/CoreFoundation.h> 40#include "NICache.h" 41#include "NICachePrivate.h" 42#include "netinfo.h" 43#include "bsdp.h" 44#include "DHCPServer.h" 45 46const char * DHCPSDHCPLeaseListNotificationKey = DHCPD_LEASES_NOTIFICATION_KEY; 47 48const char * DHCPSDisabledInterfacesNotificationKey = DHCPD_DISABLED_INTERFACES_NOTIFICATION_KEY; 49 50 51const CFStringRef kDHCPSPropName = CFSTR(NIPROP_NAME); 52const CFStringRef kDHCPSPropIdentifier = CFSTR(NIPROP_IDENTIFIER); 53 54const CFStringRef kDHCPSPropDHCPHWAddress = CFSTR(NIPROP_HWADDR); 55const CFStringRef kDHCPSPropDHCPIPAddress = CFSTR(NIPROP_IPADDR); 56const CFStringRef kDHCPSPropDHCPLease = CFSTR(NIPROP_DHCP_LEASE); 57#if ! TARGET_OS_EMBEDDED 58const CFStringRef kDHCPSPropNetBootArch = CFSTR(NIPROP_NETBOOT_ARCH); 59const CFStringRef kDHCPSPropNetBootSysid = CFSTR(NIPROP_NETBOOT_SYSID); 60const CFStringRef kDHCPSPropNetBootLastBootTime = CFSTR(NIPROP_NETBOOT_LAST_BOOT_TIME); 61const CFStringRef kDHCPSPropNetBootIPAddress = CFSTR(NIPROP_IPADDR); 62const CFStringRef kDHCPSPropNetBootImageID = CFSTR(NIPROP_NETBOOT_IMAGE_ID); 63const CFStringRef kDHCPSPropNetBootImageIndex = CFSTR(NIPROP_NETBOOT_IMAGE_INDEX); 64const CFStringRef kDHCPSPropNetBootImageKind = CFSTR(NIPROP_NETBOOT_IMAGE_KIND); 65const CFStringRef kDHCPSPropNetBootImageIsInstall = CFSTR(NIPROP_NETBOOT_IMAGE_IS_INSTALL); 66#endif /* ! TARGET_OS_EMBEDDED */ 67 68static CFStringRef 69create_cfstring(const char * name) 70{ 71 CFStringRef str; 72 73 str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); 74 if (str == NULL) { 75 str = CFStringCreateWithCString(NULL, name, kCFStringEncodingMacRoman); 76 } 77 return (str); 78} 79 80static CFMutableArrayRef 81host_list_copy(const char * filename) 82{ 83 CFMutableArrayRef arr = NULL; 84 PLCache_t cache; 85 PLCacheEntry_t * scan; 86 87 PLCache_init(&cache); 88#define ARBITRARILY_LARGE_NUMBER (100 * 1024 * 1024) 89 PLCache_set_max(&cache, ARBITRARILY_LARGE_NUMBER); 90 if (PLCache_read(&cache, filename) == FALSE) { 91 return (NULL); 92 } 93 94 arr = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 95 for (scan = cache.head; scan != NULL; scan = scan->next) { 96 int i; 97 CFMutableDictionaryRef dict = NULL; 98 ni_proplist * pl = &scan->pl; 99 100 if (pl->ni_proplist_len == 0) { 101 continue; 102 } 103 for (i = 0; i < pl->ni_proplist_len; i++) { 104 CFStringRef name; 105 ni_property * prop; 106 CFStringRef val; 107 108 prop = pl->nipl_val + i; 109 if (prop->nip_val.ninl_len == 0) { 110 continue; 111 } 112 if (dict == NULL) { 113 dict = CFDictionaryCreateMutable(NULL, 0, 114 &kCFTypeDictionaryKeyCallBacks, 115 &kCFTypeDictionaryValueCallBacks); 116 } 117 name = create_cfstring(prop->nip_name); 118 val = create_cfstring(prop->nip_val.ninl_val[0]); 119 if (name != NULL && val != NULL) { 120 CFDictionarySetValue(dict, name, val); 121 } 122 if (name != NULL) { 123 CFRelease(name); 124 } 125 if (val != NULL) { 126 CFRelease(val); 127 } 128 } 129 if (dict != NULL) { 130 CFArrayAppendValue(arr, dict); 131 CFRelease(dict); 132 } 133 } 134 if (CFArrayGetCount(arr) == 0) { 135 CFRelease(arr); 136 arr = NULL; 137 } 138 PLCache_free(&cache); 139 return (arr); 140} 141 142static int 143cfstring_to_cstring(CFStringRef cfstr, char * str, int len) 144{ 145 CFIndex l; 146 CFRange range; 147 148 range = CFRangeMake(0, CFStringGetLength(cfstr)); 149 (void)CFStringGetBytes(cfstr, range, kCFStringEncodingMacRoman, 150 0, FALSE, (UInt8 *)str, len, &l); 151 str[l] = '\0'; 152 return (l); 153} 154 155#ifdef TEST_DHCPHOSTLIST 156static void 157dump_gregorian_date(CFGregorianDate d) 158{ 159 printf("%d/%d/%d %d:%d:%d\n", 160 (int)d.year, d.month, d.day, d.hour, d.minute, (int)d.second); 161 return; 162} 163 164static void 165show_date(CFAbsoluteTime t) 166{ 167 CFGregorianDate d; 168 static CFTimeZoneRef tz = NULL; 169 170 if (tz == NULL) { 171 tz = CFTimeZoneCopySystem(); 172 } 173 174 d = CFAbsoluteTimeGetGregorianDate(t, tz); 175 dump_gregorian_date(d); 176 return; 177} 178#endif /* TEST_DHCPHOSTLIST */ 179 180static CFArrayRef 181cook_for_dhcp(CFArrayRef arr) 182{ 183 int count; 184 int i; 185 CFAbsoluteTime now_cf; 186 struct timeval now; 187 188 gettimeofday(&now, 0); 189 now_cf = CFAbsoluteTimeGetCurrent(); 190 191 count = CFArrayGetCount(arr); 192 for (i = 0; i < count; i++) { 193 char buf[128]; 194 CFDateRef expiration; 195 long lease_val = 0; 196 long lease_delta = 0; 197 CFStringRef lease; 198 CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(arr, i); 199 200 lease = CFDictionaryGetValue(dict, kDHCPSPropDHCPLease); 201 if (lease) { 202 cfstring_to_cstring(lease, buf, sizeof(buf)); 203 lease_val = strtol(buf, 0, 0); 204 lease_delta = lease_val - now.tv_sec; 205#ifdef TEST_DHCPHOSTLIST 206 { 207 CFAbsoluteTime abs_exp; 208 abs_exp = lease_delta + now_cf; 209 show_date(abs_exp); 210 } 211#endif /* TEST_DHCPHOSTLIST */ 212 expiration = CFDateCreate(NULL, lease_delta + now_cf); 213 CFDictionarySetValue(dict, kDHCPSPropDHCPLease, 214 expiration); 215 CFRelease(expiration); 216 } 217 } 218 return (arr); 219} 220 221#if ! TARGET_OS_EMBEDDED 222static CFArrayRef 223cook_for_netboot(CFArrayRef arr) 224{ 225 int count; 226 int i; 227 CFAbsoluteTime now_cf; 228 struct timeval now; 229 230 gettimeofday(&now, 0); 231 now_cf = CFAbsoluteTimeGetCurrent(); 232 233 count = CFArrayGetCount(arr); 234 for (i = 0; i < count; i++) { 235 CFMutableDictionaryRef dict; 236 char buf[128]; 237 CFStringRef image_id_str; 238 uint32_t image_id; 239 CFDateRef last_boot_time; 240 long last_boot_val = 0; 241 long last_boot_delta = 0; 242 CFStringRef last_boot_time_str; 243 244 dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(arr, i); 245 last_boot_time_str 246 = CFDictionaryGetValue(dict, kDHCPSPropNetBootLastBootTime); 247 if (last_boot_time_str) { 248 cfstring_to_cstring(last_boot_time_str, buf, sizeof(buf)); 249 last_boot_val = strtol(buf, 0, 0); 250 last_boot_delta = last_boot_val - now.tv_sec; 251#ifdef TEST_DHCPHOSTLIST 252 { 253 CFAbsoluteTime abs_exp; 254 abs_exp = last_boot_delta + now_cf; 255 show_date(abs_exp); 256 } 257#endif /* TEST_DHCPHOSTLIST */ 258 last_boot_time = CFDateCreate(NULL, last_boot_delta + now_cf); 259 CFDictionarySetValue(dict, kDHCPSPropNetBootLastBootTime, 260 last_boot_time); 261 CFRelease(last_boot_time); 262 } 263 image_id_str = CFDictionaryGetValue(dict, kDHCPSPropNetBootImageID); 264 if (image_id_str != NULL) { 265 CFNumberRef num; 266 uint32_t image_attrs; 267 uint32_t image_index; 268 uint32_t image_kind; 269 270 cfstring_to_cstring(image_id_str, buf, sizeof(buf)); 271 image_id = strtoul(buf, NULL, 0); 272 image_attrs = bsdp_image_attributes(image_id); 273 image_index = bsdp_image_index(image_id); 274 image_kind = bsdp_image_kind_from_attributes(image_attrs); 275 276 /* set the Index */ 277 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &image_index); 278 CFDictionarySetValue(dict, kDHCPSPropNetBootImageIndex, num); 279 CFRelease(num); 280 281 /* set the Kind */ 282 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &image_kind); 283 CFDictionarySetValue(dict, kDHCPSPropNetBootImageKind, num); 284 CFRelease(num); 285 286 /* set IsInstall */ 287 if (bsdp_image_identifier_is_install(image_id)) { 288 CFDictionarySetValue(dict, kDHCPSPropNetBootImageIsInstall, 289 kCFBooleanTrue); 290 } 291 else { 292 CFDictionarySetValue(dict, kDHCPSPropNetBootImageIsInstall, 293 kCFBooleanFalse); 294 } 295 } 296 } 297 return (arr); 298} 299#endif /* ! TARGET_OS_EMBEDDED */ 300 301CFArrayRef 302DHCPSDHCPLeaseListCreate() 303{ 304 CFArrayRef arr; 305 306 arr = host_list_copy("/var/db/dhcpd_leases"); 307 if (arr == NULL) { 308 return (NULL); 309 } 310 311 if (cook_for_dhcp(arr) == NULL) { 312 CFRelease(arr); 313 return (NULL); 314 } 315 return (arr); 316} 317 318#if ! TARGET_OS_EMBEDDED 319CFArrayRef 320DHCPSNetBootClientListCreate() 321{ 322 CFArrayRef arr; 323 324 arr = host_list_copy("/var/db/bsdpd_clients"); 325 if (arr == NULL) { 326 return (NULL); 327 } 328 if (cook_for_netboot(arr) == NULL) { 329 CFRelease(arr); 330 return (NULL); 331 } 332 return (arr); 333} 334#endif /* ! TARGET_OS_EMBEDDED */ 335 336#include <SystemConfiguration/SystemConfiguration.h> 337 338CFArrayRef 339DHCPSCopyDisabledInterfaces(void) 340{ 341 CFDictionaryRef dict; 342 CFArrayRef list = NULL; 343 344 dict = SCDynamicStoreCopyValue(NULL, CFSTR(DHCPD_DYNAMIC_STORE_KEY)); 345 if (dict != NULL) { 346 list = CFDictionaryGetValue(dict, CFSTR(DHCPD_DISABLED_INTERFACES)); 347 if (list != NULL) { 348 CFRetain(list); 349 } 350 CFRelease(dict); 351 } 352 return (list); 353} 354 355#ifdef TEST_DHCPHOSTLIST 356int 357main(int argc, char * argv[]) 358{ 359 CFArrayRef arr; 360 361 arr = DHCPSDHCPLeaseListCreate(); 362 if (arr) { 363 printf("DHCP Clients\n"); 364 CFShow(arr); 365 CFRelease(arr); 366 } 367 arr = DHCPSNetBootClientListCreate(); 368 if (arr) { 369 printf("\nNetBoot Clients\n"); 370 CFShow(arr); 371 CFRelease(arr); 372 } 373 exit(0); 374} 375#endif /* TEST_DHCPHOSTLIST */ 376