1/* 2 * Copyright (c) 2010 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#include "NetworkAuthenticationHelper.h" 25#include "KerberosHelper.h" 26 27#include <err.h> 28 29#define IS_LOVE 0 30 31static void 32lkdc_classic(void) 33{ 34 CFArrayRef array; 35 CFIndex n; 36 NAHRef na; 37 38 CFShow(CFSTR("lkdc_classic")); 39 40 na = NAHCreate(NULL, CFSTR("localhost.local"), CFSTR("host"), NULL); 41 if (na == NULL) 42 errx(1, "NACreate"); 43 44 array = NAHGetSelections(na); 45 46 for (n = 0; n < CFArrayGetCount(array); n++) 47 CFShow(CFArrayGetValueAtIndex(array, n)); 48 49 CFRelease(na); 50} 51 52uint8_t token[] = 53 "\x60\x66\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x5c" 54 "\x30\x5a\xa0\x2c\x30\x2a\x06\x09\x2a\x86\x48\x82" 55 "\xf7\x12\x01\x02\x02\x06\x09\x2a\x86\x48\x86\xf7" 56 "\x12\x01\x02\x02\x06\x0a\x2b\x06\x01\x04\x01\x82" 57 "\x37\x02\x02\x0a\x06\x06\x2b\x05\x01\x05\x02\x07" 58 "\xa3\x2a\x30\x28\xa0\x26\x1b\x24\x6e\x6f\x74\x5f" 59 "\x64\x65\x66\x69\x6e\x65\x64\x5f\x69\x6e\x5f\x52" 60 "\x46\x43\x34\x31\x37\x38\x40\x70\x6c\x65\x61\x73" 61 "\x65\x5f\x69\x67\x6e\x6f\x72\x65"; 62 63static void 64lkdc_wellknown(void) 65{ 66 CFMutableDictionaryRef info; 67 CFDictionaryRef negToken; 68 CFArrayRef array; 69 CFDataRef serverToken; 70 CFIndex n; 71 NAHRef na; 72 73 CFShow(CFSTR("lkdc_wellknown")); 74 75 serverToken = CFDataCreateWithBytesNoCopy(NULL, 76 token, sizeof(token) - 1, 77 kCFAllocatorNull); 78 79 80 negToken = KRBDecodeNegTokenInit(NULL, serverToken); 81 CFRelease(serverToken); 82 83 info = CFDictionaryCreateMutable(NULL, 84 0, 85 &kCFTypeDictionaryKeyCallBacks, 86 &kCFTypeDictionaryValueCallBacks); 87 88 CFDictionaryAddValue(info, kNAHNegTokenInit, negToken); 89 CFRelease(negToken); 90 91 92 na = NAHCreate(NULL, CFSTR("localhost.local"), kNAHServiceAFPServer, info); 93 CFRelease(info); 94 if (na == NULL) 95 errx(1, "NACreate"); 96 97 array = NAHGetSelections(na); 98 99 for (n = 0; n < CFArrayGetCount(array); n++) 100 CFShow(CFArrayGetValueAtIndex(array, n)); 101 102 CFRelease(na); 103} 104 105static void 106test_ntlm(void) 107{ 108 CFMutableDictionaryRef info; 109 CFDictionaryRef negToken; 110 CFArrayRef array; 111 CFIndex n; 112 NAHRef na; 113 114 CFShow(CFSTR("test_ntlm")); 115 116 negToken = KRBCreateNegTokenLegacyNTLM(NULL); 117 if (negToken == NULL) 118 errx(1, "KRBCreateNegTokenLegacyNTLM"); 119 120 info = CFDictionaryCreateMutable(NULL, 121 0, 122 &kCFTypeDictionaryKeyCallBacks, 123 &kCFTypeDictionaryValueCallBacks); 124 125 CFDictionaryAddValue(info, kNAHNegTokenInit, negToken); 126 CFRelease(negToken); 127 128 129 na = NAHCreate(NULL, CFSTR("localhost.local"), CFSTR("host"), info); 130 CFRelease(info); 131 if (na == NULL) 132 errx(1, "NACreate"); 133 134 array = NAHGetSelections(na); 135 136 for (n = 0; n < CFArrayGetCount(array); n++) { 137 NAHSelectionRef s = (void *)CFArrayGetValueAtIndex(array, n); 138 CFShow(s); 139 140 if (CFBooleanGetValue(NAHSelectionGetInfoForKey(s, kNAHUseSPNEGO))) 141 errx(1, "not raw NTLM"); 142 } 143 144 CFRelease(na); 145} 146 147static void 148kerberos_classic(CFStringRef hostname, 149 CFStringRef service, 150 CFStringRef user, 151 CFStringRef password) 152{ 153 CFMutableDictionaryRef info; 154 CFDictionaryRef negToken; 155 CFArrayRef array; 156 CFIndex n; 157 NAHRef na; 158 159 CFShow(CFSTR("test KRBCreateNegTokenLegacyKerberos")); 160 161 negToken = KRBCreateNegTokenLegacyKerberos(NULL); 162 if (negToken == NULL) 163 errx(1, "KRBCreateNegTokenLegacyKerberos"); 164 165 CFShow(CFSTR("kerberos_classic")); 166 167 info = CFDictionaryCreateMutable(NULL, 168 0, 169 &kCFTypeDictionaryKeyCallBacks, 170 &kCFTypeDictionaryValueCallBacks); 171 172 CFDictionaryAddValue(info, kNAHUserName, user); 173 CFDictionaryAddValue(info, kNAHPassword, password); 174 175 CFDictionaryAddValue(info, kNAHNegTokenInit, negToken); 176 CFRelease(negToken); 177 178 179 na = NAHCreate(NULL, hostname, service, info); 180 if (na == NULL) 181 errx(1, "NAHCreate"); 182 183 array = NAHGetSelections(na); 184 185 for (n = 0; n < CFArrayGetCount(array); n++) { 186 NAHSelectionRef s = (void *)CFArrayGetValueAtIndex(array, n); 187 CFErrorRef error = NULL; 188 Boolean ret; 189 190 ret = NAHSelectionAcquireCredential(s, NULL, &error); 191 printf("NAHSelectionAcquireCredential: %s\n", ret ? "yes" : "no"); 192 CFShow(s); 193 if (error) 194 CFShow(error); 195 196 if (ret) { 197 CFDictionaryRef authinfo = NAHSelectionCopyAuthInfo(s); 198 if (authinfo) { 199 CFShow(CFSTR("Authinfo")); 200 CFShow(authinfo); 201 CFRelease(authinfo); 202 } 203 204 /* if NAHCopyReferenceKey returns NULL, refcounting not supported */ 205 206 CFStringRef refinfo = NAHCopyReferenceKey(s); 207 208 CFStringRef label = CFSTR("fs:/testing"); 209 210 NAHAddReferenceAndLabel(s, label); 211 212 NAHCredRemoveReference(refinfo); 213 214 NAHCredAddReference(refinfo); 215 NAHCredRemoveReference(refinfo); 216 217 if (refinfo) 218 CFRelease(refinfo); 219 220 /* should delete */ 221 NAHFindByLabelAndRelease(label); 222 } 223 } 224 225 CFRelease(na); 226 227 CFRelease(info); 228} 229 230/* 231 * 232 */ 233 234static void 235check_valid(bool expected, bool found, const char *check) 236{ 237 if (expected ^ found) 238 errx(1, "%s doesn't have expected result: %s %sfound", 239 check, check, found ? "" : "not "); 240} 241 242 243static void 244verify_result(bool expect_mech_kerberos, 245 bool expect_ntlm, 246 bool expect_iakerb, 247 bool expect_classic_kerberos, 248 bool expect_classic_lkdc, 249 bool expect_wlkdc, 250 bool expect_raw_kerberos, 251 CFStringRef service, 252 CFStringRef hostname, 253 CFStringRef username, 254 CFStringRef password, 255 void *spnego, 256 size_t len, 257 CFDictionaryRef negToken) 258{ 259 CFDataRef serverToken = CFDataCreate(NULL, spnego, len); 260 CFMutableDictionaryRef info; 261 NAHRef na; 262 263 info = CFDictionaryCreateMutable(NULL, 264 0, 265 &kCFTypeDictionaryKeyCallBacks, 266 &kCFTypeDictionaryValueCallBacks); 267 268 if (spnego) { 269 negToken = KRBDecodeNegTokenInit(NULL, serverToken); 270 CFRelease(serverToken); 271 if (negToken == NULL) 272 errx(1, "failed to decode NegTokenInit"); 273 274 CFShow(negToken); 275 276 CFDictionaryAddValue(info, kNAHNegTokenInit, negToken); 277 CFRelease(negToken); 278 } else if (negToken) { 279 CFShow(negToken); 280 CFDictionaryAddValue(info, kNAHNegTokenInit, negToken); 281 } 282 CFRelease(serverToken); 283 284 285 286 if (username) 287 CFDictionaryAddValue(info, kNAHUserName, username); 288 if (password) 289 CFDictionaryAddValue(info, kNAHPassword, password); 290 291 na = NAHCreate(NULL, hostname, service, info); 292 if (info) 293 CFRelease(info); 294 if (na == NULL) 295 errx(1, "NAHCreate"); 296 297 CFArrayRef r = NAHGetSelections(na); 298 299 CFIndex n, num = CFArrayGetCount(r); 300 301 bool found_wlkdc = false, 302 found_classic_lkdc = false, 303 found_kerberos = false, 304 found_raw_kerberos = false, 305 found_mech_kerberos = false, 306 found_mech_ntlm = false, 307 found_mech_iakerb = false; 308 309 CFShow(hostname); 310 311 for (n = 0; n < num; n++) { 312 NAHSelectionRef s = (NAHSelectionRef)CFArrayGetValueAtIndex(r, n); 313 CFStringRef name; 314 CFRange range1, range2; 315 316 CFShow(s); 317 318 name = NAHSelectionGetInfoForKey(s, kNAHMechanism); 319 if (CFStringCompare(name, CFSTR("Kerberos"), 0) == kCFCompareEqualTo) { 320 found_raw_kerberos = true; 321 } 322 323 name = NAHSelectionGetInfoForKey(s, kNAHInnerMechanism); 324 if (CFStringCompare(name, CFSTR("Kerberos"), 0) == kCFCompareEqualTo) { 325 found_mech_kerberos = true; 326 327 name = NAHSelectionGetInfoForKey(s, kNAHClientPrincipal); 328 329 range1 = CFStringFind(name, CFSTR("WELLKNOWN:COM.APPLE.LKDC"), 0); 330 range2 = CFStringFind(name, CFSTR("@LKDC:SHA1"), 0); 331 if (range1.location != kCFNotFound) 332 found_wlkdc = true; 333 else if (range2.location != kCFNotFound) 334 found_classic_lkdc = true; 335 else 336 found_kerberos = true; 337 338 } else if (CFStringCompare(name, CFSTR("IAKerb"), 0) == kCFCompareEqualTo) { 339 found_mech_iakerb = true; 340 } else if (CFStringCompare(name, CFSTR("NTLM"), 0) == kCFCompareEqualTo) { 341 found_mech_ntlm = true; 342 } 343 } 344 345 check_valid(expect_mech_kerberos, found_mech_kerberos, "kerberos mech"); 346 check_valid(expect_ntlm, found_mech_ntlm, "ntlm mech"); 347 check_valid(expect_iakerb, found_mech_iakerb, "iakerb"); 348 check_valid(expect_classic_kerberos, found_kerberos, "kerberos classic"); 349 check_valid(expect_classic_lkdc, found_classic_lkdc, "lkdc classic mech"); 350 check_valid(expect_wlkdc, found_wlkdc, "wellknown lkdc"); 351 check_valid(expect_raw_kerberos, found_raw_kerberos, "raw kerberos"); 352 353 354 CFRelease(na); 355} 356 357 358uint8_t win2k8[108] = 359 "\x60\x6a\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x60\x30\x5e\xa0\x30" 360 "\x30\x2e\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02\x06\x09\x2a" 361 "\x86\x48\x86\xf7\x12\x01\x02\x02\x06\x0a\x2a\x86\x48\x86\xf7\x12" 362 "\x01\x02\x02\x03\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a" 363 "\xa3\x2a\x30\x28\xa0\x26\x1b\x24\x6e\x6f\x74\x5f\x64\x65\x66\x69" 364 "\x6e\x65\x64\x5f\x69\x6e\x5f\x52\x46\x43\x34\x31\x37\x38\x40\x70" 365 "\x6c\x65\x61\x73\x65\x5f\x69\x67\x6e\x6f\x72\x65"; 366 367uint8_t snowleopard[] = 368 "\x60\x81\xa6\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x81\x9b\x30\x81" 369 "\x98\xa0\x24\x30\x22\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" 370 "\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02\x06\x0a\x2b\x06\x01" 371 "\x04\x01\x82\x37\x02\x02\x0a\xa3\x70\x30\x6e\xa0\x6c\x1b\x6a\x63" 372 "\x69\x66\x73\x2f\x4c\x4b\x44\x43\x3a\x53\x48\x41\x31\x2e\x35\x38" 373 "\x46\x43\x45\x33\x36\x44\x42\x44\x42\x44\x38\x36\x41\x45\x37\x30" 374 "\x31\x30\x39\x33\x42\x34\x42\x31\x44\x37\x39\x41\x44\x44\x30\x37" 375 "\x30\x35\x44\x30\x30\x42\x40\x4c\x4b\x44\x43\x3a\x53\x48\x41\x31" 376 "\x2e\x35\x38\x46\x43\x45\x33\x36\x44\x42\x44\x42\x44\x38\x36\x41" 377 "\x45\x37\x30\x31\x30\x39\x33\x42\x34\x42\x31\x44\x37\x39\x41\x44" 378 "\x44\x30\x37\x30\x35\x44\x30\x30\x42"; 379 380uint8_t lion[] = 381 "\x60\x7e\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x74\x30\x72\xa0\x44" 382 "\x30\x42\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02\x06\x09\x2a" 383 "\x86\x48\x86\xf7\x12\x01\x02\x02\x06\x06\x2a\x85\x70\x2b\x0e\x03" 384 "\x06\x06\x2b\x06\x01\x05\x05\x0e\x06\x0a\x2b\x06\x01\x04\x01\x82" 385 "\x37\x02\x02\x0a\x06\x06\x2b\x05\x01\x05\x02\x07\x06\x06\x2b\x06" 386 "\x01\x05\x02\x05\xa3\x2a\x30\x28\xa0\x26\x1b\x24\x6e\x6f\x74\x5f" 387 "\x64\x65\x66\x69\x6e\x65\x64\x5f\x69\x6e\x5f\x52\x46\x43\x34\x31" 388 "\x37\x38\x40\x70\x6c\x65\x61\x73\x65\x5f\x69\x67\x6e\x6f\x72\x65"; 389 390int 391main(int argc, char **argv) 392{ 393 /* validate expected behaviors */ 394 395 system("/System/Library/PrivateFrameworks/Heimdal.framework/Helpers/gsstool destroy --all"); 396 397 /* 398 * Basic tests 399 */ 400 401 lkdc_classic(); 402 lkdc_wellknown(); 403 test_ntlm(); 404 405 kerberos_classic(CFSTR("host.ads.apple.com"), CFSTR("host"), 406 CFSTR("ktestuser"), CFSTR("foobar")); 407 408 kerberos_classic(CFSTR("host.ads.apple.com"), CFSTR("host"), 409 CFSTR("ktestuser@ADS.APPLE.COM"), CFSTR("foobar")); 410 411 system("/System/Library/PrivateFrameworks/Heimdal.framework/Helpers/gsstool destroy --all"); 412 413 /* windows 2008 server */ 414 verify_result(true, true, false, true, false, false, false, CFSTR("cifs"), CFSTR("host.ads.apple.com"), CFSTR("user"), CFSTR("password"), win2k8, sizeof(win2k8), NULL); 415 verify_result(false, false, false, false, false, false, false, CFSTR("cifs"), CFSTR("host.ads.apple.com"), NULL, NULL, win2k8, sizeof(win2k8), NULL); 416 417 /* snowleopard SMB */ 418 verify_result(true, true, false, true, false, false, false, CFSTR("cifs"), CFSTR("nutcracker.apple.com"), CFSTR("user"), CFSTR("password"), snowleopard, sizeof(snowleopard), NULL); 419 verify_result(false, false, false, false, false, false, false, CFSTR("cifs"), CFSTR("nutcracker.apple.com"), NULL, NULL, snowleopard, sizeof(snowleopard), NULL); 420 /* next two tests only really for N.N. when his laptop is turned on.... :-/ */ 421#if IS_LOVE 422 verify_result(true, true, false, true, true, false, false, CFSTR("cifs"), CFSTR("nutcracker.local"), CFSTR("user"), CFSTR("password"), snowleopard, sizeof(snowleopard), NULL); 423 verify_result(true, true, false, false, true, false, false, CFSTR("cifs"), CFSTR("nutcracker.bitcollector.members.mac.com"), CFSTR("user"), CFSTR("password"), snowleopard, sizeof(snowleopard), NULL); 424#endif 425 426 /* snowleopard VNC */ 427 CFShow(CFSTR("VNC - snow leopard")); 428 verify_result(true, false, false, true, false, true, false, CFSTR("vnc"), CFSTR("nutcracker.apple.com"), CFSTR("user"), CFSTR("password"), NULL, 0, NULL); 429 verify_result(false, false, false, false, false, false, false, CFSTR("vnc"), CFSTR("nutcracker.apple.com"), NULL, NULL, NULL, 0, NULL); 430#if IS_LOVE 431 verify_result(true, false, false, true, true, true, false, CFSTR("vnc"), CFSTR("nutcracker.local"), CFSTR("user"), CFSTR("password"), NULL, 0, NULL); 432 verify_result(true, false, false, false, true, true, false, CFSTR("vnc"), CFSTR("nutcracker.bitcollector.members.mac.com"), CFSTR("user"), CFSTR("password"), NULL, 0, NULL); 433 verify_result(true, false, false, false, true, true, false, CFSTR("vnc"), CFSTR("nutcracker.bitcollector.members.btmm.icloud.com"), CFSTR("user"), CFSTR("password"), NULL, 0, NULL); 434#endif 435 436 CFShow(CFSTR("afpserver - No initial packet - snow leopard")); 437 verify_result(true, false, false, true, false, false, true, CFSTR("afpserver"), CFSTR("nutcracker.apple.com"), CFSTR("user"), CFSTR("password"), NULL, 0, NULL); 438#if IS_LOVE 439 verify_result(true, false, false, true, true, false, false, CFSTR("afpserver"), CFSTR("nutcracker.local"), CFSTR("user"), CFSTR("password"), NULL, 0, NULL); 440#endif 441 verify_result(false, false, false, false, false, false, false, CFSTR("afpserver"), CFSTR("nutcracker.apple.com"), NULL, NULL, NULL, 0, NULL); 442#if IS_LOVE 443 verify_result(false, false, false, true, true, false, false, CFSTR("afpserver"), CFSTR("nutcracker.local"), NULL, NULL, NULL, 0, NULL); 444#endif 445 446 CFShow(CFSTR("afpserver - Initial packet without IAKERB or SupportLKDC - 3rd party")); 447 verify_result(true, false, false, true, false, false, true, CFSTR("afpserver"), CFSTR("nutcracker.apple.com"), CFSTR("user"), CFSTR("password"), snowleopard, sizeof(snowleopard), NULL); 448 verify_result(false, false, false, false, false, false, false, CFSTR("afpserver"), CFSTR("nutcracker.apple.com"), NULL, NULL, snowleopard, sizeof(snowleopard), NULL); 449 450 CFShow(CFSTR("afpserver - Initial packet with IAKERB or SupportLKDC - lion")); 451 verify_result(true, false, true, true, false, false, false, CFSTR("afpserver"), CFSTR("nutcracker.apple.com"), CFSTR("user"), CFSTR("password"), lion, sizeof(lion), NULL); 452 verify_result(false, false, false, false, false, false, false, CFSTR("afpserver"), CFSTR("nutcracker.apple.com"), NULL, NULL, lion, sizeof(lion), NULL); 453#if IS_LOVE 454 verify_result(true, false, false, true, true, true, false, CFSTR("afpserver"), CFSTR("nutcracker.local"), CFSTR("user"), CFSTR("password"), NULL, 0, NULL); 455 verify_result(true, false, false, false, true, true, false, CFSTR("afpserver"), CFSTR("nutcracker.bitcollector.members.mac.com"), CFSTR("user"), CFSTR("password"), NULL, 0, NULL); 456#endif 457 458 printf("PASS\n"); 459 460 return 0; 461} 462