blob: b8f86588975790217751905c6beebdd12cedc7ac [file] [log] [blame]
Oleg Besedin90f11c12008-04-24 20:07:19 +00001/*******************************************************************************
2 * Copyright (c) 2008 IBM Corporation and others.
Lars Vogela05e8872018-08-21 17:28:48 +02003 *
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
Oleg Besedin90f11c12008-04-24 20:07:19 +00006 * which accompanies this distribution, and is available at
Lars Vogela05e8872018-08-21 17:28:48 +02007 * https://www.eclipse.org/legal/epl-2.0/
8 *
9 * SPDX-License-Identifier: EPL-2.0
Oleg Besedin90f11c12008-04-24 20:07:19 +000010 *
11 * Contributors:
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14
15#include <jni.h>
16#include "keystoreNative.h"
17#include <CoreFoundation/CoreFoundation.h>
18#include <Security/Security.h>
19#include <CoreServices/CoreServices.h>
20
21/**
22 * Implements the get password functionality.
23 */
24jstring getPassword(JNIEnv *env, jobject this, jstring serviceName, jstring accountName) {
25 OSStatus status;
26 UInt32 passwordLength = (UInt32) nil;
27 void *passwordData = nil;
28 const char *serviceNameUTF = (*env)->GetStringUTFChars(env, serviceName, NULL);
29 const char *accountNameUTF = (*env)->GetStringUTFChars(env, accountName, NULL);
30
31 status = SecKeychainFindGenericPassword (NULL,
32 (*env)->GetStringUTFLength(env, serviceName), serviceNameUTF,
33 (*env)->GetStringUTFLength(env, accountName), accountNameUTF,
34 &passwordLength, &passwordData,
35 NULL
36 );
37
38 // free the UTF strings
39 (*env)->ReleaseStringUTFChars( env, serviceName, serviceNameUTF );
40 (*env)->ReleaseStringUTFChars( env, accountName, accountNameUTF );
41
42 // throw an exception if we have an error
43 if (status != noErr) {
44 (*env)->ExceptionClear(env);
45 char buffer [60];
46 sprintf(buffer, "Could not obtain password. Result: %d", (int) status);
47 (*env)->ThrowNew(env, (* env)->FindClass(env, "java/lang/SecurityException"), buffer);
48 }
49
50 // massage the string into a Java-friendly UTF-8 string
51 char *truncatedPassword = (char *) malloc(passwordLength * sizeof(char) + 1);
52 strncpy(truncatedPassword, passwordData, passwordLength * sizeof(char));
53 truncatedPassword[passwordLength * sizeof(char)] = '\0';
54 jstring result = (*env)->NewStringUTF(env, truncatedPassword);
55 free(truncatedPassword);
56 // free the returned password data
57 SecKeychainItemFreeContent (NULL, passwordData);
58 return result;
59}
60
61JNIEXPORT jstring JNICALL Java_org_eclipse_equinox_internal_security_osx_OSXProvider_getPassword(JNIEnv *env, jobject this, jstring serviceName, jstring accountName) {
62 return getPassword(env, this, serviceName, accountName);
63}
64
65/**
66 * Implements the set password functionality.
67 */
68void setPassword(JNIEnv *env, jobject this, jstring serviceName, jstring accountName, jstring password) {
69 OSStatus status;
70 const char *serviceNameUTF = (*env)->GetStringUTFChars(env, serviceName, NULL);
71 const char *accountNameUTF = (*env)->GetStringUTFChars(env, accountName, NULL);
72 const char *passwordUTF = (*env)->GetStringUTFChars(env, password, NULL);
73
74 // attempt to add the password
75 status = SecKeychainAddGenericPassword (NULL,
76 (*env)->GetStringUTFLength(env, serviceName), serviceNameUTF,
77 (*env)->GetStringUTFLength(env, accountName), accountNameUTF,
78 (*env)->GetStringUTFLength(env, password), passwordUTF,
79 NULL);
80
81 // it already exists, try to change it
82 if (status == errSecDuplicateItem) {
83 SecKeychainItemRef itemRef = (SecKeychainItemRef) nil;
84
85 // find the ItemRef corresponding to the item
86 status = SecKeychainFindGenericPassword (NULL,
87 (*env)->GetStringUTFLength(env, serviceName), serviceNameUTF,
88 (*env)->GetStringUTFLength(env, accountName), accountNameUTF,
89 NULL, NULL,
90 &itemRef
91 );
92
93 // this should rarely happen - we're in this state because it exists.
94 if (status != noErr) {
95 // free the UTF strings
96 (*env)->ReleaseStringUTFChars( env, serviceName, serviceNameUTF );
97 (*env)->ReleaseStringUTFChars( env, accountName, accountNameUTF );
98 (*env)->ReleaseStringUTFChars( env, password, passwordUTF );
99 // release the pointer to the item
100 // the following code craps out for some unknown reason when called from within Eclipse. It works fine in a standalone app, however.
101 //if (itemRef) CFRelease(itemRef);
102
103 (*env)->ExceptionClear(env);
104 char buffer [60];
105 sprintf(buffer, "Could not obtain password. Result: %d", (int) status);
106 (*env)->ThrowNew(env, (* env)->FindClass(env, "java/lang/SecurityException"), buffer);
107 }
108
109 // modify the data based on the item we've gotten above
110 status = SecKeychainItemModifyAttributesAndData (itemRef, NULL, (*env)->GetStringUTFLength(env, password), passwordUTF);
111
112 // free the UTF strings
113 (*env)->ReleaseStringUTFChars( env, serviceName, serviceNameUTF );
114 (*env)->ReleaseStringUTFChars( env, accountName, accountNameUTF );
115 (*env)->ReleaseStringUTFChars( env, password, passwordUTF );
116
117 // release the pointer to the item
118 // the following code craps out for some unknown reason when called from within Eclipse. It works fine in a standalone app, however.
119 //if (itemRef) CFRelease(itemRef);
120
121 // throw an exception if it didnt work
122 if (status != noErr) {
123 (*env)->ExceptionClear(env);
124 char buffer [60];
125 sprintf(buffer, "Could change password. Result: %d", (int) status);
126 (*env)->ThrowNew(env, (* env)->FindClass(env, "java/lang/SecurityException"), buffer);
127 }
128
129 }
130}
131
132JNIEXPORT void JNICALL Java_org_eclipse_equinox_internal_security_osx_OSXProvider_setPassword(JNIEnv *env, jobject this, jstring serviceName, jstring accountName, jstring password) {
133 setPassword(env, this, serviceName, accountName, password);
134}
135