1/* 2 * Copyright (c) 2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <stdio.h> 30 31#include <CoreFoundation/CoreFoundation.h> 32 33#include <kxld.h> 34 35#define kCFBundleGetInfoStringKey CFSTR("CFBundleGetInfoString") 36#define kNSHumanReadableCopyrightKey CFSTR("NSHumanReadableCopyright") 37 38const char *gProgname = NULL; 39 40static void usage(void); 41static void printFormat(void); 42static char *convert_cfstring(CFStringRef the_string); 43 44/****************************************************************************** 45******************************************************************************/ 46static void 47usage(void) 48{ 49 printf("usage: %s [path to kext]\n\n" 50 "This program validates the copyright string in a kext's info " 51 "dictionary.\n\n", gProgname); 52 53 printFormat(); 54} 55 56/****************************************************************************** 57******************************************************************************/ 58static void 59printFormat(void) 60{ 61 fprintf(stderr, 62 "The copyright string should be contained in the NSHumanReadableCopyright key.\n" 63 "It should be of the format:\n" 64 "\tCopyright © [year(s) of publication] Apple Inc. All rights reserved.\n\n" 65 "where [year(s) of publication] is a comma-separated list of years and/or\n" 66 "year ranges, e.g., 2004, 2006-2008. Years must be four digits. Year ranges\n" 67 "may not contain spaces and must use four digits for both years.\n\n" 68 "The following are examples of valid copyright strings:\n" 69 "\tCopyright © 2008 Apple Inc. All rights reserved.\n" 70 "\tCopyright © 2004-2008 Apple Inc. All rights reserved.\n" 71 "\tCopyright © 1998,2000-2002,2004,2006-2008 Apple Inc. All rights reserved.\n"); 72} 73 74/****************************************************************************** 75******************************************************************************/ 76char * 77convert_cfstring(CFStringRef the_string) 78{ 79 char *result = NULL; 80 CFDataRef the_data = NULL; 81 const UInt8 *data_bytes = NULL; 82 char *converted_string = NULL; 83 u_long converted_len = 0; 84 u_long bytes_copied = 0; 85 86 the_data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, 87 the_string, kCFStringEncodingUTF8, 0); 88 if (!the_data) { 89 fprintf(stderr, "Failed to convert string\n"); 90 goto finish; 91 } 92 93 data_bytes = CFDataGetBytePtr(the_data); 94 if (!data_bytes) { 95 fprintf(stderr, "Failed to get converted string bytes\n"); 96 goto finish; 97 } 98 99 converted_len = strlen((const char *)data_bytes) + 1; // +1 for nul 100 converted_string = malloc(converted_len); 101 if (!converted_string) { 102 fprintf(stderr, "Failed to allocate memory\n"); 103 goto finish; 104 } 105 106 bytes_copied = strlcpy(converted_string, (const char *) data_bytes, 107 converted_len) + 1; // +1 for nul 108 if (bytes_copied != converted_len) { 109 fprintf(stderr, "Failed to copy converted string\n"); 110 goto finish; 111 } 112 113 result = converted_string; 114finish: 115 CFRelease(the_data); 116 return result; 117} 118 119/****************************************************************************** 120******************************************************************************/ 121int 122main(int argc, const char *argv[]) 123{ 124 int result = 1; 125 boolean_t infoCopyrightIsValid = false; 126 boolean_t readableCopyrightIsValid = false; 127 CFURLRef anURL = NULL; // must release 128 CFBundleRef aBundle = NULL; // must release 129 CFDictionaryRef aDict = NULL; // do not release 130 CFStringRef infoCopyrightString = NULL; // do not release 131 CFStringRef readableCopyrightString = NULL; // do not release 132 char *infoStr = NULL; // must free 133 char *readableStr = NULL; // must free 134 135 gProgname = argv[0]; 136 137 if (argc != 2) { 138 usage(); 139 goto finish; 140 } 141 142 anURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 143 (const UInt8 *) argv[1], strlen(argv[1]), /* isDirectory */ FALSE); 144 if (!anURL) { 145 fprintf(stderr, "Can't create path from %s\n", argv[1]); 146 goto finish; 147 } 148 149 aBundle = CFBundleCreate(kCFAllocatorDefault, anURL); 150 if (!aBundle) { 151 fprintf(stderr, "Can't create bundle at path %s\n", argv[1]); 152 goto finish; 153 } 154 155 aDict = CFBundleGetInfoDictionary(aBundle); 156 if (!aDict) { 157 fprintf(stderr, "Can't get info dictionary from bundle\n"); 158 goto finish; 159 } 160 161 infoCopyrightString = CFDictionaryGetValue(aDict, kCFBundleGetInfoStringKey); 162 readableCopyrightString = CFDictionaryGetValue(aDict, kNSHumanReadableCopyrightKey); 163 164 if (!infoCopyrightString && !readableCopyrightString) { 165 fprintf(stderr, "This kext does not have a value for NSHumanReadableCopyright"); 166 goto finish; 167 } 168 169 if (infoCopyrightString) { 170 fprintf(stderr, "Warning: This kext has a value for CFBundleGetInfoString.\n" 171 "This key is obsolete, and may be removed from the kext's Info.plist.\n" 172 "It has been replaced by CFBundleVersion and NSHumanReadableCopyright.\n\n"); 173 174 infoStr = convert_cfstring(infoCopyrightString); 175 if (!infoStr) goto finish; 176 177 infoCopyrightIsValid = kxld_validate_copyright_string(infoStr); 178 } 179 180 if (readableCopyrightString) { 181 readableStr = convert_cfstring(readableCopyrightString); 182 if (!readableStr) goto finish; 183 184 readableCopyrightIsValid = kxld_validate_copyright_string(readableStr); 185 } 186 187 if (!readableCopyrightIsValid) { 188 if (infoCopyrightIsValid) { 189 fprintf(stderr, "Warning: The copyright string in NSHumanReadableCopyright is invalid,\n" 190 "but the string in CFBundleGetInfoString is valid. CFBundleGetInfoString is\n" 191 "obsolete. Please migrate your copyright string to NSHumanReadableCopyright.\n\n"); 192 } else { 193 fprintf(stderr, "Error: There is no valid copyright string for this kext.\n\n"); 194 printFormat(); 195 goto finish; 196 } 197 } 198 199 result = 0; 200finish: 201 if (anURL) CFRelease(anURL); 202 if (aBundle) CFRelease(aBundle); 203 if (infoStr) free(infoStr); 204 if (readableStr) free(readableStr); 205 206 return result; 207} 208 209