/* * ==================================================================== * Copyright (c) 2004-2010 TMate Software Ltd. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://svnkit.com/license.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.tmatesoft.svn.core.internal.util.jna; import java.io.UnsupportedEncodingException; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.util.SVNLogType; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.PointerByReference; /** * @author TMate Software Ltd. * @version 1.3 */ class SVNMacOsKeychain { private static final int ERR_SEC_ITEM_NOT_FOUND = -25300; public static boolean isEnabled() { final boolean enabled = Boolean.valueOf(System.getProperty("svnkit.library.osxkeychain.enabled", "true")); return enabled && SVNFileUtil.isOSX && JNALibraryLoader.getMacOsSecurityLibrary() != null; } public static synchronized boolean setPassword(String realm, String userName, char[] password, boolean nonInteractive) throws SVNException { final ISVNMacOsSecurityLibrary library = JNALibraryLoader.getMacOsSecurityLibrary(); if (library == null) { return false; } if (realm == null) { return false; } if (nonInteractive) { library.SecKeychainSetUserInteractionAllowed(false); } byte[] rawPassword = null; try { byte[] rawRealm = realm.getBytes("UTF-8"); byte[] rawUserName = userName == null ? null : userName.getBytes("UTF-8"); int rawUserNameLength = userName == null ? 0 : rawUserName.length; rawPassword = SVNEncodingUtil.getBytes(password, "UTF-8"); PointerByReference itemHolder = new PointerByReference(); int status = library.SecKeychainFindGenericPassword(null, rawRealm.length, rawRealm, rawUserNameLength, rawUserName, null, null, itemHolder); if (status == ERR_SEC_ITEM_NOT_FOUND) { status = library.SecKeychainAddGenericPassword(null, rawRealm.length, rawRealm, rawUserNameLength, rawUserName, rawPassword.length, rawPassword, null); } else { Pointer item = itemHolder.getValue(); try { status = library.SecKeychainItemModifyAttributesAndData(item, null, rawPassword.length, rawPassword); } finally { release(item); } } return status == 0; } catch (UnsupportedEncodingException e) { SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e); SVNErrorManager.error(error, e, SVNLogType.DEFAULT); } finally { if (nonInteractive) { library.SecKeychainSetUserInteractionAllowed(true); } SVNEncodingUtil.clearArray(rawPassword); } return false; } public static synchronized char[] getPassword(String realm, String userName, boolean nonInteractive) throws SVNException { ISVNMacOsSecurityLibrary library = JNALibraryLoader.getMacOsSecurityLibrary(); if (library == null) { return null; } if (realm == null) { return null; } if (nonInteractive) { library.SecKeychainSetUserInteractionAllowed(false); } try { byte[] rawRealm = realm.getBytes("UTF-8"); byte[] rawUserName = userName == null ? null : userName.getBytes("UTF-8"); int rawUserNameLength = userName == null ? 0 : rawUserName.length; IntByReference passwordLengthHolder = new IntByReference(); PointerByReference passwordHolder = new PointerByReference(); int status = library.SecKeychainFindGenericPassword(null, rawRealm.length, rawRealm, rawUserNameLength, rawUserName, passwordLengthHolder, passwordHolder, null); if (status != 0) { return null; } Pointer passwordPointer = passwordHolder.getValue(); if (passwordPointer == null) { return null; } int passwordLength = passwordLengthHolder.getValue(); byte[] rawPassword = passwordPointer.getByteArray(0, passwordLength); char[] password; try { password = SVNEncodingUtil.getChars(rawPassword, "UTF-8"); } finally { library.SecKeychainItemFreeContent(null, passwordPointer); SVNEncodingUtil.clearArray(rawPassword); } return password; } catch (UnsupportedEncodingException e) { SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e); SVNErrorManager.error(error, e, SVNLogType.DEFAULT); return null; } finally { if (nonInteractive) { library.SecKeychainSetUserInteractionAllowed(true); } } } private static void release(Pointer pointer) { if (pointer != null) { ISVNMacOsCFLibrary library = JNALibraryLoader.getMacOsCFLibrary(); if (library != null) { library.CFRelease(pointer); } } } }