+ // Create a login/default keychain for the user using UI.
+ // The user can cancel out of the operation, or create a new login keychain.
+ // If auto-login is turned off, the user will be asked for their login password.
+ //
+ OSStatus result = noErr;
+ Keychain keychain = NULL; // We return this keychain.
+ //
+ // Set up the Auth ref to bring up UI.
+ //
+ AuthorizationRef authRef = NULL;
+ result = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authRef);
+ if ( result != noErr )
+ MacOSError::throwMe(errAuthorizationInternal);
+ AuthorizationEnvironment envir;
+ envir.count = 5; // 5 hints are used.
+ AuthorizationItem* authEnvirItemArrayPtr = (AuthorizationItem*)malloc(sizeof(AuthorizationItem) * envir.count);
+ if ( !authEnvirItemArrayPtr )
+ {
+ if ( authRef )
+ AuthorizationFree(authRef, kAuthorizationFlagDefaults);
+ MacOSError::throwMe(errAuthorizationInternal);
+ }
+ envir.items = authEnvirItemArrayPtr;
+ AuthorizationItem* currItem = authEnvirItemArrayPtr;
+ //
+ // 1st Hint (optional): The keychain item's account attribute string.
+ // When item is specified, we assume an 'add' operation is being attempted.
+ char buff[255];
+ UInt32 actLen;
+ SecKeychainAttribute attr = { kSecAccountItemAttr, 255, &buff };
+ try
+ {
+ item->getAttribute(attr, &actLen);
+ }
+ catch(...)
+ {
+ actLen = 0; // This item didn't have the account attribute, so don't display one in the UI.
+ }
+ currItem->name = AGENT_HINT_ATTR_NAME; // name str that identifies this hint as attr name
+ if ( actLen ) // Fill in the hint if we have a 'srvr' attr
+ {
+ if ( actLen > 255 )
+ buff[255] = 0;
+ else
+ buff[actLen] = 0;
+ currItem->valueLength = strlen(buff)+1;
+ currItem->value = buff;
+ }
+ else
+ {
+ currItem->valueLength = 0;
+ currItem->value = NULL;
+ }
+ currItem->flags = 0;
+ //
+ // 2nd Hint (optional): The item's keychain full path.
+ //
+ currItem++;
+ char* currDefaultName = NULL;
+ try
+ {
+ currDefaultName = (char*)globals().storageManager.defaultKeychain()->name(); // Use the name if we have it.
+ currItem->name = AGENT_HINT_LOGIN_KC_NAME; // Name str that identifies this hint as kc path
+ currItem->valueLength = strlen(currDefaultName);
+ currItem->value = (void*)currDefaultName;
+ currItem->flags = 0;
+ currItem++;
+ }
+ catch(...)
+ {
+ envir.count--;
+ }
+
+ //
+ // 3rd Hint (optional): If curr default keychain is unavailable.
+ // This is determined by the parent not existing.
+ //
+ currItem->name = AGENT_HINT_LOGIN_KC_EXISTS_IN_KC_FOLDER;
+ Boolean loginUnavail = false;
+ try
+ {
+ Keychain defaultKC = defaultKeychain();
+ if ( !defaultKC->exists() )
+ loginUnavail = true;
+ }
+ catch(...) // login.keychain not present
+ {
+ }
+ currItem->valueLength = sizeof(Boolean);
+ currItem->value = (void*)&loginUnavail;
+ currItem->flags = 0;
+ //
+ // 4th Hint (required) userName
+ //
+ currItem++;
+ currItem->name = AGENT_HINT_LOGIN_KC_USER_NAME;
+ char* uName = getenv("USER");
+ string userName = uName ? uName : "";
+ if ( userName.length() == 0 )
+ {
+ uid_t uid = geteuid();
+ if (!uid) uid = getuid();
+ struct passwd *pw = getpwuid(uid); // fallback case...
+ if (pw)
+ userName = pw->pw_name;
+ endpwent();
+ }
+ if ( userName.length() != 0 ) // did we ultimately get one?
+ {
+ currItem->value = (void*)userName.c_str();
+ currItem->valueLength = userName.length();
+ }
+ else // trouble getting user name; can't continue...
+ {
+ if ( authRef )
+ AuthorizationFree(authRef, kAuthorizationFlagDefaults);
+ free(authEnvirItemArrayPtr);
+ MacOSError::throwMe(errAuthorizationInternal);
+ }
+ currItem->flags = 0;
+ //
+ // 5th Hint (optional) flags if user has more than 1 keychain (used for a later warning when reset to default).
+ //
+ currItem++; // last hint...
+ currItem->name = AGENT_HINT_LOGIN_KC_USER_HAS_OTHER_KCS_STR;
+ Boolean moreThanOneKCExists = false;
+ {
+ StLock<Mutex> _(mLock);
+ if (mSavedList.searchList().size() > 1)
+ moreThanOneKCExists = true;
+ }
+ currItem->value = &moreThanOneKCExists;
+ currItem->valueLength = sizeof(Boolean);
+ currItem->flags = 0;
+ //
+ // Set up the auth rights and make the auth call.
+ //
+ AuthorizationItem authItem = { LOGIN_KC_CREATION_RIGHT, 0 , NULL, 0};
+ AuthorizationRights rights = { 1, &authItem };
+ result = AuthorizationCopyRights(authRef, &rights, &envir, kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights, NULL);
+ free(authEnvirItemArrayPtr); // done with the auth items.
+ if ( result == errAuthorizationSuccess ) // On success, revert to defaults.
+ {
+ try
+ {
+ resetKeychain(true); // Clears the plist, moves aside existing login.keychain
+ login(authRef, userName.length(), userName.c_str()); // Creates a login.keychain
+ keychain = loginKeychain(); // Return it.
+ defaultKeychain(keychain); // Set it to the default.
+ }
+ catch(...)
+ {
+ // Reset failed, login.keychain creation failed, or setting it to default.
+ // We need to release 'authRef'...
+ }
+ }
+ if ( authRef )
+ AuthorizationFree(authRef, kAuthorizationFlagDefaults);
+ if ( result )
+ MacOSError::throwMe(result); // Any other error means we don't return a keychain.
+ return keychain;