JNIEXPORT void JNICALL Java_com_mcdermottroe_apple_OSXKeychain__1modifyGenericPassword(JNIEnv *env, jobject obj, jstring serviceName, jstring accountName, jstring password) { OSStatus status; jstring_unpacked service_name; jstring_unpacked account_name; jstring_unpacked service_password; SecKeychainItemRef existingItem; /* Unpack the params */ jstring_unpack(env, serviceName, &service_name); jstring_unpack(env, accountName, &account_name); jstring_unpack(env, password, &service_password); /* check for allocation failures */ if (service_name.str == NULL || account_name.str == NULL || service_password.str == NULL) { jstring_unpacked_free(env, serviceName, &service_name); jstring_unpacked_free(env, accountName, &account_name); jstring_unpacked_free(env, password, &service_password); return; } status = SecKeychainFindGenericPassword( NULL, service_name.len, service_name.str, account_name.len, account_name.str, NULL, NULL, &existingItem ); if (status != errSecSuccess) { throw_osxkeychainexception(env, status); } else { /* Update the details in the keychain. */ status = SecKeychainItemModifyContent( existingItem, NULL, service_password.len, service_password.str ); if (status != errSecSuccess) { throw_osxkeychainexception(env, status); } } /* Clean up. */ jstring_unpacked_free(env, serviceName, &service_name); jstring_unpacked_free(env, accountName, &account_name); jstring_unpacked_free(env, password, &service_password); }
SEXP find_password(SEXP svc, SEXP usr, SEXP new_pwd, SEXP quiet, SEXP del) { SEXP res; OSStatus status; SecKeychainRef kc = NULL; /* default */ SecKeychainItemRef kci; const char *un, *sn; char *svc_name; void *pwd; UInt32 pwd_len = 0; int l; int silent = Rf_asInteger(quiet) == 1; int do_rm = Rf_asInteger(del) == 1; int modify = 0; if (TYPEOF(svc) != STRSXP || LENGTH(svc) != 1) Rf_error("Invalid service name"); if (new_pwd != R_NilValue && (TYPEOF(new_pwd) != STRSXP || LENGTH(new_pwd) != 1)) Rf_error("Invalid password"); if (new_pwd != R_NilValue || do_rm) modify = 1; if (usr == R_NilValue) { un = getlogin(); if (!un) Rf_error("Unable to get current user name via getlogin()"); } else { if (TYPEOF(usr) != STRSXP || LENGTH(usr) != 1) Rf_error("Invalid user name (must be a character vector of length one)"); un = Rf_translateCharUTF8(STRING_ELT(usr, 0)); } sn = Rf_translateCharUTF8(STRING_ELT(svc, 0)); l = strlen(sn); if (l > sizeof(buf) - 16) { svc_name = (char*) malloc(l + 16); if (!svc_name) Rf_error("Cannot allocate memory for service name"); } else svc_name = buf; /* we are enforcing R.keychain. prefix to avoid abuse to access other system keys */ strcpy(svc_name, SEC_PREFIX); strcat(svc_name, sn); status = SecKeychainFindGenericPassword(kc, strlen(svc_name), svc_name, strlen(un), un, &pwd_len, &pwd, modify ? &kci : NULL); if (svc_name != buf) free(svc_name); if (silent && status == errSecItemNotFound) return R_NilValue; chk_status(status, "find"); res = PROTECT(Rf_ScalarString(Rf_mkCharLenCE(pwd, pwd_len, CE_UTF8))); /* FIXME: we'll leak if the above fails in R */ SecKeychainItemFreeContent(NULL, pwd); if (do_rm) { status = SecKeychainItemDelete(kci); chk_status(status, "delete"); } else if (new_pwd != R_NilValue) { /* set a new one */ const char *np = Rf_translateCharUTF8(STRING_ELT(new_pwd, 0)); status = SecKeychainItemModifyContent(kci, NULL, strlen(np), np); chk_status(status, "modify"); } UNPROTECT(1); return res; }