1/* 2 * Copyright (c) 2000-2004 Apple Computer, 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 "webdavd.h" 25 26#include <sys/types.h> 27#include <pthread.h> 28#include "webdav_authcache.h" 29#include "webdav_network.h" 30 31/*****************************************************************************/ 32 33/* define authcache_head structure */ 34LIST_HEAD(authcache_head, authcache_entry); 35 36struct authcache_entry 37{ 38 LIST_ENTRY(authcache_entry) entries; 39 uid_t uid; 40 CFHTTPAuthenticationRef auth; 41 CFStringRef username; 42 CFStringRef password; 43 CFStringRef domain; /* can be NULL if there is no account domain */ 44 u_int32_t authflags; /* The options for this authorization */ 45}; 46 47/* authFlags */ 48enum 49{ 50 /* No flags */ 51 kAuthNone = 0x00000000, 52 53 kCredentialsFromMount = 0x00000001, /* Credentials passed at mount time */ 54 55 /* Set if mount credentials should not be used (they were tried and didn't work) */ 56 kNoMountCredentials = 0x00000002, 57 58 /* Set once the credentials are successfully used for a transaction */ 59 kCredentialsValid = 0x00000004 60}; 61 62/*****************************************************************************/ 63 64static pthread_mutex_t authcache_lock; /* lock for authcache */ 65static u_int32_t authcache_generation = 1; /* generation count of authcache (never zero)*/ 66static struct authcache_head authcache_list; /* the list of authcache_entry structs for the server */ 67static struct authcache_entry *authcache_proxy_entry = NULL; /* the authcache_entry for the proxy server, or NULL */ 68static CFStringRef mount_username = NULL; 69static CFStringRef mount_password = NULL; 70static CFStringRef mount_proxy_username = NULL; 71static CFStringRef mount_proxy_password = NULL; 72static CFStringRef mount_domain = NULL; 73 74/*****************************************************************************/ 75 76// static 77char *CopyCFStringToCString(CFStringRef theString); 78 79static 80void ReleaseCredentials(struct authcache_entry *entry_ptr); 81 82/*****************************************************************************/ 83 84static 85void RemoveAuthentication(struct authcache_entry *entry_ptr) 86{ 87 /* authcache_proxy_entry is never in the authcache_list */ 88 if ( entry_ptr != authcache_proxy_entry ) 89 { 90 LIST_REMOVE(entry_ptr, entries); 91 } 92 else 93 { 94 authcache_proxy_entry = NULL; 95 } 96 ++authcache_generation; 97 if ( authcache_generation == 0 ) 98 { 99 ++authcache_generation; 100 } 101 102 if ( entry_ptr->auth != NULL ) 103 { 104 CFRelease(entry_ptr->auth); 105 entry_ptr->auth = NULL; 106 } 107 108 ReleaseCredentials(entry_ptr); 109 110 free(entry_ptr); 111} 112 113/*****************************************************************************/ 114 115static 116void ReleaseCredentials( 117 struct authcache_entry *entry_ptr) 118{ 119 if (entry_ptr->username != NULL) 120 { 121 CFRelease(entry_ptr->username); 122 entry_ptr->username = NULL; 123 } 124 if (entry_ptr->password != NULL) 125 { 126 CFRelease(entry_ptr->password); 127 entry_ptr->password = NULL; 128 } 129 if (entry_ptr->domain != NULL) 130 { 131 CFRelease(entry_ptr->domain); 132 entry_ptr->domain = NULL; 133 } 134} 135 136/*****************************************************************************/ 137 138static 139void SetCredentials( 140 struct authcache_entry *entry_ptr, 141 CFStringRef new_username, 142 CFStringRef new_password, 143 CFStringRef new_domain) 144{ 145 entry_ptr->username = new_username; 146 entry_ptr->password = new_password; 147 entry_ptr->domain = new_domain; 148} 149 150/*****************************************************************************/ 151 152// static 153char *CopyCFStringToCString(CFStringRef theString) 154{ 155 char *cstring; 156 CFIndex usedBufLen; 157 CFIndex converted; 158 CFRange range; 159 160 range = CFRangeMake(0, CFStringGetLength(theString)); 161 converted = CFStringGetBytes(theString, range, kCFStringEncodingUTF8, 0, false, NULL, 0, &usedBufLen); 162 cstring = malloc(usedBufLen + 1); 163 if ( cstring != NULL ) 164 { 165 converted = CFStringGetBytes(theString, range, kCFStringEncodingUTF8, 0, false, (UInt8 *)cstring, usedBufLen, &usedBufLen); 166 cstring[usedBufLen] = '\0'; 167 } 168 return ( cstring ); 169} 170 171/*****************************************************************************/ 172 173static 174int CopyMountCredentials( 175 CFHTTPAuthenticationRef auth, 176 CFStringRef *username, 177 CFStringRef *password, 178 CFStringRef *domain, 179 int *secureAuth) /* <- TRUE if auth is sent securely */ 180{ 181 int result; 182 CFStringRef method; 183 184 /* determine if this authentication is secure */ 185 if ( gSecureConnection ) 186 { 187 /* the connection is secure so the authentication is secure */ 188 *secureAuth = TRUE; 189 } 190 else 191 { 192 /* the connection is not secure, so secure means "not Basic authentication" */ 193 method = CFHTTPAuthenticationCopyMethod(auth); 194 if ( method != NULL ) 195 { 196 *secureAuth = !CFEqual(method, CFSTR("Basic")); 197 CFRelease(method); 198 } 199 else 200 { 201 *secureAuth = FALSE; 202 } 203 } 204 205 /* make sure we aren't using Basic over an unsecure connnection if gSecureServerAuth is TRUE */ 206 if ( (gSecureServerAuth == TRUE) && (*secureAuth == FALSE) ) { 207 syslog(LOG_ERR, "Mount failed, Authentication method (Basic) too weak"); 208 result = EAUTH; 209 goto SecureServerAuthRequired; 210 } 211 212 if ( mount_username != NULL ) 213 { 214 CFRetain(mount_username); 215 *username = mount_username; 216 217 if ( mount_password != NULL ) 218 { 219 CFRetain(mount_password); 220 } 221 *password = mount_password; 222 223 if ( mount_domain != NULL ) 224 { 225 CFRetain(mount_domain); 226 } 227 *domain = mount_domain; 228 229 result = 0; 230 } 231 else 232 { 233 result = 1; 234 } 235 236SecureServerAuthRequired: 237 238 return ( result ); 239} 240 241/*****************************************************************************/ 242 243static 244int CopyMountProxyCredentials(CFHTTPAuthenticationRef auth, 245 CFStringRef *username, 246 CFStringRef *password, 247 CFStringRef *domain, 248 int *secureAuth) /* <- TRUE if auth is sent securely */ 249{ 250#pragma unused(domain) 251 int result = 1; 252 CFStringRef method; 253 254 if (auth == NULL) { 255 syslog(LOG_ERR, "auth object arg is NULL"); 256 return result; 257 } 258 if (username == NULL) { 259 syslog(LOG_ERR, "user arg is NULL"); 260 return result; 261 } 262 if (password == NULL) { 263 syslog(LOG_ERR, "credential arg is NULL"); 264 return result; 265 } 266 if (domain == NULL) { 267 syslog(LOG_ERR, "domain arg is NULL"); 268 return result; 269 } 270 if (secureAuth == NULL) { 271 syslog(LOG_ERR, "secureAuth object is NULL"); 272 return result; 273 } 274 275 /* determine if this authentication is secure */ 276 if ( gSecureConnection ) 277 { 278 /* the connection is secure so the authentication is secure */ 279 *secureAuth = TRUE; 280 } 281 else 282 { 283 /* the connection is not secure, so secure means "not Basic authentication" */ 284 method = CFHTTPAuthenticationCopyMethod(auth); 285 if ( method != NULL ) 286 { 287 *secureAuth = !CFEqual(method, CFSTR("Basic")); 288 CFRelease(method); 289 } 290 else 291 { 292 *secureAuth = FALSE; 293 } 294 } 295 296 if ( mount_proxy_username != NULL ) 297 { 298 CFRetain(mount_proxy_username); 299 *username = mount_proxy_username; 300 301 if ( mount_proxy_password != NULL ) 302 { 303 CFRetain(mount_proxy_password); 304 } 305 *password = mount_proxy_password; 306 result = 0; 307 } 308 309 return ( result ); 310} 311 312/*****************************************************************************/ 313 314static 315int AddServerCredentials( 316 struct authcache_entry *entry_ptr, 317 CFHTTPMessageRef request) 318{ 319 int result; 320 /* locals for getting new values */ 321 CFStringRef username; 322 CFStringRef password; 323 CFStringRef domain; 324 int secureAuth; 325 326 username = password = domain = NULL; 327 result = EACCES; 328 329 if ( CFHTTPAuthenticationRequiresUserNameAndPassword(entry_ptr->auth) ) 330 { 331 /* invalidate credential sources already tried */ 332 if (entry_ptr->authflags & kCredentialsFromMount) 333 { 334 entry_ptr->authflags |= kNoMountCredentials; 335 } 336 337 /* if we haven't tried the mount credentials, try them now */ 338 if ( (entry_ptr->authflags & kNoMountCredentials) == 0 ) 339 { 340 result = CopyMountCredentials(entry_ptr->auth, &username, &password, &domain, &secureAuth); 341 if ( result == 0 ) 342 { 343 ReleaseCredentials(entry_ptr); 344 SetCredentials(entry_ptr, username, password, domain); 345 entry_ptr->authflags |= kCredentialsFromMount; 346 } 347 else 348 { 349 /* there are no mount credentials */ 350 syslog(LOG_DEBUG, "AddServerCred: no mount creds, req %p", request); 351 entry_ptr->authflags |= kNoMountCredentials; 352 } 353 } 354 355 if ( (result == 0) && !(secureAuth) ) 356 { 357 CFURLRef url; 358 CFStringRef urlString; 359 char *urlStr; 360 361 urlStr = NULL; 362 363 url = CFHTTPMessageCopyRequestURL(request); 364 if ( url != NULL ) 365 { 366 urlString = CFURLGetString(url); 367 if ( urlString != NULL ) 368 { 369 urlStr = CopyCFStringToCString(urlString); 370 } 371 else 372 { 373 urlStr = NULL; 374 } 375 CFRelease(url); 376 } 377 378 syslog(LOG_ERR | LOG_AUTHPRIV, "WebDAV FS authentication credentials are being sent insecurely to: %s", (urlStr ? urlStr : "")); 379 380 if ( urlStr != NULL ) 381 { 382 free(urlStr); 383 } 384 } 385 } 386 else 387 { 388 result = 0; 389 } 390 return ( result ); 391} 392 393/*****************************************************************************/ 394 395static 396int AddProxyCredentials(struct authcache_entry *entry_ptr, CFHTTPMessageRef request) 397{ 398 int result; 399 /* locals for getting new values */ 400 CFStringRef username; 401 CFStringRef password; 402 CFStringRef domain; 403 int secureAuth; 404 405 if ( CFHTTPAuthenticationRequiresUserNameAndPassword(entry_ptr->auth) ) 406 { 407 username = password = domain = NULL; 408 result = EACCES; 409 410 /* invalidate credential sources already tried */ 411 if (entry_ptr->authflags & kCredentialsFromMount) 412 { 413 entry_ptr->authflags |= kNoMountCredentials; 414 } 415 416 /* if we haven't tried the mount credentials, try them now */ 417 if ( (entry_ptr->authflags & kNoMountCredentials) == 0 ) 418 { 419 if ( CopyMountProxyCredentials(entry_ptr->auth, &username, &password, &domain, &secureAuth) == 0 ) 420 { 421 ReleaseCredentials(entry_ptr); 422 SetCredentials(entry_ptr, username, password, domain); 423 entry_ptr->authflags |= kCredentialsFromMount; 424 result = 0; 425 } 426 else 427 { 428 /* there are no mount credentials */ 429 syslog(LOG_DEBUG, "AddProxyCredentials: no mount creds, req %p", request); 430 entry_ptr->authflags |= kNoMountCredentials; 431 } 432 } 433 434 if ( (result == 0) && !(secureAuth) ) 435 { 436 CFURLRef url; 437 CFStringRef urlString; 438 char *urlStr; 439 440 urlStr = NULL; 441 442 url = CFHTTPMessageCopyRequestURL(request); 443 if ( url != NULL ) 444 { 445 urlString = CFURLGetString(url); 446 if ( urlString != NULL ) 447 { 448 urlStr = CopyCFStringToCString(urlString); 449 } 450 else 451 { 452 urlStr = NULL; 453 } 454 CFRelease(url); 455 } 456 457 syslog(LOG_ERR | LOG_AUTHPRIV, "WebDAV FS authentication proxy credentials are being sent insecurely to: %s", (urlStr ? urlStr : "")); 458 459 if ( urlStr != NULL ) 460 { 461 free(urlStr); 462 } 463 } 464 } 465 else { 466 result = 0; 467 } 468 469 return ( result ); 470} 471 472/*****************************************************************************/ 473 474static 475struct authcache_entry *CreateProxyAuthenticationFromResponse( 476 uid_t uid, /* -> uid of the user making the request */ 477 CFHTTPMessageRef request, /* -> the request message to apply authentication to */ 478 CFHTTPMessageRef response) /* -> the response message */ 479{ 480 struct authcache_entry *entry_ptr; 481 int result; 482 483 entry_ptr = calloc(sizeof(struct authcache_entry), 1); 484 require(entry_ptr != NULL, calloc); 485 486 entry_ptr->uid = uid; 487 entry_ptr->auth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, response); 488 require(entry_ptr->auth != NULL, CFHTTPAuthenticationCreateFromResponse); 489 490 require(CFHTTPAuthenticationIsValid(entry_ptr->auth, NULL), CFHTTPAuthenticationIsValid); 491 492 result = AddProxyCredentials(entry_ptr, request); 493 require_noerr_quiet(result, AddProxyCredentials); 494 495 authcache_proxy_entry = entry_ptr; 496 ++authcache_generation; 497 if ( authcache_generation == 0 ) 498 { 499 ++authcache_generation; 500 } 501 502 return ( entry_ptr ); 503 504AddProxyCredentials: 505CFHTTPAuthenticationIsValid: 506 507 CFRelease(entry_ptr->auth); 508 509CFHTTPAuthenticationCreateFromResponse: 510 511 free(entry_ptr); 512 513calloc: 514 515 return ( NULL ); 516} 517 518/*****************************************************************************/ 519 520static 521struct authcache_entry *CreateAuthenticationFromResponse( 522 uid_t uid, /* -> uid of the user making the request */ 523 CFHTTPMessageRef request, /* -> the request message to apply authentication to */ 524 CFHTTPMessageRef response, /* -> the response message */ 525 int *result, /* -> result of this function (errno) */ 526 int isProxy) /* -> if TRUE, create authcache_proxy_entry */ 527{ 528 struct authcache_entry *entry_ptr; 529 *result = 0; 530 531 entry_ptr = calloc(1, sizeof(struct authcache_entry)); 532 require_action(entry_ptr != NULL, calloc_err, *result = ENOMEM); 533 534 entry_ptr->uid = uid; 535 entry_ptr->auth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, response); 536 require_action(entry_ptr->auth != NULL, CFHTTPAuthenticationCreateFromResponse, *result = EIO); 537 538 require_action(CFHTTPAuthenticationIsValid(entry_ptr->auth, NULL), CFHTTPAuthenticationIsValid, *result = EIO); 539 540 if ( !isProxy ) 541 { 542 *result = AddServerCredentials(entry_ptr, request); 543 require_noerr_quiet(*result, AddServerCredentials); 544 545 LIST_INSERT_HEAD(&authcache_list, entry_ptr, entries); 546 } 547 else 548 { 549 *result = AddProxyCredentials(entry_ptr, request); 550 require_noerr_quiet(*result, AddProxyCredentials); 551 } 552 553 ++authcache_generation; 554 if ( authcache_generation == 0 ) 555 { 556 ++authcache_generation; 557 } 558 559 return ( entry_ptr ); 560 561AddProxyCredentials: 562AddServerCredentials: 563CFHTTPAuthenticationIsValid: 564 565 CFRelease(entry_ptr->auth); 566 567CFHTTPAuthenticationCreateFromResponse: 568 569 free(entry_ptr); 570 571calloc_err: 572 573 return ( NULL ); 574} 575 576/*****************************************************************************/ 577 578static 579struct authcache_entry *FindAuthenticationForRequest( 580 uid_t uid, /* -> uid of the user making the request */ 581 CFHTTPMessageRef request) /* -> the request message to apply authentication to */ 582{ 583 struct authcache_entry *entry_ptr; 584 585 /* see if we have an authentication we can use */ 586 LIST_FOREACH(entry_ptr, &authcache_list, entries) 587 { 588 /* 589 * If this authentication is for the current user or root user, 590 * and it applies to this request, then break. 591 */ 592 if ( (entry_ptr->uid == uid) || (0 == uid) ) 593 { 594 if ( CFHTTPAuthenticationAppliesToRequest(entry_ptr->auth, request) ) 595 { 596 break; 597 } 598 } 599 } 600 return ( entry_ptr ); 601} 602 603/*****************************************************************************/ 604 605static int ApplyCredentialsToRequest(struct authcache_entry *entry_ptr, CFHTTPMessageRef request) 606{ 607 int result; 608 609 if ( entry_ptr->domain != NULL ) { 610 CFMutableDictionaryRef dict; 611 612 dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 613 require_action(dict != NULL, CFDictionaryCreateMutable, result = FALSE); 614 615 if ( entry_ptr->username != NULL ) { 616 CFDictionaryAddValue(dict, kCFHTTPAuthenticationUsername, entry_ptr->username); 617 } 618 619 if ( entry_ptr->password != NULL ) { 620 CFDictionaryAddValue(dict, kCFHTTPAuthenticationPassword, entry_ptr->password); 621 } 622 623 if ( entry_ptr->domain != NULL ) { 624 CFDictionaryAddValue(dict, kCFHTTPAuthenticationAccountDomain, entry_ptr->domain); 625 } 626 627 result = CFHTTPMessageApplyCredentialDictionary(request, entry_ptr->auth, dict, NULL); 628 629 CFRelease(dict); 630 631 } 632 else { 633 result = CFHTTPMessageApplyCredentials(request, entry_ptr->auth, entry_ptr->username, entry_ptr->password, NULL); 634 } 635 636CFDictionaryCreateMutable: 637 638 return ( result ); 639} 640 641/*****************************************************************************/ 642 643static 644int AddExistingAuthentications( 645 uid_t uid, /* -> uid of the user making the request */ 646 CFHTTPMessageRef request) /* -> the request message to apply authentication to */ 647{ 648 struct authcache_entry *entry_ptr; 649 650 entry_ptr = FindAuthenticationForRequest(uid, request); 651 if ( entry_ptr != NULL ) 652 { 653 /* try to apply valid entry to the request */ 654 if ( CFHTTPAuthenticationIsValid(entry_ptr->auth, NULL) ) 655 { 656 if ( !ApplyCredentialsToRequest(entry_ptr, request) ) 657 { 658 /* 659 * Remove the unusable entry and do nothing -- we'll get a 401 when this request goes to the server 660 * which should allow us to create a new entry. 661 */ 662 RemoveAuthentication(entry_ptr); 663 } 664 } 665 else 666 { 667 /* 668 * Remove the unusable entry and do nothing -- we'll get a 401 when this request goes to the server 669 * which should allow us to create a new entry. 670 */ 671 RemoveAuthentication(entry_ptr); 672 } 673 } 674 675 if ( authcache_proxy_entry != NULL ) 676 { 677 /* try to apply valid entry to the request */ 678 if ( !CFHTTPAuthenticationIsValid(authcache_proxy_entry->auth, NULL) || !ApplyCredentialsToRequest(authcache_proxy_entry, request) ) 679 { 680 /* 681 * Remove the unusable entry and do nothing -- we'll get a 407 when this request goes to the server 682 * which should allow us to create a new entry. 683 */ 684 RemoveAuthentication(authcache_proxy_entry); 685 } 686 } 687 688 return ( 0 ); 689} 690 691/*****************************************************************************/ 692 693/* 694 * DoServerAuthentication 695 * 696 * Handles authentication challenge (401) from the server 697 * Adds a new authcache_entry, or update an exiting authcache_entry for a server. 698 */ 699 static 700int DoServerAuthentication( 701 uid_t uid, /* -> uid of the user making the request */ 702 CFHTTPMessageRef request, /* -> the request message to apply authentication to */ 703 CFHTTPMessageRef response) /* -> the response containing the challenge, or NULL if no challenge */ 704{ 705 struct authcache_entry *entry_ptr; 706 int result = 0; 707 708 /* see if we already have an authcache_entry */ 709 entry_ptr = FindAuthenticationForRequest(uid, request); 710 711 /* if we have one, we need to try to update it and use it */ 712 if ( entry_ptr != NULL ) 713 { 714 // Clear valid flag since we just got a 401 for this auth_entry 715 entry_ptr->authflags &= ~kCredentialsValid; 716 717 /* ensure the CFHTTPAuthenticationRef is valid */ 718 if ( CFHTTPAuthenticationIsValid(entry_ptr->auth, NULL) ) 719 { 720 result = 0; 721 } 722 else 723 { 724 /* It's invalid so release the old one and try to create a new one */ 725 CFRelease(entry_ptr->auth); 726 entry_ptr->auth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, response); 727 if ( entry_ptr->auth != NULL ) 728 { 729 if ( CFHTTPAuthenticationIsValid(entry_ptr->auth, NULL) ) 730 { 731 result = AddServerCredentials(entry_ptr, request); 732 } 733 else 734 { 735 result = EACCES; 736 } 737 } 738 else 739 { 740 result = EACCES; 741 } 742 } 743 if ( result != 0 ) 744 { 745 RemoveAuthentication(entry_ptr); 746 } 747 } 748 else 749 { 750 /* create a new authcache_entry */ 751 entry_ptr = CreateAuthenticationFromResponse(uid, request, response, &result, FALSE); 752 } 753 754 return ( result ); 755} 756 757/*****************************************************************************/ 758 759/* 760 * AddProxyAuthentication 761 * 762 * Add a new authcache_entry, or update an exiting authcache_entry for a proxy. 763 */ 764static 765int AddProxyAuthentication( 766 uid_t uid, /* -> uid of the user making the request */ 767 CFHTTPMessageRef request, /* -> the request message to apply authentication to */ 768 CFHTTPMessageRef response) /* -> the response containing the challenge, or NULL if no challenge */ 769{ 770 int result; 771 772 /* if we have an entry for the proxy, we need to try to update it and use it */ 773 if ( authcache_proxy_entry != NULL ) 774 { 775 authcache_proxy_entry->authflags &= ~kCredentialsValid; 776 777 /* ensure the CFHTTPAuthenticationRef is valid */ 778 if ( CFHTTPAuthenticationIsValid(authcache_proxy_entry->auth, NULL) ) 779 { 780 result = 0; 781 } 782 else 783 { 784 /* It's invalid so release the old and try to create a new one */ 785 CFRelease(authcache_proxy_entry->auth); 786 authcache_proxy_entry->auth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, response); 787 if ( authcache_proxy_entry->auth != NULL ) 788 { 789 if ( CFHTTPAuthenticationIsValid(authcache_proxy_entry->auth, NULL) ) 790 { 791 result = AddProxyCredentials(authcache_proxy_entry, request); 792 } 793 else 794 { 795 result = EACCES; 796 } 797 } 798 else 799 { 800 result = EACCES; 801 } 802 } 803 if ( result != 0 ) 804 { 805 RemoveAuthentication(authcache_proxy_entry); 806 } 807 } 808 else 809 { 810 /* create a new authcache_entry for the proxy */ 811 authcache_proxy_entry = CreateProxyAuthenticationFromResponse(uid, request, response); 812 if ( authcache_proxy_entry != NULL ) 813 { 814 result = 0; 815 } 816 else 817 { 818 result = EACCES; 819 } 820 } 821 822 return ( result ); 823} 824 825/*****************************************************************************/ 826 827int authcache_apply( 828 uid_t uid, /* -> uid of the user making the request */ 829 CFHTTPMessageRef request, /* -> the request message to apply authentication to */ 830 UInt32 statusCode, /* -> the status code (401, 407), or 0 if no challenge */ 831 CFHTTPMessageRef response, /* -> the response containing the challenge, or NULL if no challenge */ 832 UInt32 *generation) /* <- the generation count of the cache entry */ 833{ 834 int result, result2; 835 836 /* lock the Authcache */ 837 result = pthread_mutex_lock(&authcache_lock); 838 require_noerr_action(result, pthread_mutex_lock, webdav_kill(-1)); 839 840 switch (statusCode) 841 { 842 case 0: 843 /* no challenge */ 844 result = 0; 845 break; 846 847 case 401: 848 /* server challenge -- add server authentication */ 849 850 /* only add server authentication if the uid is the mount's user or root user */ 851 if ( (gProcessUID == uid) || (0 == uid) ) 852 { 853 result = DoServerAuthentication(uid, request, response); 854 } 855 else 856 { 857 result = EACCES; 858 } 859 break; 860 861 case 407: 862 /* proxy challenge -- add proxy authentication */ 863 864 /* only add proxy authentication if the uid is the mount's user or root user */ 865 if ( (gProcessUID == uid) || (0 == uid) ) 866 { 867 result = AddProxyAuthentication(uid, request, response); 868 } 869 else 870 { 871 result = EACCES; 872 } 873 break; 874 875 default: 876 /* should never happen */ 877 result = EACCES; 878 break; 879 } 880 881 /* only apply existing authentications if the uid is the mount's user or root user */ 882 if ( (result == 0) && ((gProcessUID == uid) || (0 == uid)) ) 883 { 884 result = AddExistingAuthentications(uid, request); 885 } 886 887 /* return the current authcache_generation */ 888 *generation = authcache_generation; 889 890 /* unlock the Authcache */ 891 result2 = pthread_mutex_unlock(&authcache_lock); 892 require_noerr_action(result2, pthread_mutex_unlock, result = result2; webdav_kill(-1)); 893 894pthread_mutex_unlock: 895pthread_mutex_lock: 896 897 return ( result ); 898} 899 900/*****************************************************************************/ 901 902int authcache_valid( 903 uid_t uid, /* -> uid of the user making the request */ 904 CFHTTPMessageRef request, /* -> the message of the successful request */ 905 UInt32 generation) /* -> the generation count of the cache entry */ 906{ 907 int result, result2; 908 909 /* only validate authentications if the uid is the mount's user or root user */ 910 require_quiet(((gProcessUID == uid) || (0 == uid)), not_owner_uid); 911 912 /* lock the Authcache */ 913 result = pthread_mutex_lock(&authcache_lock); 914 require_noerr_action(result, pthread_mutex_lock, webdav_kill(-1)); 915 916 if ( generation == authcache_generation ) 917 { 918 struct authcache_entry *entry_ptr; 919 920 /* see if we have an authcache_entry */ 921 entry_ptr = FindAuthenticationForRequest(uid, request); 922 if ( entry_ptr != NULL ) 923 { 924 /* mark this authentication valid */ 925 entry_ptr->authflags |= kCredentialsValid; 926 } 927 928 if ( authcache_proxy_entry != NULL ) 929 { 930 /* mark this authentication valid */ 931 authcache_proxy_entry->authflags |= kCredentialsValid; 932 } 933 } 934 935 /* unlock the Authcache */ 936 result2 = pthread_mutex_unlock(&authcache_lock); 937 require_noerr_action(result2, pthread_mutex_unlock, result = result2; webdav_kill(-1)); 938 939pthread_mutex_unlock: 940pthread_mutex_lock: 941not_owner_uid: 942 943 return ( 0 ); 944} 945 946/*****************************************************************************/ 947 948int authcache_proxy_invalidate(void) 949{ 950 int result, result2; 951 952 /* lock the Authcache */ 953 result = pthread_mutex_lock(&authcache_lock); 954 require_noerr_action(result, pthread_mutex_lock, webdav_kill(-1)); 955 956 /* called when proxy settings change -- remove any proxy authentications */ 957 if ( authcache_proxy_entry != NULL ) 958 { 959 RemoveAuthentication(authcache_proxy_entry); 960 } 961 962 /* unlock the Authcache */ 963 result2 = pthread_mutex_unlock(&authcache_lock); 964 require_noerr_action(result2, pthread_mutex_unlock, result = result2; webdav_kill(-1)); 965 966pthread_mutex_unlock: 967pthread_mutex_lock: 968 969 return ( result ); 970} 971 972/*****************************************************************************/ 973 974int authcache_init( 975 char *username, /* -> username to attempt to use on first server challenge, or NULL */ 976 char *password, /* -> password to attempt to use on first server challenge, or NULL */ 977 char *proxy_username, /* -> username to attempt to use on first proxy server challenge, or NULL */ 978 char *proxy_password, /* -> password to attempt to use on first proxy server challenge, or NULL */ 979 char *domain) /* -> account domain to attempt to use on first server challenge, or NULL */ 980{ 981 int result; 982 pthread_mutexattr_t mutexattr; 983 984 /* set up the lock on the list */ 985 result = pthread_mutexattr_init(&mutexattr); 986 require_noerr(result, pthread_mutexattr_init); 987 988 result = pthread_mutex_init(&authcache_lock, &mutexattr); 989 require_noerr(result, pthread_mutex_init); 990 991 LIST_INIT(&authcache_list); 992 authcache_generation = 1; 993 994 result = 0; 995 996 if ( username != NULL && password != NULL && username[0] != '\0') 997 { 998 mount_username = CFStringCreateWithCString(kCFAllocatorDefault, username, kCFStringEncodingUTF8); 999 require_action(mount_username != NULL, CFStringCreateWithCString, result = ENOMEM); 1000 1001 mount_password = CFStringCreateWithCString(kCFAllocatorDefault, password, kCFStringEncodingUTF8); 1002 require_action(mount_password != NULL, CFStringCreateWithCString, result = ENOMEM); 1003 } 1004 1005 if ( proxy_username != NULL && proxy_password != NULL && proxy_username[0] != '\0') 1006 { 1007 mount_proxy_username = CFStringCreateWithCString(kCFAllocatorDefault, proxy_username, kCFStringEncodingUTF8); 1008 require_action(mount_proxy_username != NULL, CFStringCreateWithCString, result = ENOMEM); 1009 1010 mount_proxy_password = CFStringCreateWithCString(kCFAllocatorDefault, proxy_password, kCFStringEncodingUTF8); 1011 require_action(mount_proxy_password != NULL, CFStringCreateWithCString, result = ENOMEM); 1012 } 1013 1014 if ( domain != NULL && domain[0] != '\0' ) 1015 { 1016 mount_domain = CFStringCreateWithCString(kCFAllocatorDefault, domain, kCFStringEncodingUTF8); 1017 require_action(mount_domain != NULL, CFStringCreateWithCString, result = ENOMEM); 1018 } 1019 1020CFStringCreateWithCString: 1021pthread_mutex_init: 1022pthread_mutexattr_init: 1023 1024 return ( result ); 1025} 1026 1027/*****************************************************************************/ 1028