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